MC9S12XEP100 Flash erase and burn routine

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

MC9S12XEP100 Flash erase and burn routine

Jump to solution
4,898 Views
roberthiebert
Contributor IV

MC9S12XEP100, CodeWarrior 5.9.0 Special Edition, absolute assembler.

I have a program that uses three blocks of configurable constants, 1024 bytes each. They reside in Flash at addresses, $7000, $7400 and $7C00 respectively. When the program starts these three blocks are copied to RAM at addresses, $2400, $2800 and $2C00 respectively and the program access them from RAM. I have another program on my laptop that communicates with the MC9S12XEP100 via SCI. With it I can modify these configurable constants that are in RAM. After they have been modified I would like to burn them back into Flash. I know this can be done but I am unclear on exactly how to do it. Can anyone point me in the right direction?

 

Regards,

Robert  

0 Kudos
1 Solution
4,719 Views
roberthiebert
Contributor IV

Hi Stano,

Thanks again for your suggestions.

The light bulb finally came on with regard to the Send_Command subroutine. I finally realized that it was coded in machine language, so I went to my S12XCPUV1 reference manual and looked up what the hex numbers represented. I found that $1C represents BSET, $1F represents BRCLR, $3D represents RTS, $0106 represents FSTAT and $80 is the bit mask for CCIF. The only remaining mystery is what $1F represents. I looked it up as ADDB, but that doesn't make sense to me. However, the code works in that respect so I can accept the mystery.

I was still having no joy in erasing my sector so I kept on digging. Then I found a gem in "datapage.c". A description of the HCS12X Logical Memory map which in part stated that the logic address $004000 was the same as global address 7F4000. So I plugged $7F in for the low byte of FCCOB with FCOB!X as $00 and it worked. I am now reasonably confident I can get the rest of my code to work.

Thanks again for your help and patience with me.

Regards,

Robert

 

View solution in original post

0 Kudos
16 Replies
4,887 Views
StanoA
NXP TechSupport
NXP TechSupport

Hello Robert,

Attached is the example how to use the XEP P-Flash memory on global address from 0x7F_0000 to 0x7F_FFFF for save such data.

The smallest unit of the P-Flash memory is sector = 1024 bytes. See Section 24.3 of RM.

It is possible to use also the D-Flash memory for save the data with smaller sector = 256 bytes only.

As first important step is to setup the right Flash frequency by FCLKDIV register.

The next steps are described in attached examples but in C-code and not asm and in RM Section 24.4.

If you wish to use the asm code the next Application Note could be the example for you:

https://www.nxp.com.cn/docs/en/application-note/AN2720.pdf

I think it could help you to solve your task.

Best Regards,

Stano.

0 Kudos
4,855 Views
roberthiebert
Contributor IV

Hi Stano,

In both of the attached examples, CW46 and CW47, the main.c code makes reference to a subroutine named Send_Command. I can't find that anywhere, can you tell me where I can find it please?

 

The AN2720 is interesting but it appears to be written for the MC9S12DP256 and some of the defines for the necessary registers are different for the MC9S12XEP100. I'm not clear if the processors use the same flash erase and program methods or not.

 

Because my program is relatively small I have lots of non paged RAM available, and the program itself resides in the non paged Flash with lots of unused space as well. In  order to keep things as simple as possible I would like to copy the erase and burn routines to RAM on startup and use them from there, once I can figure out what those routines should be, of course.

Regards,

Robert

0 Kudos
4,848 Views
roberthiebert
Contributor IV

Hi Stano,

I found the Send_Command subroutine. It just shows how little I understand about "C". Now that I've found it, I have no idea what it does.

Regards,

Robert

0 Kudos
4,884 Views
StanoA
NXP TechSupport
NXP TechSupport
0 Kudos
4,868 Views
roberthiebert
Contributor IV

Hi Stano,

Thanks so much for the information. I'm finding it quite daunting but I'll work away on it and see if I can make sense of it all, I'll probably have more questions as I progress.

Regards,

Robert

0 Kudos
4,841 Views
StanoA
NXP TechSupport
NXP TechSupport

Hi Robert,

I suppose all is going well.

Still one comment for the clarification and summary: the FLASH module in MCU contains the Memory Controller and the input point for this controller are FCCOBIX and  FCCOB registers. See Section 24.4 for detail function.

As the first step the right FLASH clocks (equal to 1MHz) must be set by FCLKDIV register. If not set the all FLASH commands are ignored.

The second point – the CCIF flag must be checked if it is set. If CCIF=0 the previous flash command is not finished yet and it must not change the contents of the FCCOBIX and FCCOB registers.

The next point the ACCERR and PVIOL flags must be cleared.

So if the previous steps are OK the valid data (required command, start address, end address, pointer to data which have to be loaded into FLASH, …) can be loaded into FCCOB register (together with FCCOBIX too).

When it is done the write CCIF=1 must be executed to start the flash command loaded into FCCOB register. This is showed in examples as the “Send_Command” function.

