; ****************************************************************************** ; Virtual Peripheral: I2C Subroutines ; ; Length: 133 bytes (total) ; Authors: Chip Gracey, President, Parallax Inc. ; modified by Craig Webb, Consultant to Scenix Semiconductor, Inc. ; Written: 97/03/10 to 98/6/03 ; ;****************************************************************************** ; ;****** Assembler directives ; ; uses: SX28AC, 2 pages of program memory, 8 banks of RAM, high speed osc. ; operating in turbo mode, with 8-level stack & extended option reg. ; DEVICE pins28,pages2,banks8,oschs DEVICE turbo,stackx,optionx ID 'I2C' ;program ID label RESET reset_entry ;set reset/boot address ; ;******************************* Program Variables *************************** ; ; Port Assignment: Bit variables ; scl EQU RA.0 ;I2C clock sda EQU RA.1 ;I2C data I/O ; ; ;****** Register definitions (bank 0) ; org 8 ;start of program registers main = $ ;main bank ; temp ds 1 ;temporary storage byte ds 1 ;temporary UART/I2C shift reg. flags DS 1 ;program flags register ; seq_flag EQU flags.1 ;I2C: R/W mode (if sequential=1) got_ack EQU flags.2 ; if we got ack signal ; org 90H ;bank4 variables I2C EQU $ ;I2C bank ; data DS 1 ;data byte from/for R/W address DS 1 ;byte address count DS 1 ;bit count for R/W delay DS 1 ;timing delay for write cycle byte_count DS 1 ;number of bytes in R/W num_bytes DS 1 ;number of byte to view at once save_addr DS 1 ;backup location for address ; in_bit EQU byte.0 ;bit to receive on I2C out_bit EQU byte.7 ;bit to transmit on I2C ; control_r = 10100001b ;control byte: read E2PROM control_w = 10100000b ;control byte: write E2PROM portsetup_r = 00000110b ;Port A config: read bit portsetup_w = 00000100b ;Port A config: write bit eeprom_size = 128 ;storage space of EEPROM ; t_all = 31 ;bit cycle delay (62=5 usec) ; ; ORG 0h ;Program Start adress ; ;******************************** I2C Subroutines ***************************** ; ; These routines write/read data to/from the 24LCxx EEPROM at a rate of approx. ; 200kHz. For faster* reads (up to 400 kHz max), read, write, start amd stop ; bit cycles and time between each bus access must be individually tailored ; using the CALL Bus_delay:custom entry point with appropriate values in the W ; register - in turbo mode: delay[usec] = 1/xtal[MHz] * (6 + 4 * (W-1)). ; Acknowledge polling is used to reduce delays between successive operations ; where the first of the two is a write operation. In this case, the speed ; is limited by the EEPROM's storage time. ; ;****** Subroutine(s) : Write to I2C EEPROM ; These routines write a byte to the 24LCxxB EEPROM. Before calling this ; subroutine, the address and data registers should be loaded accordingly. The ; sequential mode flag should be clear for normal byte writing operation. ; To write in sequential/page mode, please see application note. ; ; Input variable(s) : data, address, seq_flag ; Output variable(s) : none ; Variable(s) affected : byte, temp, count, delay ; Flag(s) affected : none ; Timing (turbo) : approx. 200 Kbps write rate ; : approx. 10 msec between successive writes ; I2C_write CALL Set_address ;write address to slave :page_mode MOV W,data ;get byte to be sent CALL Write_byte ;Send data byte JB seq_flag,:done ;is this a page write? CALL Send_stop ;no, signal stop condition :done RETP ;leave and fix page bits ; Set_address CALL Send_start ;send start bit MOV W,#control_w ;get write control byte CALL Write_byte ;Write it & use ack polling JNB got_ack,Set_address ; until EEPROM ready MOV W,address ;get EEPROM address pointer CALL Write_byte ; and send it RETP ;leave and fix page bits ; Write_byte MOV byte,W ;store byte to send MOV count,#8 ;set up to write 8 bits :next_bit CALL Write_bit ;write next bit RL byte ;shift over to next bit DJNZ count,:next_bit ;whole byte written yet? CALL Read_bit ;yes, get acknowledge bit SETB got_ack ;assume we got it SNB in_bit ;did we get ack (low=yes)? CLRB got_ack ;if not, flag it ; ; to use the LED as a 'no_ack' signal, the ':toggle_led' line in the interrupt ; section must be commented out, and the next 3 instructions uncommented. ; CLRB led_pin ;default: LED off ; SNB in_bit ;did we get ack (low=yes)? ; SETB led_pin ; if not, flag it with LED ; RETP ;leave and fix page bits ; Write_bit MOVB sda,out_bit ;put tx bit on data line MOV !ra,#portsetup_w ;set Port A up to write JMP :delay1 ;100ns data setup delay :delay1 JMP :delay2 ; (note: 250ns at low power) :delay2 SETB scl ;flip I2C clock to high ; MOV W,#t_high ;get write cycle timing* CALL Bus_delay ;do delay while bus settles CLRB scl ;return I2C clock low MOV !ra,#portsetup_r ;set sda->input in case ack ; MOV W,#t_low ;get clock=low cycle timing* CALL Bus_delay ;allow for clock=low cycle RETP ;leave and fix page bits ; Send_start SETB sda ;pull data line high MOV !ra,#portsetup_w ;setup I2C to write bit JMP :delay1 ;100ns data setup delay :delay1 JMP :delay2 ; (note: 250ns at low power) :delay2 SETB scl ;pull I2C clock high ; MOV W,#t_su_sta ;get setup cycle timing* CALL Bus_delay ;allow start setup time :new CLRB sda ;data line goes high->low ; MOV W,#t_hd_sta ;get start hold cycle timing* CALL Bus_delay ;allow start hold time CLRB scl ;pull I2C clock low ; MOV W,#t_buf ;get bus=free cycle timing* CALL Bus_delay ;pause before next function RETP ;leave and fix page bits ; Send_stop CLRB sda ;pull data line low MOV !ra,#portsetup_w ;setup I2C to write bit JMP :delay1 ;100ns data setup delay :delay1 JMP :delay2 ; (note: 250ns at low power) :delay2 SETB scl ;pull I2C clock high ; MOV W,#t_su_sto ;get setup cycle timing* CALL Bus_delay ;allow stop setup time SETB sda ;data line goes low->high ; MOV W,#t_low ;get stop cycle timing* CALL Bus_delay ;allow start/stop hold time RETP ;leave and fix page bits ; Bus_delay MOV W,#t_all ;get timing for delay loop :custom MOV temp,W ;save it :loop DJNZ temp,:loop ;do delay RETP ;leave and fix page bits ; ;****** Subroutine(s) : Read from I2C EEPROM ; These routines read a byte from a 24LCXXB E2PROM either from a new address ; (random access mode), from the current address in the EEPROM's internal ; address pointer (CALL Read_byte:current), or as a sequential read. In either ; the random access or current address mode, seq_flag should be clear. Please ; refer to the application note on how to access the sequential read mode. ; ; Input variable(s) : address, seq_flag ; Output variable(s) : data ; Variable(s) affected : byte, temp, count, delay ; Flag(s) affected : none ; Timing (turbo) : reads at approx. 200Kbps ; I2C_read CALL Set_address ;write address to slave :current CALL Send_start ;signal start of read MOV W,#control_r ; get read control byte CALL Write_byte ; and send it :sequential MOV count,#8 ;set up for 8 bits CLR byte ;zero result holder :next_bit RL byte ;shift result for next bit CALL Read_bit ;get next bit DJNZ count,:next_bit ;got whole byte yet? MOV data,byte ;yes, store what was read SB seq_flag ;is this a sequential read? :non_seq JMP Send_stop ; no, signal stop & exit CLRB out_bit ; yes, setup acknowledge bit CALL Write_bit ; and send it RETP ;leave and fix page bits ; Read_bit CLRB in_bit ;assume input bit low MOV !ra,#portsetup_r ;set Port A up to read SETB scl ;flip I2C clock to high ; MOV W,#t_high ;get read cycle timing* CALL Bus_delay ;Go do delay SNB sda ;is data line high? SETB in_bit ;yes, switch input bit high CLRB scl ;return I2C clock low ; MOV W,#t_buf ;get bus=free cycle timing* CALL Bus_delay ;Go do delay RETP ;leave and fix page bits ; ; ***** High level functions: Store byte & Erase ; Store_W BANK I2C ;switch to EEPROM bank MOV data,W ;save incoming value CALL I2C_Write ;store it in EEPROM INC address ;move to next address INC byte_count ;adjust # bytes stored MOV W,eeprom_size ;get memory size MOV W,address-W ;are we past end? SNZ ;if not, skip ahead CLR address ;if so, reset it :done RETP ;leave and fix page bits ; Erase_Mem CLR address ;restore address pointer MOV num_bytes,#eeprom_size ;wipe whole mem :wipeloop CLR data ;byte to wipe with=0 ; MOV data,address ;byte to wipe with=addr CALL I2C_write ;wipe EEPROM byte INC address ;move to next address DJNZ num_bytes,:wipeloop ;Erased enough yet? CLR byte_count ;done, reset stored count CLR save_addr ;reset backup address RETP ;leave and fix page bits ; ;************************** End of I2C Subroutines **************************** ; ;***************************** MAIN PROGRAM CODE ****************************** ; ; ORG 100h ; ; Program execution begins here on power-up or after a reset ; reset_entry mov ra,#%1011 ;initialize port RA mov !ra,#%0100 ;Set RA in/out directions CLR FSR ;reset all ram starting at 08h :zero_ram SB FSR.4 ;are we on low half of bank? SETB FSR.3 ;If so, don't touch regs 0-7 CLR IND ;clear using indirect addressing IJNZ FSR,:zero_ram ;repeat until done mov !option,#%11011111 ;disable rtcc interrupt ; ; Main Program Loop ; :loop MOV W,#55 ;example byte CALL Store_W ;Store byte in next I2c address ; ; <program code goes here> ; JMP :loop ;back to main loop ; ;*************** END ;End of program code
file: /Techref/scenix/i2cm_vp.src, 13KB, , updated: 1999/2/20 12:23, local time: 2024/12/2 11:43,
18.97.9.168:LOG IN
|
©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://massmind.org/techref/scenix/i2cm_vp.src"> scenix i2cm_vp</A> |
Did you find what you needed? |
Welcome to massmind.org! |
Welcome to massmind.org! |
.