;###################################################################### ; i2clib.inc - I2C LIBRARY - IMPLEMENTATION ; ; See i2clib.asm for documentation of the interface to this file. include /usr/share/gputils/header/p18f458.inc radix dec include ../iwjpictest/insn-aliases.inc include ../iwjpictest/clockvaries.inc include panic.inc include morse+auto.inc include i2clib.incm ;====================================================================== ; NOTATION ; Naming conventions ; ; m_... routines used by master only ; s_... routines used by slave only ; routines used by both ; ; [ms]_event_... event handler, branched to from interrupt ; handler; conditions are as in the name; ; should `return' at end which will return ; from i2c[ms]_interrupt ; ; [sm]_event_bad[_...] event handler which panics; called when i2c ; controller did something unexpected ; ; m_improper_... panics; called when main program ; does something wrong ; ; [ms]_ routines or labels of some other kind ; Whenever flow does not pass past the end of some code, we ; have a boundary `;----------', and when flow passes past ; an important label we sometimes mark it specially with `;...', ; like this: ; ; ;---------- ; m_event_spong ; bt_f_if0 st, st_something ; bra m_event_bad ; ;... ; ; m_event_several_including_spong ; bs_f st, st_sponging ; bra metasyntacticing ; ; ;---------- ; m_event_wombat ;============================================================ ; COMMON ADMINISTRATIVE ROUTINES and VARIABLES udata_acs sspstat res 1 ; master only sspcon1 res 1 ; master only sspcon2 res 1 ; master only slave res 1 ; master only slave_next res 1 ; master only st res 1 st_orig res 1 ; st is a bitmask, bit set in visible states: ; master st_starting equ 7 ; Writing-Setup?, Reading-Busy? st_addressing equ 6 ; Writing-Setup?, Reading-Busy? st_writing equ 5 ; Writing-*, Stopping(after Reading-Wait:write_start) st_subsequent equ 4 ; Writing? st_reading equ 3 ; Reading-* st_awaiting equ 2 ; Reading-Wait st_acking equ 1 ; Reading-Busy?, Stopping(from read) st_stopping equ 0 ; Stopping ; ...? means not always set in that state code ;---------- slave2addr ; computes slave address in form suitable for use in i2c controller ; actual i2c slave address is (slave number) + 0b0001000 ; W slave number i2c address * 2 add_lw b'0001000' rlc_w return ;---------- improper_read_done_data i2cpanic morse_SD ;====================================================================== ; MASTER ;---------- i2cm_init mov_lw i2c_sspadd mov_wf SSPADD clr_f st clr_f slave_next mov_lw 0x08 ; !SSPEN, Master mode mov_wf SSPCON1 clr_f SSPCON2 ; nothing going mov_lw 0x80 ; SMP(noslew), !CKE(!smbus) mov_wf SSPSTAT bc_f IPR1, SSPIP ; low priority bra init_enable ;---------- i2cm_interrupt bt_f_if0 PIR1, SSPIF return ; We have an interrupt: ;... i2cm_interrupt_definite mov_ff SSPSTAT, sspstat mov_ff SSPCON1, sspcon1 mov_ff SSPCON2, sspcon2 bc_f PIR1, SSPIF mov_lw (1< 0 (disabled) 1 (enabled) ; SSPIE 0 (disabled) 1 (enabled) ; SSPIF configured correctly unchanged ; TRISB<1,0> any configured for I2C ; SSPIP any configured correctly ; GIEL 0 (disabled) 0 (disabled) ; ssp* shadows any all bits set set_f sspstat set_f sspcon1 set_f sspcon2 set_f st_orig bs_f TRISC, 3 bs_f TRISC, 4 bs_f SSPCON1, SSPEN bs_f PIE1, SSPIE return ;======================================== ; SLAVE ; ; In general, we figure out our state and then see what kind of events ; we were expecting. Bits we want to check: ; 80 40 20 10 08 04 02 01 ; SMP CKE D_A P S R_W UA BF ; set clr data? stop start read? clr full? ; (we don't usually mention SMP, CKE and UA below) ; ; Labels of the form s_event_* are branches of the interrupt ; handler and are supposed to finish with return. ;---------- ; Macros: chkvals_start and chkval chkvals_start macro chvals_what mov_fw chvals_what endm chkval macro chkval_lastval, chkval_value, chkval_label xor_lw chkval_value ^ chkval_lastval bra_z chkval_label endm near_i2csu code ;---------- s_write_slurpbyte macro ; W any byte from master ; i2c controller waiting due to SEN etc continuing with next byte mov_fw SSPBUF bs_f SSPCON1, CKP endm ;---------------------------------------- i2cs_read_data i2cs_read_data_macro return ;---------------------------------------- ; branches from the ISR ;---------- s_event_addrrecvwrite s_write_slurpbyte goto i2csu_write_begin ;---------- s_event_reading_datanack return ;---------- s_event_writing_datarecv s_write_slurpbyte goto i2csu_write_data ;---------- s_event_bad_intr i2cpanic morse_IH ; unknown high-priority interrupt ;---------------------------------------- i2cs_interrupt ; 4cy interrupt latency + 3cy until branch to here bt_f_if0 PIR1, SSPIF bra s_event_bad_intr ; We have an interrupt: mov_lw (1<