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

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

[复制链接]
STMCU小助手 发布时间:2021-12-15 11:00
ADC1DMA_Handler.Init.Mode; W, N0 N, w$ S  m% X  M
DMA的正常模式(DMA_NORMAL):采集到DMA_BufferSize 的个数后,DMA停止。
  O$ ~/ W, M2 n2 R# q% R5 L5 ODMA的循环模式(DMA_CIRCULAR):采集到DMA_BufferSize 的个数后,重新回到设置的RAM的起点位置,如此循环。
/ E: f4 |/ l2 g  |" O+ {  T- i! s虽然道理很好理解,但个人感觉要配合触发信号来用,通过HAL_ADC_Start_DMA软件触发需要设置起点位置和长度,否则这个参数是没有意义的。2 G6 @% O1 v2 X+ Z

5 \! {  ?1 D! p* p% dADC1_Handler.Init.ScanConvMode9 a1 J1 n7 b2 w$ M4 _* S
扫描模式(ENABLE):ADC会依次扫描设置的各个rank9 y( S7 y$ f7 x* i
非扫描模式(DISABLE):ADC只会读取rank1,即使设置的DMA_BufferSize大于2,也只会读取第一个;如果没设置rank1(此时我的设置里rank2接的3V3,rank3接的gnd),读出来的结果是516这种奇怪的东西,我也不知道是个什么鬼东西……
! `* k6 `, t" ]: L即使需要只读取rank1的值,把NbrOfConversion不就可以了嘛~, v7 B6 _4 F4 d( M- q: E! n
所以这个参数我建议设置成ENABLE,我也不知道什么时候该用DISABLE。
! E. _" u) d1 R; a2 x9 b0 Q+ W# Y: \* z( Y7 P+ V- Y  S0 u
ADC1_Handler.Init.ContinuousConvMode: r( b$ X2 _3 p) e, m" P+ \! ~
开启连续转换:开启了连续转换后,adc会一直转换,直到DMA_BufferSize大小,如图是HAL_ADC_Start_DMA 64个长度的结果。
' r% g3 E7 n3 T$ ?+ Q
' N: x( g% A' u: C8 S$ k0 _
20200419192759329.png
3 B4 G1 q; @* o1 z$ K  A
而不开启连续转换,长度为64的同时,DMA的传输中断都不会进。
. A1 |; O' c# e& p7 n
20200419192936345.png
$ O- W& ^) i# r3 B' f: Q. E

3 s, o- s3 d) ~! u( [而将传输长度设置为3的时候,就进入了传输完成过半的中断。
; m8 R0 A9 ^3 n' a# }3 u
7 }* Y4 u0 ^9 t. [+ }2 F
20200419194129548.png

2 y- B8 G( r: H' I8 K: e  O
  u7 F& T+ T8 y% c0 J% d3 V- f如果我们需要采集连续的N个次结果求平均值,用这个连续转换会很方便。0 E& w! f5 L( x3 G! _
也从侧面说明,dma的传输中断是一定要有那么长的真实采集数据来才能进的。: [: t5 E: U/ j

( |2 t7 A& O7 K8 @( v在另外一篇里看到了这么一个表格,希望能够辅助大家理解:
; ^* \; E& a* [' a
# c9 y) D" s2 b# q  c* Y- A
20200421214739891.png
* l' @% _! f1 l) Q: X1 N+ e$ e
8 N/ @7 W' T* _% ]9 a5 f! c6 p
ADC1_Handler.Init.DMAContinuousRequests  J" q& e1 X8 h: b
当设置了定时器触发DMA之后,这个参数如果设置为DISABLE,就只会采集一轮数据,然后结束。
1 @) X# K5 }4 \- p- r( H1 E) s这个数据设置成了ENABLE之后,这个参数设置为ENABLE,一轮采集完成之后,感觉就会自动调用一次HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)buffer, 100);,触发DMA请求,以实现不停采集。
0 e8 h& u1 q4 y" B# |# Z! _9 v) j( f
但是需要注意,如果开启了连续转换,又开启了DMA连续请求,adc将一直进行采集,一刻也不停歇……9 _/ ^$ _: \+ I4 v
1 i5 q- c& j! a, V" s+ v
ADC1_Handler.Init.EOCSelection
2 n& b3 G2 r* V; U; ^EOC听说是转换结束标志,这里暂时也没用到,也先埋一个坑……- ]; R3 \8 I) Q2 {5 t& {
填坑STM32F7实现ADC等周期采集(定时器触发+DMA传输)采集完成后的中断设置( _9 n" o/ w+ E6 P% m% J1 i: @

6 }: R: y5 S( s! `9 D# I' R" |偶然看到一个帖子的回复:
! i2 {: m! c' v; \0 t当有CPU和其它主设备【如DMA】共同访问某可缓存的二级存储器比方SRAM1,同时该存储器又具有回写属性,此时就可能发生数据一致性问题。因为该存储器的回写属性,导致通过CPU欲写入存储器的数据只是缓冲在CACHE里,而没有及时写入存储器。如果此时DMA访问该二级存储器的话,读到的数据可能跟预期不一致。
, e+ Y4 Q6 {8 n; x) Z0 Q  |. N为了避免数据不一致的问题,我们需要做D-CACHE维护操作。一般有如下四种方法: 1、当对一个可缓存的二级存储器做了写数据操作之后,通过软件对D-CACHE进行清除操作,即运行SCB_CleanDCache()。这样将CACHE里的缓存内容写回到二级存储器,比如把那些DIRTY
/ H2 ?" x* `; l6 z# HCACHE行的数据写进SRAM1。  W3 Q4 O- ]) Q8 |; G' |% Z. D
2、通过MPU调整可缓存存储器的存储属性,将其CACHE使用方式改为透写模式。这样保证每次写入CACHE里的内容也同时写入二级存储器,比如写进SRAM1。: |. ]: L4 p4 U
3、通过MPU调整可缓存存储器的存储属性,将其共享属性改为可共享的【SHAREABLE】。此后该二级存储器将变为不可缓存。
5 E+ X/ B3 l8 ?( ]4、通过配置CACR寄存器中的D-CACHE位,强制将所有写操作配置为透写属性。
3 ~4 s6 e. ^$ G0 `  o
" Q( G; n3 j$ e7 b+ ~$ ~! G在main函数中关闭cache,DMA采集的数据就可以更新了。. i# f1 ?6 o: {5 r2 \- X

5 c2 }! Z% h/ K* _. J# |' z5 e
20200419215859139.png

2 y( y2 U- G, L
5 L/ q( E# L0 C& c9 ]$ k附上成功时候的配置,注释掉HAL_NVIC_EnableIRQ是因为中断服务函数里的打印会导致main函数无法继续执行。: B5 q- C! h+ K
2 ?* q/ \  `, G( M$ y/ W: O6 i
  1. #include "adc.h"* N) f; ?4 r, s# ~2 r. X
  2. #include "delay.h"  K/ ^8 ?( y- Y

  3. # H' Z) C5 y' C/ ^% g8 p! _% y
  4. ADC_HandleTypeDef ADC1_Handler;//ADC句柄
    , ?' I) m! G9 M% l
  5. DMA_HandleTypeDef ADC1DMA_Handler;( p4 U, d7 d9 T; w1 B! Q# ]" f
  6. ADC_ChannelConfTypeDef ADC1_ChanConf;
    . P# \: f) [8 M

  7. , g. s; J8 B" Y0 ~9 A  T
  8. uint16_t buffer[128];7 {+ g8 U+ i. q6 G9 ~
  9. ; p6 a  C: V; @8 E, E6 O7 ^- H

  10. $ R" A' t( W6 T
  11. //初始化ADC
    5 z: U' E% T! z6 s* C) D  }
  12. //ch: ADC_channels9 d# G6 y4 p' {! p2 C
  13. //通道值 0~16取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_166 |; D1 }/ S" q  W! Y( N6 ~0 p; A3 y4 H
  14. void MY_ADC_Init(void)
    : y' L7 ]6 Y7 t3 N
  15. {
    1 [6 G2 @* I/ g
  16.     __HAL_RCC_DMA2_CLK_ENABLE();; n% x, _- h- ~+ f  R0 o9 x
  17.     HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);4 E+ |; R1 ]7 E' a: T% H; ]
  18.     //HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);6 D1 ?+ u. ]; V1 c
  19. # e4 W- z, J2 n6 \% I. ]
  20.     ADC1DMA_Handler.Instance = DMA2_Stream0;. A) e" B, ~" n* i$ m
  21.     ADC1DMA_Handler.Init.Channel = DMA_CHANNEL_0;
    0 q% o' A2 J& w$ \2 z; K
  22.     ADC1DMA_Handler.Init.Direction = DMA_PERIPH_TO_MEMORY;
      ?+ ?7 E( F; ?6 i9 E
  23.     ADC1DMA_Handler.Init.PeriphInc = DMA_PINC_DISABLE;               //外设非增量模式
    4 a! U: u8 t+ I# Z" x
  24.     ADC1DMA_Handler.Init.MemInc = DMA_MINC_ENABLE;                   //存储器增量模式
    ) W! _) w7 v4 F1 y
  25.     ADC1DMA_Handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;  //外设数据长度:16位1 j  X/ X# i) v; Y
  26.     ADC1DMA_Handler.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;     //存储器数据长度:16位) W- j7 o: `) U5 ?" f6 e1 {9 ]
  27.     ADC1DMA_Handler.Init.Mode = DMA_CIRCULAR;                          //传输一次就结束
    9 a9 ~7 K$ M) U+ M: V
  28.     ADC1DMA_Handler.Init.Priority = DMA_PRIORITY_LOW;             //中等优先级$ o) Q4 Y. p3 y  _9 O) ~2 X
  29.     ADC1DMA_Handler.Init.FIFOMode = DMA_FIFOMODE_DISABLE;            /* 禁止FIFO*/" E( z) Z- A& j& z3 f. [/ t, u( L/ R
  30. 3 D& K0 k* _; A9 x8 a
  31.     HAL_DMA_Init(&ADC1DMA_Handler);
    " m5 C# ?1 q) b) J3 J

  32. & O, V  p7 z7 b! W5 K( r
  33.     __HAL_LINKDMA(&ADC1_Handler, DMA_Handle, ADC1DMA_Handler);                //将DMA与ADC联系起来- W' y2 R' p; i# p0 ]6 E
  34. 7 \/ C* L# X- s3 \" y8 U

  35. . h0 U0 L$ N2 y4 c5 V3 p( Y$ f
  36.     ADC1_Handler.Instance = ADC1;
    4 j- h5 u8 F, }$ ~( n9 y
  37.     ADC1_Handler.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; //4分频,ADCCLK=PCLK2/4=108/4=27MHZ
    - {, S* y0 {# ]) S" g/ m. y
  38.     ADC1_Handler.Init.Resolution = ADC_RESOLUTION_12B;           //12位模式
    ' `9 w& k6 K( y0 \
  39.     ADC1_Handler.Init.ScanConvMode = ENABLE;                    //非扫描模式  ]% q0 _6 m$ ?7 _$ [
  40.     ADC1_Handler.Init.ContinuousConvMode = ENABLE;              //关闭连续转换$ S- F# E% i5 w: |  Q! A& b
  41.     ADC1_Handler.Init.DiscontinuousConvMode = DISABLE;           //禁止不连续采样模式
    ' _5 p+ }3 O5 o& P' R) @; I
  42.     ADC1_Handler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //使用软件触发9 U3 Y/ z/ w3 @2 x
  43.     ADC1_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START;     //软件触发
    - T$ @. D8 V' I7 h" [. c2 y
  44.     ADC1_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT;           //右对齐
    6 D2 t3 d$ o# P* o, x, M) Q) Q) Z
  45.     ADC1_Handler.Init.NbrOfConversion = 2;                       //1个转换在规则序列中 也就是只转换规则序列1
    1 d- S* b6 l* {# D2 p2 d
  46.     ADC1_Handler.Init.DMAContinuousRequests = ENABLE;           //关闭DMA请求; h- v+ s2 O. o! E, V
  47.     ADC1_Handler.Init.EOCSelection = ADC_EOC_SINGLE_CONV;        , ^. C: \, Y8 ?0 e( B3 m
  48.     HAL_ADC_Init(&ADC1_Handler);- y' V  @& X  L( l  s( T3 e8 J! x
  49. * k* E1 [& g* C4 {
  50.     ADC1_ChanConf.Channel = ADC_CHANNEL_5;                                 //通道
    4 H% q1 a7 p+ B' s5 t4 s- i0 a
  51.     ADC1_ChanConf.Rank = 1;                                     //序列1
    % Q; M0 A& e5 F0 Y: y! z+ J
  52.     ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES;      //采样时间/ R' _2 j" A! `" P! H$ |
  53.     ADC1_ChanConf.Offset = 0;- S$ x. M  n7 C7 L+ u1 g. t
  54.     HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf);       //通道配置1 n- _4 C7 f  m7 \* U
  55. ' X" k; l: Y8 G) u0 ^2 V
  56.     ADC1_ChanConf.Channel = ADC_CHANNEL_6;                                 //通道+ ^8 R& H0 F  o( U: ^7 _
  57.     ADC1_ChanConf.Rank = 2;                                     //序列2
    1 A, {. j1 D: A" D% B8 [& e
  58.     ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES;      //采样时间8 u" J3 I* K1 Q
  59.     ADC1_ChanConf.Offset = 0;+ Z* f4 _  M3 O8 B; |
  60.     HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf);       //通道配置3 ]7 Q" y" m- u2 Z' C+ I8 D1 w

  61. ) R7 g9 z3 ?/ I' L& U% E
  62.                 HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)buffer, 100);; j. O. I+ Z0 N7 @, u+ m3 Q) ^1 N& L
  63. }
    9 I9 H. ~5 _6 d0 F4 D

  64. 3 c' F' _4 U; i* n* j0 G$ f
  65. //ADC底层驱动,引脚配置,时钟使能
    " `0 ]5 _7 y6 B6 S5 `& x% Q. Y
  66. //此函数会被HAL_ADC_Init()调用: g' S7 y, r& V6 S7 e
  67. //hadc:ADC句柄
    6 z8 u% X* u$ W' k! n
  68. void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
    5 \8 D/ a, R/ @
  69. {
    ; T6 Y( V1 [" o# t
  70.     GPIO_InitTypeDef GPIO_Initure;) h1 f; |& r9 |7 o
  71.     __HAL_RCC_ADC1_CLK_ENABLE();            //使能ADC1时钟7 k: }- F% P: V: U5 D
  72.     __HAL_RCC_GPIOA_CLK_ENABLE();           //开启GPIOA时钟: }5 X$ L) c/ Y$ A) {
  73. $ S" d, j% g" `3 l
  74.     GPIO_Initure.Pin = GPIO_PIN_5|GPIO_PIN_6;          //PA52 @8 ~  ~2 R! [0 v0 X
  75.     GPIO_Initure.Mode = GPIO_MODE_ANALOG;   //模拟
    . ]$ e4 }% @+ o2 i" [* c6 q( F" O
  76.     GPIO_Initure.Pull = GPIO_NOPULL;        //不带上下拉% D9 N" ?" E8 f: q4 ^# ~/ Z- K9 J
  77.     HAL_GPIO_Init(GPIOA, &GPIO_Initure);( Y% L8 h" {& y  X/ _4 s; j/ X
  78. }# W* a: f7 G4 m8 ?" l1 O
  79. ' s, S# ~; p3 x7 L( ~0 H
  80. void DMA2_Stream0_IRQHandler(void)/ d0 ~: T+ ?2 f7 P! I
  81. {
    8 ]5 Y4 V  i7 s  Q0 G
  82.     HAL_DMA_IRQHandler(&ADC1DMA_Handler);1 i, f5 y' E5 Q7 G  N( E( X
  83. }
    & G+ A( {8 i1 Z$ f- k' M

  84. ! a& \/ u5 ~/ i# m3 s% N) F8 b
  85. void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
    . P8 J  i( ~/ {9 M
  86. {
    : s' A7 [5 E; R" e! ^
  87.         printf("DMA transfer complete\r\n");
    ; y, A. z7 ]8 g# w3 h8 N6 ~+ k
  88. }6 h) e- ?# l, ?7 ~+ |
  89. void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc)& w2 w  {2 M" Q' S
  90. {
    5 j2 j* P3 m/ ?7 g$ p
  91.         printf("DMA Half transfer complete\r\n");! r! D! \/ g9 c& `, _9 B  P$ [. C
  92. }
    , t& Y' g; _/ k+ m6 L  I3 C% ?4 l
  93. ' S# \  X5 Y* M+ J6 `5 h
  94. void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc)3 x$ i" Y, F( ^) [% d+ |8 l) ~' E
  95. {) f( z! h5 m1 \
  96.         printf("DMA transfer error\r\n");
    ; Q$ e) d' |: e7 J/ [0 [
  97. }
复制代码
0 v- `" g3 x6 h3 @

7 \5 [- g7 L5 X, w* T6 ]) I6 Q
  1. #include "sys.h"- s3 o; B0 r* B% {- |
  2. #include "delay.h". R! G. L9 M( {1 q
  3. #include "usart.h"9 C; Y( U: `1 ]9 w' @* I
  4. ! T' i! n2 S' \: P% E3 P
  5. #include "adc.h"1 E1 Y) w( n. P0 s" \& B% q
  6. . i( k# ?: ~6 ^/ r* x& ]
  7. extern uint16_t buffer[128];
    1 o7 T' p. @2 o
  8. * t- K+ f% }1 U/ x' ~
  9. void show()
    " R& {0 \- k3 v1 l6 N
  10. {0 y) Z+ H, A+ o2 ]+ X# B
  11.     int i;
    6 I; y1 i7 i: ^" a) a0 Y
  12.     printf("\r\ndata:");0 s* X* B4 T4 ~& o! m
  13.     for (i = 0; i < 128; i++)/ {7 b) n$ P4 j& p8 j, J
  14.     {# o+ T# p( b- r) s% S: d
  15.         if (i % 16 == 0) printf("\r\n");( h7 E$ P, ?2 d+ Z& M
  16.         printf("%6d", buffer);
      a1 R: n! H/ K* x+ F! h+ u" b
  17.                         buffer=0;4 h* \# H# x* V% |

  18. 9 Z" Z3 b* Y5 D+ u
  19.     }. y4 E% w) {2 E5 Z9 F
  20.     printf("\r\n");# U4 Q) n# n, p# d5 f( T9 |
  21. }" \( q/ `6 @: G$ T% d8 f
  22. % H" A, H6 n+ V1 x7 Z" E
  23. ) O* _) o/ e# s# z
  24. int main(void); z+ l0 C" t$ T: {" D8 C5 L
  25. {
    $ W! @8 |% p; M. I. D: ~' w( B
  26.     //Cache_Enable();                 //打开L1-Cache
    / u0 ~8 P4 `3 Y$ Y. K4 y& q* M) {
  27.     HAL_Init();                     //初始化HAL库  U; W; c6 o4 v5 r2 z' ~
  28.     Stm32_Clock_Init(432, 8, 2, 9); //设置时钟,216Mhz# X2 E; V( p6 [; k5 S. D/ p1 R
  29.     delay_init(216);                //延时初始化1 M( H- J) G5 E4 ?; o
  30.     uart_init(115200);              //串口初始化
    # w0 Z5 @) f4 D3 z
  31. % R- u- f) Z9 |7 C: w
  32.     printf("start\r\n");
    ) ~" _# `" N; m2 c$ w& K
  33.     MY_ADC_Init();                  //初始化ADC1通道54 T! G6 ]3 m! j! J& m, L

  34. $ n. Q. Z+ b/ G9 e3 u1 n8 \
  35.     while (1)7 z5 o: k9 _. }; b; m
  36.     {0 p: _6 |- P* [
  37.         show();
    8 s$ s5 [9 F: s: H
  38.         delay_ms(1000);
    , R& ?7 W9 F6 }+ C  u
  39.     }
    & K7 q5 |6 T- w, p
  40. }
复制代码

+ i# ~; i+ O( ^  h% U: q3 A1 n5 K; ^' N5 F# h8 r
收藏 评论0 发布时间:2021-12-15 11:00

举报

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