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

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

[复制链接]
STMCU小助手 发布时间:2021-12-15 11:00
ADC1DMA_Handler.Init.Mode
: _7 P3 _' c0 ADMA的正常模式(DMA_NORMAL):采集到DMA_BufferSize 的个数后,DMA停止。
  i) K0 G$ |0 p1 kDMA的循环模式(DMA_CIRCULAR):采集到DMA_BufferSize 的个数后,重新回到设置的RAM的起点位置,如此循环。
$ i% P3 p% T1 f1 t" e虽然道理很好理解,但个人感觉要配合触发信号来用,通过HAL_ADC_Start_DMA软件触发需要设置起点位置和长度,否则这个参数是没有意义的。
) w0 E* M2 w$ k  `+ Z1 d) V; i( v8 j
) \. T/ {5 ?2 e! \$ J, AADC1_Handler.Init.ScanConvMode; f. U: O: Q& e6 H  |
扫描模式(ENABLE):ADC会依次扫描设置的各个rank) g/ l& I& _% y) s; q: V9 F
非扫描模式(DISABLE):ADC只会读取rank1,即使设置的DMA_BufferSize大于2,也只会读取第一个;如果没设置rank1(此时我的设置里rank2接的3V3,rank3接的gnd),读出来的结果是516这种奇怪的东西,我也不知道是个什么鬼东西……
# v/ p5 M9 i" A! Y( ^* r" C0 l即使需要只读取rank1的值,把NbrOfConversion不就可以了嘛~" |6 k3 z& d" l1 L: G* M+ K7 g
所以这个参数我建议设置成ENABLE,我也不知道什么时候该用DISABLE。
$ g- `  u; ]( H! s) Q# G, V! R7 u: t' @
ADC1_Handler.Init.ContinuousConvMode. d- o1 A% z) B) p% D5 `) e
开启连续转换:开启了连续转换后,adc会一直转换,直到DMA_BufferSize大小,如图是HAL_ADC_Start_DMA 64个长度的结果。
. f: B+ I4 w7 L4 |4 o+ [3 X. M
; A+ f2 D- _' K% C9 |
20200419192759329.png
( T! w2 @+ k5 p) r6 _- t8 I
而不开启连续转换,长度为64的同时,DMA的传输中断都不会进。0 _6 J( V+ v5 |% b0 S3 u0 l
20200419192936345.png

5 t5 ]: D" V! a) L1 z' ~6 h9 B
) @1 _, M* q9 M+ P! `( g而将传输长度设置为3的时候,就进入了传输完成过半的中断。8 _2 k5 O, H" U+ Y: @
  [. ^) Y3 n( \) S' M( E3 I
20200419194129548.png
, L5 a2 y5 g' z6 @6 M/ j: f
) B  `! t4 W$ C3 R; ^
如果我们需要采集连续的N个次结果求平均值,用这个连续转换会很方便。
) ^2 O7 R, J  A6 f, n* I也从侧面说明,dma的传输中断是一定要有那么长的真实采集数据来才能进的。
3 s3 v. U( G9 U: g
. C5 J- w* j' h6 l  {" p  \在另外一篇里看到了这么一个表格,希望能够辅助大家理解:
) y& u3 u" w( ]  i& ~$ [/ i; W) j  x% v1 }/ ~
20200421214739891.png
; l( K6 M% ^, F9 v

; I( j2 M: [6 {$ B. VADC1_Handler.Init.DMAContinuousRequests
2 W0 z5 W' R( ^5 l/ O当设置了定时器触发DMA之后,这个参数如果设置为DISABLE,就只会采集一轮数据,然后结束。) r- _  _- A) d! O& }4 K: j
这个数据设置成了ENABLE之后,这个参数设置为ENABLE,一轮采集完成之后,感觉就会自动调用一次HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)buffer, 100);,触发DMA请求,以实现不停采集。5 ^4 A+ j) e' R8 y
7 X& v0 \3 Q4 Y" b$ O1 ~
但是需要注意,如果开启了连续转换,又开启了DMA连续请求,adc将一直进行采集,一刻也不停歇……
; z: l- _2 a) l; ^" ^+ i& G: x0 Z6 d5 r2 d
ADC1_Handler.Init.EOCSelection! A# \0 Z# P! X- {5 Y
EOC听说是转换结束标志,这里暂时也没用到,也先埋一个坑……* X& m" j0 m2 Y/ Q8 h3 r' a
填坑STM32F7实现ADC等周期采集(定时器触发+DMA传输)采集完成后的中断设置
3 T6 S( }  P  n+ X5 c
8 C+ e+ @1 [3 b% S+ q6 `, Y偶然看到一个帖子的回复:
9 F" H" H& g& m# K, T' w+ i当有CPU和其它主设备【如DMA】共同访问某可缓存的二级存储器比方SRAM1,同时该存储器又具有回写属性,此时就可能发生数据一致性问题。因为该存储器的回写属性,导致通过CPU欲写入存储器的数据只是缓冲在CACHE里,而没有及时写入存储器。如果此时DMA访问该二级存储器的话,读到的数据可能跟预期不一致。
* d1 b( S. q# [2 B" z为了避免数据不一致的问题,我们需要做D-CACHE维护操作。一般有如下四种方法: 1、当对一个可缓存的二级存储器做了写数据操作之后,通过软件对D-CACHE进行清除操作,即运行SCB_CleanDCache()。这样将CACHE里的缓存内容写回到二级存储器,比如把那些DIRTY, y) G" I; g, N8 N
CACHE行的数据写进SRAM1。
' R  v$ q# h, \7 B. l8 |3 Q/ C2、通过MPU调整可缓存存储器的存储属性,将其CACHE使用方式改为透写模式。这样保证每次写入CACHE里的内容也同时写入二级存储器,比如写进SRAM1。
; K; x' w2 B: Y, T3、通过MPU调整可缓存存储器的存储属性,将其共享属性改为可共享的【SHAREABLE】。此后该二级存储器将变为不可缓存。3 _/ j( F7 B; G% L/ n
4、通过配置CACR寄存器中的D-CACHE位,强制将所有写操作配置为透写属性。4 Z" h) o8 _' \

$ M4 x: c- |" R在main函数中关闭cache,DMA采集的数据就可以更新了。0 R  N+ i+ `$ l% e4 g7 {

+ s: V4 n/ |4 O5 Y" k3 I# w$ q
20200419215859139.png

" G6 J* O' S1 |! c% q0 \4 {: m) Y3 V' P: r9 ]: g+ X
附上成功时候的配置,注释掉HAL_NVIC_EnableIRQ是因为中断服务函数里的打印会导致main函数无法继续执行。5 T1 q6 D8 C. c/ H+ l2 F$ x( l' ^
: B* Y' h5 V# |) E) m9 W3 S3 o# X1 L
  1. #include "adc.h"# O' l+ \$ N& f, |; x% |4 b+ D
  2. #include "delay.h"1 r5 I& L; [5 w7 P; t
  3.   B& r( y# A  y4 _
  4. ADC_HandleTypeDef ADC1_Handler;//ADC句柄! n7 l5 {9 N' U( q
  5. DMA_HandleTypeDef ADC1DMA_Handler;
    " h, x) w5 \9 s* o6 m  F4 ^( x
  6. ADC_ChannelConfTypeDef ADC1_ChanConf;
    : D$ ?3 u) H6 ~# x8 y$ ]3 X4 B. t

  7.   n% P4 g. u  a* l/ q8 f7 p
  8. uint16_t buffer[128];
    5 N) B! o9 B6 s; _0 P

  9. , w* S2 e+ s8 ^+ _

  10. & Q$ B( d$ E8 Z' n4 A! j' {
  11. //初始化ADC
    ) L+ ?" Z4 ^  o! h. O  J  q' ^/ Q
  12. //ch: ADC_channels
    6 ^5 W+ w7 C' l* g
  13. //通道值 0~16取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16
    : J9 o( ~+ g' O% Y' A3 l
  14. void MY_ADC_Init(void)  W! ~" F( K( t8 V/ Y
  15. {7 i% i; N# r3 V% a" a$ Z
  16.     __HAL_RCC_DMA2_CLK_ENABLE();
    + ?0 H' F) m  k2 O. Q6 M
  17.     HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);- c4 c( k# n8 O1 Q& P$ `8 D
  18.     //HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
    ( M" [8 X* z0 u+ e6 l* |' C) b, X

  19. ! y" t' T, h/ z2 F' M
  20.     ADC1DMA_Handler.Instance = DMA2_Stream0;
    ! D- S/ T( i; l
  21.     ADC1DMA_Handler.Init.Channel = DMA_CHANNEL_0;1 U( _5 |7 j5 ~$ u, K( K
  22.     ADC1DMA_Handler.Init.Direction = DMA_PERIPH_TO_MEMORY;: h! t$ [2 G4 z3 S) O
  23.     ADC1DMA_Handler.Init.PeriphInc = DMA_PINC_DISABLE;               //外设非增量模式$ P" E6 Z3 r/ f
  24.     ADC1DMA_Handler.Init.MemInc = DMA_MINC_ENABLE;                   //存储器增量模式. ]2 X7 v9 H. g8 I! D4 S' n
  25.     ADC1DMA_Handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;  //外设数据长度:16位/ b2 P! _5 b) A% D& g) z
  26.     ADC1DMA_Handler.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;     //存储器数据长度:16位
    ' [1 r2 A8 f) N& ^; T  ]
  27.     ADC1DMA_Handler.Init.Mode = DMA_CIRCULAR;                          //传输一次就结束; |9 I' L! @, f1 r! a8 b
  28.     ADC1DMA_Handler.Init.Priority = DMA_PRIORITY_LOW;             //中等优先级6 W. P2 R9 a6 [2 |$ \4 X
  29.     ADC1DMA_Handler.Init.FIFOMode = DMA_FIFOMODE_DISABLE;            /* 禁止FIFO*/
    4 V" ?# [! _- p% f2 f1 [5 z; G) c
  30. 3 a. S  c9 a% @
  31.     HAL_DMA_Init(&ADC1DMA_Handler);
    2 q: ]2 m  S" c0 I, ?- q( X

  32. + p5 ~/ X: |) Y! w% ]
  33.     __HAL_LINKDMA(&ADC1_Handler, DMA_Handle, ADC1DMA_Handler);                //将DMA与ADC联系起来
    0 z" t) a; d, t/ v% Q' Y

  34. ) r9 L& k4 W, A  ~  x
  35. 7 M  n6 u% G+ S! |
  36.     ADC1_Handler.Instance = ADC1;7 x/ h% P+ d9 E6 s/ w
  37.     ADC1_Handler.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; //4分频,ADCCLK=PCLK2/4=108/4=27MHZ: s' T& h( N, A5 o
  38.     ADC1_Handler.Init.Resolution = ADC_RESOLUTION_12B;           //12位模式
    ( i, C3 |7 b: m' X+ |  o1 D
  39.     ADC1_Handler.Init.ScanConvMode = ENABLE;                    //非扫描模式
    & w3 w; E6 |( U" a% D3 O8 R
  40.     ADC1_Handler.Init.ContinuousConvMode = ENABLE;              //关闭连续转换( }, F( t) S+ z$ N' k7 F
  41.     ADC1_Handler.Init.DiscontinuousConvMode = DISABLE;           //禁止不连续采样模式2 H9 R8 A8 _# X% d) L
  42.     ADC1_Handler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //使用软件触发
    5 d9 {& ?2 B( f9 y
  43.     ADC1_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START;     //软件触发
    % p* u& O' C7 @3 q) ]( x) B; d$ m
  44.     ADC1_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT;           //右对齐6 y  {, {0 B) T0 P
  45.     ADC1_Handler.Init.NbrOfConversion = 2;                       //1个转换在规则序列中 也就是只转换规则序列1
    + B* X* z1 k! P
  46.     ADC1_Handler.Init.DMAContinuousRequests = ENABLE;           //关闭DMA请求
    . D) L0 ^/ Z9 L- H' N' Y
  47.     ADC1_Handler.Init.EOCSelection = ADC_EOC_SINGLE_CONV;        1 f1 o/ u6 f. G
  48.     HAL_ADC_Init(&ADC1_Handler);/ ~- n: R5 N+ x" \' ]6 E! @

  49. ) ]( B2 M) m8 y' B
  50.     ADC1_ChanConf.Channel = ADC_CHANNEL_5;                                 //通道
    ; @* E6 ^+ Y3 D/ c( A2 v2 P
  51.     ADC1_ChanConf.Rank = 1;                                     //序列18 u+ e" v! |# q  v7 m
  52.     ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES;      //采样时间
    0 W! V) _5 B1 @8 K) I  }0 O7 D
  53.     ADC1_ChanConf.Offset = 0;
    & D- z8 J- h5 @: _; e- Q
  54.     HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf);       //通道配置/ C3 t( q. C+ Q7 c$ v9 e

  55. 0 s' e- V4 p% @# d( F: f
  56.     ADC1_ChanConf.Channel = ADC_CHANNEL_6;                                 //通道
    : y- Q  ~. @0 M7 E: R' k/ S
  57.     ADC1_ChanConf.Rank = 2;                                     //序列28 j& L5 t# }( k0 J7 ?
  58.     ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES;      //采样时间: Z! u" X- p* p3 d# m- v5 W
  59.     ADC1_ChanConf.Offset = 0;
    5 N' R' I+ d! Y7 A/ g' N: L! [
  60.     HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf);       //通道配置+ j0 W9 ^0 W, h" h. |
  61. 9 ]9 h6 s+ c4 P$ d
  62.                 HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)buffer, 100);4 {# p5 k$ g  q& u, ?
  63. }
    * k( q8 a7 t' K7 z: c/ u+ b( }
  64. 3 E' a2 a  V! F7 ^# l4 n$ _" \
  65. //ADC底层驱动,引脚配置,时钟使能
    % a4 l' r' r1 L/ r
  66. //此函数会被HAL_ADC_Init()调用
      J1 Q3 k* w, H1 Q
  67. //hadc:ADC句柄
    ; |! H1 L' P" K3 h$ h
  68. void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)4 m! v; H+ K  I' a# j6 O* m% L
  69. {, p% E$ e: V# m
  70.     GPIO_InitTypeDef GPIO_Initure;9 O9 u/ v9 P) H6 {
  71.     __HAL_RCC_ADC1_CLK_ENABLE();            //使能ADC1时钟
    ' j5 v- h( e0 ~# f" d7 B3 L! Y+ g
  72.     __HAL_RCC_GPIOA_CLK_ENABLE();           //开启GPIOA时钟* P5 P- _8 S  o8 f4 w  H* X

  73. ) X* s: s( F1 j( h/ G/ o" q! W4 X
  74.     GPIO_Initure.Pin = GPIO_PIN_5|GPIO_PIN_6;          //PA5: [8 G8 r# T$ E
  75.     GPIO_Initure.Mode = GPIO_MODE_ANALOG;   //模拟7 s  \, h' M8 F# }1 A
  76.     GPIO_Initure.Pull = GPIO_NOPULL;        //不带上下拉
    * f7 W- X- x5 h% I9 O* ]; t! R
  77.     HAL_GPIO_Init(GPIOA, &GPIO_Initure);
    & v4 o# O. L+ z8 P7 [; P4 _
  78. }
    * A9 K+ M2 P6 y' j9 Z* {% ]
  79. : t6 W: f6 E2 @6 r" n7 c& [
  80. void DMA2_Stream0_IRQHandler(void)! l% `9 z' ^2 _1 Z
  81. {
    : X# X4 Q6 T/ z+ J- }% T
  82.     HAL_DMA_IRQHandler(&ADC1DMA_Handler);
    % p2 S7 C6 P: o( a# a' g3 f$ T! ^
  83. }
    5 {: K! u+ r- ?( e1 ?

  84. ( u4 t3 E4 {; \( T; t1 W
  85. void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)5 l/ L! @5 S2 [& ]' c
  86. {
    2 `; c( V1 u) m- d6 Y6 d# ^
  87.         printf("DMA transfer complete\r\n");
    $ f. `* T3 Y0 \8 [; t
  88. }% D9 v5 [: \4 q) C
  89. void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc)6 k" Q4 I( t% B7 v  n' Q) I' U! h
  90. {
    & c% x1 S  E. {* |  v  ?! Q
  91.         printf("DMA Half transfer complete\r\n");6 H) @2 ^8 u, u+ v
  92. }4 V* _4 C, G% I! ^9 P5 p3 T2 N& _
  93. 2 x, w* D( j/ [) g# L; H
  94. void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc)
    # J( [# b: v- j% N* _
  95. {
    " L& M, V+ b( h
  96.         printf("DMA transfer error\r\n");
    7 w* t/ Q, t$ r6 {4 }' a, @
  97. }
复制代码
9 ~, [* `# f5 F4 E  M8 i8 }

