Writing into Flash memory for MC9S12C32

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

Writing into Flash memory for MC9S12C32

6,479 Views
armitron
Contributor I
Hi,

I'm using Flash routines based on the AN2720 download from Freescale to erase/write into the Flash of my MC9S12C32 microprocessor. However, since the coding in the AN2720 files are designed for the MC9S12DP256 microprocessor and are made for memory banks with 64 kb of storage, how would I modify the software files in the AN2720 folder to suit my needs for the SMALL memory for the MC9S12C32? For example, in the flash.c file, I removed all of the "far*" variable names since they are not needed, but I was not sure what else to remove/change in the flash.c file.

Any help would be appreciated.
Labels (1)
0 Kudos
Reply
11 Replies

2,715 Views
armitron
Contributor I
Hmm...I've set the initial setting to SMALL memory for the MC9S12C32...so I don't believe that's the problem...

I've just been running the source code from the AN2720 folder to try and write/erase Flash on the MC9S12C32. The modified code I have so far seems to run okay on the Real-Time Simulator as long as I Single-Step through the code. However, when I check the Memory at address $4000, I only notice an "A" character and a bunch of "FF" characters that follow after it. So, the problem seems to be that the program is not writing the correct word "ABCD" into address $4001. Any suggestions on how to fix the code?

Again, any help would be greatly appreciated.

Here is the modified code based off of AN2720 so far:

#include /* common defines and macros */
#include /* derivative information */
#pragma LINK_INFO DERIVATIVE "mc9s12c32"
#define Flash_Odd_Access -1
#define Flash_Not_Erased -2
#define Access_Error -3
#define Protection_Error -4
#define Not_StartofSector_Error -5
//#define PAGE 0x3E0000

#define Flash_Sector_Size 0x400 /* must be modified for particual device */
extern DoOnStack(unsigned int* address);

// Prototypes
void Flash_Init(unsigned long oscclk);
signed char Flash_Write_Word(unsigned int* address, unsigned int data);
signed char Flash_Erase_Sector(unsigned int* far_address);
signed char Flash_Write_Block(unsigned int* address_source,\
unsigned int* far_address_destination,\
unsigned int count);
signed char Flash_Erase_Block(unsigned int* start_address,\
unsigned int* end_address);

const volatile unsigned char caliz1 @ 0xD002 = 'A';
//const volatile unsigned char far caliz2 @(PAGE+0xB400) = 'B';
const volatile unsigned char caliz3 @ 0x8000 = 'A';

