https://www.marcelpost.com/wiki/index.php?title=I2c-master&feed=atom&action=historyI2c-master - Revision history2024-03-28T23:13:36ZRevision history for this page on the wikiMediaWiki 1.39.5https://www.marcelpost.com/wiki/index.php?title=I2c-master&diff=1372&oldid=prevAdmin: Created page with "These code snippets and functions are intended for an I2C master device. Functions: * address an I2C slave and write data to it * address an I2C slave and read data from it ..."2014-03-16T10:59:49Z<p>Created page with "These code snippets and functions are intended for an I2C master device. Functions: * address an I2C slave and write data to it * address an I2C slave and read data from it ..."</p>
<p><b>New page</b></p><div>These code snippets and functions are intended for an I2C master device. <br />
<br />
Functions:<br />
* address an I2C slave and write data to it<br />
* address an I2C slave and read data from it<br />
<br />
<br />
<br />
==initialisation==<br />
<pre><br />
<br />
// I2C definitions<br />
int LCD_I2C_DEVICE_ID=58;<br />
#define SCL PA4 <br />
#define SDA PA5<br />
<br />
#define I2C_SCL_T_HIGH_US 50<br />
#define I2C_SCL_T_LOW_US 50<br />
<br />
// Testing i2c reads with 24LC256 EEPROM module<br />
#define I2C_EEPROM 0x50 // ID# of eeprom<br />
<br />
int got_ack;<br />
int I2C_STRETCH_TIMEOUT_MS=10; // how long to wait for a slave that's stretching the clock<br />
unsigned int i2c_timeout=65535; // when listening for read replies<br />
<br />
</pre><br />
<br />
<br />
<br />
==functions==<br />
<pre><br />
<br />
// --- I2C Functions ---<br />
// --- I2C Functions ---<br />
// --- I2C Functions ---<br />
<br />
<br />
void setPin(int line, int state)<br />
{<br />
// set the I2C SDA or SCL PIN<br />
<br />
if (state == LOW) // if state = 0 <br />
{<br />
// set the pin low<br />
<br />
DDRA |= (1 << line); // set line to output<br />
PORTA &= ~(1 << line); // set it to zero<br />
<br />
} else {<br />
<br />
// set the pin high (let external pull-up resistor bring it high)<br />
<br />
DDRA &= ~(1 << line); // set line to input<br />
<br />
}<br />
<br />
}<br />
<br />
<br />
void i2c_tx(char d)<br />
{<br />
<br />
// SDA is LOW, SCL is high (inherited from START sequence)<br />
<br />
// 1010 0000 0 0000 00000 0 0001 0101 0 00010<br />
// 80 << 1 W A <br />
<br />
// bring clock low to start data transfer<br />
<br />
setPin(SCL,LOW);<br />
_delay_us(I2C_SCL_T_LOW_US);<br />
<br />
char x;<br />
//static int b;<br />
for(x=8; x; x--) <br />
{ <br />
if(d&0x80) <br />
{<br />
setPin(SDA,HIGH); <br />
<br />
<br />
<br />
} else {<br />
setPin(SDA,LOW); <br />
<br />
}<br />
<br />
setPin(SCL,HIGH); // strobe clock<br />
<br />
<br />
// allow for I2C clock stretching (SCL can be held low by slave)<br />
// see I2C_STRETCH_TIMEOUT_MS<br />
<br />
int stretch_counter;<br />
<br />
for (stretch_counter=0; stretch_counter < I2C_STRETCH_TIMEOUT_MS; stretch_counter++)<br />
{<br />
// allow for some cycles for SCL to go high <br />
<br />
if (bit_is_clear(PINA,SCL))<br />
{<br />
// SCL is held low by slave<br />
// we'll just wait a little <br />
<br />
_delay_us(5);<br />
<br />
} else {<br />
<br />
// SCL has risen, ready to move on<br />
stretch_counter = I2C_STRETCH_TIMEOUT_MS;<br />
}<br />
<br />
<br />
}<br />
<br />
_delay_us(I2C_SCL_T_HIGH_US); // if everything went fine we still need to make sure<br />
setPin(SCL,LOW); // we're waiting at least 4us until we can bring SCL LOW<br />
_delay_us(I2C_SCL_T_LOW_US);<br />
d <<= 1; // shift byte<br />
<br />
}<br />
<br />
// read acknowledge bit if any<br />
<br />
_delay_us(I2C_SCL_T_LOW_US);<br />
setPin(SDA,HIGH); // first bring SDA into listening mode<br />
<br />
<br />
// An addressed i2c slave that wants to set an ACK will have already set SDA low.<br />
// If the slave doesn't respond to the ACK we need to make sure not to see a false<br />
// positive from our own SDA pin<br />
<br />
_delay_us(I2C_SCL_T_HIGH_US); // give the bus some time to possibly bring the pin high<br />
setPin(SCL,HIGH); // start the clock pulse<br />
<br />
// check if slave set an ack on the SDA line or not<br />
if (bit_is_set(PINA,SDA))<br />
{<br />
got_ack=0;<br />
} else {<br />
got_ack=1;<br />
}<br />
<br />
<br />
<br />
//setPin(SDA,LOW); // we now bring SDA low<br />
//_delay_us(10); // give the bus some time to prevent slaves from detecting this as a false stop? ----- may go <br />
<br />
<br />
_delay_us(I2C_SCL_T_HIGH_US); <br />
<br />
setPin(SCL,LOW); // end the clock pulse<br />
<br />
// show ack result here..<br />
<br />
// slave detects SCL is low and will release SDA <br />
<br />
// need an extra bit of delay here for our I2C LCD Module<br />
// _delay_us(100);<br />
_delay_us(I2C_SCL_T_LOW_US); // this should be 10us or so <br />
_delay_us(I2C_SCL_T_LOW_US); // this should be 10us or so <br />
<br />
<br />
<br />
<br />
// -- end of i2c_tx function --<br />
// function ends with:<br />
//<br />
// SDA: HIGH<br />
// SCL: LOW <br />
<br />
<br />
}<br />
<br />
void i2c_start()<br />
{<br />
<br />
// SDA goes from high to low while SCL is high<br />
<br />
// we expect both SDA and SCL to be high<br />
<br />
//_delay_us(500);<br />
//setPin(SDA,HIGH); <br />
//_delay_us(500); // give bus some time to bring SDA high<br />
//setPin(SCL,HIGH);<br />
<br />
//_delay_us(100); <br />
<br />
setPin(SDA,LOW);<br />
_delay_us(I2C_SCL_T_LOW_US); <br />
<br />
}<br />
<br />
<br />
void i2c_write(char i2c_id)<br />
{<br />
<br />
i2c_start();<br />
<br />
// send the I2C Device ID<br />
// send as Write (last bit is 0)<br />
<br />
i2c_tx(i2c_id<<1);<br />
<br />
<br />
}<br />
<br />
void i2c_stop()<br />
{<br />
// SDA goes from low to high while SCL is high<br />
<br />
// we expect SCL to be low but don't know the state of SDA<br />
// therefore we force SCL to be low so we don't accidentally <br />
// generate a .. and then bring down SDA so we begin with<br />
// a known start condition.<br />
<br />
setPin(SCL,LOW);<br />
_delay_us(I2C_SCL_T_LOW_US); // give bus some time to bring SCL LOW<br />
setPin(SDA,LOW); <br />
_delay_us(I2C_SCL_T_LOW_US); // give bus some time to bring SDA LOW<br />
<br />
// initiate STOP sequence<br />
<br />
setPin(SCL,HIGH);<br />
_delay_us(I2C_SCL_T_HIGH_US);<br />
<br />
setPin(SDA,HIGH);<br />
_delay_us(I2C_SCL_T_HIGH_US);<br />
<br />
<br />
}<br />
<br />
void i2c_lcd_text(char *StrData)<br />
{<br />
<br />
int p = 0;<br />
int q = strlen(StrData);<br />
int temp = 0;<br />
<br />
for (p = 0; p < q; p++)<br />
{<br />
temp = StrData[p];<br />
i2c_tx(temp);<br />
}<br />
}<br />
<br />
void i2c_lcd_number(int number)<br />
{<br />
int digits;<br />
<br />
if (number == 0)<br />
{<br />
digits = 0;<br />
int array[0];<br />
array[0]=0;<br />
i2c_tx(array[0]+48);<br />
<br />
} else {<br />
<br />
// determine the number of digits<br />
digits = (int) (log(number)/log(10))+1;<br />
<br />
// split up the number's digits into an array<br />
int i = digits -1;<br />
int array[digits];<br />
while (number > 0)<br />
{<br />
array[i--] = number % 10;<br />
number /= 10;<br />
}<br />
<br />
// send array over i2c<br />
for (i =0; i <= digits-1; i++)<br />
{<br />
i2c_tx(array[i]+48);<br />
}<br />
<br />
}<br />
}<br />
<br />
<br />
void i2c_cls(uint8_t device)<br />
{<br />
// send out Clear LCD command to I2C_LCD device<br />
i2c_write(device); <br />
i2c_tx(12); // blank lcd command<br />
i2c_stop();<br />
}<br />
<br />
void i2c_pos (uint8_t device, uint8_t row, uint8_t col)<br />
{ <br />
// positions the cursor on an I2C_LCD device<br />
i2c_write(device); <br />
i2c_tx(10); // i2c position command<br />
i2c_tx(row); // row position<br />
i2c_tx(col); // col position<br />
i2c_stop(); <br />
}<br />
<br />
void i2c_write_number(uint8_t device, int16_t number)<br />
{<br />
// write a number to an I2C_LCD device<br />
i2c_write(device);<br />
i2c_lcd_number(number);<br />
i2c_stop();<br />
}<br />
<br />
<br />
<br />
unsigned char i2c_rxbyte()<br />
{<br />
<br />
// read a byte from an i2c slave we just addressed with its ID and the register we wish to read<br />
<br />
unsigned char rxbyte=0;<br />
int bitcount=8;<br />
<br />
<br />
// i2c_tx ends with:<br />
// SDA: HIGH<br />
// SCL: LOW<br />
<br />
<br />
// the ic2_tx command lastly sent the ack pulse and now has SDA and SCL set to LOW<br />
// we now control the read from the i2c slave device by pulsing SCL and reading SDA <br />
<br />
<br />
while (bitcount > 0)<br />
{ <br />
<br />
rxbyte = rxbyte << 1; // shift all bits in rxbyte one position to the left<br />
<br />
setPin(SCL,HIGH); // start the clock pulse<br />
_delay_us(I2C_SCL_T_HIGH_US); // give the bus some time to possibly bring the pin high<br />
<br />
if (bit_is_set(PINA,SDA))<br />
{<br />
// -- detected bit '1' --<br />
rxbyte |= 1 << 0 ; // sets bit 0 of rxbyte to 1<br />
<br />
} else {<br />
// -- detected bit '0' --<br />
<br />
}<br />
setPin(SCL,LOW); // stop the clock pulse<br />
_delay_us(I2C_SCL_T_LOW_US); // give the bus some time to possibly bring the pin high<br />
<br />
bitcount--; // decrement bitcounter<br />
<br />
}<br />
<br />
<br />
<br />
// send ack clock pulse<br />
<br />
setPin(SCL,HIGH); // start the clock pulse<br />
_delay_us(I2C_SCL_T_HIGH_US); <br />
setPin(SCL,LOW); // stop the clock pulse<br />
_delay_us(I2C_SCL_T_HIGH_US);<br />
<br />
<br />
return rxbyte;<br />
}<br />
<br />
<br />
unsigned char i2c_read(uint8_t i2c_id, uint16_t DEV_REG)<br />
{<br />
<br />
// reading a register from an eeprom device<br />
<br />
unsigned char read_result=0;<br />
<br />
i2c_id = i2c_id<<1; // shift all bits one position to the left (i.e. multiply by 2)<br />
<br />
// send start sequence<br />
i2c_start();<br />
<br />
// send the I2C Device ID with the R/W bit low (send as Write, last bit is 0)<br />
i2c_tx(i2c_id); <br />
<br />
//_delay_us(10); <br />
<br />
// send the register we want to query to the device<br />
<br />
// for the 74LC256 we need to do this in two goes. First the MSB then the LSB<br />
<br />
i2c_tx(DEV_REG >> 8); // MSB<br />
<br />
i2c_tx(DEV_REG & 0xFF); // LSB<br />
<br />
// i2c_tx alread has a delay at the end<br />
// i2c_tx ends with:<br />
// SDA: HIGH<br />
// SCL: LOW<br />
<br />
<br />
// -- send repeated start --<br />
// in order to generate a valid repeated-start we must make sure SCL is high<br />
//setPin(SCL,HIGH);<br />
//_delay_us(10);<br />
<br />
// -- or --<br />
<br />
// send stop <br />
i2c_stop();<br />
<br />
<br />
_delay_us(I2C_SCL_T_LOW_US);<br />
<br />
// send start sequence again<br />
i2c_start();<br />
// i2c_start ends with:<br />
// SDA: LOW<br />
// SCL: HIGH<br />
// i2c_tx will bring SDA low again in order to start a valid transmission <br />
<br />
// send the I2C Device ID with the R/W bit high (send as Read, last bit is 1)<br />
i2c_id |= 1 << 0; // set bit 0 to 1<br />
i2c_tx(i2c_id); <br />
// i2c_tx ends with:<br />
// SDA: HIGH<br />
// SCL: LOW<br />
<br />
<br />
// read data from device, one byte long<br />
read_result=i2c_rxbyte(); <br />
<br />
i2c_stop();<br />
<br />
<br />
return read_result;<br />
}<br />
<br />
// -- end I2C functions --<br />
// -- end I2C functions --<br />
// -- end I2C functions --<br />
</pre><br />
<br />
<br />
<br />
==usage==<br />
<pre><br />
int main()<br />
{<br />
<br />
setPin(SDA,HIGH);<br />
setPin(SCL,HIGH);<br />
<br />
uint8_t eeadr=0;<br />
int getvalue=0;<br />
<br />
while (eeadr < 25)<br />
{<br />
<br />
getvalue=i2c_read(I2C_EEPROM,eeadr);<br />
<br />
Write_Serial_Number(eeadr);<br />
Write_Serial_Data(',');<br />
<br />
Write_Serial_Number(getvalue);<br />
Write_Serial_Text(crlf); // crlf<br />
<br />
eeadr++;<br />
}<br />
}<br />
</pre></div>Admin