455 lines
12 KiB
Markdown
455 lines
12 KiB
Markdown
# I2C设备
|
||
|
||
[English](i2c_EN.md)
|
||
|
||
<!-- TOC -->
|
||
* [I2C设备](#i2c设备)
|
||
* [注册I2C设备](#注册i2c设备)
|
||
* [打开I2C设备](#打开i2c设备)
|
||
* [关闭I2C设备](#关闭i2c设备)
|
||
* [控制I2C设备](#控制i2c设备)
|
||
* [设置/获取I2C设备配置](#设置获取i2c设备配置)
|
||
* [设置/获取寄存器值](#设置获取寄存器值)
|
||
* [设置/获取读缓冲区大小](#设置获取读缓冲区大小)
|
||
* [清空读缓冲区](#清空读缓冲区)
|
||
* [获取读缓冲区数据大小](#获取读缓冲区数据大小)
|
||
* [设置/获取读回调函数](#设置获取读回调函数)
|
||
* [读取I2C设备数据](#读取i2c设备数据)
|
||
* [写入I2C设备数据](#写入i2c设备数据)
|
||
* [使用示例:](#使用示例)
|
||
* [软件I2C](#软件i2c)
|
||
* [注册软件I2C总线](#注册软件i2c总线)
|
||
<!-- TOC -->
|
||
|
||
## 注册I2C设备
|
||
|
||
```c
|
||
int mr_i2c_dev_register(struct mr_i2c_dev *i2c_dev, const char *path, int addr, int addr_bits);
|
||
```
|
||
|
||
| 参数 | 描述 |
|
||
|-----------|------------|
|
||
| i2c_dev | I2C设备结构体指针 |
|
||
| path | 设备路径 |
|
||
| addr | 设备地址 |
|
||
| addr_bits | 设备地址位数 |
|
||
| **返回值** | |
|
||
| `=0` | 注册成功 |
|
||
| `<0` | 错误码 |
|
||
|
||
- `path`:I2C设备要绑定到指定的I2C总线,路径需要加上总线,例如:`i2cx/dev-name`, `i2c1/i2c10`。
|
||
- `addr`:设备地址(最低位为读写位,请传入向左移位后的地址)。作为主机时,地址为对方地址,作为从机时,地址为自身地址。
|
||
- `addr_bits`:设备地址位数:
|
||
- `MR_I2C_ADDR_BITS_7`:7位地址。
|
||
- `MR_I2C_ADDR_BITS_10`:10位地址。
|
||
|
||
## 打开I2C设备
|
||
|
||
```c
|
||
int mr_dev_open(const char *path, int flags);
|
||
```
|
||
|
||
| 参数 | 描述 |
|
||
|---------|---------|
|
||
| path | 设备路径 |
|
||
| flags | 打开设备的标志 |
|
||
| **返回值** | |
|
||
| `>=0` | 设备描述符 |
|
||
| `<0` | 错误码 |
|
||
|
||
- `path`:I2C设备路径,例如:`i2cx/dev-name`,`i2c1/i2c10`。
|
||
- `flags`:打开设备的标志,支持 `MR_O_RDONLY`、 `MR_O_WRONLY`、 `MR_O_RDWR`。
|
||
|
||
注:使用时应根据实际情况为不同的任务分别打开I2C设备,并使用适当的`flags`进行管理和权限控制,以确保它们不会相互影响。
|
||
|
||
## 关闭I2C设备
|
||
|
||
```c
|
||
int mr_dev_close(int desc);
|
||
```
|
||
|
||
| 参数 | 描述 |
|
||
|---------|-------|
|
||
| desc | 设备描述符 |
|
||
| **返回值** | |
|
||
| `=0` | 关闭成功 |
|
||
| `<0` | 错误码 |
|
||
|
||
## 控制I2C设备
|
||
|
||
```c
|
||
int mr_dev_ioctl(int desc, int cmd, void *args);
|
||
```
|
||
|
||
| 参数 | 描述 |
|
||
|---------|-------|
|
||
| desc | 设备描述符 |
|
||
| cmd | 命令码 |
|
||
| args | 命令参数 |
|
||
| **返回值** | |
|
||
| `=0` | 设置成功 |
|
||
| `<0` | 错误码 |
|
||
|
||
- `cmd`:命令码,支持以下命令:
|
||
- `MR_IOC_I2C_SET_CONFIG`: 设置I2C设备配置。
|
||
- `MR_IOC_I2C_SET_REG`: 设置寄存器值。
|
||
- `MR_IOC_I2C_SET_RD_BUFSZ`: 设置读缓冲区大小。
|
||
- `MR_IOC_I2C_CLR_RD_BUF`: 清空读缓冲区。
|
||
- `MR_IOC_I2C_SET_RD_CALL`:设置读回调函数。
|
||
- `MR_IOC_I2C_GET_CONFIG`: 获取I2C设备配置。
|
||
- `MR_IOC_I2C_GET_REG`: 获取寄存器值。
|
||
- `MR_IOC_I2C_GET_RD_BUFSZ`: 获取读缓冲区大小。
|
||
- `MR_IOC_I2C_GET_RD_DATASZ`: 获取读缓冲区数据大小。
|
||
- `MR_IOC_I2C_GET_RD_CALL`:获取读回调函数。
|
||
|
||
### 设置/获取I2C设备配置
|
||
|
||
I2C设备配置:
|
||
|
||
- `baud_rate`:波特率。
|
||
- `host_slave`:主机/从机模式。
|
||
- `reg_bits`:寄存器位数。
|
||
|
||
```c
|
||
/* 设置默认配置 */
|
||
struct mr_i2c_config config = MR_I2C_CONFIG_DEFAULT;
|
||
|
||
/* 设置I2C设备配置 */
|
||
mr_dev_ioctl(ds, MR_IOC_I2C_SET_CONFIG, &config);
|
||
/* 获取I2C设备配置 */
|
||
mr_dev_ioctl(ds, MR_IOC_I2C_GET_CONFIG, &config);
|
||
```
|
||
|
||
不依赖I2C接口:
|
||
|
||
```c
|
||
/* 设置默认配置 */
|
||
int config[] = {100000, 0, 8};
|
||
|
||
/* 设置I2C设备配置 */
|
||
mr_dev_ioctl(ds, MR_IOC_SCFG, &config);
|
||
/* 获取I2C设备配置 */
|
||
mr_dev_ioctl(ds, MR_IOC_GCFG, &config);
|
||
```
|
||
|
||
注:
|
||
|
||
- 如未手动配置,默认配置为:
|
||
- 波特率:`100000`
|
||
- 主机/从机模式:`MR_I2C_HOST`
|
||
- 寄存器位数:`MR_I2C_REG_BITS_8`
|
||
- 当I2C总线上有I2C设备被配置成从机模式后,其将持续占用I2C总线,此时其余I2C设备无法进行读写等操作,直至从机模式I2C设备被重新配置为主机模式。
|
||
|
||
### 设置/获取寄存器值
|
||
|
||
寄存器值将在读取和写入数据前被优先写入(范围:`0` ~ `INT32_MAX`)。
|
||
|
||
```c
|
||
/* 设置寄存器值 */
|
||
mr_dev_ioctl(ds, MR_IOC_I2C_SET_REG, MR_MAKE_LOCAL(int, 0x12));
|
||
|
||
/* 获取寄存器值 */
|
||
uint8_t reg;
|
||
mr_dev_ioctl(ds, MR_IOC_I2C_GET_REG, ®);
|
||
```
|
||
|
||
不依赖I2C接口:
|
||
|
||
```c
|
||
/* 设置寄存器值 */
|
||
mr_dev_ioctl(ds, MR_IOC_SPOS, MR_MAKE_LOCAL(int, 0x12));
|
||
|
||
/* 获取寄存器值 */
|
||
uint8_t reg;
|
||
mr_dev_ioctl(ds, MR_IOC_GPOS, ®);
|
||
```
|
||
|
||
注:
|
||
|
||
- 寄存器值仅在主机模式下生效。
|
||
- 设为负数时不生效。
|
||
- 寄存器值不计入读写大小。
|
||
|
||
### 设置/获取读缓冲区大小
|
||
|
||
```c
|
||
size_t size = 256;
|
||
|
||
/* 设置读缓冲区大小 */
|
||
mr_dev_ioctl(ds, MR_IOC_I2C_SET_RD_BUFSZ, &size);
|
||
/* 获取读缓冲区大小 */
|
||
mr_dev_ioctl(ds, MR_IOC_I2C_GET_RD_BUFSZ, &size);
|
||
```
|
||
|
||
不依赖I2C接口:
|
||
|
||
```c
|
||
size_t size = 256;
|
||
|
||
/* 设置读缓冲区大小 */
|
||
mr_dev_ioctl(ds, MR_IOC_SRBSZ, &size);
|
||
/* 获取读缓冲区大小 */
|
||
mr_dev_ioctl(ds, MR_IOC_GRBSZ, &size);
|
||
```
|
||
|
||
注:如未手动配置,将使用 `Kconfig`中配置的大小(默认为32Byte)。只有在从机模式下才使用读缓冲区。
|
||
|
||
### 清空读缓冲区
|
||
|
||
```c
|
||
mr_dev_ioctl(ds, MR_IOC_I2C_CLR_RD_BUF, MR_NULL);
|
||
```
|
||
|
||
不依赖I2C接口:
|
||
|
||
```c
|
||
mr_dev_ioctl(ds, MR_IOC_CRBD, MR_NULL);
|
||
```
|
||
|
||
### 获取读缓冲区数据大小
|
||
|
||
```c
|
||
size_t size = 0;
|
||
|
||
/* 获取读缓冲区数据大小 */
|
||
mr_dev_ioctl(ds, MR_IOC_I2C_GET_RD_DATASZ, &size);
|
||
```
|
||
|
||
不依赖I2C接口:
|
||
|
||
```c
|
||
size_t size = 0;
|
||
|
||
/* 获取读缓冲区数据大小 */
|
||
mr_dev_ioctl(ds, MR_IOC_GRBDSZ, &size);
|
||
```
|
||
|
||
### 设置/获取读回调函数
|
||
|
||
```c
|
||
/* 定义回调函数 */
|
||
void fn(int desc, void *args)
|
||
{
|
||
/* 获取缓冲区数据大小 */
|
||
ssize_t data_size = *(ssize_t *)args;
|
||
|
||
/* 处理中断 */
|
||
}
|
||
void (*callback)(int desc, void *args);
|
||
|
||
/* 设置读回调函数 */
|
||
mr_dev_ioctl(ds, MR_IOC_I2C_SET_RD_CALL, &fn);
|
||
/* 获取读回调函数 */
|
||
mr_dev_ioctl(ds, MR_IOC_I2C_GET_RD_CALL, &callback);
|
||
```
|
||
|
||
不依赖I2C接口:
|
||
|
||
```c
|
||
/* 定义回调函数 */
|
||
void fn(int desc, void *args)
|
||
{
|
||
/* 获取缓冲区数据大小 */
|
||
ssize_t data_size = *(ssize_t *)args;
|
||
|
||
/* 处理中断 */
|
||
}
|
||
void (*callback)(int desc, void *args);
|
||
|
||
/* 设置读回调函数 */
|
||
mr_dev_ioctl(ds, MR_IOC_SRCB, &fn);
|
||
/* 获取读回调函数 */
|
||
mr_dev_ioctl(ds, MR_IOC_GRCB, &callback);
|
||
```
|
||
|
||
## 读取I2C设备数据
|
||
|
||
```c
|
||
ssize_t mr_dev_read(int desc, void *buf, size_t count);
|
||
```
|
||
|
||
| 参数 | 描述 |
|
||
|---------|---------|
|
||
| desc | 设备描述符 |
|
||
| buf | 读取数据缓冲区 |
|
||
| count | 读取数据大小 |
|
||
| **返回值** | |
|
||
| `>=0` | 读取数据大小 |
|
||
| `<0` | 错误码 |
|
||
|
||
```c
|
||
uint8_t buf[128];
|
||
/* 读取I2C设备数据 */
|
||
ssize_t size = mr_dev_read(ds, buf, sizeof(buf));
|
||
/* 是否读取成功 */
|
||
if (size < 0)
|
||
{
|
||
|
||
}
|
||
```
|
||
|
||
注:
|
||
|
||
- 主机模式下,将使用轮询方式同步读取数据。从机模式下,从读缓冲区读取指定数量的数据(返回实际读取的数据大小)。
|
||
- 当寄存器参数不为负数时,将在读取操作前插入寄存器值的写入操作。
|
||
|
||
## 写入I2C设备数据
|
||
|
||
```c
|
||
ssize_t mr_dev_write(int desc, const void *buf, size_t count);
|
||
```
|
||
|
||
| 参数 | 描述 |
|
||
|---------|---------|
|
||
| desc | 设备描述符 |
|
||
| buf | 写入数据缓冲区 |
|
||
| count | 写入数据大小 |
|
||
| **返回值** | |
|
||
| `>=0` | 写入数据大小 |
|
||
| `<0` | 错误码 |
|
||
|
||
```c
|
||
uint8_t buf[] = {0x01, 0x02, 0x03, 0x04};
|
||
/* 写入I2C设备数据 */
|
||
ssize_t size = mr_dev_write(ds, buf, sizeof(buf));
|
||
/* 是否写入成功 */
|
||
if (size < 0)
|
||
{
|
||
|
||
}
|
||
```
|
||
|
||
注:当寄存器参数不为负数时,将在写入操作前插入寄存器值的写入操作。
|
||
|
||
## 使用示例:
|
||
|
||
```c
|
||
#include "include/mr_lib.h"
|
||
|
||
/* 定义I2C设备 */
|
||
struct mr_i2c_dev host_dev;
|
||
struct mr_i2c_dev slave_dev;
|
||
|
||
/* 定义I2C设备描述符 */
|
||
int host_ds = -1;
|
||
int slave_ds = -1;
|
||
|
||
void i2c_init(void)
|
||
{
|
||
int ret = MR_EOK;
|
||
|
||
/* 注册I2C-HOST设备 */
|
||
ret = mr_i2c_dev_register(&host_dev, "i2c1/host", 0x62, MR_I2C_ADDR_BITS_7);
|
||
if (ret < 0)
|
||
{
|
||
mr_printf("host i2c device register failed: %d\r\n", mr_strerror(ret));
|
||
return;
|
||
}
|
||
|
||
/* 注册I2C-SLAVE设备 */
|
||
ret = mr_i2c_dev_register(&slave_dev, "i2c2/slave", 0x62, MR_I2C_ADDR_BITS_7);
|
||
if (ret < 0)
|
||
{
|
||
mr_printf("slave i2c device register failed: %d\r\n", mr_strerror(ret));
|
||
return;
|
||
}
|
||
|
||
/* 打开I2C-HOST设备 */
|
||
host_ds = mr_dev_open("i2c1/host", MR_O_RDWR);
|
||
if (host_ds < 0)
|
||
{
|
||
mr_printf("host i2c device open failed: %d\r\n", mr_strerror(ret));
|
||
return;
|
||
}
|
||
/* 设置寄存器值 */
|
||
mr_dev_ioctl(host_ds, MR_IOC_I2C_SET_REG, MR_MAKE_LOCAL(int, 0x12));
|
||
|
||
/* 打开I2C-SLAVE设备 */
|
||
slave_ds = mr_dev_open("i2c2/slave", MR_O_RDWR);
|
||
if (slave_ds < 0)
|
||
{
|
||
mr_printf("slave i2c device open failed: %d\r\n", mr_strerror(ret));
|
||
return;
|
||
}
|
||
/* 设置为从机模式 */
|
||
struct mr_i2c_config config = MR_I2C_CONFIG_DEFAULT;
|
||
config.host_slave = MR_I2C_SLAVE;
|
||
ret = mr_dev_ioctl(slave_ds, MR_IOC_I2C_SET_CONFIG, &config);
|
||
if (ret < 0)
|
||
{
|
||
mr_printf("slave i2c device set config failed: %d\r\n", mr_strerror(ret));
|
||
}
|
||
}
|
||
/* 导出到自动初始化(APP级) */
|
||
MR_INIT_APP_EXPORT(i2c_init);
|
||
|
||
int main(void)
|
||
{
|
||
/* 自动初始化(i2c_init函数将在此处自动调用) */
|
||
mr_auto_init();
|
||
|
||
/* 发送测试数据 */
|
||
uint8_t wr_buf[] = {0x01, 0x02, 0x03, 0x04};
|
||
mr_dev_write(host_ds, wr_buf, sizeof(wr_buf));
|
||
|
||
/* 接收测试数据 */
|
||
uint8_t rd_buf[128];
|
||
mr_dev_read(slave_ds, rd_buf, sizeof(rd_buf));
|
||
|
||
/* 比较寄存器值 */
|
||
if (rd_buf[0] == 0x12)
|
||
{
|
||
/* 比较数据 */
|
||
if (memcmp(wr_buf, (rd_buf + 1), sizeof(wr_buf)) == 0)
|
||
{
|
||
mr_printf("i2c test success\r\n");
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
while (1)
|
||
{
|
||
|
||
}
|
||
}
|
||
```
|
||
|
||
将I2C1与I2C2相接,进行收发测试。I2C1作为主机,I2C2作为从机。I2C2将接收到的数据与发送的数据进行比较。
|
||
由于设置了寄存器值,故在写入数据前,先接收到了寄存器值,然后才是写入的数据。
|
||
|
||
## 软件I2C
|
||
|
||
注:软件I2C需使能PIN设备。
|
||
|
||
### 注册软件I2C总线
|
||
|
||
```c
|
||
int mr_soft_i2c_bus_register(struct mr_soft_i2c_bus *soft_i2c_bus, const char *path, int scl_pin, int sda_pin);
|
||
```
|
||
|
||
| 参数 | 描述 |
|
||
|--------------|--------------|
|
||
| soft_i2c_bus | 软件I2C总线结构体指针 |
|
||
| path | 总线 |
|
||
| scl_pin | SCL引脚编号 |
|
||
| sda_pin | SDA引脚编号 |
|
||
| **返回值** | |
|
||
| `=0` | 注册成功 |
|
||
| `<0` | 错误码 |
|
||
|
||
```c
|
||
/* 定义软件I2C总线SCL、SDA引脚编号 */
|
||
#define SCL_PIN_NUMBER 0
|
||
#define SDA_PIN_NUMBER 1
|
||
|
||
/* 定义软件I2C总线 */
|
||
struct mr_soft_i2c_bus soft_i2c_bus;
|
||
|
||
/* 注册软件I2C总线 */
|
||
mr_soft_i2c_bus_register(&soft_i2c_bus, "i2c1", SCL_PIN_NUMBER, SDA_PIN_NUMBER);
|
||
```
|
||
|
||
注册完成后,软件I2C总线将模拟成硬件I2C。
|
||
|
||
注:软件I2C总线仅支持主机模式。
|