在线时间1846 小时
UID3338155
ST金币1693
蝴蝶豆32
注册时间2016-12-11
该用户从未签到
论坛元老
- 最后登录
- 2023-2-9
|
rt-thread 4.0.1版本已经集成了基于stm32 IIC驱动框架,美中不足的是官方代码的驱动框架是基于模拟IIC的方式实现的,要是集成的是硬件的方式就更棒了,相信不久以后的RTT会有的,主要涉及的文件如下,以下指示个人的一点理解,理解的有不对的地方欢迎各位拍砖。
\rt-thread\components\drivers\i2c\i2c_dev.c
\rt-thread\components\drivers\i2c\i2c_core.c
\rt-thread\components\drivers\i2c\i2c-bit-ops.c
\rt-thread\bsp\stm32\libraries\HAL_Drivers\drv_soft_i2c.c
我们由下而上的了解熟悉各个文件的作用:
①drv_soft_i2c.c:提供BSP相关的硬件操作函数,操作IIC 的SDA,和SCL总线电平,提供上层模拟IIC总线使用完成IIC信号的物理层操作。
向上层提供的操作函数如下:
- struct rt_i2c_bit_ops
- {
- void *data; /* private data for lowlevel routines */
- void (*set_sda)(void *data, rt_int32_t state);
- void (*set_scl)(void *data, rt_int32_t state);
- rt_int32_t (*get_sda)(void *data);
- rt_int32_t (*get_scl)(void *data);
- void (*udelay)(rt_uint32_t us);
- rt_uint32_t delay_us; /* scl and sda line delay */
- rt_uint32_t timeout; /* in tick */
- };
复制代码 上述的void *data;指向如下的内部私有数据,配置设置对应硬件的ID,和向上注册的总线name。rt-thread将引脚的抽象成对应芯片封装的引脚号,具体再次不具体讲述,感兴趣可以查看RTT的gpio框架。如下链接是之前写的自己的认识。https://www.stmcu.org.cn/module/forum/thread-616950-1-1.html
- /* stm32 config class */
- struct stm32_soft_i2c_config
- {
- rt_uint8_t scl;
- rt_uint8_t sda;
- const char *bus_name;
- };
复制代码 该文件的入口函数如下:该函数会在系统启动完成后自动调用。
stm32_i2c_gpio_init==》设置GPIO默认电平总线空闲状态,SDA,SCL为高电平。
rt_i2c_bit_add_bus==》调用(\rt-thread\components\drivers\i2c\i2c-bit-ops.c)中的函数,向上注册驱动层IO操作函数,注册的结构如下,其中的priv成员指向底层的IO操作函数完成总线设备和底层的IO操作函数的绑定,从而上层使用rt_i2c_bus_device 对应的对象就能完成对总线的操作。- /*for i2c bus driver*/
- struct rt_i2c_bus_device
- {
- struct rt_device parent;
- const struct rt_i2c_bus_device_ops *ops;
- rt_uint16_t flags;
- rt_uint16_t addr;
- struct rt_mutex lock;
- rt_uint32_t timeout;
- rt_uint32_t retries;
- void *priv;
- };
复制代码
stm32_i2c_bus_unlock==》按照注释是解锁总线,具体的原理现在还没有搞明白什么情况下总线会被锁状态,希望路过有了解的留下脚印讲解下。
- /* I2C initialization function */
- int rt_hw_i2c_init(void)
- {
- ......
- stm32_i2c_gpio_init(&i2c_obj[i]);
- result = rt_i2c_bit_add_bus(&i2c_obj[i].i2c2_bus, soft_i2c_config[i].bus_name);
- RT_ASSERT(result == RT_EOK);
- stm32_i2c_bus_unlock(&soft_i2c_config[i]);
- ......
- }
- INIT_BOARD_EXPORT(rt_hw_i2c_init);
复制代码
②i2c-bit-ops.c:封装底层提供的IO操作函数,实现IIC协议层相关信号操作,提供IIC core核心层对应的操作函数,向IIC core提供的操作方法如下。- struct rt_i2c_bus_device_ops
- {
- rt_size_t (*master_xfer)(struct rt_i2c_bus_device *bus,
- struct rt_i2c_msg msgs[],
- rt_uint32_t num);
- rt_size_t (*slave_xfer)(struct rt_i2c_bus_device *bus,
- struct rt_i2c_msg msgs[],
- rt_uint32_t num);
- rt_err_t (*i2c_bus_control)(struct rt_i2c_bus_device *bus,
- rt_uint32_t,
- rt_uint32_t);
- };
复制代码
该文件中只实现master_xfer函数,另外两个函数指针设置为NULL。
- static const struct rt_i2c_bus_device_ops i2c_bit_bus_ops =
- {
- i2c_bit_xfer,
- RT_NULL,
- RT_NULL
- };
复制代码 从i2c_bit_xfer 函数我们可以看出,该函数只是只是对底层提供函数的操作的进一步封住,提供核心层(core)使用,struct rt_i2c_bit_ops *ops = bus->priv 取出底层的函数来按照IIC协议来发送数据。
- static rt_size_t i2c_bit_xfer(struct rt_i2c_bus_device *bus,
- struct rt_i2c_msg msgs[],
- rt_uint32_t num)
- {
- struct rt_i2c_msg *msg;
- struct rt_i2c_bit_ops *ops = bus->priv;
- ......
- i2c_start(ops);
- ......
- i2c_stop(ops);
- return ret;
- }
复制代码 ③i2c_core.c:抽象通用的IIC操作函数供应用层使用,调用i2c-bit-ops.c注册的函数指针master_xfer 完成数据的处理。- rt_size_t rt_i2c_transfer(struct rt_i2c_bus_device *bus,
- struct rt_i2c_msg msgs[],
- rt_uint32_t num)
- {
- rt_size_t ret;
- if (bus->ops->master_xfer)
- {
- #ifdef RT_I2C_DEBUG
- for (ret = 0; ret < num; ret++)
- {
- i2c_dbg("msgs[%d] %c, addr=0x%02x, len=%d\n", ret,
- (msgs[ret].flags & RT_I2C_RD) ? 'R' : 'W',
- msgs[ret].addr, msgs[ret].len);
- }
- #endif
- rt_mutex_take(&bus->lock, RT_WAITING_FOREVER);
- ret = bus->ops->master_xfer(bus, msgs, num);
- rt_mutex_release(&bus->lock);
- return ret;
- }
- else
- {
- i2c_dbg("I2C bus operation not supported\n");
- return 0;
- }
- }
复制代码
④i2c_dev.c 文件只是对core层文件的简单处理,BUS注册到驱动的IO设备层,供用户调用使用。
框架的注册层级关系如下:
- 注册流程:
- rt_hw_i2c_init(void)
- ==>>rt_i2c_bit_add_bus()
- ==>rt_i2c_bus_device_register()
- ==>rt_i2c_bus_device_device_init()
- ==>rt_device_register()
- 调用关系:
- rt_device_find()
- i2c_bus_device_read()
- ==>rt_i2c_master_recv()
- ==>rt_i2c_transfer()
- ==> bus->ops->master_xfer(bus, msgs, num)<==>i2c_bit_xfer(bus, msgs, num)
复制代码
编译时选上IIC,启动后就会发现设备列表里就出现了我们注册的IIC设备了。
上述解索的原因在万能的度上找到答案了贴出来和大家分享下: 在I2C主设备中增加I2C总线恢复程序。 每次I2C主设备复位后,如果检测到SDA数据线被拉低,则控制I2C中的SCL时钟线产生9个时钟脉冲(针对8位数据的情况,“9个clk可以激活”的方法来自NXP的文档,NXP(Philips)作为I2C总线的鼻祖,这样的说法是可信的),这样I2C从设备就可以完成被挂起的读操作,从死锁状态中恢复过来。
最后推荐两本RT-THREAD的书籍仅供参考: 一本是官方出品的:《嵌入式实时操作系统——RT-Thread设计与实现》 和之前论坛活动送的野火的书《RT-Thread内核实现与应用开发实战指南》
I2C_接口进入_Busy_状态不能退出.pdf
(43.75 KB, 下载次数: 2)
|
|