请选择 进入手机版 | 继续访问电脑版

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

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

[复制链接]
STMCU小助手 发布时间:2021-12-15 11:00
ADC1DMA_Handler.Init.Mode
9 e: \5 |- T) U4 xDMA的正常模式(DMA_NORMAL):采集到DMA_BufferSize 的个数后,DMA停止。' L7 m4 I/ F  ^5 N7 h; z
DMA的循环模式(DMA_CIRCULAR):采集到DMA_BufferSize 的个数后,重新回到设置的RAM的起点位置,如此循环。9 Z# E" R' i: O# m! d
虽然道理很好理解,但个人感觉要配合触发信号来用,通过HAL_ADC_Start_DMA软件触发需要设置起点位置和长度,否则这个参数是没有意义的。
! J3 Z# y1 S) U1 R5 v. g! u4 c/ C9 N0 w, V- ?+ h
ADC1_Handler.Init.ScanConvMode  ^" I# j* W) b9 x
扫描模式(ENABLE):ADC会依次扫描设置的各个rank
- J& P( \) [7 ^, E4 G非扫描模式(DISABLE):ADC只会读取rank1,即使设置的DMA_BufferSize大于2,也只会读取第一个;如果没设置rank1(此时我的设置里rank2接的3V3,rank3接的gnd),读出来的结果是516这种奇怪的东西,我也不知道是个什么鬼东西……* \! t7 t  Q! f8 N  s! K
即使需要只读取rank1的值,把NbrOfConversion不就可以了嘛~- P$ q, f3 g2 c% Z+ j3 t
所以这个参数我建议设置成ENABLE,我也不知道什么时候该用DISABLE。* U; c7 x, Z9 G, H9 g

! F9 B5 {1 B+ e8 |% J5 w4 LADC1_Handler.Init.ContinuousConvMode
' _6 G  G7 D1 f2 m开启连续转换:开启了连续转换后,adc会一直转换,直到DMA_BufferSize大小,如图是HAL_ADC_Start_DMA 64个长度的结果。
! K" V' [- ?* J" P9 v  x' O' V0 F0 s0 F" c$ f' D6 B  h
20200419192759329.png
) d5 _8 I4 d4 A' [: `
而不开启连续转换,长度为64的同时,DMA的传输中断都不会进。$ o* \1 X, C+ P( r
20200419192936345.png

) |$ U, x5 N9 I! ~0 M+ o9 V3 ], k* a1 |: m+ J/ r6 H) j
而将传输长度设置为3的时候,就进入了传输完成过半的中断。/ e1 \) W/ s& b# h! x

