EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
f5 Q; q& Q/ h( ]: b$ t: Y
1.介绍2 m0 |* x7 Y( j- U3 k+ j
GD32L233C采用的是一款M23的内核。这个芯片据说功耗非常的低,低到什么程度呢?等后面我们再进行测试,今天我们主要来测试GD32L233C-START的DAC,既然要测试DAC,示波器是不可少的,这个实验在家做,然而LZ家里并没有示波器,不过最近看到一款好东西,LOTO虚拟示波器,看过这款示波器的参数,还不错。所以入手了一款,测量芯片输出的DAC应该没什么问题,接下来开始测试吧。5 d. S& N& N6 D, j/ x; e# L
2.设计
, |- g) D+ d" O2 T$ U6 Z, g首先需要输出让芯片输出DAC,而且还需要输出波形,这个稍微费点功夫,之前在GD32L233C-START移植了RTThread,现在在这个代码的基础上添加DAC的输出程序,这个程序移植了其他网友的,代码我也贴出来,经过测试,代码没有啥问题:
+ Y: Q% `7 C6 d' P比较麻烦的是正弦波的代码: const float sinus_I_quarter[91] =
5 S/ M4 U7 V& f{
2 z# ~, j0 D- o- b3 j 0.0000, 0.0175, 0.0349, 0.0523, 0.0698, 0.0872, 0.1045, 0.1219, 0.1392, 0.1564, // 00 .. 09) j! i6 l4 [) t( c* `" b$ ~
0.1736, 0.1908, 0.2079, 0.2250, 0.2419, 0.2588, 0.2756, 0.2924, 0.3090, 0.3256, // 10 .. 19, p& H0 S9 b) \8 y6 _
0.3420, 0.3584, 0.3746, 0.3907, 0.4067, 0.4226, 0.4384, 0.4540, 0.4695, 0.4848, // 20 .. 29$ l6 i- v# `- q+ F& y+ }
0.5000, 0.5150, 0.5299, 0.5446, 0.5592, 0.5736, 0.5878, 0.6018, 0.6157, 0.6293, // 30 .. 391 J, @( `( p5 x( C
0.6428, 0.6561, 0.6691, 0.6820, 0.6947, 0.7071, 0.7193, 0.7314, 0.7431, 0.7547, // 40 .. 49# o5 A% s# M$ ]% |# s
0.7660, 0.7771, 0.7880, 0.7986, 0.8090, 0.8192, 0.8290, 0.8387, 0.8480, 0.8572, // 50 .. 597 l0 U3 q1 i8 g) L. ^# J6 `; V/ }
0.8660, 0.8746, 0.8829, 0.8910, 0.8988, 0.9063, 0.9135, 0.9205, 0.9272, 0.9336, // 60 .. 69
4 R7 i4 d3 h! }+ o" a 0.9397, 0.9455, 0.9511, 0.9563, 0.9613, 0.9659, 0.9703, 0.9744, 0.9781, 0.9816, // 70 .. 79& @4 M9 ? t W" F2 Y
0.9848, 0.9877, 0.9903, 0.9925, 0.9945, 0.9962, 0.9976, 0.9986, 0.9994, 0.9998, // 80 .. 89
2 M3 T( f ~- x6 ? A8 S" O- ^ 1.0000 // 90( Y( `* F4 k7 ?7 T
};9 {6 C0 c% h; p7 ~* f; i" y+ f
( h+ [4 t% s" R7 N9 w
#define CIRCLE_QUARTER_1 13 j! m0 S9 S/ d' I
#define CIRCLE_QUARTER_2 2' C6 }) I% F0 ?3 Y) V/ c i
#define CIRCLE_QUARTER_3 30 v: L: y8 h( b0 v" e
#define CIRCLE_QUARTER_4 4
: |3 v( `8 O* A* `/ x5 }% \float sinus_lookup (unsigned int angle)3 z9 L! m# o J5 n: T
{3 y+ d C# q' a; w0 {6 E
float sin_value;
- V& T2 O$ q2 V" T" ?* l unsigned int circle_quarter;. y) r7 S3 H$ t0 z9 M3 S
// correct angles outside the accepted angle range into 0 .. 359
6 R2 b, W2 q9 y. X& k4 x if (angle > 359u)
2 E: u- Z* T3 f; E angle = angle % 360u;
7 u% j( I `# Y1 A' I circle_quarter = 1 + (angle / 90u);, B6 e: U' Z. [8 A+ }' b
switch (circle_quarter)+ \2 M, b4 V( ^/ [
{
5 b2 t7 M* N3 u: c$ t( `5 N case CIRCLE_QUARTER_1: // 00 .. 89# S7 ^$ M/ G9 z" U3 D
sin_value = sinus_I_quarter[angle];
; g+ X# a! e0 {9 B' V break;/ E5 }+ q* n) G' w
case CIRCLE_QUARTER_2: // 90 .. 179
5 K" F+ l' G! ]+ ` sin_value = sinus_I_quarter[180 - angle];
/ l! Z( {! E2 o+ @: p0 T( {! g, j7 s break;
) H! U2 ?& s2 H8 I7 r1 L1 ^ case CIRCLE_QUARTER_3: // 180 .. 269
2 e' Y* i& K$ a& v4 R+ q sin_value = -sinus_I_quarter[angle - 180];% {. l: H y, p2 h1 G1 D) M
break;
& {/ ~; \% O2 x3 m& [% a( F% H& |! j case CIRCLE_QUARTER_4: // 270 .. 359
1 \+ Z- B5 `/ U5 S- x0 C2 } { sin_value = -sinus_I_quarter[360 - angle];
& M1 |; X* A3 r8 @1 c( Z$ C' s6 ^ break;
8 j/ u; n$ b6 u2 U k' l, b5 T }, F, f- k# |4 ~' W! ]
return sin_value; q7 W3 v; p* N
} k2 ?) D( A/ e8 ^; u6 B3 ^+ d
0 I/ u; D; F+ s
void plot_sin(uint32_t f, uint32_t delta_f)
; N3 \$ n( i8 D{
3 L8 \: X* N% j: k) y N /* 定时周期为T=1/delta_f, f=1/(pMax*T) */
5 S- U6 I$ K, l5 P6 j" Q& u3 n) _ static uint32_t point = 0;3 n- X+ B# A4 q" {# t
uint32_t pMAX = delta_f/f;$ U* c1 n# E4 A
uint32_t value = 0;+ N2 p) J8 Y! V+ G
if (point++ > pMAX) point = 0; 2 R1 r3 J( s0 v+ j A( k- n% k
value = (uint32_t)((sinus_lookup(360*point/pMAX)+1)*10000)*2047/10000;
" A* b" [+ K) C U. _ dac_software_trigger_enable();1 E$ _ L$ H3 L0 M. S# x
dac_data_set(DAC_ALIGN_12B_R, value);7 a4 L# |6 Q. J
} 接下来是锯齿波和方波的代码,这两个代码比较简单: void plot_triangle(uint32_t f, uint32_t delta_f)( ]! |% @7 M7 @# f3 t/ I7 E( g
{
; p& Y2 X, r# E# c7 u; S /* 定时周期为T=1/delta_f, f=1/(pMax*T) */( Y9 K5 b' w+ k$ N7 y2 Q, b. J6 U
static uint32_t point = 0;6 w2 n& @4 @* }- [9 l* u: Y* o
uint32_t pMAX = delta_f/f;
, g5 a# @3 R8 X3 b" b, I uint32_t pMAX2 = pMAX/2;
$ c/ G3 T- B4 `' v( j# w( z uint32_t value = 0;. s+ x' l1 g- J& [( z4 H2 _1 |
if (++point > pMAX) point = 0;
+ g, ]2 S- O+ T1 T if (point < pMAX2)
& C, V3 o0 j: f8 w+ r2 ] {
7 z1 C R1 d" N value = point * 4095 / pMAX2;
3 H$ \" f/ \$ i5 l }
+ d8 f4 l( r2 ?7 w9 f7 M, ]. Q else b, S* S. w9 [0 M' M. w! v
{
$ A/ _8 _, C2 |5 T( j' M1 i+ \ value = (pMAX - point) * 4095 / pMAX2;
9 N3 D9 H9 v, i) C4 E2 |3 X4 g }
+ @7 ?4 ?" }1 K- i; v8 A dac_software_trigger_enable();
4 t3 ~1 s+ i. ]3 S dac_data_set(DAC_ALIGN_12B_R, value);
S% O9 ?, x! o0 H9 c}
7 u9 T- z- X. x/ wvoid plot_square(uint32_t f, uint32_t delta_f)
. N8 @" @# m. n/ o{
! `/ k5 y8 H: C% e, y% d( M8 a9 h /* 定时周期为T=1/delta_f, f=1/(pMax*T) */) v% E8 g, \' c L. K
static uint32_t point = 0;
5 d; U b7 ?- Y/ Z% r& u uint32_t pMAX = delta_f/f;9 `* D5 H5 Z8 Y, l8 A
uint32_t pMAX2 = pMAX/2;! `% \* ?% i$ O$ {5 w, r
uint32_t value = 0;
9 t0 G! w. a; R( [1 e, G$ F7 K. I1 D if (++point > pMAX) point = 0;3 n( V! e: J7 ~. ~2 `2 Q
if (point < pMAX2); p& F; l/ B, u, f! x
{
. P7 T/ R2 }( _# W# U- q: n value = 0;/ x& r" z$ j! J e
}
+ `/ X4 _( C$ b3 p8 M* O else1 T1 b# s, }7 ]" ?1 b
{
, X* t. ~& v$ i+ j value = 0xFFF;& y3 a$ Y) U$ _3 s" L# ~
}: N. |9 T9 V# ]8 }
dac_software_trigger_enable();
5 ]8 @1 [, t. i dac_data_set(DAC_ALIGN_12B_R, value);. `! h9 A6 M: i7 V& g+ P- p
} 最后需要开启一个定时器,还有DAC的初始化: void timerx_init(uint32_t timer_periph, uint16_t period, uint16_t prescaler)
+ W$ r; r6 I( D5 h7 X* g% {8 K{6 p- M# C" v) F6 T8 r
/* TIMER1 configuration: input capture mode -------------------: N: E8 @/ J! x' D$ g8 n- V# u
the external signal is connected to TIMER1 CH0 pin (PA0)1 K7 J8 u6 N& z
the rising edge is used as active edge
; A- R3 E1 L* c7 [. r1 q) L% r" f the TIMER1 CH0CV is used to compute the frequency value
( R$ c/ p: w$ i' b7 P2 O+ }0 A ------------------------------------------------------------ */
6 c, g% e w: h timer_parameter_struct timer_initpara;
2 Q' e9 p7 Q1 {& Q timer_ic_parameter_struct timer_icinitpara;
% R4 H$ p0 C% i U! j- D& o% q$ \* H( m e* F# R
/* enable the peripherals clock */9 i* N: e9 o& u
rcu_periph_clock_enable(RCU_TIMER2);
- ~- \0 u I# Z) S2 s& z7 j' O) G
- ~1 o4 S+ `- H/ s /* deinit a TIMER */0 {; Y& A' ?- h" y3 d. _
timer_deinit(timer_periph);( l& P& Y2 n) @% x6 u
/* initialize TIMER init parameter struct */# Z5 x* w& A, k2 s$ l
timer_struct_para_init(&timer_initpara); a; m1 N9 v& {; B* D
/* TIMER1 configuration */
) S0 w, }$ V" M e timer_initpara.prescaler = prescaler;' W2 C& i4 [. X. `1 E
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;6 e1 u: c9 ]2 u8 d% s$ b
timer_initpara.counterdirection = TIMER_COUNTER_UP;* i/ W K; }( ]* P9 n
timer_initpara.period = period;
# C: x$ Q- e- U' N% } timer_initpara.clockdivision = TIMER_CKDIV_DIV1;' B% d1 ^0 _% s0 j
timer_init(timer_periph, &timer_initpara);4 m1 ^1 y" X: S2 p$ f8 u
/ o( ]6 o/ ^1 `. I; \1 Y
/* TIMER1 CH0 input capture configuration */
6 p0 r6 L) Y6 H1 V9 J timer_icinitpara.icpolarity = TIMER_IC_POLARITY_RISING;. V) r- @% h; q( h& i7 Z2 V2 L* f
timer_icinitpara.icselection = TIMER_IC_SELECTION_DIRECTTI;$ L m5 v9 f& E1 N6 O3 [
timer_icinitpara.icprescaler = TIMER_IC_PSC_DIV1;0 L9 o, B% a4 `3 E+ B3 j/ W7 K8 ~
timer_icinitpara.icfilter = 0x00;
, G) X3 o0 N" h4 b# @$ v. X: @ timer_input_capture_config(timer_periph, TIMER_CH_0, &timer_icinitpara);
* S7 b1 S4 _, T# P/ F3 p+ s/ v) N" U
/* auto-reload preload enable */
% b- k* H& Q8 F' i: O timer_auto_reload_shadow_enable(timer_periph);7 L4 A3 s, ]. E) G- \
/* clear channel 0 interrupt bit */3 h# H @; @/ _
timer_interrupt_flag_clear(timer_periph, TIMER_INT_CH0);3 X' i1 y* P+ \( ~0 F( [5 d
/* channel 0 interrupt enable */
9 ~" w: {: ]: j, `0 S; W' E3 n2 q# c/ g timer_interrupt_enable(timer_periph, TIMER_INT_CH0);* o# t/ _+ a, F" A% w2 H( |4 Y
5 O6 g2 Q& I; C8 @* w" W% l /* enable a TIMER */ w" _& \: v# Q# n
timer_enable(timer_periph);
" W' z7 s7 ]* y0 q}
' @0 y) k+ z4 i1 R+ x" d) F
' X8 K0 w- n9 W$ W& u6 p4 S+ M#define DAC_WAVE_TEST
* l5 z; d& f& o0 F9 P9 N& o) V& _# x( h' m# E* \2 R. E
void timer2_init(void): F" X2 V [$ v4 U: s, _5 G+ `, k/ T
{
) X. ]. O7 L/ ?, {) e" i, x timer_deinit(TIMER2);
0 x5 z8 T! X! e" S7 S/ [; B rcu_periph_clock_enable(RCU_TIMER2);
( A4 [/ J& r& N1 _" Q#ifdef DAC_WAVE_TEST
2 I/ h" u6 W& W timerx_init(TIMER2, 639, 9); // 100KHz 0.1ms5 H5 U! [; Z a7 Z' D
#endif
8 e# K% H2 F+ f3 L$ m timer_interrupt_enable(TIMER2, TIMER_INT_UP);1 a [5 Q8 E; _4 E/ p. z3 q- }/ |& Y
nvic_irq_enable(TIMER2_IRQn, 3);& f+ a B+ p9 E6 S2 {
} D. m2 j; m& D% j1 C
- O8 v; t# H+ B( F6 Nvoid TIMER2_IRQHandler(void), n' G4 P4 U/ M5 G2 E
{
- ~* ~. A* F6 |#ifdef DAC_WAVE_TEST0 X! Y4 m) I- \9 m
plot_sin(100, 10000); //正弦波
% w+ N3 y8 o, K' y! H- O' ?/ l //plot_triangle(1, 10000); //锯齿波3 i4 k! R4 p) q. [
//plot_square(1, 10000); //方波* `% [7 K: K* W6 U
#endif
( h! T: r' ?' f4 F3 o. u7 U timer_interrupt_flag_clear(TIMER2, TIMER_INT_FLAG_UP);' A( h( ]: o8 U! k
}3 h8 V4 ^& ]$ w& k& C/ ]- J
; F; R1 f- H; z7 F& S( m; V4 V
void dac1_init(void)* J" q8 H# T; o6 H
{, Y; n9 A- q/ S& \/ i( B
rcu_periph_clock_enable(RCU_GPIOA);
$ r7 J" G1 J# i3 @$ {+ E rcu_periph_clock_enable(RCU_DAC);
! I* \9 r; [+ N$ n5 h3 [( H% b gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_4);2 ~( V9 t; Q+ C1 H' x- e, T
dac_deinit();
7 T% d2 Q% _/ K3 _5 y /* software trigger */
+ |; K1 J; L# b+ R" \4 j dac_trigger_enable();2 s. w# [, w* t# }; V
dac_trigger_source_config(DAC_TRIGGER_SOFTWARE);
$ q, i7 b* T1 f1 V( e /* no noise wave */! _1 O$ ?( e4 c! @# O9 M( S# l
dac_wave_mode_config(DAC_WAVE_DISABLE);/ f$ Z5 M; d: P% R: c" k
/* noise wave - triangle */
; ~" y7 w W, ^5 i5 { //dac_wave_mode_config(DAC_WAVE_MODE_TRIANGLE);$ |" i% a5 S/ ?* y3 X$ R& q, `; g
//dac_triangle_noise_config(DAC_TRIANGLE_AMPLITUDE_4095);9 ^" q( e3 k, U0 p
/* noise wave - lfsr */$ t k, f Q0 Z
//dac_wave_mode_config(DAC_WAVE_MODE_LFSR);
) J d: P5 g, f5 E! h: ]2 L //dac_lfsr_noise_config(DAC_LFSR_BITS11_0);
* ^) ?$ d$ t) T+ G+ h dac_output_buffer_enable();
5 V! _, |% h4 e2 v/ ] /* enable DAC and set data */' E6 W, A1 W$ Y2 f9 o& u: [! o
dac_enable();
+ r: l; S, ^* M+ R2 p$ [, z( b dac_software_trigger_enable();
9 C! G4 D$ Z5 r" f+ R1 y dac_data_set(DAC_ALIGN_12B_R, 0);9 S* ^: b: q% Z- h+ D
} 这样就可以输出正弦波、锯齿波和方波了。
2 ~& {! }* u7 q" Q, ~* D8 F' B3.波形测量
. L: O8 p: X0 s: ]/ B. l7 e接下来我们来看一下输出的波形是否符合要求,首先需要将【GD32L233C-START】开发板连接LOTO示波器,分别连接GND和PA4管教,连接效果图如下图1所示。 图1
) c% e; C: W' S7 m! s) r- {然后让DAC输出正弦波,看一下波形如何。
图2 " [0 y+ R; k5 j2 v; r; x
从上图2中可以看到,一个周期大约在10ms,所以正弦波的周期为100Hz,输出还是听精准的。/ I+ P+ P4 k7 z2 Q+ A% v- ^
然后输出锯齿波看看波形如何。 图3 3 z3 Z3 D* [# R. [: K8 T
从上图3可以得出,锯齿波的波形频率为1Hz。
/ F- ` M2 Q2 Q# r最后我们来看看方波的波形图如何。 图4
2 O: I% V/ V# A2 M; ?: i从上图4可以看到,方波的波形频率为1Hz。
% Z& f* f9 P! I3 f从上面波形可以得出,【GD32L233C-START】的定时器比较精准,DAC的输出值也比较稳定,性能还是不错的!
2 u* A# m7 \7 o6 k3 I/ h4.总结
) P1 p# @' L/ `刚入手的LOTO示波器还不错,测量的精度挺高的,不过还有好多设置没弄明白,等后续多琢磨琢磨。做电子的示波器是必不可少的,我先替你们测试测试这个示波器如何。) }# `4 ?6 ^% [* \+ ^+ [2 V
GD32L233C是新出来的芯片,整体功能还需要多进行测试,它最突出的低功耗后续要好好测量一下,这次就先到这里了。
|