2 T+ w% S/ E- [# x  `  [
  1. #include "sys.h"
    4 s0 Q) L; |* U
  2. #include "delay.h"7 m9 T/ L" t. ]0 h' e
  3. #include "usart.h". O1 D( e* e1 N# C: U
  4. 6 D3 J- j  Q7 Z! s4 }
  5. #include "adc.h"$ U& P; M- b1 N+ t$ ?% r
  6. # b% `5 d" n  g8 W/ ]
  7. extern uint16_t buffer[128];: D& k# W: c5 R9 |) }5 R; i& p

  8. ! |5 Q; E+ ^" y9 ~4 O& ]* G( o3 Q
  9. void show()7 p0 s* o. g) b" @  K
  10. {
    9 y1 o) W, o7 v/ l& f; c
  11.     int i;
    * |) W* H3 r* D0 X6 C( `
  12.     printf("\r\ndata:");, Z: Z. J4 f5 \7 G. Q
  13.     for (i = 0; i < 128; i++)' w+ t5 j8 t4 z- i2 c
  14.     {$ [8 Y! n5 M6 `& [; C
  15.         if (i % 16 == 0) printf("\r\n");+ Q3 l+ C/ ~' E8 Y9 {3 j
  16.         printf("%6d", buffer);
    ( s- V% j  K# X! k  B8 E
  17.                         buffer=0;
    6 ?- Y$ G8 ]$ ?+ E8 V! t  R- U
  18. 6 r) s4 B+ K8 S5 ]
  19.     }
    4 S) n# @) X+ o; O2 ~7 g
  20.     printf("\r\n");
    5 O7 a+ `; N% \! a" s. N  L
  21. }' l( Q1 I0 B8 y( {0 {/ g

  22. + a) _+ S& t9 M' Q
  23. % K  |. y0 w4 S  A. p+ n* d0 |& h
  24. int main(void)4 J2 [  W8 p& l7 A7 n: N
  25. {
      {/ }7 o( v3 G" Y
  26.     //Cache_Enable();                 //打开L1-Cache
    # Q4 Z% J% V4 K: a5 K
  27.     HAL_Init();                     //初始化HAL库
    # ?5 q" }9 }7 g3 e) s2 w) ^; ]- Q
  28.     Stm32_Clock_Init(432, 8, 2, 9); //设置时钟,216Mhz
    , O& U; |7 B$ R+ @+ j
  29.     delay_init(216);                //延时初始化
    . h2 y& H/ L3 G  `
  30.     uart_init(115200);              //串口初始化/ ]9 M: Y" T1 E

  31. - B* E; o3 M9 R
  32.     printf("start\r\n");; p9 O! p$ L- H1 w
  33.     MY_ADC_Init();                  //初始化ADC1通道5
    ! W  h8 U2 F0 L+ Y1 f% j7 z
  34. ; S! d% d+ Z5 N: Z: r( s
  35.     while (1)+ R3 n! d. G0 D6 ?; m: G  }! Z
  36.     {- ~+ D+ S7 G; X
  37.         show();
    % j0 D4 L8 J! S5 ]) l" z
  38.         delay_ms(1000);6 {4 K) x8 P/ o1 R1 z0 ]
  39.     }0 O8 K' ?. J* n* c/ r3 S
  40. }
复制代码

( y2 |) c7 f: t' h$ C4 b; {9 f+ ~- u
! G4 r# k' F7 w9 F3 v9 [: T# m( H/ _
收藏 评论0 发布时间:2021-12-15 11:00

举报

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