Are there any plans for a FLASH programming utility app note (much like AN2720) to be created and released specific to the S12X. I am working with a MC9S12XDP512 and would like to have the capability of reprogramming a few pages of FLASH that contain data tables.
I think I understand the basic setup of the FLASH registers along with address and data lines but don't fully understand the assembly code in AN2720. Is the stack being used to basically check the CBEIF for the flash complete signal because the FLASH cannot be read from at this time meaning RAM has to be used. Can this assembly code be used as is on an S12X core?
Also, if the XGATE is configured to run out of RAM, could 1 of the 8 software trigger interrupt routines be used after the FLASH command is sent to the fcmd register. This would eliminate the need to specifically use the stack. Any feedback on any of these questions is appreciated.
Thanks,
Thomas
/* FLASH data table address range */
#define TABLE_ADDRESS_LOW 0x780000
#define TABLE_ADDRESS_HIGH 0x783FFF
Not sure if this is what you are looking for. This did allow me to store larger data tables in FLASH though.
Code:
#pragma DATA_SEG FlashCtrl_DATA #pragma CODE_SEG FlashCtrl_CODE /* FlashCtrl_WriteWord */BYTE FlashCtrl_WriteWord(WORD *__far WriteAddress, WORD Data){ /* Check range of WriteAddress */ if(WriteAddress < (WORD *__far)TABLE_ADDRESS_LOW || WriteAddress > (WORD *__far)TABLE_ADDRESS_HIGH) return FALSE; /* Has the FLASH divider clock been set— */ if(!FCLKDIV_FDIVLD) FlashCtrl_Init(); /* Check command flag */ if(!FSTAT_CBEIF) return FALSE; /* Clear flags */ FSTAT = 48; /* Array address and program data */ WriteAddress[0] = Data; /* Word program command */ FCMD = 32; /* Clear flag command buffer empty */ FSTAT = 128; /* Is protection violation or acces error detected– */ if ((FSTAT_PVIOL == 1)||(FSTAT_ACCERR == 1)) return FALSE; /* Wait to buffer empty */ while(FSTAT_CBEIF == 0); /* Wait to command complete */ while(FSTAT_CCIF == 0); /* Was write successful˜ */ if(WriteAddress[0] != Data) return FALSE; /* Return success */ return TRUE;}/* FlashCtrl_EraseSector */BYTE FlashCtrl_EraseSector(WORD *__far EraseAddress){ /* Check range of EraseAddress */ if(EraseAddress < (WORD *__far)TABLE_ADDRESS_LOW || EraseAddress > (WORD *__far)TABLE_ADDRESS_HIGH) return FALSE; /* Has the FLASH divider clock been set™ */ if(!FCLKDIV_FDIVLD) FlashCtrl_Init(); /* Check command flag */ if(!FSTAT_CBEIF) return FALSE; /* Clear flags */ FSTAT = 48; /* Write to erase address */ EraseAddress[0] = 0x10; /* Initiate Sector Erase commamd */ FCMD = 64; /* Clear flag command buffer empty */ FSTAT = 128; /* Is protection violation or access error detected ? */ if ((FSTAT_PVIOL == 1)||(FSTAT_ACCERR == 1)) /* If yes then error */ return FALSE; /* Wait to buffer empty */ while(FSTAT_CBEIF == 0); /* Wait to command complete */ while(FSTAT_CCIF == 0); /* Return success */ return TRUE;}/* FlashCtrl_Init */void FlashCtrl_Init(void){#if OSC_SPEED == 4000000 /* 4mhz clock */ FCLKDIV = 20; #else if OSC_SPEED == 10000000 /* 10mhz clock */ FCLKDIV = 50;#endif}#pragma DATA_SEG DEFAULT #pragma CODE_SEG DEFAULT
I am trying to write some code in C to do a mass erase and program of the flash for a 9S12X.
I have declared a pointer to the flash:
typedef uint16_t * far Flash_TAddress;
During the process I increment this address to point to the next block. The Code W\rrior compiler treats it as a 14-bit effective address, so when I try to add 0x4000 to it it effectively adds 0 and produces no code. This is presumable becuse it teats the address as an effective address used with the PPAGE register.
I have done some experiments to see what code the compiler produces, and it seems to use a mixture of GPAGE and PPAGE, as shown in the following snippet:
static uint32_t * far dq;
dq = (Flash_TAddress)0xE0;
*dq = 12;
dq = dq + 0x4000L;
*dq = 23;
The compiler assembly output for this is:
228: dq = (Flash_TAddress)0xE0;
0001 c6e0 [1] LDAB #224
0003 87 [1] CLRA
0004 7c0000 [3] STD dq:1
0007 7a0000 [3] STAA dq
229:
230: *dq = 12;
000a fe0000 [3] LDX dq:1
000d f60000 [3] LDAB dq
0010 5b10 [2] STAB /*GPAGE*/16
0012 c7 [1] CLRB
0013 186c00 [3] GSTD 0,X
0016 c60c [1] LDAB #12
0018 186c02 [3] GSTD 2,X
231:
232: dq = dq + 0x4000L;
233:
234: *dq = 23;
001b c7 [1] CLRB
001c 186c00 [3] GSTD 0,X
001f c617 [1] LDAB #23
0021 186c02 [3] GSTD 2,X
So it uses GPAGE for assigning the pointer and storing the 12, but assumes PPAGE when I add 0x4000 to it.
How do I get the compiler o incremement the address and automatically increment PPAGE, or can I not do this? If not, how do I do what I am trying to do, i.e. erase the flash?
The compiler version is Code WArrior of rS12X version 4.7, with command line compiler chc12 version 5.0.35 build 8093.
Thanks
Try replacing far with __far24. __far GPAGE pointer +- update only lower 16bits of pointer. __far24 updates all bits. Or maybe convert __far pointer to long, add/subtract and finally convert long back into __far pointer.
Thanks for your suggestions. I have been busy with a few other things so have not got round to this.
I have set up the PPAGE register and written to a dummy address within the block as the data sheet suggests. In this way I can use 16-bit addresses and everything seems to work OK.
Thanks
dq is a pointer to uint_32t. So when you add 0x4000 to dq, pointer address should increment by 0x4000*sizeof(uint_32t). Thats + 0x10000 and not the size of PPAGE.
i'm using trying to program a p-flash sector of 1024 bytes on a s12xet256.
all works well in the adddress space (0x00780000-0x0079FFFF),(0x007E0000-0x007F3FFF) and (0x007F8000-0x007FBFFF) but if I try to program and erase sectors in the spaces (0x007F4000-0x007F7FFF) and (0x007FC000-0x007F7F00) the program jumps to strange address and don't program the memory
my code is placed in 0x007F4000-0x007F7FFF
someone have the same problem or could help me?
tanks
Flash block is not readable while any flash command is in progress (in this flash block). Also not readable while you are applying backdoor unsecure key (KEYACC bit is set). This means CPU can't read memory and runs away. Also CPU can't read interrupt vectors from flash block being programmed.
Your flash routines should be placed to and run from RAM.
tanks!
I'm using this code to write a block in PFlash.
if I break(with 2 breakpoints) at the executions "while (FSTAT_CCIF == 0);" it writes in memory the data otherwise if the program runs it jumps away.
how can I modify to correct this function?
static byte flashpxWriteBlock(dword Addr, word From, word To, word* Data)
Just move your flash routines to RAM. Search box at the bottom of this page can give many possible answers. One of results:
Also, if the XGATE is configured to run out of RAM, could 1 of the 8 software trigger interrupt routines be used after the FLASH command is sent to the fcmd register. This would eliminate the need to specifically use the stack. Any feedback on any of these questions is appreciated.
Application note AN2548 describes a HCS12-based serial monitor with some basic debugging operations and writing to flash. Probably overkill for you, but still an excellent source of information. The source code is in two separate archive files and is in assembly, but is heavily commented. I'm going to attach these files here to save you the trouble of tracking them down.
In regard to your other questions:
1) The HC12S instructions should run on a S12X core, but you may have to modify the programming logic to make it work with the S12X's memory map.
2) I don't know anything about the XGATE and so can't answer to that.
3) When you're programming Flash, it's usually a really good idea to disable interrupts, since an interrupt is going to take the CPU to a routine in Flash, which happens to be what you're trying to modify. Barring that, the interrupt can also disrupt the precise sequence of writes required to program the Flash.
---Tom
http://www.freescale.com/files/microcontrollers/doc/app_note/AN2548.pdf