raspberrypi / pico-sdk

BSD 3-Clause "New" or "Revised" License
3.27k stars 841 forks source link

Pico SPI in master mode asserts/deasserts chip select around every byte sent #88

Closed joan2937 closed 3 years ago

joan2937 commented 3 years ago

This behaviour breaks SPI chips which expect the complete transaction to be framed by chip select assert/deassert.

E.g. To request a reading from a MCP3008 on channel 0 you might send the bytes 0x01, 0x80, 0x00. A CS deassert after 0x01 makes the MCP3008 think the command has been cancelled.

A workaround is to leave CS in SIO (rather than SPI) mode and toggle the line in software.

This appears to be a known bug/feature as the SPI C examples bme280_spi, mpu9250_spi, and spi_flash each toggle CS in software.

JamesH65 commented 3 years ago

@kilograham @Wren6991 Any thoughts? I've always used CS on SIO in the examples, didn't know there was another way!

joan2937 commented 3 years ago

@JamesH65 The Pi's Broadcom SoC SPI worked properly when the CE were in SPI mode.

The original Linux driver did use that mode. It was later altered to handle CE in software, but I thought that change was more to do with flexibility in choosing GPIO for chip selects (the hardware was limited to two choices for the main SPI CE and three choices for the auxiliary SPI CE).

JamesH65 commented 3 years ago

I don't think the SPI block on the Pico has any relation to the ones on the 27xx SoC's.

Wren6991 commented 3 years ago

The PL022 SPI supports Motorola SPI, TI SPI, and NS Microwire, all of which pulse the chip select around individual data frames. It doesn't support the de facto SPI variant used on e.g. flash chips, where CSn is used to frame an entire transaction. If you need this behaviour, you need to use a software chip select. You can find the original Arm reference manual for the PL022 here, or see 4.4 in our datasheet:

image

This is a fairly common limitation of SPI blocks (due to there being three "standard" SPI variants, a fourth de facto one which a lot of slaves use, and many others besides), which is why many cross-micro APIs like Mbed's SPI API don't expose the hard chip select function at all. See their SPI API reference here, which uses a soft chip select in the very first example. See also the MicroPython machine.SPI reference, which doesn't expose a CS pin due to this same common frustration. If an API does expose a chip select it is often using a software GPIO in the background.

If you want hardware SPI chip select of an entire SPI transaction, based on FIFO fullness, you can have a look at this PIO example code which will keep CS asserted as long as there is data, and provide a clean front/back porch on the chip select, plus deassertion dwell time.

JamesH65 commented 3 years ago

I knew we put that PIO in for a reason!

joan2937 commented 3 years ago

Thanks for the update. It's useful to know there is no hardware configuration of CS toggling on/off. So for full control you need to toggle CS in software.

nielmistry commented 2 years ago

Hey guys! Is there a workaround to get slave mode working without individual CS toggles?

lurch commented 2 years ago

@nielmistry It's generally not a good idea to add comments to already-closed issues, but perhaps there's something useful in https://github.com/raspberrypi/pico-examples/issues/26 ? Alternatively, you could ask on the forums.

Nate711 commented 1 year ago

@lurch @Wren6991 @joan2937 @JamesH65 Following up on @nielmistry 's question, is there now a solution for making the pico a SPI slave that is compatible with a master that pulls CS low for the entire data transmission? Thanks

nielmistry commented 1 year ago

@Nate711 I ended up solving this, iirc I had just missed something in the datasheet:

https://github.com/uwopus/pico-code/blob/3594e67c1ac34e5454eb4db8362b673bcc7c8862/opus_comms/opus_comms.c#L44-L46

Nate711 commented 1 year ago

@nielmistry Thanks so much! Copying the portion of the datasheet you mentioned in the code here for reference


4.4.3.13. Motorola SPI Format with SPO=1, SPH=1
Figure 95 shows the transfer signal sequence for Motorola SPI format with SPO=1, SPH=1, and it covers both single and continuous transfers.
 NOTE
In this configuration, during idle periods:
• the SSPCLKOUT signal is forced HIGH
• the SSPFSSOUT signal is forced HIGH
• the transmit data line SSPTXD is arbitrarily forced LOW
• the nSSPOE pad enable signal is forced HIGH (note this is not connected to the pad in RP2040)
• when the PrimeCell SSP is configured as a master, the nSSPCTLOE line is driven LOW, enabling the SSPCLKOUT pad, active-LOW enable
• when the PrimeCell SSP is configured as a slave, the nSSPCTLOE line is driven HIGH, disabling the SSPCLKOUT pad, active-LOW enable.
If the PrimeCell SSP is enabled, and there is valid data within the transmit FIFO, the start of transmission is signified by the SSPFSSOUT master signal being driven LOW. The nSSPOE line is driven LOW, enabling the master SSPTXD output pad. After an additional one half SSPCLKOUT period, both master and slave data are enabled onto their respective transmission lines. At the same time, the SSPCLKOUT is enabled with a falling edge transition. Data is then captured on the rising edges and propagated on the falling edges of the SSPCLKOUT signal.
After all bits have been transferred, in the case of a single word transmission, the SSPFSSOUT line is returned to its idle HIGH state one SSPCLKOUT period after the last bit has been captured.
For continuous back-to-back transmissions, the SSPFSSOUT pin remains in its active-LOW state, until the final bit of the last word has been captured, and then returns to its idle state as the previous section describes.
For continuous back-to-back transfers, the SSPFSSOUT pin is held LOW between successive data words and termination is the same as that of the single word transfer
pressdot commented 8 months ago

@Nate711 I ended up solving this, iirc I had just missed something in the datasheet:

https://github.com/uwopus/pico-code/blob/3594e67c1ac34e5454eb4db8362b673bcc7c8862/opus_comms/opus_comms.c#L44-L46

Thank You Very Much, at first, I don't think that it was the spi mode problem , now I am working at spi slave pio.