This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Sharing a SPI bus with an SD card (FATFS) and another SPI Slave

Hello, 

I am having a few issues with getting the SD card FATFS example code to share the same bus as another slave I transfer data to. 

I have a few questions:

1) Since, I don't need the two slaves to transfer simultaneously, should I have them use the same SPI instance?

2) What part of the FATFS example needs to be done only once? I want to write to the SD card every 1 second or so, so I split the example code into two functions: sd_spi_start() containing the initializing and the mounting, and sd_write() containing the directory reading, file opening, file writing and file closing. So I was planning on calling sd_spi_start() once and the sd_write() multiple times... is this the correct approach?

3) Right now I am stuck where I write to SD card using sd_write() (Channel 6), write to the other slave using nrf_drv_spi_transfer() , then try to write to SD card again and it just gets stuck (the CS pin just stays low):

Do you have any idea to why this is happening?

  • In general (not specific to Nordic), I would always try to avoid sharing an SD-Card with any other SPI device.

    I don't really that SD-Cards are designed to share their SPI interface.

    What part of the FATFS example needs to be done only once?

    I don't know if the FatFs design assumes that it has exclusive control of the SPI lines.

    You'd probably have to check that with ChaN: 

    http://elm-chan.org/fsw/ff/00index_e.html

    http://elm-chan.org/fsw/ff/bd/

  • 1) Since, I don't need the two slaves to transfer simultaneously, should I have them use the same SPI instance?

    Usually it's more a matter of how may pins you have available on the chip. The nRF52832 has 32 pins and multiple serial device blocks that can be enabled simultaneously. I don't know how many you're going to use for your application, but if you have enough, putting each device on its own dedicated bus avoids contention.

    I did build a project once where for various and sundry reasons I was forced to put 3 slaves on one bus -- sd card, graphics display and resistive touch controller chip. I used an RTOS, and to keep things from exploding, I used a mutex to guard access to the SPI controller. (Any time I needed to do a SPI transfer to one of the slaves, I had to acquire the mutex first, do the transfer, then release the mutex again after.)

    I think the Nordic SDK examples are mostly single-threaded. That being the case, you may be able to get away without using mutexes, provided you manage your chip selects correctly and don't try to issue a transfer for slave B while a transfer for slave A is still in progress,

    3) Right now I am stuck where I write to SD card using sd_write() (Channel 6),

    I know this might make sense to you, but remember the "we can't see over your shoulder" rule. Tell us which channel is MISO, which is MOSI, which is SCK and which is CS.

    Each slave should have its own chip select pin. When a slave's CS pin is asserted (pulled low), the it will listen to the MOSI/MISO/SCK pins on the SPI bus. If you're sharing a bus with multiple slaves, only one slave must have its CS pin asserted at any given time.

    I don't know if the FatFs design assumes that it has exclusive control of the SPI lines.

    Well, if you do use an RTOS, there are two things to worry about:

    - The SPI bus controller state

    - The FatFs library's internal state

    FatFs has the notion of a synchronization object, and it has an optional API called ff_cre_syncobj(), ff_del_syncobj(), ff_req_grant() and ff_rel_grant(). I think you need to define FF_FS_REENTRANT in order to use it. It's up to you provide implementations of these functions that make sense for your application.

    If you have two threads in your RTOS which may both be accessing files via FatFs and they could be running concurrently, then you need to use the above mechanism to make sure FatFs itself stays sane.

    However, if you're using SPI for your SD card, and you have another kind of SPI slave on the same bus (temperature sensor, display, etc...), then since that slave isn't using FatFs, the above synchronization mechanism won't help you. (The thread accessing files via FatFs will be using it, the thread talking to the other slave will not.)

    In that case, you need to define a mutex to guard the SPI bus itself, and then make sure both the FatFs SPI driver and your other slave code both use it, so that both can't try to use the SPI bus at the same time.

    This means that when you use FatFs to access files, you'll be taking two mutexes instead of one, but that's ok (as long as FatFs always takes the SPI mutex _after_ its own mutex).

    To make a long story short, if you can spare the pins, it may be easier if you use two separate SPI buses.

    -Bill

  • Damn, I didn't know that SD-cards were designed to have its own SPI bus. It's kind of too late now though since my custom board has space for only one bus. I will take note of that for future revisions.

  • Hello,

    Sorry for not being clear. Channel 2 is SCLK, Channel 3 is MOSI, Channel 4 is MISO, Channel 6 is CS of SD card and channel 7 is CS of another SPI slave that isn't an SD card.

    Basically, I'm at a point where the custom board has already been fabricated and I have only allocated enough space for one SPI bus. Therefore, I will try my best on this revision to make this work with one bus if possible.

    I am currently not using an RTOS as we have deemed it not that useful right now since all the operations the device will be doing is very low frequency (0.5-10Hz) and they are not that complex.

    I think for now I will use some sort of flag/mutex within the callback functions for both the SPI slave and the SPI Fatfs drivers to prevent simultaneous communication. I'll let you guys know what happens.

  • So I can get it to work if I uninitialize SPI in between SD card SPI transfers and other slave SPI transfers. Since it works I'll move forward with this but if someone has an idea why I have to do this let me know so that I can optimize this further.

Related