include ../iwjpictest/clockvaries.inc
include panic.inc
include morse+auto.inc
+ include i2clib.incm
;======================================================================
; NOTATION
return
;========================================
-; SLAVE - INTERRUPT HANDLING
-
+; SLAVE
+;
; 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
+; 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.
-; Some macros:
+;----------
+; Macros: chkvals_start and chkval
chkvals_start macro what
mov_fw what
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
+near_i2csu_section code
;----------
-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<<WCOL) | (1<<SSPOV)
- 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 ; 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 ; 23cy to 1st insn of addrrecvread
-s_event_bad
- i2cpanic morse_SS ; slave, interrupt, controller in bad state
-
-s_event_bad_intr
- i2cpanic morse_IH ; unknown high-priority interrupt
+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
-;========================================
-; SLAVE - READING
+;----------------------------------------
+i2cs_read_data
+ i2cs_read_data_macro
+ return
-;----------
-s_event_idle_addrrecvread
- bs_f st, st_awaiting
- goto i2csu_read_begin ; 26cy until 1st insn of read_begin
+;----------------------------------------
+; branches from the ISR
;----------
-s_event_reading
- bs_f st, st_awaiting ; (probably)
-
- mov_fw SSPSTAT
- xor_lw 0xac ; D,!P, S,R,!BF
- bra_nz s_event_reading_not_another
- goto i2csu_read_another
- ; 24cy until 1st insn of i2csu_read_another
+s_event_addrrecvwrite
+ s_write_slurpbyte
+ goto i2csu_write_begin
;----------
s_event_reading_datanack
return
;----------
-s_event_reading_not_another
- ; Whatever is happening, we're done reading now !
- clr_f st
- call i2csu_read_done
-
- 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
-
-;----------
-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
- return
-
-;========================================
-; SLAVE - WRITING
-
-;----------
-s_event_idle_addrrecvwrite
- bs_f SSPCON1, 3 ; we'll need the Stop interrupt
- bs_f st, st_writing
- ; well, this is all fine so far, so do carry on:
-
-s_write_slurpbyte
-; W any byte from master
-; i2c controller waiting due to SEN etc continuing with next byte
- mov_fw SSPBUF
- bs_f SSPCON1, CKP
- return
+s_event_writing_datarecv
+ s_write_slurpbyte
+ goto i2csu_write_data
;----------
-s_event_writing
- chkvals_start SSPSTAT
- chkval 0, 0xa9, s_event_writing_datarecv ; D,!P, S,W,BF
-
- ; 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.
+s_event_bad_intr
+ i2cpanic morse_IH ; unknown high-priority interrupt
- ; First, the nice cases:
- chkvals_start SSPSTAT
- chkvals_addrrecv 0
+;----------------------------------------
+i2cs_interrupt ; 4cy interrupt latency + 3cy until branch to here
+ bt_f_if0 PIR1, SSPIF
+ bra s_event_bad_intr
+ ; We have an interrupt:
- ; Then random junk:
- mov_fw SSPSTAT
- and_lw 0xc7 ; ?D_A, ?P; ?S
- xor_lw 0x80 ; SMP, !CKE, !R_W, !UA, !BF
+ mov_lw (1<<WCOL) | (1<<SSPOV)
+ and_wfw SSPCON1
bra_nz s_event_bad
- return
-;----------
-s_event_writing_datarecv
- rcall s_write_slurpbyte
-
- bt_f_if1 st, st_subsequent
- goto i2csu_write_another
-
- bs_f st, st_subsequent
- goto i2csu_write_begin
+; Firstly, clear the interrupt flag so that if something else happens
+; while we faff, the interrupt will be regenerated:
+ bc_f PIR1, SSPIF
+ chkvals_start SSPSTAT
+ chkval 0, 0x8c, i2csu_read_begin ;A,!P, S,R,!BF
+ chkval 0x8c,0xac, i2csu_read_another ;D,!P, S,R,!BF
+ chkval 0xac,0x89, s_event_addrrecvwrite ;A,!P, S,W,BF
+ chkval 0x89,0xa9, s_event_writing_datarecv ;D,!P, S,W,BF
+ chkval 0xa9,0xa8, s_event_reading_datanack ;D,!P, S,!R,!BF
+s_event_bad
+ i2cpanic morse_SS
;======================================================================
; [Not-in-use]
; |
; |init
-; v
-; [Idle]<-------------------------.
-; write_begin/ \ |
-; / \read_begin |
-; V V |
-; ,->[Receiving] [Transmit-Wait]<-. |
-; `-----' | | | |
-; write_another | |read_data | |
-; | V | |
-; | [Transmit-Busy] | |
-; | | `------' |
-; | | read_another |
-; | | |
-; | |read_done |
-; write_done| \ |
-; `---------+->---------------------'
+; |
+; V
+; [Idle]
+; |
+; |<----------------------------.
+; + |
+; / \ |
+; / \ |
+; write_begin/ \read_begin |
+; / \ |
+; V V |
+; ,->[Receiving] [Transmit-Wait]<-. |
+; `-----' | | | |
+; write_data | |read_data | |
+; | V | |
+; | [Transmit-Busy] | |
+; | | `------' |
+; | | read_another |
+; | \ |
+; `----------+->---------------------'
;========================================
; SLAVE - WRITES (ie, reception of data from the master)
extern i2csu_write_begin
;
; Called to notify the main program that the master PIC has selected this
-; slave to talk to, for writing. Provides the first byte of data
-; we received from the master PIC.
+; slave to talk to, for writing. There is no data at this stage; when
+; data is received, i2csu_write_data will be called.
;
; Beforehand At call On return
; State Idle Receiving Receiving
-; W data from master any
;--------------------
- extern i2csu_write_another
+ extern i2csu_write_data
;
-; Called to notify the main program that the master PIC has continued
-; by transmitting another byte of data. Provides the byte we received.
+; Called to notify the main program that the master PIC has
+; transmitted a byte of data. Provides the byte we received.
;
; Beforehand At call On return
; State Receiving Receiving Receiving
; W data from master any
-;--------------------
- extern i2csu_write_done
-;
-; Called to notify the main program that the master PIC has stopped
-; transmitting data (ie, finished the i2c conversation).
-;
-; Beforehand At call On return
-; State Receiving Idle
-
;========================================
; SLAVE - READS (ie, transmission of data to 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. The main program should call
+; this slave to talk to, for reading. The main program should invoke
; 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 Transmit-Wait Transmit-Busy Transmit-Busy
; W byte for master any
+;
+; There is also a macro i2cs_read_data_macro
+; in i2clib.incm, which does the same thing.
;--------------------
extern i2csu_read_another
;
; Called to notify the main program that the master PIC has continued
; by asking for another byte of data. The main program should once
-; more call i2cs_read_data.
+; more invoke i2cs_read_data.
;
; Beforehand At call
; State Transmit-Busy Transmit-Wait
-
-;--------------------
- extern i2csu_read_done
-;
-; Called to notify the main program that the master PIC has stopped
-; asking for data (ie, finished receiving).
-;
-; Beforehand At call On return
-; State Transmit-Busy Idle