DMAMEM and malloc() how to use with DMA?
I know I have been over some/most of this before, but it keeps coming up and I am not really sure of what approaches people are expecting to do with these types of memory allocations on the T4...
So far I believe DMAMEM stands for: make it a pain in the a.. to use with DMA
a) DMA out of memory (example to MOSI), will not see any data that changed in the cache so it gets stale information
b) DMA into memory (example MISO to mem) will go directly into RAM, but memory reads will go to cache again old data...
Example suppose you have a display: example ST7789 240x320 pixel display. So you have a frame buffer of 240*240*2 bytes = 153600 bytes. And you setup your frame class to go into continuous update mode using DMA. This will require lets say 3 DMASettings to be chained to each other with lets say 51200 bytes output each... Sort of besides the point, but is the state of st7789_t3 code in my fork/branch
Now I sort of make the assumption that you turned on continuous updates as you are actually wanting to update it... Note: currently when you write to memory in this memory range, it goes through a cache, which great for speeding things up, BUT DMA goes through always reading from the real memory, which may be stale and show the old stuff...
So currently my display driver, when it finishes a frame it tries to force the cache to flush into real memory.
Hack for address range: if ((uint32_t)_pfbtft >= 0x20200000u) arm_dcache_flush(_pfbtft, _width*_height*2);
Which sort of works.
Note: that same DMA ISR also increments a frame count... Now suppose my mainline program has:
Code:
void testContinuousUpdate() {
elapsedMillis emu = 0;
Serial.println("Start Continuous update test");
tft.fillScreen(ST7735_RED);
tft.updateScreenAsync(true);
Serial.println("After updateScreenAsync");
while(tft.frameCount() < 10) {
if (emu > 500) {
emu = 0;
Serial.printf("Frame count: %d\n", tft.frameCount());
}
}
tft.fillScreen(ST7735_GREEN);
while(tft.frameCount() < 20) ;
tft.fillScreen(ST7735_BLUE);
while(tft.frameCount() < 30) ;
tft.fillScreen(ST7735_RED);
tft.drawRect(0,0, tft.width(), tft.height(), ST7735_BLUE);
tft.setCursor(10, tft.height() / 2 - 4);
tft.printf("R:%d W:%d H:%d", rotation, tft.width(), tft.height());
while(tft.frameCount() < 35) ;
Serial.println("Finished all frames");
tft.endUpdateAsync();
Serial.println("After call to endUpdateAsync");
while (tft.asyncUpdateActive());
Serial.println("Test completed");
}
Now suppose we get to frame 10 and we are fill the screen with GREEN (was RED)
Note the fillScreen will simply iterate and write the color green to all of the memory locations....
OK so far, except: You will likely see some splotchy output, as some of the writes stay in the cache and some make it through RAM which shows up in that screen update.
The interesting questions include, what should I do about this?
I could in cases like this, maybe have all three of my DMASettings fire an interrupt, could also have them fire interrupt at mid point... Could then in cases like this or maybe showing simple movie frames, then have the code synchronize itself to wait until lets say the top third of a frame displays and fill in that third, then when second third completes update that third....
But that is more problematic if you wish to more general graphics.
Could maybe try to setup to double buffer. and maybe have the system copy current buffer code is using into secondary memory that the DMA actually outputs from...
BUT I keep wondering how many hoops code like this should jump through?
Maybe again DMAMEM - should be defined to be - Good to use for DMA?
Maybe a new define FASTMEM or CACHEDMEM or ... that has the cache enabled?
Wondering if when linking sections in upper memory could be setup, that if the user did define DMAMEM, that section would be created and use up the sizes requested of the upper memory and then the rest could be allocated to cached?
Thoughts? What am I missing?