当前位置:文档之家› STM32 IIC 学习笔记总结

STM32 IIC 学习笔记总结

STM32 IIC 学习笔记总结
STM32 IIC 学习笔记总结

STM32系列IIC学习笔记经验总结一、各寄存器内容与组织:控制、地址匹配、数据、状态、时钟控制、上升沿控制

二、IIC协议及STM32的master实现

EVENT后的第一个符号表示事件发生后对应的标志位的状态,着重看7位地址的通信;

三、基础知识(主要讨论起主机模式,从机模式的配置与使用可类比)

1.默认工作在从机模式,产生起始信号后自动转为主机模式,产生终止信号或仲裁失权后自动转为从机模式;起止信号由主

机模式下的软件实现,地址也只能由主机发送,响应信号由接收器发出(软件实现),要注意区别主机、从机、发送机、接收机;

2.数据通信的直接通道,SDA LineShift RegisterDRMemory(数据寄存器与存储器直接的数据交换发生在DMA模式,

另外若从机在SDA接收到的是地址则直接会与地址寄存器比较,而不会送入数据寄存器)

3.主机产生时钟信号,一串数据总是以起始于start信号,终止于stop信号,一旦SDA线上产生start位信号,主机模

式便被选中;9个寄存器的功能分配简单明了:I2C_CR2主要配置时钟与模块中断及DMA使能位,I2C_CR1则主要产生Start等控制信号,I2C_SR2主要是MSL、TRA和BUSY标志位,I2C_SR1则是其他事件的标志位,接下来就是存储数据的I2C_DR,时钟设置的I2C_CC4R和I2C_TRISE,地址匹配的I2C_OAR1和I2C_OAR2;

4.主机模式必要操作序列:外围时钟输入最少2M(标准模式)、4M(快速模式)

1)配置I2C_CR2寄存器以产生正确时序;

2)配置时钟控制寄存器I2C_CCR;

3)配置上升时间寄存器I2C_TRISE;

4)配置I2C_CR1寄存器以使能接口电路;

5)配置I2C_CR1寄存器,置位START位以产生起始信号;

5.时序具体解析

1)Start信号,置位I2C_CR1的START位以产生起始信号(在总线空闲时,即I2C_SR2的BUSY清零),使转为主机模式(置位I2C_SR2的MSL);在主机模式下,置位START位会在当前字节传输完成后产生一个重启ReStart信号;一旦Start信号送出,I2C_SR1的SB位会由硬件置位并产生中断(前提是ITEVFEN位被置位,貌似文档有误,我认为应是IC2_SR2的ITEVTEN位),然后需要读SR1和写DR以清零SB(这也符合操作时序);

2)从机地址发送,7位模式下,地址字节一旦送出,I2C_SR1的ADDR位会由硬件置位并产生中断(前提是ITEVFEN 置位),然后主机等待读取SR1和SR2以清零ADDR(稍微符合,读SR2貌似饶了一步);7位模式下,地址字节最低位若是0则说明主机要进入发送模式,若是1则是接收模式;I2C_SR2的TRA表示主机在发送模式还是接收模式;

3)主机发送模式,地址送出且ADDR清零后,主机会将DR中数据发送到SDA line(当然经过Shift Register),主机会等到第一个数据写入DR(EV8_1阶段),若收到响应脉冲,SR1中的TxE位会置位(前提是ITEVFEN和ITBUFEN已置位);在最后一个字节传输结束前的传输过程中,若TxE置位且某数据字节没有写入DR,BTF会置位直到(硬件清零)该数据字节被写入到DR,这个过程中SCL会一直被拉低;

4)主机发送模式关闭通信,最后一个字节被写入DR,CR1的STOP位要由软件置位而产生停止信号,接口自动转为从机模式(MSL清零);置位Stop位即对应于EV8_2事件;

5)主机接收模式,地址送出且ADDR清零后,主机会进入接收模式,接口会从SDA line中读数据到DR中(同样经过Shift Register);每个字节接收后的操作序列为,产生应答信号(前提是CR1的ACK位置位),RxNE位置位并产生中断(前提是SR2的ITEVFEN和ITBUFEN置位);在最后一个字节传输结束前的传输过程中,若RxNE 置位且某数据未从DR中读取,BTF会置位直到(硬件清零)该数据字节被读出,这个过程SCL会一直被拉低;

6)主机接收模式关闭通信,收到最后一个字节后会发送NACK信号给从机,从机收到NACK会释放总线(SDA和SCL),此时主机便可发送一个Stop或Restart信号;在读完倒数第二个字节后(RxNE中断后),要清零ACK 位以产生NACK应答,要置位STOP/START位以产生Stop/Restart信号;在单字节数据接收状况,NACK 要在ADDR清零前(EV6)设置,STOP信号要在ADDR清零后配置;Stop信号产生后,主机自动进入从机模式(SR2的MSL清零);

7)最后一字节数据接收的ACK响应前若RxNE清零(ACK清零与Stop请求)没有完成,则建议采取以下步骤以确保ACK位在最后一字节数据接收前被清零,STOP位在最后一字节数据接受完后(没有附加数据)被置位:

(1)2字节的数据接收:等到ADDR=1;清零ACK,置位POS;清零ADDR;等到BTF=1(数据1在DR,

数据2在Shift Register——即最后一个字节到来时RxNE置位且DR中没有写入最后字节);置位STOP;读取数据1和数据2;

(2)N>2字节的数据接收:对前N-2个数据,等到BTF=1(N-2在DR且N-1在Shift Register);清零ACK(永远是对最后一个数据的响应,而且后面跟随的信号是STOP信号);读取N-2;等到BTF=1(N-1在DR且N在Shift Register);STOP置位;读取N-1与N;

6.DMA控制

1)DMA请求只产生于数据传输过程,当发送时DR为空或接收时DR为满时便会激发DMA请求,DMA请求必须在当前字节传输完前服务,当传输的字节数达到DMA channel通道的程序设定值时,DMA controller控制器会发送EOT(End of Transfer)信号给I2C接口并产生传输完成的中断(若中断已被使能);主机发送模式,在中断程序中要disable DMA requests,然后在编程Stop位前要等待BTF时间;主机接收模式,当接收字节数大于等于2时,DMA controller发送硬件信号EOT_1(对应倒数第2个数据),若在CR2中的LAST置位,I2C 会自动产生NACK以响应EOT_1的下一个字节,用户只需在DMA完成中断中产生一个Stop信号;主机接收模式中,接收单个字节时,NACK必须在EV6(ADDR=1)事件中编程实现即当ADDR=1时令ACK=0,然后可以再清零ADDR(可软件可硬件、选择时参考时序)后发送STOP信号,也可在DMA完成中断程序中(发送EOT 信号时)实现;

2)DMA发送模式:CR2的DMAEN置位,当TxE置位时数据会通过DMA外围电路从某个内存单元装载到I2C_DR,为实现一个DMA通道的I2C发送,可以执行以下操作序列,x是选择的通道号:

(1)在DMA_CPARx寄存器中设置I2C_DR的地址;在DMA_CMARx寄存器中设置存储单元的地址;随TxE 而访问;

(2)在DMA_CNDTRx寄存器中设置字节总数,随TxE而递减;

(3)在DMA_CCRx寄存器中用Pl[0:1]配置通道优先级;

(4)在DMA_CCRx寄存器中设置DIR位,根据实际需要在传输一半或完成时配置中断;

(5)配置DMA_CCRx寄存器的EN位以激活通道;

当设置的数目到达时,DMA controller会发送EOT/EOT_1信号到I2C接口,产生DMA完成中断,DMA

通道中断允许向量;

3)DMA接收模式:DMAEN置位,当接收到数据时数据会通过DMA外围电路从I2C-DR装载到某个没存单元,为实现DMA通道的I2C接收,可以执行以下操作序列,x是选择的通道号:

(1)在DMA_CPARx寄存器中设置I2C_DR的地址;在DMA_CMARx寄存器中设置存储单元的地址;随RxNE 而访问;

(2)在DMA_CNDTRx寄存器中设置字节总数,随RxNE而递减;

(3)在DMA_CCRx寄存器中用Pl[0:1]配置通道优先级;

(4)在DMA_CCRx寄存器中设置DIR位,根据实际需要在传输一半或完成时配置中断;

(5)配置DMA_CCRx寄存器的EN位以激活通道;

当设置的数目到达时,DMA controller会发送EOT/EOT_1信号到I2C接口,产生DMA完成中断,DMA

通道中断允许向量;

若使用DMA接收,不要使能I2C_CR2寄存器中的ITBUFEN位;

4)其他

7.中断映射

8.补充知识

1)POS是对于数据接收的响应或PEC位置,由硬件置位或清零(PE=0时硬件清零),必须在2字节读取时用到(主机接收模式);清零时表示ACK位是对当前Shift Register中所接收数据的响应,置位时表示ACK位是对下一个到Shift Register中的数据的响应;没接收一个字节,数据接收或地址匹配都会引起ACK响应;

2)PE是Peripheral Enable,在通信结束前不能使用;CR2中的LAST是在主机接收模式中确保最后一个数据响应为NACK(DMA通信);SR1中的AF在没有响应时置位;

3)BTF置位说明某数据字节传输已经成功完成(并不是说所有数据传输已经完成),是在NOSTRETCH=0时由硬件自动置位,由软件通过读写DR清零或起止信号后硬件自动清零;NACK接收到后BTF不会置位,下一个要传输的是PEC时BTF不会置位;

9.I2C通信频率不能超过400k,I2C模块的输入频率不能小于2M(标准模式、快速模式是4M),I2C对应的IO口输入

频率要高于2/4M,一般取50M;

四、编程实现:

1.相关库函数:

1)按指定参数初始化I2Cx寄存器(x可为1或2),void I2C_Init(I2C_TypeDef*I2Cx,I2C_InitTypeDef *I2C_InitStruct)

2)使能或失能I2C外设,void I2C_Cmd(I2C_TypeDef*I2Cx,FunctionalState NewState)

