include ../iwjpictest/insn-aliases.inc
;============================================================
-; COMMON ADMINISTRATIVE ROUTINES
+; COMMON ADMINISTRATIVE ROUTINES and VARIABLES
udata_acs
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 0b0001000
+ rlc_w
+ return
+
+
+;======================================================================
+; SLAVE
+
+;----------
i2cs_init
; W slave number undefined
rcall slave2addr2
mov_wf SSPADD
clr_f st
- mov_lw 0x1e ; !SSPEN, CKP(release), I2C 7-bit slave S&P
+ mov_lw 0x16 ; !SSPEN, CKP(release), I2C 7-bit slave no-SP-int
mov_wf SSPCON1
mov_lw 0x01 ; !GCEN, SEN
mov_wf SSPCON2
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
+ mov_fw ssp
+chkval_lastvalue equ 0
+ endm
+
+chkval macro value, label
+ xor_lw value ^ chkval_lastvalue
+ chkval_lastvalue equ value
+ bra_z label
+ endm
+
+chkvals_addrrecv macro
+ chkval 0x8c, s_event_idle_addrrecvread ; A,!P, S,R,!BF
+ chkval 0x89, s_event_idle_addrrecvwrite ; A,!P, S,W,BF
+ endm
+
+;----------
i2cs_interrupt
bt_f_if0 PIR1, SSPIF
return
; Check that nothing obvious is wrong:
mov_fw SSPCON1
mov_wf ssp
- and_lw 0xc0
+ and_lw 0xc0 ; WCOL, SSPOV
bra_nz i2cs_interrupt_wcolsspov_endif
panic morse_SV
i2cs_interrupt_wcolsspov_endif
-; Find out what's just happened:
- mov_ff SSPSTAT, ssp
- ; 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?
-
- mov_fw ssp
-chkval_lastvalue equ 0
-
-chkval macro value, label
- xor_lw value ^ chkval_lastvalue
- chkval_lastvalue equ value
- bra_z label
- endm
-
- chkval 0x89, s_case_addr_recv_write
- chkval 0x8d, s_case_addr_recv_read
- chkval 0xa9, s_case_write_data_recv
-
bt_f_if0 st, st_reading
- bra s_ifnot_reading
+ bra s_event_reading
- ; only check this if we're reading; otherwise
- ; this will be handled by s_case_uninteresting_start
- chkval 0xac, s_case_read_data_sent
- chkval 0xa8, s_case_read_data_nack
+ bt_f_if0 st, st_writing
+ bra s_event_writing
-s_ifnot_reading
+s_event_idle
+ chkvals_start
+ chkvals_addrrecv
-chkvalm macro mask, value, label
- mov_fw ssp
- xor_lw value
- bra_z label
- endm
+ panic morse_SI
- chkvalm 0xdf, 0x90, s_case_something_stop
- chkvalm 0xdb, 0x88, s_case_uninteresting_start
+;========================================
+; SLAVE - READING
- mov_ff ssp, WREG2 ; fixme
- panic morse_SS
+;----------
+s_event_idle_addrrecvread
+ bs_f st, st_reading
+ call i2csu_read_begin
+ bra s_events_read_datasend
;----------
-s_case_something_stop
-s_case_something_start
-s_ensure_idle
- mov_fw st ; were we doing something ?
- bt_f_if1 STATUS,Z
- return
- ; we were, it seems:
+s_event_reading
+ chkvals_start
+ chkval 0xac, s_event_reading_datasent ; D,!P, S,R,!BF
- bc_f SSPCON, 3
+ ; Whatever is happening, we're done reading now !
clr_f st
- ; now we're not (but W still has old st)
+ call i2csu_read_done
- bt_f_if1 WREG, st_writing
- goto i2csu_write_done
+ chkval 0xa8, s_event_reading_datanack ; D,!P, S,!R,!BF
+ ; Or, maybe it was nack and then we were reselected:
+ chkvals_addrrecv
- bt_f_if1 WREG, st_reading
- goto i2csu_read_done
+ panic morse_SR
- mov_wf st ; put it back and then ...
+;----------
+s_event_reading_datasent
+ call i2csu_read_another
+s_events_reading_datasend
+ mov_wf SSPBUF
+ bs_f SSPCON1, CKP
+s_event_reading_datanack
+ return
-s_panic_st_unexpected
- panic morse_ST
+;========================================
+; SLAVE - WRITING
;----------
-s_case_addr_recv_write
- rcall s_ensure_idle
- bs_f SSPCON, 3; we'll need the Stop interrupt
+s_event_idle_addrrecvwrite
+ bs_f SSPCON, 3 ; we'll need the Stop interrupt
bs_f st, st_writing
- ; well, now this is all fine so do carry on:
+ ; well, this is all fine so far, so do carry on:
s_write_slurpbyte
; W any byte from master
return
;----------
-s_case_write_data_recv
- bt_f_if0 st, st_writing
- bra s_panic_st_unexpected
- ; ok, we are writing:
+s_event_writing
+ chkvals_start
+ chkval 0xa9, s_event_writing_datarecv ; D,!P, S,W,BF
- rcall s_write_slurpbyte
-
- bt_f_if1 st, st_subsequent
- goto i2csu_write_another
- ; not subsequent (yet):
-
- bs_f st, st_subsequent
- goto i2csu_write_begin
-
-;----------
-s_case_addr_recv_read
- rcall s_ensure_idle
- bs_f st, st_reading
- call i2csu_read_begin
- bra s_cases_read_data_send
-
-;----------
-s_case_read_data_sent
- call i2csu_read_another
-
-s_cases_read_data_send
- mov_wf SSPBUF
- bs_f SSPCON1, CKP
- return
-
-;----------
-s_case_read_data_nack
- rcall s_ensure_idle
- goto i2csu_read_done
-
-
-s_cases_write_alliswell
-
+ ; Well, we're done writing now in any case
+ clr_f st
+ bc_f SSPCON1, 3 ; no Start and Stop interrupts any more
+ call i2csu_write_done
+ ; Who knows what might have happened. We may have
+ ; missed a number of S and P due to delay between
+ ; clearing SSPIF and SSPM3(s&p-intrs) so we can't be
+ ; too picky.
- bt_f_if1 ssp, I2C_START
- bra si_if_start
+ ; First, the nice cases:
+ chkvals_start
+ chkvals_addrrecv
-si_if_notstart
- ; So it should be stop
+ ; Then random junk:
mov_fw ssp
- and_lw 0xdf ; ?D_A
- xor_lw 0x90 ; SMP, !CKE, P; !S, !R_W, !UA, !BF
- bra_nz si_if_bad
-
-si_if_start
- bt_f_if1 ssp, BF
- bra si_if_bufferfull
-si_if_bufferempty
- bt_f_if1 ssp, R_W ;read?
- bra si_if_bufferempty_reading
-si_if_bufferempty_notreading
- ; So we think this is just a START (which we want to ignore)
- mov_fw ssp
- and_lw 0xdf ; ?D_A
- xor_lw 0x88 ; SMP, !CKE, !P; S, !R_W, !UA, !BF
- bra_nz si_if_bad
-
- ; OK, ignore it
+ and_lw 0xc7 ; ?D_A, ?P; ?S
+ xor_lw 0x80 ; SMP, !CKE, !R_W, !UA, !BF
+ bt_f_if1 STATUS, Z
return
-
-
-
-
-;----------
-s_case_unknown_stop
-s_case_unknown_start
- return
+ panic morse_SW
;----------
-s_case_got_write_addr
-
-
- mov_fw SSPBUF
- and_lw 0xfe
- bra_nz nonzero
-
- mov_wf ssp
-
-
- mov_fw SSPSTAT
- and_lw 0xe7 ; all except P and S
-
- xor_lw 0x80
- ; bits which might sensibly be set
-
-chkval_last equ 0
-chkval macro value, label
- xor_lw value ^ chkval_last
- bra_z label
-chkval_last equ value
- endm
- chkval 0x80 ; addr dunno
-
- mov_lw 0x8
-
-
- bt_f_if0 DATA_ADDRESS, SSPSTAT
- bra data
-
-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 0b0001000
- rlc_w
- return
+s_event_writing_datarecv
+ rcall s_write_slurpbyte
+ bt_f_if1 st, st_subsequent
+ goto i2csu_write_another
+ ; not subsequent (yet):
+ bs_f st, st_subsequent
+ goto i2csu_write_begin
+;======================================================================
include i2clib.inc
end