SOLVED. Nrf24 (Mirf lib) + Micro SD-card works OK together

I've met the problem that SD-cards and Nrf24 dont 'play well' on the SPI-bus.

this module: http://www.ebay.com/itm/Micro-SD-TF-Card-Storage-Memory-Module-For-Arduino-SPI-Level-conversion-TOP-/321461876510?hash=item4ad89ef71e:g:OOgAAOSwMjNTzMZI
only needs a small mod to make it work.
The card has a level shifter (LVC125A) with 3-state outputs, but they are not used as such.
This mod controls the SO-pin to be high-Z when chip is not selected.
Picture shows 'cut' and 'new connection'.

The code isn't very relevant, but her goes..

 /*************** RADIO
 ** CE   - your choice
 ** CSN  - pin 10  (other pin may also work?)
 ** MOSI - pin 11 
 ** MISO - pin 12
 ** CLK  - pin 13
 * ************* SD-KORT-LESER
 ** CS   - pin 4 (choice)
 ** MOSI - pin 11 
 ** MISO - pin 12
 ** CLK  - pin 13
 * 
 */

#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
#include <MirfSpiDriver.h>
#include <SD.h>
const int SelectSD  = 4;  // pinnenummer brukt for CS til SD-kortet
const int Radio_CSN = 10; // pinnenummer brukt for CSN på radio (ikke endre denne)
const int Radio_CE  = 8;  // pinnenummer brukt til CE på radio (kan være uansett ledig pin)

const byte payload = 4;  // max er 32 bytes i hver pakke. 

union
{
  byte ch[payload];
  long tid;
} rx_buffer ; 

void setup()
{
  SD.begin(SelectSD);
  Serial.begin(9600);
  digitalWrite(SelectSD,HIGH); // disable sd-kortet
  Mirf.csnPin =  Radio_CSN;                                                                                                                                                          ; // kan endres etter behov. Kan utelates hvis default
  Mirf.cePin  = Radio_CE; 
  Mirf.spi = &MirfHardwareSpi;
  Mirf.init();
  Mirf.payload = payload;
  Mirf.channel = 101; // any channel:  1..125 (avtales med den som sender)
  Mirf.config();
  Mirf.setRADDR((byte *)"aaaaa"); // sett inn 'receive'-navn - alltid 5 tegn!
  digitalWrite(Radio_CSN,HIGH); // disable radio
  digitalWrite(SelectSD,HIGH); // disable sd-kortet
}

void loop()
{
  digitalWrite(Radio_CSN,LOW); // enable radio
  while(!Mirf.dataReady()) {};  // wait for data to arrive
  Mirf.getData(rx_buffer.ch);  // read to buffer
  Serial.println(rx_buffer.tid); 
  digitalWrite(Radio_CSN,HIGH); // disable radio
  digitalWrite(SelectSD,LOW); // enable sd-kortet
  if (File dataFile = SD.open("testA.txt", FILE_WRITE))
  {
    dataFile.println(rx_buffer.tid); // 'tid' is time (millis() from sender)
    dataFile.close();
  }
  else  Serial.println("Can't save");
  digitalWrite(SelectSD,HIGH); // disable SD-card
}

1 Like

I spend hours reading about SPI , arduino and other things trying to make SD-cards and Nrf24 to work.

knut_ny , thanks very much for this fix

I buffer MISO coming back from 3.3V devices to:
a) prevent poorly behaved devices from interfering with MISO from other devices when not selected
b) prevent 5V from being applied to 3.3V devices - a good example is Programmers connected to ICSP pins.
c) prevent input diode protection on 3.3V devices from dragging down 5V signals.

My method is typically use cd74HC4050 to buffer 5V down to 3.3V, and some form of HC125 to enable 3.3V MISO onto 5V MISO line using the devices chip select. Put a pullup resistor on the Chip Select line so the buffer is not accidentally active due to a floating pin when the microcontroller is being reset. You can see that in U9 and U10 here, with the pullup on D10:




(the links open to much more viewable schematics)

knut_ny:
I've met the problem that SD-cards and Nrf24 dont 'play well' on the SPI-bus.

