SPI CS pin rises too early

First time working with SPI and I am having an issue. So far SCK (GPIO 5) and MOSI (GPIO 3) are working. CS0 (GPIO 2) will go low initially, but after 8 clock cycles it will set itself to high, when I need it to stay low for 24 clock cycles in order to receive data from the MCP3008. Altering the the Frame Format Register’s length will change how long the CS pins stays low, but I can’t set it higher than 8 bits.

Picture from oscilloscope:

  • Yellow = SCK
  • Blue= CS

link to main.cpp here.

I am using a low level library - link here - that is very much in early development to interact with the Hifive1 Rev.B, so a bare bones solution would be appreciated.

Hi Gareth, Very good question you ask here. In the FE310’s SPI implementstion everything is byte-wise, thus 8 bits. There’s an undocumented option for setting multiple bytes per CS assertion - I’ll look this up and post here in a few days.
Alternately, you can always “disconnect” CS from the SPI block and put it to GPIO, thus doing pseudo bit-bang where you do your Chip Enable assertions manually.

First, I don’t think it’s a good idea to change csdef as this can result in a signal contention. Second, you write 3 bytes in a loop, but read only 2, this can result in RX FIFO overflow. Third, you set CSMODE to HOLD, this results in asserting CS before the first byte, and it stays asserted all the time. In general, you need to set CSMODE to HOLD before the first byte and set it to AUTO after the last byte.

Changed main.cpp to read rxdata every time txdata is written to and have set csmode to off.

Using GPIO results in the CS pin rising before the last clock goes low:

Using csdef fixes the issue:

Zoomed out:

But, as you said there is an issue with using csdef: on power up, UART reports ‘send flag errors’ from the WiFi module. After that though, everything appears to be fine as the data from the MISO pin is read, until several seconds later the voltage on the MISO pin drops to near zero and rxdata reads zero.

Pressing the reset button or re-flashing the chip results in the WiFi module now reporting everything is ok, but the ADC continues to output near zero voltage on the MISO pin. Removing power, then re-applying it gets the ADC outputting at a decent voltage, but again for only several seconds.

If you use a user-controlled CS, then you have to add a delay after the last byte, because the very last bit of the byte is received on a rising edge, so you can receive the whole byte before the trailing edge. Peripheral-controlled CS mode solves this problem for you.

@Disasm added a delay and it does cause the CS pin to rise after the last clock, but the MCP3008 MISO pin still outputs zeros with a voltage below 1V, several seconds from power being reapplied.

MISO with correct voltage output:

MISO seconds later:

@pds What is the undocumented option? It might help fix the issue.

Third, you set CSMODE to HOLD , this results in asserting CS before the first byte, and it stays asserted all the time.

@Gaz, I apologize for the long delay. The two undocumented fields relating to SPI operation are ‘extradel’ and ‘sampledel’. They may be able to help solve the issue you observe.

The SPI blocks at 0x10014000 , 0x10024000 , and 0x10034000 have two very important registers not shown in Chapter 19, Table 65 of the Manual:
extradel : 0x38
sampledel : 0x3c

You can see how these are implemented at the two git links here:
Implementation of sampledel and extradel adjustments to SPI
asic circuit code

Also, you probably are already aware of the missing descriptions for rhe GPIO settings for IOF control, defined in the src/drivers/sifive,gpio0.c file
#define GPIO_IOF_EN (0x38)
#define GPIO_IOF_SEL (0x3C)

The suggestion of @CoolJuniper to use CSMODE (and its conjugate pair to release the CS) is also an excellent idea.

These are three other useful discussions on the subject:
Freedom Metal Register Addresses Header File
FE310-G000 manual is missing the GPIO IOF mappings
SiFive FE310-G002 Manual v19p05 missing GPIO IOF mapping