Problems Erase Flash Sectors

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

Problems Erase Flash Sectors

9,581 Views
MichaelA
Contributor I
Hello,
 
I am trying to erase all (well, most actually) of the Flash in the HCS12XDP512, but am having problems getting it to work right.  I am using the code from AN2720 to do the Flash operations (the relevant code is pasted at the bottom of this message).  What I want to do is erase page $FF (local address 0xC000-0xFFFF), and then the paged flash, $E0 through $FC, and then also page $FE.  For some reason, when I run the following code, it gets hung up (I try to halt the debugger to see where it hangs up, but it will not let me halt it, rather it goes straight back to running - have never had this happen).  But now if I comment out the line that erases the sector in $E0, the code works fine and it seems to erase correctly.  Does anyone see anything wrong with what I'm doing?  Just to test, I'm only erasing one sector in $E0, but eventually it'll be a loop that erases all sectors in all the pages.
 
//Erase local page FF
flash_start = (long) 0xFFC000;
flash_end = (long) 0xFFF000;
result = Flash_Erase_Block((unsigned int *far) flash_start, (unsigned int *far) flash_end);
if(result < 0) return result;
    
//Erase vector table
flash_start = (long) 0xFFFF10;
flash_end = (long) 0xFFFFFF;
result = Flash_Erase_Block((unsigned int *far) flash_start, (unsigned int *far) flash_end);
if(result < 0) return result;
    
//erase paged flash
flash_current = (long) 0xE08000;
result = Flash_Erase_Sector((unsigned int *far) flash_current);
if(result < 0) return result;
flash_current = flash_current + Flash_Sector_Size;
signed char Flash_Erase_Sector(unsigned int *far far_address)
{
 unsigned int* address;
 address = (unsigned int*)far_address; // strip page off
 if((unsigned int)address & 0x0001) {return Flash_Odd_Access;} // Aligned word?
 //if((unsigned int)address % Flash_Sector_Size !=0) {return Not_StartofSector_Error;}
 Flash.fstat.byte = Flash.fstat.byte & (ACCERR | PVIOL); // clear errors*/
 (*address) = 0xFFFF;/* Dummy store to page to be erased */
 Flash.fcmd.byte=ERASE;
 (void)DoOnStack(far_address);
 if (Flash.fstat.bit.accerr) {return Access_Error;}
 if (Flash.fstat.bit.pviol) {return Protection_Error;}
 return 1;
}

signed char Flash_Erase_Block(unsigned int *far start_address, unsigned int *far end_address)
{
 unsigned int i;
 unsigned int count;
 unsigned long address;
 signed char ret_val;
 count = ((((unsigned int)end_address)-((unsigned int)start_address))/Flash_Sector_Size)+1;
 address = (unsigned long)start_address;
 for (i = 0;i < count;i++)
 {
   ret_val = Flash_Erase_Sector((unsigned int *far)address);
   if (ret_val == Access_Error) {return Access_Error;}
   if (ret_val == Protection_Error) {return Protection_Error;}
   address = address+Flash_Sector_Size;
   SendByte('*');
 }
 return 1;
}
 
DoOnStack ASM:

; Local defines
                       ORG   $5000           
           CBEIF:      EQU   $80
           FSTAT:      EQU   $105
           FCMD:       EQU   $106
           CCIF:       EQU   $40
           PAGE_ADDR:  EQU   $30
                       xdef  DoOnStack
;* DoOnStack - copy SpSub onto stack and call it (see also SpSub)
;* De-allocates the stack space used by SpSub after returning from it.
;* Allows final steps in a flash prog/erase command to execute out
;* of RAM (on stack) while flash is out of the memory map
;* This routine can be used for flash word-program or erase commands
DoOnStack:
           pshb                          ;save B - PPAGE
           ldx     #SpSubEnd-2           ;point at last word to move to stack
SpmoveLoop: ldd     2,x-                  ;read from flash
           pshd                          ;move onto stack
           cpx     #SpSub-2              ;past end?
           bne     SpmoveLoop            ;loop till whole sub on stack
           tfr     sp,x                  ;point to sub on stack
           ldaa    #CBEIF                ;preload mask to register command
           call    0,x,00                ;execute the sub on the stack
           leas    SpSubEnd-SpSub,sp     ;de-allocate space used by sub
           pulb                          ;restore B
           rtc                           ;to flash where DoOnStack was called
