Flashing Made Simple Min Ram Version - MC9S08QG4

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 

Flashing Made Simple Min Ram Version - MC9S08QG4

4,239 次查看
JimDon
Senior Contributor III
This subject has pretty much been beat to death, but I think this code has some appeal to it, and has some ideas that make it nice for a lib.

Advantages:
Handles interrupts in the only way I see as acceptable for a lib. The user should not have to worry about this, but should be aware of the lock out. This code leaves the IM flag the way it found it.

Uses a minimum of ram - 35 bytes. I use this code on QG4 project where I only have 256 byte of RAM, so this is a big consideration.

No changes required to the PRM file and no special pragmas used, and no worries about other ram variables overlaying it.

And it is darned simple.

If you need to, you can reuse the ram space and copy it back later. Once you have committed to a stack size you are stuck with it, and I really don't like stressing the stack on little ones like this.  Plus, in a library this could be a hidden nasty surprise. The map file will reflect the usage with this method.

This was adapted from HCS08RUG.

Disadvantages:
Does not use burst mode to program. According to the QG8/4 spec sheet if you set the clock to 200Khz, it takes 45 us in single mode and 20us in burst mode. While this is a 2x difference, if you only need a few bytes of config data it is no big deal. Thats 23ms for a 512 byte sector - interestingly enough just about as long as it take the erase a sector. If this is an issue, it  would be easy enough to make a tweaked burst version, but you won't get away with using the same code for erasing and writing as easily.

I normally don't use asm language, but this is a just cause. In theory, this should work with all HCS08, and I will try other chips. I have done a fair amount of testing, and it seems fine.

Debugging Advice:
Hiwave will not read back flash unless you pretend to write in it, unless you set the region to R/W and check "refresh memory when halting" you should also check "no memory access while running". This is in the "Debugging Memory Map" dialog. I had not troubles at all stepping thru the code and watching memory change - I did not step through the actual command execution code.

Code:
#define Page_Erase   PGM[2]=0x40; temp = ((unsigned char(*)(unsigned int, unsigned char))(PGM))
#define Program_Byte PGM[2]=0x20; temp = ((unsigned char(*)(unsigned int, unsigned char))(PGM))

//Array of opcode instructions of the Erase/Program function in the HCS08 family// A = data, X = Address.

volatile unsigned char PGM[35]  = {  0xF7,              // STA ,X   Save the data byte into the address. 0xA6,0x00,         //  LDA cmd (Filled in before calling)0xC7,0x18,0x26,    //  STA   _FCMD0x45,0x18,0x25,    //  LDHX  @_FSTAT0xF6,              // LDA   ,X0xAA,0x80,         // ORA   #$800xF7,              // STA   ,X0x9D,0x9D,0x9D,0x9D, // NOP, NOP,NOP,NOP0xC6,0x18,0x25,     // LDA   _FSTAT0xA5,0x30,          // BIT   #$300x27,0x03,          // BEQ   *+5 (Label1)0xa6,0xff,          // RTS
0x81,
// Label1:
0xC6,0x18,0x25,     // LDA   _FSTAT
0xa5,0x40,          // BIT #$40
0x27,0xF9,          // BEQ *-5 (Label)
0x81,               // RTS
};
byte FlashErasePage(word page)
{
   volatile unsigned char temp ;
   byte im;
   asm TPA;    // get the flags
   asm STA im  // save them
   asm SEI     // clear the im bit

   if (FSTAT&0x30){                     //Check to see if FACCERR or FPVIOL is set
        FSTAT = FSTAT | 0x30;            //write a 1 to clear
    }

   temp = Page_Erase(page,0);
   asm LDA im   // get the flags back
   asm TAP      // restore the im bit.
   return temp; 
 
}
byte FlashProgramByte(word address, byte data)
{
  volatile unsigned char temp;
   byte im;
   asm TPA;
   asm STA im
   asm SEI
    if (FSTAT&0x30){                     //Check to see if FACCERR or FPVIOL is set
        FSTAT = FSTAT | 0x30;            //write a 1 to  clear
    }

   temp = Program_Byte(address, data);
   asm LDA im
   asm TAP
  return temp; 
}


 









Message Edited by JimDon on 2008-02-25 01:24 AM

 

Added p/n to subject.



Message Edited by NLFSJ on 2008-02-25 07:29 AM
标签 (1)
0 项奖励
回复
7 回复数

