Flash erase/write works only with Breakpoints (MC56F8014)

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Flash erase/write works only with Breakpoints (MC56F8014)

5,504 Views
Hollaborst
Contributor II
Hi,

for my application I need to store values for the time when the controller is powered down. To save costs I want to use one page of the internal flash of the MC56F8014. So my program will be stored from 0x0000 - 0x1EFF and the values will be stored from 0x1F00 - 0x1FFF. I wrote functions to erase this page and to write words at addresses from this section of flash. But this works only if I'm in debug mode an I've set breakpoints into these functions. Otherwise the controller jumps during this functions to an address in the reserved area of memory and stays there. This is normally at address 0x7800 +-20.
Do anybody have an idea what's the reason for this?
Thank you,
David
Labels (1)
9 Replies

989 Views
Hollaborst
Contributor II
Hi,

so, I find the solution! And for those who may have the same problems in the future I want to post what I've done.
First I had to store the function, which I want to execute from pRAM, in the flash. To have a start address of this function for later copying it to pRAM I had to reserve space in the memory map. Therefor I had to change the *.cmd linker file as shown:
Code in *.cmd linker file:
MEMORY {    .p_interrupts_ROM     (RX)  : ORIGIN = 0x0000,   LENGTH = 0x005C   # reserved for interrupts     .p_flash_ROM          (RX)  : ORIGIN = 0x005C,   LENGTH = 0x1E84      .p_ERASE_ROM          (RX)  : ORIGIN = 0x1EE0,   LENGTH = 0x0020   # stored Flash-Routine for copying to pRAM    .p_savedata_ROM       (RX)  : ORIGIN = 0x1F00,   LENGTH = 0x0100   # 1 page = 256 words      # p_flash_ROM_data mirrors internal xRAM, mapping to origin and length     # the "X" flag in "RX" tells the debugger to download to p-memory.     # the download to p-memory is directed to the address determined by AT     # in the section definition below.                      .p_flash_ROM_data     (RX)  : ORIGIN = 0x0000,   LENGTH = 0x07E0   # internal xRAM mirror                                                                       # for pROM-to-xRAM copy    .p_ERASE_RAM          (RWX) : ORIGIN = 0x87E0,   LENGTH = 0x0020   # copied Flash-Routine will be execute from here     # for MC56F801x, reserved area of memory from 0x0000 to 0x07FF      # is mirrored to shared RAM as well.  We use this for SDM (Small Data Model).         .x_internal_RAM       (RW)  : ORIGIN = 0x0000,   LENGTH = 0x07E0    .x_ERASE_reserved_RAM (R)   : ORIGIN = 0x07E0,   LENGTH = 0x0020 # reserved for Flash-Routine, should not be overwritten    .reserved_1           (RW)  : ORIGIN = 0x0800,   LENGTH = 0xE800    .x_onchip_peripherals (RW)  : ORIGIN = 0xF000,   LENGTH = 0x1000       .reserved_2           (RW)  : ORIGIN = 0x010000, LENGTH = 0xFEFF00     .x_EOnCE              (RW)  : ORIGIN = 0xFFFF00, LENGTH = 0x0000FF   }

Then I had to declare the master function in a section at the location of p_ERASE_ROM and the dummy for copy in a section at the location p_ERASE_RAM for the linker:
Code in *.c source file:
#pragma define_section ERASE_FLASH_Code ".ERASE_FLASH_Code" RX#pragma section ERASE_FLASH_Code beginvoid Flash_execute_Copy (){ asm(nop);// launch command    FM_USTAT |= B7_SET;    while ((FM_USTAT & B6_SET) == 0)    {    asm(nop);    }    asm(nop);}#pragma section ERASE_FLASH_Code end/*--------------------------------------------------------------------------*/#pragma define_section ERASE_FLASH_Code_RAM ".ERASE_FLASH_Code_RAM" RWX#pragma section ERASE_FLASH_Code_RAM beginvoid Flash_execute (){ asm(nop);  //dummy}#pragma section ERASE_FLASH_Code_RAM end
Code in *.cmd linker file:
SECTIONS { ... ...    .ERASE_FLASH_Code :   # stored in flash    {     __pERASE_data_start = .;  # start address             * (.ERASE_FLASH_Code)  # flash routine                __pERASE_data_end = .;   # end address                __pERASE_size = __pERASE_data_end - __pERASE_data_start;           } > .p_ERASE_ROM    .ERASE_FLASH_Code_RAM :  # execute from pRAM    {     __xERASE_data_start = .;  # start address             * (.ERASE_FLASH_Code_RAM) # dummy            } > .p_ERASE_RAM ... ... .data :  {    ...  ...  F_FLASH_ERASE_size     = __pERASE_size;  F_FLASH_ERASE_RAM_addr = __xERASE_data_start;  F_FLASH_ERASE_ROM_addr = __pERASE_data_start; } > .x_internal_RAM                        }

 In the main() I had now to copy the function from pROM to the dummy in pRAM. With the globalized addresses it's like this:
Code in *.c source:
...
...
extern _FLASH_ERASE_size;extern _FLASH_ERASE_RAM_addr;extern _FLASH_ERASE_ROM_addr;int main(void){ ... ...// prom2pram() copy function    asm(nop);    asm(move.l  #>>_FLASH_ERASE_size,r2);     // set data size    asm(move.l  #>>_FLASH_ERASE_ROM_addr,r3); // src address -- pROM data start    asm(move.l  #>>_FLASH_ERASE_RAM_addr,r1); // dest address -- xRAM data start    asm(nop);    asm(do      r2,>>end_prom2pram_ERASE);    // copy for r2 times    asm(move.w  p:(r3)+,x0);             // fetch value at address r3    asm(nop);    asm(nop);    asm(nop);    asm(move.w  x0,x:(r1)+);             // stash value at address r1    asm(end_prom2pram_ERASE:);    asm(nop);    ...    ...}

Later in the program I will just call the function Flash_execute(). The program counter will jump to the start address of this section at 0x87E0 in pRAM and will execute the code from the master function Flash_execute_copy(), which is copied there.
To be sure that the master function will be mapped in the map file I called the function in the source, even if it will be never executed:
Code in *.c source:
void tricky()
{
   int copy = 0;

   if (copy) Flash_execute_Copy();

}

I hope that helps those who want to do the same as me.
Nice debugging,
Hollaborst
0 Kudos

989 Views
WayneHowell
Contributor I
Hi,
 
Had a similar problem on the NE64.
 
As far as I can tell the problem is:
 
You cannot read from flash whilst you are burning it. If you single step through the code, the debugger tries to refresh the debug window, thereby reading the flash. It then fails to write correctly.
 
Running to breakpoints solves the problem because the debugger does not try to read ram after every instruction.
 
Cheers
 
Wayne
0 Kudos

989 Views
Hollaborst
Contributor II
Hi Wayne,

I think you missunderstood me:
When I'm running the controller as stand alone application, without a connection to the PC or CodeWarrior, the failure occurs. When I'm running the controller in debug mode with one breakpoint in the routine it works.
That's what I don't understand. I've attached the routine and marked the breakpoint.


#pragma interrupt called
void Flash_ProgramValue ( WORD wAddr, WORD wData)
{
    WORD wIrqState;

    asm(nop);
// check if FMCLKD is written after reset/boot, nessecary for flash operation
    if ((FM_CLKDIV & B7_SET) == 0)
        FM_CLKDIV = 0x0028;
    
// check if flash is busy
    while ((FM_USTAT & B6_SET) == 0)
    {
        asm(nop);
    }

// wait for flash command buffer is empty
    while ((FM_USTAT & B7_SET) == 0)
    {
        asm(nop);
    }

// interrupt state (disable/enable) save
    wIrqState = ITCN_ICTRL;
    Interrupts_Disable();

// write data to desired flash address for programming
    WriteProgramFlash((WORD*)wAddr, wData);

// write command
    FM_CMD = FLASH_COMMAND_PROGRAM;

// launch command
    FM_USTAT |= B7_SET;

    while ((FM_USTAT & B6_SET) == 0)
    {
    }                      <=============BREAKPOINT==============

// interrupt state (disable/enable) restore
    ITCN_ICTRL = wIrqState;
    Interrupts_Enable();
}

0 Kudos

989 Views
kef
Specialist I
Wayne,
 
I should correct you a bit. I agree with you warning "don't read the flash while burning it". But I don't agree with the details. S12 flash is not readable while it's being programmed/erased/blank checked etc. It's not only not readable to you via BDM but also not readable to the CPU that may keep fetching instructions from "disconnected" memory. No wonder it will runaway immediately. 
 
Refreshing the memory window doesn't matter. Reading flash locations being programmed isn't illegal but just doesn't make sense.
 
Single stepping or putting the breakpoint immediately past the "clear the command buffer is empty flag" can make you fealing that it's OK to run program/erase routine from the same bank of flash. This works because CPU gets stopped for long enough to complete flash command.
 
Hollaborst,
 
I'm not familiar with 56xxx but I scaned it's docs and 56xxx memory looks very similar to S12. I didn't find the warning about "not readable while being programmed" flash but I guess that it should be there. I would try to move your whole flash erase/program routine, or at least this piece of code
 
// launch command
    FM_USTAT |= B7_SET;

    while ((FM_USTAT & B6_SET) == 0)
    {
    }                     
 
to the RAM.
 
Sorry for bad English
0 Kudos

989 Views
Hollaborst
Contributor II
Thank you for your answer! That's an idea. But how can I do this, copying a routine into RAM?
0 Kudos

989 Views
J2MEJediMaster
Specialist I
Search for Technical Note 288 (TN288). It describes how to copy code to RAM and execute it. Try looking for in the documentation directory in the CodeWarrior folder first, and if it's not there, then try the Freescale web site. HTH.

---Tom
0 Kudos

989 Views
kef
Specialist I
TN228 probably, not 288? Here's  a link to S12 TNs. I don't know if these will work for 56xxxx
 
 
 
0 Kudos

989 Views
Hollaborst
Contributor II
Thank you for your answer. Maybe I can get some ideas from there. But the technical Note is for HC08 or HC12. And as I already tried to implement the code I would say, that it doesn't work like discribed ind the TN228 in my application with the MC56F8014.
So how can I do this? In my linker file I already reseved space where I want to copy my routines. But I still don't know,
-> how I can copy the routines to RAM and
-> how I have to say the controller, that the routines are stored in RAM and he has to execute them from RAM.
Does anybody can help me there? I'm using CW 7.3 without PE.
Thank you.
0 Kudos

989 Views
Hollaborst
Contributor II
Hello once again,

it tooks me a bit of time, but now I'm able to copy a routine stored in the flash memory into the RAM. I also create a section in pRAM and pROM where the routine is stored. (I've attached the linker file *.cmd.) But when I want to execute the routine, the routine is always executed from pROM. I saw the adress in the program counter register.
This is how I wrote the routine:

#pragma define_section ERASE_FLASH_Code ".ERASE_FLASH_Code" RWX
__declspec(ERASE_FLASH_Code) void Flash_EraseBlock ()
{
    asm(nop);
// launch command
    FM_USTAT |= B7_SET;

    while ((FM_USTAT & B6_SET) == 0)
    {
    asm(nop);
    }
    asm(nop);
}


So how can I execute the routine from RAM? Is "RWX" for this section right or should I changed it?
Thanks,
Hollaborst
0 Kudos