void EXIT(void) {
for(;:smileywink: {} /* wait forever */
}

void main(void) {
/* put your own code here */
volatile unsigned char a,rval;
unsigned long i;
a = caliz1;
a = caliz3;

Flash_Init(16000); //osc freq
rval=Flash_Erase_Sector((unsigned int*)0x4001);
rval=Flash_Write_Word((unsigned int*)0x4001,0xABCD);
//rval=Flash_Erase_Sector((unsigned int *far)0x4000);
//rval=Flash_Write_Word((unsigned int *far)0x4000,0xABCD);
//for (i=0x3C; i0x40; i++)
//{
// rval=Flash_Erase_Sector((unsigned int *far)((i16) + 0xB400));
// rval=Flash_Write_Word((unsigned int *far)((i16) + 0xB400),0xABCD);
// rval=Flash_Write_Word((unsigned int *far)((i16) + 0xB800),0xABCD);
// rval=Flash_Write_Word((unsigned int *far)((i16) + 0xBC00),0xABCD);
//}

//a = caliz2;


EnableInterrupts;
for(;:smileywink: {} /* wait forever */
/* please make sure that you never leave this function */
}

#pragma MESSAGE DISABLE C1860 //Pointer conversion, Possible loss of data

void Flash_Init(unsigned long oscclk)
{
unsigned char fclk_val;

/* Next, initialize FCLKDIV register to ensure we can program/erase */
if (oscclk >= 12000) {
fclk_val = oscclk/8/200 - 1; /* FDIV8 set since above 12MHz clock */
FCLKDIV |= fclk_val | FCLKDIV_PRDIV8_MASK;
}
else
{
fclk_val = oscclk/200 - 1;
FCLKDIV |= fclk_val;
}

FPROT = 0xFF; /* Disable all protection (only in special modes)*/
FSTAT |= (FSTAT_PVIOL|FSTAT_ACCERR);/* Clear any errors */
}

signed char Flash_Write_Word(unsigned int* far_address,unsigned int data)
{
unsigned int* address;
unsigned char i;
address = (unsigned int*)far_address; // strip page off
FSTAT = FSTAT_ACCERR | FSTAT_PVIOL;
if((unsigned int)address & 0x0001) {return Flash_Odd_Access;} // Aligned word?
if(*far_address != 0xFFFF) {return Flash_Not_Erased;} // Is it erased?
for(i=0;i4;i++) {
FCNFG = i;
FSTAT = (FSTAT_ACCERR_MASK | FSTAT_PVIOL_MASK); // clear errors all banks
} /* */

FCNFG = 0x00;

(*far_address) = data; // Store desired data to address being programmed

FCMD = 0x20; // Store programming command in FCMD
(void)DoOnStack(far_address); // just passed for PPAGE
if (FSTAT_ACCERR) {return Access_Error;}
if (FSTAT_PVIOL) {return Protection_Error;}
return 1;
}

signed char Flash_Write_Block(unsigned int* address_source,\
unsigned int* far_address_destination,\
unsigned int count)
{
unsigned long i; // long supports > 64K words
signed char ret_val;

for (i = 0;i
{
ret_val = Flash_Write_Word(far_address_destination++, *address_source++);
if (ret_val == Access_Error) {return Access_Error;}
if (ret_val == Protection_Error) {return Protection_Error;}
}
return 1;
}

signed char Flash_Erase_Sector(unsigned int* far_address)
{
unsigned int* address;
unsigned char i;
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;}
for(i=0;i4;i++) {
FCNFG = i;
FSTAT = (FSTAT_ACCERR_MASK | FSTAT_PVIOL_MASK); // clear errors all banks
} /* */

FCNFG = 0x00;

FSTAT = (FSTAT_ACCERR | FSTAT_PVIOL); // clear errors
(*far_address) = 0xFFFF; /* Dummy store to page to be erased */

FCMD=0x40;
(void)DoOnStack(far_address);
if (FSTAT_ACCERR) {return Access_Error;}
if (FSTAT_PVIOL) {return Protection_Error;}
return 1;
}

signed char Flash_Erase_Block(unsigned int* start_address,\
unsigned int* 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*)address);
if (ret_val == Access_Error) {return Access_Error;}
if (ret_val == Protection_Error) {return Protection_Error;}
address = address+Flash_Sector_Size;
}
return 1;
}

#pragma MESSAGE DEFAULT C1860 // Pointer conversion, Possible loss of data
0 Kudos
Reply

2,715 Views
tabull
Contributor I
    As far as I know, this problem has never been resolved. If I am mistaken, please steer me to the appropriate msg.

As written here by armitron, the line

rval=Flash_Erase_Sector((unsigned int*)0x4001);

will not work because the alignment is not right, however, because the error-checking will abort the routine the program will continue to the next statement

rval=Flash_Write_Word((unsigned int*)0x4001,0xABCD);

which will also not work, but the first time through the program

rval=Flash_Write_Word((unsigned int*)0x4000,0xABCD);

will work using the P&E Multilink, because the debugger will have erased the entire flash so 0x4000 will be 0xFF. But it can't be done again, because a call to Flash_Erase_Sector will not set the location back to 0xFF. In fact, trying

rval=Flash_Erase_Sector((unsigned int*)0x4000);

will send things into la-la land, and I have not been able to determine why no matter how many breakpoints, etc, I set.

The gurus at Freescale assured me that this would all be straightforward, but 'tain't so. There are numerous lines in AN2720 that I can't make sense of. For example,

for(i=0;i<4;i++) {
FCNFG = i;
FSTAT = (FSTAT_ACCERR_MASK | FSTAT_PVIOL_MASK); // clear errors all banks
} /* */

According to the Flash Module Guide, only bits 5, 6, and 7 are accessible in FCNFG, and bit 5 KEYACC only if KEYEN is set in the FSEC register, and all bits in FSEC are readable but not writable.

The next line

FCNFG = 0x00;

is the default at reset. I can't figure out what

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

is supposed to do, or even if it will do anything at all without employing DoOnStack. In the Flash_Init routine we see

FPROT = 0xFF; /* Disable all protection (only in special modes)*/

but at least with my NanoCore12 FPROT is 0xFF on reset. I tried setting FPROT = 0x18 to specifically unprotect the lower part of flash, but that didn't seem to help. What the comment about "only in special modes" means I can't fathom and the Flash Module Guide was not very helpful.

Since Flash_Write_Word will work when the location is 0xFF, DoOnStack works at least for Flash_Write_Word.  Again, the Freescale experts assured me that development with the HC9S12C32 would be _way_ easier than using the MC68HC11F1, but at this point I am stuck. AN2720, which is supposed to be a guide to using Flash as EEPROM has many lines that can only be comprehended by someone who already knows how to do this operation. Experts, characteristically, make easy assumptions about the reader, frequently making things cryptic. There are other lines that are not clear, but 'nuff for now. Code Warrior writes ILLEGAL_BP after running this program as I have modified it from armitron's msg, but the CW help files are not helpful, at least I couldn't find out anything.

Working alone as I do, and as an autodidact without any formal training, sometimes things become opaquely problematic. I have been successful with all other aspects of setting up the chip thus far such as writing to LCDs through SPI, button input, flip-flops, and so on. I am willing to spend a lot of time searching for my own solutions to problems I encounter, but I could sure use some useful guidance for Flash as EEPROM, and I suspect "armitron" might as well. Surely someone has used Flash as EEPROM using the HC9S12C32.

I hope someone is willing to help constructively.

Thanks,
Dan
0 Kudos
Reply

2,715 Views
Alban
Senior Contributor II
Hello Dan,

I aim to think that these "Experts" as you call them try to share they knowledge and don't deliberately obsfuscate descriptions.

  • I will forward your indications about AN2720 to its author. I don't know if I will get an answer or not.

  • FPROT = 0xFF; /* Disable all protection (only in special modes)*/
FPROT is read over from the Flash at 0xFF0F and then loaded in the register space. You cannot have your software change its content on the fly. You need to change the Flash content and then generate a reset to change its status in your program.

Special modes are defined in the device datasheet (see MODA, MODB and MODC used). The most used is Special Single Chip Mode (SSCM) which is the MCU with the BDM enabled but no external bus.
In this case, you can edit FPROT at any time.

  • rval=Flash_Erase_Sector((unsigned int*)0x4000); will send things into la-la land, and I have not been able to determine why no matter how many breakpoints, etc, I set.
If you have the software at $4000 and you erase the page, you lose the execution and will probably see $FFFF all around in the debugger. That's what it does with me.

  • what (*far_address) = 0xFFFF; /* Dummy store to page to be erased */ is supposed to do, or even if it will do anything at all without employing DoOnStack.
When you do a page erasure, you need to specify which page you want to erase. The address of the page is latched in the FADDR register when you do a WRITE. The *far in this case is not necessary as it is a 16-bit address.

  • Illegal Breakpoint
It means the software crashed, basically. There are a lot of reasons for it. In our case, it could be because you delete the page it is supposed to execute from. For instance, deleting page 0xFFFF deletes the vector table.
Upon reset, the software will look at 0xFFFF where is should execute from. As it will read 0xFFFF (erased state), it will start executing the code at 0xFFFF. The code will be 0xFFFF which is not a legal instruction, so it causes a reset... and so on.

A lot of questions are resolved by Freescale formal support system (Service Requests) and posters don't always post their resolution, when they have one.

What type of training material would you be interested in ?

I hope I helped you see a bit clearer.

Alban.
--
Edit: replaced guru by experts


Message Edited by Alban on 2007-05-08 01:34 PM
0 Kudos
Reply

2,715 Views
tabull
Contributor I
    Hello, Alban

I did not mean to imply that the "experts" were deliberately obfuscating.  I personally am an "expert" (or at least I used to be) on fermentation and bioprocesses.  Very often when I tried to explain some phenomenon to a layman I would be accused of this very sort of obfuscation.  This would usually surprise me, and I would retreat to a position of very carefully explaining _every_ detail as much as possible.  One consequence is that transmitting info involved substantially more text (or spoken words, as the case may be.)  Anyway, my apologies if I came across inappropriately.  AN2720, I think, is written from the viewpoint of a Paged Flash, which will be different from the 'C32 but I'm not sure just how.

==========
FPROT is read over from the Flash at 0xFF0F and then loaded in the register space. You cannot have your software change its content on the fly. You need to change the Flash content and then generate a reset to change its status in your program.

Special modes are defined in the device datasheet (see MODA, MODB and MODC used). The most used is Special Single Chip Mode (SSCM) which is the MCU with the BDM enabled but no external bus.
In this case, you can edit FPROT at any time.

==========
Here is an example of what I was trying to get at. Your explanation is quite comprehensible.  However, lacking your msg, I don't know how to figure out the mode using the BDM on my own.  The info is probably _somewhere_, but it is a real chore to find it, although I recognize that is part of my responsibility.  I found that I could edit FPROT, but did not know it was due to the reason you describe.  I did read about how special modes are entered, but since I could edit FPROT I became confused.

According to Chapter 18 Rev. 01.22 of the MC9S12C-Family Guide the FSEC register is read from 0xFF0F on reset, and FPROT is read from 0xFF0D, the Flash Protection byte (p. 514).  So I guess I have to unprotect the high part of the Flash and then change 0xFF0D.  Then I have to run the program again modified so the high part will not be erased so the desired value will be read into FPROT.  Apparently FSEC is readable but not  writable by the user (p. 511).  If I am not using the BDM I will normally not be in special mode (sic), so using Flash as EEPROM will be quite different while debugging than at runtime.  In any event, none of this is in AN2720, unless I am badly mistaken.  Plus, the HiWave debugger _always_ erases _all_ Flash, does it not?

This becomes even more problematical as without the BDM I need some sort of I/O to tell me if the Sector is erased or not.  Not impossible, but not what I thought I could do.  Remember, I am a neophyte.

=========
  • rval=Flash_Erase_Sector((unsigned int*)0x4000); will send things into la-la land, and I have not been able to determine why no matter how many breakpoints, etc, I set.
If you have the software at $4000 and you erase the page, you lose the execution and will probably see $FFFF all around in the debugger. That's what it does with me.
========
I am guessing you mean the program is loaded at $4000. When I look at address $4000 when the debugger first starts, that whole sector is written with 0xFF.  La-la land was a bit hyperbolic, but it was not clear to me what single step was executing.  I would either see a whole succession of LDS instructions (Load Stack Pointer) or a bunch of BKGNDs, which is not in my CPU12 book.

========
  • what (*far_address) = 0xFFFF; /* Dummy store to page to be erased */ is supposed to do, or even if it will do anything at all without employing DoOnStack.
When you do a page erasure, you need to specify which page you want to erase. The address of the page is latched in the FADDR register when you do a WRITE. The *far in this case is not necessary as it is a 16-bit address.
========
Thanks, that helps.  In this case, the *far is part of the variable name, and is an artifact from editing AN2720.  So, if my intent is to erase the Flash Sector at $4000, that line should be not (*far_address)=0xFFFF; but rather (*far_address)=0x4000;  Is this correct?

========
Illegal Breakpoint
It means the software crashed, basically. There are a lot of reasons for it. In our case, it could be because you delete the page it is supposed to execute from. For instance, deleting page 0xFFFF deletes the vector table.
Upon reset, the software will look at 0xFFFF where is should execute from. As it will read 0xFFFF (erased state), it will start executing the code at 0xFFFF. The code will be 0xFFFF which is not a legal instruction, so it causes a reset... and so on.
=======
I am trying to write the SW so only one sector at $4000 is erased, but maybe I'm doing more without realizing it.