The addresses for this function must be in *far ptr format – CW recognizes them as in 24-bit format.

I hope it helps you to reach success in your project.

Best Regards,

Stano.

0 Kudos
4,835 Views
roberthiebert
Contributor IV

Hi Stano,

Thanks for your quick reply. I have been studying the reference manual and the information you have provided. I am beginning to understand how things are supposed to work but my knowledge of "C" is very limited.

I think the entire Send_Command subroutine consists of this:

static unsigned char Send_Command[]=
{
0x1C, 0x01, 0x06, 0x80, 0x1F, 0x01, 0x06, 0x80, 0xFB, 0x3D
};

 

What does this do?

Regards,

Robert

0 Kudos
4,821 Views
StanoA
NXP TechSupport
NXP TechSupport

Hi Robert,

The registers FCCOB and FCCOBIX are inputs for the memory control register. So if you need make such action with memory (erase, write such area) the required command and other information which belongs to selected command must be written into FCCOB in conjunction with FCCOBIX register.

As first the CCIF bit in FSTAT register must be checked if it is set. The CCIF=1 means the memory controller is ready to execute next command (the possible previous is finished). It must be cleared the ACCERR and PVIOL flag in FSTAT before FCCOB write also.

Let’s suppose you have written required command (one byte) with starting and end addresses e.g. for sector erase (more bytes) and possible next info – detail description in RM.

Then the Send_Command[]=…. code in RAM starts the execution of the memory command in memory controller. The command starts with write CCIF=1 when CCIF equal 1. This is in fact the code in RAM: [ ]= {0x1C, 0x01, 0x06, 0x80, 0x1F, 0x01, 0x06, 0x80, 0xFB, 0x3D}. This sequence mut run from RAM because the FLASH memory will be controlled by memory controller and the code cannot run from FLASH.

When the command is started the FLASH is not accessible and the only FSTAT register can provide information about memory status. So it is checked for final info from the memory controller – may be error or OK status. The CCIF=1 in FSTAT register signaling the memory command is finished.

It looks as complicated but it is very simply – just use the code from example and fill in the required data and addresses.

I suggest you to read the RM more times (I have done too) and try simulate the example code. You must write the value of the CCIF bit manually for continue in simulator.

I wish you success in your project.

Best Regards,

Stano.

0 Kudos
4,813 Views
roberthiebert
Contributor IV

Hi Stano,

Your explanation makes sense, and agrees with my interpretation of the instructions in the reference manual, but I am programming in assembler and simply cannot use the "C" example. Anyway, I have written a test program in assembler and have been debugging it on full chip simulation. I have successfully copied the program from Flash to RAM and it runs from there. Whenever I try to read or write to any of the Flash module registers I get a warning that I am either reading or writing to an unimplemented register and destination bytes in Flash are unchanged. I am attaching my program and would appreciate it if you could have a look and see why I might be getting these warnings.

Regards,

Robert

0 Kudos
4,806 Views
roberthiebert
Contributor IV

Hi Stano,

Update. I tried running the program in the MC9S12XEP100. That took care of the warnings and the program runs, but the target area in Flash doesn't change. I tried single stepping through the program and everything appears to be as it should, but it doesn't look like anything got erased or burnt. That's quite interesting. Any suggestions?

Regards,

Robert

0 Kudos
4,785 Views
StanoA
NXP TechSupport
NXP TechSupport

Hi Robert,

Thanks for your update. If you want to use FLASH area it must be not protected so please check the FPOPEN bit in FPROT register. The simplest way is use the mass erase first to have full access to the FLASH memory. The Figure 24-26 describes the Generic FLASH command write sequence. This is used for fill in the required command and address into FCCOB register. So you don’t need to build your own asm code for the FLASH command execution and only fill in the required Flash command from Table 24-30 and the address if needed. For example the code 0x02 = Erase Verify Block command (Sec 24.4.2.2) requires the only one address – the block address (22:16). The code which writes contents into FCCOB and FCCOBIX registers can run from FLASH in this case. In case you want write such own data into FLASH the data must be in RAM area to be able to read from during programming.

So the FLASH controller will make the required operation without other influence required.

The asm code of the

Send_Command[]={0x1C, 0x01, 0x06, 0x80, 0x1F, 0x01, 0x06, 0x80, 0xFB, 0x3D}

can be placed in RAM:

ORG $2100

Send_Command:

          DC.B    $1C, $01, $06, $80, $1F, $01, $06, $80, $FB, $3D   ;start function

as in attached example.

This is in fact:

          BSET 0x0106, #128                     ; CCIF = 1;

          BRCLR 0x0106, #128, *+0           ; wait for CCIF = 1;

          RTS

Then the instruction JMP Send_Command will start the command execution.

Best Regards,

Stano.

0 Kudos
4,777 Views
roberthiebert
Contributor IV

Hi Stano,

