I was having some issues communicating with an ENC28J60 Ethernet controller on Teensy 4.0 using SPI.
At seemingly random intervals, the most significant bit of an octet would get transferred incorrectly, causing the controller to malfunction.
Once I analysed the SPI communication, I noticed that, if the first SI bit is supposed to be a 0, the Teensy pulls SI low on the first rising edge of the clock.
Since I have my SPI configuration set to mode 0 (which is what the Ethernet controller requires), this is too late,
because the ethernet controller will sample SI on the rising edge of the clock - right as it's in the process of switching from high to low.
Because of this, for the same byte, it sometimes reads the first bit as a 0, other times as a 1.
Curiously, this only happens with the most significant bit. All other bits correctly switch state on the falling edge.
I used the following code to reproduce the problem:
Recording the output of this program with a logic analyser shows this:
As you can see, SI goes low on the first rising edge, but after that, all remaining bits are switched on the falling edge.
The diagram below is from the ENC28J60 datasheet, which shows that MOSI already needs to be high/low before the first rising edge of the clock passes.
I am unsure what causes this, and I am wondering whether I am doing something wrong here, if I have bad hardware, or if this is a bug in Teensyduino (I am using Teensyduino 1.51 with Arduino IDE 1.8.12 on Windows).
At seemingly random intervals, the most significant bit of an octet would get transferred incorrectly, causing the controller to malfunction.
Once I analysed the SPI communication, I noticed that, if the first SI bit is supposed to be a 0, the Teensy pulls SI low on the first rising edge of the clock.
Since I have my SPI configuration set to mode 0 (which is what the Ethernet controller requires), this is too late,
because the ethernet controller will sample SI on the rising edge of the clock - right as it's in the process of switching from high to low.
Because of this, for the same byte, it sometimes reads the first bit as a 0, other times as a 1.
Curiously, this only happens with the most significant bit. All other bits correctly switch state on the falling edge.
I used the following code to reproduce the problem:
Code:
#include <SPI.h>
SPISettings spi0(1000000, MSBFIRST, SPI_MODE0);
void setup()
{
SPI.begin();
}
void loop()
{
SPI.beginTransaction(spi0);
SPI.transfer(0x0D);
SPI.endTransaction();
delay(500);
}
Recording the output of this program with a logic analyser shows this:
As you can see, SI goes low on the first rising edge, but after that, all remaining bits are switched on the falling edge.
The diagram below is from the ENC28J60 datasheet, which shows that MOSI already needs to be high/low before the first rising edge of the clock passes.
I am unsure what causes this, and I am wondering whether I am doing something wrong here, if I have bad hardware, or if this is a bug in Teensyduino (I am using Teensyduino 1.51 with Arduino IDE 1.8.12 on Windows).
Last edited: