I’m experiencing an EEprom fault using MC9S12DP512 where seemingly random addresses get erased after 2 or 3 years of use typically. I originally thought this was because the memory location was wearing out, but this is happening in locations where the EEprom is written to just once in the lab when first programmed. After we manually reset the data in the location, it will retain the data for about 6 weeks.
What external factors could affect the EEprom in this way? Ie. power supply, oscillator, decoupling?
Any help would be greatly appreciated.
Hi,
Do you mean flash eeprom or eeprom?
What do you mean by erased? Erased status is 0xFF (charged cap.).
Main factors are temperature, correctly set flash machine frequency, correct bus clock.
In the case of flash eeprom it is necessary to clear flags in all blocks before E/W a word...
for(err=0;err<4;err++) { FCNFG_BKSEL = err; FSTAT=0x30; } // PVIOL=ACERR=0
or
;erase error flags in all blocks
MOVB FCNFG,temp ; store FCNFG
LDAA FCNFG ; get FCNFG
LDAB #FLASHblocks ; loop constant
FES1:
DECB ; calculate block in loop
ANDA #$F0 ; mask block in FCNFG
ABA ; write block to FCNFG
STAA FCNFG ;
MOVB #$30,FSTAT ; errase error flags in given block
TSTB
BNE FES1
Best regards,
Ladislav
Thanks for your message Ladislav.
It’s Flash EEprom and the memory sectors are reset to 0xFFFF. Below is part of a memery dump where we have lost data at 0404 to 0407:
vvvv vvvv (been reset)
0400: FFBF 163F FFFF FFFF 3032 3335 FFFF FFFF
^^ ^^ ^^ ^^ (unused)
0410: FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF
0420: FFFF FFFF FFFF FFFF FFFF FFFF 8025 FFFF
0430: 01AD 3EAB 541B E50A 0ED4 FFFF FFFF FFFF
Below is the function we use to write one word to the flash EEprom:
; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
EEWRITE: ; EEPROM[X]:=D; 1 WORD, X is preserved
; Note can only write aligned WORDs, i.e. EVEN addresses,
; and can only erase 4 bytes, i.e. address [1:0] ignored for erase
; Time to erase 4byte EEPROM sect {or 512k Flash sector} 22ms
; To prog 1 WORD 55us, to prog subsequent WORD 22us
; ** measured as 23ms proc !!!
; 16MHz OSCCLK{XTAL} /8 {b6} /(10d+1) = 182kHz NVMclk {Eclk of Fclk}
; MOVB #4AH,ECLKDIV ; EEPROM clock divider
; Method is to copy make stack of 2 WORDS, one of them being new, and one being
; copy of original. Then erase the 4 bytes, then write 2 WORDs back.
; Stack is to be:-
; <address>
; <lower WORD>
; <upper WORD>
; ----------------------------
; Example of usage ...
;
; LDX #TestEE1 ;^TestEE1
; LDD #12ABH ; WORD to write
; JSR EEWRITE ; EEPROM[X]:=D {TestEE1:=12ABH}
;
; LDD TestEE1 ; Check written
; JSR DISPHEX4
; ----------------------------
PSHX ; preserve
PSHD ; save data to write
PSHD ; twice {one will be wrong !}
; Make address even if not
TFR X,D ; D:=X
ANDB #0FEH ; clr lsb
PSHD ; store real address
ANDB #0FCH ; clear d1 to align to 4 byte sector
TFR D,X ; X is ^ low end of the 4 byte sector to write
; ? which word are we requested to change ?
CPX 0,SP ; compare aligned address with stacked value
BEQ EEw01 ; lower WORD needs to change
; so, upper WORD to change
LDD 0,X ; get original lower WORD
STD 2,SP ; and save in stack
BRA EEw02
EEw01: ; lower word to change
LDD 2,X ; get original upper WORD
STD 4,SP ; change upper word in stack
EEw02:
PULD ; address clear off stack
; ready to erase/prog 4 bytes
MOVB #30H,ESTAT ; clr PVIOL & ACCERR
PULD ; retrieve lower data WORD
STD 0,X ; M[X]:=D setup to write
; commands are 20 - prog WORD; 40 erase 2 WORDs; 41 erase all EEPROM
; 60 - ERASE 2 WORDs then prog 1 WORD ..... in same operation
MOVB #60H,ECMD ; command 60 to erase then write
MOVB #80H,ESTAT ; clr CBEIF bit
BRCLR ESTAT,80h,* ; wait for CBEIF before next write !
PULD ; retrieve upper data WORD
STD 2,X ; M[X+2]:=D
MOVB #20H,ECMD ; command 20 to prog WORD
MOVB #80H,ESTAT ; clr CBEIF bit
BRCLR ESTAT,80h,* ; wait for buffer empty - this seems to be necessary
BRCLR ESTAT,40h,* ; wait for write complete before returning
PULX ; restore X
RTS
; ***** End of EEWRITE SUBroutine *****
We also use a write 2 words to EEprom function but in essences it is the same just a larger stack.
Let me know if you need anymore details; I'm quite stuck on this one.
Thanks
Kind regards
Tom
Hi,
The address 0400 is not flash EEPROM. It is EEPROM. Only to set terms.
Flash EPROM is the memory which usually stores code. It has larger sector size (512B or 1024B for S12 devices), less EW cycles,….
The EEPROM is memory usually used for data. It has smaller sector size (4B in S12 family devices), higher amount of E-W cycles,…
I do not know the setup of the INITRG, INITRM and INTEE registers. They are by default 0x00, 0x09,0x01 which places the memrie to following addresses.
Registers 0000~03FF size = 1kB
RAM 0800~3FFF size = 14kB
EEPROM 0000~0FFF size = 4kB (useable 0400~07FF, all other parts are overlapped by memories with higher priority)
Is suppose you use BUSCLK = 8MHz OSCCLK=16MHz => ECLKDIV = 0x4A which I can also see in your code.
!!! What I am missing is a safe period of time for writing to EEPROM to avoid an interrupt routine to read from EEPROM while it is written. It is forbidden to read while write if you do not want to have corrupted data.
The difference I use is for write finishing check.
You: BRCLR ESTAT,80h,* ; wait for CBEIF before next write !
Me: CkStat3:
ldab ESTAT
BitB #mESTAT_CBEIF+mESTAT_CCIF ;check command buffer empty status bit
Beq CkStat3
Moreover, if you check the data by IDE then you have to remove the window which reads the memory which is currently written. You have to avoid unexpected reading even by BDM.
However, I think it does not relate to an issue. The question is what were conditions for programming in lab. Lower programming frequencies can cause the memory cell is overloaded and data retention decreases. Higher programming frequencies, in opposite, cause either the EEPROM is not correctly erased or it is not correctly programmed or both together. Data retention is also decreased but the memory cell has correct quality.
Are you able to remember the conditions the EEPROM was originally programmed in lab?
Is it a problem of the only one device or you have observed it on more devices. (Could you send me entire text you can read on the top of the device)
Could I see schematic design of MCU environment to be sure it is OK before I suggest you to solve it as a quality incident. You can send it to me via technical support pages. Open a case, write correct part number and you can add “To Ladislav” to subject or description.
How to do it you can see in: https://community.nxp.com/docs/DOC-329745
The code I used for explanation with another customer for similar MCU many years ago. Only to show you if you want to compare.
;_______________________________________________________________________________
; - Example present erase sector and write word to the EEPROM
; - Before write it checks:
; * alignment (2B)
; * whwther sector is erased
; - Before sector erase it checks:
; * alignment (4B)
; - Variable err_code is used as a error return code
;_______________________________________________________________________________
; export symbols
XDEF Entry ; export 'Entry' symbol
ABSENTRY Entry ; for absolute assembly: mark this as application entry point
; include derivative specific macros
INCLUDE 'mc9s12dg256.inc'
;_______________________________________________________________________________
; definitions
;_______________________________________________________________________________
ROMStart EQU $4000 ; absolute address to place my code/constant data
ERR_OK: EQU $0 ; OK
ERR_RANGE: EQU $1 ; Parameter out of range. (not alligned sector 4B; data 2B))
ERR_BUSY: EQU $2 ; Device is busy.
ERR_NOTAVAIL: EQU $3 ; Requested value or method not available.
ERR_NOTERASED: EQU $4 ; Requested address is not erased
;_______________________________________________________________________________
; variable/data section
;_______________________________________________________________________________
ORG RAMStart
;_______________________________________________________________________________
EE_data DS.W 1 ; data to be written
err_code DS.B 1 ; return value from flash erase/write functions
CCRbackup DS.B 1 ; CCR backup value
p_EE_address:
EE_address DS.W 1 ; address for sector erase or data write
p_EE_lngdata:
EE_lngdataH DS.W 1 ; long data to write
EE_lngdataL DS.W 1 ; long data to write
;_______________________________________________________________________________
; code section
;_______________________________________________________________________________
ORG ROMStart
;_______________________________________________________________________________
; main loop
;_______________________________________________________________________________
Entry:
;--- memory mapping ------------------
;MOVB #$0,INITRM ; INITRM = 0x00; Set the RAM map position 0x0000~0x2FFF
;MOVB #$31,INITEE ; INITEE = 0x31; Set the EEPROM map position 0x3000~0x3FFF, EEON=1
;MOVB #$0,$INITRG ; INITRG = 0x00; Set the Reg map position 0x0000~0x03FF
;NOP; ; recommended
;LDS #$3000 ; initialize stack on the top of RAM
;--- reset default memory mapping ----
;INITRG = 0x00; Set the Reg map position 0x0000~0x03FF
;INITEE = 0x01; Set the EEPROM map position 0x0000~0x0FFF, EEON=1 => visible 0x0400~0x0FFF
;INITRM = 0x09; Set the RAM map position 0x1000~0x3FFF
LDS #$4000 ; initialize stack on the top of RAM
;--- EEPROM clock---------------------
MOVB #$4A,ECLKDIV ; ECLKDIV = 0x4A, eeprom clock prescaler; OSCCLK = 16MHz BUSCLK=8MHz
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
loopCTM:
; no EEPROM range checking
; no 4B allignment checking
; no EEPROM busy checking
; no protection checking
; no error checking
; default memory map (no remapping) - part of visible EEPROM is at 0400~0FFF
; Y *data
; X *addr
;-------------------------------------
;your approach X stores destination address Y stores pointer to data
MOVW #$0400,EE_address ; prepare address for sector modify function
MOVW #$7654,EE_lngdataH ; prepare data for sector modify function
MOVW #$3210,EE_lngdataL ; prepare data for sector modify function
LDX #p_EE_address
LDY #p_EE_lngdata
JSR WriteLong ; corrected your approach
;-------------------------------------
; my approach parameters are EE_address, EE_lngdataH, EE_lngdataL
MOVW #$0404,EE_address ; prepare address for sector modify function
MOVW #$DEAD,EE_lngdataH ; prepare data for sector modify function
MOVW #$D0D0,EE_lngdataL ; prepare data for sector modify function
JSR WriteLong1
JMP loopCTM
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
loop:
;--- Erase sector --------------------
MOVW #$0400,EE_address ; prepare address for write function
JSR EraseSector ; erase sector at address $0400
;--- Write word to eeprom ------------
MOVW #$0400,EE_address ; prepare address for write function
MOVW #$1234,EE_data ; prepre data for write function
JSR WriteWord ; write word to the eeprom without checking address and EEPROM erased
;--- check error code and written data
;...
;...
;...
;--- Write word to eeprom ------------
MOVW #$0402,EE_address ; prepare address for write function
MOVW #$5678,EE_data ; prepre data for write function
JSR WriteWord ; write word to the eeprom without checking address and EEPROM erased
;--- check error code and written data
;...
;...
;...
;--- loop forever---------------------
JMP loop ; endless loop
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
WriteLong:
Wrt1stWord:
; get CCR disable interrupts to avoid EEPROM reading while EEPROM under E/W
TPA
STAA CCRbackup
SEI
;....................................
; erase sector and write first word
;....................................
MovB #$30,ESTAT ; Clear error flags
LdD 0,Y ; prepare higher word for wrriting
LDX 0,X
StD 0,X
MovB #$60,ECMD ;sector modify command
MovB #$80,ESTAT ;start command
CkStat:
LdaB ESTAT
BitB #mESTAT_CBEIF+mESTAT_CCIF ;check command buffer empty status bit
Beq CkStat
;....................................
; write second word
;....................................
Wrt2ndWord:
LdD 2,Y ; get lower word for writing
INX
INX
StD X ; store it to next address
MovB #$20,ECMD ; write a word command
MovB #$80,ESTAT ;start command
CkStat1:
LdaB ESTAT
BitB #mESTAT_CBEIF+mESTAT_CCIF ; check for all commands complete
Beq CkStat1
;....................................
; RESTORE_CCR;
LDAA CCRbackup
TAP
;....................................
RTS
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
WriteLong1:
PSHD ; store what modified
PSHX
; get CCR disable interrupts to avoid EEPROM reading while EEPROM under E/W
TPA
STAA CCRbackup
SEI
;....................................
; erase sector and write first word
;....................................
MovB #$30,ESTAT ; Clear error flags
LDX EE_address
LDD EE_lngdataH
STD 0,X
MovB #$60,ECMD ;sector modify command
MovB #$80,ESTAT ;start command
CkStat3:
LdaB ESTAT
BitB #mESTAT_CBEIF+mESTAT_CCIF ;check command buffer empty status bit
Beq CkStat3
;....................................
; write second word
;....................................
LDD EE_lngdataL ; get lower word for writing
INX
INX
StD X ; store it to next address
MovB #$20,ECMD ; write a word command
MovB #$80,ESTAT ;start command
CkStat4:
LdaB ESTAT
BitB #mESTAT_CBEIF+mESTAT_CCIF ; check for all commands complete
Beq CkStat4
;....................................
; RESTORE_CCR;
LDAA CCRbackup
TAP
;....................................
PULX ;restore
PULD
RTS
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
;_______________________________________________________________________________
; WriteWord
; inputs: EE_address
; EE_data
; output: err_code
;_______________________________________________________________________________
WriteWord:
PSHD
PSHX
LDD EE_address ; check alignment (4B)
LDX #$2
IDIV
CPD #$0 ; if != $0 => error
BEQ WriteWord_LBL6
MOVB #ERR_RANGE,err_code ;return ERR_RANGE;
BRA WriteWord_LBL2
WriteWord_LBL6: ; check whether word is errased
LDX EE_address ;*(volatile word *) AddrRow = Data16; // Array address and program data
LDD 0,X
CPD #$FFFF ; if != $FFFF => error
BEQ WriteWord_LBL5
MOVB #ERR_NOTERASED,err_code ;return ERR_BUSY; // If yes then error
BRA WriteWord_LBL2
WriteWord_LBL5:
BRSET ESTAT,#128,WriteWord_LBL1 ;if (ESTAT_CBEIF == 0) // Is command buffer full ?
MOVB #ERR_BUSY,err_code ;return ERR_BUSY; // If yes then error
BRA WriteWord_LBL2
WriteWord_LBL1:
MOVB #$30,ESTAT ;ESTAT = 0x30; // Clear error flags
LDX EE_address ;*(volatile word *) AddrRow = Data16; // Array address and program data
LDD EE_data
STD 0,X
MOVB #$20,ECMD ;ECMD = 0x20; // Word program command
BSET ESTAT,#$80 ;ESTAT_CBEIF = 1; // Clear flag command buffer empty
BRSET ESTAT,#$20,WriteWord_LBL3 ;if ((ESTAT_PVIOL == 1)||(ESTAT_ACCERR == 1)) // Is protection violation or acces error detected ?
BRCLR ESTAT,#$10,WriteWord_LBL4
WriteWord_LBL3:
MOVB #ERR_NOTAVAIL,err_code ;return ERR_NOTAVAIL; // If yes then error
BRA WriteWord_LBL2
WriteWord_LBL4:
LDAB ESTAT ;while (EEPROM_BUSY); // Wait for command completition
ANDB #192
CMPB #192
BNE WriteWord_LBL4
MOVB ERR_OK,err_code ;return ERR_OK;
WriteWord_LBL2:
PULX
PULD
RTS
;_______________________________________________________________________________
; EraseSector
; inputs: EE_address
; output: err_code
;_______________________________________________________________________________
EraseSector:
PSHD
PSHX
LDD EE_address ; check alignment (4B)
LDX #$4
IDIV
CPD #$0 ; if != $0 => error
BEQ EraseSector_LBL5
MOVB #ERR_RANGE,err_code ;return ERR_RANGE;
BRA EraseSector_LBL2
EraseSector_LBL5:
BRSET ESTAT,#128,EraseSector_LBL1;if (ESTAT_CBEIF == 0) // Is command buffer full ?
MOVB #ERR_BUSY,err_code ;return ERR_BUSY; // If yes then error
BRA EraseSector_LBL2
EraseSector_LBL1:
MOVB #$30,ESTAT ;ESTAT = 0x30; // Clear error flags
LDX EE_address ;*(volatile word *) AddrRow = Data16; // Array address and program data
LDD #$FFFF ; dummy data
STD 0,X
MOVB #$40,ECMD ;ECMD = 0x20; // Word program command
BSET ESTAT,#$80 ;ESTAT_CBEIF = 1; // Clear flag command buffer empty
BRSET ESTAT,#$20,EraseSector_LBL3 ;if ((ESTAT_PVIOL == 1)||(ESTAT_ACCERR == 1)) // Is protection violation or acces error detected ?
BRCLR ESTAT,#$10,EraseSector_LBL4
EraseSector_LBL3:
MOVB #ERR_NOTAVAIL,err_code ;return ERR_NOTAVAIL; // If yes then error
BRA EraseSector_LBL2
EraseSector_LBL4:
LDAB ESTAT ;while (EEPROM_BUSY); // Wait for command completition
ANDB #192
CMPB #192
BNE EraseSector_LBL4
MOVB ERR_OK,err_code ;return ERR_OK;
EraseSector_LBL2:
PULX
PULD
RTS
;_______________________________________________________________________________
;**************************************************************
;* Interrupt Vectors *
;**************************************************************
ORG $FFFE
DC.W Entry ; Reset Vector
Best regards,
Ladislav
Thanks Ladislav that is really useful and gave me a lot to think about.
The program can interrupt while there is an EEprom write in process, but it doesn't do any EEprom read or writes in the interrupt. We use the interrupt mainly for timing and CAN RX signals. Could the interrupt be affecting the EEprom?
We program the MCU with a bootloader that has some basic functions first using PE micro mulitlink and noICE. Using some of the functions in the bootloader we can set things like serial number in EEprom (@0404 to 040B) and this is only done once in the lab via a RS232 interface and uses the EEwrite function I mentioned above. We can then load the main program in afterwards.
The eeprom fault has happened on about 14 devices out of about 400 that regularly use the eeprom. We tried replacing the processor on a bad board that was failing frequently but it made no difference (keeping the program the same). It had worked correctly for about 3 years, then got worse as time when on until it would fail overnight.
An device example is: MC9S12DP512MPVE 4L00M QQQG1317
I will send you the circuit diagrams in a ticket.
Thanks for your help.
Kind regards
Tom
Hi Tom,
I am sorry, but Ladislav is now sick.
I just shortly check your conversation and received schematic and layout.
I didn’t found any obvious or potential issue at schematic and layout until now.
Interesting is your last statement about bootloader and programming serial number in EEprom (@0404 to 040B).
How did you manage enter bootloader mode and what steps are necessary prior bootloader jumps into programming routine (erase sector from 0x0404 and … )?
Is it possible that MCU unintentionally jumps into bootloader mode, automatically erase EEPROM sector with serial number and wait for data from SCI (since there is no valid communication, the serial number is not programmed)?
Have a great day,
Radek
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------