修改FLASH數據通常需要很長時間,不像RAM那樣可以實時操作。而且擦除、編程或讀取FLASH數據需要遵循相當復雜的時序步驟。N76E003提供方便FALSH編程方式,可以幫助用戶通過IAP方式,重新編程FLASH內容。IAP就是通過軟件實現在線電擦除和編程的方法。
通過設置IAPEN(CHPCON.0受TA保護)使能IAP,並且設置IAPUEN寄存器的相應位,使能需要升級的FLASH區域(CONFIG、LDROM、APROM),用戶將16位操作地址寫入IAPAH和IAPAL,數據寫入IAPFD,命令寫入IAPCN。然后通過設置觸發位IAPGO(IAPTRG.0),去執行IAP。注意:IAPTRG也受TA保護。此時,CPU保持程序計數器,內嵌IAP自動控制內部充電泵提高電壓和信號時序。擦除和編程時間是內部控制的,與工作電壓和頻率無關。通常頁擦除時間是5ms,字節編程時間是 3.5μs。IAP動作完成后,程序計數器繼續運行之后的指令,IAPGO位將自動清零。IAPFF (CHPCON.6)是IAP錯誤標志,可以用來檢查之前IAP操作成功與否。通過這些純軟件的設置,用戶可以很方便對FLASH存儲器進行擦除、編程和校驗。
IAP可以方便用戶更新FLASH內容,不過用戶必須遵循一定規則,以確保IAP正確執行,否則可能引起不確定的結果,甚至損壞器件。此外,下文對於正確執行IAP有很好建議。
(1)沒有IAP操作時,用戶必須清IAPEN (CHPCON.0)位。可以防止系統意外觸發IAP。此外,IAP需要使用內部HIRC振盪器。如果選擇外部時鍾源,禁止IAP將停止內部HIRC,可以達到省電的目的。注:寫IAPEN受TA保護。
(2)當LOCK位(CONFIG0.1) 被激活,IAP讀、寫或擦除仍然有效。
在進行IAP時,如果中斷打開應該臨時清除EA位
擦除或編程的頁不能是當前代碼執行的頁。否則會出現不可預計程序動作,甚至破壞存儲的數據
使用flash存儲器作為數據存儲
在一般應用中,有時需要一些數據在斷電情況下不能丟失,以便用戶讀回或更新,作為系統控制的參數。N76E003支持IAP功能並且存儲在flash中的字節都可以用MOVC指令讀取,所以很適合作為非易失數據存儲器。Flash寫次數為100,000次,以下參考應用代碼:
匯編例程如下:
;******************************************************************************
; This code illustrates how to use IAP to make APROM 201h as a byte of
; Data Flash when user code is executed in APROM.
;******************************************************************************
PAGE_ERASE_AP EQU 00100010b
BYTE_PROGRAM_AP EQU 00100001b
ORG 0000h
MOV TA,#0Aah ;CHPCON is TA protected
MOV TA,#55h
ORL CHPCON,#00000001b ;IAPEN = 1, enable IAP mode
MOV TA,#0Aah ;IAPUEN is TA protected
MOV TA,#55h
ORL IAPUEN,#00000001b ;APUEN = 1, enable APROM update
MOV IAPCN,#PAGE_ERASE_AP ;Erase page 200h~27Fh
MOV IAPAH,#02h
MOV IAPAL,#00h
MOV IAPFD,#0FFh
MOV TA,#0Aah ;IAPTRG is TA protected
MOV TA,#55h
ORL IAPTRG,#00000001b ;write ‘1’ to IAPGO to trigger IAP process
MOV IAPCN,#BYTE_PROGRAM_AP ;Program 201h with 55h
MOV IAPAH,#02h
MOV IAPAL,#01h
MOV IAPFD,#55h
MOV TA,#0Aah
MOV TA,#55h
ORL IAPTRG,#00000001b
MOV TA,#0Aah
MOV TA,#55h
ANL IAPUEN,#11111110b ;APUEN = 0, disable APROM update
MOV TA,#0Aah
MOV TA,#55h
ANL CHPCON,#11111110b ;IAPEN = 0, disable IAP mode
MOV DPTR,#201h
CLR A
MOVC A,@A+DPTR ;Read content of address 201h
MOV P0,A
SJMP $
C 語言例程如下:
//******************************************************************************
// This code illustrates how to use IAP to make APROM 201h as a byte of
// Data Flash when user code is executed in APROM.
//******************************************************************************
#define PAGE_ERASE_AP 0x22
#define BYTE_PROGRAM_AP 0x21
/*Data Flash, as part of APROM, is read by MOVC. Data Flash can be defined as
128-element array in “code” area from absolute address 0x0200 */
volatile unsigned char code Data_Flash[128] _at_ 0x0200;
Main (void)
{
TA = 0xAA; //CHPCON is TA protected
TA = 0x55;
CHPCON |= 0x01; //IAPEN = 1, enable IAP mode
TA = 0xAA; //IAPUEN is TA protected
TA = 0x55;
IAPUEN |= 0x01; //APUEN = 1, enable APROM update
IAPCN = PAGE_ERASE_AP; //Erase page 200h~27Fh
IAPAH = 0x02;
IAPAL = 0x00;
IAPFD = 0xFF;
TA = 0xAA; //IAPTRG is TA protected
TA = 0x55;
IAPTRG |= 0x01; //write ‘1’ to IAPGO to trigger IAP process
IAPCN = BYTE_PROGRAM_AP; // Program 201h with 55h
IAPAH = 0x02;
IAPAL = 0x01;
IAPFD = 0x55;
TA = 0xAA;
TA = 0x55;
IAPTRG |= 0x01; //write ‘1’ to IAPGO to trigger IAP process
TA = 0xAA; //IAPUEN is TA protected
TA = 0x55;
IAPUEN &= ~0x01; //APUEN = 0, disable APROM update
TA = 0xAA; //CHPCON is TA protected
TA = 0x55;
CHPCON &= ~0x01; //IAPEN = 0, disable IAP mode
P0 = Data_Flash[1]; //Read content of address 200h+1
while(1);
}
N76E003 APROM程序DATAFLASH為EEPROM方式
#include <stdio.h> #include "N76E003.h" #include "Common.h" #include "Delay.h" #include "SFR_Macro.h" #include "Function_Define.h" bit BIT_TMP; //------------------------------------------------------------------------- UINT8 read_APROM_BYTE(UINT16 code *u16_addr) { UINT8 rdata; rdata = *u16_addr>>8; return rdata; } //------------------------------------------------------------------------- /***************************************************************************************************************** write_DATAFLASH_BYTE : user can copy all this subroutine into project, then call this function in main. ******************************************************************************************************************/ void write_DATAFLASH_BYTE(UINT16 u16_addr,UINT8 u8_data) { UINT8 looptmp=0,u8_addrl_r; unsigned char code *cd_longaddr; unsigned char xdata *xd_tmp; //Check page start address u8_addrl_r = u16_addr; if (u8_addrl_r<0x80) { u8_addrl_r = 0; } else { u8_addrl_r = 0x80; } //Save APROM data to XRAM xd_tmp = 0x80; cd_longaddr = (u16_addr&0xff00)+u8_addrl_r; while (xd_tmp !=0x100) { *xd_tmp = *cd_longaddr; looptmp++; xd_tmp++; cd_longaddr++; } // Modify customer data in XRAM u8_addrl_r = u16_addr; if (u8_addrl_r<0x80) { xd_tmp = u8_addrl_r+0x80; } else { xd_tmp = u8_addrl_r+0; } *xd_tmp = u8_data; //Erase APROM DATAFLASH page IAPAL = u16_addr; IAPAH = u16_addr>>8; IAPFD = 0xFF; set_IAPEN; set_APUEN; IAPCN = 0x22; set_IAPGO; //Save changed RAM data to APROM DATAFLASH u8_addrl_r = u16_addr; if (u8_addrl_r<0x80) { u8_addrl_r =0; } else { u8_addrl_r = 0x80; } xd_tmp = 0x80; IAPAL = u8_addrl_r; IAPAH = u16_addr>>8; set_IAPEN; set_APUEN; IAPCN = 0x21; while (xd_tmp !=0xFF) { IAPFD = *xd_tmp; set_IAPGO; IAPAL++; xd_tmp++; } clr_APUEN; clr_IAPEN; } /******************************************************************************************************************/ void main (void) { UINT8 datatemp; /* -------------------------------------------------------------------------*/ /* Dataflash use APROM area */ /* APROM 0x3800~0x38FF demo as dataflash */ /* Please use Memory window key in C:0x3800 to check earse result */ /* -------------------------------------------------------------------------*/ //call write byte write_DATAFLASH_BYTE (0x3881,0x55); write_DATAFLASH_BYTE (0x3882,0x56); write_DATAFLASH_BYTE (0x3855,0xaa); write_DATAFLASH_BYTE (0x3856,0x66); //call read byte datatemp = read_APROM_BYTE(0x3882); while(1); }
下面針對每一個調用函數進行講解
void write_DATAFLASH_BYTE(UINT16 u16_addr,UINT8 u8_data) { UINT8 looptmp=0,u8_addrl_r; unsigned char code *cd_longaddr; unsigned char xdata *xd_tmp; //Check page start address u8_addrl_r = u16_addr; if (u8_addrl_r<0x80) { u8_addrl_r = 0; } else { u8_addrl_r = 0x80; } //Save APROM data to XRAM xd_tmp = 0x80; cd_longaddr = (u16_addr&0xff00)+u8_addrl_r; while (xd_tmp !=0x100) { *xd_tmp = *cd_longaddr; looptmp++; xd_tmp++; cd_longaddr++; } // Modify customer data in XRAM u8_addrl_r = u16_addr; if (u8_addrl_r<0x80) { xd_tmp = u8_addrl_r+0x80; } else { xd_tmp = u8_addrl_r+0; } *xd_tmp = u8_data; //Erase APROM DATAFLASH page IAPAL = u16_addr; IAPAH = u16_addr>>8; IAPFD = 0xFF; set_IAPEN; set_APUEN; IAPCN = 0x22; set_IAPGO; //Save changed RAM data to APROM DATAFLASH u8_addrl_r = u16_addr; if (u8_addrl_r<0x80) { u8_addrl_r =0; } else { u8_addrl_r = 0x80; } xd_tmp = 0x80; IAPAL = u8_addrl_r; IAPAH = u16_addr>>8; set_IAPEN; set_APUEN; IAPCN = 0x21; while (xd_tmp !=0xFF) { IAPFD = *xd_tmp; set_IAPGO; IAPAL++; xd_tmp++; } clr_APUEN; clr_IAPEN; }
上面這個函數,是對DATAFLASH EEPROM進行讀寫,有主函數給出地址和數據,由該函數進行處理
void write_DATAFLASH_BYTE(UINT16 u16_addr,UINT8 u8_data) { UINT8 looptmp=0,u8_addrl_r; unsigned char code *cd_longaddr; unsigned char xdata *xd_tmp; //Check page start address u8_addrl_r = u16_addr; if (u8_addrl_r<0x80) { u8_addrl_r = 0; } else { u8_addrl_r = 0x80; } //Save APROM data to XRAM xd_tmp = 0x80; cd_longaddr = (u16_addr&0xff00)+u8_addrl_r; while (xd_tmp !=0x100) { *xd_tmp = *cd_longaddr; looptmp++; xd_tmp++; cd_longaddr++; } // Modify customer data in XRAM u8_addrl_r = u16_addr; if (u8_addrl_r<0x80) { xd_tmp = u8_addrl_r+0x80; } else { xd_tmp = u8_addrl_r+0; } *xd_tmp = u8_data; //Erase APROM DATAFLASH page IAPAL = u16_addr; IAPAH = u16_addr>>8; IAPFD = 0xFF; set_IAPEN; set_APUEN; IAPCN = 0x22; set_IAPGO; //Save changed RAM data to APROM DATAFLASH u8_addrl_r = u16_addr; if (u8_addrl_r<0x80) { u8_addrl_r =0; } else { u8_addrl_r = 0x80; } xd_tmp = 0x80; IAPAL = u8_addrl_r; IAPAH = u16_addr>>8; set_IAPEN; set_APUEN; IAPCN = 0x21; while (xd_tmp !=0xFF) { IAPFD = *xd_tmp; set_IAPGO; IAPAL++; xd_tmp++; } clr_APUEN; clr_IAPEN; }
標紅部分涉及到兩個寄存器IAPL與IAPH,這起什么作用呢?看一下手冊
由此可知,這兩個寄存器是寫入16位地址字節的,也就是說u8_addrl_r這個變量的含義是給寄存器提供地址,因此,需要一些數據的分析和處理,
u8_addrl_r = u16_addr;
if (u8_addrl_r<0x80)
{
u8_addrl_r = 0;
}
else
{
u8_addrl_r = 0x80;
}
//Save APROM data to XRAM
xd_tmp = 0x80;
cd_longaddr = (u16_addr&0xff00)+u8_addrl_r;
while (xd_tmp !=0x100) { *xd_tmp = *cd_longaddr; looptmp++; xd_tmp++; cd_longaddr++; }
Save APROM data to XRAM
首先查看N76E003的數據手冊得知這顆芯片的XRAM的大小為:768字節i ,即大小為0x300,另外還可知道Flash每一頁的大小為128字節即0x80。這段歷程划分區域到0X100(256)。
// Modify customer data in XRAM u8_addrl_r = u16_addr; if (u8_addrl_r<0x80) { xd_tmp = u8_addrl_r+0x80; } else { xd_tmp = u8_addrl_r+0; } *xd_tmp = u8_data; //Erase APROM DATAFLASH page IAPAL = u16_addr; IAPAH = u16_addr>>8; IAPFD = 0xFF; set_IAPEN; set_APUEN; IAPCN = 0x22; set_IAPGO;
Modify customer data in XRAM
在XRAM中修改客戶數據
//Save changed RAM data to APROM DATAFLASH u8_addrl_r = u16_addr; if (u8_addrl_r<0x80) { u8_addrl_r =0; } else { u8_addrl_r = 0x80; } xd_tmp = 0x80; IAPAL = u8_addrl_r; IAPAH = u16_addr>>8; set_IAPEN; set_APUEN; IAPCN = 0x21; while (xd_tmp !=0xFF) { IAPFD = *xd_tmp; set_IAPGO; IAPAL++; xd_tmp++; } clr_APUEN; clr_IAPEN; }
這部分比較復雜,我后續會有更新,如果有什么意見或建議,歡迎評論
知識沒有學完的時候,我只能保證明天的自己跟今天不一樣,各個方面,無論是做人還是做事,無論是專業素質,還是為人處世,待人接物。