When you are looking (like me) for a SPI Slave implementation on Teensy 4.1...
(all the code provided by PJRC, Arduino, looking in Internet says: "just SPI master is supported")
Based on tonton81's approach: https://github.com/tonton81/SPISlave_T4 - I could bring up
this SPI Slave to work (but it needs some modifications, see attached ZIP with my code and sketch).
How does it work?
It configures some MCU registers directly (the mode for SPI), so it goes to the MCU Config registers for SPI, directly!
It sets an ISR handler for the SPI: so, the SPI slave runs in INT-mode (not DMA).
The format for SPI (e.g. SPI mode, LSB vs. MSB first) is fix and hard-coded (but could be changed, if you use the RT1062 reference manual, knowing which register to write with what).
Strange is just: the H-file includes the "SPISlave_T4.tpp" file (the CPP source code, but not as *.CPP file). Changing to use as CPP instead fails with compile error.
(maybe somebody could fix to have real *.H and *.CPP files).
So, the entire code comes via this "SPISlave_T4.h" included, including also this "SPISlave_T4.tpp" (watch the file extension not as *.CPP).
My example code works this way:
The ISR places all the received SPI Slave bytes into a shared buffer.
The buffer index keeps incrementing (so, the buffer is filled with the received bytes on SPI Slave input, every ISR called for a complete Rx bytes fills the buffer in ISR).
When the PCS comes, the SPI Slave Select signal (CS, SS) comes (this is enabled now as ISR trigger!) - it sets a flag so that main thread (loop) can realize the SPI Rx has completed (the deactivation of SPI CS was there).
Print all the received bytes, reset the notification flag and also the buffer index (a handshake between main() and ISR(), write from start again on next SPI Rx transaction).
The original implementation has some flaws, e.g.:
- the handling of the PCS signal (SPI Chip Select, CS) plus/as "Frame Complete Flag" (PCS goes high) was not enabled, not working (the order of bytes received were wrong, the logic was wrong).
- the ISR keeps looping inside the ISR ("not nice") and uses also Serial.print() calls inside ISR (it slows down the performance, dramatically)
- so, the maximum speed was limited to the USB VCP speed, so, just 1 MHz SPI was working (doing printfs or Serial in an ISR is not a "smart idea", esp. if USB VCP tickles out with 1 KHz clock)
- the order and number of received bytes was wrong (the logic inside ISR was wrong, because it has not really acted on "Frame Complete" (PCR))
I could improve and fix some issues:
- it runs now up to 22 MHz generated by a SPI master (faster fails with wrong number of bytes received or the order is wrong)
Important:
the original code and even my one use still the "swapped pin mapping":
So, the input as MOSI is located on the MISO Teensy 4.1 pin (as MISO, pin number 12)!
(a bit strange, because MOSI remains MOSI, per definition, never mind if slave or master)
So, if you are looking for a SPI Slave for Teensy 4.1... - give it a try.
(all the code provided by PJRC, Arduino, looking in Internet says: "just SPI master is supported")
Based on tonton81's approach: https://github.com/tonton81/SPISlave_T4 - I could bring up
this SPI Slave to work (but it needs some modifications, see attached ZIP with my code and sketch).
How does it work?
It configures some MCU registers directly (the mode for SPI), so it goes to the MCU Config registers for SPI, directly!
It sets an ISR handler for the SPI: so, the SPI slave runs in INT-mode (not DMA).
The format for SPI (e.g. SPI mode, LSB vs. MSB first) is fix and hard-coded (but could be changed, if you use the RT1062 reference manual, knowing which register to write with what).
Strange is just: the H-file includes the "SPISlave_T4.tpp" file (the CPP source code, but not as *.CPP file). Changing to use as CPP instead fails with compile error.
(maybe somebody could fix to have real *.H and *.CPP files).
So, the entire code comes via this "SPISlave_T4.h" included, including also this "SPISlave_T4.tpp" (watch the file extension not as *.CPP).
My example code works this way:
The ISR places all the received SPI Slave bytes into a shared buffer.
The buffer index keeps incrementing (so, the buffer is filled with the received bytes on SPI Slave input, every ISR called for a complete Rx bytes fills the buffer in ISR).
When the PCS comes, the SPI Slave Select signal (CS, SS) comes (this is enabled now as ISR trigger!) - it sets a flag so that main thread (loop) can realize the SPI Rx has completed (the deactivation of SPI CS was there).
Print all the received bytes, reset the notification flag and also the buffer index (a handshake between main() and ISR(), write from start again on next SPI Rx transaction).
The original implementation has some flaws, e.g.:
- the handling of the PCS signal (SPI Chip Select, CS) plus/as "Frame Complete Flag" (PCS goes high) was not enabled, not working (the order of bytes received were wrong, the logic was wrong).
- the ISR keeps looping inside the ISR ("not nice") and uses also Serial.print() calls inside ISR (it slows down the performance, dramatically)
- so, the maximum speed was limited to the USB VCP speed, so, just 1 MHz SPI was working (doing printfs or Serial in an ISR is not a "smart idea", esp. if USB VCP tickles out with 1 KHz clock)
- the order and number of received bytes was wrong (the logic inside ISR was wrong, because it has not really acted on "Frame Complete" (PCR))
I could improve and fix some issues:
- it runs now up to 22 MHz generated by a SPI master (faster fails with wrong number of bytes received or the order is wrong)
Important:
the original code and even my one use still the "swapped pin mapping":
So, the input as MOSI is located on the MISO Teensy 4.1 pin (as MISO, pin number 12)!
(a bit strange, because MOSI remains MOSI, per definition, never mind if slave or master)
So, if you are looking for a SPI Slave for Teensy 4.1... - give it a try.