; ee.asm LIST P=16C74A, F=INHX8M __CONFIG _BODEN_OFF & _CP_OFF & _WDT_OFF & _XT_OSC include ;***************************************************************************** ; This application written by Virgil Stamps, 6-12-99 ; I had an application that needed configuration files for various modes of operation. ; A 24C32 I2C EEPROM provides 4Kx8 non-volatile storage. A PIC 16C74 is the processor. ; "Creating electronic products for fun and profit." This code is given ; to the public domain. If you need help, email author at stamps@brokersys.com ;***************************************************************************** RESET_V EQU 0x0000 ; Address of RESET Vector ISR_V EQU 0x0004 ; Address of Interrupt Vector ORG RESET_V ; RESET vector location RESET GOTO START ORG ISR_V ; Interrupt vector location nop ; interrupt service would be here retfie INIT bsf STATUS,RP0 ; bank 1 movlw b'10010110' movwf TRISC ; rc7= RX rc6= TX rc5=SDO rc4=SDI rc3=SCLK rc1=na rc0=na BCF STATUS, RP0 ; bank 0 clrf event return ;***************************************************************************** ; Program start. Simple poll loop. A good place for breakpoint and testing. ;***************************************************************************** START CALL INIT ; Initialize Processor Registers bsf event,ee_busy ; read block movlw .0 ; which block movwf BLK POLL nop btfsc event,ee_busy ; ee busy? call EE_SERVICE ; service eeprom if needed GOTO POLL ; Driver for Microchip 24C32A Serial EEPROM (32K-bit). ; Generic program listing for those seeking information on programming this type EEPROM. ; Approximately 30 ms to read and 80 ms to write a block of 80 bytes. ; The EEPROM is organized as virtual memory accessed by a block number ; and temporarily stored in RAM at BLOCK (0x0A0 - 0x0EF) ; A 32K-bit device has a maximum of 51 blocks. 4,096 bytes / 80 = 51.2 blocks ; A virtual memory location in your application could be defined as BLK (0-50) ; and a offset (0-79). EE equ PORTC ; EEPROM port SDA equ 1 ; EE data SCL equ 0 ; EE clk block equ 0x0A0 blk_size equ 0x050 ; 80 decimal ; VARIABLES defined in low RAM Arbitrary as to where you want to put them event equ 0x03D ; event register where: ee_busy EQU 2 ; service requested 1=busy, 0=idle ee_write EQU 1 ; 1=write, 0=read ee_blk_op EQU 0 ; 1=read or write block operation, 0=idle ADDR0 equ 0x03E ; address high byte ADDR1 equ 0x03F ; address low byte BLK equ 0x040 ; block number (0-50) BLKC equ 0x041 ; block counter blkptr equ 0x042 ; block pointer o_data equ 0x043 ; output data i_data equ 0x044 ; input data ee_cntr4 equ 0x045 ; temp counter ee_cntr3 equ 0x046 ; temp counter ee_cntr2 equ 0x047 ; temp counter ee_cntr1 equ 0x048 ; temp counter X_DELAY equ 0x04B ; delay counter MS DELAY equ 0x04C ; delay counter LS ;***************************************************************************** ; This application burst mode writes 10 groups of 8-bytes each. ; The read function block reads 80-bytes in a loop. ; To write the 80 bytes at block, set BLK= block number in EEPROM, set event,ee_busy, ; set event,ee_write, call EE_SERVICE. ; To read 80 bytes to block from EEPROM, set BLK= block number in EEPROM, ; set event,ee_busy, clear event,ee_write, call EE_SERVICE. ; on return: event,ee_busy is zero, event,ee_block is zero. ;***************************************************************************** EE_SERVICE btfss event,ee_busy ; busy? return ; no call EEPRMSVC ; service eeprom btfss event,ee_busy goto EE_SERVICE movlw .10 call X_DELAY500 goto EE_SERVICE ; if yes EEPRMSVC btfsc event,ee_write ; write to ee? goto write_block ; if yes goto read_block ; no, read a block write_block btfsc event,ee_blk_op ; writing a block now? goto write_busy ; if yes bsf event,ee_blk_op ; no, signal writing a block call set_addr movlw block movwf blkptr ; addr of block buffer movlw .10 movwf ee_cntr4 ; write 10 groups of 8 bytes each write_busy call low_scl call low_sda movlw blk_size/.10 movwf ee_cntr2 movf blkptr,w movwf FSR call w_block decfsz ee_cntr4 ; done all groups of 8? goto poll_ack ; if no bcf event,ee_blk_op ; eeprom block operation done bcf event,ee_write ; eeprom not writing bcf event,ee_busy ; eeprom not busy goto delay50ms ; return after delay poll_ack movlw .100 movwf ee_cntr3 ack_loop decfsz ee_cntr3 goto ack_tst goto err ack_tst call strt movlw 0x0a0 call out_byte call wait btfsc PORTC,SDA ; did chip acknowledge? goto clkit ; if no goto pulse ; yes, so exit clkit call pulse goto ack_loop ; poll again err nop ; EEPROM is bad (add your own error recovery) goto err ; eeprom did not respond in 100 tries w_block call strt ; burst write 8 bytes movlw 0x0a0 call out_byte call ack movf ADDR0,w ; ms addr call out_byte call ack movf ADDR1,w ; ls addr call out_byte call ack wrtblk movf INDF,w ; byte to write call out_byte call ack incf FSR incf blkptr movlw .1 addwf ADDR1 ; EEPROM addr low btfsc STATUS,C incf ADDR0 ; EEPROM addr high decfsz ee_cntr2 goto wrtblk call stop return read_block bsf event,ee_blk_op ; signal reading a block call set_addr call low_scl call high_sda call high_scl ; idle bus movlw block movwf FSR ; addr of block buffer movlw blk_size movwf ee_cntr2 ; bytes to copy call strt movlw 0x0a0 ; write preface call out_byte call ack movf ADDR0,w ; ms address call out_byte call ack movf ADDR1,w ; ls address call out_byte call ack call strt movlw 0x0a1 call out_byte ; read preface more_seq call ack call in_byte ; fetch the byte movf i_data,w movwf INDF ; copied to current block incf FSR ; point to next address in block movlw .1 addwf ADDR1 btfsc STATUS,C incf ADDR0 decfsz ee_cntr2 ; read all bytes? goto more_seq call stop bcf event,ee_blk_op ; block read is done bcf event,ee_busy ; ee not busy return out_byte movwf o_data ; output 8 bits to eeprom movlw .8 movwf ee_cntr1 o_loop rlf o_data ; msb to carry call low_sda btfsc STATUS,C ; is it a 1? call high_sda call pulse decfsz ee_cntr1 ; done? goto o_loop ; no call high_sda return in_byte movlw .8 ; input 8 bits from eeprom movwf ee_cntr1 call high_sda i_loop call high_scl ; data valid bcf STATUS,C btfsc PORTC,SDA bsf STATUS,C rlf i_data call low_scl call wait decfsz ee_cntr1 goto i_loop return ack call high_sda ; acknowledge operation btfsc PORTC,SDA ; bit low? goto force0 ; if no goto pulse ; slave acknowledges force0 call low_sda ; master acknowledges call pulse goto high_sda ; return as input strt call high_sda call high_scl call low_sda ; strt condition goto low_scl stop call low_sda call high_scl call high_sda ; stop condition goto low_scl low_sda call wait BSF STATUS, RP0 ; bank 1 bcf TRISC,SDA ; output bcf STATUS, RP0 ; bank 0 bcf PORTC,SDA goto wait high_sda call wait BSF STATUS, RP0 ; bank 1 bsf TRISC,SDA ; input bcf STATUS, RP0 ; bank 0 bsf PORTC,SDA goto wait low_scl bcf EE,SCL ; clock line goes low return high_scl bsf EE,SCL ; clock line goes high return wait nop ; delay for the chip nop nop nop return pulse call high_scl ; one clock pulse call wait goto low_scl ; subroutine to compute block address: addr = n * 80 set_addr clrf ADDR0 ; assume 1st block clrf ADDR1 movf BLK,w movwf BLKC movf BLK,w btfss STATUS,Z ; zero? goto next_addr2 ; if n goto set_done ; if yes next_addr2 bcf STATUS,C ; set ADDR0 and ADDR1 modulo 80 movlw blk_size ; sizeof block addwf ADDR1,f btfsc STATUS,C ; overflow? incf ADDR0 ; if yes decfsz BLKC goto next_addr2 ; if no set_done return ; a delay routine delay50ms movlw .100 X_DELAY500 MOVWF X_DELAY ; +1 1 cycle X_DELAY500_LOOP CALL DELAY500 ; step1 wait 500uSec DECFSZ X_DELAY, F ; step2 1 cycle GOTO X_DELAY500_LOOP ; step3 2 cycles RETURN ; +2 2 cycles DELAY500 MOVLW D'165' ; +1 1 cycle MOVWF DELAY ; +2 1 cycle DELAY500_LOOP DECFSZ DELAY, F ; step 1 1 cycle GOTO DELAY500_LOOP ; step 2 2 cycles RETURN ; +3 2 cycles END ; End of program