SPI Slave Select glitch after first byte of first transfer

Hi,
I am using the BW16 to relay a data stream received from 5GHz wifi (in promiscuous mode) to the SPI. Each packet is about 400 bytes. I use a handshake line from the SPI receiver to acknowledge each transfer.
My development environment is Arduino SDK 3.1.5 and I am currently using the Arduino SPI.h library.

The picture below is a general view of the SPI activity, here showing 8 packets.

However, as the Handshake line shows, there has been something weird happening on the very first edge of the Slave Select (here called HSPI_CSn). Below is a zoom on this first edge:

SPI_glitch

What it shows is a short Slave Select glitch occurring just after the first byte, just 250 ns wide here, but can be as wide as 1.2 µs. Because of this, the entire packet is corrupted and lost.

As I was using SPI in mode 0, I first thought this was a misbehavior of the hardware logic that allows Slave Select to toggle between each byte, as described in UM400 §19.2.1.1. As this mechanism is specific to Clock Phase (SCPH)=0, I then switched to mode 1, i.e. SCPH=1. Unfortunately the behavior is the same, and the glitch remains.

Weirdly enough, this situation is not permanent. I can have entire sessions without the glitch, whether in mode 0 or mode 1. And other sessions where the glitch won’t disappear, even after software updates and reboots. Unfortunately until now I have not been able to identify a deterministic method to make it appear.

From the SPI.h library I cannot play with the raw SDK’s SSI_SetSSTogglePhase() function, because I have no hook to SPIClass::pSpiMaster. Even then, I doubt it would solve my problem, because the SSTOGGLE bit of the RTL8720’s CTRLR0 register is already initialized to SPI_SS_NOT_TOGGLE, which means that SPI supports continuous transfers without toggling Slave Select in mode 0.

Now I’m a little bit stuck in the dark. Any help appreciated !

Cheers,
Xavier

Hey @xsutter,
I am also using BW16 to receive data steams over wifi and save them to an external SPI flash (W25Q64) and had a lot of problems with the SPI Library functions.
For me only spi functions that take the chip select as an input work properly, so:

//works properly
byte transfer(byte _pin, uint8_t _data, SPITransferMode _mode = SPI_LAST);
//e.g
SPI.transfer(PA15, 0x06, SPI_LAST);

//does NOT work
byte transfer(uint8_t _data, SPITransferMode _mode = SPI_LAST);

They should be doing the same thing, since PA15 is the standard CS Pin, but it only works like this for me; I hope this helps you.

Greetings,
mxv3a

Hi @mxv3a,
Thanks for your interesting remark.
What you describe is quite strange, because from the SPI.cpp source code it appears that if the Slave_Select pin you specify is the default pin (PA15 in the BW16), both functions should be strictly identical. Only in the case the pins differ, does the

byte transfer(byte _pin, uint8_t _data, SPITransferMode _mode = SPI_LAST);

function control the SS pin by software:

if (_pin != pinSS) {
    pinMode(_pin, OUTPUT);
    digitalWrite(_pin, 0);
}

while (!(HAL_READ32(spi_addr, 0x28) & 0x0000002));
HAL_WRITE32(spi_addr, 0x60, (_data & 0xFFFF));
while (!(HAL_READ32(spi_addr, 0x28) & 0x0000008));
d = HAL_READ32(spi_addr, 0x60);

if ((_pin != pinSS) && (_mode == SPI_LAST)) {
    digitalWrite(_pin, 1);
}

Unless the object code in the Realtek library actually differs from the source…

Anyway, I just found another way to eliminate the glitch I described in my initial post. Since the SPI.transfer() call is non-blocking, I had to follow it with a delay long enough to cover the duration of the transfer:

SPI.transfer(*buf, length);       // This call is non-blocking
delayMicroseconds(transfer_duration); 

This apparently solved my problem.

1 Like