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

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

[复制链接]
STMCU小助手 发布时间:2021-12-15 11:00
ADC1DMA_Handler.Init.Mode/ M: c! X% V4 U, O0 g# l
DMA的正常模式(DMA_NORMAL):采集到DMA_BufferSize 的个数后,DMA停止。$ G; F( f9 \( v7 J1 _& \$ C( j
DMA的循环模式(DMA_CIRCULAR):采集到DMA_BufferSize 的个数后,重新回到设置的RAM的起点位置,如此循环。
+ s7 d- H& T2 q- k: t5 b虽然道理很好理解,但个人感觉要配合触发信号来用,通过HAL_ADC_Start_DMA软件触发需要设置起点位置和长度,否则这个参数是没有意义的。* l1 o" B) r* C* U
3 L8 k. {4 j: O2 \7 \- w  ^6 c
ADC1_Handler.Init.ScanConvMode8 M/ K! k& L; |6 T
扫描模式(ENABLE):ADC会依次扫描设置的各个rank' H3 Q4 n8 |/ S: J) [2 N' W
非扫描模式(DISABLE):ADC只会读取rank1,即使设置的DMA_BufferSize大于2,也只会读取第一个;如果没设置rank1(此时我的设置里rank2接的3V3,rank3接的gnd),读出来的结果是516这种奇怪的东西,我也不知道是个什么鬼东西……3 \& \# x3 z: {" b6 x5 [2 h
即使需要只读取rank1的值,把NbrOfConversion不就可以了嘛~
" X' Z$ y7 B7 k2 s所以这个参数我建议设置成ENABLE,我也不知道什么时候该用DISABLE。( {( f3 c5 B' L( d

4 k1 W# L0 x8 a: o! T7 _ADC1_Handler.Init.ContinuousConvMode
/ W: j0 h" B# X2 S' n) c开启连续转换:开启了连续转换后,adc会一直转换,直到DMA_BufferSize大小,如图是HAL_ADC_Start_DMA 64个长度的结果。- |; f* y# P' f; m; \9 h8 a3 d. C

, R, Q9 x) f& b* m& @& M
20200419192759329.png
5 z0 P, l" H0 ^, c% y; ?
而不开启连续转换,长度为64的同时,DMA的传输中断都不会进。
& Q6 y# ?0 h9 x8 V8 e7 ]9 D
20200419192936345.png

: f& m( z1 \. T, E0 Y) A. |1 W2 A- }: T# w7 M7 f3 ]
而将传输长度设置为3的时候,就进入了传输完成过半的中断。
' F7 o; }$ p  x0 }
5 F& A4 k1 y, R, |- H9 i& E. j& h
20200419194129548.png

! e; Y  b* c4 T9 Y
0 S; D) c: C2 s: V$ ?/ ^如果我们需要采集连续的N个次结果求平均值,用这个连续转换会很方便。0 K  n! s  [/ W& o6 i
也从侧面说明,dma的传输中断是一定要有那么长的真实采集数据来才能进的。
- A3 h$ ]- `. Z" m( W; [$ V
' }6 f, f8 H% M7 T- R9 N: G在另外一篇里看到了这么一个表格,希望能够辅助大家理解:" ]+ Q6 A4 `' N) }2 [

: S; q; Y6 ^' Q2 b1 k* G! V
20200421214739891.png

: B. Y4 ~' f; U
6 R. A  L  Z3 |; N: L8 a  fADC1_Handler.Init.DMAContinuousRequests3 W- s3 L2 k0 S6 V! \: V7 d' {) ~
当设置了定时器触发DMA之后,这个参数如果设置为DISABLE,就只会采集一轮数据,然后结束。
9 E: w( m: ]( \2 _: B  B这个数据设置成了ENABLE之后,这个参数设置为ENABLE,一轮采集完成之后,感觉就会自动调用一次HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)buffer, 100);,触发DMA请求,以实现不停采集。1 t- Q' T% H' t% g" x

