MC9S12XEP100. Code Warrior 5.9.0, single chip, absolute assembler.
I have a program, similar to the one I wrote using the MC9S12C64, but larger and more complex. I couldn't figure out the flash burner process for that one until I posted the question and Ladislav was able to explain it to me with his C64-FLASH-ASM test program. Using that I was able to get my program to work just fine.
Now I am having the same issue using the MC9S12XEP100 processor. I was hoping there would be enough similarities in the process that I could adapt what I learned, but I'm having some difficulties. Is there a test program similar to the C64-FLASH-ASM, but specific to the MC9S12XEP100 in single chip, absolute assembler that I could study and see if I could get that to work?
I'm attaching a basic test code that I am using to troubleshoot.
Regards,
Robert
Solved! Go to Solution.
Hi,
I have found my notes contain copy/paste mistakes.
I am not sure what are you looking at so more detailed comments. Moreover, I suppose the DFLASH is in erased status before it is written.
Moreover, the question is how the RAM content is refreshed in your memory window. You should also check the setup lime it is done for DFLASH.
The address 0x2100 is selected by compiler so the array is placed:
Buffer[0] is at address 0x2100,0x2101 of a local address space
Buffer[1] is at address 0x2102,0x2103
Buffer[2] is at address 0x2104,0x2105
Buffer[3] is at address 0x2106,0x2106
Finally, it is good to understand local and global address space. The RAM 0x2100 is in local address space 0x2100 and in the global address space 0x0F_E100. Si memory map in attachment.
... and be careful when you show address space ... extension 'G or 'L. For example 0FE100'G and 2100'L represents the same address from different views.
.... does no exist
.... the variable "buffer" in a local address space
... the variable "buffer" in a global address space
better comments of the original asm code..
;---------------------------
;err = DFLASH_Program(0x0000, &buffer[0], 4); //write 4 words to D Flash address 0x10_0000
; GPAGE (0x10_.... ) is not used in the Addr variable because it is directly used in the DFLASH_Program routine
MOVW #$0000,Addr ; address to be written 0x(10)0000~0x(10)0007
MOVB #4,Cnt ; number of words to be written
;for example data to be written into DFLASH are 0x0123, 0x4567, 0x89AB, 0xCDEF
; written global DFLASH address is 0x10_0000’G … for data visualization in a debugger memory
; window“ ’G ” must be added into memory address
LDX #Buffer ; Load the base address of the array into X register, the base address
; is selected by compiler if you do not set exact address
LDD #$0123 ; Load the hexadecimal value 0x0123 into D register
STD 0,X ; Store the value at the 0th position of the array; Buffer[0] = 0x0123
LDD #$4567 ; Load the value 0x4567 into D register
STD 2,X ; Store the value at the 1st position of the array; Buffer[1] = 0x4567
LDD #$89AB ; Load the value 0x89AB into D register
STD 4,X ; Store the value at the 2nd position of the array; Buffer[2] = 0x89AB
LDD #$CDEF ; Load the value 0xCDEF into D register
STD 6,X ; Store the value at the 3rd position of the array; Buffer[3] = 0xCDEF
CALL DFLASH_Program ; note there is a status of verification in the Err variable after execution of this command
;---------------------------
;err = DFLASH_Program(0x0008, &buffer[0], 4); //write 4 words to eeprom address 0x0000
;… at this place you should check whether Err value is OK to be sure entire write process has
; finished correctly. I am not doing it in this example.
;---------------------------
; write another set of data to a 8 bites higher address of the DFLASH
; written global DFLASH address is 0x10_0008’G
MOVW #$0008,Addr ; address to be written 0x(10)0008~0x(10)000F
MOVB #4,Cnt ; number of words to be written
;for example data to be written into DFLASH are 0xDEAD,0xBEEF,0xC0DE,0xCAFE
LDX #Buffer ; Load the base address of the array into X register, the base address
; is selected by compiler if you do not set exact address
LDD #$DEAD ; Load the hexadecimal value 0xDEAD into D register
STD 0,X ; Store the value at the 0th position of the array; Buffer[0] = 0x0123
LDD #$BEEF ; Load the value 0xBEEF into D register
STD 2,X ; Store the value at the 1st position of the array; Buffer[1] = 0x4567
LDD #$C0DE ; Load the value 0XC0DE into D register
STD 4,X ; Store the value at the 2nd position of the array; Buffer[2] = 0x89AB
LDD #$CAFE ; Load the value 0xCAFE into D register
STD 6,X ; Store the value at the 3rd position of the array; Buffer[3] = 0xCDEF
CALL DFLASH_Program ; note there is a status of verifiction in the Err variable after execution of this command
;---------------------------
;err = DFLASH_Program(0x0008, &buffer[0], 4); //write 4 words to eeprom address 0x0000
;… at this place you should check whether Err value is OK to be sure entire write process has
; finished correctly. I am not doing it in this example.
;---------------------------
Best regards,
Ladislav
Hi,
I have found my notes contain copy/paste mistakes.
I am not sure what are you looking at so more detailed comments. Moreover, I suppose the DFLASH is in erased status before it is written.
Moreover, the question is how the RAM content is refreshed in your memory window. You should also check the setup lime it is done for DFLASH.
The address 0x2100 is selected by compiler so the array is placed:
Buffer[0] is at address 0x2100,0x2101 of a local address space
Buffer[1] is at address 0x2102,0x2103
Buffer[2] is at address 0x2104,0x2105
Buffer[3] is at address 0x2106,0x2106
Finally, it is good to understand local and global address space. The RAM 0x2100 is in local address space 0x2100 and in the global address space 0x0F_E100. Si memory map in attachment.
... and be careful when you show address space ... extension 'G or 'L. For example 0FE100'G and 2100'L represents the same address from different views.
.... does no exist
.... the variable "buffer" in a local address space
... the variable "buffer" in a global address space
better comments of the original asm code..
;---------------------------
;err = DFLASH_Program(0x0000, &buffer[0], 4); //write 4 words to D Flash address 0x10_0000
; GPAGE (0x10_.... ) is not used in the Addr variable because it is directly used in the DFLASH_Program routine
MOVW #$0000,Addr ; address to be written 0x(10)0000~0x(10)0007
MOVB #4,Cnt ; number of words to be written
;for example data to be written into DFLASH are 0x0123, 0x4567, 0x89AB, 0xCDEF
; written global DFLASH address is 0x10_0000’G … for data visualization in a debugger memory
; window“ ’G ” must be added into memory address
LDX #Buffer ; Load the base address of the array into X register, the base address
; is selected by compiler if you do not set exact address
LDD #$0123 ; Load the hexadecimal value 0x0123 into D register
STD 0,X ; Store the value at the 0th position of the array; Buffer[0] = 0x0123
LDD #$4567 ; Load the value 0x4567 into D register
STD 2,X ; Store the value at the 1st position of the array; Buffer[1] = 0x4567
LDD #$89AB ; Load the value 0x89AB into D register
STD 4,X ; Store the value at the 2nd position of the array; Buffer[2] = 0x89AB
LDD #$CDEF ; Load the value 0xCDEF into D register
STD 6,X ; Store the value at the 3rd position of the array; Buffer[3] = 0xCDEF
CALL DFLASH_Program ; note there is a status of verification in the Err variable after execution of this command
;---------------------------
;err = DFLASH_Program(0x0008, &buffer[0], 4); //write 4 words to eeprom address 0x0000
;… at this place you should check whether Err value is OK to be sure entire write process has
; finished correctly. I am not doing it in this example.
;---------------------------
; write another set of data to a 8 bites higher address of the DFLASH
; written global DFLASH address is 0x10_0008’G
MOVW #$0008,Addr ; address to be written 0x(10)0008~0x(10)000F
MOVB #4,Cnt ; number of words to be written
;for example data to be written into DFLASH are 0xDEAD,0xBEEF,0xC0DE,0xCAFE
LDX #Buffer ; Load the base address of the array into X register, the base address
; is selected by compiler if you do not set exact address
LDD #$DEAD ; Load the hexadecimal value 0xDEAD into D register
STD 0,X ; Store the value at the 0th position of the array; Buffer[0] = 0x0123
LDD #$BEEF ; Load the value 0xBEEF into D register
STD 2,X ; Store the value at the 1st position of the array; Buffer[1] = 0x4567
LDD #$C0DE ; Load the value 0XC0DE into D register
STD 4,X ; Store the value at the 2nd position of the array; Buffer[2] = 0x89AB
LDD #$CAFE ; Load the value 0xCAFE into D register
STD 6,X ; Store the value at the 3rd position of the array; Buffer[3] = 0xCDEF
CALL DFLASH_Program ; note there is a status of verifiction in the Err variable after execution of this command
;---------------------------
;err = DFLASH_Program(0x0008, &buffer[0], 4); //write 4 words to eeprom address 0x0000
;… at this place you should check whether Err value is OK to be sure entire write process has
; finished correctly. I am not doing it in this example.
;---------------------------
Best regards,
Ladislav
Hi Ladislav,
Thanks so much for your detailed response. There are still a few minor errors in your comments, but no matter, I'm quite sure I know what you are doing and they really helped.
Your screen shots of the memory window were a big revelation to me. I didn't know about the l, g and r suffix. That explains a lot.
The spread sheet that compares the equivalent addresses also really helped in my education. I now feel I have a good understanding of what you have done and a better understanding of what the debugger can do.
As a result of my new found knowledge I am realizing that I should be using EEPROM emulation. I have some questions about that in a separate thread.
Thanks once more for all your help and patience.
Regards,
Robert
Hi,
Create critical section which is not interrupted using CLI, SEI.
Best regards,
Ladislav
I have the memory set to refresh on halt, but no matter what I do, the memory never changes. I've tried setting breakpoints where I see you have highlighted, but nothing. I tired running the program and halting it at random points. No change. What am I doing wrong?
Hi Ladislav,
I have made some progress. To make a long story short, I discovered that my controller was secured. I don't know how that happened, but I was able to unsecure it and now your program is working the way you have shown in your last post.
Now I am able to study your ASM code to make sure I understand it fully before I try to adapt it it work in my code.
I have one thing that is puzzling me though. If I am understanding you r code correctly, you have placed your test data to be burned to D-Flash, in RAM memory starting at Buffer: (address $2100). But when I look at that address all I ever see is $CA,$FE, repeat.
Why is this?
Regards,
Robert
Hi Ladislav,
One more thing. I did some more research and I understand that in order for CW to be able to read the D-Flash the FSEC register needs to be set to $FE. I see that your code has done this, but I can't find out where and how you did it. Could you explain how I can do that in my code please?
Regards,
Robert
Hi,
The topic has already been processes...
https://community.nxp.com/t5/S12-MagniV-Microcontrollers/S12-X-MCU-Security/ta-p/1111118
https://community.nxp.com/t5/S12-MagniV-Microcontrollers/Unsecuring-MC9S12XEP100MAG/m-p/617603
Best regards,
Ladislav
I've spent a lot of time stepping through this code and recording all the variable and register states on each step. I think I have a pretty good understanding of what is happening here, but one thing in particular still has me puzzled.
In this section of code:
LDX #Buffer ; Load the base address of the array into X register
LDD #$0123 ; Load the value 0123 into A register
STD 0,X ; Store the value at the 0th position of the array
X is loaded with $2100, the address of "Buffer" in RAM
D is loaded with decimal 0123
Decimal 0123 is copied into the first two bytes of the "Buffer" array at address $2100 in RAM.
Now, when I use the debugger to check the contents of RAM address $2100 I see $CA, $FE in the first two bytes, and they never change. Why is this and where are the example words stored?
Regards,
Robert
Hello @roberthiebert,
What debugger do you use?
The debugger can interpret the data as 0xCAFE because of ECC, for example.
Regards,
Daniel
Hi Daniel,
Code Warrior IDE V5.9.0 Build 5294 Special Edition.
Regards,
Robert
Hi Robert,
I mean debugger like PE Micro Multilink (with revision), USBDM, ...
Hi Daniel,
Freescale USBDM (from China). I use it successfully to load programs. Does that answer your question?
Regards,
Robert
I am very sorry but I see no issue to rebuilt C to ASM. C shows you principle and this C code is not a object oriented programming. It is simple Ansi C.
Here you can see programming of D-Flash. (Not P-Flash, it is a little bit different but in principle very similar)
;**************************************************************
;* This stationery serves as the framework for a *
;* user application. For a more comprehensive program that *
;* demonstrates the more advanced functionality of this *
;* processor, please see the demonstration applications *
;* located in the examples subdirectory of the *
;* Freescale CodeWarrior for the HC12 Program directory *
;**************************************************************
; Include derivative-specific definitions
INCLUDE 'derivative.inc'
; export symbols
XDEF Entry, _Startup, main
; we use export 'Entry' as symbol. This allows us to
; reference 'Entry' either in the linker .prm file
; or from C/C++ later on
XREF __SEG_END_SSTACK ; symbol defined by the linker for the end of the stack
;*********************************************************************
OK EQU 0
ERASED EQU 1
NON_ERASED EQU 2
LENGTH_OUT_OF_RANGE EQU 3
;*********************************************************************
; variable/data section
MY_EXTENDED_RAM: SECTION
; Insert here your data definition.
Buffer ds.w 4;
Err ds.b 1;
Addr ds.w 1;
Cnt ds.b 1;
var_i ds.b 1;
var_j ds.b 1;
var_Data ds.w 1;
;*********************************************************************
; code section
MyCode: SECTION
main:
_Startup:
Entry:
;---------------------------
LDS #__SEG_END_SSTACK ; initialize the stack pointer
CLI ; enable interrupts
;---------------------------
EndlessLoop:
;---------------------------
;EE_Init ... 0x0F //oscillator 16MHz -> divide by 0x0F to achieve FCLK 800kHz - 1.05MHz
;while(FSTAT_CCIF == 0); //wait if command in progress
BRCLR FSTAT,#128,*+0 ;abs = 0001
;FCLKDIV = fdiv; //osc = 16MHz
LDAB #$0F
STAB FCLKDIV
;---------------------------
;DFLASH_Erase_Sector(0x0000); //erase first sector (256 bytes)
MOVW #$0000,Addr
CALL DFLASH_Erase_Sector
;---------------------------
;err = DFLASH_Erase_Verify(0x0000, 16); //check if 16 words are erased - we will receive ERASED message
MOVW #$0000,Addr
MOVB #16,Cnt
CALL DFLASH_Erase_Verify ; note there is a status of verification in the Err variable after execution of this command
;---------------------------
;err = DFLASH_Program(0x0000, &buffer[0], 4); //write 4 words to D Flash address 0x0000
MOVW #$0000,Addr ; address to be written
MOVB #4,Cnt ; number of words to be written
;for example data to be written into DFLASH are 0123, 4567, 89AB, CDEF
LDX #Buffer ; Load the base address of the array into X register
LDD #$0123 ; Load the value 0123 into A register
STD 0,X ; Store the value at the 0th position of the array
LDD #$4567 ; Load the value 4567 into A register
STD 2,X ; Store the value at the 1st position of the array
LDD #$89AB ; Load the value 89SB into A register
STD 4,X ; Store the value at the 2nd position of the array
LDD #$CDEF ; Load the value CDEF into A register
STD 6,X ; Store the value at the 3rd position of the array
CALL DFLASH_Program ; note there is a status of verifiction in the Err variable after execution of this command
;---------------------------
;err = DFLASH_Program(0x0008, &buffer[0], 4); //write 4 words to eeprom address 0x0000
MOVW #$0008,Addr ; address to be written
MOVB #4,Cnt ; number of words to be written
;for example data to be written into DFLASH are 0123, 4567, 89AB, CDEF
LDX #Buffer ; Load the base address of the array into X register
LDD #$DEAD ; Load the value 0123 into A register
STD 0,X ; Store the value at the 0th position of the array
LDD #$BEEF ; Load the value 4567 into A register
STD 2,X ; Store the value at the 1st position of the array
LDD #$C0DE ; Load the value 89SB into A register
STD 4,X ; Store the value at the 2nd position of the array
LDD #$CAFE ; Load the value CDEF into A register
STD 6,X ; Store the value at the 3rd position of the array
CALL DFLASH_Program ; note there is a status of verifiction in the Err variable after execution of this command
;---------------------------
; get written data
;---------------------------
MOVW #$0000,Addr
CALL DFLASH_Read
STD var_Data
MOVW #$0002,Addr
CALL DFLASH_Read
STD var_Data
MOVW #$0004,Addr
CALL DFLASH_Read
STD var_Data
MOVW #$0006,Addr
CALL DFLASH_Read
STD var_Data
;---------------------------
JMP EndlessLoop ; restart.
;---------------------------
;*********************************************************************
;DFLASH_Read
;*********************************************************************
DFLASH_Read:
MOVB #$10, GPAGE
LDX Addr
GLDD X
RTC
;*********************************************************************
;DFLASH_Program
;*********************************************************************
DFLASH_Program:
;if((Cnt < 1) || (Cnt > 4))
LDAB Cnt
CMPB #1
BCS LBL_DP1
CMPB #4
BLS LBL_DP2
;return LENGTH_OUT_OF_RANGE;
LBL_DP1: MOVB #LENGTH_OUT_OF_RANGE,Err
RTC
LBL_DP2: ;while(FSTAT_CCIF == 0); //wait if command in progress
BRCLR FSTAT,#128,*+0 ;abs = 000e
;FSTAT = 0x30; //clear ACCERR and PVIOL
MOVB #$30, FSTAT
;FCCOBIX = 0x00;
CLR FCCOBIX
;FCCOB = 0x1110;
MOVW #$1110,FCCOB
;FCCOBIX = 0x01;
MOVB #$1,FCCOBIX
;FCCOB = address;
MOVW Addr,FCCOB
;for(i=2; i<=Cnt+1; i++) //fill appropriate number of words to FCCOB
CLRA
LDX #Buffer
LDAB Cnt
INCB
STAB var_j ; end variable of cycle
LDAA #$2 ; start value of cycle
LBL_DP3:
;FCCOBIX = A = 2 to {3,4,5};
STAA FCCOBIX
;FCCOB = *ptr;
LDD 2,X+
STD FCCOB
LDAA FCCOBIX
INCA
CMPA var_j
BLS LBL_DP3
;FSTAT_CCIF = 1; //launch command
BSET FSTAT,#128
;while(FSTAT_CCIF == 0); //wait for done
BRCLR FSTAT,#128,*+0 ;abs = 004b
;return OK;
MOVB OK,Err
RTC
;*********************************************************************
;DFLASH_Erase_Verify
;*********************************************************************
DFLASH_Erase_Verify:
;while(FSTAT_CCIF == 0); //wait if command in progress
BRCLR FSTAT,#128,*+0 ;abs = 0001
;FSTAT = 0x30; //clear ACCERR and PVIOL
MOVB #$30,FSTAT
;FCCOBIX = 0x00;
CLR FCCOBIX
;FCCOB = 0x1010;
MOVW #$1010, FCCOB
;FCCOBIX = 0x01;
MOVB #$1, FCCOBIX
;FCCOB = address;
MOVW Addr, FCCOB
;FCCOBIX = 0x02;
MOVB #$2, FCCOBIX
;FCCOB = number_of_bytes;
MOVB Cnt,FCCOB
;FSTAT_CCIF = 1; //launch command
BSET FSTAT,#128
;while(FSTAT_CCIF == 0); //wait for done
BRCLR FSTAT,#128,*+0 ;abs = 002b
;if(FSTAT_MGSTAT == 0)
BRCLR FSTAT,#3,*+7 ;abs = 0037
BRA lbl_nonerased
;return ERASED;
MOVB #ERASED, Err
RTC
lbl_nonerased:
;return NON_ERASED;
MOVB #NON_ERASED, Err
RTC
;*********************************************************************
;void DFLASH_Erase_Sector(unsigned int address)
;*********************************************************************
DFLASH_Erase_Sector:
;while(FSTAT_CCIF == 0); //wait if command in progress
BRCLR FSTAT,#128,*+0 ;abs = 0001
;FSTAT = 0x30; //clear ACCERR and PVIOL
MOVB #$30, FSTAT
;FCCOBIX = 0x00;
CLR FCCOBIX
;FCCOB = 0x1210;
MOVW #$1210, FCCOB
;FCCOBIX = 0x01;
MOVB #$1, FCCOBIX
;FCCOB = address;
MOVW Addr,FCCOB
;FSTAT_CCIF = 1; //launch command
BSET FSTAT,#128
;while(FSTAT_CCIF == 0); //wait for done
BRCLR FSTAT,#128,*+0 ;abs = 0022
RTC
;*********************************************************************
;*********************************************************************
;*********************************************************************
;*********************************************************************
;*********************************************************************
Hi Ladislav,
Thank you for that excellent attachment. It was just what I was looking for. It runs just fine on my controller, except for one thing.
I can't seem to get the debugger to update the memory window, either for the RAM or the D-Flash.
I when I single step through the program I expected to see the RAM addresses from $2100 to $2110 update with the appropriate steps. I'm not seeing this.
I also expected to see the D-Flash addresses from $10000 to $100010 update as I step through, but I'm not seeing that either.
Also, if I run the program and halt it, the memory locations are not updated.
Are there some settings in the de-bugger that I don't have set right?
Regards,
Robert
Hi again Ladislav,
After stepping through the program again several times I noticed some other peculiar things.
After running the FLASH_ERASE_VERIFY subroutine the returned "err" was $01. Which was expected. However, after any FLASH_PROGRAM subroutine "returned "err" was $40.
The FLASH_READ subroutine seems to work but it doesn't return the var_Data values I expected.
It returns $FA, $CF first. $4 second. $BB $B6 third. $46 $46 forth. The values at address $100000 are $FA, $CF, $00,$04,$BB, $B6, $46, $46. These are not the values that should have been burned to this address if I am understanding the program correctly.
The values at address $2100 are $CA,$FE,$CA,$FE,$CA,$FE,$CA,$FE and they don't change.
Something seems odd here.
Regards,
Robert
Hi,
there are no similarities. It is 2 levels higher MCU with different memory organization. In this case I suggest to use DFLASH for data storage. There is no ASM code available but I believe it is not any problem to do it by disassembling C code. If you are C coding engineer it must be easy for you to rebuilt it to asm.
Here is a C code and the project is attached. You can go/step through the ASM code in debugger to see how it works.
I have also attached C code for PFLASH programming. Nothing easier but it does not require to perform partitioning of this memory. There are some similarities in addresses but global address must be used for data E/W. Short (4000-7FFF) and PPAGE_Offset addresses are used for program execution.
In the case of the MCU it will require more effort to understand how flash is organized and how it works.
Moreover, to go from relocatable assembly of the single file project to the absolute assembly is easy. Directive EQU is used for data placement into RAM and ORG is used to place code in given PFLASH space.
What is necessary to be understand is that for reading and writing DFLASH the global address must be used. However in the case of this memory it is solved easily because it has higher word (DPAFE ) always 0x10 so it is enough to send to the routine only offset in the range 0000-7FFF and full address is created in routine, for example DFLASH_Program..
I am sorry we do not have any empty space, resources or responsibility for such complex projects … plus in assembler.
Best regards,
Ladislav
Hi Ladislav,
This is not easy stuff for me, but I was able to load your XEP100-DFLASH-CW47 program into my controller using a USBDM. I believe the program is running correctly. I expected to see the D-Flash address from $10_0000 loaded with $12, $34, $56, $78 $9A, $BC, $DE, $F0, but nothing is there. I also expected to see each of the remainder of the 256 byte sector loaded with $FF. Perhaps my understanding of how the program is supposed to work is flawed?
Regards,
Robert
I'm still not getting anywhere with this.
I've tried to figure out the ASM by stepping through the code, but I really have to be able to understand what the program is doing in "C" first. I believe that it partitions the DFlash then erases it all. Then it writes 16 bytes that it had written into RAM into D FLash. I can find the bytes in RAM, but in no place in D Flash can I find where it has written them in.
Any suggestions would be greatly appreciated.
Regards,
Robert
I'm still working hard at trying to figure this "C" code out but getting nowhere. The code runs and says that the first 256 bytes in D Flash have been erased at $10_0000, but I don't see that. Then it says that buffer[0] has been written into $0_0000, $10_0008 and $10_0010, But I don't see that either.
What am I missing here?
Regards,
Robert
Hi Ladislav,
Thanks again for your prompt reply and the files. I am not a "C" engineer and only have a basic knowledge of the language so the disassembly process will be challenging, but I'll give it my best shot.
Regards,
Robert