一. 对于BTF(Byte Transfer Finished)何时置1,给出详解。

上述给出了手册中对BTF位的定义,以及在主发送模式下和主接收模式下,BTF置为时机的描述。

  ————————— 1.主发送模式下BTF置位详解


—————————2.主接收模式下BTF置位详解

/

/

总结:
BTF 的核心作用是标志移位寄存器完成当前字节的发送或接收,并协调数据寄存器的状态。它为主机提供了关键的控制点,用于:

发送:判断是否继续写入数据或结束传输。
接收:及时读取数据以确保接收过程的连续性。
最终,BTF 的设计目的是确保 I2C 通信过程的高效性和可靠性。

/

/

/

二,使用dma配合硬件iic传输

1.dma的工作模式要选择单次模式

如果设置dma为循环模式,可能出现问题

例如

下面是我实际遇到的一个问题,配置dma为循环模式,使用按键的外部中断,在按键中断的回调函数中,启动HAL_I2C_Mem_Write_DMA(),对at24c02存储器写入指定数据,如果写入完成在iic存储器写入完成回调函数中,用串口输出 uart_printf('写入成功'),出现的问题是在按按键第一次的时候,能写入成功,可以看到串口发来的‘写入成功’,而后面接着按按键,就会出现没反应的现象。

在经过我debug后发现,这由于dma连续模式下,转运完成数据后,其state=HAL_DMA_STATE_BUSY,而并没有改变为HAL_DMA_STATE_READY,因此下次按键调用HAL_I2C_Mem_Write_DMA(),在其中调用HAL_DMA_Start_IT(),因为dma状态仍为HAL_DMA_STATE_BUSY,dma此刻认为此刻有数据传输而配置失败,因此导致只能通过按键写入一次数据传输。

归根结底是HAL引入状态机的,符合相应状态,执行相应操作!

处理方法:手动将连续模式下的dma在完成一次传输后,将状态更改HAL_DMA_STATE_READY

即可。

三,带seq的操作与不带seq的操作区别

HAL_I2C_Master_Transmit_IT
    这是一个简单的发送函数,适用于不需要复杂通信序列的情况。发送数据后,通信结束,I2C总线会生成一个 STOP 信号。

    用于一次性传输数据。
    适合与只需要一段数据传输的从设备通信。
