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?

  • I know that the Nordic SPI controller has a feature where you can tell it what chip select pin to use and it will toggle it automatically when issuing transfers. Are you using this feature?

    Having the SPI controller assert the chip select line automatically is handy in that it saves you from having to manually toggle the GPIO pin yourself (there's some savings in code), however it really only works well if there is one slave, because the SPI controller can only control one chip select pin at a time, and each slave has a different chip select line.

    If you are using the automatic chip select handling feature, then I could see how you'd have to reconfigure the SPI controller each time you decide to switch from using one slave to another. In that case, I would suggest that you stop doing it that way and manually toggle the chip select lines instead.

    If you're not using that feature, then I'm not sure what could be wrong. For my current project I have an SD card and resistive touch controller on the same bus, and I can access both of them without needing to reconfigure the SPI bus in between. I do manually toggle the chip selects though.

    -Bill

  • How do I disable automatic CS handling? Do I give config a null Chipselect pin when initializing SPI?

  • Also, are you doing an nrf_drv_spi_init for your touch controller as well as a blk_dev_init for your SD card on the same instance? Or do you only do it once for both?

  • I just went to look at the documentation again, and I need to make one clarification/correction. The SPIM controller block in the nRF52840 has the hardware chip select feature, however I think you're using the nRF52832 chip, and that one doesn't have it. I forgot that you were using the nRF52832 when I was writing my previous reply. Sorry. Disappointed

    However, note that when you call nrf_drv_spi_init(), you give it a pointer to an nrf_drv_spi_config_t structure. This structure has a member called ss_pin, where ss stands for Slave Select. This is also what I'm calling the chip select. While the nRF52832 doesn't let you control the slave select pin from hardware, the Nordic SPI driver code can do it from software. When you set a pin value here, the nrfx_spi.c or nrfx_spim.c code will internally call nrf_gpio_pin_set() and nrf_gpio_pin_clear() to control the chip select pin when you issue a transfer.

    That's convenient if you only have one slave on the bus, but it doesn't work if you have two. I think the reason you're calling nrf_drv_spi_init() twice is that you're not toggling the chip select pin yourself: you're letting the Nordic SPI code do it for you via the ss_pin feature. So to go from one slave to the other, you have to keep re-initializing the SPI driver with a different ss_pin each time.

    What I think you need to do is set the ss_pin value to NRF_DRV_SPI_PIN_NOT_USED. Then you can initialize the SPI controller just once. After that, you need to modify your code to add explicit calls to nrf_gpio_pin_clear() (assert the chip select) and nrf_gpio_pin_set() (deassert the chip select) into your code before and after you issue SPI transactions to the slaves.

    In other words, you have to do this yourself instead of relying on the Nordic SPI code doing it for you.

    Note that I'm not using the nRF SDK for my project: I'm running an RTOS called ChibiOS and it has its own drivers for the SPIM block in the nRF52 chips. Conceptually though, it works the same. Really all I'm doing is initializing the SPIM block once, which configures the pin select registers (i.e. sets which pins are MOSI, MISO and SCK) and programs in the desired bus clock speed.

    Once the SPI bus itself is initialized, then I have to initiate SPI transfers from the different blocks that need to talk to the SPI peripherals. For the touch controller, I basically do:

    - assert CS pin for touch controller

    - issue SPI command to read the touch state

    - deassert CS pin for touch controller

    (The touch controller is very simple.)

    I also have an SD card driver module sitting under FatFs. When FatFs needs to read a block, it calls the block read function in the SD card driver, which behaves similarly:

    - assert CS pin for SD card

    - issue commands to read a sector from the card (involves several SPI bus transactions)

    - deassert CS pin for SD card

    What's important here is to never have the CS pins for both the SD card and touch controller asserted at the same time. As I said earlier, I use a mutex to guard the bus, and both the touch controller code and SD card code have to acquire the mutex before they can do any SPI transfers. Since only one of them can acquire the mutex at a time, it stops them from both trying to talk to the SPI bus at once.

    I hope that makes sense.

    -Bill

  • Hello, it's been a year but I have tried all what you said. The main  problem seems to be the FatFs itself. It won't let me initialize FATfs blkdev without unitializing the SPI instance I have for the other slave I want to share the bus with.

Related