DMA具备双缓冲机制,可以让数据在传输时候不断流,也就是我们所谓的PING-PONG-BUFFER,也就是说有AB两个BUFFER,DMA访问A时候,CPU访问B,DMA访问B时候,CPU访问A.这种实现导致总线矩阵相对复杂,所以,一般低端MCU也不会有这个机制.但是在做这个机制的试验时候,虽然可以做到PING-PONG BUFFER的传输,但是..却有点小意外.其实双缓冲,在配置过程并不难,比如提供一个配置参考:
9 j1 R* I+ @. b% s4 R( ] n( u
( G; u6 ^4 H) U/ X- DMA_DeInit(DMA1_Stream4);& _& k; L. s! k. z
- DMA_StructInit(&DMA_InitStructure);* F* ~( V9 r# {& C
- DMA_InitStructure.DMA_Channel = DMA_Channel_7;4 r1 R1 ^- k2 Y2 v* i
- DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART3->DR; //数据传输的外设首地址
, ^2 k# _6 |* y6 e - DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Buffer0; //自己定义待发送数组的首地址,要强制转换为32位
9 ^' m+ b6 o( H) N2 @; y - DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; //数据传输方向选择为内存->外设
8 [* J- C8 u8 y* `& b; Q - DMA_InitStructure.DMA_BufferSize = 4; //传输数据大小为8,大小要配合定义的数组类型和外设数据类型,否则会丢失或补充数据% E; t& w1 P9 A( ]9 o6 \+ w8 R$ z @) t
- DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器自动增加禁止,因为这里只用到了 DR 数据寄存器
# }9 B3 O1 g; e& J3 u8 x. k1 m. p - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址自增允许,因为要读取一个数组
7 j& R* `5 R5 Q1 V - DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设的数据大小,因为 USART3_DR 数据寄存器为8位,故选Byte
. Y6 d8 t, w6 O0 b0 ^- Y8 R+ }9 ]7 E - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //这里也选 Byte
, C! }) F+ ]( E. \7 C6 ^ - DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //DMA 传输模式为 DMA_Mode_Normal,如果为 DMA_Mode_Circular,将会循环传输1 f. O1 }# m/ w
- DMA_InitStructure.DMA_Priority = DMA_Priority_Low; //优先级为 High
8 J3 z- Y1 x9 S3 r) R - DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
6 R4 \5 B$ L/ S( ` - DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
3 U$ Q$ Z5 z, Z - DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
! m4 Q3 o8 q9 s4 S% \ - DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;1 \/ ] S6 d3 Y* _3 q6 K& ~0 A
- DMA_DoubleBufferModeConfig(DMA1_Stream4, (uint32_t)Buffer1, DMA_Memory_0);
2 P: p/ C0 h# l( M. a S - DMA_DoubleBufferModeCmd(DMA1_Stream4, ENABLE);
复制代码
5 s* B& ]+ `9 U9 J我们用了DMA1中STREAM4的CH7,所以这么初始化,并填入双Buffer,每个Buffer长度是4.因为用到的是Stream4,所以查询DMA_IT_TCIF4,然后再通过DMA_GetCurrentMemoryTarget,就可以知道该换那个Buffer,查到是在用1的Buffer,我们就填0号数组,否则填1号数组,就这么简单.) D K1 {1 p! l {3 M
+ c% X; V+ E1 D0 i4 P. Y- void DMA1_Stream4_IRQHandler(void)
5 C* Q4 g2 j$ A! T! t - {
4 F3 z! T8 ]5 K: e - uint16_t i = 0;
6 N/ F- `* u9 a/ q - GPIO_ResetBits(GPIOB, GPIO_Pin_12);3 ?: e3 ^. z3 j% K: w6 E
- if(DMA_GetITStatus(DMA1_Stream4, DMA_IT_TCIF4) == SET)$ p. L( _( I) Y( x Z+ w
- {$ E7 w0 G9 V A3 O' h1 O8 D
- DMA_ClearITPendingBit(DMA1_Stream4, DMA_IT_TCIF4);
6 \: a. E/ u5 B2 n: q4 e6 [3 C -
C* @7 c5 ?& y0 \2 P - if(DMA_GetCurrentMemoryTarget(DMA1_Stream4)) Q0 r+ n. ~9 W9 K" ?8 A& b2 j
- {9 [: E. C0 ]/ H
- //现在访问是Buufer1,所以写Buffer0.$ }) [4 p4 {: T0 P5 j+ W6 O. W. p
- for(i = 0; i < 4; i++)% \ `+ F% D& f% P/ j
- {& {& c( L3 t/ j7 U3 G" h1 O
- Buffer0[i]++;
5 y$ a- J" i8 }7 K - }$ j& J2 O" h! Y
- }9 K$ ~1 I0 j( ]8 X
- else7 [9 L( C1 L" x9 p0 Z
- {" A) m( Y! V3 c; }4 }5 `9 x
- for(i = 0; i < 4; i++): G. ?& l( s% B
- {
G- A& x8 {, H5 ?" x; c9 P* Z -
6 S4 m2 A& b# O3 i - Buffer1[i]--;) ^9 B+ p: Q+ \$ a' t( R* Q! o
- }" e5 [9 }; A/ V. @2 g0 C& u( P! L
- }
" M% K+ k k( v; E- m0 l7 i - & F, {! D+ m0 Y+ s$ w; Z
- }: N7 ]' e$ `6 Q! r7 R& S
- ! F" a8 Z! R) ~3 k/ g7 g
- }
复制代码
. Z U- R( E. X3 Y+ E' V! \; i; D# ~4 M————————————————8 e3 Z8 z# q9 S" n. T& f1 z
版权声明:JawSoW4 B7 z" p2 J4 \
* p2 c+ u* t% |! C3 Z# O |