Gpio模拟i2c总线对24c02进行读写

时间:2021-06-06 17:52:43

作者:华清远见讲师

使用资料:i2c总线时序手册、24c02手册及ARM主芯片的datasheet

一、通过原理图查看i2c的sda/scl两个引脚连接到ARM主芯片的哪两个GPIO口,以我现在使用的单板为例,如下图

Gpio模拟i2c总线对24c02进行读写

从此图可以看出连接的GPIO口为9_3、9_2两个引脚。

二、通过控制GPIO高低电平来模拟I2C的时序完成总线驱动

首先通过i2c时序手册可以查看到如下图的一个时序

Gpio模拟i2c总线对24c02进行读写

使用gpio9_2 和gpio9_3两个引脚来模拟sda/scl的时序,核心代码如下:

Gpioi2c.c

#define SCL (1 <<3) /* GPIO 9_3 */

#define SDA (1 << 2) /* GPIO 9_2 */

#define GPIO_I2C_SDA_REG (GPIO_9_BASE + 0x10)

#define GPIO_I2C_SCL_REG (GPIO_9_BASE + 0x20)

#define GPIO_I2C_SCLSDA_REG (GPIO_0_BASE + 0x30)

#define HW_REG(reg) *((volatile unsigned int *)(reg))

/*

* I2C by GPIO simulated read data routine.

*

* @return value: a bit for read

*

*/

static unsigned char i2c_data_read(void)

{

unsigned char regvalue;

regvalue = HW_REG(GPIO_9_DIR);

regvalue &= (~SDA);

HW_REG(GPIO_9_DIR) = regvalue;

DELAY(1);

regvalue = HW_REG(GPIO_I2C_SDA_REG);

if((regvalue&SDA) != 0)

return 1;

else

return 0;

}

/*

* sends a start bit via I2C rountine.

*

*/

static void i2c_start_bit(void)

{

DELAY(1);

i2c_set(SDA | SCL);

DELAY(1);

i2c_clr(SDA);

DELAY(2);

}

/*

* sends a stop bit via I2C rountine.

*

*/

static void i2c_stop_bit(void)

{

/* clock the ack */

DELAY(1);

i2c_set(SCL);

DELAY(1);

i2c_clr(SCL);

/* actual stop bit */

DELAY(1);

i2c_clr(SDA);

DELAY(1);

i2c_set(SCL);

DELAY(1);

i2c_set(SDA);

DELAY(1);

}

/*

* sends a character over I2C rountine.

*

* @param c: character to send

*

*/

static void i2c_send_byte(unsigned char c)

{

int i;

// local_irq_disable();

for (i=0; i<8; i++)

{

DELAY(1);

i2c_clr(SCL);

DELAY(1);

if (c & (1<<(7-i)))

i2c_set(SDA);

else

i2c_clr(SDA);

DELAY(1);

i2c_set(SCL);

DELAY(1);

i2c_clr(SCL);

}

DELAY(1);

// i2c_set(SDA);

// local_irq_enable();

}

/* receives a character from I2C rountine.

*

* @return value: character received

*

*/

static unsigned char i2c_receive_byte(void)

{

int j=0;

int i;

unsigned char regvalue;

// local_irq_disable();

for (i=0; i<8; i++)

{

DELAY(1);

i2c_clr(SCL);

DELAY(2);

i2c_set(SCL);

regvalue = HW_REG(GPIO_9_DIR);

regvalue &= (~SDA);

HW_REG(GPIO_9_DIR) = regvalue;

DELAY(1);

if (i2c_data_read())

j+=(1<<(7-i));

DELAY(1);

i2c_clr(SCL);

}

// local_irq_enable();

DELAY(1);

// i2c_clr(SDA);

// DELAY(1);

return j;

}

/* receives an acknowledge from I2C rountine.

*

* @return value: 0--Ack received; 1--Nack received

*

*/

static int i2c_receive_ack(void)

{

int nack;

unsigned char regvalue;

DELAY(1);

regvalue = HW_REG(GPIO_9_DIR);

regvalue &= (~SDA);

HW_REG(GPIO_9_DIR) = regvalue;

DELAY(1);

i2c_clr(SCL);

DELAY(1);

i2c_set(SCL);

DELAY(1);

nack = i2c_data_read();

DELAY(1);

i2c_clr(SCL);

DELAY(1);

// i2c_set(SDA);

// DELAY(1);

if (nack == 0)

return 1;

return 0;

}

EXPORT_SYMBOL(gpio_i2c_read);

unsigned char gpio_i2c_read(unsigned char devaddress, unsigned char address)

{

int rxdata;

i2c_start_bit();

i2c_send_byte((unsigned char)(devaddress));

i2c_receive_ack();

i2c_send_byte(address);

i2c_receive_ack();

i2c_start_bit();

i2c_send_byte((unsigned char)(devaddress) | 1);

i2c_receive_ack();

rxdata = i2c_receive_byte();

//i2c_send_ack();

i2c_stop_bit();

return rxdata;

}

EXPORT_SYMBOL(gpio_i2c_write);

void gpio_i2c_write(unsigned char devaddress, unsigned char address, unsigned char data)

{

i2c_start_bit();

i2c_send_byte((unsigned char)(devaddress));

i2c_receive_ack();

i2c_send_byte(address);

i2c_receive_ack();

i2c_send_byte(data);

// i2c_receive_ack();//add by hyping for tw2815

i2c_stop_bit();

}

三、编写测试程序i2c_read/i2c_write工具调用gpio_i2c_write/read操作24c02的基地址,基地址通过原理图来查看地址是为0xa0-0xae(这个地址是通过24c02的手册查看)中的哪一个,测试通过后进行24c02驱动的接口编写,若不通过需要查看sda/scl两根引脚是否正常上拉,连接是否有问题等。

Gpio模拟i2c总线对24c02进行读写从上面的原理图可以看出A0-A2均为接地,所以A0-A2的值全为0,再根据24c02的手册可以查出下图的slave address,值为0xa0。
Gpio模拟i2c总线对24c02进行读写
四、编写24c02接口,并完成整个驱动的调试。