DMA方式实现的I2C通信库.docx

上传人:b****8 文档编号:9373648 上传时间:2023-02-04 格式:DOCX 页数:10 大小:217.36KB
下载 相关 举报
DMA方式实现的I2C通信库.docx_第1页
第1页 / 共10页
DMA方式实现的I2C通信库.docx_第2页
第2页 / 共10页
DMA方式实现的I2C通信库.docx_第3页
第3页 / 共10页
DMA方式实现的I2C通信库.docx_第4页
第4页 / 共10页
DMA方式实现的I2C通信库.docx_第5页
第5页 / 共10页
点击查看更多>>
下载资源
资源描述

DMA方式实现的I2C通信库.docx

《DMA方式实现的I2C通信库.docx》由会员分享,可在线阅读,更多相关《DMA方式实现的I2C通信库.docx(10页珍藏版)》请在冰豆网上搜索。

DMA方式实现的I2C通信库.docx

DMA方式实现的I2C通信库

1.函数库接口

a)I2C_Comm_MasterSend

i.返回参数:

void

ii.函数参数:

1.端口:

I2Cx

2.从设备地址:

slave_addr

3.从设备偏移量:

offset

4.发送数据的内容:

pBuffer

5.发送数据的长度:

length

iii.函数意义:

从某个端口向slave_addr这个从设备发送数据pBuffer,并写入它的偏移量offset开始的地方。

如果从设备没有偏移量,则offset取值0xffffffff。

b)I2C_Comm_MasterReceive

i.返回参数:

void

ii.函数参数:

1.端口:

I2Cx

2.从设备地址:

slave_addr

3.从设备偏移量:

offset

4.接收数据存放的地方:

pBuffer

5.接收数据的长度:

length

iii.函数意义:

从某个端口向slave_addr这个从设备的偏移量offset的地方读取数据,放到pBuffer指定的地方。

c)I2C_Comm_SlaveReceive

i.返回参数:

void

ii.函数参数:

1.端口:

I2Cx

2.接收到的偏移量:

pOffset

3.接收数据存放的地方:

pBuffer

4.数据长度:

length

iii.函数意义:

从某个端口接收到length个数据放到从pBuffer开始,偏移量为*pOffset的地方。

d)I2C_Comm_SlaveSend

i.返回参数:

void

ii.函数参数:

1.端口:

I2Cx

2.接收到的偏移量:

pOffset

3.发送数据存放的地方:

pBuffer

4.数据长度:

length

iii.函数意义:

从某个端口接发出放在pBuffer的偏移量pOffset开始的地方length个数据。

注意1:

对于Slave函数来说,pBuffer始终指向的是它存放所有数据的总地址,真正要发送时,是从pBuffer开始的*pOffset开始的地方取出的数据;接受数据时,也是放到从pBuffer开始的*pOffset开始的地方。

另外一个参数pOffset也是从master传过来的,不管Slave是要接收还是发送数据,这个偏移量都是master来指定的。

注意2:

当使用STM32作为主设备时,如果对方从设备是类似E2PROM的器件,对其读写操作时,在“从设备偏移量Offset”这个参数指明;如果对方是比如另外一个MCU的I2C端口,双方只是通过I2C传递数据,那么“从设备偏移量Offset”这个参数可以指明0xff。

但是这样的通信协议,需要对方MCU知道,以处理收到的无效偏移量。

注意3:

当使用STM32作为从设备时,对方主设备应该是MCU。

需要对方MCU知道,需要发送“偏移量”这个参数来满足通信协议。

通信协议如下:

2.通信过程<事件/寄存器描述>

3.关于I2C总线的控制:

a)正常情况下,初始化I2C对应GPIO后,总线SDA&SCK都处于高电平。

从主设备发出START位开始,总线进入通信状态(BUSY@SR2被硬件置位),知道主设备发出STOP位,总线又恢复空闲状态(BUSY@SR2被硬件清零)。

b)异常情况:

i.主设备在通信过程中(不管是MasterSender还是MasterReceiver),因为异常重启,也就是没有发送STOP。

则SCK保持低,会导致I2C时钟一旦使能,BUSY@SR2马上被硬件置位。

这样的话,再想进行I2C通信,则不能成功。

[Solution:

]

(1)重新发送STOP,可以使得SCK恢复高电平。

或者软件置位SWRST@CR1,等SCK恢复高电平了,再清零

(2)SWRST@CR1

ii.主设备接收通信过程中,如果没有正确发出NAK,则SDA将保持低电平。

[什么叫做没有正确发出NAK:

在while和中断方式下,没有在合时的地方清零ACK@CR1;在DMA方式下,没有在合时的地方置位LAST@CR2]

[Solution:

]

(1)板子断电

(2)关掉I2CAPB时钟,恢复GPIO功能,将SDA推高,再重新使能I2C。

iii.…

注释1:

如果I2C总线上还有其他主设备,可能会造成争抢对总线的控制,从而带来总线仲裁的问题。

因此,这里可以不发送Stop,而是直接发送ReStart,以免是否总线。

注释2:

为什么会有0x20010(BUSY+STOPF)的情况。

当I2C2接收DMA完成后,处理TC中断。

在这个过程中,I2C1这个主设备发出的STOP出现在总线上。