========
A lot of questions are resolved by Freescale formal support system (Service Requests) and posters don't always post their resolution, when they have one.

What type of training material would you be interested in ?
========
I'm reluctant to ask for this info through a Service Request as it feels as though I'm asking Freescale to write my SW for me.  I'm more comfortable in the forum setting, rightly or wrongly, as I regard it as sharing info with others who have struggled with one problem or another.  That's the democrat (with a small d) in me.  As for training material, I wish I knew what to ask for.  I "attended" CodeWarriorU, but that was rather limited.  Finding stuff on the Freescale site is, for me, _very_ tricky and not an easy task.

=========
I hope I helped you see a bit clearer.
=========
Your msg is very helpful, although I'm not sanguine that I will be able to run over and get things all fixed post-haste.  It does get me back to work, though.

Can you explain to me the portent of the lines with FCNFG I mentioned?

Thank you for your help.  Maybe I can get my thick head straightened out yet.

Dan

0 Kudos
Reply

2,715 Views
Alban
Senior Contributor II
Hello Dan,

There are two different notions with FRPOT and FSEC: Protection and Security.
The Protection is to avoid software overwritting itself.
The Security is to prevent users from reading the NVM (non volatile memory = Flash + EEPROM) content.

The firmware can access the regions whatever the status of FSEC.
However, is FSEC puts the MCU is "secured" state, you will not be able to debug, nor dump the content of the memory, only a mass-erase will allow you to get back into the chip in BDM.

In your case, you are only interested about FPROT @FF0D and not FSEC @FF0F. Ignore FSEC for now.

HiWave erases the whole Flash before programming, but immediately writes into FSEC to keep the device is unsecured.


If your debugger shows only 0xFF in the code window it is because it is trying to execute from an erased location. Reading the PC (Program Counter) tells you where it is executing from.

Background = asm BGND; is in the CPU12 datasheet and has the opcode "0x00".
LDS with a 16-bit operand has for opcode "0xFF". Therefore your debugger displays the code as being LDS #FFFF, as the matching code is "FFFFFF".

For free training material, I would advise you to click on TRAINING from http://www.freescale.com/support
Training link is in the bottom left part of the page, under the title explore.

Other questions, keep them coming !

Cheers,
Alban.

edit: links




Message Edited by Alban on 2007-05-09 11:36 AM
0 Kudos
Reply

2,715 Views
tabull
Contributor I
    Hello, Alban

I took a look at the training material you steered me toward.  I took the "course" on the Flash, and a number of things became much clearer.  I now know why the calls to FCNFG were legitimate in AN2720, and why I cannot use a similar scheme with the C32, and why FCNFG bits 0 and 1 are not accessible for that chip.

As for BGND, I totally goofed, looking for BKGND without checking out my own debugger windows.  Apologies.

Your wrote
"If your debugger shows only 0xFF in the code window it is because it is trying to execute from an erased location. Reading the PC (Program Counter) tells you where it is executing from."

I should have been clearer that the 0xFFs were in the memory window starting at $4000.  After running Flash_Write_Word under the circumstances I described, I saw AB CD starting at $4000, which was what I wanted to do.  It's Flash_Erase_Sector that I have not yet succeeded with, but I hope I'm getting closer.

You wrote:
"Other questions, keep them coming !"

OK.
1. Given that I only want to erase one sector starting at $4000, can I do this without using DoOnStack?
2. Can you steer me to training material about how triggers are handled for this system? I assume that triggers are set by the HiWave debugger, but maybe I'm wrong.
3. The "Address Range Protection" section of the Flash tutorial points out that to change the [Flash] protection in user mode requires changing (in my case) the Flash location $FF0D and reset the MCU to reload the modified FPROT from $FF0D.  It's not clear to me how I could do that.  Must I boot initially in special mode and then reset in user mode?  I think I'm missing something here.

Many thanks for all your help. There really are some good-guys left.

Dan

0 Kudos
Reply

2,715 Views
Alban
Senior Contributor II
Hello,

