| SH79Fxxx Flash use as EEPROM 79Fxxx的flash可以当EEPROM用
 原理:79Fxxx的flash rom是由数个sector组成,每个sector大小为2kB
 如 79F161,有16K rom, 则有8个sector
 可以划分一个sector作为flash eeprom,节省外围的eeprom器件,如24C02
 从而节省成本。
 
 79Fxxx Flash ROM的擦写寿命最少有1万次,若每次只需要保存8个字节,
 可以把整个sector 2k空间划分为256页,每页8个字节,
 当写满256页才进行擦除,这样理论上寿命可以达到128万次,大大提高可靠性能
 
 由于每次写保存到flash rom的地址都不一样,例如采用sector 6
 第一次保存数据是保存到 0x3000~0x3007,第二次写flash后数据则保存到0x3008~0x300f,
 例子中通过二分法算法查询上次保存的那8个数据保存到第几页,以便读出最新写入的数据,或者继续写数据到后续空页处,
 二分法算法大大提高索引效率。
 
 程序提供2个函数,方便对flash读写操作
 void WriteFlash(Byte *ptr)        //ptr is the head pointer of the write buffer
 void ReadFlash(Byte *ptr)        //ptr is the head pointer of the read buffer
 
 注意的地方:
 Flash ROM的第一个sector和最后一个sector不能用作flash eeprom
 因为第一个sector(即程序code区0x0000~0x0fff)包含中断向量入口,
 最后一个sector的最后64个Bytes被硬件屏蔽,
 eg:对于79F161,Sector 1,2,3,4,5,6可以用作flash eeprom,而Sector0和Sector7则不能用作flash eeprom
 
 振荡器频率为8M,写周期为30us(写入一个Byte),擦周期为60ms(擦除整个Sector)
 也可以根据需要使用其它振荡器频率,擦Flash和写Flash周期设置为符合规格书要求即可
 
 具体说明及设置请查看源程序注释
 程序解釋
 SSP實現Flash當EEPROM驅動:
 79Fxxx的flash rom是由数个sector组成,每个sector大小为2kB,79F161有16K rom, 共8个sector
 程序中劃分sector6作为flash eeprom,节省外围的eeprom器件,如24C02,从而节省成本。
 
 Flash ROM的第一个sector和最后一个sector不能用作flash eeprom用途
 因为第一个sector包含中断向量入口,最后一个sector的最后64个Bytes被硬件屏蔽,对于79F161,Sector 1,2,3,4,5,6可以用作flash eeprom,而Sector0和Sector7则不能用作flash eeprom
 #define        SECTOR1         0x0800                        //0800~0fff
 #define        SECTOR2         0x1000                        //1000~17ff
 #define        SECTOR3         0x1800                        //1800~1fff
 #define        SECTOR4         0x2000                        //2000~27ff
 #define        SECTOR5         0x2800                        //2800~2fff
 #define        SECTOR6         0x3000                        //3000~37ff
 #define        SECTOR         SECTOR6                        //劃分SECTOR6作為EEPROM
 79Fxxx Flash ROM的擦写寿命有1萬次,程序中把整个sector 2k空间划分为256页,每页8个字节,当写满256页才进行擦除,这样理论上數據保存可以达到128万次,大大提高壽命及可靠性能
 #define FLASH_PAGE_BYTES                8        //    this value divide exactly by 2048
 #define FLASH_PAGE_COUNT                2048/FLASH_PAGE_BYTES
 //allocate flash eeprom area at ROM sector 6 (C:0x3000~C:0x37ff)
 typedef struct
 {
 Byte        ROM[FLASH_PAGE_BYTES];
 }FLASH_MEMORY;                                                                                                //flash Page datastructure
 FLASH_MEMORY        code        Flash[FLASH_PAGE_COUNT]         _at_        SECTOR;                //flash eeprom datastructure
 
 每次寫數據即寫一個Byte時間必須設定在30us左右,每次擦除即整個Sector清零時間必須設定在60ms左右
 #define                PROGRAM_CLK                (65536 - 30)                                //*** 30us/(8*125ns) = 30us
 #define                ERASE_CLK                        (65536 - 60000)                                //*** 60ms/(8*125ns) = 60000us
 
 每次寫時寫到上次寫的那頁的后一頁,每次讀時返回最新寫的那一頁的數據,由于每次写保存到flash rom的地址都不一样,采用sector 6,第一次保存数据是保存到 0x3000~0x3007,第二次写flash后数据则保存到0x3008~0x300f,通过二分法算法求得上次保存的数据保存到第几页,以便读出最新写入的数据,或者继续写数据到后續的空页处,二分法算法大大提供索引效率。
 
 
 判斷某一頁是否為NULL
 bit        CheckFlashPageNull(Byte index)
 {
 Byte i;
 for(i=0;i<FLASH_PAGE_BYTES;i++)
 {
 if(Flash[index].ROM)
 {
 return 1;
 }
 }
 return 0;
 }
 
 
 二分法求得有效數據的頁索引號,并返回有效數據是否為NULL標記
 bit        GetFlashPageIndex(Byte *index)
 {
 Byte low  = 0;
 Byte high = FLASH_PAGE_COUNT-1;
 Byte mid;
 bit         flag;
 
 while(1)
 {
 mid  = low+(high-low)/2;
 flag = CheckFlashPageNull(mid);
 if(mid == low)
 {
 break;
 }
 if(flag)
 {
 low = mid;
 }
 else
 {
 high = mid;
 }
 }
 if(CheckFlashPageNull(high))
 {
 *index = high;
 return 1;
 }
 else
 {
 *index = low;
 return        flag;
 }
 }
 SSP寫Flash函數
 void        ProgramFlash(Byte pageIndex,Byte *ptr)
 {
 Word        FlashAddr=Flash;
 Byte         i;
 Bit                EA_BAK = EA;
 //---------------------------------------
 for(i=0;i<pageIndex;i++)
 {
 FlashAddr +=FLASH_PAGE_BYTES;
 }
 EA = 0;                                                                //step 1
 IB_CLK1        =        (PROGRAM_CLK>>8)&0xff;        //step 2
 IB_CLK0        =        (PROGRAM_CLK)&0xff;
 for(i=0;i<FLASH_PAGE_BYTES;i++)
 {
 XPAGE          = HIBYTE(FlashAddr);        //step 3
 IB_OFFSET= LOBYTE(FlashAddr);
 IB_DATA         = *(ptr+i);                        //step 4
 IB_CON1         = 0x6E;                                //step 5
 IB_CON2         = 0x05;
 IB_CON3         = 0x0A;
 IB_CON4         = 0x09;
 IB_CON5         = 0x06;
 _nop_();                                                //step 6
 _nop_();
 _nop_();
 _nop_();
 FlashAddr ++;                                        //step 7
 }
 //---------------------------------------
 EA = EA_BAK;
 }
 SSP擦除Flash函數
 void        EraseFlash(void)
 {
 Word        FlashAddr=Flash;
 Bit                EA_BAK = EA;
 //---------------------------------------
 EA = 0;                                                                //step 1
 IB_CLK1         = (ERASE_CLK>>8)&0xff;
 IB_CLK0         = (ERASE_CLK)&0xff;                //step 2
 XPAGE          = HIBYTE(FlashAddr);                //step 3
 IB_OFFSET= LOBYTE(FlashAddr);
 IB_CON1         = 0xE6;                                        //step 4
 IB_CON2         = 0x05;
 IB_CON3         = 0x0A;
 IB_CON4         = 0x09;
 IB_CON5         = 0x06;
 _nop_();                                                        //step 5
 _nop_();
 _nop_();
 _nop_();
 //---------------------------------------
 EA = EA_BAK;
 }
 寫數據
 第1次寫數據時,由于之前從未寫過數據,返回的索引號為0,且該頁為NULL,于是便把數據寫到第0頁。
 第2次寫數據時,返回的索引號為0,該頁非NULL,于是便把數據保存到第1頁
 ….
 第256次寫數據時,返回的頁索引號為0xff,該頁非NULL,先擦除整個SECTOR,再把數據寫到第0頁
 void Driver_WriteFlash(Byte *ptr)
 {
 bit        flag;
 Byte index;
 flag = GetFlashPageIndex(&index);
 if(index == (FLASH_PAGE_COUNT-1))
 {
 EraseFlash();
 index =0;
 }
 else if(flag)
 {
 index ++;
 }
 ProgramFlash(index,ptr);
 }
 讀數據
 根據索引值讀出有效數據,有待后續校驗
 void Driver_ReadFlash(Byte *ptr)
 {
 Byte i;
 Byte index;
 GetFlashPageIndex(&index);
 for(i=0;i<FLASH_PAGE_BYTES;i++)
 {
 *ptr = Flash[index].ROM;
 ptr ++;
 }
 }
 
 |