this module: http://www.ebay.com/itm/Micro-SD-TF-Card-Storage-Memory-Module-For-Arduino-SPI-Level-conversion-TOP-/321461876510?hash=item4ad89ef71e:g:OOgAAOSwMjNTzMZI
only needs a small mod to make it work.
The card has a level shifter (LVC125A) with 3-state outputs, but they are not used as such.
This mod controls the SO-pin to be high-Z when chip is not selected.
Picture shows 'cut' and 'new connection'.

The code isn't very relevant, but her goes..

 /*************** RADIO

** CE  - your choice
** CSN  - pin 10  (other pin may also work?)
** MOSI - pin 11
** MISO - pin 12
** CLK  - pin 13

  • ************* SD-KORT-LESER
    ** CS  - pin 4 (choice)
    ** MOSI - pin 11
    ** MISO - pin 12
    ** CLK  - pin 13

*/

#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
#include <MirfSpiDriver.h>
#include <SD.h>
const int SelectSD  = 4;  // pinnenummer brukt for CS til SD-kortet
const int Radio_CSN = 10; // pinnenummer brukt for CSN på radio (ikke endre denne)
const int Radio_CE  = 8;  // pinnenummer brukt til CE på radio (kan være uansett ledig pin)

const byte payload = 4;  // max er 32 bytes i hver pakke.

union
{
  byte ch[payload];
  long tid;
} rx_buffer ;

void setup()
{
  SD.begin(SelectSD);
  Serial.begin(9600);
  digitalWrite(SelectSD,HIGH); // disable sd-kortet
  Mirf.csnPin =  Radio_CSN;                                                                                                                                                          ; // kan endres etter behov. Kan utelates hvis default
  Mirf.cePin  = Radio_CE;
  Mirf.spi = &MirfHardwareSpi;
  Mirf.init();
  Mirf.payload = payload;
  Mirf.channel = 101; // any channel:  1..125 (avtales med den som sender)
  Mirf.config();
  Mirf.setRADDR((byte *)"aaaaa"); // sett inn 'receive'-navn - alltid 5 tegn!
  digitalWrite(Radio_CSN,HIGH); // disable radio
  digitalWrite(SelectSD,HIGH); // disable sd-kortet
}

void loop()
{
  digitalWrite(Radio_CSN,LOW); // enable radio
  while(!Mirf.dataReady()) {};  // wait for data to arrive
  Mirf.getData(rx_buffer.ch);  // read to buffer
  Serial.println(rx_buffer.tid);
  digitalWrite(Radio_CSN,HIGH); // disable radio
  digitalWrite(SelectSD,LOW); // enable sd-kortet
  if (File dataFile = SD.open("testA.txt", FILE_WRITE))
  {
    dataFile.println(rx_buffer.tid); // 'tid' is time (millis() from sender)
    dataFile.close();
  }
  else  Serial.println("Can't save");
  digitalWrite(SelectSD,HIGH); // disable SD-card
}

Thanks for this mod, If I understand your image correctly.
It says that cut connection of pin 13 in that chip from ground and connect CE to pin 13 of the chip.
Is it correct?

correct (ouput enable pin now controlled by cs)

I am facing the exact same while trying to connect an micro sd card reader and rf24 together on one uno.
if i disonnect the SD reader it works. If i connect both the radio initialisation fails.Cause i got a micro sd reader the connections are all stuffed together so no modding opportunity.Is there any way know to make them work together anyway ?.Heres the code i use :

#include "RF24.h"
#include <printf.h>
#include <SdFat.h>

RF24 radio(7,8);
byte addresses[][6] = {"Base","W01"};
SdFat SD;

#define SD_CHIP_SELECT                10

void setup() {
 Serial.begin(115200);
 printf_begin();

 pinMode(SD_CHIP_SELECT, OUTPUT);
 digitalWrite(SD_CHIP_SELECT, HIGH);
 if (!SD.begin(SD_CHIP_SELECT)) {
    Serial.println("CardBegin failed");
  }
  else{
    Serial.println("CardBegin succeded");
  }
 
 radio.begin();
 radio.setPALevel(RF24_PA_MIN);
 radio.setRetries(15, 15);
 radio.openWritingPipe(addresses[0]);
 radio.openReadingPipe(1,addresses[1]);
 radio.startListening();
 radio.printDetails();
 Serial.println("RadioBegin succeded");
}