1. I don't understand what DoOnStack is. When you want to erase flash memory, you cannot execute the erasing code from the same flash block. So you do need to execute your code from somewhere else. The fact that you want to erase only one sector or the full block does not change the way to do it.

2. triggers of what ?

3. No, you just need to write the flash location as normal flash. But as the MCU is not using the value in flash but the register, you need to reset the MCU so the register takes the new value from flash. The register is not modifiable and loads its value from flash on resets only.
Between two write on the same location in flash, you need to do an erase.

Cheers,
Alban.
0 Kudos
Reply

2,715 Views
tabull
Contributor I
    Alban -
I see from the k-noo site that you are in Glasgow by way of France, two pluses in my view.

You wrote:
1. I don't understand what DoOnStack is. When you want to erase flash memory, you cannot execute the erasing code from the same flash block. So you do need to execute your code from somewhere else. The fact that you want to erase only one sector or the full block does not change the way to do it.

DoOnStack was first mentioned in this thread in a msg from armitron, who initiated this thread. Jim Sibigtroth wrote a routine for the '08 some time ago that carried out erasures by putting code on the stack that was used to carry out the erasure.  This along with similar material in AN2548  was later adapted for the MC9S12 in AN2720.  If it would help I could post the code for DoOnStack.  In this case the stack was the "somewhere else" you mentioned above.

The debugger shows in the Command window lines that declare four "Blocks" 0,1,2,3 named FLASH_4000 ranging from 0x4000 to 0x 7FFF, FLASH_C000 ranging from 0xC000 to 0xFFFF, ALL_PPAGES ranging from 0x3E0000 to 0x3FBFFF, and FLAT8000_3PE ranging from 0x8000 to 0xBFFF. The next four lines in the Command window are "FP: The UNPROTECT command is not available for the xxxx flash_module => Skipped."  I don't know what's happening here, and to my knowledge there is no list of HiWave debugger Commands with explanations.

Maybe the term "Block" is used unconventionally in this case, but I thought perhaps if I only wanted to erase a Sector in the FLASH_4000 block, and the code is at 0x8000, the FLAT8000_3PE block, I was already "somewhere else" and I could avoid having to execute code placed on the stack and then removed.  I guess the term "Block" refers to an array block, of which there is only one in the C32.  So, I need a somewhere else, and that may be easiest using the stack.

You wrote:
2. triggers of what ?

Well, I'm not sure. HiWave issues a msg "Trigger A occurred" and stops the processor.  I don't have a clue what caused "Trigger A" to happen.  The triggering mechanism can be disabled by right clicking in the Source window and choosing "Open Trigger Settings Dialog ... ."  I'd like to know more about this "feature" and how it is used.

You wrote:
3. No, you just need to write the flash location as normal flash. But as the MCU is not using the value in flash but the register, you need to reset the MCU so the register takes the new value from flash. The register is not modifiable and loads its value from flash on resets only.
Between two write on the same location in flash, you need to do an erase.

OK. I think I understand.

As always, thanks in advance.

Dan

0 Kudos
Reply

2,715 Views
Alban
Senior Contributor II
Hi Dan,

Thanks for the flattery, my head is big enough already...
K-Noo is Glasgwegian means Knowledge Now. In French, it means Only Ours (my and my 'wife' company).

1a. DoOnStack --> OK, I see. Jim Sib is a reference.

1b. The user guide would include all the info about HiWave commands. It is in a CodeWarrior installation folder, if it was selected during the installation. As the MegaByte is relatively cheap I used Full Installation.

1c. Please see the file I enclosed. This is a command file used to UNSECURE S12. Used usually with the P&E cable. Rename to .CMD and also change the value at the start to match your clock.

1d. Areas declared in the "Flash Window3 of HiWave reflect different addressing modes and some are overlapping others.
For instance 4000 and C000 are the standard flash visible directly in the MCU map (=logical map) without any paging. But the 4000 and C000 are also accessible via the paging scheme.
Blocks here are not hardware blocks. You need to look in the datasheet to see how many blocks you have on your device.
With only one flash block, you need to execute from RAM. The stack is in RAM, so no problem.

