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

基于STM32G4芯片的DAC应用示例

[复制链接]
STMCU小助手 发布时间:2021-9-13 12:47
有人使用STM32G431芯片做DAC应用,具体来说就是通过DMA将数据从指定内存传送给DAC数据寄存器,并由定时器触发DAC转换。他发现总是没法实现该功能。这里简单介绍下相关实现过程,并做些提醒。这里要演示的基本功能就是让DAM将内存数据周期性传输给DAC数据寄存器,最后输出一路正弦波。
" T% I" ^0 f* o$ E, ]
13.png
* o2 B* u" {2 i0 K% I5 y8 Z3 w
结合STM32G4芯片的特性,这里可以有两种实现方式。
2 V4 _% a: \7 \4 V/ J
5 o0 @9 a5 H$ W  H; K2 f% S
+ k9 \/ l0 G$ u- f* @3 f
第一种,DMA的请求来自于DAC1的转换事件。第二种,DMA的请求来自于定时器事件,下面用到的是定时器的更新事件。这里就两种实现方式的配置及相关用户代码简单介绍下,以供参考。
/ q4 U4 k  Y% H6 O# v/ y' B5 q$ r5 D5 e, R! K
我们先看第一种方式,即DMA请求来自DAC转换事件,定时器3触发DAC的转换。, T, J& h, @# G6 R5 X# }. G
使用CubeMx进行配置,主要配置如下:; {0 l. n$ \6 Q# b* ^' Q  w! M, Q
14.png

5 b" Z9 @9 d5 ^% X
4.png

7 ?: G8 g. c4 R( C) [0 t
15.png

5 |* S' Z5 t* q, b- q8 }- c完成配置后生成初始代码,再添加下面代码即可验证测试:% b- B9 b9 G2 s. ?. y, ?
  1. #define   Tpai     (2*3.14159)
    4 u3 b, v) J! ^9 s! {* F
  2. uint32_t  PData[200],Dac_data;% E: d+ h0 T! ~; [( D0 [
  3. uint16_t     i;
    , `6 h4 a: p. Z& ~) j
  4. for (i=0;i<200;i++)
    0 E1 A% c" F) j; E8 Y
  5. {
    ; p  o& |! I2 R- t
  6. PData[i]=& D; x+ ?9 T- y' v& b2 ^9 t
  7. (uint32_t ) (2000*(sin((Tpai/200)*i))+2000);9 `) a3 T% p3 M
  8. } //prepare data for DAC
    + a: m" ^/ l. H; F
  9. HAL_DAC_Start_DMA(&hdac1,DAC_CHANNEL_1,(uint32_t*)&PData[0],  200,DAC_ALIGN_12B_R);
    $ B$ B8 Y% K/ \; h* E& P
  10. __HAL_TIM_ENABLE(&htim3);
复制代码
上面配置的DMA传输方向是从内存到外设,目的和源的访问宽度都是32位WORD. 当然也可以是内存访问宽度为16位的半字,外设访问宽度为32位字。即DMA的配置像下面这样也是可以的。( c% n  X( T1 d# \' b3 b
16.png
- ~8 C6 w, e6 r; ]% X
其它配置不动,代码稍微改动和整理下即可。参见下面代码:
% c( @( z. O" u$ R/ q3 L9 b  P" x0 R: `0 d2 u/ ]2 k
  1. Uint16_t  PData[200],Dac_data;
    : L- \9 c8 w/ x" y7 B, g

  2.   ~0 {# Y1 x6 e+ K9 k1 U
  3. #define   Tpai (2*3.14159)
      F, X$ I* j" A. A( I4 I) v& i

  4. % v/ u7 p, m7 u( K
  5. uint16_t     i;1 K& D! ]( K6 _; [
  6. & ~% Q, M! Y$ l2 ?: G
  7. for (i=0;i<200;i++)
    5 p5 a0 w/ C' W+ `  w& F
  8. ! s- {  S6 X& C/ Y! N) d
  9. {% ~0 O0 U- z- M9 d' l
  10.   d# ]6 ~, I% d* W: ~
  11. PData[i]=
    2 m5 d9 u3 O+ S# k2 {! G

  12. . j) a) G! u& k
  13. (uint16_t )(2000*(sin((Tpai/200)*i))+2000);, v) \' j3 z! s$ M' D& P0 i
  14. - c! T9 _2 G2 o3 ]) `
  15. } //prepare data for DAC
    ! P2 \7 `& e4 {3 Z
  16. + A$ ]' I! X  E4 ?1 G' }, Y' R
  17. SET_BIT(hdac1.Instance->CR,DAC_CR_DMAEN1);1 S# t, q/ x. B) g8 h
  18. 0 n5 W* c# R$ w* L0 S) }
  19. HAL_DAC_Start(&hdac1,DAC_CHANNEL_1 );
    8 N' n1 s' u& Y

  20. 2 {- _# E2 u9 k7 I! [. ~' c, {
  21. HAL_Delay(2);# C+ _( _& j0 k  T4 I4 ?0 {
  22. 9 C3 P0 X5 i8 T; q7 @( q
  23. HAL_DMA_Start_IT(&hdma_dac1_ch1,(uint32_t)&PData[0],(uint32_t)&DAC1->DHR12R1, 200);
    ' I2 R) l& f+ U/ x5 h1 f

  24. 1 g2 s: _2 @2 o9 C* [
  25. __HAL_TIM_ENABLE(&htim3);
复制代码
第一种方式就介绍到这里,再来看看第二种实现方式,即TIMER更新事件作为DMA请求源,同时作为DAC转换触发源。  M, U& ~& G. f
2 R* U) q7 k7 o; Q
基于CubeMx配置,主要调整下DMA配置,其它配置基本不动。
7 i" V" V2 k9 w8 g
17.png
, ]1 I! I* [" i0 d: h
主要是DMA请求事件变了,其它配置跟第一种模式基本一样。, \7 c2 O  d1 H6 U9 h4 B

4 ~  `) u2 b5 f5 r! t8 O

" B2 P  c+ r9 l* @配置完成后生成初始化代码,再添加下面用户代码:
) t2 g3 [; J0 ^4 r4 z2 s
3 F2 ]* n' I% B
  1. #define   Tpai     (2*3.14159)
    ( }- b5 S; G' g) }$ F; G" g3 @
  2. 1 I3 F7 b* R- d1 P5 n' \
  3. uint16_t PData[200], Dac_data;# G* a, E* B& Q/ \9 I8 w( W
  4. , ?# O+ v! v" ?: M# l' f2 }
  5. uint16_t     i;, C9 y/ E* u2 Y4 W: m. H2 |
  6. 3 R0 T9 x: r0 e
  7. / K. X) O/ k( A0 ]# q- X5 m  Y$ ?
  8.   J9 u  @0 {" q5 E. x  A
  9. for (i=0;i<200;i++)1 h1 c; y/ j& I8 E0 x1 U3 f
  10. $ |2 m# b  i8 I$ V
  11. {
    % l6 h" w! P+ k7 y: a" P& R/ q- `$ H
  12. 6 K3 I- Q. k2 U
  13. PData[i]=
    ; k' R8 C1 C9 Q" _: H/ w

  14. / h+ L8 k$ S/ `) |. U" a0 V$ M
  15. (uint16_t )(2000*(sin((Tpai/200)*i))+2000);/ ~/ f& ?+ Z1 Q  H! `% E( m
  16. # X" y# U2 `, \" O4 n' E3 z" A
  17. }" r) ]8 Q4 E/ Z

  18. ; u) O+ L/ x- F+ e# O" z) g" M
  19. HAL_DAC_Start(&hdac1,DAC_CHANNEL_1 );
    ! L8 R9 k; k) q+ C2 S( f. w/ f3 n, j, M

  20. # V( n# q# v# a3 y# G
  21. HAL_Delay(3);
    1 O) {( f& D( y  m) {

  22. " |7 e( i1 u0 h( j
  23. 3 Z* @8 `8 j% q
  24. " ]9 u. h4 n+ J+ ?- \  s. @
  25. HAL_DMA_Start(&hdma_tim3_up,(uint32_t)&PData[0],(uint32_t)&DAC1->DHR12R1, 200);: D1 d. v4 h4 ]( e* B  r* F  q8 @
  26. 8 b' _+ S) Z9 p% u: o/ a0 O
  27. : l6 ~+ l* {$ V, Y$ C0 @: q

  28. & i$ V6 M1 l5 T% b0 z
  29. __HAL_TIM_ENABLE_DMA(&htim3, TIM_DMA_UPDATE);
    ) d, A1 M" P/ E6 z5 Q8 n1 o4 q
  30. 8 b( r* h/ U4 q: p2 i7 j- \, X; ~
  31. __HAL_TIM_ENABLE(&htim3);
复制代码
) n9 @& \1 e* L- B3 Y& I" Y5 D
这里要提醒一点,G4系列的DAC1的数据保持寄存器可以一次放2个通道的数据,在使用DMA传输时,即使只用到1个通道,DMA对它的访问也要遵循WORD对齐,不然你可能会遇到麻烦。
* m# s  J7 J. y# H# V" m! S6 E
$ p3 i$ f6 [6 c8 L) S+ R如果说,我们不使用DMA做数据传输,只是手动给DAC喂数据,那如何实现上述效果呢?这时我们可以使用软件触发DAC的传输,手动给DAC的数据保持寄存器赋值,参考配置及实现代码如下:( H0 @& v' ?5 ~

3 _. w/ S* D( S$ V. q& [
18.png

0 G1 Z- x' k! \$ L- M# p( G相关用户代码如下:
' g" E- A3 k+ {/ j0 ?0 T. t; }4 M" m/ m5 C; ^# G
  1. #define   Tpai (2*3.14159)
    & v0 W) B$ F' S/ c- T3 n

  2. 9 e9 ]8 k. ]2 t% g' s4 M
  3. uint16_t PData[200],Dac_data;
    7 r5 C( O" x2 m* R
  4. , B2 z& [, j" C+ f! t
  5. uint16_t     i;2 s- b# H6 E# i5 ^" h
  6. 5 n, F- w4 D4 o' M3 r0 B

  7. - W' j: d0 j( \

  8. , F" d* z3 F0 E- P/ ^/ Z  X2 ?( t9 \
  9. for (i=0;i<200;i++)
    , a/ @5 @( S0 ~! }
  10. 5 z! j- }8 p- k* }
  11. {
    2 A  M7 t# R! x9 Y

  12. 0 \- v, R% i; \
  13. PData[i]=# m' _% [  G8 e" ]* U2 w5 T% x

  14. $ O) _( r+ m1 i4 W% m9 e. s# L) d! [$ M
  15. (uint16_t)(2000*(sin((Tpai/200)*i))+2000);
    5 x& g' M6 b( K; l) d3 T' m& `

  16. # T# ]3 `- ]* q3 o1 o, I
  17. }
    0 h8 G5 z! {# w# A8 ?+ ~
  18. 6 g  L9 U9 r$ h  [
  19. HAL_DAC_Start(&hdac1,DAC_CHANNEL_1 );9 w  x+ M* ~/ g9 b5 t* n

  20. , v! y2 o+ h1 o' h% c5 z
  21.    HAL_Delay(3);' u! p. U5 j9 R9 R7 Q# M' A# h1 R

  22. 5 J7 R; E3 s% t) @+ k

  23. 9 b: Q* h5 z1 `/ S  J7 n/ L

  24. 3 j5 v  g; O2 m" q3 o* u2 G. z: r
  25. while(1)1 _$ v" s: [6 |0 @/ Q, j

  26. & p2 D" O: J/ D* E, p3 z% Q1 S# I
  27. {
    & Z9 U: E/ d6 z+ J  ]# ?0 n# Q

  28. / A  o2 }& ?  c0 K  X4 ?
  29. for(i=0;i<200;i++)
    ( j' D. u+ m- E0 X. K& r& I4 B+ C

  30. 5 F' n3 X* D3 X  y+ F3 H
  31. {( d( G* H) C) @4 A9 A/ F0 K" }

  32. : N" C# }+ k5 H( I4 Z2 `6 \
  33. DAC1->DHR12R1= PData[i]; 7 {+ v6 ]# A8 g( k
  34. 7 d7 V- M- [3 E: b
  35. SET_BIT(hdac1.Instance->SWTRIGR,DAC_SWTRIGR_SWTRIG1);8 V' z6 C, p. }5 P
  36. : B  T& o4 z4 H' ^' {) K
  37.       HAL_Delay(5);
    * A3 a" ?( P: g% e: |4 Y
  38. : ]* u( v6 G9 N$ V" s  C
  39. Dac_data = DAC1->DOR1;//for debug" m( C  W8 G! ~$ C$ @# W/ k
  40. % S) [/ ^( O# q" F  z/ s* G& q
  41. } ' M0 _6 p" n* ~4 d( B" l- r
  42. $ p- U: M/ n" X. y' p! G/ ^! p
  43. }
复制代码
总之,不论使用哪种方式,都可以实现我们所期望的结果,即输出如下正弦波。$ o2 X9 O3 \; Q+ a, t3 `8 [
19.png

3 b3 `) l- E( c+ P" n好,关于STM32G4的DAC应用就简单介绍到这里,STM32G4系列的模拟外设丰富而强大,此处算是抛砖引玉。这里做些分享也是为了让其他有需要的人少走弯路,加速开发进程。【文中代码都很简短、直观,就没做注释说明了。还有个客观原因就是在微信公众号里排版也很费劲,字符不太好对齐。若有需要交流的可以后台留言。】
5 n' `* J' t( {  K8 D, w% h0 e
% {6 Y( I! \! P+ e2 F/ v9 t5 V9 f0 d

$ s1 _; J* C! G2 k9 S2 S0 A: B
赞 收藏 评论0 发布时间:2021-9-13 12:47

举报

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