;###################################################################### ; i2clib.inc - I2C LIBRARY - DECLARATIONS AND DOCUMENTATION ; ; ;============================================================ ; GENERAL INFORMATION ; ; Naming scheme: ; i2cm_... on master or i2cmu_... for upcalls ; i2cs_... on slave or i2csu_... for upcalls ; ie, ; i2c?_... are for use by the rest of the program and ; are the entrypoints which enable I2C use. ; i2c?u_... must be defined in the rest of the program ; with the functionality and behaviour described. ; i2cm_... may only be called on the master PIC. ; i2cs_... may only be called on slave PICs. ; At all times following i2c[ms]_init, the i2c hardware in the PIC is ; completely reserved to the routines defined in i2clib.asm. Nothing ; else is allowed to read or modify the i2c controller state. ; Likewise, the memory locations (variables) defined there are for use ; by those routines only and must not be touched by the main program. ; Unless otherwise stated, all routines accept any value in, and may ; trash, W and the flags. All other registers and locations not ; specifically mentioned here will be preserved by the ; i2c?_... routines (and are therefore reserved for the rest of the ; program). In all cases, routines are called with CALL or RCALL or ; the equivalent, and routines are allowed to have subroutines (ie, to ; use the call/return address stack). ; Slave numbers (PIC numbers) are the actual PIC number, not the i2c ; address. So, they start at 1 for the first slave. (PIC #0 is the ; master but the master doesn't have an i2c address and its PIC number ; is never required by or supplied to i2clib.) ; They must be between 1 and 63 inclusive. ; i2c?_... routines except i2c?_interrupt will never _directly_ call ; any i2c?u_... routine; when we say `causes' this means that the ; relevant i2c?u_... routine will be called at some later point from ; i2c?_interrupt. i2c?u_... routines are allowed to call appropriate ; i2c?_... routines (except i2c?_interrupt) directly if the context ; and State allows. ; All routines except i2c?_init must be called only: ; * During an appropriate interrupt (high-priority for the slave; ; low-priority for the master). ; * From the main loop with those interrupts disabled; or ; * From within an i2c?u_... routine (which are always called ; from within i2c?_interrupt). ; This is to avoid having one i2c_... routine running in an interrupt ; which interrupted the middle of another i2c_... routine. ; Some time between calling i2cs_init and waiting for the first event, ; the main program should of course enable interrupts. ;============================================================ ; COMMON ADMINISTRATIVE ROUTINES ;-------------------- extern i2cm_init ; ; Initialises the i2c system for use by a master PIC. Must be called ; exactly once, which must be before any other i2c?_... function. ; At call On return ; i2c controller any for use by i2clib ; i2c interrupt config any enabled, low priority ; global interrupt enable disabled unchanged ; State Not-in-use Idle (as master) ;-------------------- extern i2cs_init ; ; Initialises the i2c system for use by a slave PIC. Must be called ; exactly once, which must be before any other i2c?_... function. ; W is the slave number. ; At call On return ; i2c controller any for use by i2clib ; i2c interrupt config any enabled, low priority ; global interrupt enable disabled unchanged ; State Not-in-use Idle (as slave) ; W slave number any ;-------------------- extern i2cm_interrupt extern i2cm_interrupt_definite extern i2cs_interrupt ; ; Must be called by the main program's interrupt handler; ; high-priority for the slave or low-priority for the master. ; ; For i2cm_interrupt, the main program's interrupt handler is ; responsible for saving W and the flags register and other ; interrupt-related administrivia. i2cm_interrupt checks for ; SSPIF and handles any interrupt. i2cm_interrupt_definite ; should only be called if SSPIF is set and handles it. In ; both cases the ISR returns with `return'. ; ; For i2cs_interrupt, it must be the only high-priority interrupt ; source and expects to be called from the interrupt handler (and it ; will return; the caller must retfie_r). ; ; If there is an i2c interrupt, the i2c?_interrupt will service it, taking ; any necessary action including calling appropriate ; i2c?u_... routines, and clear the interrupt flag[*]. ; ; At call On return ; State any except Not-in-use may change ; i2c interrupt state any cleared[*] ; ; [*] The interrupt event on entry, if any, will be dealt with. If ; interrupt processing takes a long time, another interrupt will occur ; and this may result in the i2c interrupt flag being set on return ; from i2c?_interrupt. ;====================================================================== ; MASTER ; ; States: ; [Not-in-use] ; | ; |init ; v ; [Idle]<-------------------------<------. ; / \ | ; / _ \ _____________________<______ | ; /,' \ `. | ; write_start// \read_start | | ; // \ ,------------------<---. | | ; // \ | | | | ; VV VV | | | ; [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 | ; `-------------------------------------' ;-------------------- extern i2cmu_done ; Called to notify that the previous conversation with the slave has ; been finished as requested. The i2c system is now available and ; i2cm_*_start can be called. ; ; 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) ;-------------------- extern i2cm_write_start ; ; Requests that a slave be contacted for writing. When communication ; has been established, i2cmu_write_next_byte will be called. ; ; At call On return ; State Idle/Reading-Wait Writing-Setup ; W slave number any extern i2cmu_write_next_byte ; ; Called to notify the main program that we are now ready to transmit ; a byte to the slave that we're currently talking to. This may be ; either because i2cm_write_start was previously called and ; communication has been established, or because tranmission of the ; previous byte is complete. ; ; The main program must immediately supply the actual data byte. This ; byte will then be transmitted to the slave, and then ; i2cmu_write_next_byte will be called again. ; Alternatively the main program may indicate that the tranmission ; should finish by setting the Z flag on return. In this case the ; slave will be told that this is the end of the message and the i2c ; conversation will be finished. When the conversation is finished ; and the bus and i2c controller are free again, i2cmu_done will be ; called. ; ; When transmission should continue: ; ; Beforehand At call On return After return ; State Writing[-Setup] Writing Writing Writing ; Status Z any 0 (NZ, not zero, not equal) ; W any data for slave ; ; When transmission should finish: ; ; Beforehand At call On return After return ; State Writing Writing Writing Stopping ; Status Z any 1 (Z, zero, equal) ; W any any ;======================================== ; MASTER - READS (ie, reception of data from the slave) ;-------------------- extern i2cm_read_start ; ; Requests that a slave be contacted for reading. When communication ; has been established and the first byte received, ; i2cmu_read_got_byte will be called. ; ; At call On return ; State Idle/Reading-Wait Reading-Busy ; W slave number any extern i2cmu_read_got_byte ; ; Called to notify the main program that a byte has been recieved from ; the slave PIC. The byte value is supplied. Communication with the ; slave will be suspended (with the i2c bus blocked) until the main ; program calls i2cm_read_another or i2cm_read_done. The main program ; must call one of these two before doing anything else with the i2c. ; ; Beforehand At call ; State Reading Reading-Wait ; W data from slave extern i2cm_read_another ; ; Requests that the communication with the slave continue and another ; byte be read. When this is complete, i2cmu_read_got_byte will be ; called. ; ; At call On return ; State Reading-Wait Reading-Busy extern i2cm_read_done ; ; Requests that reading from the slave be terminated. When the ; conversation is finished and the bus and i2c controller are free ; again, i2cmu_done will be called. ; ; At call On return ; State Reading-Wait Stopping ;====================================================================== ; SLAVE ; ; States: ; ; [Not-in-use] ; | ; |init ; | ; 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. 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 ;-------------------- extern i2csu_write_data ; ; 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 ;======================================== ; 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 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 invoke i2cs_read_data. ; ; Beforehand At call ; State Transmit-Busy Transmit-Wait