7 Y7 [1 G! u2 l% }1 ?8 h
20200419194129548.png
6 d& {  J7 H+ S1 H$ Q
' L/ a+ J. W! B
如果我们需要采集连续的N个次结果求平均值,用这个连续转换会很方便。
* X' q3 p$ {" }8 I" w也从侧面说明,dma的传输中断是一定要有那么长的真实采集数据来才能进的。' b% Q' d1 w) f; X, n; Z
6 f8 `: b/ A8 [: F8 c
在另外一篇里看到了这么一个表格,希望能够辅助大家理解:
& U% G! y% h" P8 p8 p7 |! b5 q2 c- N6 B
20200421214739891.png
. _# C0 }$ X( n

4 q1 ^. C8 Z. Q5 U2 WADC1_Handler.Init.DMAContinuousRequests& [' y6 _7 s% V: d$ {( Z% [
当设置了定时器触发DMA之后,这个参数如果设置为DISABLE,就只会采集一轮数据,然后结束。
: X' L$ q+ c4 |! {! v- T. e& @- G这个数据设置成了ENABLE之后,这个参数设置为ENABLE,一轮采集完成之后,感觉就会自动调用一次HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)buffer, 100);,触发DMA请求,以实现不停采集。+ E  ?) J- v: _

. @$ q- Q2 F! l/ D- M: H. h2 l但是需要注意,如果开启了连续转换,又开启了DMA连续请求,adc将一直进行采集,一刻也不停歇……
! c) O+ {; v! t7 V/ x: l8 S3 Z- m! T4 S. {9 c
ADC1_Handler.Init.EOCSelection
# I  `1 ]4 d0 ]' T5 _EOC听说是转换结束标志,这里暂时也没用到,也先埋一个坑……
1 {  c9 J: H9 S7 f, _填坑STM32F7实现ADC等周期采集(定时器触发+DMA传输)采集完成后的中断设置
2 w3 P  Q  Z" k1 X
  b6 {  M! D& E- H. X. d偶然看到一个帖子的回复:) ~8 c, v& S4 W& z# F
当有CPU和其它主设备【如DMA】共同访问某可缓存的二级存储器比方SRAM1,同时该存储器又具有回写属性,此时就可能发生数据一致性问题。因为该存储器的回写属性,导致通过CPU欲写入存储器的数据只是缓冲在CACHE里,而没有及时写入存储器。如果此时DMA访问该二级存储器的话,读到的数据可能跟预期不一致。
3 F( D5 L4 d! X" E为了避免数据不一致的问题,我们需要做D-CACHE维护操作。一般有如下四种方法: 1、当对一个可缓存的二级存储器做了写数据操作之后,通过软件对D-CACHE进行清除操作,即运行SCB_CleanDCache()。这样将CACHE里的缓存内容写回到二级存储器,比如把那些DIRTY
4 |+ @4 X. v$ K2 \2 I" NCACHE行的数据写进SRAM1。! O5 y1 S$ `# E; F2 Q! t
2、通过MPU调整可缓存存储器的存储属性,将其CACHE使用方式改为透写模式。这样保证每次写入CACHE里的内容也同时写入二级存储器,比如写进SRAM1。
9 C8 T+ v4 s9 L4 [) W! `# r! f3、通过MPU调整可缓存存储器的存储属性,将其共享属性改为可共享的【SHAREABLE】。此后该二级存储器将变为不可缓存。
2 g( `3 ^; U5 e1 T4、通过配置CACR寄存器中的D-CACHE位,强制将所有写操作配置为透写属性。
; N- Z$ ]6 v& T+ ?5 J% B# n7 J! x% b- D
在main函数中关闭cache,DMA采集的数据就可以更新了。# d; m+ H; [# V' O4 M" I

; O$ ^9 l! Z" I, g3 n3 a
20200419215859139.png
3 w7 S1 ~; _. i0 {) @5 c( Q# k

* r8 W7 q1 R: p+ V附上成功时候的配置,注释掉HAL_NVIC_EnableIRQ是因为中断服务函数里的打印会导致main函数无法继续执行。
- }% |$ q$ a3 |- T/ n' ~' k# E1 h6 C& F6 o, n5 Z% \: N' p: S
  1. #include "adc.h"
    - R: w: j. B7 C
  2. #include "delay.h"0 A1 E$ k* s3 M" W

  3. 3 g6 I; w' H% D! ]  Z
  4. ADC_HandleTypeDef ADC1_Handler;//ADC句柄: a7 k$ `6 [5 O, h
  5. DMA_HandleTypeDef ADC1DMA_Handler;5 S% N" H5 Q! b- i" Q# W
  6. ADC_ChannelConfTypeDef ADC1_ChanConf;
    + L* W+ l* Q2 M7 W/ ?

  7. & f3 j$ S+ Y/ e& O/ ~: M
  8. uint16_t buffer[128];
    , a' x5 |$ ~: z3 t0 H0 Q8 j
  9. $ Q% e: Q$ q; Q4 F) A% U! L
  10. 3 M/ I. @* o1 o$ l4 {3 A' b
  11. //初始化ADC
    / v) j' ~# {+ f
  12. //ch: ADC_channels) Z  H& u5 t8 E$ M6 j/ M* A
  13. //通道值 0~16取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16( i' z, A, Z+ l5 M3 M, f5 T: c/ o# E
  14. void MY_ADC_Init(void)
    - W' L, B% f8 i0 p
  15. {; {* T! R- U3 S' R: {( S$ }- D7 x
  16.     __HAL_RCC_DMA2_CLK_ENABLE();
    # R" k4 W1 U- y: ]- Z/ p
  17.     HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);4 W4 q- Y! p+ M- g% C$ E
  18.     //HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);- V8 @" z. n2 o" _' u1 T
  19. 4 Q8 U. n. l# Q" M# r* V; s
  20.     ADC1DMA_Handler.Instance = DMA2_Stream0;
    + |. q, R8 v& f8 [% K- u* }
  21.     ADC1DMA_Handler.Init.Channel = DMA_CHANNEL_0;) u  E- @/ h) Z; H4 t8 o/ ]+ U8 z/ P
  22.     ADC1DMA_Handler.Init.Direction = DMA_PERIPH_TO_MEMORY;
    ! |  v* T1 H. n4 p, r
  23.     ADC1DMA_Handler.Init.PeriphInc = DMA_PINC_DISABLE;               //外设非增量模式
    " `2 Q. ^3 \  p# L. W2 W
  24.     ADC1DMA_Handler.Init.MemInc = DMA_MINC_ENABLE;                   //存储器增量模式, F% M$ t1 s. I' g1 S. E/ k+ D. C
  25.     ADC1DMA_Handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;  //外设数据长度:16位
    . |- `* ~/ G4 c* r: o6 ?4 Z
  26.     ADC1DMA_Handler.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;     //存储器数据长度:16位
    ! W9 H* d$ ]) E+ O# q* |, {- s
  27.     ADC1DMA_Handler.Init.Mode = DMA_CIRCULAR;                          //传输一次就结束
    ) b0 T/ B) Q0 A* F) r+ o
  28.     ADC1DMA_Handler.Init.Priority = DMA_PRIORITY_LOW;             //中等优先级
    * P7 B( c4 `, n. y! p; f9 V
  29.     ADC1DMA_Handler.Init.FIFOMode = DMA_FIFOMODE_DISABLE;            /* 禁止FIFO*/$ n# D5 Y1 Z( f/ _8 Y" k0 v
  30. $ m0 B5 Z9 s3 U4 b4 y+ g* x8 \
  31.     HAL_DMA_Init(&ADC1DMA_Handler);8 C) B" E/ @9 a$ v- F/ f" g% U, a( G

  32. ; M0 S/ ~. W: q1 g
  33.     __HAL_LINKDMA(&ADC1_Handler, DMA_Handle, ADC1DMA_Handler);                //将DMA与ADC联系起来
    + h0 }6 Y) T8 P: H8 @& `$ L
  34. : ~4 s% K- E* _
  35. 2 \2 r% S% Q$ |5 S7 \: Q+ O
  36.     ADC1_Handler.Instance = ADC1;! t- ]+ g8 n" L, h6 V
  37.     ADC1_Handler.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; //4分频,ADCCLK=PCLK2/4=108/4=27MHZ/ h  {" n7 Z3 p$ ?/ `
  38.     ADC1_Handler.Init.Resolution = ADC_RESOLUTION_12B;           //12位模式
    : O0 h+ M/ M; ~$ q! K
  39.     ADC1_Handler.Init.ScanConvMode = ENABLE;                    //非扫描模式
    + e- e2 u5 U+ f* C4 B  ^( o
  40.     ADC1_Handler.Init.ContinuousConvMode = ENABLE;              //关闭连续转换
    2 Q9 {6 M2 f' c' Q1 P
  41.     ADC1_Handler.Init.DiscontinuousConvMode = DISABLE;           //禁止不连续采样模式
    - V% Y$ {4 ]  U. W, s
  42.     ADC1_Handler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //使用软件触发
    / C4 A$ a9 b: A, l9 n
  43.     ADC1_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START;     //软件触发
    - i( c$ H- k$ D5 ^
  44.     ADC1_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT;           //右对齐
    / m/ h. Z3 h2 t3 i2 M! F* y" C# ?
  45.     ADC1_Handler.Init.NbrOfConversion = 2;                       //1个转换在规则序列中 也就是只转换规则序列1
    / e: |. L& P- p" g
  46.     ADC1_Handler.Init.DMAContinuousRequests = ENABLE;           //关闭DMA请求+ F" W# D/ d% m- _
  47.     ADC1_Handler.Init.EOCSelection = ADC_EOC_SINGLE_CONV;        
    , ]- w8 h' w" a# q, b2 p7 C
  48.     HAL_ADC_Init(&ADC1_Handler);
    7 D# ~+ E! e+ T0 ]% C% F
  49. 4 F& ?, d7 \& z8 l
  50.     ADC1_ChanConf.Channel = ADC_CHANNEL_5;                                 //通道* v; l9 O) n& r; J" `: ?' i2 G2 M, c
  51.     ADC1_ChanConf.Rank = 1;                                     //序列1# t8 b6 v) I+ [  M
  52.     ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES;      //采样时间
    " P8 A* U9 ]7 @2 Y$ h
  53.     ADC1_ChanConf.Offset = 0;& [& }* x9 s3 a( w0 O8 E" N
  54.     HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf);       //通道配置$ c3 E. g+ i7 u0 T' v

  55. # A" L" T; C: q! B$ r! {! a
  56.     ADC1_ChanConf.Channel = ADC_CHANNEL_6;                                 //通道  t+ X& w/ L2 t& Y, ~8 }
  57.     ADC1_ChanConf.Rank = 2;                                     //序列2
    " z! h' N: P# k8 N6 p# g/ Z
  58.     ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES;      //采样时间
    # }# v; ~( o  [$ l8 {
  59.     ADC1_ChanConf.Offset = 0;
      p. \- _5 p  x1 R6 o8 {
  60.     HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf);       //通道配置
    ! N  [& O5 q1 v$ F. S% Y

  61. 2 i5 Z9 N, h8 N' _
  62.                 HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)buffer, 100);
    ' \( t( g& N' K( r
  63. }9 N3 x' ]" M  F; C
  64. & i; g7 h1 e, h6 l: J
  65. //ADC底层驱动,引脚配置,时钟使能
    . W7 O! u" ~" A0 \' l
  66. //此函数会被HAL_ADC_Init()调用! Y3 B5 q  m( O  o+ B
  67. //hadc:ADC句柄, f. l8 V" o3 T
  68. void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
    2 f/ m  R3 p& ~  d( m
  69. {4 n9 Y+ Y6 F& I8 d; n" L
  70.     GPIO_InitTypeDef GPIO_Initure;
    : m' j3 [5 N: j: l) C
  71.     __HAL_RCC_ADC1_CLK_ENABLE();            //使能ADC1时钟% G0 ]" T; P4 e! {2 n! }
  72.     __HAL_RCC_GPIOA_CLK_ENABLE();           //开启GPIOA时钟$ {0 i' d9 T0 |" Z! L; x( @- c6 q

  73. ( ], a: o5 [# k1 `
  74.     GPIO_Initure.Pin = GPIO_PIN_5|GPIO_PIN_6;          //PA5% V4 P1 E- R2 K1 P" a) `! F5 u) u
  75.     GPIO_Initure.Mode = GPIO_MODE_ANALOG;   //模拟7 C: C% B- A, h/ k7 L3 d8 R
  76.     GPIO_Initure.Pull = GPIO_NOPULL;        //不带上下拉- }8 r: ?- ~5 Q0 Z1 K5 Q- k9 J
  77.     HAL_GPIO_Init(GPIOA, &GPIO_Initure);
    3 _" C8 f+ l3 p- }, {
  78. }. L( f8 V# P1 y, f' E- C

  79. 5 k4 }2 }& ^0 Z5 T' t9 Q
  80. void DMA2_Stream0_IRQHandler(void)' U, H- M# @: g6 J4 Y
  81. {
    2 l5 O, {6 ]3 n5 ]) C
  82.     HAL_DMA_IRQHandler(&ADC1DMA_Handler);; Z$ ]4 B8 O$ K4 w* E
  83. }6 L; i9 H. m6 I+ V- Z6 ?2 E

  84. $ ?' G) W3 \- K  X" T$ u: }$ F
  85. void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
    ( j$ Y$ w! Q( L# R5 }) P, r
  86. {8 c3 a! B  j9 h- N- E, W$ e( ?
  87.         printf("DMA transfer complete\r\n");
    ' c* I! ]7 S! v; j( c* Q  h
  88. }6 C7 [! f+ l+ G& j# F
  89. void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc)  a0 M1 ]; v! E/ ~' [4 |
  90. {
    8 i* e; z1 d: `" B
  91.         printf("DMA Half transfer complete\r\n");
      [" G# M8 J: I/ ]& I/ B
  92. }( R) a; d( c, Y5 a' q) m

  93. - @5 ]: v) _/ A: f
  94. void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc)
    / R5 W# ~7 }. y4 {  p9 q' A! m
  95. {2 I; }$ @* |5 B) a% I" `8 b! T
  96.         printf("DMA transfer error\r\n");/ \" W/ f4 {- j5 u( J, R1 ~
  97. }
复制代码
1 G% D- @7 D9 m" H

* ~/ m3 j$ Q9 h8 I
  1. #include "sys.h"
      e% a  g9 m9 Q' _
  2. #include "delay.h"
    % ~7 s) ~3 h* N3 y- c; I+ n3 K( F* |
  3. #include "usart.h"
    % \  Z# \) ]; H% p

  4. ' W  _3 k5 f- L( c0 i  P: s: R
  5. #include "adc.h"
    , ~! F) Q/ Z4 S- ]7 C) S2 V6 _

  6. 0 G% Z6 ~8 K0 N
  7. extern uint16_t buffer[128];6 ~; s6 U1 ?" t3 @
  8. / }" T- E4 f3 F; z
  9. void show()4 N$ m4 f0 ^  q) _* x/ _) J
  10. {
    & T0 b0 i8 K& X/ T) J0 }9 Q
  11.     int i;$ ~' Z& X/ Z- J% H  e$ u, O. Z
  12.     printf("\r\ndata:");
    2 F  v$ P7 \5 `0 A: N- n' `
  13.     for (i = 0; i < 128; i++)2 r) r) Y) g/ _1 \/ X# ]
  14.     {( }4 P" q* w4 c6 @# t# \
  15.         if (i % 16 == 0) printf("\r\n");' t3 Y$ L0 t+ e5 ^
  16.         printf("%6d", buffer);  }5 E) [5 i6 h' _, Y
  17.                         buffer=0;  p  y& {! Z  r

  18. 8 K9 z6 s/ s( h5 I1 x) h& d
  19.     }
    & G2 s1 _$ F. j. h# E# ~
  20.     printf("\r\n");
    4 a  I3 E2 T+ t  \1 _. W
  21. }9 ?# d& m8 f+ h

  22. - k" Z7 h9 D9 f

  23. * O. j4 `+ F. o4 y# t
  24. int main(void)
      o' R4 P- x/ ~* g- s1 U: y
  25. {( h7 q: i, d: U' g
  26.     //Cache_Enable();                 //打开L1-Cache- B' a$ x7 f% T1 m. @
  27.     HAL_Init();                     //初始化HAL库
    " [1 I* o+ i2 \" Z7 @4 ]
  28.     Stm32_Clock_Init(432, 8, 2, 9); //设置时钟,216Mhz' K7 c8 d4 h7 D( K4 V' g. M
  29.     delay_init(216);                //延时初始化
    . A' o4 s7 Y* H9 d! i* n! M% ^
  30.     uart_init(115200);              //串口初始化
    + ?5 M. H$ l$ O& f( m

  31. , {' u% w- w9 B
  32.     printf("start\r\n");
    8 ?1 Q# P: [# o# r& Z9 F  {$ l; d. Z
  33.     MY_ADC_Init();                  //初始化ADC1通道58 \5 [3 `* f: u5 ~0 H' |* g0 u$ [2 }
  34. " o- O2 S4 J2 c5 k4 E" Q
  35.     while (1)) T0 A0 H" T" \1 x
  36.     {& R2 u  w0 w) t$ F0 U0 s* L) Z
  37.         show();8 `: W9 q2 l) P) D" A
  38.         delay_ms(1000);
    - G6 o8 Z1 n5 Q# @. U' G
  39.     }" `+ L/ I' ~; t( W( P1 I7 W
  40. }
复制代码

# O, L3 ^* L0 t" M) \2 r
% o* {7 W" h- Q5 }9 u, k7 D
收藏 评论0 发布时间:2021-12-15 11:00

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版