Writing variables to Flash on a GT60

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

Writing variables to Flash on a GT60

4,437 Views
Noodles
Contributor I
I am developing a program on a GT60 which has calibration values that need to persist when the unit is powered down.  I've been searching the forums for help on how to write a variable to the Flash but I've had difficulty finding useful information.  I would be grateful if anybody could help me out or direct me towards a thread or other documentation with the information I am looking for.  Example code would be useful.
Labels (1)
0 Kudos
17 Replies

779 Views
CompilerGuru
NXP Employee
NXP Employee
As the A1 version is assembly only, it does not really need the RELOCATE to. So that would simplfy the prm a bit.
The assembly routine could save two bytes by loading the address of
FSTAT into H:X.

Daniel

void Flash_Cmd( void)
{
   __asm {
      STA  ,X
      LDA  #0     ; Pre-loaded command
      LDHX @FCMD
      STA  ,X
      LDA  #0x80  ; FCBEF mask
      STA  1,X    ; FSTAT (FSTAT == FCMD + 1)
      TST  ,X     ; 3 cycle delay
      LSRA        ; FCCF mask (0x40)
L1:   BIT  ,X  ; Test for flag set
      BEQ  L1     ; Loop if not
   }
}



0 Kudos

779 Views
bigmac
Specialist III
Hello Daniel,
 
The final test of the FCCF bit  within FSTAT would actually require -
      LSRA        ; FCCF mask (0x40)
L1:   BIT  1,X    ; Test for flag set
 
or alternatively,
      LSRA        ; FCCF mask (0x40)
      INCX
L1:   BIT  ,X     ; Test for flag set
 
Since these need an extra byte, the saving would therefore be one byte.  The modification also assumes that the location of FSTAT, relative to FCMD, will remain constant for all S08 devices.  This may be the case, but I am not sure.
 
Regards,
Mac
 


Message Edited by bigmac on 2008-02-27 02:41 PM
0 Kudos

779 Views
CompilerGuru
NXP Employee
NXP Employee
Ups. Bug on my side, I initially saw that FSTAT is lower, but I got it wrong afterwards.
Better:

void Flash_Cmd( void)
{
   __asm {
      STA  ,X
      LDA  #0     ; Pre-loaded command
      LDHX @FSTAT
      STA  1,X    ; to FCMD
      LDA  #0x80  ; FCBEF mask
      STA  ,X
      TST  ,X     ; 3 cycle delay
      LSRA        ; FCCF mask (0x40)
L1:   BIT  ,X     ; Test for flag set
      BEQ  L1     ; Loop if not
   }
}


With Assembly the 1 in STA 1,X can be easily computed
there is no problem subtracting two absolute labels. In HLI, I did not see how to compute "(char*)&FCMD - (char*)&FSTAT" to get 1 at compile time. Without that STA 1,X, it still saves one byte. I did not see any side effect of reading FCMD (the tst ,x).

Daniel

0 Kudos

779 Views
CompilerGuru
NXP Employee
NXP Employee
Note also that HCS08RMV1.pdf defines the addresses of FSTAT and FCMD.
Therefore I think for all S08's it is OK to define their address explicitly as new macros and use them afterwards locally. So that way an explicit subtraction works.

Daniel
0 Kudos

779 Views
greatj
Contributor I

Hi guys

 

I am not sure this is the right place to put HCS12 issues, but as it is related to code porting from HCS08 to HCS12 u may help me out.

 

I was able to port the above code successfully  HCS12 microcontroller MC9s12NE64, just one small issue. In the function CopyInRAM , I had to assign explicitely RAM staring value to make the code work, otherwise code crashes,

 

HCS08 CODE:

void CopyInRAM(void)
{
  char *srcPtr;
  char *dstPtr;
  int count;
  srcPtr = (char *)Start_Copy_In_RAM;
  dstPtr = (char *)&Flash_Cmd;
  for (count = 0; count < (int) Size_Copy_In_RAM;  count++, dstPtr++, srcPtr++)
  {
    *dstPtr = *srcPtr;
  }   
}

 

HCS12 Code

void CopyInRAM(void)
{
  char *srcPtr;
  char *dstPtr;
  int count;
  srcPtr = (char *)Start_Copy_In_RAM;
  dstPtr = (char *)0x2000;
  for (count = 0; count < (int) Size_Copy_In_RAM;  count++, dstPtr++, srcPtr++)
  {
    *dstPtr = *srcPtr;
  }   
}

 

