pico-examples icon indicating copy to clipboard operation
pico-examples copied to clipboard

multiple SPI slaves fail because SPI slave MISO TX pin should be floated when CSN is high

Open alien999999999 opened this issue 2 years ago • 8 comments

I configured 2 PICO's as SPI slave and connected them to a raspberry pi 4B configured as SPI master with 2 slave devices, but i noticed all slave to master traffic was all 0's (from both PICO's). (disconnecting one pico worked)

I figured the miso was all 0's because the other PICO (which did not have CSN low) was interfering.

I tested the same config, but i disconnected one MISO wire and sure enough, the other pico then worked; which imo proves that the miso is not floating when that pico's CSN is high (and the chip should not be selected).

I wonder if this is fixable in software somewhere? maybe if the CSN is high when the CSN has a SPI function associated, the MISO pin could set as input pin without pull-down? when the CSN becomes low it should resume it's function? This would enable multiple slaves. if this is not desirable by default, can it at least be an option somewhere?

alien999999999 avatar Aug 08 '22 09:08 alien999999999

I think this is a duplicate of https://github.com/raspberrypi/pico-feedback/issues/227 ?

lurch avatar Aug 08 '22 10:08 lurch

not sure, this one mentions that there is a way to software change this; but i don't see any method to software control this... I had to wire a non-inverted buffer triggerd by CSN on the outside of the pico, otherwise I would not have any communication to both. I don't see a way to handle this in software; if there is one, it would be great, but, since i'm using the SPI hardware, and it send out the buffer at a later time, i have no way of matching this by disabling this pin in software at the same time...

If there is a method, it would be great to have this in the SDK

alien999999999 avatar Nov 05 '22 16:11 alien999999999

Section 4.4 of https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf says: "The SPI TX pin function is wired to always assert the pad output enable, and is not driven from nSSPOE. When multiple SPI slaves are sharing a bus software would need to switch the output enable. This could be done by toggling oeover field of the relevant iobank0.ctrl register, or by switching GPIO function."

lurch avatar Nov 06 '22 13:11 lurch

Yeah, I saw the other issue where they said that they would change the documentation; however if i'm using the hardware chip, which will send out at a later time, (so it would be too soon); i can't exactly fix this in user-software, even if I were to interrupt on the CSN, by the time the interrupt fires, it'll be too late... Now, if somehow devs can fix this i the sdk or in the kernel or somehow linked to when the data's actually getting sent out, that would be great... Or if you have another idea, i'm all ears... I'd love to be wrong on this.

alien999999999 avatar Nov 06 '22 15:11 alien999999999

I'm waiting on a solution to this as well.

schaefer01 avatar Jun 07 '23 18:06 schaefer01

@schaefer01, For my setup, I have a master MCU (PIC32) that need to collect the data from the slave Pico and 2 other sensors, each 4ms via SPI, 19 bytes each transaction to indicate that my system still can afford this design (and for other applications that require higher data rate via SPI, maybe it will not work). The general idea is to enable the SPI TX pin before sending data from pico to the master and immediately disable the TX pin after that due to the recommendation from the pico datasheet.

Also avoid using this 2 in 1 function spi_write_read_blocking() since we have no way to isolate the TX pin disable without affecting the RX side by using this function, which means that we only enable the TX pin on the pico when the slave sends out the data. And this code works for my setup.

        spi_read_blocking(spi_default, 0, in_buf, 1);
        // Enable output on the MISO pin
        gpio_set_oeover(ALTERNATE_SPI_SLAVE_MISO, GPIO_OVERRIDE_HIGH);
        spi_write_blocking(spi_default, out_buf, 19);
        // Enable the MISO Pin later, this is added due to the unquie hardware implementation of the pico
        gpio_set_oeover(ALTERNATE_SPI_SLAVE_MISO, GPIO_OVERRIDE_LOW);

From this code, the master MCU actually wants to request 19 bytes data from the SPI slave pico, I added an extra 1 byte for the reading operation using spi_read_blocking(), just for the start signal. Without adding this one extra byte, we have to wait inside the spi_write_blocking(spi_default, out_buf, 19) until receiving the sync clock from master MCU to send out the data, and we've already enabled the SPI TX pin before, this again can cause the original issue of this post "multiple SPI slaves fail because SPI slave MISO TX pin should be floated when CSN is high". This is just a workaround to solve the hardware limitation, my first time seeing this limitation after doing the SPI on several devices.

AnhNhan2803 avatar Jun 09 '23 19:06 AnhNhan2803

hi, for the featherwing and python, a workaround that worked for me was the circuitpy bitbang (software spi) library. you need to select different gpio pins, but the chip select then works.

schaefer01 avatar Jul 07 '23 11:07 schaefer01

So:

  • @AnhNhan2803 does direct spi half-duplex with blocking
  • @schaefer01 just does not use the spi hw chip
  • I added a hw buffer chip to float the TX pin when CSN is high

my pico is doing other things when not doing SPI, so i cannot just block everything and wait for this, especially when i'm using DMA to feed the FIFO, I have a feeling the firmware should be able to have a configurable workaround to handle oe at the same time the CSN is switched, maybe when the fifo is cleared? I can't do it because any IRQ would be too late

alien999999999 avatar Jul 12 '23 08:07 alien999999999