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

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

[复制链接]
攻城狮Melo 发布时间:2023-3-14 11:26
ADC1DMA_Handler.Init.Mode
- S# k1 v, c% F0 X+ TDMA的正常模式(DMA_NORMAL):采集到DMA_BufferSize 的个数后,DMA停止。
& p; {6 L9 ^, y0 X) X4 BDMA的循环模式(DMA_CIRCULAR):采集到DMA_BufferSize 的个数后,重新回到设置的RAM的起点位置,如此循环。2 B* X; B6 E/ [) {2 U( U
虽然道理很好理解,但个人感觉要配合触发信号来用,通过HAL_ADC_Start_DMA软件触发需要设置起点位置和长度,否则这个参数是没有意义的。
& q% o. b1 k: k9 I, l9 F% k

' |( ^' A% I# _  ]' XADC1_Handler.Init.ScanConvMode

: F; z' f! [( A; t# T. H扫描模式(ENABLE):ADC会依次扫描设置的各个rank7 D7 ~- e8 f9 K6 _6 f$ Q8 G9 m
非扫描模式(DISABLE):ADC只会读取rank1,即使设置的DMA_BufferSize大于2,也只会读取第一个;如果没设置rank1(此时我的设置里rank2接的3V3,rank3接的gnd),读出来的结果是516这种奇怪的东西,我也不知道是个什么鬼东西……
9 ~8 O2 L) |5 r  z6 t; [即使需要只读取rank1的值,把NbrOfConversion不就可以了嘛~$ ~4 d  o! X7 u7 H  E
所以这个参数我建议设置成ENABLE,我也不知道什么时候该用DISABLE。0 u7 a. A( Q5 k9 z. ^
+ [/ N1 s5 o! B" p& e/ x
ADC1_Handler.Init.ContinuousConvMode
( T& W" s8 x0 n% Q& }. J/ K开启连续转换:开启了连续转换后,adc会一直转换,直到DMA_BufferSize大小,如图是HAL_ADC_Start_DMA 64个长度的结果。& u0 q/ J# Q7 v2 n& I5 A* a

! g4 g0 d5 i+ a
20200419192759329.png # E. F- y: h" i7 A  z) }& `
9 t% ?  Q) N  j! M
而不开启连续转换,长度为64的同时,DMA的传输中断都不会进。
0 w  x/ D: J  i  @% h) T. O4 Q0 ^3 a0 n) u; X
20200419192936345.png 8 F3 |$ f; w3 t% ~* n$ Z
+ _) [' g9 ]5 k$ t" {; y0 ^
而将传输长度设置为3的时候,就进入了传输完成过半的中断。, O8 n: K7 A/ a/ k
20200419194129548.png . m3 F4 m8 C9 P7 F

  J* H3 e2 v/ w! \- |如果我们需要采集连续的N个次结果求平均值,用这个连续转换会很方便。
; V9 S) t& ^  B' R也从侧面说明,dma的传输中断是一定要有那么长的真实采集数据来才能进的。
5 s4 k1 [1 \7 |4 G$ ?- n

2 D6 V% f  t* c! K7 X. M在另外一篇博文里看到了这么一个表格,希望能够辅助大家理解:
: K6 a8 O; I& u+ T2 ?7 [$ ~
' X% f; J+ a" w
20200421214739891.png
, G5 x# r& u! D5 n

9 {% E# b9 E) ]4 S3 n$ dADC1_Handler.Init.DMAContinuousRequests3 Q0 t* S- j6 I3 U4 y
当设置了定时器触发DMA之后,这个参数如果设置为DISABLE,就只会采集一轮数据,然后结束。% v2 Z- S% M7 R
这个数据设置成了ENABLE之后,这个参数设置为ENABLE,一轮采集完成之后,感觉就会自动调用一次HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)buffer, 100);,触发DMA请求,以实现不停采集。
7 V) u" J, C2 M
* @/ p1 J$ B- d" ^" }# g但是需要注意,如果开启了连续转换,又开启了DMA连续请求,adc将一直进行采集,一刻也不停歇……. |  ^7 o4 [# _( S- e' o+ M  e
7 }; v( n7 _" ?  g) H
ADC1_Handler.Init.EOCSelection* g' I# o" Q; ^8 u/ [0 M( j( k  r
偶然看到一个帖子的回复:9 }2 l2 \3 `! l' W1 X
当有CPU和其它主设备【如DMA】共同访问某可缓存的二级存储器比方SRAM1,同时该存储器又具有回写属性,此时就可能发生数据一致性问题。因为该存储器的回写属性,导致通过CPU欲写入存储器的数据只是缓冲在CACHE里,而没有及时写入存储器。如果此时DMA访问该二级存储器的话,读到的数据可能跟预期不一致。6 K1 J& p8 U' S# R5 m2 p
为了避免数据不一致的问题,我们需要做D-CACHE维护操作。一般有如下四种方法: 1、当对一个可缓存的二级存储器做了写数据操作之后,通过软件对D-CACHE进行清除操作,即运行SCB_CleanDCache()。这样将CACHE里的缓存内容写回到二级存储器,比如把那些DIRTY. Z( A* s, j) d: x
CACHE行的数据写进SRAM1。& n; {& |* v. u2 {7 u
2、通过MPU调整可缓存存储器的存储属性,将其CACHE使用方式改为透写模式。这样保证每次写入CACHE里的内容也同时写入二级存储器,比如写进SRAM1。4 y* m7 M0 U' G+ X( K( l# I
3、通过MPU调整可缓存存储器的存储属性,将其共享属性改为可共享的【SHAREABLE】。此后该二级存储器将变为不可缓存。. O7 q& s* A! y4 C3 @
4、通过配置CACR寄存器中的D-CACHE位,强制将所有写操作配置为透写属性。
0 ^* d/ c6 j% P  x! m. v
. F% U0 Y  A/ U$ @) V1 E在main函数中关闭cache,DMA采集的数据就可以更新了。
& T, T! [+ \8 b+ z% ~$ J
0 k  }: n# A" \
20200419215859139.png
+ @" C  ^: d$ E3 `7 x0 @
" |' V* o3 {( _$ D# i' O( o2 w: H, H* e
附上成功时候的配置,注释掉HAL_NVIC_EnableIRQ是因为中断服务函数里的打印会导致main函数无法继续执行。$ V# \+ w' |% Y7 L) ~+ J
  1. #include "adc.h"
    ; z, m* C+ G: f4 B/ d9 l& Z1 P0 {
  2. #include "delay.h"( T, C1 Z# U0 Z
  3. 3 x" s5 s) x0 R1 B  u
  4. ADC_HandleTypeDef ADC1_Handler;//ADC句柄; I' i0 Q* |! A+ o' z1 ~4 }  d
  5. DMA_HandleTypeDef ADC1DMA_Handler;% p* u6 F( M8 Q) q% Y( S
  6. ADC_ChannelConfTypeDef ADC1_ChanConf;
    1 r1 z' }: f& e8 a6 G

  7. 1 l/ c; u9 X: v% ^3 w* S
  8. uint16_t buffer[128];: T. e: T! O& f
  9. " p% w: C" c, V. Y' H1 P( i

  10. " H5 C4 E& ?4 d7 v
  11. //初始化ADC/ A- o* E  C+ a5 Z! C& q3 b
  12. //ch: ADC_channels
    * T) M2 L2 g, B7 S0 F
  13. //通道值 0~16取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16
    / a6 Q" I# L, T# `
  14. void MY_ADC_Init(void)
    7 X6 _, |* Q; \
  15. {4 |# E/ i6 q) p2 W
  16.     __HAL_RCC_DMA2_CLK_ENABLE();
    ( ]7 m9 n" E( G: O
  17.     HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);6 x" r0 Y9 ?/ S- R7 M
  18.     //HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
    * L$ b7 V3 T+ n2 b+ t0 |" x5 W; ^
  19.   j" y" }2 N3 N+ y' [
  20.     ADC1DMA_Handler.Instance = DMA2_Stream0;. I# n) W5 K! h! G7 B. T% ?
  21.     ADC1DMA_Handler.Init.Channel = DMA_CHANNEL_0;! j; Z5 V. N0 l0 v$ E
  22.     ADC1DMA_Handler.Init.Direction = DMA_PERIPH_TO_MEMORY;
    ' S- M% ]0 ]7 F+ I3 X
  23.     ADC1DMA_Handler.Init.PeriphInc = DMA_PINC_DISABLE;               //外设非增量模式
    ( J6 }6 t. m& J- S0 b
  24.     ADC1DMA_Handler.Init.MemInc = DMA_MINC_ENABLE;                   //存储器增量模式3 Q$ q4 g9 I5 b+ i  H
  25.     ADC1DMA_Handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;  //外设数据长度:16位4 O' ^* U8 h6 Q5 h. ^5 ]
  26.     ADC1DMA_Handler.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;     //存储器数据长度:16位+ X& |: d7 C3 N. W
  27.     ADC1DMA_Handler.Init.Mode = DMA_CIRCULAR;                          //传输一次就结束
    1 l" V1 P8 V# `/ \, n
  28.     ADC1DMA_Handler.Init.Priority = DMA_PRIORITY_LOW;             //中等优先级
    $ P) h2 ~6 g; E
  29.     ADC1DMA_Handler.Init.FIFOMode = DMA_FIFOMODE_DISABLE;            /* 禁止FIFO*/
    8 U& |0 x2 `% ~/ k6 z4 p: j
  30. % j; r/ p! C) O: @; `% n# a6 ^
  31.     HAL_DMA_Init(&ADC1DMA_Handler);$ d' s7 ?- h& j( u) O( t
  32. / q" A% W; ~+ R" y( K/ n6 K* }; f  `, Z
  33.     __HAL_LINKDMA(&ADC1_Handler, DMA_Handle, ADC1DMA_Handler);                //将DMA与ADC联系起来
    9 U; q$ }# L- Y+ c8 j+ G

  34. ( u) p# m( Z8 Z8 P0 h. D& l4 y0 y; y

  35. ! k( \! E" }  A5 g& R
  36.     ADC1_Handler.Instance = ADC1;
    : A! f; I4 a: p- D# H! A6 l  ?
  37.     ADC1_Handler.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; //4分频,ADCCLK=PCLK2/4=108/4=27MHZ; g  O" E5 t3 U7 P* C/ S
  38.     ADC1_Handler.Init.Resolution = ADC_RESOLUTION_12B;           //12位模式
    # [) i/ U5 _* H1 {4 j7 V2 Z
  39.     ADC1_Handler.Init.ScanConvMode = ENABLE;                    //非扫描模式
    ( i( v0 v5 k& v: [' r( |
  40.     ADC1_Handler.Init.ContinuousConvMode = ENABLE;              //关闭连续转换
    5 F$ W1 E. [) o+ H+ i9 N' [
  41.     ADC1_Handler.Init.DiscontinuousConvMode = DISABLE;           //禁止不连续采样模式
    1 g( l+ a" c& h9 R' @
  42.     ADC1_Handler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //使用软件触发
    0 d# f3 G/ Q# D& o1 C  p
  43.     ADC1_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START;     //软件触发
    + A8 d9 P1 s3 U2 D2 n) p
  44.     ADC1_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT;           //右对齐; ^. Z; z, \& @4 W
  45.     ADC1_Handler.Init.NbrOfConversion = 2;                       //1个转换在规则序列中 也就是只转换规则序列1* A( Z6 A6 r8 l( n  {
  46.     ADC1_Handler.Init.DMAContinuousRequests = ENABLE;           //关闭DMA请求) j. Y1 l* G0 U$ w" M6 C
  47.     ADC1_Handler.Init.EOCSelection = ADC_EOC_SINGLE_CONV;        
    7 a$ C2 ~4 C0 G2 e) h& f
  48.     HAL_ADC_Init(&ADC1_Handler);
    * Q2 k9 g3 d" B% f3 t" [
  49. 4 q4 L$ c1 ^9 N9 N/ `
  50.     ADC1_ChanConf.Channel = ADC_CHANNEL_5;                                 //通道7 r; A) _. d% g9 }. U8 }, h
  51.     ADC1_ChanConf.Rank = 1;                                     //序列1
    1 {5 l# v# d7 e# X9 |
  52.     ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES;      //采样时间
    + o" N' L" O, H4 ?- }. |$ h
  53.     ADC1_ChanConf.Offset = 0;
    ; `% q% Q3 Q+ K" Y6 z
  54.     HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf);       //通道配置5 o3 m1 o: N4 p& v$ R' u

  55. : z0 M& I$ T/ j  j  z) z1 `
  56.     ADC1_ChanConf.Channel = ADC_CHANNEL_6;                                 //通道
    5 J- E/ D! A5 h' Z+ h
  57.     ADC1_ChanConf.Rank = 2;                                     //序列2( O' P4 Z6 ?$ y4 O) c- v
  58.     ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES;      //采样时间
    : \6 [( @# R% X+ j% V  S* k
  59.     ADC1_ChanConf.Offset = 0;& B3 l' P# ^0 T, y6 h* d% A
  60.     HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf);       //通道配置
    ( e1 K8 A: ], z$ H5 ^

  61. 6 |+ r  u1 a* [0 H5 X* p4 \# ?, m
  62.                 HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)buffer, 100);
    / P! @" {, h; }: S
  63. }
    6 L+ {& _) V5 c7 L4 k
  64. 8 j5 x/ h) A# Q6 F* K6 S, i
  65. //ADC底层驱动,引脚配置,时钟使能4 A) U2 A& @7 p* E1 {7 Z
  66. //此函数会被HAL_ADC_Init()调用
    ' R3 Y! r% q5 p6 G1 R9 d8 P  E
  67. //hadc:ADC句柄
    0 X. W# o: j6 _
  68. void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)/ W9 E+ ]3 I1 S; {
  69. {
    . A  T5 e! \0 O- m: V2 p1 _" l9 L
  70.     GPIO_InitTypeDef GPIO_Initure;
    # E8 C5 ]- r- j  H, A# F) k. w+ H/ h
  71.     __HAL_RCC_ADC1_CLK_ENABLE();            //使能ADC1时钟
    ) v/ c/ l+ S- I( H# ]9 F; ~! V
  72.     __HAL_RCC_GPIOA_CLK_ENABLE();           //开启GPIOA时钟
      p! |; z& W  O7 U

  73. # I# y/ D4 E0 a8 g1 b
  74.     GPIO_Initure.Pin = GPIO_PIN_5|GPIO_PIN_6;          //PA5  V3 I) c' ~: r+ e  D8 x
  75.     GPIO_Initure.Mode = GPIO_MODE_ANALOG;   //模拟
    2 L0 [# B" i5 P& y0 h
  76.     GPIO_Initure.Pull = GPIO_NOPULL;        //不带上下拉: g. j( F+ L& G* @2 r
  77.     HAL_GPIO_Init(GPIOA, &GPIO_Initure);
    " h1 z+ ]: c0 ]. V2 F, c% \
  78. }8 `4 G% [6 `2 c3 g" H

  79. % E8 f. h$ j1 w, R5 r" Z/ n
  80. void DMA2_Stream0_IRQHandler(void)
    $ a7 q' M$ F% G1 v5 y. W
  81. {
    ) Q( ~0 N8 X( n3 q' G4 {
  82.     HAL_DMA_IRQHandler(&ADC1DMA_Handler);& I: k  v, A% D; P: F% {5 ~
  83. }1 h& u' E: w" M
  84. 6 y. O4 }5 z6 t( F
  85. void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)+ d- E6 F) x! [/ {6 y' H
  86. {7 A, H  l3 G; l/ v* m
  87.         printf("DMA transfer complete\r\n");- d( s2 U7 F5 ^5 ~2 j
  88. }
    & U4 Y7 q/ W1 M9 F3 b
  89. void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc)
    * D1 X- L  c+ ?- i
  90. {; {6 |, B7 t4 Z( F0 `& `5 U6 h" E1 J
  91.         printf("DMA Half transfer complete\r\n");3 D" T, K6 t* k7 u$ n) ?0 j2 L
  92. }
    : ?. x4 V* `* l. n; X
  93. " A( u% I5 `* f9 i; z
  94. void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc)/ r$ [7 L$ l: S) M* T% h
  95. {
    ( g2 A9 |! H; z6 Z; n8 X0 e, _
  96.         printf("DMA transfer error\r\n");' g9 _5 M. R  s  Z5 ^  N4 c  W
  97. }+ [6 d$ c2 V* k' e( X
复制代码
  1. #include "sys.h"$ I/ ~" i6 ]3 v
  2. #include "delay.h"
    0 m& U9 n% A+ f, A) [  z, Q% n1 N
  3. #include "usart.h"
    8 |/ l9 i4 s! w+ y( O& P
  4. ( ]8 l0 d8 G; U3 W& W! u
  5. #include "adc.h"8 T; c$ C1 e, h  S( d* q6 |) l+ g3 _" X
  6. 6 ^* h- I8 _* R$ {1 R
  7. extern uint16_t buffer[128];
    / [- }8 v) q1 a' ^+ P
  8. " C  s1 I  z4 I1 u
  9. void show()
    : U5 W/ t2 t* u" f, s( l" e2 H" p' g
  10. {
    , @% {1 u( }- A; V3 W. y/ P7 {
  11.     int i;
    5 Q% p9 k7 |* o% z! O
  12.     printf("\r\ndata:");
    $ _+ F1 B1 ~5 ^& y
  13.     for (i = 0; i < 128; i++)
    / k, ?3 V0 t) K, B4 G5 M3 i* K" y6 m3 l
  14.     {
    : \2 T4 _- t! a% W
  15.         if (i % 16 == 0) printf("\r\n");. l  j' t, O6 Q4 H6 t2 f
  16.         printf("%6d", buffer[i]);0 U# S- w* J8 F
  17.                         buffer[i]=0;
    % t2 I3 N( |2 M; K+ Z+ N+ e# g

  18. : C5 c$ a& P3 I- c3 q
  19.     }2 y: ?5 W* P2 Q6 C- o" i
  20.     printf("\r\n");
    / b, C5 m  W' T- C2 @0 F& I
  21. }
    + C  q0 E. C, \8 x
  22. 7 }0 W3 T" K, S

  23. ! B4 W+ E* U; l* p% q1 r1 L
  24. int main(void)
      f$ s1 Q) j& g4 k+ Z% M
  25. {
    ) b9 I2 c6 Z, @; R, Y# M
  26.     //Cache_Enable();                 //打开L1-Cache
    % g9 i3 b; t: [+ i" B3 S* }
  27.     HAL_Init();                     //初始化HAL库& D! H9 [8 e( ~# |# A! d7 }
  28.     Stm32_Clock_Init(432, 8, 2, 9); //设置时钟,216Mhz
    ) d, c' q- }* X
  29.     delay_init(216);                //延时初始化
    % \& q1 l% [$ \5 b0 j" d# @! ~
  30.     uart_init(115200);              //串口初始化7 U0 C! o. C; ?( j  n

  31. / j5 O: h( D; H! r7 ~) g# Z
  32.     printf("start\r\n");
    ' K- [+ F& R" I
  33.     MY_ADC_Init();                  //初始化ADC1通道5& x$ I/ g- u/ h7 Z4 u8 Y' m  M4 O
  34.    
    & ~. n: U( v7 U
  35.     while (1)" Z8 P, b: A8 h& e( p7 h
  36.     {
    + M4 R! w  L7 I' Y' _
  37.         show();5 J5 U4 z7 X. m! [( K
  38.         delay_ms(1000);, X' @1 Z4 Z( C0 L1 i4 p$ |
  39.     }1 P& ]! H% S4 c4 t2 e2 E
  40. }
复制代码

7 @- g7 Q% E7 P————————————————7 f& `) E: z3 O$ C& ?3 _
版权声明:小盼你最萌哒- r; M9 R: V3 W; K) R
如有侵权请联系删除
1 A! X0 {9 R2 Z+ B, B; |
) u8 E* u. I9 ?+ S4 D
收藏 评论0 发布时间:2023-3-14 11:26

举报

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