Teensy 3: SPI hangs at speeds other than 24 MHz

Status
Not open for further replies.

christoph

Well-known member
Hi,

whenever I set my SPI clock to a value other than 24 MHz, I see no activity on SCK. Here is the value I use for CTAR0:
Code:
SPI0_CTAR0 = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(0) | SPI_CTAR_BR(0)
Transfers are then initiated by writing to PUSHR, using these functions:
Code:
void spi_out_1(const uint8_t val)
{
  while (!(SPI0_SR & SPI_SR_TFFF)) // wait for space in FIFO
    ;
  SPI0_PUSHR = val;                 // write byte
  while(!(SPI0_SR & SPI_SR_TCF))   // wait for transfer complete
    ;
  SPI0_SR = SPI_SR_TCF;             // clear transfer complete flag
}

void spi_out_stream(const uint8_t val)
{
  while (!(SPI0_SR & SPI_SR_TFFF)) // wait for space in FIFO
    ;
  SPI0_PUSHR = val;                 // write byte
}

void spi_out_last(const uint8_t val)
{
  while (!(SPI0_SR & SPI_SR_TFFF)) // wait for space in FIFO
    ;
  SPI0_PUSHR = val | SPI_PUSHR_EOQ; // write byte (end of queue)
  while(!(SPI0_SR & SPI_SR_EOQF))  // wait for end of queue
    ;
  SPI0_SR = SPI_SR_EOQF;            // clear end of queue flag
}
This works on my breadboard, though I have serious doubts that a breadboard would allow such speeds. But the connected display does what I tell it to, and the onboard LED seems to be on (it must be flashing at an insane speed).

Whatever change I make to the SCK speed (enable double baud rate, different PBR, different BR), the display displays some garbage and the onboard LED seems to be off.

Has anyone else seen this behavior? What could be wrong in my setup or usage of the SPI?

Regards

Christoph
 
That may depend on what SPI frequency the data sheet for the display specifies. Usually they specify a max SPI frequency, but perhaps that's different. Your post does not provide much information to go by.
 
It's this display: http://www.adafruit.com/products/1431 and it uses an SSD1351 controller. The controller's datasheet specifies 20 MHz as the max SCK frequency (min clock cycle 50 ns).

To make this clear: I'm talking about the Teensy 3's onboard LED which is connected to SCK. When I unplug the display, the LED seems to be on when I have SPI transfers taking place and the SCK speed is at 24 MHz. With a lower speed, the LED is off.

I replaced all calls to SPI_out_stream() and the call to SPI_out_last() with calls to SPI_out_1(), which solved the problem. So my understanding of how the FIFO flags work must be wrong.
 
Indeed, my usage if the TX FIFO Fill Flag (SPI_SR_TFFF) was wrong. It is set by hardware when there is space in the FIFO, but not cleared when writing to the FIFO. It must be cleared by software after writing to the FIFO, but actually will not clear unless the FIFO is full. This resulted in a FIFO overflow during subsequent calls to SPI_out_stream(). So the correct functions for the SPI are now:
Code:
void spi_out_1(const uint8_t val)
{
  while (!(SPI0_SR & SPI_SR_TFFF)) // wait for space in FIFO
    ;
  SPI0_PUSHR = val;                 // write byte
  SPI0_SR = SPI_SR_TFFF;            // clear tx fifo fill flag
  while(!(SPI0_SR & SPI_SR_TCF))   // wait for transfer complete
    ;
  SPI0_SR = SPI_SR_TCF;             // clear transfer complete flag
}

void spi_out_stream(const uint8_t val)
{
  while (!(SPI0_SR & SPI_SR_TFFF)) // wait for space in FIFO
    ;
  SPI0_PUSHR = val;                 // write byte
  SPI0_SR = SPI_SR_TFFF;            // clear tx fifo fill flag
}

void spi_out_last(const uint8_t val)
{
  while (!(SPI0_SR & SPI_SR_TFFF)) // wait for space in FIFO
    ;
  SPI0_PUSHR = val | SPI_PUSHR_EOQ; // write byte (end of queue)
  SPI0_SR = SPI_SR_TFFF;            // clear tx fifo fill flag
  while(!(SPI0_SR & SPI_SR_EOQF))  // wait for end of queue
    ;
  SPI0_SR = SPI_SR_EOQF;            // clear end of queue flag
}
 
Status
Not open for further replies.
Back
Top