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_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_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
rlc_w
return
+;----------
+improper_read_done_data
+ panic morse_SD
+
;======================================================================
; MASTER
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
; expects to return directly to main program (caller)
mov_wf slave
bra_z m_improper_slave
+ bs_f SSPCON2, SEN
+m_start_or_restart
and_lw ~31
bra_nz m_improper_slave
bs_f st, st_starting
- bs_f SSPCON2, SEN
return
;----------
; State Idle Reading-Busy
; W slave number any
tst_f_ifnz st
- bra m_improper_read_start
+ bra m_read_start_busy
bs_f st, st_reading
bra m_start
+;----------
+m_read_start_busy
+ bt_f_if1 st, st_awaiting
+ bra m_read_another
+ panic morse_SR
+
+;----------
+m_read_another
+; Main program would like to address another slave.
+ mov_wf slave_next
+ bra_z m_improper_slave
+ bra m_read_ack
+
;----------
m_event_done_addressing_read
m_event_done_acking_readmore
bc_f st, st_reading
bt_f_if0 st, st_awaiting
- bra m_improper_read_done
+ bra improper_read_done_data
; OK:
bra m_read_ack
bt_f_if1 st, st_reading
bra m_event_done_acking_readmore
- bra m_stop
-
-;----------
-m_improper_read_start
- panic morse_SR
+ mov_fw slave_next
+ bra_z m_stop
+; ok, we want to read another:
+ mov_wf slave
+ bs_f st, st_reading
+ bs_f SSPCON2, RSEN
+ bra m_start_or_restart
;----------
m_improper_read_another
panic morse_SA
-;----------
-m_improper_read_done
- panic morse_SD
-
;======================================================================
; SLAVE
; Some macros:
-chkvals_start_sspstat macro
- mov_fw sspstat
+chkvals_start macro what
+ mov_fw what
endm
chkval macro lastval, value, label
chkvals_addrrecv_lastval equ 0x89
;----------
-i2cs_interrupt
+i2cs_interrupt ; 4cy interrupt latency + 3cy until branch to here
bt_f_if0 PIR1, SSPIF
return
; We have an interrupt:
; while we faff, the interrupt will be regenerated:
bc_f PIR1, SSPIF
- mov_ff SSPSTAT, sspstat
- mov_ff SSPCON1, sspcon1
mov_ff st, st_orig
mov_lw (1<<WCOL) | (1<<SSPOV)
- and_wfw sspcon1
+ and_wfw SSPCON1
bra_nz s_event_bad
+ ; 8cy from entry to here, so total of 15cy
bt_f_if1 st, st_reading
- bra s_event_reading
+ bra s_event_reading ; 18cy to 1st insn of event_reading
bt_f_if1 st, st_writing
bra s_event_writing
s_event_idle
- chkvals_start_sspstat
- chkvals_addrrecv 0
+ chkvals_start SSPSTAT
+ chkvals_addrrecv 0 ; 23cy to 1st insn of addrrecvread
s_event_bad
panic morse_SS ; slave, interrupt, controller in bad state
;----------
s_event_idle_addrrecvread
- bs_f st, st_reading
- call i2csu_read_begin
- bra s_events_reading_datasend
+ bs_f st, st_awaiting
+ goto i2csu_read_begin ; 26cy until 1st insn of read_begin
;----------
s_event_reading
- chkvals_start_sspstat
- chkval 0, 0xac, s_event_reading_datasent ; D,!P, S,R,!BF
+ bs_f st, st_awaiting ; (probably)
-; mov_fw st
-; bra_z nopanic
-; panic morse_Z
-;nopanic
+ chkvals_start SSPSTAT
+ chkval 0, 0xac, i2csu_read_another ; D,!P, S,R,!BF
+ ; 23cy until 1st insn of i2csu_read_another
; Whatever is happening, we're done reading now !
clr_f st
call i2csu_read_done
- chkvals_start_sspstat
+ chkvals_start SSPSTAT
chkval 0, 0xa8, s_event_reading_datanack ; D,!P, S,!R,!BF
; Or, maybe it was nack and then we were reselected:
chkvals_addrrecv 0xa8
bra s_event_bad
;----------
-s_event_reading_datasent
- call i2csu_read_another
-s_events_reading_datasend
+i2cs_read_data
+; W byte for master any
+; State Transmit-Wait Transmit-Busy
mov_wf SSPBUF
bs_f SSPCON1, CKP
+
+ bt_f_if0 st, st_awaiting
+ bra improper_read_done_data
+ bc_f st, st_awaiting
+ bs_f st, st_reading
s_event_reading_datanack
return
;----------
s_event_writing
- chkvals_start_sspstat
+ chkvals_start SSPSTAT
chkval 0, 0xa9, s_event_writing_datarecv ; D,!P, S,W,BF
; Well, we're done writing now in any case
; too picky.
; First, the nice cases:
- chkvals_start_sspstat
+ chkvals_start SSPSTAT
chkvals_addrrecv 0
; Then random junk:
- mov_fw sspstat
+ mov_fw SSPSTAT
and_lw 0xc7 ; ?D_A, ?P; ?S
xor_lw 0x80 ; SMP, !CKE, !R_W, !UA, !BF
bt_f_if1 STATUS, Z
; v
; [Idle]<-----------------------------.
; write_start/ \read_start |
-; / \ |
-; V V |
-; [Writing-Setup] [Reading-Busy]<---------. |
-; | | | |
-; write_next_byte| |read_got_byte | |
-; must return NZ | | | |
-; V V | |
-; ,-->[Writing] [Reading-Wait] | |
-; `-------' \ / `-------------' |
-; write_next_byte \ / read_another |
-; returns NZ | / |
-; | /read_done |
-; write_next_byte| | |
+; / \ ,--------------. |
+; V V V | |
+; [Writing-Setup] [Reading-Busy]<---------. | |
+; | | | | |
+; write_next_byte| |read_got_byte | | |
+; must return NZ | | | | |
+; V V | | |
+; ,-->[Writing] [Reading-Wait] | | |
+; `-------' \ / | `-------------' | |
+; write_next_byte \ / | read_another | |
+; returns NZ | / `._________________,' |
+; | / read_start |
+; write_next_byte| |read_done |
; returns Z | | |
; V V |
; [Stopping] |
; write_begin/ \ |
; / \read_begin |
; V V |
-; ,->[Receiving] [Transmitting]<-. |
-; `-----' | | `------' |
-; write_another | | read_another |
-; | read_done| |
-; write_done| \ |
-; `--------------+->----------------'
+; ,->[Receiving] [Transmit-Wait]<-. |
+; `-----' | | | |
+; write_another | |read_data | |
+; | V | |
+; | [Transmit-Busy] | |
+; | | `------' |
+; | | read_another |
+; | | |
+; | |read_done |
+; write_done| \ |
+; `---------+->---------------------'
;========================================
; SLAVE - WRITES (ie, reception of data from the master)
extern i2csu_read_begin
;
; Called to notify the main program that the master PIC has selected
-; this slave to talk to, for reading, and to obtain the first byte of
-; data that we should transmit to the master.
+; this slave to talk to, for reading. The main program should call
+; i2cs_read_data with first byte of data that we should transmit to
+; the master.
+;
+; Beforehand At call
+; State Idle Transmit-Wait
+
+
+;--------------------
+ extern i2cs_read_data
+; Transmits the byte of data to the master
;
; Beforehand At call On return
-; State Idle Transmitting Transmitting
-; W any data for master
+; State Transmit-Wait Transmit-Busy Transmit-Busy
+; W byte for master any
;--------------------
extern i2csu_read_another
;
; Called to notify the main program that the master PIC has continued
-; by asking for another byte of data. Must provide the byte.
+; by asking for another byte of data. The main program should once
+; more call i2cs_read_data.
;
-; Beforehand At call On return
-; State Transmitting Transmitting Transmitting
-; W any data for master
+; Beforehand At call
+; State Transmit-Busy Transmit-Wait
;--------------------
extern i2csu_read_done
; asking for data (ie, finished receiving).
;
; Beforehand At call On return
-; State Transmitting Idle
+; State Transmit-Busy Idle
# Messages for i2clib, S*
SM i2clib:st,:sspstat,:sspcon1,:sspcon2 ; m.,i., ctrlr bad state
-SS i2clib:st,:sspstat,:sspcon1,:st_orig ; s.,i., controller bad state
+SS i2clib:st,SSPSTAT,SSPCON1,:st_orig ; s.,i., controller bad state
SK i2clib:slave ; m. couldn't address slave (no ack)
SN i2clib:slave ; improper slave number
SW i2clib:st ; improper i2cm_write_start
SF i2clib:st ; improper i2cmu_write_next_byte Z
SR i2clib:st ; improper i2cm_read_start
SA i2clib:st ; improper i2cm_read_another
-SD i2clib:st ; improper i2cm_read_done
+SD i2clib:st ; impr. i2cm_read_done/i2cs_read_data