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(); } -----------------------------------------------------------------------------------------------------------------------
Sorry, add to split my message into 2 parts Basically, I only use the 24LC16B to test my functions. The 24LC16B is a 16K serial eeprom, consisting of 8 blocks of 256 bytes (16 pages, each page consists of 16 bytes). In main.c, I want to fill the 16K, so I use a loop. ... // initialisation LCD, variables :command,address, value[]={0x12,0xDA,0xE4,…}... error = ERR_ACK_NULL; // error variable to determine if error occurred, and where (display on LCD)
for (block=0; block<=7; block++) { temp = (block<<1) | (CMDWR & MASK_BLOCK); // select block (0 to 7) for (page=0; (page<=0xF0) && (!error); page += 0x10) // select page (0 to 15) { I2C_Start(); I2C_Write(temp); if (I2C_Ack()) { error = ERR_ACK_CONTROL; break; } I2C_Write(page); if (I2C_Ack()) { error = ERR_ACK_ADDRESS; break; } for (i=0; i< sizeof(value) && (i<=0x0F) && (!error); i++) // { I2C_Write(value[i]); if (I2C_Ack()) { error = ERR_ACK_DATA; break; } } I2C_Stop(); Delay(400); // delay to avoid polling end of internal write for seeprom } }
bit I2C_Ack (void) { bit ack_bit; SDA=HIGH; // set pin in read mode 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); }