;* SpSub - register flash command and wait for Flash CCIF
;* this subroutine is copied onto the stack before executing
;* because you can't execute out of flash while a flash command is
;* in progress (see DoOnStack to see how this is used)
          EVEN                          ;Make code start word aliened
SpSub:
           ldab    SpSubEnd-SpSub+2,sp   ;get PPAGE back
           stab    PAGE_ADDR             ;Store the PPAGE address
           tfr     ccr,b                 ;get copy of ccr
           orcc    #$10                  ;disable interrupts
           staa    FSTAT                 ;[PwO] register command
           nop                           ;[O] wait min 4~ from w cycle to r
           nop                           ;[O]
           nop                           ;[O]
           brclr   FSTAT,CCIF,*          ;[rfPPP] wait for queued commands to finish
           tfr     b,ccr                 ;restore ccr and int condition
           rtc                           ;back into DoOnStack in flash
SpSubEnd:
 
Sorry for the long code listing, but I hope it saves time from not having to go look up the Application Note.
 
Thanks,
 
Michael

Message Edited by MichaelA on 03-08-200611:31 AM

Labels (1)
0 Kudos
7 Replies

1,079 Views
MichaelA
Contributor I
I was able to get it all working.
 
In response to not being able to program the vector table: well, I actually was successfully programming the vector table, but the debugger isn't very good at showing the proper local memory mapping, but if I went to the 0xFF10 global equivalent (0x7FFF10), it shows that its correctly programmed.  Why this is, I don't know.
 
The other problem with the Start code not loading correctly had to do with me not correctly loading the S-Record file into memory.  A few of the odd byte lines in an S-Record threw my algorithm off and it programmed incorrect values.  So if your bootloader doesn't work, I would suggest very carefully looking at the memory map of what the s-record is suppose to load and make sure its correct.
 
- Michael
0 Kudos

1,079 Views
DrSeuss
Contributor I
Just a note. The code for AN2720 was not written nor intended to be used with the S12X (nor HC12).
While the concepts should work for the S12X, the AN was never tested with these devices. Don't even try it with the HC12, the flash is completly differant.
0 Kudos

1,079 Views
MichaelA
Contributor I

Thanks CompilerGuru.  I was able to alter the code with the tips from your previous post and all is working fairly smoothly now.  I guess the flash functions that I was using is for the HCS12 where you can access the paged memory with the logical address (but in the HCS12X, doing it with the global addressing did the trick).

However, now I'm having two other problems with getting this bootloader to work.

One is that I can't seem to program the vector table.  It erases just fine, but when the S-Record that defines the values for the vector table, it does not program it as it should (but the other S1 records for local addresses 0xC000 program correctly).  Is there something special about the vector table and programming it?  Also, when I program using the bootloader, it for some reason secures the device (when I try to reset the controller using the debugger, is gives a message about the device being secured - not sure what I'm doing to make that happen).  Note that when I look at the global address 7FFF10'G, it is programmed correctly, but in the local address FF10'L it is not.  Is the vector table somehow not linked to the global address space like the rest of the FF page?

The other problem is the actual running of the code.  I'm loading a simple program that turns some LEDs on - the program starts at 0xC000 with the Start12.c code from CodeWarrior.  The bootloader is programmed at 0x4000, and jumps to 0xC000 once the S-Record file is loaded.  However, the startup code runs differently from the bootloader programmed application, and the CodeWarrior loaded application (the LED application works fine when loaded from CodeWarrior, but the code trails off in the Start12.c where it tries to copy initialization data from ROM to RAM when loaded using the S-Records through the bootloader).

Anyway, thanks for the responses.

- Michael

Message Edited by MichaelA on 03-14-200612:43 PM

0 Kudos

1,079 Views
MichaelA
Contributor I

Hey Daniel,

Thanks for the response.  I was able to get it to work by getting rid of that (*address) = 0xFFFF;/* Dummy store to page to be erased */ line.  I still don't know what the original purpose of this line was in the application note that I got the code from.

