bitluni / ESP32CompositeVideo

334 stars 59 forks source link

Even enabling PSRAM on boards that support it makes the signal lose sync #22

Open wgaylord opened 3 years ago

wgaylord commented 3 years ago

I have an ESP32 WROVER and I have found if I even enable PSRAM the system loses sync and the text slowly moves down the screen.

I am not sure as to why as the buffers should still be in main ram unless arduino-esp32 changed the functioning of malloc in respect to PSRAM lately.

wgaylord commented 3 years ago

I found that its specifically the -mfix-esp32-psram-cache-issue line required in the build_flags in platformIO to be the issue I suspect it is somehow affecting caching across all RAM.

wgaylord commented 3 years ago

Anyone have any idea? Could it be that I have to prevent the other core from running code except during blanking? (Like the cache is getting messed up or something.)

wgaylord commented 3 years ago

Also would it be better to continue using this or move over to the implementation in https://github.com/bitluni/ESP32Lib ?

ivorss commented 3 years ago

I was able get rid of the sync issue when using the PSRAM for the back buffer on a ESP32-WROVER-E. The idea is to use core 0 for all the rendering and core 1 to call sendFrameHalfResolution() in a loop.

Problem:

By default the ESP32 Arduino toolset runs setup() and loop() on core 1 of the ESP32. This forces us to use core 0 for calling sendFrameHalfResolution() in a loop. However any time the PSRAM is accessed core 0 is interrupted, which causes all kinds of sync issues. However core 1 is not interrupted, so to solve the problem we need to simply swap the two cores.

Solution:

I was not able to do this is in the Arduino IDE, so I used Eclipse + Sloeber which is much more powerful and flexible development environment. Here are the steps:

  1. Override extern "C" void app_main() so that setup() and loop() are no longer used and move the code to app_main(). This function always starts on core 0, which is what we want. On newer versions of the toolset you have to also undefine CONFIG_AUTOSTART_ARDUINO.
  2. Change the task that calls sendFrameHalfResolution() in a loop to run on core 1.
  3. In CompositeGraphics.init() allocate the back buffer using ps_malloc(). When swapping the buffers in CompositeGraphics.end() use memcpy() to copy the back buffer to the front buffer. Do not swap the pointers. From now on core 1 should never access the back buffer.
  4. At the end of app_main() create an infinite loop and move the code from loop() there. Also add delay(1) after draw().

Effects of the change:

  1. Increased the amount of free RAM by 66K when CompositeGraphics is 300x207.
  2. The framerate dropped from 166 FPS to 45 FPS.
wgaylord commented 3 years ago

Interesting, I will have to take a look. I have slightly moved on from using composite tho, (Currently using fabgl embed into micropython for VGA)