programming EEPROM

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 

programming EEPROM

5,930 次查看
bdayberr
Contributor I
I have closely followed AN2400 for guidance in using the EEPROM, and have it mostly functional. In the AN2400 document the C code to write data to an address is: *progAddr = data; with progAddr being defined as UINT* 16 and data UINT 16. By looking at another post on these forums I ended up accomplishing this in my own code as:

*(volatile unsigned char*)0x1400 = data;

with 0x1400 being the first address of EEPROM for my device(MC9S08DZ60) and data being defined as an int, with: typedef unsigned int word;

When data is an int less than 255, a byte, everything writes fine. And when reading the data back with:

data = *(volatile unsigned char*)0x1400;

data is correct.

However, when data is more than 255, it ends up writing as the original data-255-1, and gets recalled as such. When I change the dereferenced pointer to:

*(volatile unsigned int*)0x1400 = data;

in the any of the functions, it compiles but in debug everything fails and the error bits get set in FSTAT. Any suggestions?




Message Edited by bdayberr on 2008-02-24 12:52 AM
标签 (1)
0 项奖励
回复
18 回复数

2,391 次查看
JimDon
Senior Contributor III
Well, when the data is more that 255, then it does not fit in a byte.
You have to write one byte at a time, so to write a word you will need to write twice.
This is what I do for flash:

