This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Dear friends,
We're plagued by an occasional issue with the flash API where, after attempting to erase a sector, the erase operation nominally succeeds but the sector is not in fact blank.
In particular, this happens when trying to erase sector 1 (0x8000-0xFFFF). (Erasing sector 0 seems to work.) Again, the actual call to erase the sector returns a success code. However, the Fapi_doBlankCheck() immediately after fails on the first word of the sector (0x8000); the reported value is 0xe59ff018 (instead of the expected 0xffffffff). If I simply skip the blank check, then the subsequent program call fails, with getFsmStatus() returning INVDAT (this makes sense if the sector wasn't actually erased).
This is what my code looks like. At the point of failure, sector_address is 0x8000, sector_size is 0x8000,
==========
// Try: Blank check, erase, blank check, give up.
for (int attempt = 0; attempt < 2; ++attempt) {
// Fapi_doBlankCheck() on a whole sector takes 12+ms; do it in chunks.
status->error_code = Fapi_Status_Success;
for (uint32_t chunk = sector_address;
chunk < sector_address + sector_size; ) {
int length = Min<int>(1024, sector_address + sector_size - chunk);
Fapi_FlashStatusWordType fsw;
status->error_code = Fapi_doBlankCheck(
reinterpret_cast<uint32 *>(chunk),
length / sizeof(uint32), &fsw);
if (Failed("Fapi_doBlankCheck failed", status)) {
status->error_code = fsw.au32StatusWord[0]; // Bad address.
if (attempt > 0) return; // Should have succeeded by now.
break; // Before erase; now try erasing the sector.
}
chunk += length;
WatchdogServiceExternal();
}
if (status->error_code == Fapi_Status_Success) break; // Blank!
// First attempt: Issue the command to erase the sector.
CPU_SR_ALLOC();
CPU_INT_DIS(); // No interrupts while flashing!
status->error_code = Fapi_issueAsyncCommandWithAddress(
Fapi_EraseSector, reinterpret_cast<uint32 *>(sector_address));
if (Failed("Fapi_EraseSector failed", status)) {
CPU_INT_EN();
return;
}
while (Fapi_checkFsmForReady() == Fapi_Status_FsmBusy)
WatchdogServiceExternal(); // Wait for completion.
status->error_code = Fapi_getFsmStatus();
CPU_INT_EN();
if (Failed("Erase operation failed", status)) return;
Fapi_flushPipeline(); // Defensively flush after every erase.
}
==========
Like I said, this doesn't always seem to happen -- it comes and goes with unrelated code changes -- we're trying to narrow down what triggers this (whether it's related to the data being flashed, or the code doing the flashing, or what). Meanwhile, is there anything that could cause this kind of behavior?
I should point out, just in case it's relevant:
When the failure happens, we have used MEMSW=0x05 to swap the RAM and Flash memory blocks. (This is to enable us to run a bootloader from RAM, including interrupt vectors, while updating the flash.) I don't think I've ever seen it when flashing without MEMSW, but that could be coincidental. We're still, of course, passing in logical flash addresses (0-based), not the swapped addresses.
(I notice in another thread that Fapi_flushPipeline() is reported to perform dummy reads on fixed addresses, 0x000, 0x100, 0x200, 0x300. In MEMSW mode, those would be mapped to RAM, not flash. Not sure if that would be a problem.)
What is the value of FMSTAT register when the sector erase fails?
What version of the API are you using?
The only failures I have seen are trying to issue an erase sector to an address not in the active bank (this condition does not generate any notification from the device. FMSTAT would be 0), sector has not been enabled (FMSTAT indicates sector lock error, FMSTAT == 0x11), or trying to issue an erase command while the FSM is busy (FSM will ignore all erase and program commands in this state).
Fapi_flushPipeline() is only valid when Flash is mapped to address 0. With RAM and Flash swapped, you would need to do 2 dummy reads from Flash with remapped addresses at least 128 bytes apart to cause the pipeline to be flushed.
Also, note that the F021 Flash API does not require interrupts to be disabled while performing operations.
Thanks for the quick followup!
FMSTAT (this is what Fapi_getFsmStatus() returns, right?) is 0 after the sector erase.
This is API version 1.51.0 (I'm re-downloading and diffing to double check this now).
We definitely call Fapi_setActiveFlashBank with the correct value; I'll triple check that but I'm pretty confident.
I will add my own FlushPipeline() that does the dummy reads. (Does it matter which bank/sector they read from?) However, that should not be required between Fapi_EraseSector and Fapi_doBlankCheck?
And yeah, the interrupt disabling was a defensive measure added when debugging previous flash problems. I should probably remove it.
Normally, flushing the pipeline is not needed between erase and blank check as the blank check function has a call to Fapi_flushPipeline(), but in this memory swapped scenario, you would need to explicitly flush the pipeline.
I will look at modifying this behavior in a future version of the API.
Also, you should be checking the FSM (using Fapi_checkFsmForReady() ) to see if it is busy before issuing an erase command if you are not sure about the FSM state.
OK, I replaced Fapi_flushPipeline() with my own custom FlushPipeline():
Can you post a memory dump from 0xFFF87000 - 0xFFF873FF before and after issuing the erase command?
OK, I have verified the following variable values:
fb = 0
s = 1
sector_address = 0x8000
And I now do this defensive series of operations:
=====
=====
But yeah, still no dice.
Before the erase command:
And for good measure:
===================
After the erase command:
Update:
Turns out a large part of my confusion is that doBlankCheck() doesn't seem to support MEMSW. The sector has actually been erased for a while -- but doBlankCheck() was failing because of MEMSW. (When I pass doBlankCheck() a swapped address, it works. What would you recommend? Pass it a swapped address, or roll my own blank check?)
Nevertheless, my original problem was a real problem; it surfaced as the INVDAT error at program time; doBlankCheck() was only added for diagnosis purposes. However, this invalidates much of my previous "I made these changes, and it still fails..." debugging. So I'm starting back at square 1, and trying to reproduce the problem. It's possible that the pipeline-flush workaround may have solved the original issue.
I think it's safe to say that the situation when using the F021 library in MEMSW mode is confusing, at least :-)
Hello Dan,
I apologize as I should have snapped to the addresses thing sooner as I had to handle that in my memory swapped code. Programming and erasing are done through the registers in the FMC which requires use of the absolute address, whereas reading from Flash goes through the bus which would require using the memory mapped addresses. Therefore if you had passed the memory mapped address to Fapi_doBlankCheck(), it would have worked on the range you selected. In my code, I do the following:
if(u32StartAddress < 0xF0000000)
{
u32StartAddress |= 0x08000000;
}
as only the main Flash Addresses are remapped for read. Bank 7, Bank 7 ECC, Customer OTP, Customer OTP ECC and main Flash ECC still use their non-swapped addresses.
As you found out, to truly do a blank check, you need to check both the main memory addresses and the corresponding ECC addresses and for those checks to be completely correct, you at a minimum need to disable ECC correction before performing these operations. As main array and its ECC are on the same row, you could theoretically just do a blank check on the ECC region, but as address is included in the ECC calculation, 1 out of every 256 addresses, 0xFF is an valid ECC value.