But now I have a problem with programming the paged flash.  When the compiler optimizes the following line with its _LOAD_FAR_16 subroutine (where it then goes into a _GET_PAGE_REG subroutine, it seems to mess up the PPAGE register and the program wanders off and crashes.  There a way to tell the compiler to not use these subroutines?  Here are the lines its using it on:

if(*far_address != 0xFFFF) {return Flash_Not_Erased;}

far_address is an unsigned int *far (address in the form of 0xPPLLLL, PP = page, LLLL = local address, ie 0x8000-0xBFFF).

What's bothersome is that works great when programming a local address, but anything paged, the code wanders off in these compiler subroutines.

- Michael

0 Kudos

1,079 Views
CompilerGuru
NXP Employee
NXP Employee
Ups, that's bad news. Also for me as I have to write a bit much.

The _LOAD_FAR_16, _GET_PAGE_REG and other runtime routines are called by the compiler for the HC12/HCS12 processors (note that I did not mention HCS12X) to access the constants on other flash pages. Basically you cannot set PPAGE while you are running from the PPAGE area. So the compiler calls a runtime routine in a non paged area which then handles the PPAGE access and restores the old PPAGE before it returns.
There are now two ways for you to solve this.

1- also put the page access runtines into your non erased, always available area. This implies that your area must be unpaged. Normally, boot loaders and similar things have to control the vectors (reset vector) anyway, so they are usually located at the top of the 0xc000..0xFFFF page. The data page runtime routines are all located in datapage.c

1.5 Oh, I almost forgot. If you know you are running from a non paged area, you can allow that the compiler does some accesses without runtime call with the -CpPPAGE option. I'm not sure it will do it for your case tough.

2- Use the HCS12X..... (and tell it to the compiler)
What I mean is that the compiler is only using the runtime routines when it generates code for the HC12/HCS12, not when it generates code for the HCS12X!
So you apparently did not specify -CpuHCS12X. Well the HC12X is compatible in this respect with the HCS12, the code just runs fine. But it does not take advantage of the additional features of the HCS12X.
However for you, there is one trap in switching from the HC12 to the HCS12X code. The HCS12X architecture did introduce a new way of accessing the memory, called global access. This memory access is done by the HCS12X for far pointers.
The advantage: no runtime routines (so its what you are looking for!)
The trap: It uses different address values. To say it in another word, the (logical) address 0xFF8000'L matches the global address 0x7F8000'G. Its not the same page and (in general at least) not the 16 bit offset address.

Fortunately, the HCS12X C Compiler does help you. Use the __pptr pointer qualifier whenever you use logical addresses (as you did for the HCS12, and as your assembly routine expects!) and use __far pointer to actually do the memory accesses without runtime call.
E.g.

unsigned char* __pptr flashPageStart= (unsigned char* __pptr)0xFF8000;
..... Call assembly code with flashPageStart.

unsigned char* __far globalFlashPageStart= flashPageStart; // conversion inserted by the compiler
if (*globalFlashPageStart != 0xFF) { ...flash not erased...

Hmm. I just noted that this conversion will also use code from datapage.c. So make sure this code is not getting erased.

Daniel

Message Edited by CompilerGuru on 03-11-200603:22 PM

0 Kudos

1,079 Views
MichaelA
Contributor I

Also, when stepping through the code in the Flash_Erase_Sector function with the 0xE08000 address, the debugger gives the follow error after executing this line:

 (*address) = 0xFFFF;/* Dummy store to page to be erased */

"While in RUN mode, the emulator can only execute the STOP and RESET commands."

After this, the program quits and I have to actually close the debugger to be able to reload another program from CW.

0 Kudos

1,079 Views
CompilerGuru
NXP Employee
NXP Employee
Well, I'm not that much familiar with the flash programming that I could really state where your problem is. Just some points.
- I tought that the are large flash banks which contain multiple 16k flash pages. And than one programming one page inside of any bank, all the other pages of the same flash bank are not accessible. Well, I'm not really sure, but this would explain a bit why you cannot erase the complete flash while running out of the page 0xFD.
- far pointers for the HCS12X compiler are using global addresses. Use __pptr instead of far (void*__pptr), if you intend to use logical addresses (as you do). It does not really matter as your code is not actually accessing anything using the far pointers, but just in case for the future.
- what is the "(*address) = 0xFFFF;" for? (as I said: I never did program a flash programmer...) As address is a 16 bit pointer, it wont set the PPAGE. Therefore this write does not write to the page you intened to erase. It goes to the page of the current PPAGE register. Maybe using a __pptr pointer here helps?

Daniel
0 Kudos