/******************************************************************************/ /* Copyright 2004 MBARI - Monterey Bay Aquarium Research Institute */ /******************************************************************************/ /******************************************************************************/ /* Summary : Routines to control WIT2410 MODEM via LOBO controller I2C link */ /* Filename : IO_I2C.C */ /* Author : Luke Coletti */ /* Project : */ /* Version : 1.0 */ /* Compiler : Aztec C68k/ROM v5.2D */ /* Created : 09/11/04 */ /* Archived : */ /******************************************************************************/ /* Modification History: */ /* */ /******************************************************************************/ #include /* Tattletale Model 8 Definitions */ #include /* definitions and prototypes for Model 8 library */ #include /* definitions and prototypes for Model 8 library */ #include #include #include #include #include #include #include "lobo.h" /* I2C I/O high level function prototypes */ int I2C_ReadInputPorts(uchar *Port0, uchar *Port1) { I2C_Stop(); if( I2C_SetReadMode(MODEM_INPUT_PORT0) == FALSE ) return( ERROR ); *Port0 = I2C_RdByte(); I2C_WrAck(); *Port1 = I2C_RdByte(); I2C_WrNak(); I2C_Stop(); return( TRUE ); } int I2C_ReadInputPort0(uchar *Port0) { int ret; I2C_Stop(); if( I2C_SetReadMode(MODEM_INPUT_PORT0) == FALSE ) return( ERROR ); *Port0 = I2C_RdByte(); I2C_WrNak(); I2C_Stop(); return( TRUE ); } int I2C_ReadInputPort1(uchar *Port1) { int ret; I2C_Stop(); if( I2C_SetReadMode(MODEM_INPUT_PORT1) == FALSE ) return( ERROR ); *Port1 = I2C_RdByte(); I2C_WrNak(); I2C_Stop(); return( TRUE ); } int I2C_SetClrBitPort0(uchar Bit, uchar State) { uchar Port0; I2C_Stop(); if( I2C_SetReadMode(MODEM_INPUT_PORT0) == FALSE ) return( ERROR ); Port0 = I2C_RdByte(); I2C_WrNak(); I2C_Stop(); if( I2C_SetWriteMode(MODEM_OUTPUT_PORT0) == FALSE ) return( ERROR ); if(Bit == MODEM_CFG){ if(State == TRUE) Port0 &= 0xFE; //enable, clr output bit if(State == FALSE) Port0 |= 0x01; //disable, set output bit } else if(Bit == MODEM_RTS){ if(State == TRUE) Port0 &= 0xFD; //enable, clr output bit if(State == FALSE) Port0 |= 0x02; //disable, set output bit } else if(Bit == MODEM_SLEEP){ if(State == TRUE) Port0 |= 0x04; //enable, set output bit if(State == FALSE) Port0 &= 0xFB; //disable, clr output bit } else return( ERROR ); I2C_WrByte(Port0); if(I2C_RdAck() == FALSE){ I2C_Stop(); return( FALSE ); } I2C_Stop(); Sleep(0); Sleep(100); return( TRUE ); } int I2C_SetClrBitPort1(uchar Bit, uchar State) { uchar Port1; I2C_Stop(); if( I2C_SetReadMode(MODEM_INPUT_PORT1) == FALSE ) return( ERROR ); Port1 = I2C_RdByte(); I2C_WrNak(); I2C_Stop(); if( I2C_SetWriteMode(MODEM_OUTPUT_PORT1) == FALSE ) return( ERROR ); if(Bit == MODEM_K1_SET){ if(State == TRUE) Port1 |= 0x04; //turn it on, set output bit if(State == FALSE) Port1 &= 0xFB; //turn it off, clr output bit } else if(Bit == MODEM_K1_RESET){ if(State == TRUE) Port1 |= 0x08; //turn it on, set output bit if(State == FALSE) Port1 &= 0xF7; //turn it off, clr output bit } else if(Bit == MODEM_K2_SET){ if(State == TRUE) Port1 |= 0x10; //turn it on, set output bit if(State == FALSE) Port1 &= 0xEF; //turn it off, clr output bit } else if(Bit == MODEM_K2_RESET){ if(State == TRUE) Port1 |= 0x20; //turn it on, set output bit if(State == FALSE) Port1 &= 0xDF; //turn it off, clr output bit } else if(Bit == MODEM_STANDBY_LED){ if(State == TRUE) Port1 &= 0xBF; //turn it on, clr output bit if(State == FALSE) Port1 |= 0x40; //turn it off, set output bit } else if(Bit == MODEM_CARRIER_LED){ if(State == TRUE) Port1 &= 0x7F; //turn it on, clr output bit if(State == FALSE) Port1 |= 0x80; //turn it off, set output bit } else return( ERROR ); I2C_WrByte(Port1); if(I2C_RdAck() == FALSE){ I2C_Stop(); return( FALSE ); } I2C_Stop(); Sleep(0); Sleep(100); return( TRUE ); } int I2C_WriteDefaultPortValues(void) { // Write the default Output Data Values I2C_Stop(); if( I2C_SetWriteMode(MODEM_OUTPUT_PORT0) == FALSE ) return( ERROR ); // Port0 lower three bits SET (CFG\, RTS\ DISABLED, and SLEEP ENABLED) I2C_WrByte(MODEM_DAT_LO_BYTE); if(I2C_RdAck() == FALSE){ I2C_Stop(); return( FALSE ); } // Port1 upper two bits SET (CARRIER_LED and STANDBY_LED DISABLED) I2C_WrByte(MODEM_DAT_HI_BYTE); if(I2C_RdAck() == FALSE){ I2C_Stop(); return( FALSE ); } I2C_Stop(); return( TRUE ); } int I2C_InitPortConfiguration(void) { // This Function is ONLY called once upon PowerUp, i.e., via ModemPowerOn() // Initializes the Port Configuration or Data Direction Values I2C_Start(); I2C_WrByte(MODEM_NODE_ADDR_WR); if(I2C_RdAck() == FALSE){ I2C_Stop(); return( FALSE ); } I2C_WrByte(MODEM_CONFIG_PORT0); if(I2C_RdAck() == FALSE){ I2C_Stop(); return( FALSE ); } I2C_WrByte(MODEM_CFG_LO_BYTE); if(I2C_RdAck() == FALSE){ I2C_Stop(); return( FALSE ); } I2C_WrByte(MODEM_CFG_HI_BYTE); if(I2C_RdAck() == FALSE){ I2C_Stop(); return( FALSE ); } return( I2C_WriteDefaultPortValues() ); } int I2C_SetWriteMode(uchar Port) { I2C_Start(); I2C_WrByte(MODEM_NODE_ADDR_WR); if(I2C_RdAck() == FALSE){ I2C_Stop(); return( FALSE ); } I2C_WrByte( Port ); if(I2C_RdAck() == FALSE){ I2C_Stop(); return( FALSE ); } return( TRUE ); } int I2C_SetReadMode(uchar Port) { I2C_Start(); I2C_WrByte(MODEM_NODE_ADDR_WR); if(I2C_RdAck() == FALSE){ I2C_Stop(); return( FALSE ); } I2C_WrByte( Port ); if(I2C_RdAck() == FALSE){ I2C_Stop(); return( FALSE ); } I2C_Start(); I2C_WrByte(MODEM_NODE_ADDR_RD); if(I2C_RdAck() == FALSE){ I2C_Stop(); return( FALSE ); } return( TRUE ); } /* I2C I/O low level function prototypes */ /****************************************************************************/ /* Assert I2C Start (S) Condition, which is a HIGH to LOW transition of the */ /* I2C_TXD line while I2C_CLK is high. Go out LOW... */ /****************************************************************************/ void I2C_Start(void) { ; #asm PORTE1 equ $FFFA13 ;port E1 data r/w andi.b #%11111010,PORTE1 ;release I2C_TXD and I2C_CLK (open drain) high jsr START_DELAY ; ori.b #%00000001,PORTE1 ;set I2C_TXD low jsr START_DELAY ; ori.b #%00000100,PORTE1 ;set I2C_CLK low jsr START_DELAY ; bra START_RET ; START_DELAY moveq #6,d0 ;load loop count (4 times) START_DLOOP subq #1,d0 ;decrement bne START_DLOOP ;repeat till zero rts ; START_RET jsr START_DELAY ; ;enable interrupts ;return from C function call #endasm } /****************************************************************************/ /* Assert I2C Stop (P) Condition, which is a LOW TO HIGH transition of the */ /* I2C_TXD line while I2C_CLK is high. Go out HIGH... */ /****************************************************************************/ void I2C_Stop(void) { ; #asm ori.b #%00000100,PORTE1 ;set I2C_CLK low jsr STOP_DELAY ; ori.b #%00000001,PORTE1 ;set I2C_TXD low jsr STOP_DELAY ; andi.b #%11111011,PORTE1 ;release I2C_CLK (open drain) high jsr STOP_DELAY ; andi.b #%11111110,PORTE1 ;release I2C_TXD (open drain) high jsr STOP_DELAY ; bra STOP_RET ; STOP_DELAY moveq #6,d0 ;load loop count (4 times) STOP_DLOOP subq #1,d0 ;decrement bne STOP_DLOOP ;repeat till zero rts ; STOP_RET jsr STOP_DELAY ; ;enable interrupts ;return from C function call #endasm } /****************************************************************************/ /* Write a byte of data. Data is updated only in the I2C data Change (C) */ /* Condition, i.e., while I2C_CLK is low. Data is valid and must be held */ /* in the I2C Data (D) Condition, i.e, when I2C_CLK is high. ACK will be */ /* asserted after the falling edge of SCL on the eighth bit. */ /****************************************************************************/ void I2C_WrByte(unsigned char arg_value) { ; #asm ;disable interrupts move.b %%arg_value,d0 moveq #8,d1 ;number of bits to be shifted out = 8 WR_BYTE ori.b #%00000100,PORTE1 ;set I2C_CLK low roxl.b #1,d0 ;rotate MSB into carry bit bcc WR_ZERO ;test if carry bit is a zero jsr WR_DELAY andi.b #%11111110,PORTE1 ;release I2C_TXD high (open drain) bra WR_CLOCK WR_ZERO jsr WR_DELAY; ori.b #%00000001,PORTE1 ;set I2C_TXD low (open drain) WR_CLOCK jsr WR_DELAY; andi.b #%11111011,PORTE1 ;release I2C_CLK high (open drain) jsr WR_DELAY; subq.b #1,d1 ;decrement d1 and bne WR_BYTE ;check if zero bra WR_RET WR_DELAY nop ;let's make it short nop rts WR_RET ori.b #%00000100,PORTE1 ;set I2C_CLK low for the eighth data bit nop ;I2C_CLK will be low on exit andi.b #%11111110,PORTE1 ;release I2C_TXD for ACK jsr WR_DELAY; ;I2C_TXD will be released on exit ;enable interrupts ;return from C function call #endasm } /****************************************************************************/ /* Read a byte of data. Data is updated only in the I2C data Change (C) */ /* Condition, i.e., while I2C_CLK is low. Data is valid and must be held */ /* in the I2C Data (D) Condition, i.e, when I2C_CLK is high. MSB first. */ /* Presumably, the first bit is already waiting to be read on entry. */ /****************************************************************************/ uchar I2C_RdByte(void) { ; #asm ;disable interrupts move.w #8,a1 ;number of bits to be shifted in = 8 RD_BYTE andi.b #%11111011,PORTE1 ;release I2C_CLK high (open drain) jsr RD_DELAY move.b PORTE1,d1 ;read PORTE roxr.b #2,d1 ;rotate I2C_RXD into carry bit roxl.b #1,d0 ;rotate extend bit into LSB ori.b #%00000100,PORTE1 ;set I2C_CLK low jsr RD_DELAY suba.w #1,a1 ;decrement a1 and cmpa.w #0,a1 ;check if zero, set CC's bne RD_BYTE ;get the next bit bra RD_RET RD_DELAY nop ;let's make it short nop rts RD_RET nop ;I2C_CLK will be low on exit ;enable interrupts ;return from C function call #endasm } /****************************************************************************/ /* Verify I2C Acknowledge (ACK) Condition, which is a HIGH to LOW transition*/ /* of the I2C_RXD line asserted by the SLAVE on the falling edge of bit 8. */ /****************************************************************************/ uchar I2C_RdAck(void) { ; #asm ;disable interrupts andi.b #%11111011,PORTE1 ;release I2C_CLK high (open drain) move.w #$0010,d1 ;load loop count (16 times) ACKLOOP move.b PORTE1,d0 ;read PORTE andi.b #%00000010,d0 ;isolate bit1 (I2C_RXD), mask off rest cmpi.b #0,d0 ;check if I2C_RXD is asserted (low) beq ACKSEEN ;if asserted return TRUE subq #1,d1 ;decrement bne ACKLOOP ;repeat till zero moveq #0,d0 ;return NAK bra ACK_RET ;I2C_CLK will be high on exit ACKSEEN moveq #1,d0 ;return ACK ori.b #%00000100,PORTE1 ;I2C_CLK will be low on exit ACK_RET nop ; #endasm } /****************************************************************************/ /* Assert I2C Acknowledge (ACK) Condition, which is a LOW state on the */ /* I2C_TXD line asserted by the MASTER. */ /****************************************************************************/ void I2C_WrAck(void) { ; #asm ;disable interrupts ori.b #%00000001,PORTE1 ;set I2C_TXD low jsr WRACK_DELAY ; andi.b #%11111011,PORTE1 ;release I2C_CLK (open drain) high jsr WRACK_DELAY ; ori.b #%00000100,PORTE1 ;set I2C_CLK low jsr WRACK_DELAY bra WRACK_RET WRACK_DELAY nop ;let's make it short nop rts WRACK_RET andi.b #%11111110,PORTE1 ;release I2C_TXD #endasm } /****************************************************************************/ /* Assert I2C Acknowledge (NAK) Condition, which is a HIGH state on the */ /* I2C_TXD line asserted by the MASTER. */ /****************************************************************************/ void I2C_WrNak(void) { ; #asm ;disable interrupts andi.b #%11111110,PORTE1 ;release I2C_TXD high (open drain) jsr WRNAK_DELAY ; andi.b #%11111011,PORTE1 ;release I2C_CLK (open drain) high jsr WRNAK_DELAY ; ori.b #%00000100,PORTE1 ;set I2C_CLK low jsr WRNAK_DELAY bra WRNAK_RET WRNAK_DELAY nop ;let's make it short nop rts WRNAK_RET nop #endasm }