HAL_I2C_Master_Seq_Transmit_IT( uint32_t XferOptions
     这是一个更高级的函数,支持序列传输模式,即可以在一次通信中实现多阶段传输,例如带有重复启动条件的连续传输。适合需要更复杂的通信序列。

    支持有Restart条件的通信。
    常用于多个连续数据段传输(如读取寄存器后紧接着写入数据)。                HAL_I2C_Master_Seq_Transmit_IT 根据参数 XferOptions 可以选择是否发送 STOP 信号,或者是否继续传输下一段数据。

不同的XferOption区别在于是否有start,stop信号,这很关键,乱选胡导致时序出现问题,影响通信。

四,HAL库硬件iic,在主接收模式下,只能接收一次数据的问题,bug

(鄙人是在stm32f103的HAL库中,发现的,其他系列的HAL库,鄙人没看,详细阅读其他系列源码即知,还有在下面图片中,为了能在一张图片中完整显示调用HAL_I2C_MasterRxCpltCallback的情况,其中HAL库的提供的函数有删减,而保留了关键部分,正如我上述所说,只是为了能在一张图片中更好的显示而别无作用)

//注意标题所说,仅在主接收模式有问题,因此其他的从接收模式,从存储器接收模式等均正常。

/

问题描述:主机stm32f1操作BH1750光敏模块时,在主机向BH1750发完命令后,调用HAL_I2C_Master_Seq_Receive_DMA()此函数,从BH1750读数据,发现只能读一次数据,而第二次会出现无法读数据的情况。

原因:HAL库中iic句柄有这两个成员:PreviousState(反应先前iic的状态)和State(当前状态)

HAL库中在函数中调用HAL_I2C_MemRxCpltCallback(),主接收完成回调函数共有3处(下面图片即为这几处),在调用主接收完成回调函数之前,对iic句柄状态变量的处理,可以看出,都将PreviousState = I2C_STATE_MASTER_BUSY_RX表面上一状态为主机接收模式,思索可以发现,三处均将PreviousState = I2C_STATE_MASTER_BUSY_RX,有问题,主机可以接收单帧也可以接收多帧,

(1)如果在接收单帧的情况下,接收完这一帧就产生结束条件终止本次接收,而上一状态就应该是无状态,不然就会影响下次接收,因为HAL库是状态机处理,上次的状态会影响此次的处理,因此需要一个函数,在调用主接收完成回调函数之前,将PreviousState =I2C_STATE_NONE。

(2)如果是在接收多帧的情况下,为了表明此次传输没有结束,有函数将PreviousState = I2C_STATE_MASTER_BUSY_RX是合理的,但是必然需要一个函数,在调用主接收完成回调函数之前,将PreviousState =I2C_STATE_NONE。来标志此次传输结束。

/—————————————HAL库iic句柄中的PreviousState与State———————————/

/——————–调用HAL_I2C_MemRxCpltCallback()前的三个函数源码————————–/

/—————————————————————————————————————————-/

/——在调用主接收完成回调函数之前,                                                                                           都将PreviousState = I2C_STATE_MASTER_BUSY_RX的后果

当你再次调用函数HAL_I2C_Master_Seq_Receive_DMA接收数据时,正如上述所说,此时PreviousState =为I2C_STATE_MASTER_BUSY_RX,读下面给出的源码可知,此时清除了应答位也就会导致主机不会对从机发的数据表示应答,并且设置了其他的两个位,会导致主机不对从机发的数据应答,并且主机会产生结束信号,结束此次接收

这也就解释了为什么,只能接收一次数据。

/————————-函数HAL_I2C_Master_Seq_Receive_DMA源码———————————-/

/

/——–下图为给出的一张 在 调用发送完成回调函数   之前的一个函数对于标志位的处理,在这个示例中有对PreviousState置busy的,也有对PreviousState置NONE。——/

/

解决方案1.:在主机接收完成回调函数处理完需求后 ,                                                                    调用 HAL_I2C_Master_Seq_Transmit_DMA来发送0个数据,这是允许的,来将标志位处理到正常状态,其中函数要传入的参数 XferOptions,自行具体选择。                                                     (原因即为PreviousState为Busy_RX对下次写入没有影响,而对下次继续接收有影响,读源码即知)

/———————————————————-处理示例——————————————————-/

五,iic序列化操作,一次操作中  写入与读取 交叉进行。

例如,主机   发->收->收                                                                                                                  正如上述bug点所说,最后主机最后一下接收会导致出bug,影响下次接收。                                    因此优化为      主机    发 -> 收  -> 收   ->  发(发0个数据,仅作为该状态标志位作用)                 主机从机  收和发每次都传输3Byte数据

  XferOptions依次选择为                                                                                             I2C_FIRST_FRAME  I2C_NEXT_FRAME   I2C_LAST_FRAME_NO_STOP      ————————————————————————————————————————-    I2C_LAST_FRAME 对于从机而言,首先接收3字节数据,然后发送6字节数据。

注意点:这里从机一次性发送6字节数据,而不是分两次,一次传3字节数据 ,因为反向操作例如收和发之间是 有restart信号和再次发地址信号的,而同向操作之间(例如收收之间)是没有这些信号的,对于本例子中,从机需要一次性发送6字节数据。

如果分两次发送数据,会导致SCK始终拉低,等待从机发数据,而一直得不到,就会导致以后的任何收发操作都无效,因为SCK被拉低了。

/———————下图为从机分两次发数据,一次发送3字节数据的时序图————————–/

下图给出正常情况,从机一次发送6字节数据的时序图,从图中你可以看出我们上面所说的反向操作间有restart信号,而同向信号间无restart信号。

作者:你心如何猜透

物联沃分享整理
物联沃-IOTWORD物联网 » stm32硬件iic

发表回复