EEPROM-programming on 9S12-controllers

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

EEPROM-programming on 9S12-controllers

4,281 Views
Sten
Contributor IV
I have stumbled over a strange problem regarding EEPROM-programming on several different controllers in the 9S12-family. I have tested this on the following parts, and all behave in the same way: MC9S12DT128MPVE (chipset 1L59W), MC9S12D32VFUE (chipset 0M89C) and MC9S12XDT256CAL (chipset 0L15Y). I am using the same routines for EEPROM-handling on all parts.
 
The routine I am using to write a 4 byte page to the EEPROM starts by using the Sector-Modify command (0x60) to erase the page and program the first two bytes, then I wait for CBEIF (Command Buffer Empty Flag), continue with a Program command (0x20) to program the second two bytes and finally wait for both CBEIF and CCIF (Command Complete Flag).
 
This works (and has worked for a long time) fine, until I yesterday stumbled over something very strange. If the second two bytes of a page (any page anywhere in the EEPROM) is programmed to 10 4f, those two bytes remains erased (ff ff) and the 10 4f appears as the two first bytes in the next page to program.
 
This happens only with the exact bytes 0x10 and 0x4f and when programming to the second two bytes of a EEPROM page. For example, if I want to program 0 0 10 4f to adress 810 and 0 0 0 0 to address 820 the result will be 0 0 ff ff at 810 and 10 4f 0 0 at address 820.
 
I have fould out that if I wait also for the CCIF-bit after the Sector-Modify command (before using the Program command to write the 10 4f), it works ok. But should this be needed, because I am continuing the programming process, shouldn't it be enough to wait just for the CBEIF-bit? And why does it work with any other byte combination, but not with 10 4f?
 
Sten
 
Labels (1)
0 Kudos
Reply
8 Replies

1,400 Views
kef
Specialist I
Sten,
 
I tried today sector modify followed by wait for CBEIF, then write 104f. I tried it on 0M89C and 1L59W. Worked. Please show your test code.
0 Kudos
Reply

1,400 Views
Sten
Contributor IV
Lundin:
yes, I will also now modify all my programs to also wait for CCIF. My routines were based on the ones generated by some older version of Processor Expert, but I have noticed that since v. 4.7, they have changed the PE-routines to also wait for CCIF. The behavior is not dependent of the number of zeroes, it is only the exact combination 10 4F that fails, e.g. 20 4F (with the same number of of 0-bits) and 00 00 works fine.
 
kef:
did you try to a erased sector or did the sector contain something. If I write 10 4f to a sector already containing xx xx ff ff (to get xx xx 10 4f) it also works for me, but if I first fill the sector with some other contents (eg. 00 00 00 00) and then do a sector-modify and program sequence to get 00 00 10 4f, it fails.
 
