ADC1DMA_Handler.Init.Mode
) K1 c) d: u% i( ?4 s$ @: ZDMA的正常模式(DMA_NORMAL):采集到DMA_BufferSize 的个数后,DMA停止。
' _8 Y, L7 e% F. Y( m1 E3 eDMA的循环模式(DMA_CIRCULAR):采集到DMA_BufferSize 的个数后,重新回到设置的RAM的起点位置,如此循环。" z1 @# A5 t j( Z4 D
虽然道理很好理解,但个人感觉要配合触发信号来用,通过HAL_ADC_Start_DMA软件触发需要设置起点位置和长度,否则这个参数是没有意义的。& S/ p5 y' w& g: O) X6 g
k) `! [( I& j1 K5 V& {
ADC1_Handler.Init.ScanConvMode
0 _- d1 }+ Q! A. D3 u扫描模式(ENABLE):ADC会依次扫描设置的各个rank. Q6 Q* Q' {& r1 g3 P" d
非扫描模式(DISABLE):ADC只会读取rank1,即使设置的DMA_BufferSize大于2,也只会读取第一个;如果没设置rank1(此时我的设置里rank2接的3V3,rank3接的gnd),读出来的结果是516这种奇怪的东西,我也不知道是个什么鬼东西……
! i( U' u1 m! N6 p4 W即使需要只读取rank1的值,把NbrOfConversion不就可以了嘛~
" r6 a9 `5 \) n6 q所以这个参数我建议设置成ENABLE,我也不知道什么时候该用DISABLE。
8 _6 j2 w2 M$ ]6 {/ p) k+ _. U6 ~" i+ B
ADC1_Handler.Init.ContinuousConvMode
6 p% Y) X4 {7 N: I( ?3 F- p5 `6 o; I0 H开启连续转换:开启了连续转换后,adc会一直转换,直到DMA_BufferSize大小,如图是HAL_ADC_Start_DMA 64个长度的结果。# Z- a+ ^0 \3 W+ ?; z
. t5 S: F" m) }6 Z$ ?: S: A' {
7 b) k! a( J( C1 [* f而不开启连续转换,长度为64的同时,DMA的传输中断都不会进。' ~; I# M/ L+ J( F
6 s. W- Y/ U) r) c% P, j+ |$ o: `) H* K6 i) C$ H7 C: C0 p
而将传输长度设置为3的时候,就进入了传输完成过半的中断。2 L7 C3 ^' y& j2 I) t- F8 e
5 o3 R. K9 r* S' |% C$ M' i' Y9 W- q1 P/ p. v
1 {4 v$ e. `% c, M# ~ M
如果我们需要采集连续的N个次结果求平均值,用这个连续转换会很方便。3 _0 |4 I% @ c. ]( N
也从侧面说明,dma的传输中断是一定要有那么长的真实采集数据来才能进的。1 ]+ ?, R' b6 ~0 O' l
3 P4 q* e5 Z" K" ~, c/ L& O2 p: d
在另外一篇里看到了这么一个表格,希望能够辅助大家理解:
5 d: t) L6 }# y6 e. m
. {: e, B: r) |) a8 D$ k, n0 D
9 k: |1 e2 x9 C, u
4 D( \/ I5 b3 u& f' O: oADC1_Handler.Init.DMAContinuousRequests
- U% l- b0 I8 J& w: V- A( j/ t当设置了定时器触发DMA之后,这个参数如果设置为DISABLE,就只会采集一轮数据,然后结束。
1 r) o/ N# a R3 z: E这个数据设置成了ENABLE之后,这个参数设置为ENABLE,一轮采集完成之后,感觉就会自动调用一次HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)buffer, 100);,触发DMA请求,以实现不停采集。
% D# e: U B1 l5 Z
& B: Z2 O- p6 }) v7 g但是需要注意,如果开启了连续转换,又开启了DMA连续请求,adc将一直进行采集,一刻也不停歇…… P2 ?( n) A& _1 m
8 A9 U& O3 W1 g9 VADC1_Handler.Init.EOCSelection1 H) o0 K' q& {
EOC听说是转换结束标志,这里暂时也没用到,也先埋一个坑……
: p' Q m5 N: \$ ~填坑STM32F7实现ADC等周期采集(定时器触发+DMA传输)采集完成后的中断设置
" D) y" _6 [! d: @- U, s. K6 q
6 ^3 J# r8 _- s1 J [- u& S偶然看到一个帖子的回复:
1 {- |/ h6 p( a- I0 {5 c当有CPU和其它主设备【如DMA】共同访问某可缓存的二级存储器比方SRAM1,同时该存储器又具有回写属性,此时就可能发生数据一致性问题。因为该存储器的回写属性,导致通过CPU欲写入存储器的数据只是缓冲在CACHE里,而没有及时写入存储器。如果此时DMA访问该二级存储器的话,读到的数据可能跟预期不一致。
9 N/ R3 {2 h m8 K; s8 m! h为了避免数据不一致的问题,我们需要做D-CACHE维护操作。一般有如下四种方法: 1、当对一个可缓存的二级存储器做了写数据操作之后,通过软件对D-CACHE进行清除操作,即运行SCB_CleanDCache()。这样将CACHE里的缓存内容写回到二级存储器,比如把那些DIRTY
: \. N8 R( x1 T+ X% I" |7 S) h" f4 }& FCACHE行的数据写进SRAM1。* z0 n' Y1 v6 W$ i) T! W# c
2、通过MPU调整可缓存存储器的存储属性,将其CACHE使用方式改为透写模式。这样保证每次写入CACHE里的内容也同时写入二级存储器,比如写进SRAM1。0 S3 A, l: P7 H+ Z
3、通过MPU调整可缓存存储器的存储属性,将其共享属性改为可共享的【SHAREABLE】。此后该二级存储器将变为不可缓存。
$ Z6 S' E! }7 d. W' n/ x1 I, w4、通过配置CACR寄存器中的D-CACHE位,强制将所有写操作配置为透写属性。
1 U3 [( ~& ?+ G
9 z. t) U+ `6 L2 y在main函数中关闭cache,DMA采集的数据就可以更新了。; ]7 O R+ b `7 ?& C' w
( n/ d( _1 ]' e
2 x8 [ H& h/ L( r2 U: G9 C
& B1 C& m3 X! ]5 ]: I# m- r附上成功时候的配置,注释掉HAL_NVIC_EnableIRQ是因为中断服务函数里的打印会导致main函数无法继续执行。
+ v* H% `& A% T. x, L4 h
8 c" A3 D$ H' w8 r- #include "adc.h"
7 ]: |' R. X- \& e* O - #include "delay.h"9 \! p0 i* J, e3 Z+ c
" j$ _+ ?; N* T; u- ADC_HandleTypeDef ADC1_Handler;//ADC句柄
. s" N. F* V& u2 v9 ~5 t9 T - DMA_HandleTypeDef ADC1DMA_Handler;) \! r4 x, R* h. S6 T% L! l$ [# ]4 F5 w
- ADC_ChannelConfTypeDef ADC1_ChanConf;
* _2 B2 i3 ~6 Z$ g( t% M8 s2 @
) h' G+ w6 w* W0 N- uint16_t buffer[128];
9 s7 N2 V- F7 H9 G, R3 T
* Q; I4 l% |: _- , ~. {2 b8 I. f' q8 ^) S
- //初始化ADC
h! K0 A# {- Z1 y* z: B - //ch: ADC_channels* @! a; V& w4 [7 [4 c
- //通道值 0~16取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16
0 s2 N- U* Y ]/ W3 y4 S% S5 J9 F7 ? - void MY_ADC_Init(void)
+ G& F+ G+ t. s+ ^, W - {
( Q; T: k9 C! [/ ^& z$ c0 Y7 W - __HAL_RCC_DMA2_CLK_ENABLE();7 n5 r; c/ ~! l `& S' e
- HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
9 i7 Y. r: d" O4 }& m+ ] - //HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
6 z$ I) y/ R0 n6 f
" Z% C9 o2 y+ \+ h! J! G- ADC1DMA_Handler.Instance = DMA2_Stream0;
, D' S1 Q. {% Z, j - ADC1DMA_Handler.Init.Channel = DMA_CHANNEL_0;. ?& ]7 a9 Z0 T! f
- ADC1DMA_Handler.Init.Direction = DMA_PERIPH_TO_MEMORY;
3 L# j2 h) U, W% D- ^2 P9 x7 O0 Q - ADC1DMA_Handler.Init.PeriphInc = DMA_PINC_DISABLE; //外设非增量模式. G( O( L2 C9 g, K5 E: ]" l
- ADC1DMA_Handler.Init.MemInc = DMA_MINC_ENABLE; //存储器增量模式
, f* ^* ?& V5 n7 W/ m - ADC1DMA_Handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; //外设数据长度:16位0 P0 o# Z& N- t* y/ E, }- X+ d
- ADC1DMA_Handler.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; //存储器数据长度:16位" U' q% q* w: W! |! ]! M
- ADC1DMA_Handler.Init.Mode = DMA_CIRCULAR; //传输一次就结束7 j' _1 I7 T- e& ~/ {4 ~! }! y
- ADC1DMA_Handler.Init.Priority = DMA_PRIORITY_LOW; //中等优先级
% N4 N& r( T% }4 r - ADC1DMA_Handler.Init.FIFOMode = DMA_FIFOMODE_DISABLE; /* 禁止FIFO*/% _2 S- J& y9 R" J
- 5 B; a1 G! v) W. p; d; b
- HAL_DMA_Init(&ADC1DMA_Handler);
- a. I: v7 m% z+ B E! i/ z/ i- | - 9 q, g6 a9 s ` {! U
- __HAL_LINKDMA(&ADC1_Handler, DMA_Handle, ADC1DMA_Handler); //将DMA与ADC联系起来
* Q. |0 V* n/ z G0 K$ a8 m - : p7 r9 l+ n! V3 H
- 4 C2 C; i# O% s5 N
- ADC1_Handler.Instance = ADC1;
) S& w8 P5 K1 B/ M! B - ADC1_Handler.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; //4分频,ADCCLK=PCLK2/4=108/4=27MHZ
' z, o5 q( x9 n9 `" j$ q - ADC1_Handler.Init.Resolution = ADC_RESOLUTION_12B; //12位模式
. ~; y8 d/ j( C* c6 d - ADC1_Handler.Init.ScanConvMode = ENABLE; //非扫描模式9 y: j+ r0 ?1 i) s0 W
- ADC1_Handler.Init.ContinuousConvMode = ENABLE; //关闭连续转换
& C. P4 a1 D$ P4 C - ADC1_Handler.Init.DiscontinuousConvMode = DISABLE; //禁止不连续采样模式
4 z+ b) H$ R9 c5 g/ L! H - ADC1_Handler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //使用软件触发3 M0 f# l# A7 ~" }; }$ F z
- ADC1_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START; //软件触发& ]$ z2 J- W5 U' w& f; V; }' ~* T
- ADC1_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT; //右对齐' ~1 }" \2 x0 @- y1 i3 V8 Q9 |
- ADC1_Handler.Init.NbrOfConversion = 2; //1个转换在规则序列中 也就是只转换规则序列1) T7 b% ~& H" F' v* N+ ]! H
- ADC1_Handler.Init.DMAContinuousRequests = ENABLE; //关闭DMA请求9 [- @9 N% j( K" A' O% J
- ADC1_Handler.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
3 m7 Y. q( u! k' v& w6 x6 V4 j - HAL_ADC_Init(&ADC1_Handler);5 D) O: [2 E& K8 w# B$ `/ h
- , n' ^7 Q4 Z2 }2 R8 ^4 g
- ADC1_ChanConf.Channel = ADC_CHANNEL_5; //通道0 V4 y* \. o' \% ]! {
- ADC1_ChanConf.Rank = 1; //序列1
8 K% \/ x, x% ~- V/ b: u - ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES; //采样时间 v+ L( b* L7 C4 |4 l! k* v
- ADC1_ChanConf.Offset = 0;) r0 G7 X7 F1 T% d% `! W4 }
- HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf); //通道配置" N. a2 R7 z* Z2 J; ^% F/ @. w
- # A7 A/ U, y& D2 L- k, w' b2 H0 ~
- ADC1_ChanConf.Channel = ADC_CHANNEL_6; //通道
- {5 [( v- G7 u/ n - ADC1_ChanConf.Rank = 2; //序列2
3 \) t. X1 f0 `7 w0 F& F4 q" V - ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES; //采样时间
0 \! [2 C- R \/ ] - ADC1_ChanConf.Offset = 0;/ [1 K6 ^1 p% h3 a9 j
- HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf); //通道配置! m! q m" e. M) u2 `2 J
- 8 ^8 P! d7 m5 F
- HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)buffer, 100);
; m' q) b- v0 V; |9 K - }/ _! b) g: C0 Q6 x( A% K# E) v
2 f3 @* l+ B& P+ v" D- Y' U/ m- //ADC底层驱动,引脚配置,时钟使能
3 V0 g7 y9 r3 V1 f- o - //此函数会被HAL_ADC_Init()调用
1 r8 T( t. c( { b - //hadc:ADC句柄. T1 k1 _' p3 s; ]
- void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
' V- L6 l" l$ H2 C% w/ t. _* \ - {3 O% h4 t) h- o# O
- GPIO_InitTypeDef GPIO_Initure;2 p% U7 L3 t; D2 O$ f
- __HAL_RCC_ADC1_CLK_ENABLE(); //使能ADC1时钟
9 W) ?# f7 _3 s3 s - __HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
$ q7 j# z/ C0 u; w/ i
# _9 ?4 y e5 `# V- GPIO_Initure.Pin = GPIO_PIN_5|GPIO_PIN_6; //PA57 w) f3 z. S$ b. [& x& c( |7 b
- GPIO_Initure.Mode = GPIO_MODE_ANALOG; //模拟
7 v n) x: ?! R- D: }5 G% m0 d# i - GPIO_Initure.Pull = GPIO_NOPULL; //不带上下拉9 [- s! l7 d- q
- HAL_GPIO_Init(GPIOA, &GPIO_Initure);7 m7 j7 J' c2 R. R. T4 ]2 t, @/ X
- }: A7 k& h( v+ Q& F; {2 i$ v* u
- 5 D- w: Q) l! L6 C: f
- void DMA2_Stream0_IRQHandler(void)
5 W% a( s1 U5 }6 N+ ` - {
& j0 M3 X7 n/ D! ^! ] - HAL_DMA_IRQHandler(&ADC1DMA_Handler);* A# h/ d3 i& V6 s' g. y
- }
- ?1 t! F, ?6 J# r) V
9 ^4 T5 I/ Q: T7 R- Y+ w; ]- void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
7 C/ |( @( R1 ^4 f7 [, A& T, S - {! [ A( I& X" [) d) m1 \
- printf("DMA transfer complete\r\n");( |9 V) \7 X" G3 k
- }
0 j. i& l( X0 M- a' R) O - void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc)' ^( c2 }; V7 M! a+ O" ~; k
- {5 R9 ?0 _ z, {
- printf("DMA Half transfer complete\r\n");' f3 a8 b8 w% ]3 o: _& f
- }8 v' m4 F& r: b* J0 F. R
. o, k3 e- K* ?5 \1 A5 B, R. {- void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc)
! q S2 I& e: ~" l - {0 ~4 f* b; g! z' {/ t
- printf("DMA transfer error\r\n");( u6 ?% Q2 w w
- }
复制代码
" V" f" d3 u0 J7 {$ K2 F( o4 k; k
8 T2 N; h! S) v3 J, W1 d+ ~! q2 M- #include "sys.h"
. x+ Z# j) M2 g, J' T3 W; G. i - #include "delay.h"8 E; s- k9 S& N1 M+ F
- #include "usart.h"
& g7 H# F7 E7 M/ T0 M) P - * D( t: t; r0 ^
- #include "adc.h"; q n* l' Z; z1 p, c, T4 ?
- , N4 a, a( |3 i! Z* w, a
- extern uint16_t buffer[128];% O& Y6 U- @5 O4 b* {; K% a
- 4 \9 k# ^' Z5 u& C) b1 B! ~
- void show()
$ @2 ^" Q& r. u; d* p6 a1 g - {. m2 a r* g4 n
- int i;
, a) G3 H- Z+ h' G2 n0 e - printf("\r\ndata:");9 u y9 }$ r% T: L* _2 ]& s
- for (i = 0; i < 128; i++)
/ k. B8 u2 w9 ?( @1 d7 d - {
. C7 W" R7 N0 P" h9 ^( q5 `% ]* { - if (i % 16 == 0) printf("\r\n");! f* m0 j* a' ?! |& `2 O/ y, h
- printf("%6d", buffer);$ z7 v" I7 z2 j, W5 K
- buffer=0;
: s2 r- B, |2 F5 c; l - 8 ^2 b3 D0 O( F5 H
- }
7 X# L! A0 N0 E% G* u9 ]5 B, \ - printf("\r\n");
' b/ t% d- i! O- I. r; _- P - }
- P `5 o- J! T0 j
! `9 i' s9 J7 C2 L- ! ?8 w* E; {9 h* S
- int main(void), o% _# s% V- D) ]9 p; q" }
- {" U/ B: ] d9 q, E7 m
- //Cache_Enable(); //打开L1-Cache
. v$ p& L; L$ w% I; s8 b1 D1 j3 c' v: E - HAL_Init(); //初始化HAL库1 ?0 g" J/ O( h) k) }6 J
- Stm32_Clock_Init(432, 8, 2, 9); //设置时钟,216Mhz
6 A$ o. D# `* _! c/ d) k - delay_init(216); //延时初始化
! e3 O% D9 _* z6 e - uart_init(115200); //串口初始化! y2 ?: l( [6 d0 m) {
- % [; b2 K. K0 Y& j+ Q8 H
- printf("start\r\n"); F0 d( [! _) ?1 W, [9 _. d/ z
- MY_ADC_Init(); //初始化ADC1通道5
9 ^. [) q' t7 L- I' b/ o0 H
, u% B, y" I Q/ S% |( m0 i) C" R- while (1)( [* x5 X* h' k2 F9 u/ F/ d# ]
- {! ^: p) L" m7 f- g T4 K, o$ U
- show();
% b/ ], x! d" Z - delay_ms(1000);1 H( F( e4 F: U
- }' U0 W1 ?& f# ]" [
- }
复制代码
' |% S/ Z+ }" R! }0 n0 [9 w' z4 W2 q7 l: h9 y& ^0 @1 a3 p" S
|