# V  B4 X9 c3 X0 W3 q; u6 m但是需要注意,如果开启了连续转换,又开启了DMA连续请求,adc将一直进行采集,一刻也不停歇……
/ F1 L- v. Q; ~
2 U8 |  b& A1 |ADC1_Handler.Init.EOCSelection  C& ]" O' {- f. Q& b1 Q
EOC听说是转换结束标志,这里暂时也没用到,也先埋一个坑……
: P( W& t& }$ _) Y8 N" s填坑STM32F7实现ADC等周期采集(定时器触发+DMA传输)采集完成后的中断设置
+ S  x! B' H5 z/ {* Y  M# g; i+ b% g; @2 |" t
偶然看到一个帖子的回复:! F0 V" r% L  C# D: G8 Y  m; y
当有CPU和其它主设备【如DMA】共同访问某可缓存的二级存储器比方SRAM1,同时该存储器又具有回写属性,此时就可能发生数据一致性问题。因为该存储器的回写属性,导致通过CPU欲写入存储器的数据只是缓冲在CACHE里,而没有及时写入存储器。如果此时DMA访问该二级存储器的话,读到的数据可能跟预期不一致。; e; _; }1 c) {) ]+ r
为了避免数据不一致的问题,我们需要做D-CACHE维护操作。一般有如下四种方法: 1、当对一个可缓存的二级存储器做了写数据操作之后,通过软件对D-CACHE进行清除操作,即运行SCB_CleanDCache()。这样将CACHE里的缓存内容写回到二级存储器,比如把那些DIRTY
1 ~9 p* m* W, R0 ?$ |CACHE行的数据写进SRAM1。1 r0 Q9 N' v# C: l9 @
2、通过MPU调整可缓存存储器的存储属性,将其CACHE使用方式改为透写模式。这样保证每次写入CACHE里的内容也同时写入二级存储器,比如写进SRAM1。  u' s+ p3 ~* I" I' |9 r8 h
3、通过MPU调整可缓存存储器的存储属性,将其共享属性改为可共享的【SHAREABLE】。此后该二级存储器将变为不可缓存。
* O* w5 S, k9 \3 S% W# R4、通过配置CACR寄存器中的D-CACHE位,强制将所有写操作配置为透写属性。( K9 f# H7 O7 W9 Q( M- ^& O3 O0 N3 Z0 E
- M$ L# e# G  P4 B( }2 n# |
在main函数中关闭cache,DMA采集的数据就可以更新了。
6 E3 k( ?  L0 u- \' t+ P3 w( s5 A+ y. i' \! o' L0 R
20200419215859139.png

  I( p, B. ?1 a
% p5 ?6 F; ^- G1 Q附上成功时候的配置,注释掉HAL_NVIC_EnableIRQ是因为中断服务函数里的打印会导致main函数无法继续执行。+ o9 n4 O- h3 r# D/ h

( m$ U8 w1 h# ?
  1. #include "adc.h"! k: @* x! p  Q$ \( Q
  2. #include "delay.h"
    # ~7 z; H2 ~4 k6 `% E* y

  3. % J! O; ^0 B: i6 u# t0 Z4 ~, s* O
  4. ADC_HandleTypeDef ADC1_Handler;//ADC句柄8 p2 M2 ~6 j2 P* h( K' p' Q
  5. DMA_HandleTypeDef ADC1DMA_Handler;
    2 o3 \9 \* {' S* s2 }) @
  6. ADC_ChannelConfTypeDef ADC1_ChanConf;' o* g! @' r2 s- N4 F. U2 s' X. ?

  7. / t! b9 X: b( w
  8. uint16_t buffer[128];9 d0 s5 z2 C7 T0 q5 x

  9. : N/ }3 e; A* J7 g/ _9 Q% g
  10. ' l( M! r6 ?; R7 }8 a
  11. //初始化ADC
    " {7 i5 s# @. [( G# c
  12. //ch: ADC_channels
    7 {5 T' T1 l* I  W  ?7 p
  13. //通道值 0~16取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16
    5 J' m7 D: \2 y; k% @5 x7 X
  14. void MY_ADC_Init(void)
    , Z8 V  |1 U# d
  15. {, H( _) m8 T, K5 F( Q# n# f0 _
  16.     __HAL_RCC_DMA2_CLK_ENABLE();
    1 E& w" R' ]: \7 L! i: S5 o" x
  17.     HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
    3 h( O) F* |* Y3 n4 R( R: O. g
  18.     //HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);2 x, L8 B( K4 o8 |
  19. 6 E( U' g1 _  k0 G2 o& a+ m  P
  20.     ADC1DMA_Handler.Instance = DMA2_Stream0;, i* I8 U6 X& ?. t8 M. N+ f
  21.     ADC1DMA_Handler.Init.Channel = DMA_CHANNEL_0;
    ( N! _9 a3 n+ K
  22.     ADC1DMA_Handler.Init.Direction = DMA_PERIPH_TO_MEMORY;' q/ H8 w( K7 o7 k, ?3 W
  23.     ADC1DMA_Handler.Init.PeriphInc = DMA_PINC_DISABLE;               //外设非增量模式: o: h1 {' L; t3 Z5 x# K, \
  24.     ADC1DMA_Handler.Init.MemInc = DMA_MINC_ENABLE;                   //存储器增量模式
    % H% p$ u' }* U4 {; j
  25.     ADC1DMA_Handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;  //外设数据长度:16位' s9 N/ R& l# b
  26.     ADC1DMA_Handler.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;     //存储器数据长度:16位
    ! @* B3 s4 P/ @9 c5 p
  27.     ADC1DMA_Handler.Init.Mode = DMA_CIRCULAR;                          //传输一次就结束" ^) y$ N- b2 G) k. t3 z. ~, v6 |
  28.     ADC1DMA_Handler.Init.Priority = DMA_PRIORITY_LOW;             //中等优先级8 \! ?( Q- e8 [& b4 s
  29.     ADC1DMA_Handler.Init.FIFOMode = DMA_FIFOMODE_DISABLE;            /* 禁止FIFO*/
    5 X# {9 T, J2 b% M
  30. + k) _/ A# R- w# X+ k- G, T" M* `
  31.     HAL_DMA_Init(&ADC1DMA_Handler);
    ; E* G' ?- @" u

  32. 8 f/ L+ ?, a7 t
  33.     __HAL_LINKDMA(&ADC1_Handler, DMA_Handle, ADC1DMA_Handler);                //将DMA与ADC联系起来- f* Y+ w, U- ~4 P+ \

  34. 8 G! k) K& i3 ^8 P5 |! ?

  35.   U5 r' i  Q* Z% K1 U$ c4 Z  z
  36.     ADC1_Handler.Instance = ADC1;3 `5 Y8 W4 G( e$ ]9 O$ N
  37.     ADC1_Handler.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; //4分频,ADCCLK=PCLK2/4=108/4=27MHZ$ f7 @3 `) u& t; _
  38.     ADC1_Handler.Init.Resolution = ADC_RESOLUTION_12B;           //12位模式
    + l: k+ p- t0 h" I
  39.     ADC1_Handler.Init.ScanConvMode = ENABLE;                    //非扫描模式, J9 ]& S) T. l, R2 g8 {
  40.     ADC1_Handler.Init.ContinuousConvMode = ENABLE;              //关闭连续转换
    6 ?% O2 a; a* Y, |  \7 j) v% K' p
  41.     ADC1_Handler.Init.DiscontinuousConvMode = DISABLE;           //禁止不连续采样模式
    / q& L' \/ R$ n
  42.     ADC1_Handler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //使用软件触发6 \" H- e0 U' D: V  y; d
  43.     ADC1_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START;     //软件触发, B! m4 M* L2 z* H
  44.     ADC1_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT;           //右对齐% [' \' B* g. O' Z
  45.     ADC1_Handler.Init.NbrOfConversion = 2;                       //1个转换在规则序列中 也就是只转换规则序列10 i9 E, b- G1 a3 q5 h. i, k' ?
  46.     ADC1_Handler.Init.DMAContinuousRequests = ENABLE;           //关闭DMA请求
    4 e8 f* N" \+ K
  47.     ADC1_Handler.Init.EOCSelection = ADC_EOC_SINGLE_CONV;        
    / g2 s$ s' a- P# }$ A0 o9 W2 u
  48.     HAL_ADC_Init(&ADC1_Handler);
    6 X4 Y- U) W$ i2 i- A9 @
  49. / u& [* k. z% w' _2 C
  50.     ADC1_ChanConf.Channel = ADC_CHANNEL_5;                                 //通道6 O8 [% m2 e: h4 q( A
  51.     ADC1_ChanConf.Rank = 1;                                     //序列1* L$ }8 d# R: h
  52.     ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES;      //采样时间
    4 D  v& u3 {$ G
  53.     ADC1_ChanConf.Offset = 0;8 x- K) Q; @2 z3 i0 J) ?' @% O
  54.     HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf);       //通道配置
    6 S! i: Y5 z! A( U

  55. , @" m5 n" P6 D% R/ T6 G1 m
  56.     ADC1_ChanConf.Channel = ADC_CHANNEL_6;                                 //通道
    3 a0 U1 L0 ?) f6 @: @2 c
  57.     ADC1_ChanConf.Rank = 2;                                     //序列2
    ; G( G" i$ P( a5 l' F
  58.     ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES;      //采样时间/ _- \8 @/ w9 X
  59.     ADC1_ChanConf.Offset = 0;
    5 m2 U3 J) {. W- Q) \% g' v$ b' {7 B
  60.     HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf);       //通道配置
    , P* f9 n( U* F, ^- H' X' ~
  61. , P( z  k/ H5 M+ b# H# O
  62.                 HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)buffer, 100);' r" e3 C; i1 [, e4 {3 p* }' S# B
  63. }+ c: C$ J0 Q% }; b6 O/ b
  64. % T- S2 e0 H( `; i
  65. //ADC底层驱动,引脚配置,时钟使能
    , d" g5 o; V+ Z, a
  66. //此函数会被HAL_ADC_Init()调用* T4 {6 |2 D% I9 [9 g
  67. //hadc:ADC句柄
    ! N. T7 Z. `7 G% e1 V
  68. void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)- s3 n7 T, a& L+ v* L+ R
  69. {
    " L, ^- C* ]/ [- d" m6 e# F
  70.     GPIO_InitTypeDef GPIO_Initure;
    + F: h7 z1 o8 f
  71.     __HAL_RCC_ADC1_CLK_ENABLE();            //使能ADC1时钟
    - y* J+ s% n7 t
  72.     __HAL_RCC_GPIOA_CLK_ENABLE();           //开启GPIOA时钟6 t# E- J' S. b
  73. 9 F& W6 E0 f& k- [, k# N( Y  ^
  74.     GPIO_Initure.Pin = GPIO_PIN_5|GPIO_PIN_6;          //PA5! \% Z& M) x( X; x6 A
  75.     GPIO_Initure.Mode = GPIO_MODE_ANALOG;   //模拟* d) l& ]8 Z3 H) X  J5 W* v
  76.     GPIO_Initure.Pull = GPIO_NOPULL;        //不带上下拉$ o; o0 B$ y. p2 J
  77.     HAL_GPIO_Init(GPIOA, &GPIO_Initure);" d$ o5 l+ \' A" [/ V+ `
  78. }4 y1 @' A0 t, f4 k

  79. ) T" @4 X" [; _: i4 I; b( ^
  80. void DMA2_Stream0_IRQHandler(void)
    " r7 _( F6 B& l3 C0 A9 f; r; T
  81. {' k% i% y2 I  q" Y0 y4 L
  82.     HAL_DMA_IRQHandler(&ADC1DMA_Handler);
    " F0 u4 ?% {; A( b  a8 y# u/ `
  83. }6 e, ?  g  l2 Z8 \7 A

  84. 3 ]- n: k5 p! P$ |- ]4 O
  85. void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
    . ^  E8 a, t+ H% m- u$ R
  86. {
    : ?& f4 l) m2 Q0 t5 W
  87.         printf("DMA transfer complete\r\n");
    ) B5 z8 n+ T& t( D3 X4 K, l: p6 a6 |
  88. }
    , v; V, ]1 I1 A' e5 p
  89. void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc)6 r0 {4 W0 I: ^) n, v# g
  90. {  W6 r6 _; [8 F2 _. @+ g
  91.         printf("DMA Half transfer complete\r\n");
    ! s0 v$ q; @' f0 b
  92. }( O8 K9 o8 ~; M8 h
  93. ' Y# g1 F- N& y
  94. void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc)
    6 X6 v) h0 B( J: ^9 {, s
  95. {% G# [5 Z3 `+ |, D' }2 C; V' e8 P; v
  96.         printf("DMA transfer error\r\n");
    ; z- u0 h; ^% h( K6 ^+ E. }6 z
  97. }
复制代码
- K5 O8 \- _  Q4 j% I) @
& P7 j% E" J+ j) U# Y
  1. #include "sys.h"7 {0 m8 R' U% `8 s. d" w1 h
  2. #include "delay.h"" p# r, q% H3 M  p' j
  3. #include "usart.h". D  d. o* b7 i; s. p

  4. ) p2 P' N0 y% [' o) k
  5. #include "adc.h"
    2 o& {" d0 T/ J. r

  6. 2 X( ]* `% z8 t; Q+ N, b" T
  7. extern uint16_t buffer[128];/ W8 Z% }) t+ {2 s& l( B

  8. $ Z5 |& l' i; s/ [6 ?! k
  9. void show()
    , Q2 g3 t5 u: p: O
  10. {
    # y( ^- O/ J1 u/ f$ ?- }
  11.     int i;0 A8 C3 \, V& S9 G4 g8 m
  12.     printf("\r\ndata:");
    ! o; |; e0 T: {  W! p
  13.     for (i = 0; i < 128; i++)# D4 f/ h5 `5 l0 [
  14.     {# W- W. b7 q9 q( o
  15.         if (i % 16 == 0) printf("\r\n");
    3 N# e) I# y. d) ~" z8 ]
  16.         printf("%6d", buffer);4 M0 V5 Q6 F3 M" c) x6 U6 {& }
  17.                         buffer=0;, Y* |- D3 @% l8 I

  18. ' @' O, V' K4 k4 K" J7 E
  19.     }6 ^2 t' k1 ]" A
  20.     printf("\r\n");- F0 h1 a. W; K! \8 B
  21. }, C' U8 I2 e. R
  22. ) T$ N- I! f" y1 H* e; |! ]
  23. : K9 r/ I7 e- @9 D
  24. int main(void)
    5 d4 R+ Z" s5 ?0 |3 j
  25. {9 a% `1 `, G4 z0 O- {
  26.     //Cache_Enable();                 //打开L1-Cache4 l2 j$ D: h& b4 ?+ X1 f9 Y0 U8 @
  27.     HAL_Init();                     //初始化HAL库
    9 W1 w+ c- _+ o5 e( b% S9 ~
  28.     Stm32_Clock_Init(432, 8, 2, 9); //设置时钟,216Mhz
    . s4 {. }; {7 D% T( i
  29.     delay_init(216);                //延时初始化- F3 |. h" F3 @9 ]* Z1 q
  30.     uart_init(115200);              //串口初始化" i& x8 U- C3 l+ Z. s" J

  31. / M% V4 N! n" `+ W" V
  32.     printf("start\r\n");. {- s5 q/ V( G
  33.     MY_ADC_Init();                  //初始化ADC1通道5
    ) p% j" j) o. o5 A
  34. & d! T: _# L4 M3 F& g5 X0 C' J
  35.     while (1)
    * X( H2 T* b% a' V7 D, e
  36.     {: ]" g( e7 L7 v2 N6 \
  37.         show();
    ) W3 [% E" h' m0 Y" [* s% I
  38.         delay_ms(1000);
    ) O: ^) ~9 @; Q6 w6 @# F* ]
  39.     }
    7 u4 }9 |% F5 b8 z
  40. }
复制代码

1 w/ Z9 r' j  m+ x8 V" \4 H2 a
5 N& Y* l3 T& J" o5 l" \  w* v
收藏 评论0 发布时间:2021-12-15 11:00

举报

0个回答

所属标签

相似技术帖

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