radix dec
include ../iwjpictest/insn-aliases.inc
+;======================================================================
+; NOTATION
+
+; Naming conventions
+;
+; m_... routines used by master only
+; s_... routines used by slave only
+; <any other name> 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]_<anything else> 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 i2c_st, st_something
+; bra m_event_bad
+; ;...
+;
+; m_event_several_including_spong
+; bs_f i2c_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
+i2c_sspstat res 1
+i2c_sspcon1 res 1
+i2c_sspcon2 res 1 ; master only
+i2c_slave res 1 ; master only
+
+i2c_st res 1
-st res 1 ; bitmask, bit set in visible states:
+; i2c_st is a bitmask, bit set in visible states:
; master slave
-st_reading equ 0 ; Reading-* Transmitting
-st_writing equ 1 ; Writing-* [Idle-going-]Receiving
-st_subsequent equ 2 ; Writing? Receiving
-;st_working equ 3 ; Writing-*,Reading-Busy,Stopping
-st_starting equ 4 ; Writing-Setup?,Reading-Busy?
-st_addressing equ 4 ; Writing-Setup?,Reading-Busy?
+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-* Transmitting
+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
return
; We have an interrupt:
- mov_ff SSPSTAT, sspstat
- mov_ff SSPCON1, sspcon1
- mov_ff SSPCON2, sspcon2
+ mov_ff SSPSTAT, i2c_sspstat
+ mov_ff SSPCON1, i2c_sspcon1
+ mov_ff SSPCON2, i2c_sspcon2
- bt_f_if1 sspcon1, WCOL
+ bt_f_if1 i2c_sspcon1, WCOL
bra_z m_event_bad
- bt_f_if1 sspcon1, SSPOV
+ bt_f_if1 i2c_sspcon1, SSPOV
bra_z m_event_bad
; No ? Well, then the I2C should be idle now:
- mov_fw sspcon2
+ mov_fw i2c_sspcon2
and_lw ~0x60 ; ACKSTAT,ACKDT
bra_nz m_event_bad
; OK...
- bt_f_if1 sspstat, R_W
+ bt_f_if1 i2c_sspstat, R_W
bra_nz m_event_bad
- bt_f_if1 st, st_starting
+ bt_f_if1 i2c_st, st_stopping
+ bra m_event_done_stopping
+
+ bt_f_if1 i2c_st, st_starting
bra m_event_done_starting
; not just done SEN
- bt_f_if1 st, st_addressing
+ bt_f_if1 i2c_st, st_addressing
bra m_event_done_addressing
+ bt_f_if1 i2c_st, st_writing
+ bra m_event_done_writing
+
+ bt_f_if1 i2c_st, st_acking
+ bra m_event_done_acking
+
+ bt_f_if1 i2c_st, st_reading
+ bra m_event_done_reading
+
m_event_bad
- panic morse_SM
+ panic morse_SM ; master, interrupt, controller in bad state
+
+;========================================
+; MASTER - STARTING, ADDRESSING, STOPPING
+
+;----------
+m_start
+; i2c_st checked for busyness correct
+; st_reading/writing set unchanged
+; st_starting clear set
+; W slave number any
+; i2c_slave any slave_number
+; expects to return directly to main program (caller)
+ mov_wf i2c_slave
+ and_lw 31
+ bra_nz m_improper_slave
+ bs_f i2c_st, st_starting
+ bs_f i2c_st, st_working
+ bs_f SSPCON2, SEN
+ return
;----------
m_event_done_starting
- mov_fw slave
+ mov_fw i2c_slave
bsr slave2addr
- bt_f_if1 st_reading
+ bt_f_if1 i2c_st, st_reading
bs_w 0 ; address bottom bit means read
mov_wf SSPBUF
- bc_f st, st_starting
- bs_f st, st_addressing
+ bc_f i2c_st, st_starting
+ bs_f i2c_st, st_addressing
return
;----------
m_event_done_addressing
- bt_f_if1 sspcon2, ACKSTAT
+ bt_f_if1 i2c_sspcon2, ACKSTAT
bra m_bad_address_ack
; OK, we got ack.
- bc_f st, st_addressing
- bt_f_if1 st, st_reading
+ bc_f i2c_st, st_addressing
+ bt_f_if1 i2c_st, st_reading
bra m_event_done_addressing_read
bra m_event_done_addressing_write
;----------
-m_bad_address_ack
- panic morse_SK
+m_stop
+; st_stopping clear set
+; st_reading/acking/writing any unchanged
+; expects to return directly to main program or to end interrupt handler
+ bs_f i2c_st, st_stopping
+ bs_f SSPCON2, PEN
+ return
+;----------
+m_event_done_stopping
+ clr_f i2c_st
+ goto i2cmu_done
- mov_fw slave
- bsr slave2addr
+;----------
+m_bad_address_ack
+ panic morse_SK
- bt_f_if1 st_reading
- bs_w 0 ; address bottom bit means read
+;----------
+m_improper_slave
+; i2c_slave slave number
+ panic morse_SN
- mov_wf SSPBUF
- bc_f st, st_starting
- bs_f st, st_addressing
- return
+;========================================
+; MASTER - WRITING
;----------
i2cm_write_start
; At call On return
; State Idle Writing-Setup
; W slave number any
- tst_f_ifnz st
+ tst_f_ifnz i2c_st
bra m_improper_write_start
- bs_f st, st_writing
-m_start
- mov_wf slave
- and_lw 31
- bra_nz m_improper_slave
- bs_f st, st_starting
- bs_f st, st_working
- bs_f SSPCON2, SEN
- return
+
+ bs_f i2c_st, st_writing
+ bra m_do_start
;----------
m_event_done_writing
- check for ack ? check this when we bra here
- bs_f st, st_subsequent
+ ; Did slave ack our byte ? It had better have done !
+ bt_f_if1 i2c_sspcon2, ACKSTAT
+ bra m_event_bad
+
+ bs_f i2c_st, st_subsequent
+;...
+
m_event_done_addressing_write
+; ACKSTAT checked
+; st_addressing cleared
call i2cmu_write_next_byte
bra_z m_event_write_mustfinish
+ ; OK, we have the next byte:
- now what ? fixme
+ mov_wf SSPBUF
+ return
;----------
m_event_write_mustfinish
- bt_f_if0 st, st_subsequent
+ bt_f_if0 i2c_st, st_subsequent
bra m_improper_write_finish
- fixme
+ bra m_stop
+
+;----------
+m_improper_write_start
+ panic morse_SW
;----------
m_improper_write_finish
panic morse_SF
+;========================================
+; MASTER - READING
+
+;----------
+i2cm_read_start
+; At call On return
+; State Idle Reading-Busy
+; W slave number any
+ tst_f_ifnz i2c_st
+ bra m_improper_read_start
+
+ bs_f i2c_st, st_reading
+ bra m_do_start
+
+;----------
+m_event_done_addressing_read
+m_event_done_acking_readmore
+; ACKSTAT checked
+; st_addressing/acking cleared
+ bs_f SSPCON2, RCEN
+ return
+
+;----------
+m_event_done_reading
+ bt_f_if0 i2c_sspstat, BF
+ bra m_event_bad
+
+ mov_fw SSPBUF
+
+ bs_f i2c_st, st_awaiting
+ goto i2cmu_read_got_byte
+
+;----------
+i2cm_read_another
+; State Reading-Wait Reading-Busy
+ bt_f_if0 i2c_st, st_awaiting
+ bra m_improper_read_another
+ ; OK, we're fine to read another:
+;...
+
+m_read_ack
+; st_reading 1 iff not done unchanged
+; st_awaiting still set cleared
+; st_acking clear set
+; expects to return directly to main program or to end interrupt handler
+ bc_f i2c_st, st_awaiting
+ bs_f i2c_st, st_acking
+ bc_f SSPCON2, ACKDT ; ACKDT=0 means to acknowledge
+ bs_f SSPCON2, ACKEN
+ return
+
+;----------
+i2cm_read_done
+; State Reading-Wait Stopping
+ bc_f i2c_st, st_reading
+
+ bt_f_if0 i2c_st, st_awaiting
+ bra m_improper_read_done
+ ; OK:
+
+ bra m_read_ack
+
+;----------
+m_event_done_acking
+ bc_f i2c_st, st_acking
+
+ bt_f_if1 i2c_st, st_reading
+ bra m_event_done_acking_readmore
+
+ bra m_stop
+
+;----------
+m_improper_read_start
+ panic morse_SR
+
+;----------
+m_improper_read_another
+ panic morse_SA
+
+;----------
+m_improper_read_done
+ panic morse_SD
+
;======================================================================
; SLAVE
; W slave number undefined
rcall slave2addr2
mov_wf SSPADD
- clr_f st
+ clr_f i2c_st
mov_lw 0x16 ; !SSPEN, CKP(release), I2C 7-bit slave no-SP-int
mov_wf SSPCON1
mov_lw 0x01 ; !GCEN, SEN
; 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 i2c_sspstat
+ set_f i2c_sspcon1
+ set_f i2c_sspcon2
bs_f TRISB, 0
bs_f TRISB, 1
bc_f IPR1, SSPIP
; Some macros:
chkvals_start_sspstat macro
- mov_fw sspstat
+ mov_fw i2c_sspstat
chkval_lastvalue equ 0
endm
return
; We have an interrupt:
- bt_f_if1 sspcon1, WCOL
+ bt_f_if1 i2c_sspcon1, WCOL
bra_z s_event_bad
- bt_f_if1 sspcon1, SSPOV
+ bt_f_if1 i2c_sspcon1, SSPOV
bra_z s_event_bad
; 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 SSPSTAT, sspstat
- mov_ff SSPCON1, sspcon1
+ mov_ff SSPSTAT, i2c_sspstat
+ mov_ff SSPCON1, i2c_sspcon1
; Check that nothing obvious is wrong:
bsr check_wcolsspov
- bt_f_if0 st, st_reading
+ bt_f_if0 i2c_st, st_reading
bra s_event_reading
- bt_f_if0 st, st_writing
+ bt_f_if0 i2c_st, st_writing
bra s_event_writing
s_event_idle
chkvals_start
chkvals_addrrecv
s_event_bad
- panic morse_SS
+ panic morse_SS ; slave, interrupt, controller in bad state
;========================================
; SLAVE - READING
;----------
s_event_idle_addrrecvread
- bs_f st, st_reading
+ bs_f i2c_st, st_reading
call i2csu_read_begin
bra s_events_read_datasend
chkval 0xac, s_event_reading_datasent ; D,!P, S,R,!BF
; Whatever is happening, we're done reading now !
- clr_f st
+ clr_f i2c_st
call i2csu_read_done
chkval 0xa8, s_event_reading_datanack ; D,!P, S,!R,!BF
;----------
s_event_idle_addrrecvwrite
bs_f SSPCON, 3 ; we'll need the Stop interrupt
- bs_f st, st_writing
+ bs_f i2c_st, st_writing
; well, this is all fine so far, so do carry on:
s_write_slurpbyte
chkval 0xa9, s_event_writing_datarecv ; D,!P, S,W,BF
; Well, we're done writing now in any case
- clr_f st
+ clr_f i2c_st
bc_f SSPCON1, 3 ; no Start and Stop interrupts any more
call i2csu_write_done
chkvals_addrrecv
; Then random junk:
- mov_fw sspstat
+ mov_fw i2c_sspstat
and_lw 0xc7 ; ?D_A, ?P; ?S
xor_lw 0x80 ; SMP, !CKE, !R_W, !UA, !BF
bt_f_if1 STATUS, Z
s_event_writing_datarecv
rcall s_write_slurpbyte
- bt_f_if1 st, st_subsequent
+ bt_f_if1 i2c_st, st_subsequent
goto i2csu_write_another
; not subsequent (yet):
- bs_f st, st_subsequent
+ bs_f i2c_st, st_subsequent
goto i2csu_write_begin
;======================================================================