void loop() {
  if( radio.available()){
      unsigned int command;
      while (radio.available()) {                          
        radio.read(&command, sizeof(command) );        
      }
      Serial.println(command);
      radio.stopListening();                                       
      radio.write( &command, sizeof(command) );                       
      radio.startListening();                                        
   }
}

I have heard that this condition is related to the SD card. And some people have had success by just sending null out on the SPI bus after SD card functions. Like this:

void setup() {
 Serial.begin(115200);
 printf_begin();

 pinMode(SD_CHIP_SELECT, OUTPUT);
 digitalWrite(SD_CHIP_SELECT, HIGH);
 if (!SD.begin(SD_CHIP_SELECT)) {
    Serial.println("CardBegin failed");
  }
  else{
    Serial.println("CardBegin succeded");
  }

 SPI.transfer(0); // just activate the SPI SCK for 8 pulses, none of the devices on the bus
// have their CS pin low, so there should be no reaction, but sometimes the SD card does not release
// the MISO pin until it sees a few clocks, so by sending a null without any CS driven low it tends to 
// 'clear' the SPI bus
  
 radio.begin();
 radio.setPALevel(RF24_PA_MIN);
 radio.setRetries(15, 15);
 radio.openWritingPipe(addresses[0]);
 radio.openReadingPipe(1,addresses[1]);
 radio.startListening();
 radio.printDetails();
 Serial.println("RadioBegin succeded");
}

One other question, do these two libraries(RF24.h and SDFat.h) correctly control the SPI bus?

look through their code, look for calls to SPI.beginTransaction() and SPI.endTransaction().

If they only use SPI.setBitOrder(), SPI.setClockDivider(), SPI.setDataMode(), BOTH Libraries MUST use the EXACT SAME parameters.

If they use different config options, that could be why only one will work at a time.

Chuck.

Thanks for the answer chucktodd.
Ive went through all the solutions u offert but got no result.

SPI.transfer(0); -> doesnt change anything

The libs boths use the same mode,speed and Order (see in attachments).
Sadly i dont have an osscilosscope to mesure the clock rates to be sure.

There is another version of this module:

In order to make it work well with other SPI devices we need to mod it :slight_smile:

Pull up the pin no. 13 of the LVC125A, which controls the MISO output (soldered to GND for some reason), and connect it to the pin no. 8 (CS signal).

As a result: now this module works flawlessly with other SPI devices (ETH28J60 module in my case)

Have fun :slight_smile:

2 Likes

Excellent solution, Thanks a lot!

@knut_ny and someuser, you made my day :slight_smile:

Finally solved after 7 hours troubleshooting and searching the web.

thx!!!

As this is nothing but a temporary solution to the problem, is there any sd card modules out there that work out of the box? I have tried this mod, but it don't seem to work at all with my nRF24L01+ module.

I have never seen one.
The chineese designers should have made this easy fix a long time ago.
You say you have done the fix to your card. (and you are of course sure thats OK)
The next step is to make sure that the radio has its (often) necessary fix: The module will fail if its powerline ins't a clean voltage. Add a cap (10uF +/-) directly onto the module.
(you will find pictures/discussions on problem this fix in this forum)

Also this one has Dout directly to Arduino MISO (which is our problem)

Solution: Force the SD-card to release the line or add a buffer to 'stop' the signal

I have also come across this problem, attempted mod and first time damaged the card during soldering, second time ok and works fine. There is however a module " Adafruit 254 micro Sd breakout board " works out of the box and seems faultless ,I obtained mine from Maplin. Hope this helps.

has anyone tried the mod with calatex v1.0 SD Card module with nRF24l01+ module?

calatex v1.0 SD Card module with nRF24l01+

??

If this one Interfacing Catalex Micro SD Card Module with Arduino – Vishnu Mohanan

Mod will fix it .
See attached picture

knut_ny:
Mod will fix it .

I tried the mod, how unlucky i am that the whole pin 13 of the level shifter is pulled out, meaning that i dont have space to solder the pin...

now i use another type of SD Card module and it didn't work also...