cancel
Showing results for 
Search instead for 
Did you mean: 

Strange internal FLASH reading after sector erase.

iTTy
Associate III

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!

iTTy_0-1706202595688.png

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

1 ACCEPTED SOLUTION

Accepted Solutions
iTTy
Associate III

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!

View solution in original post

9 REPLIES 9
AScha.3
Chief III

Just as a test : disable (or not enable) caches , at least D-cache. Then try again.

If you feel a post has answered your question, please click "Accept as Solution".

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.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
TDK
Guru

+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.

If you feel a post has answered your question, please click "Accept as Solution".
iTTy
Associate III

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.

iTTy_1-1706264458340.png

No way! I should understand how to manage the cache!

> 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);

If you feel a post has answered your question, please click "Accept as Solution".
iTTy
Associate III

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?

 

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" .

If you feel a post has answered your question, please click "Accept as Solution".
Pavel A.
Evangelist III

@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.

 

iTTy
Associate III

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!