Go Down

Topic: How manage multiples modules with SPI? (Read 1 time) previous topic - next topic


Nov 15, 2012, 10:07 pm Last Edit: Nov 16, 2012, 11:07 pm by Nick Gammon Reason: 1

I'm a recent Arduino's user. I'm French, and perhaps not a English master...
I'm trying to build a weather station.

I'm using a UNO-smd-R2 with a Sparkfun SD-shield and a barometric pressure captor MPL115A1.
The both compoments use the SPI. They are running perfectly, but when try to gather the both, SD-shield and MPL115A1, this last one is inactive, sending false values.

My outline is this following:
Code: [Select]

          D13  D12  D11  D10  D9  D8    D7   D6   D5    D4   D3   D2
MPL115A1   SCK  SDO  SDI  ___  SDN  ___  ___  ___  ___  CS_  ___  ___
SD-Shield  CLK  MISO MOSI___  ___  CS    ___  ___  ___  ___  ___  ___

>>I decided to avoid the pin 10 which is the internal ChipSelect from de ArduinoBoard. I don't know if it's a good choice or good understanding? I understood the ArduinoBoard must stay the master shield...
>>In my scketch, I delcared the chipselects PINs, D4 and D8 in Output for the initialization : digitalWrite(CS_PIN, output);. When I want to control and read the MPL115A1, I switch the SD-shield chipselect on a High level : digitalWrite(CS_PIN, high)

I had the scketch in the attachment, if someone can help me to understand, find the good way or my mistakes, I will be so grateful.

And sorry again if my English translation is not so well...

Moderator edit: [code] ... [/code] tags added. (Nick Gammon)


Nov 15, 2012, 11:03 pm Last Edit: Nov 15, 2012, 11:07 pm by SurferTim Reason: 1
You do not need to disable the SD SPI. It is handled by the SD library transfer routines. Your sketch does the same here:
Code: [Select]
unsigned int readRegister(byte thisRegister) {
   byte result = 0;
   // select only the MPL115A1
   digitalWrite(MPL115A1_SELECT_PIN, LOW);

// you shouldn't do this
//    digitalWrite(SD_CS_PIN, HIGH);
   // send the request
   SPI.transfer(thisRegister | MPL115A1_READ_MASK);
   result = SPI.transfer(0x00);
   // deselect the MPL115A1
   digitalWrite(MPL115A1_SELECT_PIN, HIGH);

// you shouldn't do this
//    digitalWrite(SD_CS_PIN, LOW);
   return result;  

writeRegister() is the same. All you need to do is insure both are disabled at the end of your setup function. Leave those pins alone once in loop().

edit: I modified the code to fit traditional slave select pin settings. Each library takes care of its own.



Thanks for your advices.
I used it, but the MPL115A1 didn't work. I was frustrated, and I decided (I don't know why) to play with the chip select from the serial monitor. When I withdraw the connection from the D4 (CS MPL115A) the measurement changed. The values were not correct, but different. Also, I decided to withdraw the VCC pin (3,3V) just to know if the sensor was shutdown or enable...

It's just unbelievable, it's running perfectly now!!! without vcc!!! ??? I don't know why...

I'm going to read again and precisely the datasheets...

I added some pix in the attachment.

I'm wondering if my alunimun support is not the reason of this malfunction? perhaps that create an electric connection between the different boards... I'll inform you about my research...

Thanks so much.

Nick Gammon

I wouldn't do that. Running it without VCC is running the chip off parasitic power derived from the data lines. That won't be good for it. Solve the problem instead.

I agree with SurferTim. Fiddling with the CS for the SD card in the readRegister function is completely the wrong place for it. Leave those lines out.

If you look at their diagram on page 10 of the datasheet, I would not be lowering and raising CS for the barometer for each reading.

Put the CS stuff around all this:

Code: [Select]

    writeRegister(0x24, 0x00);      // Start Both Conversions
    //writeRegister(0x20, 0x00);    // Start Pressure Conversion
    //writeRegister(0x22, 0x00);    // Start temperature conversion
    delay(2);                       // Max wait time is 1ms, typ 0.8ms
    // Read pressure
    uiPH = readRegister(PRESH);
    uiPL = readRegister(PRESL);
    uiTH = readRegister(TEMPH);
    uiTL = readRegister(TEMPL);

And don't change it in writeRegister or readRegister. Of course all that could be simplified now:

Code: [Select]

    digitalWrite(MPL115A1_SELECT_PIN, LOW);
    SPI.transfer (0x24 & MPL115A1_WRITE_MASK);
    SPI.transfer (0x00);
    digitalWrite(MPL115A1_SELECT_PIN, HIGH);
    delay(1);                       // Max wait time is 1ms, typ 0.8ms
    digitalWrite(MPL115A1_SELECT_PIN, LOW);
    SPI.transfer (PRESH | MPL115A1_READ_MASK);
    uiPH = SPI.transfer (0x00);
    SPI.transfer (PRESL | MPL115A1_READ_MASK);
    uiPL = SPI.transfer (0x00);
    SPI.transfer (TEMPH | MPL115A1_READ_MASK);
    uiTH = SPI.transfer (0x00);
    SPI.transfer (TEMPL | MPL115A1_READ_MASK);
    uiTL = SPI.transfer (0x00);
    digitalWrite(MPL115A1_SELECT_PIN, HIGH);

Tip: Might be nice to have a define for 0x24, since you have ones for all the others. :)

Nick Gammon

Also, I decided to withdraw the VCC pin (3,3V) just to know if the sensor was shutdown or enable...

Why not run it at 5V to be compatible with the Arduino?

Go Up