锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

软件模拟IIC 非阻塞式

时间:2023-10-12 03:07:00 igt202传感器

引言

IIC常用于总线协议MCU与其他设备通信。例如,各种传感器:温度、光强、压力、加速度、速度、位置等。它被广泛使用。原因是协议简单,只有两条连接线。我们需要经常为各种设备编写驱动程序和硬件IIC外设当然是最好的,如果没有或有的话IO当我们的嘴被占用时,我们需要使用它GPIO口模拟协议时序。

协议

协议的具体内容:start,stop,ack条件等,不再详细描述。

具体协议规范:

IIC-bus specification and user manual.

https://www.nxp.com/docs/en/user-guide/UM10204.pdf

IIC-bus resource.

I2C Bus

软件模拟新思路

许多传统的模拟方法是按照协议的顺序生成的 开始条件 传输字节 应答 结束条件,时间由delayus(5-30)控制delayus几乎都是堵塞CPU,让CPU不断查询是否到时。一定的浪费CPU时钟,虽然传统的模拟方法可以正常工作。当CPU频率 当它相对较低时,传统的模拟方法更有效,不会浪费CPU时钟。但是当CPU频率 高的时候,几个微秒CPU可以做很多指令。STM32F429性能225DMIPS<1125 I/5uS>。STM32H743性能856DMIPS<4280 I/5uS>。为了CPU用硬件定时器中断更高效的操作 重新设计了IIC软件模拟方案。

软件IIC组件 方案思路

用软件对象 模拟 硬件外设,每个软件对象, 嵌入式状态机用于控制每个人的生成。每个软件对象具有自己独有的SDL和SCL引脚 以及这两个引脚的控制函数,以及完成回调等。我们可以创建多个IIC软件对象,每个对象 就代表 一个 IIC硬件外设可以控制许多条件IIC总线。多个软件对象 连接成链表。中断硬件定时器 扫描链表。更新 每个对象的IO操作。只要CPU足够强壮,可以添加很多IIC软件对象。当然也需要足够的GPIO。

仓库

这里介绍一个开源软件模拟IIC组件 softiic v1.0,非阻塞,中断处理。

废话不多说,仓库地址如下:

G-ATLAS/softiic: IIC, software IIC driver module, only master, non-blocking (github.com)

如何使用

1.移植该IIC组件,如后续所述。

2.使用前 先初始化该IIC组件: 调用 siic_init();

3.主机 写 设备:调用 例如 siic_device_write_it(&hsiic1,&data[0],3);

4.主机 读设备:调用 例如siic_device_read_it(&hsiic1,&data[0],4);

5.修改传输完成回调 根据工程需要。

使用实例如下:非常简单