the question is why the code is not taking the starting addrtess of RAM from  Flash_Cmd and why it has to be explicitely defined.

0 Kudos

779 Views
Ake
Contributor II
Hello,
Here is a code example on how to do Flash EPROM erase/programming.
It is written in C under Processor Expert and there is some notes on what to think about.
 
Regards,
Ake
 
0 Kudos

779 Views
Ake
Contributor II
Ohoh, I forgot the code. Here it is.
The code is written for the 9S08GB60 but will run on the 9S08GT60.
 
Ake
 
Message Edited by t.dowe on 2009-10-27 12:47 PM
0 Kudos

779 Views
Noodles
Contributor I
Ake,

Thanks for the sample code.  It looks very helpful.  However, I am unclear on one thing.  I see code here for writing to the Flash, but not for reading this value back from the Flash later on.  Is there a specific procedure for doing this?

Thanks for your help,
Noodles
0 Kudos

779 Views
allawtterb
Contributor IV
To read EEPROM I use a simple macro, READ_EEPROM_BYTE:

Code:
#define EEPROM_BASE 0x1400  // Base address for EEPROM memory in a DZ60#define DYNAMIC_GROUP_OFFSET 0x40 // Offset for storage of dynamic group#define READ_EEPROM_BYTE(x) *(uint8_t *)(x + EEPROM_BASE) // Macro to retrieve a byte from an absoulte address in EEPROM memory...unsigned char Read_Data;Read_Data = READ_EEPROM_BYTE(DYNAMIC_GROUP_OFFSET);    // Read from an offset value in EEPROM memory...
 
The same can be done for Flash, reading from EEPROM/Flash doesn't require a special routine.  Just set a pointer to a location in EEPROM/Flash and de-reference it for the value stored at that location.

 
0 Kudos

779 Views
bigmac
Specialist III
Hello,
 
If a variable is defined at a specific location within the flash page used for non-volatile data, simply read the contents of the variable.  As an example, look at the way in which the CW header file for the GT60 defines the NVPROT and NVOPT registers at their specific flash addresses..
 
Regards,
Mac
 
0 Kudos

779 Views
CompilerGuru
NXP Employee
NXP Employee
I just looked at the code and I like it as it really looks straight forward.

I did not see any single problem, so I only have cosmetic remarks.

- I would move the FlashBuffer variable into main.c, as it is more part of the sample application, without it,
  S08_Flash.c makes sense unmodified in other projects too.

- I would add some
#ifdef __cplusplus
extern "C"
#endif
calling convention gards in S08_Flash.h.
- Also consider using
#pragma push
...
#pragma pop

instead of the #pragma CODE_SEG DEFAULT
in the header.
The current CODE_SEG section is stored as part of the #pragma push/pop

How specific is the code to the GB60? I wonder if   "MC9S08GB60.h" has to be included in the header, if it
is not sufficient to include it in the C file.

and for macros, I would always place some braces around the actual arguments

> #define Flash_Erase(Address) \
>         Flash_Cmd((unsigned int)(Address), (unsigned int)1,  \
> (unsigned char*) &FlashBuffer[0], FLASH_ERASE_CMD)

Daniel


0 Kudos

779 Views
bigmac
Specialist III
Hello,
 
For anyone intending to use Ake's code for devices other that the GB/GT, the resources required by the
code should be considered.  The method places the RAM based function within a fixed block of RAM,
and this block remains dedicated to the erase/programming process.
 
A block size of 128 bytes has been allowed within the code, and the actual code size generated for the
function seems to be 101 bytes.  This does not include any RAM as a buffer for the data to be written, in
the case of burst programming.
 
This amount of RAM is likely to be very significant for a device with less than 1K of RAM, for example
QG8 or QG4, and potentially makes the code unworkable for such devices.  For the low end
MCUs, alternative methods will likely be necessary.
 
The other alternative would be to use the stack, rather than a dedicated block, for the RAM based
function(s).  Some versions that use this method (identified by the DoOnStack label), seem to need
about 70-80 bytes of RAM, but this is probably due to the RAM based routines being written in assembler,
rather than C.
 
Obviously, the stack size will need to be sufficiently large, but the memory does become available again,
once the function is completed.  Since interrupts need to be disabled during execution of the function, the
stack size requirement, beyond the function size, should be minimal provided the erase or programming
function calls are not too deeply nested.
 

Ake, there were a couple of issues associated with your code -

 

1) The linking initially failed because the reset vector was defined in two places (with the use of
MCUInit() function).


2) I received a C1805 warning at the line -

