在项目开发的进程中,发现程序总是死在判别DMA一次传输是否完结这个标志位上。进一步回退剖析,发现是在I2C读的进程中,有运用到DMA去取外部I2C设备的data。
可是data并没有读完,Data为32bits,DMA在读到18bits时,就呈现读不到data bit了。导致I2C硬件模块不能进一步动作,SCK一向被拉低,没有clock输出,SDA也是如此。
下面是通过示波器抓到的波形:
在上面的波形图中,绿色的是SCK,蓝色的是SDA。
在榜首幅波形图中,有2段波形,榜首段接连的I2C波形,通过承认I2C硬件和DMA合作是正常的。第二段则是有一段I2C波形,然后就SCK和SDA就都被拉低了。
将榜首幅图的第2段波形扩大,便是第二副图看到的状况。能够很显着的看到SCK输出有被其他要素打断。I2C吐出几个clock,被其他要素打断了,clock线即SCK被拉低一段时间,然后clock线再持续吐出几个clock。
直到I2C被频频中止,clock吐不出来停止,SCK和SDA都被拉低,此刻显着的I2C和DMA的合作进程被其他要素频频的搅扰打死了。
通过示波器抓到的波形验证了这一点,然后再来剖析代码和串口输出,发现是外部GPIO一向有中止输入,Cortex-M3 MCU频频的呼应中止,导致I2C&DMA操作被打挂了。
有什么办法来处理这个问题?
办法便是在I2C和DMA操作的进程开端处封闭一切中止,而在操作完毕的时分从头翻开中止,避免I2C&DMA操作被其他中止打断。
ARM MDK编译环境自带的编译器ARMCC,含有内置的c函数,可供操作中止用:
__enable_irq();
__disable_irq();
不过debug发现这两个函数只会在privileged mode运用。也便是说需求Cortex-M3 MCU先进入privileged mode,才干调用这两个函数。
用什么办法让MCU从user mode切换到privileged mode呢,excepTIon handler!
能够用SVC啦,软件能够使用SVC制作一个excepTIon,然后在excepTIon handler中使用MCU的privileged mode来完结自己的使命。有点类似于linux里边的体系调用。
SVC excepTIon能够调用SVC函数,而SVC函数能够传入参数,也能够回来参数。转为体系调用而规划。
举个比如,用户程序调用read()这个体系调用,read()会引发SVC exception,从而调用SVC函数,read()函数的参数传递给SVC函数,SVC在内核态履行硬件动作,并将SVC函数的回来成果,作为read()函数的回来,回来给用户程序。当然linux里边并不一定是SVC,这儿仅仅做个类比。
也便是说SVC能够完结从用户态到内核态的改变,不让用户直接操作硬件。用户只需求记住体系调用API的姓名和函数即可,而不必管硬件的详细完成。
所以这儿咱们就把I2C读的操作放在一个SVC函数里边去完成,并且在SVC函数的开端处调用__disable_irq();在函数的完毕处,调用__enable_irq()。
通过验证,I2C&DMA操作再也不会被中止打断了。