;###################################################################### ; 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 clock equ 0 include ../iwjpictest/clockvaries.inc include panic.inc include morse+auto.inc ;====================================================================== ; 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 sspcon1 res 1 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 slave st_starting equ 7 ; Writing-Setup?,Reading-Busy? st_addressing equ 6 ; Writing-Setup?,Reading-Busy? st_writing equ 5 ; Writing-* [Idle-going-]Receiving st_subsequent equ 4 ; Writing? Receiving st_reading equ 3 ; Reading-* Transmit-* st_awaiting equ 2 ; Reading-Wait Transmit-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 panic 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: 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 TRISB, 0 bs_f TRISB, 1 bs_f SSPCON1, SSPEN bs_f PIE1, SSPIE return ;======================================== ; SLAVE - INTERRUPT HANDLING ; In general, we figure out our state and then see what kind of events ; we were expecting. Bits we want to check: ; 80 60 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) ; Some macros: chkvals_start macro what mov_fw what endm chkval macro lastval, value, label xor_lw value ^ lastval bra_z label endm chkvals_addrrecv macro lastval chkval lastval, 0x8c, s_event_idle_addrrecvread ; A,!P, S,R,!BF chkval 0x8c, 0x89, s_event_idle_addrrecvwrite ; A,!P, S,W,BF endm chkvals_addrrecv_lastval equ 0x89 ;---------- i2cs_interrupt ; 4cy interrupt latency + 3cy until branch to here bt_f_if0 PIR1, SSPIF bra s_event_bad_intr ; We have an interrupt: ; Firstly, clear the interrupt flag so that if something else happens ; while we faff, the interrupt will be regenerated: bc_f PIR1, SSPIF mov_ff st, st_orig mov_lw (1<