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

基于STM32F7进行ADC采集解决更新问题

[复制链接]
攻城狮Melo 发布时间:2023-3-14 11:26
ADC1DMA_Handler.Init.Mode4 X& Z" O" g- O( d, l" _8 L1 C3 D) V
DMA的正常模式(DMA_NORMAL):采集到DMA_BufferSize 的个数后,DMA停止。
# d% O0 D: k, a# J% b2 `DMA的循环模式(DMA_CIRCULAR):采集到DMA_BufferSize 的个数后,重新回到设置的RAM的起点位置,如此循环。
& [( [. N, v6 s- H虽然道理很好理解,但个人感觉要配合触发信号来用,通过HAL_ADC_Start_DMA软件触发需要设置起点位置和长度,否则这个参数是没有意义的。
+ p4 }. c* s& Z& t% A' K
3 s/ M9 k. b" F  I; q7 r8 ]
ADC1_Handler.Init.ScanConvMode

& n& l9 ~) C7 s( a7 t; K$ x. P扫描模式(ENABLE):ADC会依次扫描设置的各个rank! d% c4 ?) k! R* s# p; T; f! A+ u
非扫描模式(DISABLE):ADC只会读取rank1,即使设置的DMA_BufferSize大于2,也只会读取第一个;如果没设置rank1(此时我的设置里rank2接的3V3,rank3接的gnd),读出来的结果是516这种奇怪的东西,我也不知道是个什么鬼东西……
8 H* J5 n; x' |. e( j8 O; m+ C即使需要只读取rank1的值,把NbrOfConversion不就可以了嘛~9 s5 U  A6 b; p. @6 J+ U
所以这个参数我建议设置成ENABLE,我也不知道什么时候该用DISABLE。
7 Y' T1 {7 ?% |) j
. |% R( `+ p/ r* k; Y
ADC1_Handler.Init.ContinuousConvMode
. s' v) @: }: I7 K! M9 a4 U; ]开启连续转换:开启了连续转换后,adc会一直转换,直到DMA_BufferSize大小,如图是HAL_ADC_Start_DMA 64个长度的结果。+ k# a2 O! Q# O! u% u2 V& \
, h$ x) K, T! t
20200419192759329.png
( \! Q8 |$ p- I& ~, R% T* r6 {) c
9 H$ Y2 `! u% K/ g4 f* V6 o# ^5 `7 P+ f( K
而不开启连续转换,长度为64的同时,DMA的传输中断都不会进。: G9 a) c1 s) o% g1 P

. M' n% `- Z& o" e7 _: ^* A: c. B6 @
20200419192936345.png 9 T/ V8 u" m4 b1 ?/ F: v) o, X2 [, P

/ t; B/ u- z9 a8 S9 Y( P  Y( W而将传输长度设置为3的时候,就进入了传输完成过半的中断。
; b8 `& ]) n! u9 ^5 |
20200419194129548.png
" H* Z: s6 {9 s4 n

4 C/ A/ Y2 I9 q2 W$ l4 Q& Z如果我们需要采集连续的N个次结果求平均值,用这个连续转换会很方便。- u# C. S4 ]) E; o) R& d
也从侧面说明,dma的传输中断是一定要有那么长的真实采集数据来才能进的。
" |# l' U- C/ I9 j
" [2 k( ^2 \" `( N6 O, p
在另外一篇博文里看到了这么一个表格,希望能够辅助大家理解:/ B9 }4 {. N) v2 W; E: a
4 B; }- b: D: n: i0 ~
20200421214739891.png 6 V: [* t5 D- W% w+ [
0 ~4 Z! G% z1 C  g4 E" K6 }
ADC1_Handler.Init.DMAContinuousRequests, @5 m$ G& {* E
当设置了定时器触发DMA之后,这个参数如果设置为DISABLE,就只会采集一轮数据,然后结束。
+ S' E  `3 g/ S+ D. b这个数据设置成了ENABLE之后,这个参数设置为ENABLE,一轮采集完成之后,感觉就会自动调用一次HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)buffer, 100);,触发DMA请求,以实现不停采集。/ [! f! G5 i  X+ w6 |

$ E, x, Q: B0 x4 Z5 x( N+ C但是需要注意,如果开启了连续转换,又开启了DMA连续请求,adc将一直进行采集,一刻也不停歇……$ ?* i  l: B. W
) i: g; ?1 E' R6 X
ADC1_Handler.Init.EOCSelection
4 x5 w, v9 }  \偶然看到一个帖子的回复:8 }: ]. }1 ~( u7 Y
当有CPU和其它主设备【如DMA】共同访问某可缓存的二级存储器比方SRAM1,同时该存储器又具有回写属性,此时就可能发生数据一致性问题。因为该存储器的回写属性,导致通过CPU欲写入存储器的数据只是缓冲在CACHE里,而没有及时写入存储器。如果此时DMA访问该二级存储器的话,读到的数据可能跟预期不一致。4 y) V1 R$ k2 y2 ~
为了避免数据不一致的问题,我们需要做D-CACHE维护操作。一般有如下四种方法: 1、当对一个可缓存的二级存储器做了写数据操作之后,通过软件对D-CACHE进行清除操作,即运行SCB_CleanDCache()。这样将CACHE里的缓存内容写回到二级存储器,比如把那些DIRTY
8 g! `- d7 q- C3 q9 \4 @CACHE行的数据写进SRAM1。
" B8 E2 a% W. O) R) }0 u/ q2、通过MPU调整可缓存存储器的存储属性,将其CACHE使用方式改为透写模式。这样保证每次写入CACHE里的内容也同时写入二级存储器,比如写进SRAM1。. [% M! u' Q8 R  X/ j5 O  p  n
3、通过MPU调整可缓存存储器的存储属性,将其共享属性改为可共享的【SHAREABLE】。此后该二级存储器将变为不可缓存。: Q2 d, q" m$ T4 S
4、通过配置CACR寄存器中的D-CACHE位,强制将所有写操作配置为透写属性。
; H6 p8 e) V5 A7 ^5 w9 e
6 ?! q2 d  q& _! `在main函数中关闭cache,DMA采集的数据就可以更新了。, A; F5 o4 a5 W, a
6 u6 I" K9 E3 @3 z. }# X, @
20200419215859139.png   O% |, x$ l# E; O' X9 P
" j- `2 K  K, B5 y  ^5 V
附上成功时候的配置,注释掉HAL_NVIC_EnableIRQ是因为中断服务函数里的打印会导致main函数无法继续执行。9 R1 f7 N; o/ P; p0 ^* h
  1. #include "adc.h"
    $ y! g- }1 ]1 ?. s0 n, a7 u
  2. #include "delay.h"! ^8 E% L5 ?2 t$ n
  3. : b! m: l7 q& Z8 Q
  4. ADC_HandleTypeDef ADC1_Handler;//ADC句柄
    5 d2 O# C- y4 V$ Q. ^
  5. DMA_HandleTypeDef ADC1DMA_Handler;
    ; }0 N; Q7 h* }; t$ D
  6. ADC_ChannelConfTypeDef ADC1_ChanConf;
    & \3 B  O$ A% _7 f& g6 g

  7. : Q3 c* _9 |9 q' W/ s. b
  8. uint16_t buffer[128];  @3 \* n5 T% _) b6 d8 q! e3 [

  9. & l* r6 ]' {% z( x# t

  10. : u+ e- U( }' `$ W4 ~1 I1 [" e
  11. //初始化ADC4 ]& L1 f% r0 K+ z- L" f
  12. //ch: ADC_channels
    , b8 z1 d! S/ z# L/ j
  13. //通道值 0~16取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16
    3 B! I! S0 R( C0 Q" h2 d5 _
  14. void MY_ADC_Init(void)' C8 W' r9 _- N4 M! Z
  15. {4 A# ]& i9 @- U+ ?  n5 {' i" O
  16.     __HAL_RCC_DMA2_CLK_ENABLE();
    " g8 X9 |9 o' R2 x: p; j, K
  17.     HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);+ W% ^1 t/ ]1 h. @  h
  18.     //HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
    ! f/ E6 g+ s+ g: h. E( P; Y9 i& b
  19. 8 h4 n( ?! a# Y9 ?5 M$ h3 r
  20.     ADC1DMA_Handler.Instance = DMA2_Stream0;
    + ?" v5 i# l  R
  21.     ADC1DMA_Handler.Init.Channel = DMA_CHANNEL_0;2 R# O/ x' P" D5 }. |- r5 a0 B
  22.     ADC1DMA_Handler.Init.Direction = DMA_PERIPH_TO_MEMORY;
    % i7 ^+ |+ i* ^3 B) ~+ M
  23.     ADC1DMA_Handler.Init.PeriphInc = DMA_PINC_DISABLE;               //外设非增量模式8 u  \  p( s. Q
  24.     ADC1DMA_Handler.Init.MemInc = DMA_MINC_ENABLE;                   //存储器增量模式
    3 Z- d% j3 R+ R
  25.     ADC1DMA_Handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;  //外设数据长度:16位( N( i5 h6 E# O( k) q0 A0 G" s- r- R
  26.     ADC1DMA_Handler.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;     //存储器数据长度:16位# n$ h5 F$ A( d% x
  27.     ADC1DMA_Handler.Init.Mode = DMA_CIRCULAR;                          //传输一次就结束
    4 k' O3 ~3 g! u" A
  28.     ADC1DMA_Handler.Init.Priority = DMA_PRIORITY_LOW;             //中等优先级* `5 ?/ }/ \3 g  n! p- x+ |4 z+ k
  29.     ADC1DMA_Handler.Init.FIFOMode = DMA_FIFOMODE_DISABLE;            /* 禁止FIFO*/
    6 b" y2 [' M) S7 ]- B: l' c0 B

  30. ; w5 Q! h' D$ j4 {$ n. l+ l
  31.     HAL_DMA_Init(&ADC1DMA_Handler);9 u$ J& P" `% @+ U$ C% |

  32. " ?$ y, w9 W5 O0 Y# }4 G% c& `/ [
  33.     __HAL_LINKDMA(&ADC1_Handler, DMA_Handle, ADC1DMA_Handler);                //将DMA与ADC联系起来
    + T& F: O( p. B4 l, T3 I' D7 a
  34.   p8 D4 P. b% T6 x2 c

  35. 5 V3 r8 H7 z1 C. M; q
  36.     ADC1_Handler.Instance = ADC1;
      ^- t- j, E2 G
  37.     ADC1_Handler.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; //4分频,ADCCLK=PCLK2/4=108/4=27MHZ
    1 k# A' o; O% ]* B+ H; ]
  38.     ADC1_Handler.Init.Resolution = ADC_RESOLUTION_12B;           //12位模式
    $ S& c% {( m' D) \' H
  39.     ADC1_Handler.Init.ScanConvMode = ENABLE;                    //非扫描模式" J8 [3 K5 j* E. U# e$ \5 T
  40.     ADC1_Handler.Init.ContinuousConvMode = ENABLE;              //关闭连续转换- I" b2 X7 h. D2 W4 [2 M
  41.     ADC1_Handler.Init.DiscontinuousConvMode = DISABLE;           //禁止不连续采样模式/ J2 e" B6 I0 S; c5 J- D
  42.     ADC1_Handler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //使用软件触发! w( m& p9 m1 A: g" J6 r! G
  43.     ADC1_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START;     //软件触发; G  p& D* `8 V% q1 @' W
  44.     ADC1_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT;           //右对齐
    4 f+ o( X+ l# _
  45.     ADC1_Handler.Init.NbrOfConversion = 2;                       //1个转换在规则序列中 也就是只转换规则序列1
    / h1 l" [; B3 p* c
  46.     ADC1_Handler.Init.DMAContinuousRequests = ENABLE;           //关闭DMA请求8 N+ n3 N; c4 }+ t6 k
  47.     ADC1_Handler.Init.EOCSelection = ADC_EOC_SINGLE_CONV;        : P0 E0 \- x/ O8 ?: A5 s! Z6 f
  48.     HAL_ADC_Init(&ADC1_Handler);" r+ J! h" J2 t: b, C, e

  49. 3 A! f4 F& Q8 j% r
  50.     ADC1_ChanConf.Channel = ADC_CHANNEL_5;                                 //通道
    ( Y! g6 i1 v$ |7 c
  51.     ADC1_ChanConf.Rank = 1;                                     //序列1; X7 M- R7 E. m8 O; D  ^0 A
  52.     ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES;      //采样时间
    6 V! m& S5 f" S) p, N, M  w& ?& U' E
  53.     ADC1_ChanConf.Offset = 0;
    " m" O: E- ]2 q5 M! Q5 v
  54.     HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf);       //通道配置% a. n4 o$ w* T3 n( [
  55. 0 M8 M2 k4 \( F5 p$ |+ D" g
  56.     ADC1_ChanConf.Channel = ADC_CHANNEL_6;                                 //通道/ J3 @8 M( j, B7 v3 v
  57.     ADC1_ChanConf.Rank = 2;                                     //序列2$ Q0 T! e4 O3 v: a0 a1 r
  58.     ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES;      //采样时间
    - ^& _$ p: v8 ?+ N8 r
  59.     ADC1_ChanConf.Offset = 0;% Z% Y6 ^. H' v, N* _+ t
  60.     HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf);       //通道配置
    2 l! [4 X& }  M* O
  61. 2 Q6 x6 F1 S7 t! g! r' s4 W
  62.                 HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)buffer, 100);
    * D3 w9 x' m  F& W
  63. }. b0 x6 u- ]9 E+ L/ Y% n
  64. , j+ m& @/ {. O+ C' n. u
  65. //ADC底层驱动,引脚配置,时钟使能
    1 t; Y  S5 z0 R  ]4 p+ ^
  66. //此函数会被HAL_ADC_Init()调用
      |* p  D7 a4 r6 B  d9 ~
  67. //hadc:ADC句柄! E1 U  H; b: V% j5 G
  68. void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)9 _9 c3 H4 Y  V  v9 y
  69. {3 [. S0 b5 ^+ ^
  70.     GPIO_InitTypeDef GPIO_Initure;
    2 L* M( t; r1 L5 f
  71.     __HAL_RCC_ADC1_CLK_ENABLE();            //使能ADC1时钟
    ! R: o1 _) z' P
  72.     __HAL_RCC_GPIOA_CLK_ENABLE();           //开启GPIOA时钟) B1 N5 a" [5 L* O, v9 {+ d3 p

  73. - B8 G; f4 ?* k; L4 n
  74.     GPIO_Initure.Pin = GPIO_PIN_5|GPIO_PIN_6;          //PA5
      M& e. ?% C" K$ `
  75.     GPIO_Initure.Mode = GPIO_MODE_ANALOG;   //模拟  A( ~* Y( M: ^! E" b' S' E
  76.     GPIO_Initure.Pull = GPIO_NOPULL;        //不带上下拉. Q1 ]6 S; y. K+ k9 z6 c3 o
  77.     HAL_GPIO_Init(GPIOA, &GPIO_Initure);3 E! _2 ^& \% @  o, `7 a
  78. }
    0 u: Q! m$ D0 L$ W' Y. R& w
  79. ' i0 s. F6 `  n8 _
  80. void DMA2_Stream0_IRQHandler(void)7 m7 @1 E! E2 o3 W$ b7 x! S, {
  81. {5 k5 C* l* y( b
  82.     HAL_DMA_IRQHandler(&ADC1DMA_Handler);
    7 n$ g! L8 f( f
  83. }
    , N& q/ M9 f( p, e
  84. ! `  L4 i1 u- [$ H. a/ h
  85. void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
    ! ]2 Y, L9 O1 v6 P& E, [
  86. {
    1 W4 x2 Q) Y' {$ Y/ k$ }
  87.         printf("DMA transfer complete\r\n");' D' Q# L0 S: o/ d
  88. }
    ' q! D- w6 {0 }6 r: a
  89. void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc)7 _7 D* k% G% G' Z+ ^3 r' e
  90. {
    ) `% ]' F# y* ], ~3 O# ?
  91.         printf("DMA Half transfer complete\r\n");
    ' K* k* x9 f4 S0 X) ?& L; b0 L; m
  92. }/ u# o7 ^, o, I; e/ K2 Q" Y# s
  93. # J* m. b' l1 ]9 }1 N
  94. void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc)5 ]8 f* ^( E8 g/ ]1 p
  95. {
    1 B: Q; o- o# s' K* C% L1 p
  96.         printf("DMA transfer error\r\n");% |7 g( N/ ~- Y' m" u0 u% r
  97. }
    - @7 D* t: V: E/ j/ q# G2 c
复制代码
  1. #include "sys.h"
    5 l/ b1 \3 g) Y+ Y0 _# I
  2. #include "delay.h"2 ^7 B$ S, f1 h
  3. #include "usart.h"/ u# K  y7 c  f9 a! I" I( O8 J

  4. 1 s- |  z- ?# o- S' I* g* n) G" }
  5. #include "adc.h"! J0 H7 t8 v0 |
  6. 5 i4 M# Y! |" m3 E
  7. extern uint16_t buffer[128];0 n0 s6 ?: y6 l! r4 c4 P9 C
  8. . O, _* |4 Z% W# k$ C
  9. void show()2 V! \' C, v# g9 D/ E' C; y. u" Z
  10. {
    & }) r* f# z+ ^* ?6 W: H8 T3 x$ J
  11.     int i;2 v, m0 i% ?- c* p
  12.     printf("\r\ndata:");
    & }! m. N+ r5 X8 t/ _! `
  13.     for (i = 0; i < 128; i++)
    ( t: q: v* h$ l/ Y: U# r9 d3 G9 {
  14.     {
    ( y- A, }& B) C8 T; M
  15.         if (i % 16 == 0) printf("\r\n");& B) F, B' c1 I* Q: U9 B
  16.         printf("%6d", buffer[i]);
    7 K9 d8 M% N1 U
  17.                         buffer[i]=0;
    ; x9 v1 g, m) T2 ^4 h

  18. $ U4 j5 e' ~- z  F
  19.     }4 ]6 `1 n1 u+ D7 k3 x. A  |
  20.     printf("\r\n");* `' f( r2 n+ n  U& }/ a
  21. }8 ~& C% C, x) B1 O  c2 x" M( u
  22. 0 H8 C! ?' Z: `- g8 k6 s
  23.   a5 U' b) r0 `5 Q
  24. int main(void)4 d! p! F+ y5 M
  25. {
    7 ?" B9 u2 o* m
  26.     //Cache_Enable();                 //打开L1-Cache
    2 f& }9 I' L7 I3 P
  27.     HAL_Init();                     //初始化HAL库7 h" B2 O7 r; ?/ K( r
  28.     Stm32_Clock_Init(432, 8, 2, 9); //设置时钟,216Mhz5 p" k8 J" H1 J; `9 [3 S9 Q7 b0 H
  29.     delay_init(216);                //延时初始化: X) d4 |: C0 f9 e: l8 s
  30.     uart_init(115200);              //串口初始化  J  g% P1 c1 H2 w
  31. + o6 ^: \2 b8 w
  32.     printf("start\r\n");
    ' }& G# t0 r; f0 Q, a3 p4 w
  33.     MY_ADC_Init();                  //初始化ADC1通道5! k6 Y" d: H) S/ S
  34.     * G# o) y; L/ {7 m: |! u6 `
  35.     while (1)
    0 s; o: J/ |2 o2 k0 c- z, K/ w2 t
  36.     {
    / b. d7 d2 K3 v4 G; O
  37.         show();. ]& C! f/ ~  H9 j. p: r1 \) z# C
  38.         delay_ms(1000);+ w- L% X2 _! U; l' S' l' k# `$ N1 g
  39.     }
    # p4 D: X1 g  n7 F! W3 {
  40. }
复制代码

: R6 o4 n( f  Z. K4 u# x————————————————
# N+ n0 d# l  J3 D- e版权声明:小盼你最萌哒
; N1 h) W+ O1 m- o如有侵权请联系删除
: b& B1 ?4 s. I6 _3 ]! [
: u' V0 Z7 |! W( d! e0 u5 R. w& B4 d
赞 收藏 评论0 发布时间:2023-3-14 11:26

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版