搜索
热搜: ROHM 模拟 车载
查看: 3150|回复: 0

[活动] 传感器套件试用1-基于stm32的rt-thread IIC 驱动框架代码...

[复制链接]

该用户从未签到

9

主题

388

帖子

0

精华

高级会员

最后登录
2024-3-25
发表于 2019-6-19 13:32:14 | 显示全部楼层 |阅读模式
本帖最后由 andeyqi 于 2019-6-19 15:22 编辑

感谢社区活动申请的传感器套件,申请套件的目的主要是学习RT-thread的驱动框架,将传感器应用于RT-thread平台。传感器套件中其中5种传感器模块为I2C接口(加速度传感器/气压传感器/地磁传感器/接近照度传感器/彩色传感器模块),一个是GPIO口(霍尔传感器模块),两个是模拟接口(温度传感器/紫外线传感器模块)。其中IIC使用的还是很广泛的,开始使用前学习先开始学习了解下基于stm32的rt-thread IIC 驱动框架,之后进行传感器的学习。

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信号的物理层操作。
向上层提供的操作函数如下:
  1. struct rt_i2c_bit_ops
  2. {
  3.     void *data;            /* private data for lowlevel routines */
  4.     void (*set_sda)(void *data, rt_int32_t state);
  5.     void (*set_scl)(void *data, rt_int32_t state);
  6.     rt_int32_t (*get_sda)(void *data);
  7.     rt_int32_t (*get_scl)(void *data);

  8.     void (*udelay)(rt_uint32_t us);

  9.     rt_uint32_t delay_us;  /* scl and sda line delay */
  10.     rt_uint32_t timeout;   /* in tick */
  11. };
复制代码
上述的void *data;指向如下的内部私有数据,配置设置对应硬件的ID,和向上注册的总线name。rt-thread将引脚的抽象成对应芯片封装的引脚号,具体再次不具体讲述,感兴趣可以查看RTT的gpio框架。如下链接是之前写的自己的认识。
http://www.stmcu.org.cn/module/forum/thread-616950-1-1.html
  1. /* stm32 config class */
  2. struct stm32_soft_i2c_config
  3. {
  4.     rt_uint8_t scl;
  5.     rt_uint8_t sda;
  6.     const char *bus_name;
  7. };
复制代码
该文件的入口函数如下:该函数会在系统启动完成后自动调用。
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 对应的对象就能完成对总线的操作。
  1. /*for i2c bus driver*/
  2. struct rt_i2c_bus_device
  3. {
  4.     struct rt_device parent;
  5.     const struct rt_i2c_bus_device_ops *ops;
  6.     rt_uint16_t  flags;
  7.     rt_uint16_t  addr;
  8.     struct rt_mutex lock;
  9.     rt_uint32_t  timeout;
  10.     rt_uint32_t  retries;
  11.     void *priv;
  12. };
复制代码

stm32_i2c_bus_unlock==》按照注释是解锁总线,解锁原理如下(该问题开始也没有理解后来在网上搜索到如下解释和大家共勉下):每次I2C主设备复位后,如果检测到SDA数据线被拉低,则控制I2C中的SCL时钟线产生9个时钟脉冲(针对8位数据的情况,“9个clk可以激活”的方法来自NXP的文档,NXP(Philips)作为I2C总线的鼻祖,这样的说法是可信的),这样I2C从设备就可以完成被挂起的读操作,从死锁状态中恢复过来


  1. /* I2C initialization function */
  2. int rt_hw_i2c_init(void)
  3. {
  4. ......
  5.         stm32_i2c_gpio_init(&i2c_obj[i]);
  6.         result = rt_i2c_bit_add_bus(&i2c_obj[i].i2c2_bus, soft_i2c_config[i].bus_name);
  7.         RT_ASSERT(result == RT_EOK);
  8.         stm32_i2c_bus_unlock(&soft_i2c_config[i]);
  9. ......
  10. }
  11. INIT_BOARD_EXPORT(rt_hw_i2c_init);
