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框架。如下链接是之前写的自己的认识
- /* 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; 
- } 
- } 

 
					
				
 
			
			
			
						
			 
					
				 
					
				 
					
				 
					
				 
					
				 
					
				 
					
				 
					
				 
					
				 我要赚赏金
 我要赚赏金 STM32
STM32 MCU
MCU 通讯及无线技术
通讯及无线技术 物联网技术
物联网技术 电子DIY
电子DIY 板卡试用
板卡试用 基础知识
基础知识 软件与操作系统
软件与操作系统 我爱生活
我爱生活 小e食堂
小e食堂