即在I2C2还没有退出TC中断时,STOPF已经置位,对应中断挂起位也被置位。

于是,在I2C2退出TC中断后,又因为STOPF进入中断,在这个过程中,因为I2C1发出STOP后,马上进入check阶段,又开始总线通信,所以在I2C2看来,BUSY也被置位了。

于是,I2C2会有个SR2<<8|SR1=0x20010(BUSY+STOPF)的情况。

注释3:

中线虚线-红色:

数据传输阶段;

中线虚线-绿色:

check阶段。

这是为了统一作为接收的对方是一般性的MCU的I2C接口,还是E2PROM之类的器件。

后者需要一定的写内部逻辑完成时间,所以需要这个check阶段。

注释4:

代码中,I2C1(主)I2C2(丛)。

在各自的ISR,有trace数组test1[50]&test2[50],调试用。

但是如果接收方是E2PROM的时候,注释掉。

因为E2PROM的check阶段会比较长,若干次start+addr+(nak)过程,溢出数组。

注释1:

在此设置LAST@CR2,表示下一个DMAEOT是最后一次数据传输,在收到最后一个数据后,由主设备在总线上产生一个NAK信号。

注释2:

对于MasterReceive()没有check这个阶段。

以上流程对应的主设备/从设备代码已经保存为bak_AppNote@各自的文件夹

现在对以上项目作进一步修改:

4.修改后的函数库接口

a)I2C_Comm_MasterSend

i.返回参数:

void

ii.函数参数:

1.端口:

I2Cx

2.从设备地址:

slave_addr

3.从设备偏移量:

offset

4.发送数据的内容:

pBuffer

5.发送数据的长度:

length

iii.函数意义:

从某个端口向slave_addr这个从设备发送数据pBuffer,并写入它的偏移量offset开始的地方。

如果从设备没有偏移量,则offset取值0xffffffff。

b)I2C_Comm_MasterReceive

i.返回参数:

void

ii.函数参数:

1.端口:

I2Cx

2.从设备地址:

slave_addr

3.从设备偏移量:

offset

4.接收数据存放的地方:

pBuffer

5.接收数据的长度:

length

iii.函数意义:

从某个端口向slave_addr这个从设备的偏移量offset的地方读取数据,放到pBuffer指定的地方。

c)I2C_Comm_SlaveReceive

i.返回参数:

void

ii.函数参数:

1.端口:

I2Cx

2.接收数据存放的地方:

pBuffer

3.数据长度:

length

iii.函数意义:

从某个端口接收到length个数据放到从pBuffer开始的某个地方,偏移量由master传过来。

d)I2C_Comm_SlaveSend

i.返回参数:

void

ii.函数参数:

1.端口:

I2Cx

2.发送数据存放的地方:

pBuffer

3.数据长度:

length

iii.函数意义:

从某个端口接发出放在pBuffer某个地方的length个数据,偏移量从master传过来。

1.修改Slave读写函数的参数,没有pOffset,因为它是由Master传过来的。

Slave根据此,条件性地修改DMA参数。

done

2.于是全局变量OwnOffset在每次SlaveSend/Receive()通信中,接收offset时被赋值,并且一直保持。

直到下次调用SlaveSend/Receive()是被清零。

done

修改后的函数接口为:

3.进一步修改从设备操作的参数当STM32模拟E2PROM时,往往并不知道对方读写的数据长度!

维持函数接口不变,只是函数内部处理:

如果length=0xffffffff,表示从设备预先不知道通信数据长度;否则,length为有效值,表示从设备预先知道数据长度,以此可以直接初始化DMA参数。

Length=0xffffffff,将DMAtransferlength设置为max=65536。

注意:

初始化DMA参数结构,DMA_InitStructure.DMA_BufferSize=65535;而不是65536!

因为CNDTR寄存器为16位,如果写65536(0x10000),会把低有效的16位全部清零。

这样的话,“Ifthisregisteriszero,notransactioncanbeservedwhetherthechannelisenabledornot.”

[调试时就犯了这个错误!

使得总线只能出现master发送的前两个数据。

那是因为前两个数据已把slaveI2C模块的DR和shiftReg填满了。

没有slave的接收DMA传输,DR和shiftReg都是满的,master发送方自己的DR和shiftReg也是满的,无法触发发送法自己的发送DMArequest。

]

如何检测何时结束DMA。

所以说:

Master-->slave:

stop位在ACK后,slave的该标志位可以置位;

[Solution]可以用Stop中断来结束DMA传输。

这样的话,代码流程会有变化:

由于DMAtransfersize初始化成了最大值,所以代码到不了DMATC中断了。

由于没有“接收完最后一个数据后的ISR,就不会有在那个ISR过程中stopf置位,退出中断,在进入时check阶段开始,busy又置位的情况”。

于是0x20010(busy+stopf)+0x20002(busy+ADDR)+0x10(stopf)的序列变成:

0x10(stopf)+0x20002(busy+ADDR)+0x10(stopf)。

所以0x10case要做相应修改。

流程图中,灰色框表示改变的部分。

Master<--slave:

stop位在NAK后,slave的该标志位不被置位。

[Solution]在NAK中断结束DMA传输,反正没有check阶段。

同样,所以代码到不了DMATC中断了。

在i2c2_err_isr()的NAKcase中,添加结束代码。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 学习计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1