复制代码
②i2c-bit-ops.c:封装底层提供的IO操作函数完成,提供IIC core核心层对应的操作函数,向IIC core提供的操作方法如下。
  1. struct rt_i2c_bus_device_ops
  2. {
  3.     rt_size_t (*master_xfer)(struct rt_i2c_bus_device *bus,
  4.                              struct rt_i2c_msg msgs[],
  5.                              rt_uint32_t num);
  6.     rt_size_t (*slave_xfer)(struct rt_i2c_bus_device *bus,
  7.                             struct rt_i2c_msg msgs[],
  8.                             rt_uint32_t num);
  9.     rt_err_t (*i2c_bus_control)(struct rt_i2c_bus_device *bus,
  10.                                 rt_uint32_t,
  11.                                 rt_uint32_t);
  12. };
复制代码

该文件中只实现master_xfer函数,另外两个函数指针设置为NULL。
  1. static const struct rt_i2c_bus_device_ops i2c_bit_bus_ops =
  2. {
  3.     i2c_bit_xfer,
  4.     RT_NULL,
  5.     RT_NULL
  6. };
复制代码
i2c_bit_xfer 函数我们可以看出,该函数只是只是对底层提供函数的操作的进一步封住,提供核心层(core)使用,struct rt_i2c_bit_ops *ops = bus->priv 取出底层的函数来按照IIC协议来发送数据
  1. static rt_size_t i2c_bit_xfer(struct rt_i2c_bus_device *bus,
  2.                               struct rt_i2c_msg         msgs[],
  3.                               rt_uint32_t               num)
  4. {
  5.     struct rt_i2c_msg *msg;
  6.     struct rt_i2c_bit_ops *ops = bus->priv;
  7. ......
  8.     i2c_start(ops);
  9. ......
  10.     i2c_stop(ops);

  11.     return ret;
  12. }
复制代码
③i2c_core.c:抽象通用的IIC操作函数供应用层使用,调用i2c-bit-ops.c注册的函数指针master_xfer 完成数据的处理



  1. rt_size_t rt_i2c_transfer(struct rt_i2c_bus_device *bus,
  2.                           struct rt_i2c_msg         msgs[],
  3.                           rt_uint32_t               num)
  4. {
  5.     rt_size_t ret;

  6.     if (bus->ops->master_xfer)
  7.     {
  8. #ifdef RT_I2C_DEBUG
  9.         for (ret = 0; ret < num; ret++)
  10.         {
  11.             i2c_dbg("msgs[%d] %c, addr=0x%02x, len=%d\n", ret,
  12.                     (msgs[ret].flags & RT_I2C_RD) ? 'R' : 'W',
  13.                     msgs[ret].addr, msgs[ret].len);
  14.         }
  15. #endif

  16.         rt_mutex_take(&bus->lock, RT_WAITING_FOREVER);
  17.         ret = bus->ops->master_xfer(bus, msgs, num);
  18.         rt_mutex_release(&bus->lock);

  19.         return ret;
  20.     }
  21.     else
  22.     {
  23.         i2c_dbg("I2C bus operation not supported\n");

  24.         return 0;
  25.     }
  26. }
复制代码
④i2c_dev.c 文件只是对core层文件的简单处理,BUS注册到驱动的IO设备层,供用户调用使用。

框架的注册层级关系如下:


  1. 注册流程:
  2. rt_hw_i2c_init(void)
  3. ==>>rt_i2c_bit_add_bus()
  4.          ==>rt_i2c_bus_device_register()
  5.                ==>rt_i2c_bus_device_device_init()
  6.                       ==>rt_device_register()
  7. 调用关系:
  8. rt_device_find()
  9. i2c_bus_device_read()
  10. ==>rt_i2c_master_recv()
  11.      ==>rt_i2c_transfer()
  12.            ==>  bus->ops->master_xfer(bus, msgs, num)<==>i2c_bit_xfer(bus, msgs, num)
复制代码

代码的框架理解后下一步将传感器代码融入系统框架..........................

回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条

Archiver|手机版|小黑屋|罗姆半导体技术社区

GMT+8, 2024-4-25 07:38 , Processed in 0.086946 second(s), 11 queries , MemCache On.

Powered by Discuz! X3.4

Copyright © 2001-2024, Tencent Cloud.

快速回复 返回顶部 返回列表