Any known oddities with Teensy 4, SPI1, asserting CS1?

Status
Not open for further replies.

JimKazmer

Well-known member
Using a Teensy 4, I am using SPI and SPI1 (independent from each other) to interact with two separate remote devices. I do the exact same thing with each device: send a command, and receive a response using one wire (SPI:MOSI and SPI1:MOSI1). The remote devices receive their 16-bit command, and reply with a 21 bit response. I can see both the send and receive signals on my scope for both MOSI and MOSI1; both the send and receive signals on both pins are correctly formed. Also, the remote devices are both following the commands based on their behavior.

SPI works great. SPI1 sends, but does not receive.

The general flow is this:
(1) A timer is used to trigger sending commands out the SPI peripherals at the desired frequency;
(1b) The data is written to the transmit FIFO, and
(1c) the Frame Complete interrupt is set to trigger when done.
(2) The SPI interrupt for Frame Complete is triggered, and we setup the SPI to receive (slave mode) using the MOSI to receive.
(2b) We configure it to read in the expected number of bytes as necessary to capture all the data.
(2c) We setup the "Receive Data Interrupt" to trigger when the data has been read in.
(2d) We "prime the pump" by putting some data into the transmit FIFO.
(3) The SPI's "Receive Data Interrupt" triggers, and we read in the data. And make the SPI inactive.
(4) The process repeats when the timer triggers again (back to #1).

As I indicated above, the sends are working, SPI receives, but SPI1 never gets the "Receive Data Interrupt".
In this situation, both SPI and SPI1 are in SLAVE mode, and need to see the CS pin driven low. I set pin 3 to output, drive it low. Pin 3 is connected to both pin 0 (SPI1:CS1) and pin 10 (SPI:CS).
Also, both SPI and SPI1 need a clock signal; I use another pin to supply a clock and connect that to pins 27 (SPI1:SCK1) and 13 (SPI:SCK).
I can see these signals behaving correctly on the scope.

It appears to me as though the SPI1 peripheral is not reading in the CS0 (pin 0). Like the pin muxing isn't setup correctly.

I have tried so many things:
* calling SPI1.setCS(0) in the setup, in the interrupt, both... doesn't improve the situation, sometimes disrupts SPI.
* Using another pin (e.g pin 2), connecting to pin 0, and driving pin 0 LOW
* Setting pin 0 as an output and setting it LOW
* Setting pin 0 as an input and connecting to pin 2.

I put some serial.print statements in the SPI library to see what was being set in setCS():
//SPI: i=0 hardware().cs_pin=10 hardware().sck_mux=13 ... *(portConfigRegister(pin)) = hardware().sck_mux;
//SPI1: i=0 hardware().cs_pin=0 hardware().sck_mux=12 ... *(portConfigRegister(pin)) = hardware().sck_mux;


Unfortunately, the code is long and complex, and the setup is not easily emulated. Hence, I don't think anyone would want to sift through it. Also, I am coming up on a deadline, and don't have time to externalize a clean example of the problem (my apologies).

I guess what I am looking for would be this: What are the hardware commands to configure the pin muxing so that pin 0 is operating as SPI1:CS1 (and bonus points for the best mechanism to toggle it HIGH to LOW)?
 
SOLVED: Any known oddities with Teensy 4, SPI1, asserting CS1?

I've been opening many libraries and reading many posts. Seen many examples of SPI as slave, and SPI1 as master. Still looking for one using SPI1 as slave. Recall reading someone's comment about strange behavior with SPI1 operating in Slave mode... Now I'm reading up on RT1060 pin muxing...

After 90 minutes of sleuthing through the mysteries (to me) of IOMUX... I came to the following conclusion.

The SPI peripherals do not always deduce the correct behavior for how to deal with the Chip Select pin. Chapter 47: Low Power Serial Peripheral Interface (LPSPI) states that it will use CS as an input in SLAVE mode and ignore the pin in MASTER mode. But for my program, maybe this specific mode of writing and reading the same wire, the SPI peripheral did not "figure it out".

In the IOMUX chapter, part of the pin configuration settings, the (current) SPI libraries must use a default setting for bit 4 SION (Software Input On Field) = 0, which means "Input Path is determined by functionality". Which would imply the peripherals mode of operation determines how the peripheral will use the pin. This functionality of "the peripheral will figure it" seems to work for SPI (LPSPI4), but not SPI1 (LPSPI3). I have not (yet) worked with SPI2 (LPSPI1), so I don't know how that behaves.

The solution to my problem was to explicitly set the "Software Input On Field" (SION) behavior to the value as I am using it (don't rely on the peripheral to figure it out).
Set the SION bit value to 1 for SLAVE mode and set it back to 0 in MASTER mode. Once I did this, my program read in the response as expected.

Here are the registers for each SPI peripheral:
SPI SLAVE mode: IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_00 = 0x13; //SION = 1 ENABLED — Force input path of pad GPIO_B0_00 (LPSPI4_PCS0)
SPI MASTER mode: IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_00 = 0x03;
SPI1 SLAVE mode: IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_03 = 0x17; //SION = 1 ENABLED — Force input path of pad GPIO_AD_B0_03 (LPSPI3_PCS0)
SPI1 MASTER mode: IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_03 = 0x07;
Note: the above values are based on the "PAD" configured. I am a neophyte when it comes to IOMUX knowledge, so I would assume that the values can change in some circumstances. In other words, this specific solution may not apply to your problem (but the idea may get you on the right path).
 
Last edited:
Good work Jim, and in the two hours the post could be edited! … I missed reading the slave part for the p#2 reply … opps.
 
Status
Not open for further replies.
Back
Top