出處:http://blog.csdn.net/zhenwenxian/archive/2011/03/24/6272893.aspx
gpio模擬I2C
I2C是由 Philips公司發明的一種串行數據通信協議,僅使用兩根信號線:SerialClock(簡稱SCL)和SerialData(簡稱SDA)。I2C 是總線結構,1個Master,1個或多個Slave,各Slave設備以7位地址區分,地址後面再跟1位讀寫位,表示讀(=1)或者寫(=0),所以我 們有時也可看到8位形式的設備地址,此時每個設備有讀、寫兩個地址,高7位地址其實是相同的。
I2C數據格式如下:
無數據:SCL=1,SDA=1;
開始位(Start):當SCL=1時,SDA由1向0跳變;
停止位(Stop):當SCL=1時,SDA由0向1跳變;
數據位:當SCL由0向1跳變時,由發送方控制SDA,此時SDA為有效數據,不可隨意改變SDA;
當SCL保持為0時,SDA上的數據可隨意改變;
地址位:定義同數據位,但只由Master發給Slave;
應答位(ACK):當發送方傳送完8位時,發送方釋放SDA,由接收方控制SDA,且SDA=0;
否應答位(NACK):當發送方傳送完8位時,發送方釋放SDA,由接收方控制SDA,且SDA=1。
當數據為單字節傳送時,格式為:
開始位,8位地址位(含1位讀寫位),ACK,8位數據,ACK,停止位。
當數據為一串字節傳送時,格式為:
開始位,8位地址位(含1位讀寫位),ACK,8位數據,應答,8位數據,ACK,……,8位數據,ACK,停止位。
需要注意的是:
例子1I2C數據格式如下:
無數據:SCL=1,SDA=1;
開始位(Start):當SCL=1時,SDA由1向0跳變;
停止位(Stop):當SCL=1時,SDA由0向1跳變;
數據位:當SCL由0向1跳變時,由發送方控制SDA,此時SDA為有效數據,不可隨意改變SDA;
當SCL保持為0時,SDA上的數據可隨意改變;
地址位:定義同數據位,但只由Master發給Slave;
應答位(ACK):當發送方傳送完8位時,發送方釋放SDA,由接收方控制SDA,且SDA=0;
否應答位(NACK):當發送方傳送完8位時,發送方釋放SDA,由接收方控制SDA,且SDA=1。
當數據為單字節傳送時,格式為:
開始位,8位地址位(含1位讀寫位),ACK,8位數據,ACK,停止位。
當數據為一串字節傳送時,格式為:
開始位,8位地址位(含1位讀寫位),ACK,8位數據,應答,8位數據,ACK,……,8位數據,ACK,停止位。
需要注意的是:
- SCL一直由Master控制,SDA依照數據傳送的方向,讀數據時由Slave控制SDA,寫數據時由Master控制SDA。當8位數據傳送完畢之後,應答位或者否應答位的SDA控制權與數據位傳送時相反。
- 開始位「Start」和停止位「Stop」,只能由Master來發出。
- 地址的8位傳送完畢後,成功配置地址的Slave設備必須發送「ACK」。否則否則一定時間之後Master視為超時,將放棄數據傳送,發送「Stop」。
- 當寫數據的時候,Master每發送完8個數據位,Slave設備如果還有空間接受下一個字節應該回答「ACK」,Slave設備如果沒有空間接受更 多的字節應該回答「NACK」,Master當收到「NACK」或者一定時間之後沒收到任何數據將視為超時,此時Master放棄數據傳送,發送 「Stop」。
- 當讀數據的時候,Slave設備每發送完8個數據位,如果Master希望繼續讀下一個字節,Master應該回答「ACK」以提示Slave準備下 一個數據,如果Master不希望讀取更多字節,Master應該回答「NACK」以提示Slave設備準備接收Stop信號。
- 當Master速度過快Slave端來不及處理時,Slave設備可以拉低SCL不放(SCL=0將發生「線與」)以阻止Master發送更多的數據。此時Master將視情況減慢或結束數據傳送。
1,kernel\arch\arm\mach-pxa\board-test.c 增加
/* i2c */
static struct i2c_gpio_platform_data i2c_bus_data = {
.sda_pin = VIPER_RTC_I2C_SDA_GPIO,
.scl_pin = VIPER_RTC_I2C_SCL_GPIO,
.udelay = 10,
.timeout = 100,
};
static struct platform_device i2c_bus_device = {
.name = "i2c-gpio",
.id = 1, /* pxa2xx-i2c is bus 0, so start at 1 */
.dev = {
.platform_data = &i2c_bus_data,
}
};
static struct i2c_board_info __initdata viper_i2c_devices[] = {
{
I2C_BOARD_INFO("ds1338", 0x68),
},
};
第一個結構體中sda_pin和scl_pin是開發板上對應的gpio口 (data線和clock線),udelay是與具體芯片時鐘相關的參數,需要參考具體的datasheet。下面的兩個open_drain是表明兩個 管腳是否是開漏電路,如果是則填1,否則填0。下面一個機構體中需要注意name應該填寫i2c-gpio,另外id要注意設定為2,因為系統當中已經有 兩個I2C設備了。
添加上需要的頭文件:#include <linux/i2c-gpio.h>。在頭文件devices.h中添加上設備結構體的聲明,extern struct platform_device gpio_device_i2c;
然後將gpio_device_i2c放在board-XXXX.c的數組devices中,形式請參考該數組中其他的設備。
static struct platform_device *viper_devs[] __initdata = {
&smc91x_device,
&i2c_bus_device, ///////////////////////////////////////////
&serial_device,
&isp116x_device,
&viper_mtd_devices[0],
&viper_mtd_devices[1],
&viper_backlight_device,
};
static void __init viper_init(void)
{
;
;
;
i2c_register_board_info(1, ARRAY_AND_SIZE(viper_i2c_devices));
;
}
然後再用i2c_register_board_info對其進行註冊:
i2c_register_board_info(2, i2c_gpio_devices, ARRAY_SIZE(i2c_gpio_devices)); 這樣就完成了模擬步驟,可以直接用系統的I2C相關的註冊等方法對設備進行註冊和讀寫操作。
例子2
static struct i2c_gpio_platform_data ep93xx_i2c_data = {
.sda_pin = EP93XX_GPIO_LINE_EEDAT,
.sda_is_open_drain = 0,
.scl_pin = EP93XX_GPIO_LINE_EECLK,
.scl_is_open_drain = 0,
.udelay = 2,
};
static struct platform_device ep93xx_i2c_device = {
.name = "i2c-gpio",
.id = 0,
.dev.platform_data = &ep93xx_i2c_data,
};
void __init ep93xx_register_i2c(struct i2c_board_info *devices, int num)
{
i2c_register_board_info(0, devices, num);
platform_device_register(&ep93xx_i2c_device);
}
沒有留言:
張貼留言