EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
% t* f) `3 Q* C: R( u% |) U
1.介绍
! ~- x5 d: ]8 k0 YGD32L233C采用的是一款M23的内核。这个芯片据说功耗非常的低,低到什么程度呢?等后面我们再进行测试,今天我们主要来测试GD32L233C-START的DAC,既然要测试DAC,示波器是不可少的,这个实验在家做,然而LZ家里并没有示波器,不过最近看到一款好东西,LOTO虚拟示波器,看过这款示波器的参数,还不错。所以入手了一款,测量芯片输出的DAC应该没什么问题,接下来开始测试吧。
: ~# r! A; ]/ E# n4 Z0 a2.设计
& J6 |$ _5 x5 a- r/ G* U; X首先需要输出让芯片输出DAC,而且还需要输出波形,这个稍微费点功夫,之前在GD32L233C-START移植了RTThread,现在在这个代码的基础上添加DAC的输出程序,这个程序移植了其他网友的,代码我也贴出来,经过测试,代码没有啥问题:% V* m* D& r% d6 x, a5 ]
比较麻烦的是正弦波的代码: const float sinus_I_quarter[91] =
- z, U9 u F# a! V{
. i1 V# n l' J& ^8 j; S( x 0.0000, 0.0175, 0.0349, 0.0523, 0.0698, 0.0872, 0.1045, 0.1219, 0.1392, 0.1564, // 00 .. 09; n, T$ G0 D4 n
0.1736, 0.1908, 0.2079, 0.2250, 0.2419, 0.2588, 0.2756, 0.2924, 0.3090, 0.3256, // 10 .. 19. X9 S' \, m% O) d( M
0.3420, 0.3584, 0.3746, 0.3907, 0.4067, 0.4226, 0.4384, 0.4540, 0.4695, 0.4848, // 20 .. 29
; {# F* y; M4 r% _* G: L, f 0.5000, 0.5150, 0.5299, 0.5446, 0.5592, 0.5736, 0.5878, 0.6018, 0.6157, 0.6293, // 30 .. 398 i. @( K3 f: s' f
0.6428, 0.6561, 0.6691, 0.6820, 0.6947, 0.7071, 0.7193, 0.7314, 0.7431, 0.7547, // 40 .. 49
( i6 |6 k0 o+ [/ ?& c$ X 0.7660, 0.7771, 0.7880, 0.7986, 0.8090, 0.8192, 0.8290, 0.8387, 0.8480, 0.8572, // 50 .. 59* J3 u. O1 K5 J* L; l& c
0.8660, 0.8746, 0.8829, 0.8910, 0.8988, 0.9063, 0.9135, 0.9205, 0.9272, 0.9336, // 60 .. 69! j8 ?7 \# k- K6 w% Y, q
0.9397, 0.9455, 0.9511, 0.9563, 0.9613, 0.9659, 0.9703, 0.9744, 0.9781, 0.9816, // 70 .. 798 _# Y% i& j. r% z
0.9848, 0.9877, 0.9903, 0.9925, 0.9945, 0.9962, 0.9976, 0.9986, 0.9994, 0.9998, // 80 .. 89
7 Y! ~' `, v# x) h$ q% d2 W3 _- f 1.0000 // 90
$ e; I8 Y1 z1 Y" H};6 q+ L* n9 K! ?& X/ L
% g- T0 P. D# g, [#define CIRCLE_QUARTER_1 1
! W" R& P5 }% Z/ o6 y#define CIRCLE_QUARTER_2 2
# P( c( F9 Q8 f$ T- }0 C, l7 I#define CIRCLE_QUARTER_3 35 b; q8 C3 W$ n4 ^% u" U
#define CIRCLE_QUARTER_4 4# A+ o7 d8 g# r$ C I
float sinus_lookup (unsigned int angle)
. c; a( N J" a" N' ^{/ x7 @/ d+ B; y* g5 Z
float sin_value;9 K) i0 c0 `9 C8 w" ]/ l/ L
unsigned int circle_quarter;9 I/ h5 Q1 I, Z
// correct angles outside the accepted angle range into 0 .. 359
+ H8 C8 h$ ^. j; @! r* M/ t" a if (angle > 359u)5 u3 z% N3 h/ ^' A
angle = angle % 360u;
0 g) ?( v1 h% O' W# a# V0 b circle_quarter = 1 + (angle / 90u);4 A. {6 u7 {8 ~) A2 J) k1 {
switch (circle_quarter) I9 W8 o+ n; G+ g- j
{
0 G$ d+ X7 a9 @. }3 A$ T' S case CIRCLE_QUARTER_1: // 00 .. 89
# K9 x! `+ {4 y; } sin_value = sinus_I_quarter[angle];6 m0 O Z6 W! J! i
break;; d1 ?) v% J+ B9 W* t
case CIRCLE_QUARTER_2: // 90 .. 179
9 D: K# Z/ g; m V6 z sin_value = sinus_I_quarter[180 - angle];
' Q2 y% t/ N- v+ _' i! a break;) c; M* ^3 I) W7 T, y+ U
case CIRCLE_QUARTER_3: // 180 .. 269 b. [! ~% w$ m
sin_value = -sinus_I_quarter[angle - 180];
' _4 m- t' _, u& C; F" x break;* c8 B( h- l+ D7 T/ _
case CIRCLE_QUARTER_4: // 270 .. 3591 p- h- K" P7 _. {
sin_value = -sinus_I_quarter[360 - angle];
s$ j" g0 ~, N6 x* g: X/ z9 [( }) A break;7 v: H& j: O' j: ]+ M0 K
}
# W7 s8 D1 ^$ s4 R& K# E9 c6 w h return sin_value;8 a) f" G( L& @; ]6 z& m5 o
}
7 G! p H v* h2 b1 G
, w9 P% B5 i9 u6 j5 cvoid plot_sin(uint32_t f, uint32_t delta_f)% l q) ]) h, p9 c# a# r
{
: j1 G a: @2 l1 Z* Y /* 定时周期为T=1/delta_f, f=1/(pMax*T) */ q* z. P5 n2 z8 P
static uint32_t point = 0;
' h* h+ W1 j" Y/ |5 S uint32_t pMAX = delta_f/f;
0 o% w7 U4 j- X$ { uint32_t value = 0;
6 B6 _; ^- c* w5 c% x if (point++ > pMAX) point = 0;
. ?+ |/ ~( A" w: A6 c value = (uint32_t)((sinus_lookup(360*point/pMAX)+1)*10000)*2047/10000;% H4 ?* p7 Y5 N% y+ W
dac_software_trigger_enable();
3 K0 }) z! z4 F$ J" F dac_data_set(DAC_ALIGN_12B_R, value);! p6 q2 A4 Q% X
} 接下来是锯齿波和方波的代码,这两个代码比较简单: void plot_triangle(uint32_t f, uint32_t delta_f)
% z, O- y: A3 H0 ~1 n{2 Q5 h" Q( f" }' ]9 B2 i
/* 定时周期为T=1/delta_f, f=1/(pMax*T) */- W8 t. O& ?8 V0 f# G
static uint32_t point = 0;
# x" Q7 S$ V; i% p6 c7 V5 r c/ f1 ]+ | uint32_t pMAX = delta_f/f;/ M, P0 q/ V, q' Q* Q2 w
uint32_t pMAX2 = pMAX/2;
+ ?% v2 }4 q" ~9 l( t) I! a uint32_t value = 0;
+ y$ m" g q$ f0 p7 ]1 Z5 G' b# Y if (++point > pMAX) point = 0;
" l0 I# p7 Y# F" c1 q8 G! u& j% ` if (point < pMAX2)
3 s/ s( l8 F7 j {+ _% Z3 p: a/ V6 w8 y# x" T/ F
value = point * 4095 / pMAX2;' h3 `" Y" H$ L+ N S5 G
}
, M* [' T' @) z else% a, {/ L( c' _ T: |! T$ t' |
{
1 u" s+ O% w/ u/ i: A9 B3 _ value = (pMAX - point) * 4095 / pMAX2;
9 {4 b# i' x+ H3 W: Y" b8 V3 z }
4 \; q9 P( F2 d dac_software_trigger_enable();" M2 ^; ]$ r7 a- M* R
dac_data_set(DAC_ALIGN_12B_R, value);
( M/ p& C- Z1 [5 h: K! r}+ n3 P% t$ w4 Z$ _" `
void plot_square(uint32_t f, uint32_t delta_f)
# R& K! y* B" |; L# C{2 K$ E" g1 L/ s$ z5 p# j9 p, L
/* 定时周期为T=1/delta_f, f=1/(pMax*T) */9 J% b; j0 H" |! f7 t: w6 s
static uint32_t point = 0;3 v; ?9 \& ^- E+ n: h: Z
uint32_t pMAX = delta_f/f;
8 ~: g6 A, ^! E9 U& b uint32_t pMAX2 = pMAX/2;+ q$ {' X9 q: D) V! x
uint32_t value = 0;- a, l8 G5 _8 u
if (++point > pMAX) point = 0;
) ]3 n$ \) T8 {; f if (point < pMAX2)
3 y( C) x/ g$ B$ V {+ P6 Q' @. {+ N2 J; C6 \2 x
value = 0;0 Q M9 ~! u+ u
}6 O$ j+ T( Q3 ~! O# R+ z
else
, e7 M0 m0 ]# O+ U, F+ |7 p) J {; ]) D$ q2 C. u' R( O6 K6 \/ c
value = 0xFFF;4 n B1 J/ [" e0 Y
}( V& ^- H: k+ x9 g! ~& c" |4 h4 H* ]2 _
dac_software_trigger_enable();# J2 Z/ [/ `$ P* d) r
dac_data_set(DAC_ALIGN_12B_R, value);
/ `4 d# Q- p& ~7 c2 {+ e* F2 @} 最后需要开启一个定时器,还有DAC的初始化: void timerx_init(uint32_t timer_periph, uint16_t period, uint16_t prescaler)
' N, s6 |6 j6 M{$ w h: z$ _, J$ h% X
/* TIMER1 configuration: input capture mode -------------------2 p1 K# X/ d9 b/ z' D# s
the external signal is connected to TIMER1 CH0 pin (PA0)
! z Q& s7 w/ M* i+ d0 Y* q the rising edge is used as active edge
3 B+ l. C5 k- A the TIMER1 CH0CV is used to compute the frequency value3 W* v- o8 O8 ^8 ~1 O L1 d
------------------------------------------------------------ */
0 o3 c8 W) I" f7 m, J, ?7 I timer_parameter_struct timer_initpara;
( U6 J8 \$ f% j$ B timer_ic_parameter_struct timer_icinitpara;% `. e/ H5 E9 F9 e0 X* L! b' G
. Z$ e, s$ K1 o6 T2 e
/* enable the peripherals clock */0 }2 d% B& l* m }( M, z+ x
rcu_periph_clock_enable(RCU_TIMER2);/ w" ^" t* E3 y, ~
3 }7 |! P% y9 \. P3 H1 p& Z
/* deinit a TIMER */
. I0 ^$ c6 @6 j+ r. y5 Z timer_deinit(timer_periph);. w' m" k E$ `8 ~& C( M4 f7 y
/* initialize TIMER init parameter struct */
: J/ I! N; {: @ j timer_struct_para_init(&timer_initpara);
6 R& Q% f- @+ @7 f+ I9 ~ /* TIMER1 configuration */
9 F- |- j- A: S, i timer_initpara.prescaler = prescaler;( ]# f. p& ~0 Q! L0 }
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
: L) _5 F( y V6 T7 k& K1 @7 N timer_initpara.counterdirection = TIMER_COUNTER_UP; f; N/ @3 T* O$ g/ ?+ f, ~
timer_initpara.period = period;: V! K0 d7 N, x; C% `2 A
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
" h) q& {5 V) c H+ Q3 M0 n+ [1 } | timer_init(timer_periph, &timer_initpara);
# j& m+ b% C% d. \3 p
# x, S2 m6 ~: v( y /* TIMER1 CH0 input capture configuration */, F( w9 a0 o+ q' P6 u' B- W" U
timer_icinitpara.icpolarity = TIMER_IC_POLARITY_RISING;( l" T6 ?0 C0 N3 ^3 L: N9 ^& l6 p
timer_icinitpara.icselection = TIMER_IC_SELECTION_DIRECTTI;0 L$ U" E/ r; |" e# g- N
timer_icinitpara.icprescaler = TIMER_IC_PSC_DIV1;) ~2 R+ i- i7 Z' z
timer_icinitpara.icfilter = 0x00;* s7 X6 p! v t1 d; l8 X- b3 ]! r
timer_input_capture_config(timer_periph, TIMER_CH_0, &timer_icinitpara);
, B+ M( Y: Q1 e4 o+ z, Y; j) i7 H! x# B {+ s$ t9 a2 ]( Q
/* auto-reload preload enable */
7 l G; d) ~' c1 _: n# d timer_auto_reload_shadow_enable(timer_periph);
) x+ e' n/ a/ T! D7 t /* clear channel 0 interrupt bit */6 x+ l5 A1 p2 T! R
timer_interrupt_flag_clear(timer_periph, TIMER_INT_CH0);* L$ _, Y& a' K
/* channel 0 interrupt enable */1 B) r/ e% f! H$ Q+ j9 ]% f+ s7 O
timer_interrupt_enable(timer_periph, TIMER_INT_CH0);
6 q4 H$ h5 @* q" ^# _3 o+ O
. ?6 ^0 l6 j8 C3 P- K; f$ A: q /* enable a TIMER */( F! h: n3 D- J- r
timer_enable(timer_periph);
6 Y) B& b6 |# w" a3 f6 x0 K}- ^. c! p$ Z. _* g/ c
8 g" E% B3 m- l* {, W# z' q#define DAC_WAVE_TEST2 O7 C& q7 o3 r
- m# s" I H7 D0 }2 E. p
void timer2_init(void)/ _5 S! _: p2 m4 I1 @
{) v( Y. F3 N/ y0 p9 _6 t( w+ R
timer_deinit(TIMER2);
, M. S8 D$ X, _* e# \ rcu_periph_clock_enable(RCU_TIMER2);& e* N! j5 G: w# t+ _
#ifdef DAC_WAVE_TEST
8 v( ]& C$ d1 q( `" I- ~4 p& F) X" K8 M timerx_init(TIMER2, 639, 9); // 100KHz 0.1ms V' o! D. |# o7 n, ?& E
#endif: ^$ w5 n b3 \- k$ o) K2 L! [
timer_interrupt_enable(TIMER2, TIMER_INT_UP);0 T# n( |- {& v2 c
nvic_irq_enable(TIMER2_IRQn, 3);
7 W. a- [$ w7 N}& f9 z, m8 R8 o0 S
! e* j9 T" f3 S* Q# q
void TIMER2_IRQHandler(void)
4 M7 L1 O* x5 u+ {{
5 v+ T1 c1 u: Y/ D5 h5 A#ifdef DAC_WAVE_TEST
. g4 x& p: a5 [- w" g7 w plot_sin(100, 10000); //正弦波) U: K$ y7 F4 U# w! m: s
//plot_triangle(1, 10000); //锯齿波
( y! S# G8 s9 G) c6 f! r2 E //plot_square(1, 10000); //方波
* }8 i$ ?8 p& b0 {1 V0 e#endif) ~/ x* O; v; h/ s
timer_interrupt_flag_clear(TIMER2, TIMER_INT_FLAG_UP); t# I4 _0 i* K
}6 {! I: w0 V: _' L$ A) b$ k
& S+ D; u9 W9 Q$ _ Wvoid dac1_init(void); `$ i8 s% L/ Q! [7 C
{' J. P# P9 L/ C) M
rcu_periph_clock_enable(RCU_GPIOA);
; N o' h1 q4 p9 ^1 \4 V rcu_periph_clock_enable(RCU_DAC);4 K. C2 v2 K( n4 m7 P
gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_4);
+ l. E: @$ a" L' b dac_deinit();4 g6 a" I" o* F$ x0 i- B
/* software trigger */! i6 \: }8 Y6 t: Q3 h
dac_trigger_enable();
! G1 _! A5 ~% A9 m0 d9 p dac_trigger_source_config(DAC_TRIGGER_SOFTWARE);: V& ~2 M0 {" ]: F% p6 G9 {. w3 S7 h+ h
/* no noise wave */9 G) F+ t% B: S3 K6 |' u. J
dac_wave_mode_config(DAC_WAVE_DISABLE);
4 t3 R( o+ C2 X /* noise wave - triangle */: M+ X7 U% y! C7 D. K j7 \/ S+ n9 H
//dac_wave_mode_config(DAC_WAVE_MODE_TRIANGLE);
# f) h: o$ }5 T. r1 I //dac_triangle_noise_config(DAC_TRIANGLE_AMPLITUDE_4095);3 y3 x' ~2 c! P: f8 j6 v
/* noise wave - lfsr */
- ]( z q3 r6 {1 J7 F //dac_wave_mode_config(DAC_WAVE_MODE_LFSR);( M: q0 i7 _# x7 T Z& J9 [
//dac_lfsr_noise_config(DAC_LFSR_BITS11_0);% {0 p' i1 _( ]" O" N3 v
dac_output_buffer_enable();/ `3 E4 t* i" j& d- ]! N
/* enable DAC and set data */
# O2 }" E5 U' Q- v. o. \ dac_enable();
! c. e" `$ b, E; G5 U5 ~ dac_software_trigger_enable();
/ C) x. U2 `$ [4 V8 d dac_data_set(DAC_ALIGN_12B_R, 0);
6 N" ?8 e9 r9 @ H+ `} 这样就可以输出正弦波、锯齿波和方波了。
# y# y! U: `; S- l3.波形测量
# x! [/ M! v5 b' z接下来我们来看一下输出的波形是否符合要求,首先需要将【GD32L233C-START】开发板连接LOTO示波器,分别连接GND和PA4管教,连接效果图如下图1所示。 图1 3 R- }5 \) c e$ [4 |7 ?
然后让DAC输出正弦波,看一下波形如何。 图2
" X0 A" b8 x) D+ t从上图2中可以看到,一个周期大约在10ms,所以正弦波的周期为100Hz,输出还是听精准的。
9 A0 n% y7 ^% v& C+ H4 n然后输出锯齿波看看波形如何。
图3
% v. h; b6 j- p* y从上图3可以得出,锯齿波的波形频率为1Hz。: r P1 B& ^3 Q" K1 o
最后我们来看看方波的波形图如何。
图4
+ G* Q. B& p1 a$ g" F从上图4可以看到,方波的波形频率为1Hz。- b9 s% w0 _( @9 N: S' r; d# d
从上面波形可以得出,【GD32L233C-START】的定时器比较精准,DAC的输出值也比较稳定,性能还是不错的!
# H+ C! I$ H5 J6 R) R4.总结: ~ C+ D9 W7 q& c: h# Y @3 `1 j& g
刚入手的LOTO示波器还不错,测量的精度挺高的,不过还有好多设置没弄明白,等后续多琢磨琢磨。做电子的示波器是必不可少的,我先替你们测试测试这个示波器如何。
' _( F* z1 U( _GD32L233C是新出来的芯片,整体功能还需要多进行测试,它最突出的低功耗后续要好好测量一下,这次就先到这里了。
|