dstPtr = (char *)&Flash_Cmd;

However, the pointer value was actually correct (0x0100).  The warning is "Non standard conversion
used".

 

3) The following description seems a little confusing to me -
/*
Start_Copy_In_RAM refers to the begining of the segment ToCopyToRAM.
This segment contains the functions after they have been copied to RAM.
*/
#define Start_Copy_In_RAM __SEG_START_FLASH_ROUTINES
#define Size_Copy_In_RAM __SEG_SIZE_FLASH_ROUTINES

The macro actually refers to the source address of the code block.  The segment contains the functions
as they exist in flash.

 
4) Finally, the following macro doesn't seem to make sense.
#define Flash_Erase(Address) \
  Flash_Cmd((unsigned int)Address, (unsigned int)1, (unsigned char*) &FlashBuffer[0], FLASH_ERASE_CMD)
 
FlashBuffer seems to be defined as a global RAM buffer for the source data during burst programming.
Its reference would seem unnecessary for the Flash_Erase.
 
Regards,
Mac
 


Message Edited by bigmac on 2008-02-25 04:23 AM
0 Kudos

779 Views
CompilerGuru
NXP Employee
NXP Employee
Instead of the copy to stack method approach, the FLASH_ROUTINES section could also be allocated just below the stack for devices with a small RAM.
With an additional CopyInRAM call before calling the routines in Ram, code not using the flashing routines could reuse that RAM as stack space just as the copy to stack versions.
One drawback is though that this does require an explicit stack size in the prm and not just a stacktop as in the original prm.
The warning can be avoided with an additional cast to void*.

Daniel

0 Kudos

779 Views
bigmac
Specialist III
Hello Daniel,
 
Rather than defining an explicit stack size, is it possible to automatically locate the temporary block immediately above the globals and statics used by the project?  This would maximize the available stack space.
 
What is the disadvantage of using the copy to stack method, apart from using a bit of assembly code with existing implementations?
 
Regards,
Mac
 
0 Kudos

779 Views
CompilerGuru
NXP Employee
NXP Employee
The choice of whether to use (inline) assembly is independent of that design decision,
for example ProcessorExpert's flash bean is using a pure C version.
Using (some) assembly helps of course with the code and ram usage.

Anyway, comparing execute on stack vs link time buffer (/address)

- support for relocatable code:
The link time buffer does support to relocate the C code. Conceptually HC08 code is not relocatable. However relocating it works anyway is most of the cases, especially for for small functions which are typical for these kind of tasks.
Relocated code will also show the proper C code associated in the debugger.
(Is stepping through the flash programming routines possible? If not, then at least when looking at trace output, the source code is available).
Also debugging is conceptually much easier with code addresses at fixed, link time addresses, then at addresses which do depend on the invocation.

- prm file adaptations
With relocatable support the static buffer version does need an adapted prm file.
And if the buffer should be reused as stack space for other parts of the app, then that also includes to define a fixed (base) stack size. With the stack based version, the only (really important) adaptation is to provide a sufficently large stack space.

- exact function size
With the stack based HLI methods, only the actual number of bytes used by the functions can be pushed on the stack. With a plain C implementation of the stack based approach or with the link time buffer, the max size of the function to be copied into RAM has to be hard-coded, and may therefore be suboptimal (and is problematic with code changes).

- stack based approach needs a bit more advanced C/HLI programming as both the copy to RAM and execute on the stack are less commonly used. I consider it to be more advanced that the copy to fixed buffer version.

As summary, I in order to generate a simple, robust and easy to understand lib, I would probably use a link time address and program it in C only, just as in Ake's version (which I like :smileyhappy:.
In order for a super optimized, squeeze out the last (RAM) byte version, I would stick with a assembly only (ev. HLI) version and copy (push) the code to be run onto the stack.

Daniel

PS: No, I don't see how placing it at the end after all global vars would automatically work :smileysad:, at least not with the RELOCATE_TO directive.

0 Kudos

779 Views
J2MEJediMaster
Specialist I
Do a search on AN2295 in this forum. This Application Note describes a bootloader with Flash/EEPROM programming support that covers just about every 8-bit part Freescale has. The person managing the note just did a big update on it recently.

in fact, here's the relevant forum thread. HTH.

---Tom


Message Edited by J2MEJediMaster on 2008-02-22 11:32 AM
0 Kudos

779 Views
peg
Senior Contributor IV
Hi,

Use the words "flash" and "EEPROM" in your search.
There are hundreds of threads on this.

0 Kudos