Code:
void FlashProgramWord(word address, word data) {     Program_Byte(address++,(byte) (data >> 8)); // hi byte   Program_Byte(address,(byte) (data & 0xff)); // lo byte   return;  }

 




Message Edited by JimDon on 2008-02-23 08:08 PM
0 项奖励
回复

2,391 次查看
bdayberr
Contributor I
Also, is there a better way to do the pointer referencing that I am doing?
0 项奖励
回复

2,391 次查看
JimDon
Senior Contributor III
I thought you said you had EEPROM working and that you could program a byte?

I don't have an 08 boards with EERPOM, so I can't test it. There was a long thread about it recently. Did they not end up posting some working code?
The thing is flash has to br programmed from RAM, as you can't read from flash while you are programming it. This is not true of EEPROM.

If you can't find the code I will go back and look for it.

Code:
#ifndef word#define word unsigned int#endfiword *pWord = (word*)0x1400;....  word data = *pWord++;  data = pWord[i];Don't know if that is helpful

This is the code from the other thread, but first you have to set
the ECLK register, which should be explained in the data sheet.

This is allawtterb's code, and I have no way to test it.
You also have to erase it first.

void ProgramByte( word address, byte data )
{
 if (FSTAT_FACCERR)              //If EEPROM access error flag is set
   FSTAT_FACCERR = 1;             //Then clear it
 
  while(!FSTAT_FCBEF);
  *address = data;                 //Set the data to be written to the address to be written to
  FCMD = BYTE_PROGRAM;             //Flash/EEPROM command to program a byte (0x20)
                      
  FSTAT_FCBEF = 1;                //Clear command buffer empty flag

  if (FSTAT_FACCERR)              //If EEPROM access error flag is set
   FSTAT_FACCERR = 1;             //Then clear it
 
  if (FSTAT_FPVIOL)               //If EEPROM write error flag is set
    FSTAT_FPVIOL = 1;             //Then clear it
                                 
  while (!FSTAT_FCBEF);           //Wait for command buffer to be empty
  while (!FSTAT_FCCF);            //Wait for all commands to complete
}

 



Message Edited by JimDon on 2008-02-23 08:40 PM

Message Edited by JimDon on 2008-02-23 08:43 PM

Message Edited by JimDon on 2008-02-23 08:44 PM
0 项奖励
回复

2,391 次查看
allawtterb
Contributor IV
The code Jim posted from me is what I use on the DZ60's I work with.  It should be fine except
that code won't compile as address isn't a pointer in that code.  If you are going to use that
you just need to recast address to a pointer and dereference it like so:
 
*(byte *)address = data;
0 项奖励
回复

2,391 次查看
JimDon
Senior Contributor III
Yes he is correct,

The parameter to the function should be:

Code:

#ifndef word
#define word unsigned int
#endif

#ifndef byte
#define word unsigned char
#endif
void ProgramByte( byte* address, byte data )

 If you have a complete set with clock set up and erase, how about testing it an posting it.
I hate posting code I have not tested. There is always a mistake.




0 项奖励
回复

2,390 次查看
bdayberr
Contributor I
I just tested all of this on the device and it works, thanks again to both of you for the help and code:

Code:
#include <hidef.h> /* for EnableInterrupts macro */#include <stdio.h>#include "derivative.h" /* include peripheral declarations */#include "M68DEMO908DZ60.h"#define PASS  0#define FAIL  1#define ERASE   0x40#define PROG    0x20#define CBEF    0x80#define EEPROM_START  0x1400typedef unsigned char byte;typedef unsigned int word;typedef unsigned long dword;typedef unsigned long dlong[2];int dummy=0;/* address and program commands */int eraseSector(byte* address);int writeByte(byte* address, byte data);int readByte(byte* address);int readWord(byte* address);void progByte(byte* address,byte data);void progWord(byte* address,word data);   int eraseSector(byte* address){  DisableInterrupts;  FSTAT = 0x30; /*clear errors*/  if(FSTAT_FCBEF==1){    *address = dummy;    FCMD = ERASE;    FSTAT = CBEF;    if( (FSTAT_FACCERR!=0) || (FSTAT_FPVIOL!=0)){      EnableInterrupts;      return(FAIL);    }    while(FSTAT_FCCF!=1){    }    EnableInterrupts;    return(PASS);  } else{    EnableInterrupts;    return(FAIL);  }}int writeByte(byte* address, byte data){  DisableInterrupts;  FSTAT = 0x30;  if(FSTAT_FCBEF==1){    *address = data;    FCMD = PROG;    FSTAT = CBEF;    if( (FSTAT_FACCERR!=0) || (FSTAT_FPVIOL!=0)){      EnableInterrupts;      return(FAIL);    }    while(FSTAT_FCCF!=1){    }    EnableInterrupts;    return(PASS);  } else{    EnableInterrupts;    return(FAIL);  }}int readByte(byte* address){  int data = *address;  return data;}int readWord(word* address){  int datar = *address;  return datar;}void progByte(byte* address,byte data){  eraseSector((byte*)address);  writeByte((byte*)address,data);}void progWord(byte* address,word data){  eraseSector((byte*)address);  writeByte((byte*)address++,(byte) (data >> 8));  writeByte((byte*)address, (byte) (data & 0xFF));}

 functions called like:

progWord((byte*)0x1400,444);
  data = readWord((byte*)0x1400);



Message Edited by bdayberr on 2008-02-24 06:28 AM
0 项奖励
回复

2,390 次查看
bdayberr
Contributor I
I am actually using processor expert's device initialization to create an MCU_init(), so I just used the intEEPROM bean to set the divider for the clock, but here is the code that does it. I have MCU_init() set up the clock, then I change the frequency of the bus clock on my own to 2MHz. Since the MCU_init() already sets the FCLK divider to 8, once I set the bus freq to 2MHz, the flash and EEPROM clock is operating correctly at 200kHz. Also, I put in the code for Disable and Enable Interrutps because I saw alterweb did it and felt that if I did need to do that with interrupts it would be better to be on the safe side. Here is some code for the clock inits:
Code:
From MCU_init:/* ### MC9S08DZ60_64 "Cpu" init code ... */  /*  PE initialization code after reset */  /* Common initialization of the write once registers */  /* SOPT1: COPT=0,STOPE=0,SCI2PS=0,IICPS=0 */  SOPT1 = 0x00;                                        /* SOPT2: COPCLKS=0,COPW=0,ADHTS=0,MCSEL=0 */  SOPT2 = 0x00;                                        /* SPMSC1: LVWF=0,LVWACK=0,LVWIE=0,LVDRE=1,LVDSE=1,LVDE=1,BGBE=0 */  SPMSC1 = 0x1C;                                        /* SPMSC2: LVDV=0,LVWV=0,PPDF=0,PPDACK=0,PPDC=0 */  SPMSC2 = 0x00;                                        /*  System clock initialization */  MCGTRM = *(unsigned char*far)0xFFAF; /* Initialize MCGTRM register from a non volatile memory */  MCGSC = *(unsigned char*far)0xFFAE;  /* Initialize MCGSC register from a non volatile memory */  /* MCGC2: BDIV=1,RANGE=0,HGO=0,LP=0,EREFS=0,ERCLKEN=0,EREFSTEN=0 */  MCGC2 = 0x40;                        /* Set MCGC2 register */  /* MCGC1: CLKS=0,RDIV=0,IREFS=1,IRCLKEN=0,IREFSTEN=0 */  MCGC1 = 0x04;                        /* Set MCGC1 register */  /* MCGC3: LOLIE=0,PLLS=0,CME=0,VDIV=1 */  MCGC3 = 0x01;                        /* Set MCGC3 register */  while(!MCGSC_LOCK) {                 /* Wait until FLL is locked */  }/* FCDIV: DIVLD=0,PRDIV8=0,DIV5=0,DIV4=0,DIV3=1,DIV2=0,DIV1=0,DIV0=0 */  FCDIV = 0x08;                        /* Set clock divider */From main.c;    /*  System clock initialization */    ;    MCGTRM = *(unsigned char*)0xFFAF;    /* Initialize MCGTRM register from a non volatile memory */            LDA   $FFAF ;65455            STA   MCGTRM    ;    MCGSC = *(unsigned char*)0xFFAE;     /* Initialize MCGSC register from a non volatile memory */            LDA   $FFAE ;65454            STA   MCGSC    ;    /* MCGC2: BDIV=1,RANGE=1,HGO=1,LP=0,EREFS=1,ERCLKEN=1,EREFSTEN=0 */    ;    setReg8(MCGC2, 0x36);                /* Set MCGC2 register */             MOV   #$36,MCGC2    ;    /* MCGC1: CLKS=2,RDIV=7,IREFS=0,IRCLKEN=1,IREFSTEN=0 */    ;    setReg8(MCGC1, 0xBA);                /* Set MCGC1 register */             MOV   #$B2,MCGC1    ;    /* MCGC3: LOLIE=0,PLLS=0,CME=0,—–=0,VDIV=1 */    ;    setReg8(MCGC3, 0x01);                /* Set MCGC3 register */             MOV   #1,MCGC3

 



Message Edited by bdayberr on 2008-02-24 04:43 PM

Message Edited by bdayberr on 2008-02-24 04:44 PM

Message Edited by bdayberr on 2008-02-24 04:45 PM
0 项奖励
回复

2,390 次查看
allawtterb
Contributor IV
I use code similar to what Jim posted above most of the time which doesn't use any disable interrupts for programming EEPROM.  In fact you might want to make sure that interrupts are enabled unless you can allow a 20ms delay while you are waiting for a EEPROM sector to be erased.
0 项奖励
回复

2,391 次查看
bdayberr
Contributor I
I noticed in your code you have a Pause(4), is that what you are talking about for the 20ms delay? So far without programming in any delays, and with the disints and enints removed, everything works fine.
0 项奖励
回复

2,391 次查看
allawtterb
Contributor IV


bdayberr wrote:
I noticed in your code you have a Pause(4), is that what you are talking about for the 20ms delay?


Actually that code posted a while ago on the forums was when I was just trying to get the EEPROM to work correctly.  The pause was there because the DZ data sheet asks for at least 4 bus cycles before clearing FSTAT_FCBEF.  The 20ms I was referring to is from the table 4-6- in the DZ data sheet, specificing how long a EEPROM/Flash erase/program takes.  There are the times you will see:
 
  1. Byte Program - 45us
  2. Burst Program - 20us (only avaiable for Flash programming)
  3. Sector erase - 20ms
  4. Mass erase - 100ms
  5. Sector erase abort - 20us
 
 The code I now use is:
Code:
#define EEPROM_ACCESS(x) *(uint8_t *)(x + EEPROM_BASE)....void EEPROM_Write_Byte( uint16_t address, uint8_t data)/* Writes a byte of data to the EEPROM address passed to it */{  if (FSTAT_FACCERR)        // If EEPROM access error flag is set   FSTAT_FACCERR = 1;       // Then clear it     while(!FSTAT_FCBEF);      // Make sure command buffer is empty    EEPROM_ACCESS(address) = data;        // Write the data  FCMD = BYTE_PROGRAM;      // Flash/EEPROM command to program a byte (0x20)    _asm NOP;                 // Wait at least 4 cycles before clearing FSTAT_FCBEF  _asm NOP;                      FSTAT = 0x80;             // Clear command buffer empty flag   if (FSTAT_FACCERR)        // If EEPROM access error flag is set   FSTAT_FACCERR = 1;       // Then clear it     if (FSTAT_FPVIOL)         // If EEPROM write error flag is set    FSTAT_FPVIOL = 1;       // Then clear it                                     while (!FSTAT_FCCF);      // Wait for all commands to complete}



0 项奖励
回复

2,391 次查看
anunalge
Contributor I
I am using DZ128 micro.I am programming EEPROM for storing data.What ever the timings u mentioned are common for both Flash and EEPROM.But the sector size is different for both,is there any change in timings for EEPROM with respect to size.
0 项奖励
回复

2,391 次查看
allawtterb
Contributor IV


anunalge wrote:
I am using DZ128 micro.I am programming EEPROM for storing data.What ever the timings u mentioned are common for both Flash and EEPROM.But the sector size is different for both,is there any change in timings for EEPROM with respect to size.



No, there are no changes in timing for different sector sizes.  Are you sure that you will be using a DZ128?  I don't know what the status is of this part, you might want to double check that the DZ128 is still going to be released at some point in time.
0 项奖励
回复

2,391 次查看
anunalge
Contributor I
yes it is DZ128 only.I have the softec EVB with me.Sector size is 512 for flash and 4 bytes for EEPROM,so u mean for erasing 4 bytes of EEPROM it will take 20ms.
0 项奖励
回复

2,391 次查看
allawtterb
Contributor IV


anunalge wrote:
yes it is DZ128 only.I have the softec EVB with me.Sector size is 512 for flash and 4 bytes for EEPROM,so u mean for erasing 4 bytes of EEPROM it will take 20ms.


Yes, it will take the same amount of time for both.  The 20ms is based on a FCLK of 200kHz, the allowed range for FCLK is from 150khz to 200kHz.  The table for erase/program times is in the DZ data sheet, section 4.5.2. 
 
Do you know if the EVB for the DZ128 can be found anywhere on their website? 
0 项奖励
回复

2,391 次查看
anunalge
Contributor I
Thank you for the information.DZ128 is not avilable on net.
0 项奖励
回复

2,391 次查看
allawtterb
Contributor IV
Instead of having a function to read data from EEPROM it would be easier to just use a #define like this:
Code:
#define READ_EEPROM_BYTE(x) *(byte *)(x) #define READ_EEPROM_WORD(x) *(word *)(x)   

 
0 项奖励
回复

2,391 次查看
JimDon
Senior Contributor III
Great Job!!!!

I do have my own comments.

You did sets the clocks, right? Post that code too for completeness.

It was my understanding that you did NOT need to disable interrupts for EEPROM programming.
(You need to for Flash programming, because the vectors can't be read while the flash module is busy, but this is not the case with EEPROM)
Is this incorrect ??

If you do need to disable interrupts:

Also, consider this - if interrupts were disabled before calling this, it will return with the interrupts enabled, which may be unexpected by the callers. The solution is to save the IM state, set it,  and restore to it's previous state.
(check out the TPA instruction or BMS instruction).



Message Edited by JimDon on 2008-02-24 11:24 AM
0 项奖励
回复

2,391 次查看
bdayberr
Contributor I
That makes sense to me. Can I see what the Program_Byte function looks like?
0 项奖励
回复