最近想試一下ARM9下的I2C設備與外掛MCU通信,外掛mcu用的是GD32F407,在把GD32F4的I2C0初始化成從中斷接收模式後,ARM9的i2c讀寫遇到了一點問題,mcu始終沒有進接收中斷,在搜索問題解決方法時瞭解到linux下的I2C設備操作的一些經驗,在這裏記錄一下。
一、linux下I2C設備的設置
i2c通信無非是模式設置、設備地址設置、速率設置,linux下的i2c設備設置操作給出了標準,需要使用ioctl這個函數進行設置,下面就I-MAX287A的ARM板中給的I2C讀寫例程來進行分析。
/*i2c_test.c*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include "iic.h"
#define I2C_ADDR 0x30 //從設備地址 如果單片機的i2c從地址是0x30
#define DATA_LEN 15
#define DEV_NANE "/dev/i2c-1"
int main(void)
{
unsigned int uiRet;
int i;
unsigned char tx_buf[DATA_LEN];
unsigned char rx_buf[DATA_LEN];
unsigned char addr[2] ;
addr[0] = 0x00;
GiFd = open(DEV_NANE, O_RDWR|O_NONBLOCK);
if(GiFd < 0)
perror("open i2c-1\n");
printf("i2c1 open ok\r\n");
//設置i2c的地址位寬,0:7bit addr;1:10bit addr.
uiRet = ioctl(GiFd, I2C_TENBIT, 0);
if (uiRet < 0) {
printf("setenv addr bit faile ret: %x \n", uiRet);
return -1;
}
//設置通信從設備地址
uiRet = ioctl(GiFd, I2C_SLAVE, I2C_ADDR >> 1);
if (uiRet < 0) {
printf("setenv address faile ret: %x \n", uiRet);
return -1;
}
for (i = 0; i < DATA_LEN; i++) //寫將要發送的數據到 發送buf
tx_buf[i] = i+1;
for (i = 0; i < DATA_LEN; i++){ //寫要發送的數據到 24c02
addr[0] = 0x30; //當前地址
write(GiFd, addr, 1); //寫地址
write(GiFd, &tx_buf[i], 1); //寫數據
}
// addr[0] = 0x00; //當前地址
// write(GiFd, addr, 1); //寫地址
// read(GiFd, rx_buf, DATA_LEN); //讀數據
// printf("read from eeprom:");
// for(i = 0; i < DATA_LEN; i++) {
// printf(" %x", rx_buf[i]);
// }
printf("\n");
return 0;
}
/*iic.h*/
#ifndef __I2C_H_
#define __I2C_H_
#define I2C_SLAVE 0x0703
#define I2C_TENBIT 0x0704
int GiFd;
int GiIndex;
int iicOpen();
int waitIRQ();
void waitset();
void setdriverTo500smod();
void setdriverToCOMMmod();
#endif
(1) ioctl函數的使用:
原型:struct ioctl(struct file *file,unsigned int cmd,unsigned long arg);
cmd有I2C_SLAVE,I2C_SLAVE_FORCE,I2C_TENBIT,I2C_SET_SPEED幾個選項;
I2C_SLAVE:對應的arg取值爲I2C從機地址,用來設定I2C從機地址;
I2C_SLAVE_FORCE:對應的arg取值爲I2C從機地址,用來修改I2C從機地址;
I2C_TENBIT:對應的arg取值爲0:從機地址爲7 bit;對應的arg取值爲1:從機地址爲10bit。用來指定I2C從機地址的位數;
I2C_SET_SPEED:對應的arg取值爲I2C總線控制器分頻值。用來設置I2C總線控制器時鐘頻率;
常用設置設置I2c從機地址爲0xA0,如果選用at24c08設備,那麼從機是7 bit地址,所以要右移1位,指定從機地址爲7 bit,
ioctl(fd,I2C_TENBIT,0)。
ioctl(fd,I2C_SLAVE,0xA0>>1);
上面貼的代碼中,沒有I2C_SLAVE_FORCE和I2C_SET_SPEED設置項,這個應該是示例中沒有給出的,I2C_SLAVE 的值爲何是0x0703,暫時沒有找到依據,猜測是驅動裏面給這個值過去後,會將I2C設備的某個寄存器進行相應的設置,I2C_TENBIT也同理。
二、linux下i2c設備的讀寫操作
read()與write()函數的使用
假設子地址爲48,向有子地址的器件寫進7個字節:
unsigned char buf[8]={48,'a','b','c','d','e','f','g');/*第1個字節48爲子地址*/
write(fd,buf,9);/*寫進7個字節,第1個字節爲子地址*/
從有子地址的I2C器件讀取7個字節:
unsigned char suba=0,recbuf[20];
write(fd,buf,1);/*發送子地址0*/
read(fd,recbuf,7);/*從子地址48開始讀取7個字節*/
三、linux下i2c的結束標誌位
linux下I2C做主設備讀寫數據時,結束標誌都由主設備給出,如果發現MCU設備沒有退出I2C中斷,需檢查MCU的I2C中斷配置是否有問題。
四、通信效果