How is SPI transfer actually handled on Teensy 4.1?

PAAUX4

Well-known member
In my project, if I press a lot of buttons (which causes a lot of SPI communication), the code hangs and GDB shows me it's getting stuck in the below while loop from SPI.h (starting line 1237).

Code:
	uint8_t transfer(uint8_t data) {
		port().TDR = data;
		while (1) {
			uint32_t fifo = (port().FSR >> 16) & 0x1F;
			if (fifo > 0) return port().RDR;
		}
	}

According the to RT1060 manual (page 2826), those bits in the FSR register are the number of words currently stored in the receive FIFO. I think writing to the TDR automatically starts the SPI transfer, and then the code loops until it receives something in the FIFO register. In some cases, and I don't know why, fifo stays as 0 and so the code doesn't leave the while loop.

Am I right in thinking that's how it works? Could there be an interference problem? Or maybe interrupts are getting involved?

My code is here: https://github.com/StagBeetle/Buttseqs but to compile I changed the audio library to reference SDFat, I think.

The actual code that calls the transfer in buttons.cpp is
Code:
		digitalWrite(BUTTONCS, 1);
		AUXSPIBUS.beginTransaction(shiftreg);
		for(int i = 0; i < numberOfShiftRegisters; i++){
			buttonShiftArray[i] = AUXSPIBUS.transfer(0);
		}
		AUXSPIBUS.endTransaction();
		digitalWrite(BUTTONCS, 0);
Maybe some delays would help?
 
I don't fully understand the details of how this works, but I saw a similar issue with the same symptoms. For me, it was resolved by rearranging some initialization function calls.

When I do this in my setup routine, the SPI will get stuck in that while loop inside SPI.transfer:

Code:
    // putting this before the pinMode calls causes SPI to get
    // stuck in SPI.transfer's while loop
    SPI.begin();

    pinMode(pin_cs, OUTPUT);
    pinMode(pin_clk, OUTPUT);
    pinMode(pin_mosi, OUTPUT);
    pinMode(pin_miso, INPUT);

    // next 3 lines might be unnecessary
    SPI.setMISO(pin_miso);
    SPI.setMOSI(pin_mosi);
    SPI.setSCK(pin_clk);

I resolved that issue by changing the setup routine to the following:

Code:
    pinMode(pin_cs, OUTPUT);
    pinMode(pin_clk, OUTPUT);
    pinMode(pin_mosi, OUTPUT);
    pinMode(pin_miso, INPUT);

    // next 3 lines might be unnecessary
    SPI.setMISO(pin_miso);
    SPI.setMOSI(pin_mosi);
    SPI.setSCK(pin_clk);

    // it appears that this next line MUST come after the pinMode calls
    SPI.begin();

I'm using Teensy 4.1.

My pin variables are the default Teensy 4.1 values:

Code:
static const constexpr int pin_mosi = 11;
static const constexpr int pin_miso = 12;
static const constexpr int pin_clk = 13;
static const constexpr int pin_cs = 10;

I'm not 100% sure if this is actually the same issue you have, though.
 
Yes the pinMode lines effectively disable the teensy internal spi hardware.
If you do the spi begin later, it can use the pins...
 
Thanks Penny.

I've rearranged my setup to:
Code:
	pinMode(BUTTONCS, OUTPUT);
	AUXSPIBUS.setMISO(39);
	digitalWrite(BUTTONCS, 0);
	AUXSPIBUS.begin();

from

Code:
	AUXSPIBUS.begin();
	AUXSPIBUS.setMISO(39);
	pinMode(BUTTONCS, OUTPUT);
	digitalWrite(BUTTONCS, 0);
Hopefully that does something but I've not had a chance to check yet.

I have got by so far by doing a break if it spends too many loops in the while.

I hope to see if this works and report back.
 
Back
Top