1,247 次查看
CompilerGuru
NXP Employee
NXP Employee
Small optimization, using the loaded FSTAT address 5 bytes can be saved.
If the C code would report the error by reading FSTAT, the routine could be 2 another bytes smaller.

Daniel


Code:
 include "mc9s08qg4.inc"cmd:      EQU 0; dummyPGM_SEC:  SECTION          XDEF PGMPGM:  STA   ,X  ; Save the data byte into the address.   LDA   #cmd ;(Filled in before calling)  LDHX  #FSTAT  STA   FCMD-FSTAT,X ; FCMD  LDA   ,X  ORA   #$80  STA   ,X  NOP  NOP  NOP  NOP  LDA   ,X ; FSTAT  BIT   #$30  BEQ   Label1  LDA   #-1 ; needed?  RTSLabel1:  LDA   ,X ; FSTAT  BIT #$40  BEQ Label1  RTS

 

0 项奖励
回复

1,247 次查看
tonyp
Senior Contributor II
Optimizations:

If the bit mask is loaded before reading FSTAT, the min. cycle requirement between writing and reading FSTAT can still be met while saving a few NOPs (the delay is now in the LDA instruction), for example:
STA   ,X
  NOP

  LDA   #$30
  BIT   ,X ; FSTAT

And, is there a reason (bug workaround, compatibility, etc.) for this:

 LDA ,X
 ORA #$80
 STA ,X

instead of this shorter version?
(AFAIK, the remaining FSTAT bits are indifferent at this stage):

 LDA #$80
 STA ,X

I still find this version to use less RAM.


Message Edited by tonyp on 2008-02-25 02:55 PM
0 项奖励
回复

1,247 次查看
JimDon
Senior Contributor III
Thanks guys !!!!

Well, for one thing I used a variation of the code from an app. note to be safe.

The loop will terminate if if there is an error? I had thought that the code was so as it was not assured of loop exit if error, but it seems not, so great.
I admit I am not familar enough with 08 asm language to quickly see these tweaks, plus I try not to write obfuscated code but in a case like this, it is perfectly fine! This code is short and should not require maintenance.


Code:
#define Page_Erase   PGM[2]=0x40; ((void(*)(unsigned int, unsigned char))(PGM))
#define Program_Byte PGM[2]=0x20; ((void(*)(unsigned int, unsigned char))(PGM))

//Array of opcode instructions of the Erase/Program function in the HCS08 family
// A = data, X = Address.
volatile unsigned char PGM[18]  = { 
0xF7,              // STA ,X   Save the data byte into the address.
0xA6,0x00,         // LDA cmd
0xC7,0x18,0x26,    // STA   _FCMD
0xA6,0x80,         // LDA    FCBEF bit
0xc7,0x18,0x25,    // sta       FSTAT 
0x44,              // lsra - one byte - longer delay than nop
0xc5,0x18,0x25,    // Bit fstat
0x27,0xfb,         // BEQ *-3
0x81               // RTS
};
byte FlashErasePage(word page)
{
  
   byte im;
   asm TPA         // get that flags
   asm STA im      // save the flags
   asm SEI         // kill IM bit

   if (FSTAT&0x30){                    //Check to see if FACCERR is set
      FSTAT = FSTAT | 0x30;            //write a 1 to FACCERR to clear
   }

   Page_Erase(page,0);
  
   asm LDA im                          // put the im bit bak
   asm TAP

   if (FSTAT&0x30){                     //check to see if FACCERR or FVIOL are set
     return 0xFF;                       //if so, error.
   }
  
   return 0; 
 
}
byte FlashProgramByte(word address, byte data)
{
   byte im;
   asm TPA
   asm STA im
   asm SEI

   if (FSTAT&0x30){                    
      FSTAT = FSTAT | 0x30;           
    }

   Program_Byte(address, data);
  
   asm LDA im
   asm TAP
   if (FSTAT&0x30){                     //check to see if FACCERR or FVIOL are set
     return 0xFF;                       //if so, error.
   }
  
   return 0; 
 
}

 



0 项奖励
回复

1,247 次查看
bigmac
Specialist III
Hello Jim,
 
While it does not influence the amount of RAM used, and may be a relatively minor point, I see that you have consistly used the statement -
 
if (FSTAT & 0x30){
   FSTAT = FSTAT | 0x30;
}
 
Is it not sufficient to simply use the following?
 
FSTAT = FSTAT | 0x30;
 
Why bother testing FSTAT - simply clear the flags.  If they are already clear, nothing will happen.
 
Regards,
Mac
 
