你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32F7实现ADC采集(软件触发+DMA传输)解决了采样结果不实时更新的问题

[复制链接]
STMCU小助手 发布时间:2021-12-15 11:00
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' {
20200419192759329.png

7 b) k! a( J( C1 [* f而不开启连续转换,长度为64的同时,DMA的传输中断都不会进。' ~; I# M/ L+ J( F
20200419192936345.png

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' |
20200419194129548.png
% 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
20200421214739891.png

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
20200419215859139.png
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
  1. #include "adc.h"
    7 ]: |' R. X- \& e* O
  2. #include "delay.h"9 \! p0 i* J, e3 Z+ c

  3. " j$ _+ ?; N* T; u
  4. ADC_HandleTypeDef ADC1_Handler;//ADC句柄
    . s" N. F* V& u2 v9 ~5 t9 T
  5. DMA_HandleTypeDef ADC1DMA_Handler;) \! r4 x, R* h. S6 T% L! l$ [# ]4 F5 w
  6. ADC_ChannelConfTypeDef ADC1_ChanConf;
    * _2 B2 i3 ~6 Z$ g( t% M8 s2 @

  7. ) h' G+ w6 w* W0 N
  8. uint16_t buffer[128];
    9 s7 N2 V- F7 H9 G, R3 T

  9. * Q; I4 l% |: _
  10. , ~. {2 b8 I. f' q8 ^) S
  11. //初始化ADC
      h! K0 A# {- Z1 y* z: B
  12. //ch: ADC_channels* @! a; V& w4 [7 [4 c
  13. //通道值 0~16取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16
    0 s2 N- U* Y  ]/ W3 y4 S% S5 J9 F7 ?
  14. void MY_ADC_Init(void)
    + G& F+ G+ t. s+ ^, W
  15. {
    ( Q; T: k9 C! [/ ^& z$ c0 Y7 W
  16.     __HAL_RCC_DMA2_CLK_ENABLE();7 n5 r; c/ ~! l  `& S' e
  17.     HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
    9 i7 Y. r: d" O4 }& m+ ]
  18.     //HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
    6 z$ I) y/ R0 n6 f

  19. " Z% C9 o2 y+ \+ h! J! G
  20.     ADC1DMA_Handler.Instance = DMA2_Stream0;
    , D' S1 Q. {% Z, j
  21.     ADC1DMA_Handler.Init.Channel = DMA_CHANNEL_0;. ?& ]7 a9 Z0 T! f
  22.     ADC1DMA_Handler.Init.Direction = DMA_PERIPH_TO_MEMORY;
    3 L# j2 h) U, W% D- ^2 P9 x7 O0 Q
  23.     ADC1DMA_Handler.Init.PeriphInc = DMA_PINC_DISABLE;               //外设非增量模式. G( O( L2 C9 g, K5 E: ]" l
  24.     ADC1DMA_Handler.Init.MemInc = DMA_MINC_ENABLE;                   //存储器增量模式
    , f* ^* ?& V5 n7 W/ m
  25.     ADC1DMA_Handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;  //外设数据长度:16位0 P0 o# Z& N- t* y/ E, }- X+ d
  26.     ADC1DMA_Handler.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;     //存储器数据长度:16位" U' q% q* w: W! |! ]! M
  27.     ADC1DMA_Handler.Init.Mode = DMA_CIRCULAR;                          //传输一次就结束7 j' _1 I7 T- e& ~/ {4 ~! }! y
  28.     ADC1DMA_Handler.Init.Priority = DMA_PRIORITY_LOW;             //中等优先级
    % N4 N& r( T% }4 r
  29.     ADC1DMA_Handler.Init.FIFOMode = DMA_FIFOMODE_DISABLE;            /* 禁止FIFO*/% _2 S- J& y9 R" J
  30. 5 B; a1 G! v) W. p; d; b
  31.     HAL_DMA_Init(&ADC1DMA_Handler);
    - a. I: v7 m% z+ B  E! i/ z/ i- |
  32. 9 q, g6 a9 s  `  {! U
  33.     __HAL_LINKDMA(&ADC1_Handler, DMA_Handle, ADC1DMA_Handler);                //将DMA与ADC联系起来
    * Q. |0 V* n/ z  G0 K$ a8 m
  34. : p7 r9 l+ n! V3 H
  35. 4 C2 C; i# O% s5 N
  36.     ADC1_Handler.Instance = ADC1;
    ) S& w8 P5 K1 B/ M! B
  37.     ADC1_Handler.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; //4分频,ADCCLK=PCLK2/4=108/4=27MHZ
    ' z, o5 q( x9 n9 `" j$ q
  38.     ADC1_Handler.Init.Resolution = ADC_RESOLUTION_12B;           //12位模式
    . ~; y8 d/ j( C* c6 d
  39.     ADC1_Handler.Init.ScanConvMode = ENABLE;                    //非扫描模式9 y: j+ r0 ?1 i) s0 W
  40.     ADC1_Handler.Init.ContinuousConvMode = ENABLE;              //关闭连续转换
    & C. P4 a1 D$ P4 C
  41.     ADC1_Handler.Init.DiscontinuousConvMode = DISABLE;           //禁止不连续采样模式
    4 z+ b) H$ R9 c5 g/ L! H
  42.     ADC1_Handler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //使用软件触发3 M0 f# l# A7 ~" }; }$ F  z
  43.     ADC1_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START;     //软件触发& ]$ z2 J- W5 U' w& f; V; }' ~* T
  44.     ADC1_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT;           //右对齐' ~1 }" \2 x0 @- y1 i3 V8 Q9 |
  45.     ADC1_Handler.Init.NbrOfConversion = 2;                       //1个转换在规则序列中 也就是只转换规则序列1) T7 b% ~& H" F' v* N+ ]! H
  46.     ADC1_Handler.Init.DMAContinuousRequests = ENABLE;           //关闭DMA请求9 [- @9 N% j( K" A' O% J
  47.     ADC1_Handler.Init.EOCSelection = ADC_EOC_SINGLE_CONV;        
    3 m7 Y. q( u! k' v& w6 x6 V4 j
  48.     HAL_ADC_Init(&ADC1_Handler);5 D) O: [2 E& K8 w# B$ `/ h
  49. , n' ^7 Q4 Z2 }2 R8 ^4 g
  50.     ADC1_ChanConf.Channel = ADC_CHANNEL_5;                                 //通道0 V4 y* \. o' \% ]! {
  51.     ADC1_ChanConf.Rank = 1;                                     //序列1
    8 K% \/ x, x% ~- V/ b: u
  52.     ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES;      //采样时间  v+ L( b* L7 C4 |4 l! k* v
  53.     ADC1_ChanConf.Offset = 0;) r0 G7 X7 F1 T% d% `! W4 }
  54.     HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf);       //通道配置" N. a2 R7 z* Z2 J; ^% F/ @. w
  55. # A7 A/ U, y& D2 L- k, w' b2 H0 ~
  56.     ADC1_ChanConf.Channel = ADC_CHANNEL_6;                                 //通道
    - {5 [( v- G7 u/ n
  57.     ADC1_ChanConf.Rank = 2;                                     //序列2
    3 \) t. X1 f0 `7 w0 F& F4 q" V
  58.     ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES;      //采样时间
    0 \! [2 C- R  \/ ]
  59.     ADC1_ChanConf.Offset = 0;/ [1 K6 ^1 p% h3 a9 j
  60.     HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf);       //通道配置! m! q  m" e. M) u2 `2 J
  61. 8 ^8 P! d7 m5 F
  62.                 HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)buffer, 100);
    ; m' q) b- v0 V; |9 K
  63. }/ _! b) g: C0 Q6 x( A% K# E) v

  64. 2 f3 @* l+ B& P+ v" D- Y' U/ m
  65. //ADC底层驱动,引脚配置,时钟使能
    3 V0 g7 y9 r3 V1 f- o
  66. //此函数会被HAL_ADC_Init()调用
    1 r8 T( t. c( {  b
  67. //hadc:ADC句柄. T1 k1 _' p3 s; ]
  68. void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
    ' V- L6 l" l$ H2 C% w/ t. _* \
  69. {3 O% h4 t) h- o# O
  70.     GPIO_InitTypeDef GPIO_Initure;2 p% U7 L3 t; D2 O$ f
  71.     __HAL_RCC_ADC1_CLK_ENABLE();            //使能ADC1时钟
    9 W) ?# f7 _3 s3 s
  72.     __HAL_RCC_GPIOA_CLK_ENABLE();           //开启GPIOA时钟
    $ q7 j# z/ C0 u; w/ i

  73. # _9 ?4 y  e5 `# V
  74.     GPIO_Initure.Pin = GPIO_PIN_5|GPIO_PIN_6;          //PA57 w) f3 z. S$ b. [& x& c( |7 b
  75.     GPIO_Initure.Mode = GPIO_MODE_ANALOG;   //模拟
    7 v  n) x: ?! R- D: }5 G% m0 d# i
  76.     GPIO_Initure.Pull = GPIO_NOPULL;        //不带上下拉9 [- s! l7 d- q
  77.     HAL_GPIO_Init(GPIOA, &GPIO_Initure);7 m7 j7 J' c2 R. R. T4 ]2 t, @/ X
  78. }: A7 k& h( v+ Q& F; {2 i$ v* u
  79. 5 D- w: Q) l! L6 C: f
  80. void DMA2_Stream0_IRQHandler(void)
    5 W% a( s1 U5 }6 N+ `
  81. {
    & j0 M3 X7 n/ D! ^! ]
  82.     HAL_DMA_IRQHandler(&ADC1DMA_Handler);* A# h/ d3 i& V6 s' g. y
  83. }
    - ?1 t! F, ?6 J# r) V

  84. 9 ^4 T5 I/ Q: T7 R- Y+ w; ]
  85. void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
    7 C/ |( @( R1 ^4 f7 [, A& T, S
  86. {! [  A( I& X" [) d) m1 \
  87.         printf("DMA transfer complete\r\n");( |9 V) \7 X" G3 k
  88. }
    0 j. i& l( X0 M- a' R) O
  89. void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc)' ^( c2 }; V7 M! a+ O" ~; k
  90. {5 R9 ?0 _  z, {
  91.         printf("DMA Half transfer complete\r\n");' f3 a8 b8 w% ]3 o: _& f
  92. }8 v' m4 F& r: b* J0 F. R

  93. . o, k3 e- K* ?5 \1 A5 B, R. {
  94. void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc)
    ! q  S2 I& e: ~" l
  95. {0 ~4 f* b; g! z' {/ t
  96.         printf("DMA transfer error\r\n");( u6 ?% Q2 w  w
  97. }
复制代码

" V" f" d3 u0 J7 {$ K2 F( o4 k; k
8 T2 N; h! S) v3 J, W1 d+ ~! q2 M
  1. #include "sys.h"
    . x+ Z# j) M2 g, J' T3 W; G. i
  2. #include "delay.h"8 E; s- k9 S& N1 M+ F
  3. #include "usart.h"
    & g7 H# F7 E7 M/ T0 M) P
  4. * D( t: t; r0 ^
  5. #include "adc.h"; q  n* l' Z; z1 p, c, T4 ?
  6. , N4 a, a( |3 i! Z* w, a
  7. extern uint16_t buffer[128];% O& Y6 U- @5 O4 b* {; K% a
  8. 4 \9 k# ^' Z5 u& C) b1 B! ~
  9. void show()
    $ @2 ^" Q& r. u; d* p6 a1 g
  10. {. m2 a  r* g4 n
  11.     int i;
    , a) G3 H- Z+ h' G2 n0 e
  12.     printf("\r\ndata:");9 u  y9 }$ r% T: L* _2 ]& s
  13.     for (i = 0; i < 128; i++)
    / k. B8 u2 w9 ?( @1 d7 d
  14.     {
    . C7 W" R7 N0 P" h9 ^( q5 `% ]* {
  15.         if (i % 16 == 0) printf("\r\n");! f* m0 j* a' ?! |& `2 O/ y, h
  16.         printf("%6d", buffer);$ z7 v" I7 z2 j, W5 K
  17.                         buffer=0;
    : s2 r- B, |2 F5 c; l
  18. 8 ^2 b3 D0 O( F5 H
  19.     }
    7 X# L! A0 N0 E% G* u9 ]5 B, \
  20.     printf("\r\n");
    ' b/ t% d- i! O- I. r; _- P
  21. }
    - P  `5 o- J! T0 j

  22. ! `9 i' s9 J7 C2 L
  23. ! ?8 w* E; {9 h* S
  24. int main(void), o% _# s% V- D) ]9 p; q" }
  25. {" U/ B: ]  d9 q, E7 m
  26.     //Cache_Enable();                 //打开L1-Cache
    . v$ p& L; L$ w% I; s8 b1 D1 j3 c' v: E
  27.     HAL_Init();                     //初始化HAL库1 ?0 g" J/ O( h) k) }6 J
  28.     Stm32_Clock_Init(432, 8, 2, 9); //设置时钟,216Mhz
    6 A$ o. D# `* _! c/ d) k
  29.     delay_init(216);                //延时初始化
    ! e3 O% D9 _* z6 e
  30.     uart_init(115200);              //串口初始化! y2 ?: l( [6 d0 m) {
  31. % [; b2 K. K0 Y& j+ Q8 H
  32.     printf("start\r\n");  F0 d( [! _) ?1 W, [9 _. d/ z
  33.     MY_ADC_Init();                  //初始化ADC1通道5
    9 ^. [) q' t7 L- I' b/ o0 H

  34. , u% B, y" I  Q/ S% |( m0 i) C" R
  35.     while (1)( [* x5 X* h' k2 F9 u/ F/ d# ]
  36.     {! ^: p) L" m7 f- g  T4 K, o$ U
  37.         show();
    % b/ ], x! d" Z
  38.         delay_ms(1000);1 H( F( e4 F: U
  39.     }' U0 W1 ?& f# ]" [
  40. }
复制代码

' |% S/ Z+ }" R! }0 n0 [9 w' z4 W2 q7 l: h9 y& ^0 @1 a3 p" S
收藏 评论0 发布时间:2021-12-15 11:00

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版