Because of other integrations, I choosed not to work with PlatformIO even if I agree that the plain Arduino IDE is way too basic.
I am only using PlatformIO because I would not even call "Arduino IDE 1.x" an IDE and the 2.0 still has nothing that VSCode could not do better.
I tried to move your library to the plain Arduino and it was too tricky because of PlatformIO (compiler definitions are not supported by the Arduino IDE but only using the CLI).
Hmm, I had an intern for the last two weeks and I gave him an Arduino UNO and an EVE3-50G to play with.
I took my current example and after a little convincing it ran in Arduino IDE 1.8.19.
He used my archive with Arduino IDE 2.0.3 on his own notebook and apart from that the "IDE" killed the project a couple of times it worked fine.
Also, I am pretty much done. All I have to do is integrating the "low level" APIs with my own abstraction layer that allows to draw items using OOP and completely forget about commands and the underlying BT C APIs.
Well, you still could use my library as a reference point.
Everything works but I am trying to understand what does not work with flashing. Most of the issues I had is because of the very poor documentation. But after reading tons of posts here and examples, I am pretty sure that the code is ok (I also compared the flashing procedure to your code).
I was wondering why BT does not provide a clear documentation of these procedures. Even reading the BT IC datasheet I could not find exhaustive explanations.
Have you ever had problems with unreliable writing on the flash?
No, I can't recall that I ran into severe issues when I implemented the flash commands.
But then I am probably not a good reference here since I am doing this for a number of years now. :-)
One thing that is important when using these functions though and that is that the alignment requirements must be strictly followed.
This is why I added these to the comment on top of my functions:
/* This is meant to be called outside display-list building, it includes executing the command and waiting for completion, does not support cmd-burst.*/
/* write "num" bytes from src in RAM_G to to the external flash on a BT81x board at address dest */
/* note: dest must be 4096-byte aligned, src must be 4-byte aligned, num must be a multiple of 4096 */
/* note: EVE will not do anything if the alignment requirements are not met */
/* note: the address ptr is relative to the flash so the first address is 0x00000000 not 0x800000 */
void EVE_cmd_flashupdate(uint32_t dest, uint32_t src, uint32_t num)
{
eve_begin_cmd(CMD_FLASHUPDATE);
spi_transmit_32(dest);
spi_transmit_32(src);
spi_transmit_32(num);
EVE_cs_clear();
EVE_execute_cmd();
}
And yes, it took a few iterations to make the code this "simple". :-)
I am normally using CMD_INFLATE to get the data into RAM_G since especially fonts are usually highly compressable, probabably because they contain empty glyhps and because all glyphs need to be the same pixel size.
And then flashing from the host controller is not really meant for regular use, for a bigger project with several fonts and images I would flash the image file from EAB with a USB/SPI adapter.
I was forgetting one important info.
I carefully observed with the oscilloscope the timings of the ESP32 SPI using both ESP32-IDF (with and without DMA) and the Arduino SPI for ESP32.
The results are:
- The native ESP-IDF performance is poor (even using transactions) because there are lengthy gaps between every transmissions.
- The Arduino SPI library is much way faster.
In the ESP32-IDF forums I was told that the Arduino wrapper does NOT use the IDF abstraction APIs but goes directly to the ESP32 registers. They also said that the IDF library is typically much slower because Espressif wants to provide a stable abstraction over future silicons.
Oh? When did this change?
When I implemented the ESP32 Arduino code back in end of 2020 it was really really slow.
On a first test with the SPI class my ESP32 was running the display update in 1476µs while the Arduino UNO
was running the exact same code in 516µs.
https://github.com/RudolphRiedel/FT800-FT813/issues/14The SPI class was running on top of ESP-IDF back then.
So I may need to try this again.
What I am not seeing in the current ESP32 SPI class is DMA support though.
And what I do see is that there is a heck of a lot of code that gets executed everytime in order to try to make the implementation bullet proof.
So even if it really is running faster it still is running with the handbrake engaged.
Update: I was able to reliably flash the display with the same code but changing cable.
Anyway, I always have to reboot the display (after flashing), otherwise the FLASH always stay in the "INIT" state and never changes.
How can I make the display flash transitioning from INIT to (at least) BASIC?
Is rebooting after flashing a mandatory action?
No, there is no need to put the flash thru the init state, it even should go thru the init automatically and reach BASIC state.
From my example, shortened a little:
void TFT_init(void)
{
if(E_OK == EVE_init())
{
EVE_memWrite8(REG_PWM_DUTY, 0x30); /* setup backlight, range is from 0 = off to 0x80 = max */
touch_calibrate();
#if 0
/* this is only needed once to transfer the flash-image to the external flash */
uint32_t datasize;
EVE_cmd_inflate(0, flash, sizeof(flash)); /* de-compress flash-image to RAM_G */
datasize = EVE_cmd_getptr(); /* we unpacked to RAM_G address 0x0000, so the first address after the unpacked data also is the size */
EVE_cmd_flashupdate(0,0,4096); /* write blob first */
if (E_OK == EVE_init_flash())
{
EVE_cmd_flashupdate(0,0,(datasize|4095)+1); /* size must be a multiple of 4096, so set the lower 12 bits and add 1 */
}
#endif
if (E_OK == EVE_init_flash())
{
EVE_cmd_flashread(MEM_FONT, 84928, 320); /* copy .xfont from FLASH to RAM_G, offset and length are from the .map file */
}
...
}
This code assumes that the flash is completely empty and it does not bother to check the state of the flash first since there practically is no way
that a correctly attached flash is not in state BASIC at this point, especially not after full initialization of the display.
The first 4k contain the binary blob that is necessary to put the flash into state FULL so this is flashed first.
After that my EVE_init_flash() function is called to put the flash into state FULL - and it does a whole lot more than just that, have a look.
If the flash was sucessfully initialized to state FULL the whole image is flashed with CMD_FLASHUPDATE.
The next call to EVE_init_flash() is only there as the block that flashes the image can be commented out after the first time.
So even on a first run with flash update active this just runs thru, no need for a reset at all.
And the only reason I am doing this in two steps is that writing to the flash is a lot faster in state FULL.
If the flash is viable then REG_FLASH_STATUS automatically indicates state BASIC after power-up and from there you can use CMD_ FLASHERASE, FLASHWRITE, FLASHUPDATE, FLASHPROGRAM, FLASHREAD and FLASHDETACH.