SPI too slow for a simple LED?

I am trying to write a simple driver for the WS2812B. Like a lot of other implementations mine tries to use the SPI. I push 3 SPI bits for every color bit. Either 110 (HIGH) or 100 (LOW). In the 8 bit RGB color space this makes 72 bits, hence 9 bytes to be sent over MOSI. (The 10th byte is there to get the bus HIGH again avoiding a RESET.) Unfortunately, already at a clock speed of 100 kHz I experience clock stretching between bytes, since there is no DMA. So, I am afraid the chip won’t eat it. Is there a way to implement this differently?

10 kHz clock speed, 60 MHz CPU speed, bits come out nicely

100 kHz clock speed, 320 MHz CPU speed, clock stretching

Actually, you would need a clock speed around 2.5 MHz to satisfy the requirements in the datasheet.

You should use SPI FIFO properly if you want to achieve back-to-back writes. I think it’s possible to achieve the required speed and even more.
Also note that building without optimizations may slow down your code and produce unwanted delays.

1 Like

Well, I am using Freedom Metal. buf contains all the data. Responsible for the transfer is only this command.

metal_spi_transfer(spi, &ws2812b_standard_spi_config, data_len, buf, NULL);

The problem, up to my knowledge, is, that the SPI HW does not support DMA, right? I need the CPU to fill the 8 bit SPI TX register. How can I turn on which optimizations?

Looks like this metal_spi_transfer implementation is quite inefficient. You may want to write your own one.
There is no DMA in FE310, yes.
I don’t know how to turn on optimizations in your case (it depends on a build system you use), but you can check in the command line that your code is compiled with -O or -O2 gcc option flags.

1 Like

I’ve just checked my Rust SPI example and it works on 8MHz SPI without any problems (CPU speed is 320MHz). So at least it’s possible with a correct SPI FIFO usage.
UPD: same for 8MHz SPI and 64MHz CPU

1 Like

Here is the working example in Rust: https://github.com/Disasm/fast_spi/blob/master/src/main.rs

1 Like

Thanks for proving that point. Although, I have not seen your MOSI signal :slight_smile: In freedom-e-sdk you can tune the optimization in release.mk and debug.mk respectively, as I learned now. I am at the point where I am questioning my new Chinese scope, because the data also does not make any sense. However, I have an OLED screen attached, which displays, what I want. And as far as I know there is 0 FEC involved, so something is wrong here. I will check the waveform at the bureau tomorrow.

Where is the source code to the Rust SPI driver?

I generated an array of bytes here and send it in a loop with a delay between sends. I confirmed with logic analyzer that there are no gaps between bytes and bytes sent are the same as in the buffer.

Here is the source code of the relevant part of the driver: https://github.com/riscv-rust/e310x-hal/blob/a0fa7d0a5c0792d4b3253df58ebbb3f184f26e9e/src/spi.rs#L283-L313