From: ian Date: Wed, 16 Nov 2005 23:04:02 +0000 (+0000) Subject: i2c finished we think but not yet compiled X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ijackson/git?a=commitdiff_plain;h=423beeac022df2f5530e93f35ddc3f47941a20d0;p=trains.git i2c finished we think but not yet compiled --- diff --git a/detpic/i2clib.asm b/detpic/i2clib.asm index de07695..00196b9 100644 --- a/detpic/i2clib.asm +++ b/detpic/i2clib.asm @@ -7,24 +7,68 @@ radix dec include ../iwjpictest/insn-aliases.inc +;====================================================================== +; NOTATION + +; Naming conventions +; +; m_... routines used by master only +; s_... routines used by slave only +; 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]_ 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 @@ -57,112 +101,243 @@ i2cm_interrupt 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 @@ -171,7 +346,7 @@ i2cs_init ; 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 @@ -189,9 +364,9 @@ ms_init_enable ; 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 @@ -212,7 +387,7 @@ ms_init_enable ; Some macros: chkvals_start_sspstat macro - mov_fw sspstat + mov_fw i2c_sspstat chkval_lastvalue equ 0 endm @@ -233,38 +408,38 @@ i2cs_interrupt 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 @@ -274,7 +449,7 @@ s_event_reading 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 @@ -298,7 +473,7 @@ s_event_reading_datanack ;---------- 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 @@ -314,7 +489,7 @@ s_event_writing 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 @@ -328,7 +503,7 @@ s_event_writing 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 @@ -341,11 +516,11 @@ s_event_writing 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 ;====================================================================== diff --git a/detpic/i2clib.inc b/detpic/i2clib.inc index 8fbb578..9d24229 100644 --- a/detpic/i2clib.inc +++ b/detpic/i2clib.inc @@ -138,6 +138,11 @@ extern i2cmu_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 @@ -319,3 +324,10 @@ extern i2csu_read_done ; State Transmitting Idle ;====================================================================== +; INTERNAL VARIABLES +; +; these are `extern'd only so that the morse machinery can display them + extern i2c_sspstat + extern i2c_sspcon1 + extern i2c_sspcon2 + extern i2c_slave diff --git a/detpic/morse-auto.messages b/detpic/morse-auto.messages index 19faa72..0705bea 100644 --- a/detpic/morse-auto.messages +++ b/detpic/morse-auto.messages @@ -32,38 +32,12 @@ TI4 ; for iwj TI5 ; for iwj # Messages for i2clib, S* -SM st, sspstat, sspcon1, sspcon2 ; master interrupt bad state -SS st, sspstat, sspcon1 ; slave interrupt bad state +SM i2c_st, sspstat, sspcon1, sspcon2 +SS i2c_st, sspstat, sspcon1 SK slave ; m. couldn't address slave (no ack) -SA slave ; improper slave address -SW st ; improper master write start -SF st ; improper master write finish - -# in both - -SS sspstat, sspcon1, - -SV SSPSTAT, ssp, st ; WCOL or SSPOV (ssp = SSPCON1, unusually) - -# in master - - -SM SSPSTAT, SSPCON1, ssp, st ; interrupt with unexpected bits in SSPCON2 - ; (ssp = SSPCON2, unusually) - - -# in slave -SS st, sspstat, sspcon1 - - -SI ssp, SSPCON1 ; bad SSPSTAT when idle -SR ssp, SSPCON1 ; bad SSPSTAT when reading -SW ssp, SSPCON1 ; bad SSPSTAT when writing - - - -SPW st ; write_start when not permitted - - -SA SSPCON2 ; Slave didn't I2C ack address -SD SSPCON2 ; Slave didn't I2C ack data +SN slave ; improper slave number +SW i2c_st ; improper i2cm_write_start +SF i2c_st ; improper i2cmu_write_next_byte Z +SR i2c_st ; improper i2cm_read_start +SA i2c_st ; improper i2cm_read_another +SD i2c_st ; improper i2cm_read_done