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

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

[复制链接]
STMCU小助手 发布时间:2021-12-15 11:00
ADC1DMA_Handler.Init.Mode
0 a0 y$ q7 c( ^% Q$ SDMA的正常模式(DMA_NORMAL):采集到DMA_BufferSize 的个数后,DMA停止。
* v, N0 g$ v  K/ t) `DMA的循环模式(DMA_CIRCULAR):采集到DMA_BufferSize 的个数后,重新回到设置的RAM的起点位置,如此循环。3 d9 T( L2 @- i" e3 ^
虽然道理很好理解,但个人感觉要配合触发信号来用,通过HAL_ADC_Start_DMA软件触发需要设置起点位置和长度,否则这个参数是没有意义的。
+ `) R; P9 N$ _9 S) F: C+ F6 [* m7 v3 o- g% d  S+ F& V2 b
ADC1_Handler.Init.ScanConvMode
+ D# \# K" z& g0 l  @: D2 u. z5 h扫描模式(ENABLE):ADC会依次扫描设置的各个rank
: x1 I, ~) u# L' k! `非扫描模式(DISABLE):ADC只会读取rank1,即使设置的DMA_BufferSize大于2,也只会读取第一个;如果没设置rank1(此时我的设置里rank2接的3V3,rank3接的gnd),读出来的结果是516这种奇怪的东西,我也不知道是个什么鬼东西……) H  ^- g/ U) U/ E4 l
即使需要只读取rank1的值,把NbrOfConversion不就可以了嘛~
% f; r- G8 S9 {* I5 p+ F- V所以这个参数我建议设置成ENABLE,我也不知道什么时候该用DISABLE。* B7 p& `7 h8 _* I4 i/ H, N
/ Z9 K9 }% C- w  C7 M7 w' z4 I# w
ADC1_Handler.Init.ContinuousConvMode, |, H6 w  _( ?. z2 w
开启连续转换:开启了连续转换后,adc会一直转换,直到DMA_BufferSize大小,如图是HAL_ADC_Start_DMA 64个长度的结果。
( d; u& b+ m3 m) r# \3 F- u( V- `9 s# }" X
20200419192759329.png

; c2 T" c# j( d; }, v而不开启连续转换,长度为64的同时,DMA的传输中断都不会进。6 ]( i* _2 M; f0 X. f5 v1 S
20200419192936345.png
3 @5 U. q2 O5 ^' U7 R* O
9 x/ J5 t2 [# Q' {+ I3 P3 h* B$ ^
而将传输长度设置为3的时候,就进入了传输完成过半的中断。: p$ B3 V, f2 l: N3 M2 {+ }

& W+ Y/ H+ a7 C/ l& f1 V/ F6 ^& d
20200419194129548.png
9 ^7 U0 D7 J; \4 e1 h/ i9 ?! I
  t. ?: ^8 K+ k* _# H) E1 }1 ^
如果我们需要采集连续的N个次结果求平均值,用这个连续转换会很方便。
- k1 Z( z& W: D! H! _+ k" }7 a, Y也从侧面说明,dma的传输中断是一定要有那么长的真实采集数据来才能进的。. f) w. q! f2 N

' _' x4 }' |7 u9 o3 T" y在另外一篇里看到了这么一个表格,希望能够辅助大家理解:* b9 c9 x9 a; }* l4 @
: V6 h2 y% K+ X' b+ q; A3 \# R1 `8 g
20200421214739891.png

1 @  `' ^# }) i7 [( ]7 ?4 i  w
' {: m! W( a  a, [0 {! b( PADC1_Handler.Init.DMAContinuousRequests1 n2 {5 g4 Y0 d, H3 H% E
当设置了定时器触发DMA之后,这个参数如果设置为DISABLE,就只会采集一轮数据,然后结束。# G: w& u$ v/ L' M
这个数据设置成了ENABLE之后,这个参数设置为ENABLE,一轮采集完成之后,感觉就会自动调用一次HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)buffer, 100);,触发DMA请求,以实现不停采集。& Q/ @! I# j' R) |1 _

1 A( v6 o% ?( }' U但是需要注意,如果开启了连续转换,又开启了DMA连续请求,adc将一直进行采集,一刻也不停歇……
3 U0 i3 T2 X, Q, d0 L; s% ^' b( ]" a  J4 m6 n/ g; q
ADC1_Handler.Init.EOCSelection
3 o% B8 ?, B: ~4 TEOC听说是转换结束标志,这里暂时也没用到,也先埋一个坑……' |. B7 V  t# Y/ w1 V
填坑STM32F7实现ADC等周期采集(定时器触发+DMA传输)采集完成后的中断设置% N$ d& A5 N3 `
& d. a) y" E9 r7 |
偶然看到一个帖子的回复:( x( r# L$ Y9 L  c% v5 z7 _& u
当有CPU和其它主设备【如DMA】共同访问某可缓存的二级存储器比方SRAM1,同时该存储器又具有回写属性,此时就可能发生数据一致性问题。因为该存储器的回写属性,导致通过CPU欲写入存储器的数据只是缓冲在CACHE里,而没有及时写入存储器。如果此时DMA访问该二级存储器的话,读到的数据可能跟预期不一致。) V5 c" k. o4 f8 B" X
为了避免数据不一致的问题,我们需要做D-CACHE维护操作。一般有如下四种方法: 1、当对一个可缓存的二级存储器做了写数据操作之后,通过软件对D-CACHE进行清除操作,即运行SCB_CleanDCache()。这样将CACHE里的缓存内容写回到二级存储器,比如把那些DIRTY' q+ X2 H  U* S  U$ q. V
CACHE行的数据写进SRAM1。- I0 o5 D  t3 y  @
2、通过MPU调整可缓存存储器的存储属性,将其CACHE使用方式改为透写模式。这样保证每次写入CACHE里的内容也同时写入二级存储器,比如写进SRAM1。# N8 n1 Q! ~- b7 x6 j2 C' V! r
3、通过MPU调整可缓存存储器的存储属性,将其共享属性改为可共享的【SHAREABLE】。此后该二级存储器将变为不可缓存。
! P9 N+ s4 q! [5 y6 B- u9 H! D4、通过配置CACR寄存器中的D-CACHE位,强制将所有写操作配置为透写属性。
/ d  e. f; @9 g' o5 G7 t) j+ {0 Q+ E: Y+ `& q8 w& a1 x: A
在main函数中关闭cache,DMA采集的数据就可以更新了。/ }2 n. i& L6 g) h5 I, u

" t, l/ {8 C8 B6 M8 [# V
20200419215859139.png
4 s+ f) j; B/ Q& z: L4 Q9 Q
- t7 l; `  T6 p7 d, c: {9 q
附上成功时候的配置,注释掉HAL_NVIC_EnableIRQ是因为中断服务函数里的打印会导致main函数无法继续执行。
; |8 D8 L! ]! x
: o- V( B5 k  S) g! {  \9 T- V3 d. b
  1. #include "adc.h"
      n8 T( I( Q; f. m% J
  2. #include "delay.h"
    # @5 H* T& k2 W- ^, ~

  3. * Q+ i6 k! {" n: U; K3 S. g
  4. ADC_HandleTypeDef ADC1_Handler;//ADC句柄1 ^. W1 p5 j) ^  A( [( a6 p
  5. DMA_HandleTypeDef ADC1DMA_Handler;
    % r3 ]3 @& ]4 {! N, u# o$ v# ^, ^
  6. ADC_ChannelConfTypeDef ADC1_ChanConf;
    ! ~9 v2 y$ ~+ L# W
  7. ' K0 m+ O& M0 j. [: T0 J
  8. uint16_t buffer[128];
      ?; Q( o1 s0 s
  9. , p! i' X/ V3 G, o
  10. / m) s) _+ p* y. n9 P3 P0 `
  11. //初始化ADC
    , O: F8 v( t. {9 I
  12. //ch: ADC_channels' _; Y' k! \& }8 k; E5 W
  13. //通道值 0~16取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16
    3 N; v2 T6 e5 o2 m! K3 [0 s
  14. void MY_ADC_Init(void)$ \, V$ S4 L+ x% y: `/ V5 p. k
  15. {' F) d6 a+ i; ~
  16.     __HAL_RCC_DMA2_CLK_ENABLE();
    + Q8 o, t5 Z7 e7 e9 |
  17.     HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);( k9 H) Q3 S, x, [. q1 y4 U
  18.     //HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
    4 w! E! D7 M5 e
  19. 1 Y# ^4 s6 ]( ?
  20.     ADC1DMA_Handler.Instance = DMA2_Stream0;
    7 R- J8 `: g6 `# X. f7 u
  21.     ADC1DMA_Handler.Init.Channel = DMA_CHANNEL_0;! r. i% F+ o; I4 O, N7 q" ?! o4 x' R
  22.     ADC1DMA_Handler.Init.Direction = DMA_PERIPH_TO_MEMORY;
    / A: y9 [' U5 s
  23.     ADC1DMA_Handler.Init.PeriphInc = DMA_PINC_DISABLE;               //外设非增量模式
    1 {4 @+ x; Y: q0 h8 w6 [# f
  24.     ADC1DMA_Handler.Init.MemInc = DMA_MINC_ENABLE;                   //存储器增量模式
    ; G: i: @* \& |6 `8 t
  25.     ADC1DMA_Handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;  //外设数据长度:16位, M5 n. ^3 D: ?8 S6 R  t( @' A  v
  26.     ADC1DMA_Handler.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;     //存储器数据长度:16位8 x& @+ |3 n. i
  27.     ADC1DMA_Handler.Init.Mode = DMA_CIRCULAR;                          //传输一次就结束0 o, R. |4 q# P' D; i
  28.     ADC1DMA_Handler.Init.Priority = DMA_PRIORITY_LOW;             //中等优先级6 r/ V6 j: l8 `2 h8 C  h
  29.     ADC1DMA_Handler.Init.FIFOMode = DMA_FIFOMODE_DISABLE;            /* 禁止FIFO*/6 a0 e) G. h7 f2 T
  30. ; M: a4 f# h' o7 M
  31.     HAL_DMA_Init(&ADC1DMA_Handler);& J/ j/ d! ~8 @: s( A
  32. 4 S) `( d' `6 {
  33.     __HAL_LINKDMA(&ADC1_Handler, DMA_Handle, ADC1DMA_Handler);                //将DMA与ADC联系起来
    6 X  w% H# ?+ @

  34. 7 {: M$ \% U4 s; c3 u! G# T, j/ x$ a, Z
  35. ' U7 f' @5 w. S: S
  36.     ADC1_Handler.Instance = ADC1;
    ( E* T3 w. G7 h
  37.     ADC1_Handler.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; //4分频,ADCCLK=PCLK2/4=108/4=27MHZ
    4 I; M# B5 A& Y" }6 _- v1 d; o/ v
  38.     ADC1_Handler.Init.Resolution = ADC_RESOLUTION_12B;           //12位模式1 p; k% S9 }& F# J! w' P  R
  39.     ADC1_Handler.Init.ScanConvMode = ENABLE;                    //非扫描模式
    ; N& m7 \* t& ]) q0 p5 a0 V  |( `
  40.     ADC1_Handler.Init.ContinuousConvMode = ENABLE;              //关闭连续转换0 Q$ }" ~/ r$ ~' H7 a
  41.     ADC1_Handler.Init.DiscontinuousConvMode = DISABLE;           //禁止不连续采样模式1 l* n0 @9 m$ k3 T3 e( ?. _
  42.     ADC1_Handler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //使用软件触发
      s: k& x- S7 ~; B) C
  43.     ADC1_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START;     //软件触发5 P) c/ o9 v/ D' E/ A# y
  44.     ADC1_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT;           //右对齐/ j1 [8 s% v7 g: |
  45.     ADC1_Handler.Init.NbrOfConversion = 2;                       //1个转换在规则序列中 也就是只转换规则序列1; f) W% r' h, h; B* @, [+ w
  46.     ADC1_Handler.Init.DMAContinuousRequests = ENABLE;           //关闭DMA请求
    " Z, u) F5 ~) w% t
  47.     ADC1_Handler.Init.EOCSelection = ADC_EOC_SINGLE_CONV;        
    3 x8 N) o( g9 l9 S7 K
  48.     HAL_ADC_Init(&ADC1_Handler);
    # S5 D3 T5 n2 q
  49. $ `/ g) d( y7 k& \" ]0 p0 q
  50.     ADC1_ChanConf.Channel = ADC_CHANNEL_5;                                 //通道) ?: L6 r; w2 [) I% B
  51.     ADC1_ChanConf.Rank = 1;                                     //序列1) \* F9 }9 f% E( D. _, r  z8 k8 d
  52.     ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES;      //采样时间/ V7 z) l; g0 {3 k
  53.     ADC1_ChanConf.Offset = 0;
    1 Z6 U% ?9 S# o8 _6 l
  54.     HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf);       //通道配置2 j" }0 k* C; H9 y

  55. , c. M$ E3 {) I+ |) {
  56.     ADC1_ChanConf.Channel = ADC_CHANNEL_6;                                 //通道
    & Z( X2 ?% c8 z. w
  57.     ADC1_ChanConf.Rank = 2;                                     //序列2
    6 P( e% W( i  R
  58.     ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES;      //采样时间
    4 f0 M4 C. j7 A4 w* W9 w
  59.     ADC1_ChanConf.Offset = 0;+ T- h( Y9 a) x
  60.     HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf);       //通道配置
    1 Z4 M: Q5 |- D
  61. ( y( N" }7 L" R. {
  62.                 HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)buffer, 100);
      Z2 o0 O( W6 D5 J  N+ B
  63. }/ y; [" r; W' X2 e! }) M9 l  s- Z2 ?
  64. 5 E) b9 Q- T/ Z" g8 _
  65. //ADC底层驱动,引脚配置,时钟使能' S2 E. ^3 I$ ~/ R/ u# ~$ s6 d
  66. //此函数会被HAL_ADC_Init()调用- V( A/ n/ r6 t, b, i2 v
  67. //hadc:ADC句柄4 F' C$ ]& O" C8 o. m. K5 o
  68. void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)( a8 w# L3 P5 E1 X7 n0 R8 D6 h0 ?
  69. {
    ; z, b/ q6 `2 x9 ?
  70.     GPIO_InitTypeDef GPIO_Initure;- i2 a  ^9 y3 F8 S; b9 }
  71.     __HAL_RCC_ADC1_CLK_ENABLE();            //使能ADC1时钟
    8 h7 |8 I8 f8 ^$ T. F' P
  72.     __HAL_RCC_GPIOA_CLK_ENABLE();           //开启GPIOA时钟: }7 z7 }  I3 W5 l6 y

  73. 4 \- R5 J5 @8 o+ L  u
  74.     GPIO_Initure.Pin = GPIO_PIN_5|GPIO_PIN_6;          //PA5
    8 g* g% x# U! |7 i
  75.     GPIO_Initure.Mode = GPIO_MODE_ANALOG;   //模拟! j! `2 w  d6 P+ [
  76.     GPIO_Initure.Pull = GPIO_NOPULL;        //不带上下拉
    9 \# I, [9 G5 {1 _. ^
  77.     HAL_GPIO_Init(GPIOA, &GPIO_Initure);
    & U! i# x5 L. O' P# H
  78. }
    ) O5 ^0 w# Y( u  M8 H0 c% Q& ]

  79. 5 B/ D- J3 m4 r! Z/ i
  80. void DMA2_Stream0_IRQHandler(void)
    $ s) }3 M5 a. d" C
  81. {' [. A# n2 ?- R- K
  82.     HAL_DMA_IRQHandler(&ADC1DMA_Handler);* x' K+ R# a9 F
  83. }
    ( Q2 s+ ^1 f9 O2 ?' d
  84. 1 s5 K# y+ d( g& l2 K
  85. void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
    ; C/ u+ u$ m. }
  86. {, X  m  y0 \. j; y: H/ f' a
  87.         printf("DMA transfer complete\r\n");7 i$ N8 L" i; H' y: L" E
  88. }
    9 H) B& X& C  }/ m- K  t
  89. void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc)1 D2 ^& r8 i& T8 F0 _. |+ M
  90. {+ _3 X+ P% R8 U) s: A/ b' [
  91.         printf("DMA Half transfer complete\r\n");4 D& P, f7 s/ [- C$ k' Q2 Z5 I
  92. }+ q6 i# F' H! u

  93.   i# T: t: c0 i4 a" e) h! ~* {
  94. void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc)
    5 g# @0 a3 d  w" Y( t
  95. {
    1 A# D" J6 H! F9 I
  96.         printf("DMA transfer error\r\n");
    6 J8 d9 k$ N5 D! Z! b; V2 o( x
  97. }
复制代码
! P/ d( h# y* x. J4 L

8 j2 s; ]7 u0 S
  1. #include "sys.h"  ~" y  u% e; v& u
  2. #include "delay.h"
    ( d; T: d/ M8 A( M
  3. #include "usart.h"
    5 J7 a) d* O# ?. p& `% N, m& S

  4. % z) b4 `" S5 \) r; W$ B
  5. #include "adc.h"6 r; O/ b4 t4 D, |1 [
  6. / ^. H0 }5 q  V4 S* t3 g
  7. extern uint16_t buffer[128];/ A7 {6 V8 r& r& y7 D
  8. 5 `. {4 J* Z0 H4 S% g; x8 ~
  9. void show()* x( K; w' D) Q+ y- z
  10. {5 x' v5 l, l) r$ y3 Z
  11.     int i;( ]) e$ Q/ j$ P4 B) y5 t6 x
  12.     printf("\r\ndata:");7 X9 J3 e1 K5 v, r: g1 I! P6 `8 A* |. V
  13.     for (i = 0; i < 128; i++)/ @" s3 \6 K* H- S" G
  14.     {! I, e, z& Y& }+ v7 Q- L. w' q7 }
  15.         if (i % 16 == 0) printf("\r\n");2 |7 L% }) |- w( }5 |
  16.         printf("%6d", buffer);
    9 @, C' F2 X: r8 I
  17.                         buffer=0;
    9 S) z% I2 k: V3 N

  18. & S- W' v5 k( m5 v" J0 \4 F8 ~) \7 G
  19.     }+ O# q. Z9 b8 K
  20.     printf("\r\n");+ n& Q7 W9 V' ?& _6 c( U( R5 }
  21. }! c* Q$ |" r' e9 W

  22. : b+ ~4 m) @% [. C$ K0 u6 h* u

  23. 4 d" E( c$ O" Y  O9 p
  24. int main(void)
      h6 X$ {: l) ~% Z( n
  25. {2 G: [: ~. A0 I) |2 d
  26.     //Cache_Enable();                 //打开L1-Cache
    + p! @3 X+ B# U) W8 T; X4 J( `+ D
  27.     HAL_Init();                     //初始化HAL库0 E" c. G% w  \2 P. S7 D3 y# a8 G" `
  28.     Stm32_Clock_Init(432, 8, 2, 9); //设置时钟,216Mhz
    * \; Q" W" U3 M8 n; |
  29.     delay_init(216);                //延时初始化
    + d0 Y# ~3 V2 y  ]8 Y1 w/ u
  30.     uart_init(115200);              //串口初始化
    4 y. y7 ~/ e6 p% z

  31. , H  l+ a4 L( L- q# L! ]) {& H) K/ @
  32.     printf("start\r\n");5 z! x8 x& E2 {6 v& o7 O6 G* b" k; G
  33.     MY_ADC_Init();                  //初始化ADC1通道5/ g$ K$ C7 `9 B1 S, L* A
  34. 1 w" v( y3 A9 i2 x# ^7 q( Z2 j
  35.     while (1)
    5 R: K: N! |3 ?# o8 |, W
  36.     {; B1 O! {5 I: s
  37.         show();
    + n. |/ r/ r5 ?) ~6 T
  38.         delay_ms(1000);
    2 H% a% y/ p) ?" f/ Y2 k
  39.     }/ h+ T& x; T) C3 x- X
  40. }
复制代码

) I! D9 M$ }( I) o$ J6 a4 l: ~, p. r8 n/ r) ]& x9 |
收藏 评论0 发布时间:2021-12-15 11:00

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版