|
曾经有STM32用户反馈如下情况: 5 f8 a" h3 }" b3 j8 W 选择STM32F7芯片开发产品,使用了USART1的DMA接收和发送,并开启了USART1的IDLE中断,IDLE中断正常,能成功接收到数据。通过仿真能看到接收缓冲区数组中的数据,但就是不能访问它。如果不访问,重新开启DMA接收能正常接收,并且在仿真状态下也能查看。只要访问一次这个接收数组,下一次开启DMA接收就不能接收数据了。2 Q, I( R# z8 {4 R; S& u$ p 客户还补充说,之前使用STM32F1芯片时实现同样功能没有任何问题。 * b" i8 T8 F3 d8 p4 `& E 从客户的反馈来看,他是说不能对接收到的数据进行读取访问,读取之后就再也不能接收后续数据了。这样说听起来有点玄乎。; _- R* t7 v& n7 r8 q 1 i5 { U8 m8 \+ n " F* w) A/ M- c* D0 z 随便找块STM32F7的nucleo板进行验证测试,反复验证确认,没有发生客户所说的现象。我在程序代码中也加了对接收数组数据的读取操作。使用循环模式不停让DMA进行UART的收、发,并不时修改发送缓冲区的数据,接收端一直能正常接收,收、发端数据完全一致。【如下图所示】7 ]7 H4 W: D0 M0 m) H8 E 7 J# z2 d# G+ G" a4 z1 G
0 _) f4 z2 M; @) ~$ }7 L 既然不存在客户反馈的读取接收数组后就无法继续接收数据的问题。那客户的真实问题到底是什么呢?要表达什么呢?后来进一步得知,客户的代码中有如下语句,它会读取接收缓冲的数据。 7 D2 U+ @) U( [) c6 U4 ]* P
7 {3 K7 s5 c! d/ G( w+ J( D 客户补充说,程序不能执行上面代码,否则就不能再接收后续数据了。屏蔽掉这条语句在仿真状态下能观察到aRxBuffer接收正常。0 z, }0 w8 j* q( U / l( g* c' }) G6 ^4 _) w' ` * o- b6 [; {4 a 现在事实上并非他所表述的那样,他真正要表达的是自从读取该接收数组数据之后,不管后续的收发数据怎么变化,他从这个函数里都没法从接收缓冲区读到新数据并显示出来。4 H5 f& I, _0 C+ n5 g8 i9 ~4 q7 T 6 X M% W# I. v- M" a 我在测试代码里也写了类似代码,顺便瞧瞧结果。我在测试代码了建了个临时观察数组temp[],从接收数组aRxBuffer里读取几个数据存放进去。 4 f* f. c# J9 r% `& ?7 O a
) N! t6 L$ Q" i 测试中可以发现,无论怎样修改发送缓冲区aTxBuffer的数据,接收数组aRxBuffer的数据都会同步变化,但这个temp[]数组里的数据永远都保持第一次发送/接收到的数据。/ r) p2 f' M8 Q/ L. `, d) ~+ |; l8 j . w; n; o& Y; w ) s O5 K5 q: O7 W/ R. j
3 U+ i' n6 C: ^0 W2 \* K( n 3 z9 [1 d2 _& i 看到这里,结合测试现象大致得知原因了,问题应该跟D-cache数据与实际存储区数据一致性问题有关。 ) j: c3 e3 l: w8 y. B7 ^8 B STM32F7系列芯片支持高速I-Cache和D-CACHE,接收数组aRxBuffer内存区数据默认可以使用D-cache,使用它可以大大提高CPU的访问速率。不过,使用D-Cache要注意实际物理存储区与高速缓存区的数据一致性问题。 8 z- Y H8 c# p+ M) q- u( \6 t 具体结合本案例,发送缓冲区的数据通过UART发送出去后,UART数据寄存器接受到数据后,DMA将数据写入接收缓冲区RxBuffer[],CPU从RxBuffer[]将数据读进Temp[]数组。5 [; ^7 k5 `# y$ C% f7 l 0 _4 u4 F* a+ S$ r 在使能D-Cache的前提下,CPU第一次读取接收数组的数据到Temp[]数组后,并将相应数据放入D-cache进行缓存。之后,CPU再来读接收数组的数据时,并没有前往接收数组实际物理存储区去读取数据,而是直接去D-cache里读取数据了。由于Cache数据没有做更新,这样的话,即使接收数组Rxbuffer数据变化了,D-Cache里的数据并未相应改变,所以就出现了CPU从Cache里读到的数据总不变的情况,给人一种后续数据没有接收进来的错觉。8 W1 W$ ~8 O- y ! m: f! p- {# O' w7 p5 l5 m
那如何解决这个问题呢?方法较多,可以根据具体应用情况而定。这里介绍两种方法: 1 g; D9 t# Q7 Q 1、每次读取接收数组的数据之前先对D-cache做个清除操作或者说刷新操作,让实际物理存储器里的数据与Cache里的数据先做同步更新。相应的STM32库函数代码为:SCB_CleanDCache ( );! R- o/ N9 s5 ` u# G2 e 2、在读取接收数组的数据之前先做个D-cache失效操作,这样让CPU无视D-Cache而直接去实际物理存储器区读取数据。相应的库函数代码是SCB_InvalidateDCache(); 经过验证测试,两种办法都可行,也不再出现客户反馈的异常现象。; f3 {5 w6 A8 K5 u; l6 e
关于带D-Cache的多主存储访问过程中的数据一致性问题,既可能发生在CPU对某可缓存存储区进行写操作,DMA对相应存储区进行读操作时,也可能发生在DMA对某可缓存存储区进行写操作,CPU对相应区域进行读操作的情形。本案例就是后面第二种情形,在该情形下,为了保证SRAM与D-Cache里数据的一致性,在CPU对SRAM区数据读操作之前,须针对D-Cache进行失效操作。 3 j \: R: l2 ] ; D6 V! Y9 j: K, z( \: j8 G 关于STM32 D-Cache及数据一致性问题,已经不少文章介绍,这里不再赘述。在此分享该实际案例,一方面是为了加深相关知识的了解,另一方面是为了多引起应用工程师对相关问题的关注。毕竟因D-Cache一致性导致问题时也是相对比较隐蔽的,加上以往低端MCU也没有这类东西,缺乏经验积累,应用中容易被忽视而找不到原因。 4 c# i) W0 Z3 G- [ o1 X% v |
无刷直流电机控制应用+基于STM8S系列单片机---电子书
MCSDK FOC应用详解
STM32F10xxx 正交编码器接口应用笔记 及源代码
基于STM32定时器ETR信号的应用示例
《无刷直流电机控制应用 基于STM8S系列单片机》
STM32定时器触发SPI逐字收发之应用示例
【银杏科技ARM+FPGA双核心应用】STM32H7系列10——ADC
【银杏科技ARM+FPGA双核心应用】STM32H7系列57——MDK_FLM
【STM32图书分享之九】—《STM32F 32位ARM微控制器应用设计与实践》
STM32 USB的程序,包含固件、驱动和测试用的应用程序
微信公众号
手机版