2024-01-25 09:22 AM
Hi there!
Experimenting FLASH reading/writing I done a fanny test that is giving an unexpected (to me) result.
Basically:
1) I defined 2 32 bytes buffers (aRbuff for read, and aWbuff for write)
u32t aWbuff[8U] = {
0x00010203, 0x04050607, 0x08090A0B, 0x0C0D0E0F,
0x10111213, 0x14151617, 0x18191A1B, 0x1C1D1E1F
};
volatile u32t aRbuff[8U] = {0};
2) I implemented my read, write and erase function and i integrated them into the main infinite loop
if(bIsErase == TRUE)
{
EraseFLASHsectors(uiADRtest, uiSect2Erase);
bIsErase = FALSE;
}
if(bIsWrite == TRUE)
{
printf("Writing FLASH memory...\r\n");
WriteFLASHdata(uiADRtest, aWbuff, 32U);
bIsWrite = FALSE;
}
if(bIsRead == TRUE)
{
printf("\r\n");
printf("Reading flash...\r\n");
ReadFLASHdata(uiADRtest, aRbuff, 8U);
printf("0x%08X, 0x%08X, 0x%08X, 0x%08X,\r\n", aRbuff[0], aRbuff[1], aRbuff[2], aRbuff[3]);
printf("0x%08X, 0x%08X, 0x%08X, 0x%08X,\r\n", aRbuff[4], aRbuff[5], aRbuff[6], aRbuff[7]);
bIsRead = FALSE;
}
Writing a FLASH word and reading it back works fine, but if I perform a sector erase and then I read newly the FLASH location I get the pattern I write previously... It seems the erase hasn't done!
But if i reset the MCU and connect again, reading the location gives al 0xFFFFFFFF, so erase has been performed.
Since Im working on the M7 core of a stmH755ZI, I'm in doubt that is a problem of cache coherence, and I tryed to address it in software without luck.
Since sutch topic is just a little cryptic to me, anyone has an idea?
iTTy
Solved! Go to Solution.
2024-01-26 05:59 AM
Thank You guys for your support! Now I'm understanding better my mistakes!
Just as recap to give a solution for this topic:
In this case the trick is to perform a cache invalidation just after the FLASH sector/mass erase has been done
if(bIsErase == TRUE)
{
EraseFLASHsectors(uiADRtest, uiSect2Erase);
SCB_InvalidateDCache_by_Addr((void*)uiADRtest, 32);
bIsErase = FALSE;
}
Be aware that address used to invalidate/clean cache shall be 32 byte aligned; if not, SCB_CleanDCache_by_Addr and SCB_InvalidateDCache_by_Addr function could give trouble.
Hope this can help some other newbie like me!
2024-01-25 09:42 AM
Just as a test : disable (or not enable) caches , at least D-cache. Then try again.
2024-01-25 09:47 AM
Why wouldn't it be the cache? Either the architected one or the ST ART unit if present?
Your code doesn't show you doing anything to address that.
Should use the "DCache Invalidate by Address" after the FLASH write has completed.
2024-01-25 11:07 AM
+1 to potential cache issues.
Could also be that you're simply not erasing the memory you think you're erasing. Not enough information in your post to determine that.
2024-01-26 01:12 AM - edited 2024-01-26 02:28 AM
Hi everyone!
@AScha.3 :I done the test you suggested. Disabling (only) the data cache fix the problem, while disabling the instruction cache doesn't affect the reading behaviour.
@Tesla DeLorean : Actually i tried the cache management fix in another software branch (I posted only the original version giving the issue). I'm not using the ART.
@TDK : FLASH operation is validated through readings after MCU reset and through the test suggested by @AScha.3 .
Anyway, I tried several tests invalidating and cleaning the D cache without success. I always "pointed" to the reading buffer aRbuf.
This is because is not clear to me (in a nutshell)
1) What means clean or invalidate the cache
2) When clean or invalidate
3) On what operate...
Edit:
I done the tests that @Tesla DeLorean suggested (i invalidate the cache on aRbuf after FLASH writes)
if(bIsErase == TRUE)
{
EraseFLASHsectors(uiADRtest, uiSect2Erase);
SCB_InvalidateDCache_by_Addr((void*)aRbuff, 32);
bIsErase = FALSE;
}
if(bIsWrite == TRUE)
{
printf("Writing FLASH memory...\r\n");
WriteFLASHdata(uiADRtest, aWbuff, 32U);
printf("...writing Done;\r\ninvalidating D cache ...\r\n");
SCB_InvalidateDCache_by_Addr((void*)aRbuff, 32);
printf("Done!\r\n");
bIsWrite = FALSE;
}
if(bIsRead == TRUE)
{
printf("\r\n");
printf("Reading flash...\r\n");
ReadFLASHdata(uiADRtest, aRbuff, 8U);
printf("0x%08X, 0x%08X, 0x%08X, 0x%08X,\r\n", aRbuff[0], aRbuff[1], aRbuff[2], aRbuff[3]);
printf("0x%08X, 0x%08X, 0x%08X, 0x%08X,\r\n", aRbuff[4], aRbuff[5], aRbuff[6], aRbuff[7]);
bIsRead = FALSE;
}
but the behaviour doesn't change.
No way! I should understand how to manage the cache!
2024-01-26 01:58 AM - edited 2024-01-26 02:08 AM
> 1 > " invalidate the cache" = kick out some cache lines ( = delete this copy of memory in the cache )
> 2 > IF D-cache is active, you have to "tell" the cpu/cache controller , if someone else than the cpu (maybe you or a dma ) modified the memory, that is possibly copied and still hold in the cache; so cache/cpu still have some data, thats no more the same, as now in the "real" memory and you have to delete now the "old" copy in the cache.
> 3 > Always clean the cache after anybody else than the cpu itself modified the memory content.
If using the cache management, you have 3 possible ways to do:
1. switch off D-cache (my "test" , to prove : here is the problem.
2. use the MPU to define some memory area as "not to use by the cache"
3. use the cache maintenance : to clean or flush the cache ; little problem here: the cache has 32 byte lines,
so you have to clean always to next 32 byte aligned memory address:
example for 1024 B espinbuf ->
SCB_InvalidateDCache_by_Addr((uint32_t*)(((uint32_t)&ESPinbuf[0] & ~(uint32_t)0x1F)), 1024);
2024-01-26 03:45 AM
Sorry for insisting, but I have to understand!
Following the explanation of @AScha.3 , I clean the D-cache after sectors erase (using SCB_CleanDCache_by_Addr) then I invalidated the chache after FLASH reading (using SCB_InvalidateDCache_by_Addr). In both cases I "pointed" to the FLASH address, not at the reading buffer; because is the FLASH content that is changed by erasing.
It seems work!
Doing some tests more, trying some cleaning/invalidation strategies, I obtained that the only working solution is to invalidate the cache after readings or after erase. Cleaning the cache doesn't work!
What the difference between SCB_CleanDCache_by_Addr and SCB_InvalidateDCache_by_Addr?
2024-01-26 04:14 AM - edited 2024-01-26 04:17 AM
What the difference between SCB_CleanDCache_by_Addr and SCB_InvalidateDCache_by_Addr?
The direction !
If memory is changed, cache just to be deleted , its content is "wrong" now, its "invalid".
other direction: you calculate something with the cpu, maybe decoding some data and then want to send it out with the dma. Now dma uses the "real" memory (with the "old" data, only cpu has its cache with new data) , but you want the new calculated data in memory, to get the dma send this. Now need to "empty" the cache by writing out its content to the memory, so you make the "dirty" cache "clean" .
2024-01-26 05:07 AM
@iTTy To rephrase @AScha.3 : "clean" means write from the cache (CPU) to memory. After erase operation, you don't want to flush whatever happens to be in the cache back to the memory. On the contrary, you want to forget that and load the actual data from the memory back to the CPU. Unfortunately, with the present Cortex-M7 core of STM32 it is hard to avoid polluting the cache TL;DR so there's the need to discard (a.k.a. invalidate) it more often.
2024-01-26 05:59 AM
Thank You guys for your support! Now I'm understanding better my mistakes!
Just as recap to give a solution for this topic:
In this case the trick is to perform a cache invalidation just after the FLASH sector/mass erase has been done
if(bIsErase == TRUE)
{
EraseFLASHsectors(uiADRtest, uiSect2Erase);
SCB_InvalidateDCache_by_Addr((void*)uiADRtest, 32);
bIsErase = FALSE;
}
Be aware that address used to invalidate/clean cache shall be 32 byte aligned; if not, SCB_CleanDCache_by_Addr and SCB_InvalidateDCache_by_Addr function could give trouble.
Hope this can help some other newbie like me!