Github
整个RTT学习过程中对工程的完善和开发都记录在Github上的一个项目中,项目还会随着学习的深入进行更新
项目URL:https://github.com/HITLIVING/-RT-Thread-.git
读者可以通过Pull下来整个项目进一步了解
对I2C驱动的实现需要格外关注drv_mpu6050.c
drv_mpu6050.h
两个文件
外设配置
STM32F1RCT6芯片
MPU6050模块
Cube
由于使用的是模拟I2C,不需要使用独特的板上资源,仅需两个通用IO口即可,因此这里不需要对Cube有额外操作
Kconfig
menuconfig BSP_USING_I2C1
bool "Enable I2C1 BUS (software simulation)"
default n
select RT_USING_I2C
select RT_USING_I2C_BITOPS
select RT_USING_PIN
if BSP_USING_I2C1
comment "Notice: PA2 --> 2; PA3 --> 3"
config BSP_I2C1_SCL_PIN
int "I2C1 scl pin number"
range 1 50
default 2
config BSP_I2C1_SDA_PIN
int "I2C1 sda pin number"
range 1 50
default 3
endif
这样配置后,即可以通过Env将I2C的SCL和SDA与特定的引脚(pin设备引脚号)对应
这里使用的是PA2和PA3,可以通过文件 drv_gpio.c
查到对应的设备号为2和3
Env
Kconfig完成配置后,即可在Env中看到关于I2C的设备驱动选项,使能设备,并填入对应的pin设备号后,保存退出
使用 scons
指令生成MDK5工程
MDK
即可以看到工程树下完成了对I2C驱动文件的添加
同时通过查看 rtconfig.h
文件
添加了我们在Kconfig中写好的定义
从中也可以认识到Env工具的实质:
- 用Kconfig文件配置Env菜单界面和一些配置选项
- Env中打开或关闭选项,并根据选项添加相关设备的宏定义
- 根据宏定义的内容在工程树下添加外设驱动的文件
到这里对模拟I2C外设的驱动完成
接口函数
查找 I2C 总线设备
在使用 I2C 总线设备前需要根据 I2C 总线设备名称获取设备句柄,进而才可以操作 I2C 总线设备,查找设备函数如下所示,
rt_device_t rt_device_find(const char* name);
参数 | 描述 |
---|---|
name | I2C 总线设备名称 |
返回 | —— |
设备句柄 | 查找到对应设备将返回相应的设备句柄 |
RT_NULL | 没有找到相应的设备对象 |
一般情况下,注册到系统的 I2C 设备名称为 i2c0 ,i2c1等,按照之前配置这里使用的是”i2c1”总线
数据传输
获取到 I2C 总线设备句柄就可以使用 rt_i2c_transfer()
进行数据传输。函数原型如下所示
:
rt_size_t rt_i2c_transfer(struct rt_i2c_bus_device *bus,
struct rt_i2c_msg msgs[],
rt_uint32_t num);
参数 | 描述 |
---|---|
bus | I2C 总线设备句柄 |
msgs[] | 待传输的消息数组指针 |
num | 消息数组的元素个数 |
返回 | —— |
消息数组的元素个数 | 成功 |
错误码 | 失败 |
I2C 总线的自定义传输接口传输的数据也是以一个消息为单位。参数 msgs[] 指向待传输的消息数组,用户可以自定义每条消息的内容,实现 I2C 总线所支持的 2 种不同的数据传输模式。如果主设备需要发送重复开始条件,则需要发送 2 个消息。
注:此函数会调用 rt_mutex_take(), 不能在中断服务程序里面调用,会导致 assertion 报错。
I2C 消息数据结构原型如下:
struct rt_i2c_msg
{
rt_uint16_t addr; /* 从机地址 */
rt_uint16_t flags; /* 读、写标志等 */
rt_uint16_t len; /* 读写数据字节数 */
rt_uint8_t *buf; /* 读写数据缓冲区指针 */
}
从机地址 addr:支持 7 位和 10 位二进制地址,需查看不同设备的数据手册 。
RT-Thread I2C 设备接口使用的从机地址均不包含读写位,读写位控制需修改标志 flags。
标志 flags 可取值为以下宏定义,根据需要可以与其他宏使用位运算 “|” 组合起来使用。
#define RT_I2C_WR 0x0000 /* 写标志 */
#define RT_I2C_RD (1u << 0) /* 读标志 */
#define RT_I2C_ADDR_10BIT (1u << 2) /* 10 位地址模式 */
#define RT_I2C_NO_START (1u << 4) /* 无开始条件 */
#define RT_I2C_IGNORE_NACK (1u << 5) /* 忽视 NACK */
#define RT_I2C_NO_READ_ACK (1u << 6) /* 读的时候不发送 ACK */
发送数据
此函数其实是对传输函数进行了一层封装,函数原型如下:
rt_size_t rt_i2c_master_send(struct rt_i2c_bus_device *bus,
rt_uint16_t addr,
rt_uint16_t flags,
const rt_uint8_t *buf,
rt_uint32_t count)
参数 | 描述 |
---|---|
bus | I2C总线设备句柄 |
addr | 从机地址,不包含读写位 |
flags | 标志,(写0即可,会通过封装自动配置为写)只支持10位地址选择RT_I2C_ADDR_10BIT |
buf | 指向发送数据的指针 |
count | 发送数据字节数 |
返回 | 成功发送的数据字节数 |
接收函数
此函数其实也是对传输函数进行了一层封装,函数原型如下:
rt_size_t rt_i2c_master_recv(struct rt_i2c_bus_device *bus,
rt_uint16_t addr,
rt_uint16_t flags,
const rt_uint8_t *buf,
rt_uint32_t count)
参数 | 描述 |
---|---|
bus | I2C总线设备句柄 |
addr | 从机地址,不包含读写位 |
flags | 标志,(写0即可,会通过封装自动配置为读)只支持10位地址选择RT_I2C_ADDR_10BIT |
buf | 指向发送数据的指针 |
count | 发送数据字节数 |
返回 | 成功接收的数据字节数 |
上机实验
见文件工程下的对MPU6050的驱动文件drv_mpu6050.c
drv_mpu6050.h