Hello everyone!
I'm working with HCS12 and CW4.6.
The problem I have is that sometimes, when trying to erase FLASH, I get ACCESS ERROR. I look at the datasheet, and none of the 12 statements that can cause the ACCESS ERROR is true (or so I think, I check them twice).
the DoOnStack routine is from AN2720
I found out that ACCERR flag is set when I try to erase it.
tFLASH_ERROR FLASH_eraseSector(word*__far far_address){ word* address; tFLASH_ERROR error; error = FLASH_ERR_NONE; // Assume no error FSTAT = 0x30;// [PVIOL, ACCERR] clear flags address = (word*)far_address; // strip PPAGE if((word)address & 0x0001){ error = FLASH_ERR_ODD_ACCESS; // Not-Aligned Word } if((word)address % FLASH_sectorSize !=0){ error = FLASH_ERR_NOT_START_OF_SECTOR; // Not sector ini } if (error == FLASH_ERR_NONE){ *far_address = 0xFFFF; // DUMMY SOTRE FCMD = ERASE; // erase cmd = 0x40 DoOnStack(far_address); } return (error); }
and when writting 0x30 to FSTAT, ACCERR is set. Why?
FLCKDIV = 0xC9 for a 16MHz Xtal
and the far_address = 0x3C8200.
It does not always fail. But when it does, is at FSTAT = 0x30
What could I be doing wrong?
Thanks in advance!
Solved! Go to Solution.
You're totally right kef, my bad. Sorry.
I was no able to set the watchpoints. I mean, I can place them, but they wouldn't work. I guess maybe because of the page switching. I set a write Watchpoint, and I can see how the value change (because of page switching) but it would never halt the MCU.
Anyway, you give a way to find my problem. I was running routine by routine until FADRR = 7492. And I found the problem!!!!!
It was a silly mistake but it would have take me years to find it, if you wouldn't provide me that information.
I was doing:
strcpy("TEXT", var);
instead of:
strcpy(var, "TEXT");
"TEXT" was allocated at 0x3FA924
I can't believe such a small mistake causes all this mess!
Kef, thank you very much for your help! I really appreciate that!
Sveikinimai
What MCU are you using? Old S12 with more than 64k of flash have bank select bits, which you have to set while erasing or programming.
Hi kef!
I'm using MC9S12A256, it has banked memory, indeed. I forgot to mention that I don't touch the BKSEL bits, and let them in 0, so Flash 0 is selected. And the data I'm writting is only to pages $3C and $3D.
Besides, when attempting to program. I calculate the start of the sector to be touch, and how many sectors would be modified. I backup all the data (in RAM) add/modify values, erase the whole sector (from it's begginig address) and the re-program it whit the new data. It's possible that more than one sector need to be erased/re-programed.
My project has a buzzer, which I sound every time an access error ocurrs. I have several "points" where FLASH_update routines are called. Sometimes the same "point" works, other it fails with an access error. The strange thing is that sometimes the error is not thrown. That's what mess me up; and that 's why I know that:
- PPAGE is ok (I've an error with a valid PPAGE)
- I'm not writting to a misaligned word
- I'm "inside" page addresses 0x8000 and 0xCBFF (I don't recall correctly the end value) (Also the error is thrown when trying to program address 0x3C8208)
- I've not protection set FPROT = 0xFF
- I don't have a wrong value in BKSEL, it's always cero.
- As you can see in the routine above, I'm not writting to any registrer other than FSTAT before and after FCMD0
As said before, FCLKDIV is correctly set for a 16Mhz oscillator as noted in the reference manual. Also the bit with mask 0x80 is set.
I've check that before entering the erase rotuines, CCIF is set and also CBEIF.
Then I go stepping and (when fails) I can see that ACCERR is set after writting 0x30 to FSTAT. If it wont fail, then writting to FSTAT clear the flags (which where not set before, so practillay it does nothing)
It sounds to me like an incomplete "cycle" of erase or program, so it thinks that I'm still doing something with the flash and when I try to clear a flag, it throws me an error. But still I can't figure it out.
Any help is appreciatted. Thanks!
I've found a sequence that causes the error. This sequence ALWAYS generate an ACCESS ERROR. I'm stepping it, and looking at every flash register and everything seem fine, has the same values than other sequences.
(This sequence is the one that set ACCERR after writting 0x30 to FSTAT)
What should I look for? What should I be watching? I know for sure that this sequence will fail, how can I "predict it", I mean, how can I tell that a sequence will fail before it does.
Thanks you all!
I've found a solution (for now). But I still don't know what was causing the error.
As Interrupt Vectors are allocated in Flash Block 0, I guess maybe interrupts were bothering. Despite I disable interrupts when entering flash update routine and re-enable them before exit.
I've move my data from pages 3C, 3D to 38, 39; so now I use Flash Block 1. I needed to set BKSEL = 1.
Till now I've got not a single error, even with the sequence that I've found before and always failed.
Just to fulfill my couriousity, and increase my knowledge I'd like to know why the error was happening. If anyone have a clue about it and want to share it, it would be great!
Thanks in advance!
Grrrrrrr!!!
Now the error shows up again, but worse! Now it trows that error more frequently!
What colud that be!!!????
EDIT:
I'm back again using pages 3C and 3D from Flash Block 0. Now it works fine..... I'll guess that soon it will fail again, but don't know why.
Of course you need to disable interrupts in case when interrupts vectors and/or ISR's are allocated in the same flash bank, which you are erasing/programming.
kef, I'm already disabling interrupts (since the begging). Nevertheless error keeps coming.
I don't know what's wrong.... Now pages $3C and $3D are failing again. But they weren't for a time. And the error is always after I load the code to the MCU, so the problem is not some "history" in the MCU memory or corrupted data.
Do you have the same situation in clean project, including only flash routines, and simple clean code that calls them?
If not, then you should look for piece of code, that does something wrong and writes to (random) flash address. Also check if you have enough stack space.
I tried to create a small clean project just to upload here and show you the problem, but I test for 200 erase/program and there was no error. So I guess there's something wrong with my project.
About writting to a random flash address... I save the address value each time the FLASH_update routine was called and all were correct values, between 0x8000 - 0xBFFF inside page $3C (when using Flash Block 0).
Now, I'll check the stack, an perform some more test.
Thanks for your help!
I meant some misbehaving piece of program, not belonging to flash routines, may write to flash array, which may trigger flash errors.
When you detect flash error, check what's in FADDR and FDATA registers. These may be not listed in CW header files, since they are usefull only for flash programming over BDM, but you may get their addresses from datasheets and read them. I think these registers should reflect what data and what address (relative to the start of flash array) last write attempt was made to.
I didn't know about those registers...
Well, I don't know if this is correct.... As soon as I can asure and error would ocurr, values are:
- FADDR = 0x7492 (FADDR @0x108)
- FDATA = 0x0000 (FADDR @0x10A)
Do that mean that somewhere in the code there's an attempt to write to address 0x7492, for example 0x3C7492?
I don't know if those values are correct. I know that the second access to FLASH_update routine will fail, so I put a breakpoint inside it. The first time I let it continue excecution, second time (I know it would fail) so when it reaches the breakpoint I manually write 0x30 to FSTAT, and ACCERR bit is set. Then I read FADDR and FDATA, and those are the values read.
Now, I check those registers when programming works:
Trying to program address 0x3C8208 with values: 0x78 0x78 0x78 0x78 0x78 0x00 (six bytes)
After Erase sector where 0x3C8208 belongs. So It erase sector starting at 0x3C8200
- FADDR = 0x0100
- FDATA = 0xFFFF
After Programming sector with new values
- FADDR = 0x01FF
- FDATA = 0x0000
That tells me that the answer to my question: "Do that mean that somewhere in the code there's an attempt to write to address 0x7492, for example 0x3C7492?" is NO. So what do that mean?
I've try putting a watchpoint on FADDR, but didn't work
Do this tell you something? Thanks!!!
Just tried on onebanker C32. FADDR contains bank relative address, divided by 2. Div by 2 to represent word number. Writinng wprd tp top address 3FFFFE on C32 makes FADDR showing 3FFF. I believe that on 64kB part you would find there 7FFF.
Depending on 64kB bank select bits, FADDR=7492 should mean 3FA924, 3BA924, and so on.
After Erase sector where 0x3C8208 belongs. So It erase sector starting at 0x3C8200
- FADDR = 0x0100
Yes, 0x200/2 = 0x100. Erasing 3D8200 you should see 0x2100 in FADDR
FADDR = 0x01FF Is OK for top most address 3D83FE of the same sector. 3FE/2 = 1FF
Is it possible that you've mistaken here?
FADDR=7492 should mean 3FA924, 3BA924, and so on.
Lest work on Flash Block 0:
- For 0x3C8000, FADDR = 0x0100
- For 0x3D8000, FADDR = 0x2100
- For 0x3E8000, FADDR = 0x4100
- For 0x3F8000, FADDR = 0x6100
So if BKSEL = 0 and FADDR = 7492, then, the effective offset should be (0x7492 - 0x6100) * 2 = 1392 *2 = 2724.
Address is then 3F8000 + 2724 = 3FA724.
is this correct?
If so, its a pitty, because I can't find anything on .map at that address. I've attach .map file
Thanks again, you're helping a lot!
No, these should give FADDR = 0x0, 2000, 4000 and 6000 respecively.
0x7492*2 = 0xE924.
Dividing 0xE924 by page size 0x4000 gives 3 and remainder 0x2924.
3 is page number, relative to the least bank page. As far as I know A256 has four 64kB banks. Starting bank pages are 0x3C, 0x38, 0x34 and 0x30. Add to them 3 and you'll get 0x3F, 0x3B, 0x37 and 0x33.
0x2924 is page offset. Add here bottom address of page window and you'll get 0xA924.
Try setting watchpoint for this address, and also for XXA925, since it could be misaligned word or byte write to A925.
You're totally right kef, my bad. Sorry.
I was no able to set the watchpoints. I mean, I can place them, but they wouldn't work. I guess maybe because of the page switching. I set a write Watchpoint, and I can see how the value change (because of page switching) but it would never halt the MCU.
Anyway, you give a way to find my problem. I was running routine by routine until FADRR = 7492. And I found the problem!!!!!
It was a silly mistake but it would have take me years to find it, if you wouldn't provide me that information.
I was doing:
strcpy("TEXT", var);
instead of:
strcpy(var, "TEXT");
"TEXT" was allocated at 0x3FA924
I can't believe such a small mistake causes all this mess!
Kef, thank you very much for your help! I really appreciate that!
Sveikinimai
strcpy("TEXT", var);
I thought this should produce warning, but indeed it doesn't.
I think it should warn about passing pointer to const the same like lines below. At least some C compilers are able to warn about passing pointer to const instead of pointer to nonconst data.
const char txt[]="TEXT";
strcpy(txt, var); // C1825 warning
Lint also should help.
Well, that was very helpful, kef!!
Indeed, I've got a flash vriable at 0x3CA924, so it norrowed my search. Now I need to find where I'm messing with it.
I'll look for it and let you know
I've done a simple test:
#pragma CONST_SEG FLASH_DATA_PAGE static const word far FLASH_TEST @ 0x3C8200; #endif#pragma CONST_SEG DEFAULTword*far ptr;ptr = &FLASH_TEST; // pointing to 0x3C82000*ptr = 0x5555; // Try to write to flash/*If now I write 0x30 to FSTAT the ACCERR bit is set.*/
I guess I'm messing it up with pointers. I think I should review all my code (when dealing with FLASH variables).
Is there any way to prevent above condition? Something like defining ptr to point to constant values. Not a constant pointer, but a variable pointer that points to const values, so it only can read, not write.
Thanks!
EDIT:
Nevermind about the #endif directive... I forgot to delete it