by Virgil Stamps converted and optimized for the SX by James Newton
; ee.asm ; LIST P=16C74A, F=INHX8M ; __CONFIG _BODEN_OFF & _CP_OFF & _WDT_OFF & _XT_OSC ; ; include <p16c74a.inc> ;***************************************************************************** ; 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 ;***************************************************************************** PortCTris equ %10010110 SDAOnMask equ %11111101 SDAOffMask equ %00000010 RESET START INIT setb STATUS.RP0 ; bank 1 mov M, #$0F mov !RC, #PortCTris ; rc7= RX rc6= TX rc5=SDO rc4=SDI rc3=SCLK rc1=na rc0=na clrb STATUS.RP0 ; bank 0 clr event ret ;***************************************************************************** ; Program start. Simple poll loop. A good place for breakpoint and testing. ;***************************************************************************** START call INIT ; Initialize Processor Registers setb event.ee_busy ; read block mov W, #0 ; which block mov BLK, W POLL nop snb event.ee_busy ; ee busy? call EE_SERVICE ; service eeprom if needed jmp 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 RC ; EEPROM port SDA equ 1 ; EE data SCL equ 0 ; EE clk block equ $0A0 blk_size equ $050 ; 80 decimal ; VARIABLES defined in low RAM Arbitrary as to where you want to put them event equ $03D ; 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 $03E ; address high byte ADDR1 equ $03F ; address low byte BLK equ $040 ; block number (0-50) BLKC equ $041 ; block counter blkptr equ $042 ; block pointer o_data equ $043 ; output data i_data equ $044 ; input data ee_cntr4 equ $045 ; temp counter ee_cntr3 equ $046 ; temp counter ee_cntr2 equ $047 ; temp counter ee_cntr1 equ $048 ; temp counter X_DELAY equ $04B ; delay counter MS DELAY equ $04C ; 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 sb event.ee_busy ; busy? ret ; no call EEPRMSVC ; service eeprom sb event.ee_busy jmp EE_SERVICE mov W, #10 call X_DELAY500 jmp EE_SERVICE ; if yes EEPRMSVC snb event.ee_write ; write to ee? jmp write_block ; if yes jmp read_block ; no, read a block write_block snb event.ee_blk_op ; writing a block now? jmp write_busy ; if yes setb event.ee_blk_op ; no, signal writing a block call set_addr mov W, #block mov blkptr, W ; addr of block buffer mov W, #10 mov ee_cntr4, W ; write 10 groups of 8 bytes each write_busy call low_scl call low_sda mov W, #blk_size/10 mov ee_cntr2, W mov W, blkptr mov FSR, W call w_block decsz ee_cntr4 ; done all groups of 8? jmp poll_ack ; if no clrb event.ee_blk_op ; eeprom block operation done clrb event.ee_write ; eeprom not writing clrb event.ee_busy ; eeprom not busy jmp delay50ms ; return after delay poll_ack mov W, #100 mov ee_cntr3, W ack_loop decsz ee_cntr3 jmp ack_tst jmp err ack_tst call strt mov W, #$0a0 call out_byte call wait snb RC.SDA ; did chip acknowledge? jmp clkit ; if no jmp pulse ; yes, so exit clkit call pulse jmp ack_loop ; poll again err nop ; EEPROM is bad (add your own error recovery) jmp err ; eeprom did not respond in 100 tries w_block call strt ; burst write 8 bytes mov W, #$0a0 call out_byte call ack mov W, ADDR0 ; ms addr call out_byte call ack mov W, ADDR1 ; ls addr call out_byte call ack wrtblk mov W, INDF ; byte to write call out_byte call ack inc FSR inc blkptr mov W, #1 add ADDR1, W ; EEPROM addr low snb C inc ADDR0 ; EEPROM addr high decsz ee_cntr2 jmp wrtblk call stop ret read_block setb event.ee_blk_op ; signal reading a block call set_addr call low_scl call high_sda call high_scl ; idle bus mov W, #block mov FSR, W ; addr of block buffer mov W, #blk_size mov ee_cntr2, W ; bytes to copy call strt mov W, #$0a0 ; write preface call out_byte call ack mov W, ADDR0 ; ms address call out_byte call ack mov W, ADDR1 ; ls address call out_byte call ack call strt mov W, #$0a1 call out_byte ; read preface more_seq call ack call in_byte ; fetch the byte mov W, i_data mov INDF, W ; copied to current block inc FSR ; point to next address in block mov W, #1 add ADDR1, W snb C inc ADDR0 decsz ee_cntr2 ; read all bytes? jmp more_seq call stop clrb event.ee_blk_op ; block read is done clrb event.ee_busy ; ee not busy ret out_byte mov o_data, W ; output 8 bits to eeprom mov W, #8 mov ee_cntr1, W o_loop rl o_data ; msb to carry call low_sda snb C ; is it a 1? call high_sda call pulse decsz ee_cntr1 ; done? jmp o_loop ; no call high_sda ret in_byte mov W, #8 ; input 8 bits from eeprom mov ee_cntr1, W call high_sda i_loop call high_scl ; data valid clrb C snb RC.SDA setb C rl i_data call low_scl call wait decsz ee_cntr1 jmp i_loop ret ack call high_sda ; acknowledge operation snb RC.SDA ; bit low? jmp force0 ; if no jmp pulse ; slave acknowledges force0 call low_sda ; master acknowledges call pulse jmp high_sda ; return as input strt call high_sda call high_scl call low_sda ; strt condition jmp low_scl stop call low_sda call high_scl call high_sda ; stop condition jmp low_scl low_sda call wait setb STATUS.RP0 ; bank 1 mov M, #$0F mov !RC, #PortCTris | SDAOnMask ; rc1=SDA rc0=SCL clrb STATUS.RP0 ; bank 0 clrb RC.SDA jmp wait high_sda call wait setb STATUS.RP0 ; bank 1 mov M, #$0F mov !RC, #PortCTris & SDAOffMask ; rc1=SDA rc0=SCL clrb STATUS.RP0 ; bank 0 setb RC.SDA jmp wait low_scl clrb EE.SCL ; clock line goes low ret high_scl setb EE.SCL ; clock line goes high ret wait nop ; delay for the chip nop nop nop ret pulse call high_scl ; one clock pulse call wait jmp low_scl ; subroutine to compute block address: addr = n * 80 set_addr clr ADDR0 ; assume 1st block clr ADDR1 mov W, BLK mov BLKC, W mov W, BLK sb Z ; zero? jmp next_addr2 ; if n jmp set_done ; if yes next_addr2 clrb C ; set ADDR0 and ADDR1 modulo 80 mov W, #blk_size ; sizeof block add ADDR1, W snb C ; overflow? inc ADDR0 ; if yes decsz BLKC jmp next_addr2 ; if no set_done ret ; a delay routine delay50ms mov W, #100 X_DELAY500 mov X_DELAY, W ; +1 1 cycle X_DELAY500_LOOP call DELAY500 ; step1 wait 500uSec decsz X_DELAY ; step2 1 cycle jmp X_DELAY500_LOOP ; step3 2 cycles ret ; +2 2 cycles DELAY500 mov W, #165 ; +1 1 cycle mov DELAY, W ; +2 1 cycle DELAY500_LOOP decsz DELAY ; step 1 1 cycle jmp DELAY500_LOOP ; step 2 2 cycles ret ; +3 2 cycles END ; End of program