2. I see. These are linked to the DBG = Debug Module of the S12. The module is described in its block guide. This feature is used to debug your code. For instance stop the MCU is you see the value $6000 in the bus. Or if the MCU is writting at location $5600, for instance.

We are getting there. I can feel it :smileyhappy:

Cheers,
Alban.


0 Kudos
Reply

2,715 Views
tabull
Contributor I
    Hi, Alban -

You wrote:
We are getting there. I can feel it

Well, it seems we are there.  I think I have finally figured this thing out.  In case anyone else is having the same problem writing to Flash I am including the code that works for me.  The dereferenced variables MyValue1 and MyValue2 are displayed with the correct values in the debugger using the P&E Multilink.  Still, I haven't figured out how to store negative values. I guess I would just have to split the value into two words.

Sorry the listing is somewhat long for a forum msg.  Also note that in my app I don't need Flash_Write_block or Flash_Erase_Block so they have been dropped from flash.c.  Finally, I have used the variable name far_address but it is not cast as far.

Dan

The code (most of it):

/* main.c */
#include <hidef.h>      /* common defines and macros */
#include <mc9s12c32.h>  /* derivative information */
#include "flash.h"      /* defines for the FLASHEE routines */
#define PAGE 0x3E0000
#pragma CODE_SEG DEFAULT
#pragma LINK_INFO DERIVATIVE "mc9s12c32"

#pragma MESSAGE DISABLE C1860        //Pointer conversion: Possible loss of data


void main(void) {
//  EnableInterrupts;
  volatile signed char rval1, rval2, rval3, rval4;
  volatile unsigned int myvalue1, myvalue2;
    Flash_Init(8000);
    rval1=Flash_Erase_Sector((unsigned int *)0x4000);
    rval2=Flash_Write_Word((unsigned int *)0x4000,0xABCD);
    myvalue1 = (*(volatile unsigned int*)0x4000);
    rval3=Flash_Write_Word((unsigned int *)0x4002,0x4321);
    myvalue2 = (*(volatile unsigned int*)0x4002);
    rval4=Flash_Erase_Sector((unsigned int *)0x4000);

  for( ; ; ) {} /* wait forever */
}
#pragma MESSAGE DEFAULT C1860        // Pointer conversion: Possible loss of data     

/*******************************************************************
* Freescale
*
* DESCRIPTION: Header file for S12 single array Flash routines
* SOURCE: flash.h
* COPYRIGHT: © 04/2004 Made in the USA
* AUTHOR: rat579
* REV. HISTORY: (none)
*
*******************************************************************/
#ifndef FLASH_H /* Prevent duplicated includes */
#define FLASH_H
/* Functions from flash.c */
void Flash_Init(unsigned long oscclk);
signed char Flash_Write_Word(unsigned int *address, unsigned int data);
signed char Flash_Erase_Sector(unsigned int *far_address);
signed char Flash_Write_Block(unsigned int *address_source,\
unsigned int *far_address_destination,\
unsigned int count);
signed char Flash_Erase_Block(unsigned int *start_address,\
unsigned int *end_address);
/* Error codes */
#define Flash_Odd_Access -1
#define Flash_Not_Erased -2
#define Access_Error -3
#define Protection_Error -4
#define Not_StartofSector_Error -5
#endif /*FLASH_H*/

/*******************************************************************
 *
 *    DESCRIPTION:   S12 single array Flash routines
 *    SOURCE:        flash.c
 *
 *******************************************************************/
#include "flash.h"
#include <hidef.h>      /* common defines and macros */
#include <mc9s12c32.h>     /* derivative information */
#pragma LINK_INFO DERIVATIVE "mc9s12c32"

#define Flash_Sector_Size 0x200     /* must be modified for particular device */
extern DoOnStack(unsigned int* address);

#pragma MESSAGE DISABLE C1860        //Pointer conversion: Possible loss of data

