SPI Hifive 1 Rev B

I am working with the Hifive 1 rev B, the main aim is to communicate with the ESP32 Chip on the Board using SPI. The example code that is available with the Freedom e SDK, is not working for me. I tried to debug the code and it seems stuck in a loop. How do i setup a working demo of SPI on Hifive 1B?
I just started working with the Borad, this is completely new for me. so please advice.

I am also experiencing this issue. Program hangs on ā€œmetal_spi_transfer(spi, &config, 3, tx_buf, rx_buf);ā€.

If someone reading this is working in Sifive, please hire a human to maintain and make sample programs. The included samples have problems. At least finaly thanks for led blinking demo fix. And please, restore Arduino IDE support or at least software support like in Hifive1. My Hifive revb board is currently an expensive paper weight. I canā€™t do anything meaningful without software samples and libraries.

2 Likes

Iā€™m not from SiFive, but in Rust community we do have working examples for this board: https://github.com/riscv-rust/riscv-rust-quickstart/tree/master/examples
Everyone is welcome to try this out :slight_smile:
If you are new to Rust, you can start here or here.

I barely got any of the sifive examples to work. I use the rust stuff because it actually works and its pretty easy to get started.

Canā€™t believe one has to learn a new programming language altogether to use a Microcontroller Board !!!

You do not have to. Rust is not forced or even officially supported by SiFive, itā€™s just a nice alternative.

Hi I am also facing the same problem. Please provide some help.

Hi, Iā€™m also trying to figure things out and can only find these threads. One step I figured out is that the default freedom-e-sdk repo clone ends up in an ā€˜oldā€™ branch from May. In this branch only SPI(0) is available! You need to go to the bleeding edge such that you can spi = metal_spi_get_device(1);
From there I havenā€™t been able to get a sensible response yet from the ESP32, but I believe you need to send the characters ā€˜AT\r\nā€™ as an initial message.

I donā€™t think itā€™s mandatory. At the same time, I had some observations of WiFi module behavior and noticed that two things are mandatory:

  1. CS to packet time should be small. This means that itā€™s better to use hardware-controlled CS)
  2. Delay between bytes in packet should be avoided. This means that you should prepare your packet in advance and use SPI FIFO to prevent underflows.

Also remember that SPI communication with ESP32 uses its own protocol (not just sending character bytes back and force).

Interesting indeed. Have you found the actual protocol description anywhere? Iā€™ve tried to read the ESP slave driver code but I havenā€™t been able to figure it out. Somewhere I saw some code where first a send or revc byte is sent, then the size, and then the message. But that didnā€™t work for me.

I havenā€™t seen any protocol description, so I had to reverse-engineer it. In this protocol each send or recv is a 3-packet sequence (ā€œI want to send/recvā€, ā€œdata length is yā€, ā€œactual dataā€). ESP32 also uses ā€œhandshakeā€ pin to signal its readiness.

1 Like

Thanks, did you figure out in more detail? Are they first two packets indeed 4 bytes? And are they LSB?

I set gpio 10 to input (I believe that is the handshake pin), but I also believe pgio 9 is a chip enable pin? Do I need to turn that on as well?

Btw, I saw in the slave driver somewhere that only 512 byte packages were possible, which might result in the small packets you observed.

I used a logic analyzer to analyze packet exchange during the boot stage (bootloader talks to ESP32 4 times or so). First two packets contain exactly 4 bytes. First packet is 01 00 00 00 (for recv) or 02 00 00 00 (for send). The second packet contains data size to transfer (in little endian): XX 00 00 41 for send and XX 00 00 42 for recv. The third packet contains actual bytes and nothing else.
Note that SPI performs data transfer in both directions at the same time, so, for example, if you want to receive data size packet from ESP32, you also have to send 4 bytes of garbage. The same for the last packet.

1 Like

Thanks so much for the info. Iā€™m trying to apply it but still not sure about some things. In the read response, who writes the values? Is the slave supposed to reply with 02 ā€¦ etc? I tried to use this approach but no success yet: https://gist.github.com/marijnfs/61af97c2ecdd9b1076486bcaa513051a

I believe this printf can break timings, which are important here:

  1. for reading data you should send 01 00 00 00 command, not 02 00 00 00
  2. In the second packet you will receive the length of the data available. You should use it for the third packet (send N zero bytes, receive N data bytes).
1 Like

Thanks, good idea. However removing printf doesnā€™t seem to help. There seems to be some more disccusion here: HiFive1 Rev. B - How to use Wifi? How to get/set CPU clock speed?

So this handshake protocol carries the AT command strings as its payload? I suppose that it is not guaranteed that each data packet contains exactly one AT commndā€¦

In that code, after the AT string has been sent, there are another two more SPI operations that do a ā€˜sendā€™ of zero bytes. Is that a necessary part of the protocol to indicate that all of the data has been transfered?

The ping-pong nature of this exchange is part of how SPI works. But the SPI specification is just for a bidirectional bitstream - the format of the data is up to the device maker, in this case Espressif, the maker of the ESP32-SOLO-1. So far I have been unable to find this protocol documented, but am asking in the Espressif support forums.

I believe that another two operations are first two packets of recv.

The relevant code on ESP32: https://github.com/espressif/esp-at/blob/master/main/interface/hspi/at_hspi_task.c I used this to understand the protocol.

In esp-at-master/examples/at_spi_master_for_esp8266/main/app_main.c I find these definitions:

/* SPI data cmd definition */
#define SPI_MASTER_WRITE_DATA_TO_SLAVE_CMD     2
#define SPI_MASTER_READ_DATA_FROM_SLAVE_CMD    3
 /* SPI status cmd definition */
#define SPI_MASTER_WRITE_STATUS_TO_SLAVE_CMD   1
#define SPI_MASTER_READ_STATUS_FROM_SLAVE_CMD  4

Close, but not quite what you are seeing. So far I have been unable to find code that actually generates the patterns you observe. For example, what is the purpose of the 0x41 and 0x42?