Hi, I am trying to use the I2C bus with a 89LV55 MCU. I have 2 devices : a 24LC16B serial eeprom and a digital pot DS1844. The MCU has no built-in facilities for the I2C bus so I created the low level routines for the communications. I believed, from the I2C bus specifications, that these functions should be adequate, but not the way I use them to access the devices. A first question would be how do you put them together ? or how to construct a program... I know I am in trouble ! I have two files : I2C.c with the I2C functions and a definition file I2C.h. The I2C functions are : void I2C_Start(void) // start I2C communication void I2C_Write(unsigned char data_out) // write a byte unsigned char I2C_Read(void) // read a byte bit I2C_Ack (void) // read acknowledge void I2C_NoAck (void) // no acknowledge void I2C_Delay(void) // 5 us delay for low speed (100kHz) void I2C_Stop(void) // stop I2C communication
----------------------------------------------------------------------------------------------------------------------- void I2C_Start(void) { SDA = HIGH; /* Bus idle when SDA and SCK at level HIGH */ SCK = HIGH; I2C_Delay(); SDA = LOW; /* Start condition */ I2C_Delay(); //SCK = LOW; /* I2C_READ and I2C_WRITE */ } ----------------------------------------------------------------------------------------------------------------------- void I2C_Write(unsigned char data_out) { unsigned char position; for (position = 0; position < 8; position++) { SCK = LOW; SDA = ((data_out & 0x80) ? 1 : 0); /* Mask to check the MSB and send 0 or 1 */ SCK = HIGH; I2C_Delay(); data_out <<= 1; /* Shift data */ } } ----------------------------------------------------------------------------------------------------------------------- unsigned char I2C_Read(void) { unsigned char data_in, position; SCK = LOW; SDA = HIGH; /* Set data pin in read mode */ data_in = 0x00; for (position = 0; position < 8; position++) { I2C_Delay(); data_in <<=1; SCK = HIGH; I2C_Delay(); data_in |= SDA; /* Read pin state */ SCK = LOW; } return (data_in); } ----------------------------------------------------------------------------------------------------------------------- bit I2C_Ack (void) { bit ack_bit; SCK = LOW; /* Wait for high state of SCK for the 9th clock cycle */ I2C_Delay(); SCK = HIGH; ack_bit = SDA; /* Read the acknowledge bit */ I2C_Delay(); return (ack_bit); } ----------------------------------------------------------------------------------------------------------------------- void I2C_NoAck (void) { SCK = LOW; /* Wait for high state of SCK for the 9th clock cycle */ SDA = HIGH; /* Set the acknowledge bit */ I2C_Delay(); SCK = HIGH; I2C_Delay(); } ----------------------------------------------------------------------------------------------------------------------- void I2C_Delay(void) // 5 us delay { _nop_(); } ----------------------------------------------------------------------------------------------------------------------- void I2C_Stop(void) { SCK = LOW; SDA = LOW; SCK = HIGH; /* Generate stop condition */ I2C_Delay(); SDA = HIGH; /* Generate stop condition */ I2C_Delay(); } -----------------------------------------------------------------------------------------------------------------------
"With a high-level language like 'C' you have absolutely no guarantee whatsoever that any particular source construct will generate any specific sequence of machine instructions!" Unless you use Keil's language extension _nop_(), which is guaranteed to translate to a single nop. For the delay required in this case this would seem ideal, but do inline them (possibly by encapsulating them in a macro) rather than using a function. Stefan