We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
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(); } -----------------------------------------------------------------------------------------------------------------------
"Since I know it takes 2 mc for a call, 1 nop and 2 mc to go back to caller," So you think you know, do you... But what memory model are you using? What Optimisation setting? Even, what compiler version?! All of these do affect the generated code! 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!
"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