在編寫AT89S8253片内EEPROM讀寫驅動程式時,要特别注意資料讀寫指令MOVX;
當EECON寄存器的EEMEN位置位時,MOVX通路EEPROM;
當EECON寄存器的EEMEN位清零時,MOVX通路外部RAM;
一般情況下,我們定義的用來寫入EEPROM的資料或儲存EEPROM讀取的資料都用外部RAM;代碼具體分析如下:
C語言頁寫入代碼:
unsigned char W_EEPROM_PAGE(unsigned int paddr, unsigned char *pdat)
{
unsigned char temp;
EECON |= EEMEN;
EECON |= EEMWE;
...
For(temp = 0; temp < 32; temp++)
XBYTE[paddr+temp] = pdat[temp];
...
EECON &= ~EEMEN;
EECON &= ~EEMWE;
}
此代碼邏輯清晰,容易了解,可是編譯器沒有那麼智能;編譯器知道pdat指針指向的資料在外部RAM中,用MOVX指令可以讀取;編譯器也知道paddr表示的是要寫入EEPROM的位址,頁用MOVX指令通路;于是,編譯器就将代碼翻譯成如下彙編指令:
ORL EECON,#08H
ORL EECON,#010H
...
?C0045:
; XBYTE[paddr+temp]= pdat[temp]; //将前31位元組寫入頁寫緩沖區
; SOURCE LINE # 242
MOV DPTR,#pdat?663
MOVX A,@DPTR
MOV R3,A
INC DPTR
MOVX A,@DPTR
MOV R2,A
INC DPTR
MOVX A,@DPTR
MOV R1,A
MOV DPL,R7
MOV DPH,#00H
LCALL?C?CLDOPTR
MOV R6,A
MOV A,R7
MOV R5,A
MOV DPTR,#paddr?662+01H
MOVX A,@DPTR
ADD A,R5
MOV R5,A
MOV DPTR,#paddr?662
MOVX A,@DPTR
ADDC A,#00H
MOV DPL,R5
MOV DPH,A
MOV A,R6
MOVX @DPTR,A
INC R7
MOV A,R7
CJNE A,#01FH,?C0045
...
ANL EECON,#0E7H
紅色部分代碼是讀取pdat數組裡的資料,存入R6中,藍色部分代碼是将R6中的資料寫入paddr表示的EEPROM的位址中去;乍一看,完全符合邏輯,可是MOVX指令的通路目标沒有考慮,在EEPROM使能情況下,MOVX通路的一直是EEPROM,在上面的代碼中,EEPROM始終保持使能狀态,而我們的待寫入資料,是儲存在外部RAM中的,始終沒有被讀取;這樣的代碼,其實是将EEPROM中的某頁資料複制另一頁,而沒有将按照我們的意願将外部RAM中的資料寫入EEPROM;是以,編譯器曲解了我們的C語言代碼。
到目前為止,直接編寫彙編成了唯一可以解決此BUG的方法,于是乎,我們可以修改編譯器彙編好的代碼,在要讀取外部RAM資料時,關閉EEPROM使能,擷取資料,在準備寫入EEPROM時,再打開EEPROM使能;于是乎,我們在頻繁的打開關閉EEPROM使能;于是乎,EEPROM就不正常工作了,寫入失敗;
我們可以參考ATMEL官方給出的例程,編寫彙編代碼;例程中,寫入資料是從寶貴的DATA段擷取的,使用MOV指令就可以輕松得到,不用考慮MOVX通路區域的限制。
至于此,我們隻有拿出32位元組(EEPROM一頁資料大小)寶貴的DATA段空間,用于緩存待寫入資料和讀出資料,才能實作正确的資料讀寫,實作代碼如下:
;定義全局共享資料讀寫緩沖區(32位元組)
RSEG ?DT?AT89S8253_EEPROM_drv
buff: DS 32
RSEG ?C_INITSEG
DB020H
DB020H
DBbuff
DB000H
DB 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H
DB 000H
...
; unsigned char W_EEPROM_PAGE(unsigned int paddr, unsigned char * pdat)
RSEG ?PR?_W_EEPROM_PAGE?AT89S8253_EEPROM_drv
_W_EEPROM_PAGE:
USING0
;将待寫入資料從XDATA段轉儲到DATA段緩沖區
MOV R4, #0H
MOV DPH, R2
MOV DPL, R1
w_p_dat_read:
MOV A,#LOW(buff)
ADD A, R4
MOV R0, A
MOVX A, @DPTR
MOV @R0, A
INC DPTR
INC R4
CJNE R4, #020H, w_p_dat_read
;使能EEPROM
ORL EECON,#018H
;檢查電壓是否達到寫EEPROM要求
MOV A,EECON
ANL A,#02H
MOV r0,A
jzw_p_ERROR
;等待EEPROM狀态轉為閑
w_p_rdy1:
MOV A,EECON
ANL A,#02H
MOV r0,A
jzw_p_rdy1
;打開頁寫緩沖區
ORL EECON,#020H
;向頁寫緩沖區中寫入一頁前31位元組
MOVR4, #0H
MOV DPL,R7
MOV DPH,R6
w_p_buff:
MOVA,#LOW(buff)
ADDA, R4
MOVR0, A
MOVA, @R0
MOVX @DPTR,A
INCDPTR
INCR4
CJNER4, #01FH,w_p_buff
;關閉頁寫緩沖區
ANL EECON,#0DFH
;寫入一頁的最後一個資料,啟動頁寫周期
MOVA,#LOW(buff)
ADDA, R4
MOVR0, A
MOVA, @R0
MOVX @DPTR,A
;等待硬體響應頁寫
w_p_busy:
MOV A,EECON
ANL A,#02H
MOV r5,A
jnzw_p_busy
;等待寫入完成
w_p_rdy2:
MOV A,EECON
ANL A,#02H
MOV r5,A
jzw_p_rdy2
;從DATA緩沖區讀取寫入的最後一個位元組,存于R5中
MOVA, @R0
MOVR5, A
;将寫入EEPROM的最後一個位元組從EEPROM中讀取出來,暫存于累加器A中
MOVX A, @DPTR
;用相減後零标志位來判斷寫入是否正确
SUBBA, R5
JNZw_p_ERROR
;寫入成功,準備傳回1,表示成功
MOV R7,#01H
JMPw_p_complete
;寫入失敗,準備傳回0,表示失敗
w_p_ERROR:
MOVR7, #0H
;頁寫完成,關閉EEPROM使能
w_p_complete:
ANL EECON,#0E7H
; } ; SOURCE LINE # 66
?C0004:
RET
; END OF _W_EEPROM_PAGE
以下為完整代碼,包括位元組讀、位元組寫、頁讀、頁寫四個部分
$NOMOD51
NAME AT89S8253_EEPROM_drv
EA BIT 0A8H.7
EECON DATA 96H ; watchdog and memory control register
EEMEN EQU 00001000B ; EEPROM access enable bit
EEMWE EQU 00010000B ; EEPROM write enable bit
EELD EQU 00100000B ; EEPROM page load enable bit
WRTINH EQU 00000001B ; EEPROM WRTINHbit
RDY EQU 00000010B ; EEPROM RDY/BSYbit
?PR?_R_EEPROM_BYTE?AT89S8253_EEPROM_drv SEGMENT CODE
?XD?_R_EEPROM_BYTE?AT89S8253_EEPROM_drv SEGMENT XDATA OVERLAYABLE
?PR?_R_EEPROM_PAGE?AT89S8253_EEPROM_drv SEGMENT CODE
?XD?_R_EEPROM_PAGE?AT89S8253_EEPROM_drv SEGMENT XDATA OVERLAYABLE
?PR?_W_EEPROM_BYTE?AT89S8253_EEPROM_drv SEGMENT CODE
?XD?_W_EEPROM_BYTE?AT89S8253_EEPROM_drv SEGMENT XDATA OVERLAYABLE
?PR?_W_EEPROM_PAGE?AT89S8253_EEPROM_drv SEGMENT CODE
?XD?_W_EEPROM_PAGE?AT89S8253_EEPROM_drv SEGMENT XDATA OVERLAYABLE
?C_INITSEG SEGMENT CODE
?DT?AT89S8253_EEPROM_drv SEGMENT DATA
PUBLIC buff
PUBLIC _W_EEPROM_PAGE
PUBLIC _W_EEPROM_BYTE
PUBLIC _R_EEPROM_PAGE
PUBLIC _R_EEPROM_BYTE
RSEG ?XD?_W_EEPROM_PAGE?AT89S8253_EEPROM_drv
?_W_EEPROM_PAGE?BYTE:
paddr?345: DS 2
ORG 2
pdat?346: DS 3
RSEG ?XD?_R_EEPROM_BYTE?AT89S8253_EEPROM_drv
?_R_EEPROM_BYTE?BYTE:
addr?040: DS 2
RSEG ?XD?_W_EEPROM_BYTE?AT89S8253_EEPROM_drv
?_W_EEPROM_BYTE?BYTE:
addr?243: DS 2
ORG 2
dat?244: DS 1
RSEG ?XD?_R_EEPROM_PAGE?AT89S8253_EEPROM_drv
?_R_EEPROM_PAGE?BYTE:
paddr?141: DS 2
ORG 2
pdat?142: DS 3
RSEG ?DT?AT89S8253_EEPROM_drv
buff: DS 32
RSEG ?C_INITSEG
DB 020H
DB 020H
DB buff
DB 000H
DB 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H
DB 000H
;
;
;
; unsigned char data buff[32] = {0};
;
;
; unsigned char R_EEPROM_BYTE(unsigned int addr)//讀一位址,傳回所讀值
RSEG ?PR?_R_EEPROM_BYTE?AT89S8253_EEPROM_drv
_R_EEPROM_BYTE:
USING 0
; SOURCE LINE # 21
; MOV DPTR,#addr?040
; MOV A,R6
; MOVX @DPTR,A
; INC DPTR
; MOV A,R7
; MOVX @DPTR,A
; {
; SOURCE LINE # 22
orl EECON, #EEMEN ; enable EEPROM accesses ]
r_b_rdy:
MOV A,EECON
ANL A,#02H
MOV r0,A
jz r_b_rdy
mov DPH, R6
mov DPL, R7
movx A, @dptr ; read EEPROM
xrl EECON, #EEMEN ; disable EEPROM accesses
; SOURCE LINE # 23
MOV R7,A
; }
; SOURCE LINE # 24
?C0001:
RET
; END OF _R_EEPROM_BYTE
;
;
; void R_EEPROM_PAGE(unsigned int paddr, unsigned char * pdat)
RSEG ?PR?_R_EEPROM_PAGE?AT89S8253_EEPROM_drv
_R_EEPROM_PAGE:
; SOURCE LINE # 34
; MOV DPTR,#paddr?141
; MOV A,R6
; MOVX @DPTR,A
; INC DPTR
; MOV A,R7
; MOVX @DPTR,A
; INC DPTR
; MOV A,R3
; MOVX @DPTR,A
; INC DPTR
; MOV A,R2
; MOVX @DPTR,A
; INC DPTR
; MOV A,R1
; MOVX @DPTR,A
; {
orl EECON, #EEMEN
r_p_rdy:
MOV A,EECON
ANL A,#02H
MOV r0,A
jz r_p_rdy
mov r4, #0h
mov DPH, R6
mov DPL, R7
r_p_next:
movx A, @dptr ; read EEPROM
mov r5, A
MOV A,#LOW (buff)
ADD A, R4
MOV R0, A
MOV @R0, AR5
INC DPTR
INC R4
CJNE R4, #020H, r_p_next
ANL EECON,#0F7H
MOV R4, #0H
MOV DPH, R2
MOV DPL, R1
r_p_save:
MOV A,#LOW(buff)
ADD A, R4
MOV R0, A
MOV A, @R0
MOVX @DPTR, A
INC DPTR
INC R4
CJNE R4, #020H, r_p_save
; }
; SOURCE LINE # 37
RET
; END OF _R_EEPROM_PAGE
;
;
; unsigned char W_EEPROM_BYTE(unsigned int addr ,unsigned char dat)
RSEG ?PR?_W_EEPROM_BYTE?AT89S8253_EEPROM_drv
_W_EEPROM_BYTE:
USING 0
; SOURCE LINE # 48
; MOV DPTR,#addr?243
; MOV A,R6
; MOVX @DPTR,A
; INC DPTR
; MOV A,R7
; MOVX @DPTR,A
; INC DPTR
; MOV A,R5
; MOVX @DPTR,A
; {
ORL EECON,#018H
MOV A,EECON
ANL A,#02H
MOV r0,A
jz w_b_ERROR
w_b_rdy1:
MOV A,EECON
ANL A,#02H
MOV r0,A
jz w_b_rdy1
MOV DPL,R7
MOV DPH,R6
MOV A,R5
MOVX @DPTR,A
w_b_busy:
MOV A,EECON
ANL A,#02H
MOV r0,A
jnz w_b_busy
w_b_rdy2:
MOV A,EECON
ANL A,#02H
MOV r0,A
jz w_b_rdy2
MOVX A, @DPTR
SUBB A, R5
JNZ w_b_ERROR
MOV R7,#01H
JMP w_b_complete
w_b_ERROR:
MOV R7, #0H
w_b_complete:
ANL EECON,#0E7H
; }
; SOURCE LINE # 51
?C0003:
RET
; END OF _W_EEPROM_BYTE
;
;
; unsigned char W_EEPROM_PAGE(unsigned int paddr, unsigned char * pdat)
RSEG ?PR?_W_EEPROM_PAGE?AT89S8253_EEPROM_drv
_W_EEPROM_PAGE:
USING 0
; SOURCE LINE # 63
; MOV DPTR,#paddr?345
; MOV A,R6
; MOVX @DPTR,A
; INC DPTR
; MOV A,R7
; MOVX @DPTR,A
; INC DPTR
; MOV A,R3
; MOVX @DPTR,A
; INC DPTR
; MOV A,R2
; MOVX @DPTR,A
; INC DPTR
; MOV A,R1
; MOVX @DPTR,A
; {
MOV R4, #0H
MOV DPH, R2
MOV DPL, R1
w_p_dat_read:
MOV A,#LOW(buff)
ADD A, R4
MOV R0, A
MOVX A, @DPTR
MOV @R0, A
INC DPTR
INC R4
CJNE R4, #020H, w_p_dat_read
ORL EECON,#018H
MOV A,EECON
ANL A,#02H
MOV r0,A
jz w_p_ERROR
w_p_rdy1:
MOV A,EECON
ANL A,#02H
MOV r0,A
jz w_p_rdy1
ORL EECON,#020H
MOV R4, #0H
MOV DPL,R7
MOV DPH,R6
w_p_buff:
MOV A,#LOW(buff)
ADD A, R4
MOV R0, A
MOV A, @R0
MOVX @DPTR,A
INC DPTR
INC R4
CJNE R4, #01FH,w_p_buff
ANL EECON,#0DFH
MOV A,#LOW(buff)
ADD A, R4
MOV R0, A
MOV A, @R0
MOVX @DPTR,A
w_p_busy:
MOV A,EECON
ANL A,#02H
MOV r5,A
jnz w_p_busy
w_p_rdy2:
MOV A,EECON
ANL A,#02H
MOV r5,A
jz w_p_rdy2
MOV A, @R0
MOV R5, A
MOVX A, @DPTR
SUBB A, R5
JNZ w_p_ERROR
MOV R7,#01H
JMP w_p_complete
w_p_ERROR:
MOV R7, #0H
w_p_complete:
ANL EECON,#0E7H
; } ; SOURCE LINE # 66
?C0004:
RET
; END OF _W_EEPROM_PAGE
END