;----------
m_event_done_addressing
bt_f_if1 sspcon2, ACKSTAT
- bra m_bad_address_ack
+ bra m_no_address_ack
; OK, we got ack.
bc_f st, st_addressing
goto i2cmu_done
;----------
-m_bad_address_ack
- i2cpanic morse_SK
+m_no_address_ack
+ bt_f_if0 st, st_reading
+ bra m_bad_no_address_ack_write
+ clr_f st
+ rcall m_stop
+ goto i2cmu_slave_no_ack
+
+m_bad_no_address_ack_write
+ panic morse_SW
;========================================
; MASTER - WRITING
; // \ ,------------------<---. | |
; // \ | | | |
; VV VV | | |
-; [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| | `._____________________,' |
-; returns Z | | write_start |
-; | |read_done |
-; V V |
+; [Writing-Setup] [Reading-Busy]<----------. | | |
+; | | | | | | |
+; | | | | | | |
+; | slave_no_ack| | | | | |
+; | (1st | | | | | |
+; write_next_byte| byte / |read_got_byte | | | |
+; must return NZ | only)/ | | | | |
+; V / V | | | |
+; ,-->[Writing] / [Reading-Wait] | | | |
+; `-------' \ | / || `.___________,' | | |
+; write_next_byte \ | / || read_another | | |
+; returns NZ | | / || | | |
+; | | / |`.__________________,' | |
+; | | | | read_start | |
+; write_next_byte| | | `._____________________,' |
+; returns Z | | | write_start |
+; | | |read_done |
+; V V V |
; [Stopping] |
; | done |
; `-------------------------------------'
; been finished as requested. The i2c system is now available and
; i2cm_*_start can be called.
;
-; (Note: If this arrangment means that main program ends up needing to
-; keep track of whether the I2C is Idle or not, it would probably be
-; straightforward to enhance the interface to be enhanced to make that
-; unnecessary, since this information is already tracked by i2clib.)
-;
; Beforehand At call
; State Stopping Idle
+;--------------------
+ extern i2cmu_slave_no_ack
+
+; Called to notify that the slave did not acknowledge its address when
+; we attempted to read from it. The i2c system is now clearing down
+; the i2c bus to prepare for another transaction.
+;
+; Beforehand At call
+; State Reading-Busy* Stopping
+;
+; * only Reading-Busy reached by calling read_start;
+; not Reading-Busy due to read_another.
+
;========================================
; MASTER - WRITES (ie, transmission of data to the slave)
cbyte_halted equ 0 ; also set briefly while we decide what to do next
wslave res 1 ; slave we need to write to
-outmsg_targetlen res 1 ;
+outmsg_targetlen res 1 ;
+
+slaves_awaiting res 1 ; no. of slaves without stf_responding
+slavenoack_counter res 2 ; +0=L, +=H
+slavenoack_counter_init equ (i2c_kbitpersec * 100)
+ ; slaves/sec, @ 10clocks/slave
;======================================================================
; HANDLING OF I2C EVENTS
;======================================================================
; PROCESSING OF INCOMING BYTES - CORE AND DETECTION
+;--------------------
+read_first_response
+; on entry on return
+; W received byte preserved
+; b received byte preserved
+; FSR0 any trashed
+; STATUS any trashed
+ bs_f INDF1, stf_responding
+ dec_f_ifnz slaves_awaiting
+ return
+; that's the last slave, excellent
+ mov_lw b'00001001' ; W trashed
+ call serial_addbyte
+ mov_fw b ; W = received byte (again)
+ return
+
;----------------------------------------
i2cmu_read_got_byte
; Beforehand At call
bra read_got_notfirst
; this is a first (head) byte:
+ bt_f_if0 INDF1, stf_responding ; seen this PIC ack already ?
+ rcall read_first_response ; no, we might have to send HELLO
+
bt_f_if0 POSTINC1, stf_detect ; FSR1 -> detbasel
bra read_got_first_reversers
read_got_first_detectors ; b = MdBBdddd
return
bra nextslave_nowrite
+;----------------------------------------
+i2cmu_slave_no_ack
+ mov_lfsr slavetable, 1
+ mov_ff cslot, FSR1L ; FSR1 -> slave's flags
+ bt_f_if1 INDF1, stf_responding
+ bra slavenoack_crashed
+
+ dec_f_ifnz slavenoack_counter
+ return
+ dec_f_ifnz slavenoack_counter+1
+ return
+ panic morse_ST
+
+slavenoack_crashed
+ panic morse_SC
+
;======================================================================
; INITIALISATION
; pretend we've just done us, to start with 1st actual slave
mov_wf cslot
clr_f cbyte
- bs_f cbyte, cbyte_halted ; serial output of `hello' will start us up
+ bs_f cbyte, cbyte_halted
clr_f wslave
+ mov_lw slavenoack_counter_init & 0xff
+ mov_wf slavenoack_counter
+ mov_lw slavenoack_counter_init >> 8
+ mov_wf slavenoack_counter+1
+ clr_f slaves_awaiting
+
mov_lw 2
mov_lfsr slavetable, 0 ; FSR0 -> slavetable
load_tblptr pic2detinfo ; TBLPTR* -> pic2detinfo
tblrd_postinc_fixup ; TABLAT = DSSSSSSS, N (still) = E
bra_nn mascan_init_ifabsent ; E.......
+ inc_f slaves_awaiting
+
mov_ff t, POSTINC0 ; ste_slave = slave
mov_wf u ; u = 1OOOOSSS
and_lw 0x78
add_lw -0xf8 ; W = first - 0xf8 = detbasel
mov_wf POSTINC0 ; detbasel
- clr_f POSTINC0 ; lastd0
- clr_f POSTINC0 ; lastd2
+ mov_lw 0x4f ; W = 01001111 for det., MM 05 B2 B1...
+ bt_f_if0 TABLAT, 7 ; D ? otherwise, rev. board:
+ mov_lw 0x3f ; W = 01111111 for rev., MM zz 01...
+ mov_wf POSTINC0 ; lastd0
+ set_f POSTINC0 ; lastd2
set_f POSTINC0 ; unused
- clr_f POSTINC0 ; lastd1
+ set_f POSTINC0 ; lastd1
mov_fw u ; W = 10000SSS
xor_lw b'10011000' ^ 0x80 ; W = detmsgh
# Messages for i2clib, S*
SM i2clib+panic:st,:sspstat,:sspcon1,:sspcon2 ; m.,i., ctrlr bad state
SS SSPSTAT,SSPCON1 ; s.,i., controller bad state
-SK i2clib+panic:slave ; m. couldn't address slave (no ack)
+SW i2clib+panic:slave ; m.: slave didn't ack addr for write
SN i2clib+panic:slave ; improper slave number
SO i2clib+panic:slave ; improper next slave number
SB i2clib+panic:st ; improper i2cm_{read,write}_start
SF i2clib+panic:st ; improper i2cmu_write_next_byte Z
SA i2clib+panic:st ; improper i2cm_read_another
SD i2clib+panic:st ; impr. i2cm_read_done/i2cs_read_data
+# used in mascan.asm
+SC i2clib+panic:slave ; slave didn't ack read: crashed
+ST i2clib+panic:slave ; slave didn't ack read: didn't start
+SP i2clib+panic:slave ; slave didn't ack read: in panic read
# Messages for slave detection/i2c
DQ FSR2L,::outmsg_end ; previous slave read incomplete
mov_lw ' '
goto serial_write_char
+;----------
+pan_i2cmu_slave_no_ack
+ i2cpanic morse_SP
+
;======================================================================
; SLAVE I2C
call power_polarising_init
call power_fault_init
call watchdog_init
+ call i2c_consider_restartread ; sends hello when all slaves ack'd
return
;----------------------------------------
serialtxbuf_init @
clr_f outmsg_end
clr_f outmsg_begin
- mov_lw b'00001001'
- goto serial_addbyte
+ return
;======================================================================
include final.inc
ste_flags equ 1 ; ** flags (stf_...), see below
ste_detbasel equ 2 ; dk added to 11111bbb to make 0SSSSSSS; ie first-0xf8
ste_lastd0 equ 3 ; d } [o0]* ie every bit is either 0 (for an
-ste_lastd2 equ 4 ; d } previously seen detection data bit
-ste_lastd1 equ 6 ; d } irrelevant bit) or o, meaning the
+ste_lastd2 equ 4 ; d } irrelevant bit) or o, meaning the
+ste_lastd1 equ 6 ; d } previously seen detection data bit
ste_detmsgh equ 7 ; dk 1 001 1 000 being 1 001 Y SSS
; offset^ ^which module(s) use this data:
; G global - for use by any code
; flags in ste_flags:
stf_detect equ 7 ; Gk this is a detectors board
stf_sentinel equ 6 ; Gk sentinel slot at end of table
+stf_responding equ 5 ; G board has ack'd i2c addressing at least once
include final.inc
;----------------------------------------------------------------------
; for i2c at 50kbit/s
-i2c_sspadd equ (mclock/(50*4)) - 1 ; 50kbit/s
+i2c_kbitpersec equ 50
+i2c_sspadd equ (mclock/(i2c_kbitpersec*4)) - 1 ; 50kbit/s
;----------------------------------------------------------------------
; NMRA at 50us per division