使用資料:i2c總線時序手冊、24c02手冊及ARM主芯片的datasheet
一、通過原理圖查看i2c的sda/scl兩個引腳連接到ARM主芯片的哪兩個GPIO口,以我現在使用的單板為例,如下圖
從此圖可以看出連接的GPIO口為9_3、9_2兩個引腳。
二、通過控制GPIO高低電平來模擬I2C的時序完成總線驅動
首先通過i2c時序手冊可以查看到如下圖的一個時序
使用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兩根引腳是否正常上拉,連接是否有問題等。
從上面的原理圖可以看出A0-A2均為接地,所以A0-A2的值全為0,再根據24c02的手冊可以查出下圖的slave address,值為0xa0。
四、編寫24c02接口,并完成整個驅動的調試。