(********************************************************************************) (* *) (* Function: IIC - IIC bus master *) (* *) (* Creation Date: 24.6.98 From: New *) (* *) (* Author: A. Morbach *) (* arno-morbach@web.de *) (* *) (* Description: *) (* ------------ *) (* This function provides an easy way to connect IIC devices to the 68332 or *) (* 68376. Two adjacent channels are used, the first one provides the user inter-*) (* face. The function has been tested with IIC EEPROMs, but it should work with *) (* several other IIC slaves. Since the TPU is always master of the IIC bus, *) (* there is no limit of the response time. If there are other TPU functions, *) (* the transfer time will go up, but it will not be disturbed. *) (* The following description assumes, that you are familiar with the IIC bus *) (* and its addressing scheme. *) (* *) (* The IIC bus is an open collector coupled bus. The TPU ports are not open *) (* collector, but with the TPU as bus master there is a solution: Just use the *) (* first TPU channel N as SCL in output mode. Use a pullup resitor to force high*) (* level while the uC is in reset. The second channel N+1 will work as SDA. It *) (* is used as output and input. To meet the IIC specs, there is a resistor / *) (* diode combination in series with the TPU pin. *) (* *) (* -------------| _____ *) (* uC | ----|<|---- ---| R2|------>VCC *) (* | | D | | ----- *) (* TPU pin SDA |-----+ +----+ SDA *) (* | | _____ | |-------------------------------- *) (* | ---| R1|--- *) (* -------------| ----- *) (* *) (* R1 = 10kOhm to provide the SDA level to the TPU pin in input mode. *) (* R2 = 3.32kOhm pullup for the IIC bus. This is the minimum resistance, *) (* because the uC is only capable of sinking 1.6mA. With only one or two devices*) (* connected it shouldn't be a problem. *) (* D is a shottky diode to build the equivalent of an open collector output. *) (* *) (* There are two modes of operation: Read one byte from, or write one byte to *) (* a connected IIC device. The mode is defined by the lsb of IIC_SLAVE_ADDRESS. *) (* *) (* Read mode: *) (* First the slave address is sent, with R/W bit set to 0. *) (* Then the byte address is sent. *) (* After acknowlegde, a start condition is generated and the slave address is *) (* transmitted again, with R/W bit set to 1. *) (* Next, the data byte is read into IIC_DATA. *) (* *) (* Write mode: *) (* First the slave address is sent, with R/W bit set to 0. *) (* Then the byte address is sent. *) (* Next the data byte in IIC_DATA is transmitted. *) (* *) (* The termination of the transfer is reported by setting the msb in IIC_STATE. *) (* If there was a missing acknowlegde the value of IIC_STATE is 0x8100. *) (* IIC_STATE should be set to 0 before a transmission is started, because *) (* some time will go by before the IIC function can reset IIC_STATE itself. *) (* If the software is too fast it could otherwise see the msb set and think that*) (* the transmission is over, although it has not yet been started. *) (* *) (* name: Written By: Location Bits: *) (* ----- ----------- --------------- *) (* IIC_SLAVE_ADDRESS CPU Parameter0 8..15 *) (* Slave adress of the IIC device which is HW decoded. *) (* The last bit (LSB) defines if the following transfer *) (* is read or write. See IIC specifications. *) (* *) (* IIC_BYTE_ADDRESS CPU Parameter0 0..7 *) (* Byte address. Only the IIC device which was addressed *) (* by the previous IIC_SLAVE_ADDRESS will use this *) (* IIC_BYTE_ADDRESS. *) (* *) (* IIC_DATA CPU / TPU Parameter1 0..7 *) (* In write mode this byte will be sent. In read mode the *) (* received byte will be here to be read by CPU. *) (* *) (* IIC_SHIFT_REGISTER TPU Parameter2 0..7 *) (* holds the data to be shifted out or in. *) (* *) (* IIC_COUNT TPU Parameter3 0..3 *) (* is used to count SCL edges, to determine if the *) (* actual state is to be ended. *) (* *) (* IIC_CLK_LOW_TIME CPU Parameter4 0..15 *) (* defines the minimum clock low time. The same *) (* time is used as high time, which is normally *) (* lower (about 4us instead of 4.7us as low time). *) (* CLK_LOW_TIME must be 2 or greater. Even with *) (* a very slow TCR1 CLK_LOW_TIME = 1 is not *) (* allowed, because of the internal timing. The *) (* really used time is between CLK_LOW_TIME - 1 and *) (* CLK_LOW_TIME. So 1 could degrade to 0, which *) (* would be too fast. *) (* The setting of this register depends on the system *) (* frequency and the prescaler of TCR1. Only TCR1 is used *) (* in this implemetation, but it can easily changed. *) (* CLK_LOW_TIME counts TCR1 transitions. *) (* *) (* IIC_STATE CPU / TPU Parameter5 0..15 *) (* The transmission of bits over the IIC bus is *) (* divided into several states. The actual state *) (* is stored in the lower byte of STATE. To see *) (* how the states are coded, see the table *) (* following this header. *) (* The high byte of STATE gives a status of *) (* operation. It is to be reset before starting a *) (* transmission. *) (* STATE(8..15) = 0x00: transmission in progress. *) (* STATE(8..15) = 0x80: transmission is complete *) (* without error. *) (* STATE(8..15) = 0x81: transmission is complete *) (* with error: missing *) (* acknowledge. *) (* *) (* HSQ1 HSQ0 Action *) (* ---- ---- ------ *) (* x x HSQ is not used *) (* *) (* HSR1 HSR0 Action *) (* ---- ---- ------ *) (* 0 1 Initiate transfer *) (* 1 0 No action *) (* 1 1 Initialize ports *) (* *) (* flag1 1: Read operation of IIC device *) (* 0: Write operation of IIC device *) (* *) (* flag0 1: Data IO is under way *) (* 0: Control bits are generated *) (* *) (* Links Accepted: NO Links Generated: NO *) (* *) (* Interrupts Generated After: Each complete transfer *) (* *) (* *) (* Every state (stored in IIC_STATE) begins with SCL = 0. *) (* *) (* flag1 = 1 (read) | flag1 = 0 (write) *) (* --------------------------------------------------------------------------- *) (* State by name | IIC_STATE | flag0 | State by name | IIC_STATE | flag0 *) (* --------------------------------------------------------------------------- *) (* SLAVE_ADR_OUT | 03 | 1 | SLAVE_ADR_OUT | 03 | 1 *) (* REC_ACKNOWLEDGE | 03 | 0 | REC_ACKNOWLEDGE | 03 | 0 *) (* --------------------------------------------------------------------------- *) (* BYTE_ADR_OUT | 05 | 1 | BYTE_ADR_OUT | 05 | 1 *) (* REC_ACKNOWLEDGE | 05 | 0 | REC_ACKNOWLEDGE | 05 | 0 *) (* --------------------------------------------------------------------------- *) (* START_CONDITION | 40 | 0 | | | *) (* --------------------------------------------------------------------------- *) (* SLAVE_ADR_OUT | 09 | 1 | DATA_OUT | 09 | 1 *) (* REC_ACKNOWLEDGE | 09 | 0 | REC_ACKNOWLEDGE | 09 | 0 *) (* --------------------------------------------------------------------------- *) (* DATA_IN | 80 | 1 | | | *) (* SEND_NO_ACK | 80 | 0 | | | *) (* --------------------------------------------------------------------------- *) (* STOP_CONDITION | 20 | 0 | STOP_CONDITION | 20 | 0 *) (* *) (* *) (* *) (* START_CONDITION: *) (* *) (* ---+ +--------------------- *) (* SCL | | *) (* +----------+ *) (* *) (* +++++-------------------+ *) (* SDA + | *) (* +++++ +----------- *) (* *) (* ^ ^ ^ *) (* | | +-- 2. IIC_RIS_CT: SDA Output Low *) (* | | *) (* | +------------ 1. IIC_RIS_CT: SDA Output High *) (* | *) (* +----------------------- IIC_FAL_CT: SDA Output High *) (* *) (* Next state is 09 with flag0 = 1. *) (* *) (* *) (* *) (* STOP_CONDITION: *) (* *) (* ---+ +--------------------- *) (* SCL | | *) (* +----------+ *) (* *) (* +++++ +----------- *) (* SDA + | *) (* +++++-------------------+ *) (* *) (* ^ ^ ^ *) (* | | +-- 2. IIC_RIS_CT: SDA Output High *) (* | | *) (* | +------------ 1. IIC_RIS_CT: SDA Output Low *) (* | *) (* +----------------------- IIC_FAL_CT: SDA Output Low *) (* *) (* There is no next state, no further matches are set up. STATUS = 80. *) (* *) (* *) (* *) (* SEND_NO_ACK: *) (* *) (* ---+ +----- *) (* SCL | | *) (* +----------+ *) (* *) (* +++++--------------- *) (* SDA + *) (* +++++ *) (* *) (* ^ ^ *) (* | +------------ IIC_RIS_CT: SDA Output High *) (* | *) (* +----------------------- IIC_FAL_CT: SDA Output High *) (* *) (* Next state is 20 with flag0 = 0. *) (* *) (* *) (* *) (* REC_ACKNOWLEDGE: *) (* *) (* ---+ +----- *) (* SCL | | *) (* +----------+ *) (* *) (* +++++----------+---- *) (* SDA + + *) (* +++++----------+---- *) (* *) (* ^ ^ *) (* | +------------ IIC_RIS_CT: SDA checked if low *) (* | *) (* +----------------------- IIC_FAL_CT: SDA Input *) (* *) (* If SDA is high, then STATUS = 81. No further matches. *) (* If SDA is low then next state depends on current state and flag1. *) (* *) (* current state | flag1 | next state and flag0 *) (* ---------------------------------------------- *) (* 03 | 1 | 05 1 *) (* 03 | 0 | 05 1 *) (* 05 | 1 | 40 0 *) (* 05 | 0 | 09 1 *) (* 09 | 1 | 80 1 *) (* 09 | 0 | 20 0 *) (* *) %macro IIC_ADDRESS 'prm0'. %macro IIC_DATA 'prm1'. %macro IIC_SHIFT_REGISTER 'prm2'. %macro IIC_COUNT 'prm3'. %macro IIC_CLK_LOW_TIME 'prm4'. %macro IIC_STATE 'prm5'. %macro IIC_BIT_START '#$C0'. %macro IIC_BIT_STOP '#$20'. %macro IIC_BIT_NOACK '#$C0'. (************************************************************************) (* *) (* ENTRY name: IIC_INIT *) (* *) (* PRELOAD PARAMETER : IIC_ADDRESS *) (* *) (* ENTER WHEN : HSR = %11 *) (* *) (* ACTION: Initialize portpins, SCL high, SDA high. *) (* Don't activate any matches. *) (************************************************************************) %entry start_address *; ram p<-@IIC_ADDRESS; disable_match; name = IIC_INIT; cond hsr1=1,hsr0=1. IIC_INIT: (* drive SCL high. SCL should already be high due to external pullup *) chan pin := high, TBS := out_m1_c1, PAC := no_change, disable_mtsr. au chan_reg := chan_reg + #$10. (* change to Channel SDA *) nop. (* wait for next channel *) (* drive SDA high. Since SDA is externally coupled by a diode, *) (* the bus will be high due to external pullup *) chan pin := high, TBS := out_m1_c1, PAC := no_change; disable_mtsr. end. (************************************************************************) (* *) (* ENTRY name: IIC_START_TRANSFER *) (* *) (* PRELOAD PARAMETER : IIC_ADDRESS *) (* *) (* ENTER WHEN : HSR = %01 *) (* *) (* ACTION: *) (* Initiate Transfer *) (* Load IIC_SHIFT_REGISTER with IIC_ADRESS. Clear R/W bit in *) (* IIC_SHIFT_REGISTER because the first transmission is always a *) (* write to the IIC device. *) (* Store read or write operation in flag1. *) (* Set IIC_STATE to 03. *) (* Set IIC_COUNT to 8 for 8 bit transmission. *) (* Set flag0 to 1 to transmit data. *) (* Generate Start Condition by setting SDA to low while SCL is *) (* high. *) (* *) (* Set up match time for falling SCL edge. *) (************************************************************************) %entry start_address *; ram p<-@IIC_ADDRESS; disable_match; name = IIC_START_TRANSFER; cond hsr1=0, hsr0=1. IIC_START_TRANSFER: au p_high :=>> p_high, ccl; (* RW bit into carry flag *) chan set flag0. (* begin with data transmission *) au p_high :=<< p_high. (* Back again. RW bit is now 0 *) (* Every transmission begins with RW=0 *) ram p -> @IIC_SHIFT_REGISTER. (* load shift register *) if C = 0 then goto IIC_START_WRITE, flush; (* set flag1 if RW bit is 1 *) chan tbs := out_m1_c1; enable_mtsr, clear flag1. IIC_START_READ: chan set flag1. (* RW bit is 1: set flag1 *) IIC_START_WRITE: au p := #$03. (* state 03 at the beginning *) IIC_START_CONT: ram p -> @IIC_STATE. (* state machine begins with 03 to send slave address *) au chan_reg := chan_reg + #$10. (* change to next channel, SDA *) au p := #8. (* 8 bits to be sent *) (* SDA is low, Start condition *) chan pin := low, tbs := out_m1_c1, pac := no_change; disable_mtsr. au chan_reg := chan_reg + #$F0. (* Back to SCL *) ram p -> @IIC_COUNT; goto IIC_NEXT_EDGE_LOW, flush. (************************************************************************) (* ENTRY name: IIC_FAL_IO *) (* PRELOAD PARAMETER : IIC_STATE *) (* ENTER WHEN : HSR = %00 *) (* SCL = 0 *) (* flag0 = 1 (Data bits) *) (* ACTION: *) (* A falling edge of SCL occured. Data bit has to be processed. *) (* If state is 80 (DATA_IN) just a match for the next rising edge *) (* has to be set up. *) (* Otherwise the msb of the shift register is output at SDA. *) (* *) (* Set up match time for rising SCL edge. *) (************************************************************************) %entry start_address *; ram p <- @IIC_STATE; name = IIC_FAL_IO; cond hsr1 = 0, hsr0 = 0, lsr = 0, m/tsr = 1, pin = 0, flag0 = 1. IIC_FAL_IO: au p_low :=<< p_low, ccl. (* get msb into C *) if Z = 1 then goto IIC_NEXT_EDGE_HIGH, flush. (* STATE = 80: do nothing *) (* SDA is already in input mode, because *) (* of acknowledge check. *) IIC_FAL_OUT: (* STATE = 03, 05 or 09. The msb of the shift register should be put out at SDA *) ram diob <- @IIC_SHIFT_REGISTER. (* get shift register into diob *) au chan_reg := chan_reg + #$10. (* switch to SDA *) au diob :=<< diob, ccl. (* get msb into C *) if C = 0 then goto IIC_FAL_OUT_LOW; chan tbs := out_m1_c1. (* set pin to output *) chan pin := low, pac := no_change. (* Pin is low. No matter what C is *) IIC_FAL_OUT_HI: chan pin := high. (* If C=0 this is not executed *) IIC_FAL_OUT_LOW: au chan_reg := chan_reg + #$F0. (* switch back to SCL *) ram diob -> @IIC_SHIFT_REGISTER; (* store shift register *) goto IIC_NEXT_EDGE_HIGH, flush. (* set up next edge *) (************************************************************************) (* ENTRY name: IIC_RIS_IO *) (* STATE(S) ENTERED: *) (* PRELOAD PARAMETER : *) (* ENTER WHEN : HSR = %00 *) (* SCL = 1 *) (* flag0 = 1 (Data bits) *) (* ACTION: *) (* A rising edge of SCL occured. Data bit has to be processed. *) (* If state is 80 (DATA_IN) the pin state of SDA is stored into the*) (* lsb of IIC_SHIFT_REGISTER, which has been shiftet left before. *) (* If state is 03, 05 or 09 nothing special has to be done. *) (* In all modes IIC_COUNT is decremented. If IIC_COUNT reaches 0 *) (* a switch to the next state is performed. *) (* Otherwise the msb of the shift register is output at SDA. *) (* *) (* Set up match time for rising SCL edge. *) (************************************************************************) %entry start_address *; ram p <- @IIC_STATE; name = IIC_RIS_IO; cond hsr1 = 0, hsr0 = 0, lsr = 0, m/tsr = 1, pin = 1, flag0 = 1. IIC_RIS_IO: au p_low :=<< p_low, ccl. (* get away with msb *) if Z = 0 then goto IIC_RIS_OUT, flush. (* STATE = 03, 05 or 09: goto output mode *) (* do nothing with shift register *) IIC_RIS_INP: ram diob <- @IIC_SHIFT_REGISTER. (* get shift register into diob *) au chan_reg := chan_reg + #$10. (* switch to SDA *) au diob :=<< diob. (* get ready to insert lsb *) if psl = 0 then goto IIC_RIS_INP_LO, flush. au diob := diob + 1. (* set lsb since the pin is high *) IIC_RIS_INP_LO: au chan_reg := chan_reg + #$F0. (* switch back to SCL *) ram diob -> @IIC_SHIFT_REGISTER. (* store new data into shift register *) IIC_RIS_OUT: ram p <- @IIC_COUNT. (* get counter into p *) au p := p - 1, ccl; (* decrement bit count *) ram p -> @IIC_COUNT. (* store bit count *) if Z = 0 then goto IIC_NEXT_EDGE_LOW, flush. (* if not Z there are still *) (* bits to be tranfered *) (* All bits have been transfered. Now we have to switch to the handling of ack, start or stop. *) ram p <- @IIC_STATE. au p_low :=<< p_low, ccl; ram diob <- @IIC_SHIFT_REGISTER. (* received data into diob *) if Z = 0 then goto IIC_RIS_RECACK, flush. (* In state 03, 05 and 09 acknowledge has *) (* to be received. *) IIC_RIS_NOACK: (* in state 80 no acknowledge is to be sent out. *) ram diob -> @IIC_DATA. (* store received data into IIC_DATA *) au p_high := @IIC_BIT_NOACK. ram p -> @IIC_SHIFT_REGISTER; (* set up bit pattern for stop condition *) au diob := 1. (* 1 rising edge *) ram diob -> @IIC_COUNT. IIC_RIS_RECACK: if TRUE then goto IIC_NEXT_EDGE_LOW, flush; (* setup next edge *) chan clear flag0. (* control bit is following, state keeps the same *) (************************************************************************) (* ENTRY name: IIC_FAL_CT *) (* STATE(S) ENTERED: *) (* PRELOAD PARAMETER : *) (* ENTER WHEN : HSR = %00 *) (* SCL = 0 *) (* flag0 = 0 (Control bits: ack, start or stop) *) (* ACTION: *) (* A falling edge of SCL occured. Control bit has to be processed. *) (* If state is 03, 05 or 09, SDA is set to input. *) (* if state is 20, 40 or 80, the msb of the shift register is put *) (* out at SDA. *) (* *) (* Set up match time for rising SCL edge. *) (************************************************************************) %entry start_address *; ram p <- @IIC_STATE; name = IIC_FAL_CT; cond hsr1 = 0, hsr0 = 0, lsr = 0, m/tsr = 1, pin = 0, flag0 = 0. IIC_FAL_CT: au p_low :=>> p_low, ccl. if C = 0 then goto IIC_FAL_CT_STSTNOACK, flush. (* STATE = 80, 40 or 20: *) IIC_FAL_CT_ACK: (* with the states 03, 05 and 09, the reception of the acknowledge bit is to be *) (* arranged. SDA is to be switched to input. *) au chan_reg := chan_reg + #$10. (* switch to SDA *) chan tbs := in_m1_c1, pac := no_detect. (* SDA to input *) au chan_reg := chan_reg + #$F0. (* switch back to SCL *) goto IIC_NEXT_EDGE_HIGH, flush. (* do nothing, just generate rising edge *) IIC_FAL_CT_STSTNOACK: (* With all three states 20, 40 and 80, the content of the shift register is to be *) (* put out at SDA *) ram p <- @IIC_SHIFT_REGISTER. au chan_reg := chan_reg + #$10. (* switch to SDA *) au p :=<< p, ccl. (* set C with msb *) if C = 0 then goto IIC_FAL_CT_LO_OUT, flush; chan tbs := out_m1_c1, pac := no_change, pin := low. (* SDA to output *) chan pin := high. IIC_FAL_CT_LO_OUT: au chan_reg := chan_reg + #$F0. (* switch back to SCL *) ram p -> @IIC_SHIFT_REGISTER; (* store new value into shift register *) goto IIC_NEXT_EDGE_HIGH, flush. (* do nothing, just generate rising edge *) (************************************************************************) (* *) (* ENTRY name: IIC_RIS_CT *) (* *) (* STATE(S) ENTERED: *) (* *) (* PRELOAD PARAMETER : IIC_COUNT *) (* *) (* ENTER WHEN : HSR = %00 *) (* SCL = 1 *) (* flag0 = 0 (Control bits: ack, start or stop) *) (* ACTION: *) (* A rising edge of SCL occured or this is the second match with *) (* SCL high (start or stop). Control bit has to be processed. *) (* With SCL high (start, stop: 2. match) the next state has to be *) (* determined. A lot of decisions have to be made. They are *) (* explained in the code section. *) (* flag0, IIC_SHIFT_REGISTER, IIC_COUNT and IIC_STATE are set up *) (* for the beginning of the next state. *) (* *) (* Set up match time for rising SCL edge. *) (************************************************************************) %entry start_address *; ram p <- @IIC_STATE; name = IIC_RIS_CT; cond hsr1 = 0, hsr0 = 0, lsr = 0, m/tsr = 1, pin = 1, flag0 = 0. IIC_RIS_CT: au p_low :=>> p_low, ccl; (* Shift lsb into C *) ram diob <- @IIC_COUNT. (* get Count into diob *) if C = 1 then goto IIC_RIS_CT_ACK, flush. (* STATE = 03, 05 or 09 *) IIC_RIS_CT_STSTNOACK: (* STATE = 20, 40 or 80 *) ram p <- @IIC_SHIFT_REGISTER. (* get Shift register *) au chan_reg := chan_reg + #$10. (* switch to SDA *) au p :=<< p, ccl. (* set C with msb *) (* at this output are no glitches allowed, because SCL is already high. With SCL high, *) (* there are no unwanted edges at SDA allowed.*) chan tbs := out_m1_c1, pac := no_change; (* SDA to output *) if C = 0 then goto IIC_RIS_CT_LO_OUT, flush. chan pin := high; if TRUE then goto IIC_RIS_CT_CONT, flush. IIC_RIS_CT_LO_OUT: chan pin := low. IIC_RIS_CT_CONT: au chan_reg := chan_reg + #$F0. (* switch back to SCL *) au diob := diob - 1, ccl; (* decrement COUNT *) ram p -> @IIC_SHIFT_REGISTER. (* store new value into shift register *) ram diob -> @IIC_COUNT. (* store IIC_COUNT *) if Z = 0 then goto IIC_NEXT_EDGE_HIGH, flush. (* still one edge left *) ram p <- @IIC_STATE. (* get state *) au p_low :=<< p_low, ccl. if Z = 1 then goto IIC_RIS_CT_NOACK, flush. (* STATE = 80 *) au p_low :=<< p_low, ccl. if Z = 1 then goto IIC_RIS_CT_START, flush. (* STATE = 40 *) IIC_RIS_CT_STOP: (* STATE = 20 *) au p := $8000; ram p -> @IIC_STATE. (* STATE = 80: end of transmission, no errors *) chan disable_mtsr. (* no further matches *) chan cir; (* generate interrupt *) end. IIC_RIS_CT_NOACK: (* STATE = 80 *) au p_high := @IIC_BIT_STOP. ram p -> @IIC_SHIFT_REGISTER. (* set up bit pattern for stop condition *) au p := #$20. (* next state will be 20 *) au diob := #2. (* 2 rising edges *) goto IIC_RIS_CT_SETUP, flush. (* with p and diob set, goto setup *) IIC_RIS_CT_START: (* STATE = 40 *) ram p <- @IIC_ADDRESS. (* get slave address into p *) ram p -> @IIC_SHIFT_REGISTER. (* and then into SHIFT_REGISTER *) au p := #$09; (* next state is 09 *) chan set flag0. (* data IO *) IIC_RIS_CT_SETUP8: au diob := #8. (* 8 bits to be sent *) IIC_RIS_CT_SETUP: (* The registers IIC_STATE and IIC_COUNT are loaded with the values of p and diob *) ram p -> @IIC_STATE. (* store next state *) ram diob -> @IIC_COUNT. (* store count *) goto IIC_NEXT_EDGE_LOW, flush. (* next time it will be a falling edge *) IIC_RIS_CT_ACK: (* STATE = 03, 05 or 09 *) (* p_low is 01 02 or 08 depending on the current state (03, 05 09) *) au chan_reg := chan_reg + #$10. (* switch to SDA *) au p_low :=>> p_low. (* shift state right *) if psl = 1 then goto IIC_RIS_CT_RECNOACK, flush. (* SDA = 1: No Ack *) IIC_RIS_CT_RECACK: au chan_reg := chan_reg + #$F0. (* switch back to SCL *) au p_low :=>> p_low, ccl. (* shift state right, the second time *) if C = 1 then goto IIC_RIS_CT_BYT, flush. (* STATE = 05 *) if Z = 1 then goto IIC_RIS_CT_FIRSLV, flush. (* STATE = 03 *) IIC_RIS_CT_SECSLV: (* STATE = 09 *) if flag1 = 0 then goto IIC_RIS_CT_DATA, flush. (* STATE = 09, flag1 = 0 *) (* STATE = 09, flag1 = 1 *) au p := #$80; (* next state is 80 *) chan set flag0. (* data IO *) goto IIC_RIS_CT_SETUP8, flush. (* store IIC_STATE and IIC_COUNT *) IIC_RIS_CT_DATA: (* STATE = 09, flag1 = 0 *) au p_high := @IIC_BIT_STOP. ram p -> @IIC_SHIFT_REGISTER. (* set up bit pattern for stop condition *) au p := #$20. (* next state is 20 *) au diob := #2. (* 2 rising edges *) goto IIC_RIS_CT_SETUP, flush. (* store IIC_STATE and IIC_COUNT *) IIC_RIS_CT_FIRSLV: (* STATE = 03 *) au p := #$05; (* next state is 05 *) chan set flag0. (* data IO *) goto IIC_RIS_CT_SETUP8, flush. (* store IIC_STATE and IIC_COUNT *) IIC_RIS_CT_BYT: (* STATE = 05 *) if flag1 = 0 then goto IIC_RIS_CT_DATA_OUT, flush. (* STATE = 05, flag1 = 0 *) IIC_RIS_CT_START_COND: (* STATE = 05, flag1 = 1 *) au p_high := @IIC_BIT_START. ram p -> @IIC_SHIFT_REGISTER. (* set up bit pattern for stop condition *) au p := #$40. (* next state is 40 *) au diob := #2. (* 2 rising edges *) goto IIC_RIS_CT_SETUP, flush. (* store IIC_STATE and IIC_COUNT *) IIC_RIS_CT_DATA_OUT: (* STATE = 05, flag1 = 0 *) ram p <- @IIC_DATA. (* get data byte into p_high *) au p_high := p_low. (* get low byte into high byte *) ram p -> @IIC_SHIFT_REGISTER. (* and store it in IIC_SHIFT_REGISTER *) au p := #$09; (* next state is 09 *) chan set flag0. (* data IO *) goto IIC_RIS_CT_SETUP8, flush. (* store IIC_STATE and IIC_COUNT *) IIC_RIS_CT_RECNOACK: (* still in SDA channel *) au chan_reg := chan_reg + #$F0. (* switch back to SCL *) au p_high := #$81. (* end with error bit set *) ram p -> @IIC_STATE. (* STATE = 81: end of transmission *) (* error: missing acknowledge *) chan disable_mtsr. chan cir; (* generate interrupt *) end. (**********************************************************************) (**********************************************************************) IIC_NEXT_EDGE_HIGH: chan pac := high; if TRUE then goto IIC_SET_NEXT_EDGE, flush. IIC_NEXT_EDGE_LOW: chan pac := low. IIC_SET_NEXT_EDGE: au ert := tcr1; ram diob <- @IIC_CLK_LOW_TIME. au ert := ert + diob; chan write_mer, neg_lsl, neg_tdl, neg_mrl. nop. end. (**********************************************************************) (**********************************************************************) %entry start_address End_of_Link; name = IIC_UNDEF; cond hsr1=0,hsr0=0, lsr = 1, m/tsr = 0. %entry start_address End_of_Link; name = IIC_UNDEF; cond hsr1=0,hsr0=0, lsr = 1, m/tsr = 1. %entry start_address End_of_Link; name = IIC_UNDEF; cond hsr1=1,hsr0=0.