void StartTask02(void *argument) {  uint8_t data[5];   ///init this module  siic_init();    ///read  data[0] = 0x70u; ///slave add write  data[1] = 0x02u; ///register  data[2] = 0x71u; ///slave add read  data[3] = 0x00u; ///the read data will be here  data[4] = 0x00u;  siic_device_read_it(&hsiic1,&data[0],4);  hsiic1_wait_cplt(100);   ///write   data[0] = 0x70u; ///slave add write  data[1] = 0x80u; ///register  data[2] = 22u;     ///value to be written  siic_device_write_it(&hsiic1,&data[0],3);  hsiic1_wait_cplt(100);     for(;;)  {  osDelay(100);  } }

组件特点

1.纯C语言构建

2.非阻塞软件IIC设备

3.虚拟化软件的无限扩展IIC如果有足够的设备GPIO和CPU速度

4.如果有足够的通信速度,可调通信速度。CPU速度

5.非常简单API接口

6.自动生成START,STOP,ACK,NACK,STARTr条件

7. 只支持7个地址和几个主机的常用命令模式

8. 不支持时钟同步

9.不支持总线仲裁

10.不支持时钟拉扯

11.需要硬件定时器节拍

组件功能

- 主机写从设备

-<主机写从设备> /**   * @brief     * @note   pdata       -pdata[0]= ,pdata[1]= ,pdata[2--n]=the data to be written.   * @param  hsiicdevice -a pointer to the structure which contains information  about siic.    * @param  pdata       -the data pointer.    * @param  size        -the size of data. in byte. should be >=2.   * @retval SIIC_Status_TypeDef   */ SIIC_Status_TypeDef siic_device_write_it(SIIC_Device_TypeDef *hsiicdevice,uint8_t *pdata,uint16_t size)

- 主机读从设备

-<主机读从设备> /**   * @brief     * @note   pdata       -pdata[0]= ,pdata[1]= ,                          pdata[2]=  ,pdata[3--n]= the data to be read.   * @param  hsiicdevice -a pointer to the structure which contains information  about siic.    * @param  pdata       -the data pointer.   * @param  size        -the size of data. in byte.should be >=3.   * @retval SIIC_Status_TypeDef   */ SIIC_Status_TypeDef siic_device_read_it(SIIC_Device_TypeDef *hsiicdevice,uint8_t *pdata,uint16_t size)

- 主机写从设备 不带Stop条件

/**   * @brief  the same as func,just without the stop condition.   * @note   pdata       -pdata[0]= ,pdata[1]= ,pdata[2--n]=the data to be written.   * @param  hsiicdevice -a pointer to the structure which contains information  about siic.    * @param  pdata       -the data pointer.    * @param  size        -the size of data. in byte. should be >=2.   * @retval SIIC_Status_TypeDef   */ SIIC_Status_TypeDef siic_device_write_nostop_it(SIIC_Device_TypeDef *hsiicdevice,uint8_t *pdata,uint16_t size)

- 主机读从设备 寄存器偏移没有指定

-<主机读从设备 寄存器偏移没有指定> /**   * @brief  the same as func,just without indicate the offset of the internal register.   * @note   pdata       -pdata[0]=  ,pdata[1--n]= the data to be read.   * @param  hsiicdevice -a pointer to the structure which contains information  about siic.    * @param  pdata       -the data pointer.   * @param  size        the size of data. in byte.should be >=2.
  * @retval SIIC_Status_TypeDef
  */
SIIC_Status_TypeDef siic_device_read_random_it(SIIC_Device_TypeDef *hsiicdevice,uint8_t *pdata,uint16_t size)

- 更多  

-<软件IIC组件初始化>
void siic_init(void)

 移植说明

1- 把目光转移到xx_port.c文件中,为软件IIC准备 硬件定时器 相关接口函数。

void siic_tick_init(void)-初始化硬件定时器,使用其 更新中断。配置中断优先级等等。中断频率5-50uS为宜,根据平台性能。  
void siic_tick_start(void) -启动硬件定时器。可做重复启动优化,见源文件。  
void siic_tick_stop(void) -停止硬件定时器。可做重复停止优化,见源文件。  
siic_tick_handler(); -在 定时器更新中断 的服务程序中调用,原则尽量快。  

2-为 某个软件IIC设备 准备 GPIO 相关接口函数。 

void siic1_api_init(void) -初始化SDL,SCL相关io口,注意默认高电平,OD输出,上拉。 
void siic1_api_sdlin(void) -切换SDL方向为输入。  
void siic1_api_sdlout(void) -切换SDL方向为输出。  
void siic1_api_sdlset(uint8_t iostate) -设置SDL输出电平。  
void siic1_api_sclset(uint8_t iostate) -设置SCL输出电平 。  
uint8_t siic1_api_sdlread(void) -读入SDL输入电平。  

 3-为 更多软件IIC设备 准备 GPIO 相关接口函数。如果需要。  

void siic2_api_init(void) -初始化SDL,SCL相关io口,注意默认高电平,OD输出,上拉。  
void siic2_api_sdlin(void) -切换SDL方向为输入。  
void siic2_api_sdlout(void) -切换SDL方向为输出。  
void siic2_api_sdlset(uint8_t iostate) -设置SDL输出电平。  
void siic2_api_sclset(uint8_t iostate) -设置SCL输出电平 。  
uint8_t siic2_api_sdlread(void) -读入SDL输入电平。

4-实现软件IIC组件 初始化函数。如下  

SIIC_Device_TypeDef hsiic1;
///SIIC_Device_TypeDef hsiic2;and more device
void siic_init(void)
{
	/* tick init  */
	siic_tick_init();
	
	/* hsiic1 init */
	hsiic1.API.init =siic1_api_init;
	hsiic1.API.sdlin =siic1_api_sdlin;
	hsiic1.API.sdlout =siic1_api_sdlout; 
	hsiic1.API.sclset =siic1_api_sclset;
	hsiic1.API.sdlset =siic1_api_sdlset;
	hsiic1.API.sdlread =siic1_api_sdlread;
	siic_device_init(&hsiic1);
	
	
	/* hsiic2 and more init */
	/* blank statement */
	
	
	/* register hsiic1's callbcak  */
	siic_callback_register(&hsiic1,SIIC_XFER_CPLT_CB_ID,hsiic1_CpltCallback);
	siic_callback_register(&hsiic1,SIIC_XFER_ERROR_CB_ID,hsiic1_ErrorCallback);
	
	/* register hsiic2's callbcak  */
	/* blank statement */

	/* register siic device  */
	siic_device_register(&hsiic1);
	///siic_device_register(&hsiic2); and more device
}
void hsiic1_CpltCallback(SIIC_Device_TypeDef *hSIIC)
{
	///osSemaphoreRelease(myBinarySem01Handle);
}
void hsiic1_wait_cplt(uint16_t timeout)
{
	///osSemaphoreAcquire(myBinarySem01Handle,timeout);
}
void hsiic1_ErrorCallback(SIIC_Device_TypeDef *hSIIC)
{
	
}

5-注意!!!  

本组件测试平台STM32F429IGT6  180Mhz,性能 225DMIPS, <225 I/uS><1125 I/5uS>  
本硬件定时器中断周期的 设置为5uS。 一个位的传输需要3个tick<15uS>  
!!!!!!!!!!!!!!  
不同平台性能不同,你必须确保 <从 中断发生 到 扫描完一遍siic_tick_handler(); >  
所用时间 < 硬件定时器中断周期。  
总的来说 性能越好,中断周期可以更短。性能越差,中断周期必须更长。  
!!!!!!!!!!!!!!
 

6-注意!!! 

建议CPU>32Mhz的平台移植,频率过低 从 这种实现的软件IIC组件 得不到任何好处。  
虽然也可以工作,通信速度变慢,效率会降低。由于过多的中断开销,还不如传统的  
CPU阻塞式软件模拟方案。

组件设计意义  

非阻塞式工作方案,尽可能的节约CPU的时钟。  
更适合有RTOS的软件结构。  
更适合具有高频率的CPU的平台。

结语

通过这个IIC组件,可以创建很多个 IIC软件对象 虚拟化 多个IIC硬件外设。虽然要适当降低通信速率,但是以后操作 IIC设备 就像 操作 串口一样简单。屏蔽了协议的复杂性,抽出简单的通信接口,就像串口通信一样。根本就不用考虑 时序问题,简化了软件设计。

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章