Hi All,
I have a strange issue, using an MPC5674 in VLE mode, when I write data to the 4Mb internal flash (not external flash) where I am intending it to be written is not where it is getting written.
Actual Address in red
000B8000 000B8004 000B8008 000B800C 000B8010 000B8014 000B8018 000B801C << Actual address in Flash
000B8010 000B8014 000B8008 000B800C FFFFFFFF FFFFFFFF 000B8018 000B801C << Data should have been written to this address
So what I set up was I just had a loop that incremented the write to address by 8 in total, wrote 2 x 4 bytes as per the rules of this flash and this is what I've ended up with.
Essentially all it is doing to writing the address value to the actual address in flash I am writing to. Eg, load address 0xB8000 and write that value to 0xB8000, then load address 0xB8004 and write that value to 0xB8004 and so on.
The first one, I was writing to address 0xB8000, but what was actually written was 0xB8010 meaning that data should have been written to 0xB8010, but it ended up at address 0xB8000 in the flash.
Then on the 0xB8010 and 0xB8014 in the flash there was nothing written at all (it should have contained the values 0xB8010 and 0xB8014) that is a mystery too.
This was the test code I ran (if it makes more sense than my description) - r8 was preloaded with 0xB8000.
e_li | r11,0 | |
add | r11,r11,r8 | ; Get address to write to |
e_stw | r11,0(r8) | ; Write address value to flash |
e_addi | r8,r8,4 | ; Increment write address for next pass |
e_li | r11,0 | |
add | r11,r11,r8 | ; Get address to write to |
e_stw | r11,0(r8) | ; Write address value to flash |
e_addi | r8,r8,4 | ; Increment write address for next pass |
This problem only happens on addresses above 0xA0000, eg if I write to address 0x90010 then the data is written to 0x90010, above 0xA0000 if I write to 0xA0010 the data ends up at 0xA0000.
Can anyone please give me a hint as to why the address I am telling the CPU to write to is not where the data ends up once above 0xA0000.
Thanks.
Hi,
I can't understand from your description what's going on. I would need to see whole function that was used to program the flash. I found this piece of working code in my repository for MPC5674F:
/* unlock M0 in flash array B */ |
FLASH_B.LMLR.R = 0xA1A11111;
FLASH_B.LMLR.R = 0x001203FF;
FLASH_B.SLMLR.R = 0xC3C33333;
FLASH_B.SLMLR.R = 0x001203FF;
/* erase M0 */
FLASH_B.MCR.B.ERS = 1;
FLASH_B.LMSR.R = 0x00010000; /* select M0 only */
*(unsigned int *)0x000C0000 = 0xFFFFFFFF; /* interlock write */
FLASH_B.MCR.B.EHV = 1; /* start erase */
while(FLASH_B.MCR.B.DONE == 0){}; /* wait for done */
FLASH_B.MCR.B.EHV = 0;
FLASH_B.MCR.B.ERS = 0;
/* program some data */
FLASH_B.MCR.B.PGM = 1;
*(unsigned int *)0x000C0000 = 0xAAAAAAAA; /* interlock write */
*(unsigned int *)0x000C0004 = 0xBBBBBBBB; /* interlock write */
FLASH_B.MCR.B.EHV = 1;
while(FLASH_B.MCR.B.DONE == 0){}; /* wait for done */
FLASH_B.MCR.B.EHV = 0;
FLASH_B.MCR.B.PGM = 0;
FLASH_B.MCR.B.PGM = 1;
*(unsigned int *)0x000C0008 = 0xCCCCCCCC; /* interlock write */
*(unsigned int *)0x000C000C = 0xDDDDDDDD; /* interlock write */
FLASH_B.MCR.B.EHV = 1;
while(FLASH_B.MCR.B.DONE == 0){}; /* wait for done */
FLASH_B.MCR.B.EHV = 0;
FLASH_B.MCR.B.PGM = 0;
FLASH_B.MCR.B.PGM = 1;
*(unsigned int *)0x000C0010 = 0xEEEEEEEE; /* interlock write */
*(unsigned int *)0x000C0014 = 0x11111111; /* interlock write */
FLASH_B.MCR.B.EHV = 1;
while(FLASH_B.MCR.B.DONE == 0){}; /* wait for done */
FLASH_B.MCR.B.EHV = 0;
FLASH_B.MCR.B.PGM = 0;
Thanks for the response Lukas, sorry for the explanation being a bit confusing, I'll try again.
Writing to the flash is no problem, I have that working just like you did above with the interlock writes, setting the EHV bit etc.
My problem is once I start to write data above the address 0xA0000 things are going bad.
Lets assume I have a RAM buffer that contains the 32 bit values 0, 1, 2 , 4, 5, 6, 7, 8 that I want to write to the Flash.
If I write that buffers contents to Flash address 0x80000 the data is written to the flash memory like this (yes this works).
0x80000 = 00000001
0x80004 = 00000002
0x80008 = 00000003
0x8000C = 00000004
0x80010 = 00000005
0x80014 = 00000006
0x80018 = 00000007
0x8001C = 00000008
But once I start to write to any address above 0xA0000 then the buffers data is not getting written to the flash in the correct order
0xA0000 = 00000005
0xA0004 = 00000006
0xA0008 = 00000003
0xA000C = 00000004
0xA0010 = FFFFFFFF (nothing written)
0xA0014 = FFFFFFFF (nothing written)
0xA0018 = 00000007
0xA001C = 00000008
So relating that back to your example, here is what would be happening for me when I read back what was actually written to the Flash.
Your System....
*(unsigned int *)0x000C0000 = 0xAAAAAAAA; | /* interlock write */ |
*(unsigned int *)0x000C0004 = 0xBBBBBBBB; | /* interlock write */ |
*(unsigned int *)0x000C0008 = 0xCCCCCCCC; | /* interlock write */ |
*(unsigned int *)0x000C000C = 0xDDDDDDDD; | /* interlock write */ |
*(unsigned int *)0x000C0010 = 0xEEEEEEEE; | /* interlock write */ |
*(unsigned int *)0x000C0014 = 0x11111111; | /* interlock write */ |
My system....
*(unsigned int *)0x000C0000 = 0xEEEEEEEE; | /* interlock write */ |
*(unsigned int *)0x000C0004 = 0x11111111; | /* interlock write */ |
*(unsigned int *)0x000C0008 = 0xCCCCCCCC; | /* interlock write */ |
*(unsigned int *)0x000C000C = 0xDDDDDDDD; | /* interlock write */ |
*(unsigned int *)0x000C0010 = 0xFFFFFFFF; | /* interlock write */ |
*(unsigned int *)0x000C0014 = 0xFFFFFFFF; | /* interlock write */ |
So the 0xEEEEEEEE you are writing to 0x000C0010 on my system ends up getting written to 0x000C0000 even though I am telling the CPU to write 0xEEEEEEEE to 0x000C0010.
My routine is very basic, just read from the RAM buffer and write back to Flash, looping until done...obviously I'm not showing all the interlock code as that is working because data is getting written.
; r8 = Address to write to in Flash
; r11 & r16 used to get data from buffer and write to flash
; r31 = RAM Buffer to get data from
; e_lwz r11,0(r31) ; Get data from Write buffer
; e_lwz r16,4(r31) ; Get data from Write buffer + 4
; e_stw r11,0(r8) ; Write data to flash
; e_stw r16,4(r8) ; Write data to flash + 4
Regards.
Copied from RM:
"The user can program the values in any or all of four words within a page in a single program sequence."
That means you can't program more than four words at once. You have to start next programming sequence.
FLASH_B.MCR.B.PGM = 1;
*(unsigned int *)0x000C0000 = 0xAAAAAAAA; /* interlock write */
*(unsigned int *)0x000C0004 = 0xBBBBBBBB; /* interlock write */
*(unsigned int *)0x000C0008 = 0xAAAAAAAA; /* interlock write */
*(unsigned int *)0x000C000C = 0xBBBBBBBB; /* interlock write */
//no more data can be written!!!
FLASH_B.MCR.B.EHV = 1;
while(FLASH_B.MCR.B.DONE == 0){}; /* wait for done */
FLASH_B.MCR.B.EHV = 0;
FLASH_B.MCR.B.PGM = 0;
If you need to program next data, repeat the sequence above like this:
FLASH_B.MCR.B.PGM = 1;
*(unsigned int *)0x000C0010 = 0xAAAAAAAA; /* interlock write */
*(unsigned int *)0x000C0014 = 0xBBBBBBBB; /* interlock write */
*(unsigned int *)0x000C0018 = 0xAAAAAAAA; /* interlock write */
*(unsigned int *)0x000C001C = 0xBBBBBBBB; /* interlock write */
//no more data can be written!!!
FLASH_B.MCR.B.EHV = 1;
while(FLASH_B.MCR.B.DONE == 0){}; /* wait for done */
FLASH_B.MCR.B.EHV = 0;
FLASH_B.MCR.B.PGM = 0;
Yes I understand that, I am in fact only ever writing 64 bits at a time. I just had your example laid out like that to help explain what is going on with the data not being written to the target address.
So I am actually doing this (note I am programming in VLE assembler, not C, but that is ok I can follow your code fine). Note all this is in a loop that writes 64bits at a time, if more data is needed to be written then it will loop back with the address of the buffer and write to flash incremented by 8.
FLASH_B.MCR.B.PGM = 1;
*(unsigned int *)0x000C0000 = 0xAAAAAAAA; /* interlock write */
*(unsigned int *)0x000C0004 = 0xBBBBBBBB; /* interlock write */
FLASH_B.MCR.B.EHV = 1;
while(FLASH_B.MCR.B.DONE == 0){}; /* wait for done */
FLASH_B.MCR.B.EHV = 0;
FLASH_B.MCR.B.PGM = 0;
FLASH_B.MCR.B.PGM = 1;
*(unsigned int *)0x000C0008 = 0xAAAAAAAA; /* interlock write */
*(unsigned int *)0x000C000C = 0xBBBBBBBB; /* interlock write */
FLASH_B.MCR.B.EHV = 1;
while(FLASH_B.MCR.B.DONE == 0){}; /* wait for done */
FLASH_B.MCR.B.EHV = 0;
FLASH_B.MCR.B.PGM = 0;
FLASH_B.MCR.B.PGM = 1;
*(unsigned int *)0x000C0010 = 0xAAAAAAAA; /* interlock write */
*(unsigned int *)0x000C0014 = 0xBBBBBBBB; /* interlock write */
FLASH_B.MCR.B.EHV = 1;
while(FLASH_B.MCR.B.DONE == 0){}; /* wait for done */
FLASH_B.MCR.B.EHV = 0;
FLASH_B.MCR.B.PGM = 0;
FLASH_B.MCR.B.PGM = 1;
*(unsigned int *)0x000C0018 = 0xAAAAAAAA; /* interlock write */
*(unsigned int *)0x000C001C = 0xBBBBBBBB; /* interlock write */
FLASH_B.MCR.B.EHV = 1;
while(FLASH_B.MCR.B.DONE == 0){}; /* wait for done */
FLASH_B.MCR.B.EHV = 0;
FLASH_B.MCR.B.PGM = 0;
But this is my problem, when I do this....
*(unsigned int *)0x000C0010 = 0xAAAAAAAA; /* interlock write */
*(unsigned int *)0x000C0014 = 0xBBBBBBBB; /* interlock write */
The 0xAAAAAAAA is getting written to 0x000C0000, not 0x000C0010
The 0xBBBBBBBB is getting written to 0x000C0004, not 0x000C0014
But this only happens when the address is above 0xA0000, below that the data is going to the correct address.
I am absolutely sure the 'write to' pointer is at the write address, it seems the CPU (or MMU) is adjusting the address to where it finally gets written.
Regards,
Do you have more MCUs? Are you facing the problem on all of them? Or is it related to one device only? I'm still not sure if it is related to HW or SW.
The only thing that comes into my mind is:
http://www.freescale.com/files/32bit/doc/app_note/AN4521.pdf
Take a look at chapter 4.2.
Mentioned SSD flash drivers can be downloaded here:
http://www.freescale.com/lgfiles/Qorivva/MPC5674F_C90FL_SSD_DRV.exe
The devices are fine, but I will have a close look at the SSD drivers you linked to, thanks.