[SOLVED]: Compile errror when using SPI.transfer with DMA of const array

I have a 240x240 picture for a display, 115,200 bytes. I know, it’s huge and I should store it externally.
I can’t store it in RAM, so I declare it as const:

const uint8_t Bitmap[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,.....

The program works if I use single byte transfers over SPI. This is too slow, so I implemented DMA.

SPI.beginTransaction(SPISettings(30*MHZ, MSBFIRST, SPI_MODE0));
digitalWrite(dc, HIGH);
digitalWrite(cs, LOW);
SPI.transfer(Bitmap, NULL, sizeof(Bitmap), NULL);
digitalWrite(cs, HIGH);
SPI.endTransaction();

The compiler (WebIDE) gives me this error:
invalid conversion from 'const void*' to 'void*' [-fpermissive]

I tested the code above with a smaller buffer in RAM, declared as:

uint8_t Bitmap[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,.....

This compiles fine and I get the faster transfer speed.

I don’t understand the type conversion issue.
Does SPI DMA support transferring data from Flash?
Running on Photon with OS 1.5.2

I also learned that I cannot change the contents of Flash during run time (compiler error). I guess it makes sense since it is declared as const. Are there ways of doing this?

No. You cannot write the flash during the runtime. The flash area is write protected during the app runtime. The protection is turned off during the flash process.

1 Like

It should work. Just cast it to the correct type but you cannot change the contents at run time.

SPI.transfer((void*)Bitmap, NULL, sizeof(Bitmap), NULL);

BTW, the way you are transferring the data is not making full use of the DMA capabilities. If you provided a callback function your other code could move on while the data is transferred in the background.

If I recall correctly, you should be able cast away the const on Gen 2 (STM32F205) devices like the Photon as ScruffR suggested.

On Gen 3 devices (nRF52840) the MCU cannot DMA transfer directly out of flash which is why the read parameter (which is not modified) is not declared const in the prototype.

Or at least that’s what I remember about how it works. That may not be completely correct.

@Pescatore

This is also resolved in 3.0.0-beta.1: Gen3: SPI.transfer() supports accepting const void* parameter. by XuGuohui · Pull Request #2196 · particle-iot/device-os · GitHub

  1. SPI.transfer() now takes const void* for TX buffer
  2. Gen 3 devices will automagically copy data into RAM if needed in chunks and DMA out of it
3 Likes

Aaaaaah, the parenthesis!! I tried casting, but forgot the parenthesis around void. Rookie mistake.
It’s working now. Thank you.

Thanks for the tip about the callback. I was trying so many things and wanted to keep it simple.
Besides the asynchronicity, is the intent to set a flag in the callback to tell when the transfer is done?

1 Like

Thanks for the info. Does this mean I still have to type cast for non const type, or is it an override?

Starting with 3.0 you won’t have to cast manually at all, as const void* argument type can accept both const pointers and non-const.

1 Like

This is one thing you’d do in there. Another would be to release the SlaveSelect pin - either in side the callback or as first action once the “transferDone” flag is set.

Got it. Thank you all for responding so soon.