Here is an extract from my code:
Code:
void main(void) {....   prog_eeprom_WORD(0x0c00, 0);          /* clear 0x0c00..0x0c07 */   prog_eeprom_WORD(0x0c02, 0);   prog_eeprom_WORD(0x0c04, 0);   prog_eeprom_WORD(0x0c06, 0);      prog_eeprom_WORD(0x0c02, 0x104f);     /* try to write 0x104f to 0x0c02  (will be 0xffff) */   prog_eeprom_WORD(0x0c06, 0x1234);     /* try to write something to 0x0c06  (succeeds but 0x0c04 will be 0x104f) */......}        /* Note that low_level_WriteWORD does NOT erase nor verify the EEPROM for erased state */        /* the timer interrupt must be disabled during this time (parameters in EEPROM are not accessable during this operation) */void low_level_WriteWORD(WORD addr, WORD data16) {   BYTE iflag;   if (*(volatile WORD *) addr == data16) return;       /* no need to program */   if (ESTAT_CBEIF == 0) {      /* Command Buffer not empty— */      int_err |= 2;     /* flag an OnChip EEPROM internal error */      return;   }//  keep the interrupts enabled, to prevent SCI OverRuns, just disable the Modulus Counter Interrupt    iflag = MCCTL_MCZI – 1 : 0;    MCCTL_MCZI = 0;     /* Disable Modulus Counter Interrupt */   ESTAT = 0x30;                        /* writing a 1 to the error flags PVIOL and ACCERR resets them */   *(volatile WORD *) addr = data16;    /* Array address and program data */   ECMD = WORD_Program;                 /* WORD program command */   ESTAT_CBEIF = 1;                     /* Clear flag command buffer empty */   if (ESTAT_PVIOL || ESTAT_ACCERR) {      int_err |= 4;     /* flag an OnChip EEPROM internal error */      goto ww_exit;   }   while (ESTAT_CBEIF == 0);            /* Wait to buffer empty */   while (ESTAT_CCIF == 0);             /* Wait for command completition */ww_exit:   if (iflag) MCCTL_MCZI = 1;   /* Reenable Modulus Counter Interrupt */   return;}        /* the timer interrupt must be disabled during this time (parameters in EEPROM are not accessable during this operation) */void low_level_WriteSector(WORD sect_addr, DWORD data32) {   BYTE iflag;   if (*(volatile DWORD *) sect_addr == data32) return;      /* no need to program */   if (ESTAT_CBEIF == 0) {      /* Command Buffer not empty˜ */      int_err |= 2;     /* flag an OnChip EEPROM internal error */      return;   }//  keep the interrupts enabled, to prevent SCI OverRuns, just disable the Modulus Counter Interrupt    iflag = MCCTL_MCZI ™ 1 : 0;    MCCTL_MCZI = 0;     /* Disable Modulus Counter Interrupt */   ESTAT = 0x30;                        /* writing a 1 to the error flags PVIOL and ACCERR resets them */   *(volatile WORD *) sect_addr = (WORD)(data32 >> 16); /* Array address and program data - higher part */   ECMD = Sector_Modify;                /* Sector modify command */   ESTAT_CBEIF = 1;                     /* Clear flag command buffer empty */   if (ESTAT_PVIOL || ESTAT_ACCERR) {      int_err |= 4;     /* flag an OnChip EEPROM internal error */      goto ws_exit;   }   while (ESTAT_CBEIF == 0);            /* Wait to buffer empty */   low_level_WriteWORD(sect_addr + 2, (WORD) data32); /* Write lower part */ws_exit:   if (iflag) MCCTL_MCZI = 1;   /* Reenable Modulus Counter Interrupt */   return;}        /* program one word in the internal EEPROM      */        /*  - if the bytes fall into different sectors  */        /*    - program the word as two bytes           */        /*  - else if the word is aligned and erased    */        /*    - just program that word                  */        /*  else                                        */        /*    - read the 4-byte sector it belongs to    */        /*    - erase the sector                        */        /*    - program back the modified sector        */void prog_eeprom_WORD(WORD Addr, WORD Data) {   union {      BYTE  b[4];      WORD  w[2];      DWORD l;   } backup;   BYTE idx = Addr & 0x0003;   if (*(volatile WORD *) Addr == Data) return;         /* no need to program */   if (Addr < EEPROM_START || Addr > EEPROM_END) { /* Is given address out of EEPROM area array */      *(WORD *) Addr = Data;      return;   }   if (idx == 3) {                        // the word spans over two segments       prog_eeprom_BYTE(Addr, Data >> 8);      prog_eeprom_BYTE(Addr + 1, Data & 0xff);   }    else if ((Addr & 1) == 0 && *(volatile WORD *) Addr == 0xFFFF) low_level_WriteWORD(Addr, Data); /* Write new content directly if word aligned and already erased */   else {                                               /* Not erased  or not word aligned */      backup.l = *(volatile DWORD *) (Addr & 0xFFFC);   /* Load sector to variable backup (from sector-aligned address) */      backup.b[idx]     = Data >> 8;                    /* Store data to variable backup */      backup.b[idx + 1] = Data & 0xff;      low_level_WriteSector(Addr & 0xFFFC, backup.l);   /* Erase sector and write new content */   }}

 
0 Kudos
Reply

1,400 Views
kef
Specialist I
Hm, works for me on 1L59W. With RAM remapped to 0x2000 and EEPROM to 0x800.
Both step by step in BDM mode and at full speed in normal mode. Of course I removed
calls to not defined prog_eeprom_BYTE().
 
BTW IMO this is a bad piece of code
Code:
   ESTAT_CBEIF = 1;                     /* Clear flag command buffer empty */   if (ESTAT_PVIOL || ESTAT_ACCERR) {      ...   }

 
Clearing CBEIF as you do above, you also may write ones to PVIOL and ACCERR bits!
Every time PVIOL or ACCERR, or both are set, you clear them doing ESTAT_CBEIF=1.
You should use ESTAT = CBEIF_MASK to clear just CBEIF.
0 Kudos
Reply

1,400 Views
Sten
Contributor IV
Found it! My fault! :smileysad:
 
The first condition in the low_level_WriteWORD()-routine (if (*(volatile WORD *) addr == data16) return:smileywink: is not allowed in that stage! It tries to check if the contents of the EEPROM already is correct and skip the programming in that case, but because this routine is called from low_level_WriteSector which just has started a SectorModify-command, the EEPROM is busy and unreadable!
 
It seems that a busy EEPROM returns 104f when read, and that will cause the low_level_WriteWORD()-routine to be skipped when trying to program 104f.
 
kef:
ESTAT_CBEIF = 1; compiles to BSET  _ESTAT,#128. Isn't that as safe as ESTAT = ESTAT_CBEIF_MASK (which compiles to LDAB #128, STAB _ESTAT)?
 
Sten
 
0 Kudos
Reply

1,400 Views
kef
Specialist I
Glad you found it!
 
ESTAT_CBEIF = 1  and BSET  _ESTAT,#128 and LDAB  #128 STAB _ESTAT DO CLEAR NOT ONLY CBEIF flag, but also other writeable flags (ACCERR, PVIOL). It doesn't make sense to check if ACCERR or PVIOL are set after ESTAT_CBEIF = 1. You should use
 
ESTAT = ESTAT_CBEIF_MASK
 
or
 
ESTAT &= ESTAT_CBEIF_MASK
 
or
 
BCLR  ESTAT, #127  // 127 = ~0x80
 
These 3 varianst will clear just CBEIF
0 Kudos
Reply

1,400 Views
Lundin
Senior Contributor IV
I always wait for CCIF after erase, as advised by Freescale. See the example flowchart for an eeprom programming algorithm in the manual.

Edit: The reason why your partcular example isn't working might be because it contains a lot of binary zeroes. To me, it makes sense that zeroes takes longer time to program than ones, since the cell is set to FF after reset. Bit far-fetched maybe... But try the value 00h.

Message Edited by Lundin on 2008-10-16 05:02 PM
0 Kudos
Reply

1,400 Views
J2MEJediMaster
Specialist I
That sounds really odd. I have no idea why that is happening. Please file a service request on this.

---Tom
0 Kudos
Reply

1,400 Views
Sten
Contributor IV
Thanks Tom,
 
I will make a small project that demonstrates this and file a service request.
 
Sten
 
0 Kudos
Reply