Thanks for being so patient with me but I'm still having difficulty understanding this "Send_Command" subroutine. I wrote another small assembler program just to erase one sector at Flash $7000. I have the Send_Command subroutine in RAM. I am expecting to see all 1s in the 1024 bytes in Flash starting at $7000, but After running the program I still see the first 16 bytes as 0s which I initially placed there. I initialized FPROT with $FF which I believe is no protection. I'm baffled. I've attached my program so you can see if I have any errors. Much appreciated.

Regards,]

Robert

0 Kudos
4,766 Views
StanoA
NXP TechSupport
NXP TechSupport

Hi Robert,

Did you try the example? It is in C-language but if you run “disassemble” command from menu you will see the asm code.

So as first the FLASH area must be erased and then can be programmed. Otherwise the error flags will be set and nothing programmed. This is the first command issued in example. Then the FLASH is programmed.

So try the example in Simulator and go step by step to see the asm code sequence executed. Then try to extract the asm code to your new clear asm file and then debug it or run it. As first debug it in Simulator and then run it. Be sure the MCU is fully erased and unsecured first.

The routine in your code has to be as in follow:

Send_Command:

    BSET $0106,#128          ; CCIF = 1;    ; FSTAT equ$106,128 = $80 = %10000000 bit7 CCIF this starts the subroutine

    BRCLR $0106,#128,*+0     ; wait for CCIF = 1;      

    RTS

You can either use this standard asm format OR use the “DC.B …. “ format. It is the same.

I wish you success in you task!

Best Regards,

Stano.

0 Kudos
4,749 Views
roberthiebert
Contributor IV

Hi Stano,

Thanks for your latest suggestion. I've tried it but I'm still not getting anywhere with this. I've tried to break it down to one simple routine. I have a sector of Pflash in the unpaged 16K area at local address $7000. I just want to erase that 1024 byte sector. I can check with the debugger if it has been erased by looking at that sector and making sure that it is all 1s. If I can accomplish that, then I will move on to the burn routine.

I am assuming that the global address for the local address $7000 is $00_7000. Is that correct?

Also, is the Send_Command subroutine I have in RAM suppose to be just this?

Send_Command:

          DC.B    $1C, $01, $06, $80, $1F, $01, $06, $80, $FB, $3D  

          BSET 0x0106, #128                     ; CCIF = 1;

          BRCLR 0x0106, #128, *+0           ; wait for CCIF = 1;

          RTS

0 Kudos
4,738 Views
StanoA
NXP TechSupport
NXP TechSupport

Hi Robert,

The global address bits [22:16] are used only when certain instructions are used – Sec. 3.3.2.3. So the address 0x7000 is from the unpaged linear space (Figure 3-17).

The Send_Command routine is eighter DC.B ….., or BSET…. - … RTS. That is only different write style. The BSET = 0x1C, then address 0x0106 and data 0x80, …

So if you use for example in RAM:

ORG $3000             ;position of the Send_Command routine

          DC.B $1C, $01, $06, $80, $1F, $01, $06, $80, $FB, $3D

Or use this style:

ORG $3000             ;position of the Send_Command routine

BSET 0x0106, #128                     ; CCIF = 1;

BRCLR 0x0106, #128, *+0           ; wait for CCIF = 1;

RTS

The result is the same.

The next thinks you need to take care of – in the debugger the memory window has to show different memory segment as used for FLASH manipulation. For example when the memory controller working on sector $7000 the memory window must show e.g. RAM window. The reason is that the BDM is trying to refresh data which is showed in debugger and it could influence the memory controller action. So the best way is to set the breakpoint after RTS instruction executed from RAM. Then change the address in debugger memory window to $7000 and see the result.

Please check if the “refresh….” Is selected in: HC12MultilinkCyclonePro/Debugging Memory Map/ - select global /Modify/Details / -> refresh memory when halting.

This must be enabled if you want to see actual data in debugger memory window.

Best Regards,

Stano.

0 Kudos
4,720 Views
roberthiebert
Contributor IV

Hi Stano,

Thanks again for your suggestions.

The light bulb finally came on with regard to the Send_Command subroutine. I finally realized that it was coded in machine language, so I went to my S12XCPUV1 reference manual and looked up what the hex numbers represented. I found that $1C represents BSET, $1F represents BRCLR, $3D represents RTS, $0106 represents FSTAT and $80 is the bit mask for CCIF. The only remaining mystery is what $1F represents. I looked it up as ADDB, but that doesn't make sense to me. However, the code works in that respect so I can accept the mystery.

I was still having no joy in erasing my sector so I kept on digging. Then I found a gem in "datapage.c". A description of the HCS12X Logical Memory map which in part stated that the logic address $004000 was the same as global address 7F4000. So I plugged $7F in for the low byte of FCCOB with FCOB!X as $00 and it worked. I am now reasonably confident I can get the rest of my code to work.

Thanks again for your help and patience with me.

Regards,

Robert

 

0 Kudos