//*****************************************************************************
//* Function Name    : Flash_Init
//* Description     : Initialize Flash NVM for HC9S12 by programming
//*                   FCLKDIV based on passed oscillator frequency, then
//*                      uprotect the array, and finally ensure PVIOL and
//*                      ACCERR are cleared by writing to them.
//*
//*****************************************************************************
void Flash_Init(unsigned long oscclk)
{
unsigned char fclk_val;
   
/* Next, initialize FCLKDIV register to ensure we can program/erase */
    if (oscclk >= 12000) {
        fclk_val = oscclk/8/200 - 1; /* FDIV8 set since above 12MHz clock */
        FCLKDIV |= fclk_val | FCLKDIV_PRDIV8_MASK;
    }
    else
    {
        fclk_val = oscclk/180 - 1;
        FCLKDIV |= fclk_val;
    }

//    FPROT = 0xFF; /* Disable all protection (only in special modes)*/
    FPROT = 0x18; /* Disable protection for 0x4000 - 0x4FFF (only in special modes)*/
    FSTAT |= (FSTAT_PVIOL|FSTAT_ACCERR);/* Clear any errors  */
}
//*****************************************************************************
//* Function Name    : Flash_Write_Word
//* Description     : Program a given Flash location using address and data
//*                   passed from calling function.
//*
//*****************************************************************************
signed char Flash_Write_Word(unsigned int *far_address,unsigned int data)
{
unsigned int *address;
    address = (unsigned int *)far_address;                        // strip page off
    FSTAT = FSTAT_ACCERR | FSTAT_PVIOL;
    if((unsigned int)address & 0x0001) {return Flash_Odd_Access;} // Aligned word?
    if(*far_address != 0xFFFF) {return Flash_Not_Erased;}         // Is it erased?
    //    FCNFG = 0x00;
    (*far_address) = data;            // Store desired data to address being programmed

    FCMD = 0x20;                     // Store programming command in FCMD
    (void)DoOnStack(far_address);
    if (FSTAT_ACCERR) {return Access_Error;}
    if (FSTAT_PVIOL) {return Protection_Error;}
    return 1;
}
//*****************************************************************************
//* Function Name    : Flash_Erase_Sector
//* Description     : Erases a given Flash sector using address
//*                   passed from calling function.
//*
//*****************************************************************************
signed char Flash_Erase_Sector(unsigned int *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;}
  FCNFG = 0x00;
    FSTAT = (FSTAT_ACCERR | FSTAT_PVIOL);               //   clear errors
    (*far_address) = 0xFFFF;    /* Dummy store to page to be erased */

    FCMD=0x40;
    (void)DoOnStack(far_address);
    if (FSTAT_ACCERR) {return Access_Error;}
    if (FSTAT_PVIOL) {return Protection_Error;}
    return 1;
}
#pragma MESSAGE DEFAULT C1860        // Pointer conversion: Possible loss of data     

;*******************************************************************
;*
;*    DESCRIPTION:   S12 Flash Asm Routines
;*    SOURCE:        Do_On_Stack.asm
;*
;*******************************************************************/
;*****************************************************************************
; Local defines
;*****************************************************************************
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
;*
;* Calling Convention:
;*           jsr    DoOnStack
;*
;********************************************************************
DoOnStack: 
            pshx                 ;save IX
            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
            jsr ,x         ;execute the sub on the stack
        leas   SpSubEnd-SpSub,sp  ;de-allocate space used by sub
            ldaa FSTAT         ;get result of operation
        anda #$30         ;and mask all but PVIOL or ACCERR
        pulx                 ;restore IX
            rts                  ;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)
;*
;* Note: must be even # of bytes!
;*
;*********************************************************************
            EVEN                 ;Make code start word aliened
SpSub:      
            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
            rts                  ;back into DoOnStack in flash
SpSubEnd:


0 Kudos
Reply

2,715 Views
J2MEJediMaster
Specialist I
I would try setting the compiler to build code for the small memory model. That might flush out declarations and references to segment registers that are used for banked memory. Use the compiler switch -Ms in the command line arguments field of CodeWarrior's Compiler for HC12 settings panel. It's probably set to -Mb for banked memory. HTH.

---Tom
0 Kudos
Reply