0 项奖励
回复

1,247 次查看
tonyp
Senior Contributor II

bigmac wrote:
Why bother testing FSTAT - simply clear the flags.  If they are already clear, nothing will happen.


As bigmac says, a direct write works perfectly.

Unfortunately, the flowchart offered by Freescale is misleading in that it clears the flags only if these are set.  This is certainly incorrect, as writing ones to those bits will not set them into error state, or else my current working code would fail.

0 项奖励
回复

1,247 次查看
bigmac
Specialist III
Hello Tony,
 
I was originally thinking that the flag clearing required read-modify-write, as with many other flags.  However, on checking with the data sheet, these flags only require a write to clear them.  This is explicitly stated within the description for each flag.
 
FSTAT = 0x30;  // This should work if flags are set, and have no effect if flags are clear.
 
JimD,
With the interrupt control process within the erase and program functions, I see that you are creating a local variable (on the stack), and then writing to it using inline assembly.  Probably better to directly push the value on the stack.  So your functions might look like this.
 
byte FlashErasePage( word page)
{
   volatile byte temp;
 
   asm {
      TPA  
      PSHA    // Save current status  
      SEI     // Disable interrupts
   }
   FSTAT = 0x30;  // Clear FACCERR & FPVIOL flags
   temp = Page_Erase( page, 0);  
   asm {
      PULA   // Restore previous status
      TAP
   }
   return temp;
}
 
byte FlashProgramByte( word address, byte data)

   volatile byte temp;
 
   asm {
      TPA  
      PSHA    ; Save current status  
      SEI     ; Disable interrupts
   }
   FSTAT = 0x30;  // Clear FACCERR & FPVIOL flags
   temp = Program_Byte(address, data);
   asm {
      PULA   ; Restore previous status
      TAP
   }
   return temp;
}
 
However, since assembly is being used, why not stick entirely with assembly, and also avoid the need for the complex incantations within the macros - well I find them complex.  The following might be a possibility.
 
byte FlashErasePage( word page)
{
   volatile byte temp;
 
   asm {
      TPA  
      PSHA        ; Save current status  
      SEI         ; Disable interrupts
      LDA   #0x30
      STA   FSTAT ; Clear FACCERR & FPVIOL flags
      LDA   #0x40 ; ERASE command
      STA   PGM:2
      LDHX  page
      JSR   PGM   ; Execute RAM routine
      STA   temp  ; Return value
      PULA        ; Restore previous status
      TAP
   }
   return temp;
}
 
byte FlashProgramByte( word address, byte data)

   volatile byte temp;
 
   asm {
      TPA  
      PSHA        ; Save current status  
      SEI         ; Disable interrupts
      LDA   #0x30
      STA   FSTAT ; Clear FACCERR & FPVIOL flags
      LDA   #0x20 ; PROGRAM command
      STA   PGM:2
      LDHX  address
      LDA   data
      JSR   PGM   ; Execute RAM routine
      STA   temp  ; Return value
      PULA        ; Restore previous status
      TAP
   }
   return temp;
}
 
Finally, on the subject of "padding" delays, a benign, single byte instruction is TST  ,X.  This provides a delay of 3 cycles for the 9S08.
 
Probably not relevant here, but a very simple way to generate much longer delays using 4 bytes -
 
  lda   #<delay_value>
  dbnza *   ; 4 cycles per loop
 
Regards,
Mac
 


Message Edited by bigmac on 2008-02-26 07:28 AM
0 项奖励
回复

1,247 次查看
JimDon
Senior Contributor III
I had the same thought, but again this is from Freescale sample code.
I seems like it should be ok to do that.

Couldn't all this code be in flash as well?
0xF7,              // STA ,X   Save the data byte into the address.
0xA6,0x00,         // LDA cmd
0xC7,0x18,0x26,    // STA   _FCMD
0xA6,0x80,         // LDA    FCBEF bit


In my world I don't even get the error return, as if the burn code is correct, it means either you have a bug (trying to write some where that is not flash) or the part is cooked, meaning once the code is verified correct, this  should never happen in any recoverable way.

Besides, who are you going to report the bad return to?

Tonight I will write a stack version - 18 bytes is not enough to be a nasty surprise.

In the future, see if you can get FSL to post the sample code here before publishing :--)

The "red ink" would do us all some good.




Message Edited by JimDon on 2008-02-25 12:25 PM

Message Edited by JimDon on 2008-02-25 12:27 PM
0 项奖励
回复