3)使能或失能I2C的DMA请求,I2C_DMACmd(I2C_TypeDef*I2Cx,FunctionalState NewState) 4)使下次的DMA传输为最后一次传输,I2C_DMALastTransferCmd(I2C_TypeDef*I2Cx, FunctionalState NewState)

5)产生起始条件,void I2C_GenerateSTART(I2C_TypeDef*I2Cx,FunctionalState NewState) 6)产生终止条件,void I2C_GenerateSTOP(I2C_TypeDef*I2Cx,FunctionalState NewState)

7)使能或失能I2C的应答:void I2C_AcknowledgeConfig(I2C_TypeDef*I2Cx,FunctionalState NewState)

8)设定自身的I2C地址:void I2C_OwnAddress2Config(I2c_TypeDef*I2Cx,u8Address)

9)使能或失能指定的I2C中断:void I2C_ITConfig(I2C_TypeDef*I2Cx,u16I2C_IT, FunctionalState NewState)

10)通过外设I2C发送一个数据:void I2C_SendData(I2C_TypeDef*I2Cx,u8Data)

11)返回通过I2Cx最近接受的数据:u8I2C_ReceiveData(I2C_TypeDef*I2Cx)

12)向指定的I2C设备传送地址字:void I2C_Send7bitAddress(I2C_TypeDef*I2Cx,u8Address,

u8I2C_Direction)

13)读取指定的I2C寄存器并返回其值:u16I2C_ReadRegister(I2C_TypeDef*I2Cx,u8 I2C_Register)

14)使能或失能指定的I2C的软件复位:I2C_SoftwareResetCmd(I2C_TypeDef*I2Cx, FunctionalState NewState)

15)使能或失能指定的I2C的PEC传输:I2C_TransimitPEC(I2C_TypeDef*I2Cx, FunctionalState NewState)

16)使能或失能时钟延展:void I2C_StrechClockCmd(I2C_TypeDef*I2Cx,FunctionalState NewState)

17)指定I2C的快速模式的占空比:void I2C_FastModeDutyCycleConfig(I2C_TypeDef*I2Cx,u 16I2C_DutyCycle),其实在初始化中已经有所介绍;

18)返回最近一次I2C事件,u32I2C_GetLastEvent(I2C_TypeDef*I2Cx)

19)检查最近一次I2C事件是否是输入的事件,ErrorStatus I2C_CheckEvent(I2C_TypeDef*I2C x,u32I2C_EVENT)

20)检查指定的I2C标志位设置与否:FlagStatus I2C_GetFlagStatus(I2C_TypeDef*I2Cx,u3 2I2C_FLAG)

21)清除I2Cx的待处理标志位:void I2C_ClearFlag(I2C_TypeDef*I2Cx,u32I2C_FLAG)---若不能自动硬件清除的话

22)检查指定的I2C中断发生与否:ITStatus I2C_GetITStatus(I2C_TypeDef*I2cx,u32I2C_I T)

23)清除I2Cx的中断待处理位:void I2C_ClearITPendingBit(I2C_TypeDef*I2Cx,u32I2C_I T)

2.基本思路:

1)了解各库函数的功能及其涉及到的数据结构;

2)定义枚举状态变量(检测最后状态):typedef enum{FAILED=0;PASSED=!FAILED}TestStatus;

定义比变量并初始化volatile TestStatus TransferStatus=FAILEd;

3)首先时钟配置,RCC_Configuration();打开端口时钟:RCC_APB2PeriphClockCmd(RCC_APB2P eriph_GPIOB|RCC_APB2Periph_GPIOB,ENABLE);打开APB1总线上的I2C1:RCC_APB1Per iphClockCmd(RCC_APB1Periph_I2C1,ENABLE),即I2C模块与相应I/O口要分别打开;

4)其次是中断配置,这里没用到,NVIC_Configuration的中断向量若需要则要合理配置;

5)从机的初始化配置,首先是GPIO的配置,然后是I2C的配置;GPIO配置,先定义配置结构体变量(类似I2C),然后对引脚、速率、模式分别赋值,调用GPIO_Init初始化;50MHz上面配置完,下面的C口就不用再重新配置了;

I2C配置,定义配置结构体,对个成员赋初值,调用初始化函数,然后使能I2C模块,便可对其进行操作;

6)写数据函数(调用有关函数实现将发送数组写入EEPROM)I2C_EE_SequentialWrite(Tx_Buffer, EEPROM_WriteAddress,BufferSize);字节数BufferSize可能超过一页,可能超过一页,用页写函数(根

据时序和轮询用库函数来实现);每次操作都要考虑通信芯片的自编程;

7)读数据函数:I2C_EE_SequentialWrite(Rx_Buffer,EEPROM_WriteAddress,BufferSize);

8)若要用I2C自带中断的话,需要在中断程序中用状态机来实现;

3.当确认用主机模式时,接下来要了解的便是要通信的器件的I2C的读写时序,对应主机只需要知道怎么检测标志

就可以了,而从机的数据需要一定的时序才能读出或写入;

五、其他

相关主题
文本预览
相关文档 最新文档