|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
转——基于ZX-2型FPGA开发板的串口示波器(三)
9 v0 p: n9 y) B: V+ }9 o! _: k) w 3 n# X: }8 b ~# f6 l8 q- E
( B9 `1 p7 e0 h8 Q
串口转memory mapped 总线与配置系统子模块寄存器代码分析; j0 u8 w& {+ \. H0 V1 L7 H$ H! Q
CMD
( g) v: g' K+ ^, j1 oCMD模块为串口数据帧接收与解析模块,该模块负责对串口接收到的每一帧的数据进行解码判断,并从数据帧中提取出地址字节和数据字节。最后将地址字节和数据字节转换为类似于Avalon-MM形式的总线,以实现对其它模块的控制寄存器的读写,从而实现通过串口控制FPGA中各个模块工作的目的。+ [ P# a. H+ b1 q
在工业应用中,串口指令大多以数据帧的格式出现,包含帧头、帧长、帧命令、帧内容、校验和以及帧尾,不会只是单纯的传输数据。在这个实验中,小梅哥也使用了数据帧的形式来通过上位机向FPGA发送命令,不过这里我使用的帧格式非常简单,帧格式以帧头、帧长、帧内容以及帧尾组成,忽略了校验部分内容,帧头、帧长以及帧尾内容都是固定的,不固定的只是帧内容,以下为小梅哥的设计中一帧数据的格式:
: ~5 H: k% A) M5 }% |5 Z; L- ]- ~8 v& G9 `% t/ G" J
2 L8 `8 A+ ` _) A" _; i& t( x3 i# {: q( w
帧头
4 L/ z$ v% M8 }- j/ Y4 p' Z% V+ j3 a |
$ J: [: D. ?* R% Y帧长
3 g* ?# G" f+ I$ B0 g% A |
1 v D( U' X% d; _2 d0 U. a地址6 v' R$ r4 F2 _7 }+ S
|
) U: F' u4 i) k" h, R* e数据
0 m4 i$ X I# U* l7 P |
9 ^9 N1 `1 A+ T, z- f数据' v/ s" [; q1 J
|
+ w; X" r1 E( D$ @ H& R; E帧尾3 c+ L# U) D& M' r
|
- f& H: ?4 D% p9 q( e0xAA
7 `5 p3 H- n, T" g6 F/ b' l: o# J* u |
, Y: R# x3 u, P6 K6 g0x03! a4 u. d" B. ^7 R& n6 }6 _
|
$ ?0 ?! B8 l: {6 s0xXX
" x6 w1 D1 F3 c/ T* q4 [. J) F2 v |
" f$ ~/ v H; j: O$ w: X0xXX
" w+ p/ P$ N$ m) X | % ]4 ?1 R# @+ w& Z* L0 b% Y+ T" F: x
0xXX
2 T' [; G- \9 \' p v4 Y | & ^) Y/ _8 B/ U' r6 H8 _4 t9 P. k
0x88% F$ _& r9 d( K2 G5 m- |
| 由于数据帧本身结构简单,因此数据帧的解析过程也相对简洁,以下为小梅哥的数据帧解析状态机设计,该状态机分为帧头解析、帧长解析、数据接收以及帧尾解析。默认时,状态机处于帧头解析状态,一旦出现帧头数据,则跳转到帧长接收状态,若下一个字节为帧长数据(这里严格意义上并不能算作帧长,因为长度固定,充其量只能算作帧头,读者不须过分纠结),则开始连续接收三个字节的数据,若非指定的帧长内容,则表明这是一次无关传输,状态机将返回到帧头解析状态继续等待新的数据帧到来。在帧尾解析状态,若解析到的数据并非指定的帧尾数据,则表明此次数据帧非有效帧,则将此帧已解析到的数据舍弃。若为帧尾数据,则解析成功,产生命令有效标志信号(CMD_Valid),Memory Mapped 总线进程在检测到此命令有效信号后,即产生写外设寄存器操作。3 ]8 ~8 w& Y7 J N/ b% i, p; [2 S
: Z0 R$ I) z+ T. h % S4 v3 K8 R* J1 |
. |' {0 }4 W( r$ R
命令解析的状态机实现代码如下所示:
/ N- R y3 J1 V3 E# I' E5 V& ^( \
1 K! n, k! v d; E9 g, e3 w% G017 localparam
1 T2 x# u) U3 M8 B1 y% l% U7 X0 W" `: H, ^ I: w
018 Header = 8'hAA, /*帧头*/
& `; Y W6 i# |9 s3 E; C
% P! ]0 h8 f) f019 Length = 8'd3, /*帧长*/
6 x0 u& \' a+ b' E P
- ]3 t' h. F8 Z' e' V$ ~3 _2 A* b020 Tail = 8'h88; /*帧尾*/5 p% E8 r6 h, K, }/ V4 p
& O# E4 E. j8 N3 y
021( |4 j! a" e3 C" v
# d6 C: ^. a- Y' Y, O+ J8 N o# d022 /*----------状态定义-----------------*/
- B0 G% S' t. y* S! I# u) E5 s, E3 O9 d& C; C
023 localparam
! K% Q3 R7 v" A% u% f2 c
7 g: ^+ K9 s- |8 o7 Z: g) r- _0 q024 CMD_HEADER = 6'b00_0001,
* F- c4 Q/ z3 e$ e% Q+ H. Q7 c$ @( |9 V0 L) H
025 CMD_LENGTH = 6'b00_0010,. \# t& d' O: w, H( T' D1 @
( e/ y% V: ?& t7 \) C _: f! U
026 CMD_DATAA = 6'b00_0100,( w/ V* {9 Q6 ]# e. ^
2 Y4 Z, j+ u( [ F
027 CMD_DATAB = 6'b00_1000,1 Y& E! u7 p9 h8 T5 S( L1 [
" J9 W5 `( z9 l# v
028 CMD_DATAC = 6'b01_0000,# `* V) F$ ?- G8 [
9 B3 A( _7 o2 g \( k" e
029 CMD_TAIL = 6'b10_0000;
. c3 e9 A9 f$ U% A0 J/ Q- R
$ j. n. k& Q4 s. P/ J7 V# X030
5 ?$ R2 i! s! `6 Q6 w1 ~, u' e+ C1 s+ C; r. M8 q% t. t3 T I6 O- ?
031
: G9 Z4 |* m) m+ C
$ h: J4 B& b b1 O0 G3 i2 w8 N032 always@(posedge Clk or negedge Rst_n). \: O3 c( t0 ~
, m9 I7 n5 ~/ I6 O2 M( L2 n033 if(!Rst_n)begin1 l+ @/ e, W: ~/ ?5 S
% k5 v3 u1 l7 a9 K# f! M5 a3 d9 \3 v034 reg_CMD_DATA <= 24'd0;
0 y/ I b& x" _4 S5 h" y* D* K4 M! ~2 A
035 CMD_Valid <= 1'b0;4 w3 x$ Z1 D5 x& s
- B* b+ s" B7 P3 O1 U0 J
036 state <= CMD_HEADER;
; K, a* J# I! f/ b( L* ?
8 ]7 ^- \6 o* \' C& f' J037 end
. U$ j4 j5 i- u3 i# V: [% j! f6 l* Q
038 else if(Rx_Int)begin
1 t4 ~3 G* W3 t. \& N8 k8 B6 Z7 B+ e8 R
039 case(state)
( c4 d2 A( n6 T/ _+ b5 t
# Q2 J5 g( Y9 h( Z, C8 A4 M+ r040 CMD_HEADER: /*解码帧头数据*/- F# |* B4 {; Y% [, K. R
2 @+ j5 G) }7 H- g* z' B041 if(Rx_Byte == Header)
; \- M0 ^- s6 X* z
: c2 j5 Q9 x' P042 state <= CMD_LENGTH;9 Q w( t. j" H+ R* p1 S
6 e4 g3 e! |8 V9 _043 else! Q0 {4 @0 e! Z7 _: `8 w
( K) u. N- f0 {6 T5 }, r
044 state <= CMD_HEADER;
* T$ M) o; T9 L+ O; f
( \) \) z% O, }1 t4 }045
) t, t* t3 ?$ `" {9 ~
6 @" Q4 G+ e- y6 a046 CMD_LENGTH: /*解码帧长数据*/
* o1 F& Q% w$ H$ {0 ?: @
! D3 ]' p1 U: W- c% h9 t# F+ D047 if(Rx_Byte == Length)$ @$ I* H6 ?/ Q3 _7 F
% S$ D' L4 ~' |: y& \& r
048 state <= CMD_DATAA;: Y6 M$ z2 z; x
' C) m$ H& O8 Y7 }, T/ X049 else6 b d1 V* e- V" V
! v& [! {1 l p+ t) S4 n050 state <= CMD_HEADER;
$ ^, q+ V8 e% M+ Z8 R4 [2 P2 h, B
051 " Z. J5 ?) U6 g" V& `' I7 U) F0 s
+ T, F0 |6 S; t% p$ \9 C052 CMD_DATAA: /*解码数据A*/7 E* z5 X. ^2 ]+ n
8 ]" {6 Q& i6 _. j# d( a5 Q& z
053 begin
$ f& z, T' o7 H7 t/ T$ W* [5 @. n% a9 M% c' G+ O8 B
054 reg_CMD_DATA[23:16] <= Rx_Byte;
& P: g& X* \, j; Z7 J, `
6 j& m; R! Q4 N8 ^& Q4 }$ [055 state <= CMD_DATAB;
2 s' h4 k1 `/ B" L# N; ~2 X4 a. v4 c+ K8 Q& G
056 end. v+ m! d2 |$ n0 G* W
* M- u$ ]0 x5 z& V) P057 - ]* o' Q5 F8 `% n: C; C
. ?. I" A# j% q0 C$ n ^: M
058 CMD_DATAB: /*解码数据B*/
7 }3 I& o- T8 K( p8 x% a' i0 T+ _
+ G" o; ]9 q. Z- F4 f059 begin% P O" U# N: z" ^
- A& I7 A- n$ f$ p; x8 M& l4 H060 reg_CMD_DATA[15:8] <= Rx_Byte;3 Q4 \) W/ ?/ l) s) a1 h% t
, O( X/ E2 g# G& b) K+ w; X$ q% X061 state <= CMD_DATAC; . J5 `3 n! t# Y6 X- Y
2 S. {$ \: |# C9 j062 end- J }& e. g- y9 I3 R) L
3 A4 V# r5 V- ^6 v3 ]063
/ a" G* G+ i$ p9 c# L# q$ V- e( H. g( I+ |$ ~# k( d' y
064 CMD_DATAC: /*解码数据C*/
- d! N7 ?( s+ K, ~8 Y
- `! {- L: {4 r065 begin" y4 \% v- E! w" v1 q
; H0 n0 h$ e2 M$ l A$ t066 reg_CMD_DATA[7:0] <= Rx_Byte;
$ X2 g! U+ Q- g2 |( w2 d4 J" q+ K4 y8 q! m, {) P' S
067 state <= CMD_TAIL; / G9 r) Q) W' Z& z
% U. b2 U5 W4 n$ C5 a6 K$ Z
068 end9 Y' U l v; v w' w( h4 T% t+ z
" y: U5 B9 G( T7 S& @. P
069' I% z$ ]$ G) Q1 t5 o
" b* G2 A6 W; f3 ~. m `' t9 K: q+ O070 CMD_TAIL: /*解码帧尾数据*/- j: B' s" [8 O% ?! L
) s. h5 Z) l" ~; I# _071 if(Rx_Byte == Tail)begin
# `+ o+ y( x8 n1 R, X; W; s% l1 f7 a$ Y! K- d8 `# G" t( s
072 CMD_Valid <= 1'b1; /*解码成功,发送解码数据有效标志*/ _! |0 d1 m' f* w, E M
8 I$ ?8 V/ h. L' `, ^073 state <= CMD_HEADER;: R: @+ c8 F J [. e( W
* Y1 U$ L% @1 e' o! Z074 end. p) e2 d/ J. F' l3 ^1 }0 u
% @5 i) e0 o$ p; b$ v' C4 J" J
075 else begin
6 {) F; ~. u* `8 o+ E; s0 x- ^$ F: k. x/ G$ D) ~) ] ~( O
076 CMD_Valid <= 1'b0;# a, C6 J: Z" j8 Z7 U* }7 |- t8 ` T: Z
3 |9 @: _7 h1 Y077 state <= CMD_HEADER;, M+ W: o3 U6 a' |4 i7 b7 G& C y
# E: C$ e# O9 q$ G# |! C4 Q
078 end
0 l- g0 k: E+ Z! Z! \) z
' g4 f9 P$ b' j7 q6 }2 {079 default:;. w3 Q6 p9 G1 G, D# Y, T
5 A3 C+ T# A Q% M* n
080 endcase + z0 d S/ R- H, Z' G" Q
$ B; Q+ }' ~& k* G
081 end
* l" a/ O: x# r: F/ [- K# }& w1 _' O5 Y9 o6 a; K1 J8 n) {
082 else begin5 N9 n1 Q. Q9 j- c& r3 e6 P: W
/ D/ j2 M E9 I3 ?1 c* o( U
083 CMD_Valid <= 1'b0;
& p4 t' Y& g" A# A& d& P5 \. H; p/ y T$ `+ n9 G, V' f3 g
084 reg_CMD_DATA <= reg_CMD_DATA;
8 Z9 Y' f5 P8 l) ]) a3 s0 B- n/ T" [* {! h; y5 D8 Q6 B( Q
085 end4 t) G$ _2 U" }
| 第23行到第29行为状态机编码,这里采用独热码的编码方式。状态机的编码方式有很多种,包括二进制编码、独热码、格雷码等,二进制编码最接近我们的常规思维,但是在FPGA内部,其译码电路较为复杂,且容易出现竞争冒险,导致使用二进制编码的状态机最高运行速度相对较低。独热码的译码电路最简单,因此采用独热码方式编码的状态机运行速度较二进制编码方式高很多,但是编码会占用较多的数据位宽。格雷码以其独特的编码特性,能够非常完美的解决竞争冒险的问题,使状态机综合出来的电路能够运行在很高的时钟频率,但是格雷码编码较为复杂,尤其对于位宽超过4位的格雷码,编码实现较二进制编码和独热码编码要复杂的多。这里,详细的关于状态机的编码问题,小梅哥不做过多的讨论,更加细致的内容,请大家参看夏宇闻老师经典书籍《Verilog数字系统设计教程》中第12章相关内容。
( ]- ^4 B0 U( _/ a0 _# D% sMemory Mapped 总线进程根据命令有效标志信号产生写外设寄存器操作的相关代码如下所示:
# x5 F2 ?1 U4 H* D! V
) ^" }" ]3 h4 ?" G087 /*------驱动总线写外设寄存器--------*/
/ a6 I/ R; r- F. f Z- R6 @* f; R% F' q$ f; c
088 always@(posedge Clk or negedge Rst_n): U0 O; ~5 Z& s% a
U* `( r( U/ M1 \" L* Y089 if(!Rst_n)begin3 O. X7 A7 U( @' _- q9 o5 R
! m8 B3 H0 d$ r1 d+ ]1 Q1 j" A& j
090 m_wr <= 1'b0;: l$ {* p. p- b. I( b" k
; `" Z. t6 p& |: S$ H' R+ x091 m_addr <= 8'd0;
. D0 A' D: F. j% j8 d9 [% p" X
. A8 @/ z/ |* d+ J, O6 N" Z092 m_wrdata <= 16'd0;
% [: r/ x6 A) v( |* R8 z& C) W3 a2 ^' o; l: w6 n. }( ?$ X, v
093 end5 T5 i/ _, I6 D% g. ~9 ?2 v- ]) q: g
6 a, g' u; V! N1 T e" X
094 else if(CMD_Valid)begin
0 W1 _* t+ y# [4 ?4 V) u8 q- r8 H9 I
095 m_wr <= 1'b1;
+ Z& B% X9 c1 C+ F5 b+ C+ J, g' z8 ^; Z" l, l
096 m_addr <= reg_CMD_DATA[23:16];; j1 Z5 E' f/ {
* s8 B) }/ u/ K/ @ v& y097 m_wrdata <= reg_CMD_DATA[15:0];
% w I0 {" h( a( r" ]3 s1 {( d9 x3 y) D3 m
098 end
: t. L+ {" G/ ?# Q+ O3 P8 y
, o, Z+ o* |2 F$ }0 z099 else begin. O1 b' g4 V9 W* }
3 B) N6 o. \! ]7 m5 e9 w100 m_wr <= 1'b0;
; I3 z7 k; t1 C& E, O4 C0 i
1 s. `" ~6 \( M+ h% A& n, Z( i4 T101 m_addr <= m_addr;5 \/ @1 k9 _, l& N/ E( Y% P Y# h* |
5 @% X/ }: r5 ~0 c5 g102 m_wrdata <= m_wrdata; ( K; \6 K/ X. k/ `/ o
/ n' z) i8 D0 u% G0 [8 K+ B4 l
103 end
. @! a; L- c+ O$ I! x | 6 R& @$ A( l; c
5 z2 Z. w9 d/ w/ M$ h5 I8 G
& z' @7 W5 B. u
. Q6 S' f5 Q" j% p. Y `
- T1 y5 [4 ~3 Q% K( F" \5 ?
% a& T h: K- h( c8 y在本系统中,需要通过该Memory Mapped 总线配置的寄存器总共有12个,分别位于ADC采样速率控制模块(Sample_Ctrl)、串口发送控制模块(UART_Tx_Ctrl)、直接数字频率合成信号发生器模块(DDS)中,各寄存器地址分配及物理意义如下所示:. O# T* v3 n |* M- b) Z
/ Y8 C( u9 f* I
地址" ~( Q7 d2 k |" i. |
|
0 N6 Y- c( k% g0 H# M( }0 J8 L寄存器名称
) k% p/ w: ^% G/ ?" W, {2 @ |
7 V R( V6 D: I+ Q, G寄存器宽度$ h3 F3 E. g+ K5 O( W
|
. s' [$ }4 n* Q/ Q5 I: k寄存器功能9 o$ ?+ |, [4 {5 j
| 6 k, k h* t% Z5 F A
0x011 t7 ~& D# p' w% C
|
1 {! T, W, V- z' t7 BADC_Sample_Cnt_Max_L- i' h* g0 i6 Z& b" E
| % M7 b9 Z( t: ~+ Y3 J* [2 ]
16
& ?% T3 M7 _, P& I* a |
( w! T, k4 L7 s7 I9 k/ ?) ]0 VADC采样率设置分频计数器计数最大值的低16位2 K* J& s8 z4 `4 u6 U1 `( l
| * E& i2 i" n. ?! L/ k+ S
0x023 ?3 K( m+ [; ]2 T* n) |
|
+ P" m/ [+ n T/ MADC_Sample_Cnt_Max_H
+ b6 _: W$ |& F | ) j: S& z- L7 r" L3 t( [* W+ Q
16, n6 z. s& q+ f- [6 W- f- _3 i
| " n) p3 Q% |4 j$ y. ^
ADC采样率设置分频计数器计数最大值的高16位$ {9 e' H. ]$ B
|
; j/ ~- h2 l" A; \) w9 f0x03
( {+ l/ t1 P8 P( {1 p | a4 J; Z8 j& f8 R& y* N8 L: ^
ADC_Sample_En
! ?. \( w" D& a4 J3 _; E. m | 7 l' \2 V# q; D5 X' C& I" [- a
14 p0 W+ ^ W! R" g$ n# ?
| ' k1 ^5 N( Q$ C E
ADC采样使能寄存器
, G$ V. K5 z( l6 d1 X+ s9 w6 I | ' y8 M3 ~, L, q" A
0x047 C, C6 y! l: ^; }
|
7 a' E" v# g3 q7 x# ]5 w; U2 [, R; }En_Tx
. H: Q! e4 m' K4 n7 ^1 }# Y/ p/ l% F | . l1 @' B& \6 t5 o# E8 n
1, o" L$ R$ h0 a: b
| 8 X ~5 R) F" X8 K5 t2 _
串口发送使能寄存器* Y6 e! b9 d8 I1 Q9 A
|
: m% V! r* b# s7 ~. L0x05
/ J$ p& V4 a/ ?8 Y0 v' X | 3 i6 X M9 U+ L7 w4 Y# o) \
reg_Baud_Set
9 h2 _1 d8 X" o& U7 @9 D |
1 `( Y4 u. f9 _* S2
; X) r4 _) G5 Q$ `" @; {- y |
: i3 r: C+ y9 M0 ]! @$ u串口发送波特率设置寄存器1 x8 w ]9 l; D1 L$ N1 Y
| 1 ]! o8 i4 V5 S
0x066 ~' c. G* R8 }1 G1 Z% V+ i
| 0 Y' f7 n- T: \6 p9 F
DDS_En
, I6 |4 l5 _0 }! `4 O9 m1 l; ] |
n# |, d0 r M( u9 f1) i) o* \* t& r; @5 V$ a" {: z/ C
| ! P1 _' n8 f( `' ]
DDS使能寄存器
J9 y9 X2 g7 @- J# B$ A |
( M6 N c2 F" d5 L0x079 V7 n) C8 n+ _+ L9 d7 `' }
|
- N7 H0 U Q5 p1 Areg_Fword_H
6 G& g j$ Q0 V* o | 4 D s' |+ E( f' ]9 d
16: @8 T: h8 ~5 t" o% g0 \; ^
|
4 O$ p( z, [& O+ G6 qDDS频率控制字高16位- g0 O, L1 \. w) N
|
8 \, F$ \7 r% U0x084 E" }3 H K8 p$ F4 y
|
0 I! g6 ^* _1 i+ }9 Q) H/ Qreg_Fword_L5 S9 \: A2 U. H5 t3 i; d
|
# P; [, J( K* q2 N16
' Y) R5 h- y6 l4 u* } |
2 W q$ l4 A. b( L5 mDDS频率控制字低16位
; G7 r) \1 x# a$ } |
1 D0 c5 @1 M8 r) f" d/ f0x09
, o# V" | n3 j) ~. B |
1 w A2 V" y" _' ?7 [/ breg_Pword
2 S, ?# {) z( q: p | 7 @- [+ K# J7 p S0 i' w$ A, ]8 \
126 h* M% } w/ H" P( a2 X
|
3 v8 a6 d' e% P9 }/ T; PDDS相位控制字5 G! @. i& X N2 H
|
8 K/ g" Z1 ^; r' F" A& H0x0a
$ b8 ?, @' \2 ~: ^ |
. e5 J! t: H# E, lDDS_Sample_Cnt_Max_L
4 f) V/ E l$ v9 m; I, y | 6 K! K1 K2 r3 j0 S
16
) l- H$ M* Y" s3 g& W/ J |
7 W& _$ ^9 b: `0 gDDS采样率设置分频计数器计数最大值的低16位& [! f4 N9 m0 V
| 0 O" c9 O I0 C7 R2 B! ^: F: T# e
0x0b6 N* J! t; \- Y
| & R/ O. n& R' ?$ O
DDS_Sample_Cnt_Max_H
$ ~& H: \5 f* j2 k! h! z |
" s) }0 i; B4 \9 S+ f: H D4 E( m6 x16
2 x: U4 e- B5 r' Z x | * b" L5 m5 B# E1 Z I1 A
DDS采样率设置分频计数器计数最大值的高16位
; U3 O* r$ s) l% D |
% {: ^1 V0 j( G2 \2 v/ Q: \4 g0x0c5 a' U3 y0 j) V- u0 I
|
$ e7 G- r2 s3 l2 Y2 g$ X" ?( e, oDDS_Sample_En
# }3 E( u2 d1 T+ w$ Q* ] | ' g: n8 T$ }9 v/ f: Q$ b
1
& x+ s" a) S4 q$ R | 9 ~$ X& U- _, q/ N5 a" ~. K
DDS采样使能寄存器6 c6 P: t: J6 E3 t
|
: _4 b- I5 i' S9 L0 P* S) Z8 P1 ^ ^. ?/ m$ i% z3 j: \
4 Y# s% B+ a [
指令使用说明:
) v9 l8 t( ?8 u2 k$ p+ s( [' f! j. U5 |8 H. }( v9 [6 X8 Q: R, s
* @$ Z4 k. x* Q+ z( P$ r9 K( l
) F* x# }4 B5 s' z" } r操作
' ^6 }2 p1 s0 `1 |5 g |
2 w7 A0 |- ? i& N2 T2 {指令
& R! B- |$ m% X' @& h) h3 e% u | / c$ _$ W; x5 w0 y
使能DDS生成数据9 b1 n! m% ~. l4 z& e0 I, l, ~. q
|
* y& ~' a2 X, b% qAA 03 06 00 01 88/ S Z0 r$ X5 G4 P! Q
|
% n6 P% L' z- {停止DDS生成数据" P7 k( z# L$ h6 |9 _" ?) }
| . L' w3 q. }6 ]* T; Y( z7 w3 P
AA 03 06 00 00 88* o0 K3 \7 a! T( T4 `% m; [: r
|
4 X5 ^+ d! C$ @ N& e# V$ b5 O. t使能采样DDS数据1 q/ I( C( [; r$ E
|
7 q- _& y5 r) I0 @4 S1 qAA 03 0C 00 01 88
4 A B0 n/ S! u# J* f |
5 X" V# a/ A) W停止采样DDS数据 A4 F1 j# n- c- f! x. Q5 L9 h
| 7 N8 N+ Z! C' a+ ]' z
AA 03 0C 00 00 88
+ x) b2 @; s' s; q1 G |
8 I, \; ^/ r! W6 _5 c5 }使能串口发送# H" Q4 t9 P" j4 [' I0 Z: s
| & i/ X, u3 y5 J
AA 03 04 00 01 88
; }" ^* R& `5 ~" C) Y |
% ^5 D" g) O. \ f) x9 a/ n停止串口发送
; x3 O8 y" H8 n6 Z% s" e | / n" U( D/ P7 X: F! T
AA 03 04 00 00 886 _+ k7 L' J6 Q) G1 S+ a7 }
|
& H6 M6 p* A- f Q7 W# I$ ^使能ADC采样; V1 _ }. E r" r0 d! |; M0 D$ u
| 5 P6 J4 {4 Z% ~5 `! t2 k
AA 03 03 00 01 88; k- M+ u$ y9 I, _, [ [" E; B
|
2 i1 i- m% B; e- I3 F% e5 Z停止ADC采样. W4 j3 u! q3 e6 ^( r2 s
|
2 X- O: j, q( i! Z+ f0 {8 ?AA 03 03 00 00 88% `- X6 O; `" t; M
| 6 j% ]1 H9 C; f3 z
写DDS频率控制字高16位2 u" O; W- @6 J8 \3 g
|
4 H7 h; C4 g/ g/ GAA 03 07 XX XX 88
1 @. _3 k! r' [1 L, P |
- N/ P* D# O. l T& u( C% l写DDS频率控制字低16位) x6 n( R6 G( z, Q! L% Z [- ]
| / p- M% h8 }; [! l; Q7 I
AA 03 08 XX XX 88
# A+ o! i+ g) V. H, _
3 a; j1 g: q8 L9 b5 N" P& j2 R! a& FXX_XX_XX_XX = 232*Fout/50_000_000; P# K; N9 l( M9 @% `5 l
W+ ~0 k: ~. j" e
6 w @- ~1 ]0 l& N# {" ?5 V( B O | : `5 c' e& P, u h) k
写DDS相位控制字; U* R6 y% \1 z+ \7 T
|
3 Y+ @! {2 R# p! Q9 z2 B" sAA 03 09 0X XX 88
- j( {, M2 K3 P o8 j5 U | Y) n, s+ s$ }( M5 s3 J! k, s
采样DDS输出数据的采样速率控制高16位$ T Y6 ?0 r1 H r
| * Q" N- H- u6 \4 z4 y& k; P
AA 03 0B XX XX 88
. @' ?3 X. r) o; x7 x6 T* Y9 S | % [! v& d/ i; N7 [) M" m
采样DDS输出数据的采样速率控制低16位
( l3 Q8 {, q6 Y& x | . x; Z3 ~8 r2 i
AA 03 0A XX XX 884 g7 p3 ~& a5 ~3 w& o; R
+ t+ A" f: X/ {. _1 eXX_XX_XX_XX = 50_000_000/Fs - 1+ `! F% C4 j! n+ V
; X1 U2 Z$ A$ O% }7 z# j G
3 j8 b2 L; G5 I# Q# A6 o5 Q: J |
- u% n+ s( e7 DADC采样速率控制高16位9 I- b2 b6 D1 o5 @( @
| ( Z. r9 U, x4 E M
AA 03 02 XX XX 88; s1 v) I* d" {/ F
|
* m& P7 y9 s# P) xADC采样速率控制低16位
5 W6 r6 ?& {- G |
0 |, a) f' N H8 e U9 a2 \, r% gAA 03 01 XX XX 88; b" }0 P+ v* f Y- `: z
1 \! L+ c. C k; x* }XX_XX_XX_XX = 50_000_000/Fs - 1& A6 T$ [" \2 E7 B* m
6 i0 \6 M; g, `. @4 ^$ n
3 ~$ y0 b$ ~8 y8 o' S6 O! o |
! A( B4 L1 \9 ~* m m* E设置串口波特率* `- g' d e. G+ ?
|
3 V' C/ Y: \6 C. ]+ t9 A2 j1 ?AA 03 05 00 0X 88
% }$ Y/ `. G) s0 }0 i7 z4 ` O7 G* e5 ~1 @
X=
/ H& g3 ]5 |6 B# V: ^. x; \' H. E
6 u8 Q% x6 m& X) d) F' F4’d0:9600bps;/ C# W1 u2 m+ ]6 }1 y$ A; D
+ Y6 C" w; m" E2 ?3 Z2 v- U" K5 L
4’d1:19200bps;
) L3 y! i; h6 S% H+ m- v: i3 p7 K& W( }6 k+ e
4’d2:38400bps;
) f1 Q5 ^& j$ S0 ~3 T! J$ ?" K0 V" f
4’d3:57600bps;
4 `/ ?5 _8 U4 P2 ~
4 C1 D, f6 i1 r5 \ c4’d4:115200bps;8 l1 D% V+ L: z5 {+ a7 \- E7 ]
* [, m' [1 K$ A! @# F- k4’d5:230400bps;! q4 k. g9 F+ ?% p& ^
, E; k0 R% u0 C @! X! k. j* G+ T
4’d6:460800bps;) |! E+ e; l _" U& T1 L3 G
5 ]& r/ c( r. x A4’d7:921600bps;
7 m! j9 W4 e, S) q |
8 o2 ~% W( ~3 H5 N5 h" {2 `) K( [/ `) O9 L
例如,系统在上电后,各个模块默认是没有工作的,要想在上位机上看到数据,就必须先通过上位机发送控制命令。因为系统上电后默认选择的数据通道为DDS生成的数据,为了以最快的方式在串口猎人上看到波形,一种可行的控制顺序如下所示:5 {9 j& J6 e- h
使能DDS生成数据(AA 03 06 00 01 88) —> 使能采样DDS数据(AA 03 0C 00 01 88) —>使能串口发送数据(AA 03 04 00 01 88),& f( Y7 L/ I2 \/ A' o0 y5 k
这里,为了演示方便,因此在系统中对数据采样速率和DDS生成的信号的频率初始值都做了设置,因此不设置采样率和输出频率控制字这几个寄存器也能在串口猎人上接收到数据。
7 ~1 S1 g8 E; v9 _7 D4 P经过此操作后,串口猎人的接收窗口中就会不断的接收到数据了。当然,这离我们最终显示波形还有一段距离,这部分内容我将放到文档最后,以一次具体的使用为例,来step by step的介绍给大家。
5 G; ^6 v! P5 h2 y, P; N9 r& K5 C
, g; e! L4 F: y% ^/ O$ n1 @+ P2 q+ W% E4 D- \& ^8 O9 ^, O
关于Memory Mapped 总线如何实现各模块寄存器的配置,这里小梅哥以ADC采样控制模块Sample_Ctrl中三个寄存器的配置来进行介绍。Sample_Ctrl中三个寄存器的定义及配置代码如下所示:( l" @- w! x3 V1 z `
1 G/ n* L" S# y0 x) A) n+ L, B14 reg [15:0]ADC_Sample_Cnt_Max_L;/*采样分频计数器计数最大值的低16位,ADDR = 8'd1*/
2 c, D% l: F9 i4 H* p) {
4 f' w j& g! H/ H5 ?( Q0 o7 o15 reg [15:0]ADC_Sample_Cnt_Max_H;/*采样分频计数器计数最大值的高16位,ADDR = 8'd2*/
% e$ U6 {1 [% z
. f- y l8 |% k$ t. ?# n: b' W16 reg ADC_Sample_En;/*采样使能寄存器,ADDR = 8'd3*/+ K1 s/ Z9 E1 a- q
1 r6 Q4 I0 n/ u, x, q
17
% M. L4 |9 V5 I% p8 [( C4 l
0 s5 f; M9 E" X18 /*-------设置采样分频计数器计数最大值---------*/ 1 ~, D* k/ }. o" D
$ m2 \) T t) w: L6 f% ] q19 always@(posedge Clk or negedge Rst_n), U& p7 w4 I. C6 |
6 r) z* p8 K9 \: y6 U+ J3 C" B20 if(!Rst_n)begin
% h" R; p: f$ ?- d0 u* X/ e% R0 v9 t5 P0 K2 a/ T" r8 V& P/ G- N
21 ADC_Sample_Cnt_Max_H <= 16'd0;
; Y+ t- h0 \- C/ \9 q# M& M) X% a4 Z" z8 V
22 ADC_Sample_Cnt_Max_L <= 16'd49999;/*默认设置采样率为1K*/
8 v4 N6 g! V3 U3 G, c |1 E& g
, `& i! {; t5 Z" t23 end/ G3 y) Z/ r9 N
^7 N# W: l. T2 M24 else if(m_wr && (m_addr == `ADC_S_Cnt_Max_L))//写采样分频计数器计数最大值的低16位
4 k* U, p1 G1 o2 x& v+ s# D# w, |5 h
25 ADC_Sample_Cnt_Max_L <= m_wrdata;
3 h. |0 y# J2 y9 `# R8 k; P( s2 J
% M* d3 z1 ]% d& H26 else if(m_wr && (m_addr == `ADC_S_Cnt_Max_H))//写采样分频计数器计数最大值的高16位
' _5 X: o/ c- J9 q8 ?( b# K" `' \* `( ~3 b. q
27 ADC_Sample_Cnt_Max_H <= m_wrdata;5 `9 M5 R" y6 _" k0 q) m
* |* T. W) @8 _28 else begin- q1 f% K% b1 j; C+ O( T9 H T
. a7 \# u p9 \# j
29 ADC_Sample_Cnt_Max_H <= ADC_Sample_Cnt_Max_H;; f" X$ w" v5 ~4 n
, F3 R, Q0 X, u2 i30 ADC_Sample_Cnt_Max_L <= ADC_Sample_Cnt_Max_L;7 X% U2 I. T5 C3 T, h
9 A* x# W+ r: W; D m* C7 W31 end
; d( d& a+ `& F; G4 r
" ?3 p* a( g/ J. s7 L1 E- h32
l' Z* D% e7 Y- I+ C8 E) o* S8 T6 Z" i3 w# Q# ^$ J, r8 o
33 /*---------写采样使能寄存器-------------*/
' Z% ]( s5 }/ r S. [$ c( j& e' |
5 j: M b$ t& W7 n9 h8 e" _5 ^6 h34 always@(posedge Clk or negedge Rst_n)( x# V& a4 P+ Q( c. _9 p# o
* E7 G. M" @0 L6 @7 Q# o
35 if(!Rst_n)( [* J& F* V) H" Y
9 o: v1 T f, i
36 ADC_Sample_En <= 1'b0;
" o& _9 }: \' L E6 a# S% I" P1 M2 E1 W
37 else if(m_wr && (m_addr == `ADC_Sample_En)): U, o! m+ Y L$ k. m
. Z0 m& b v' ^3 ]2 t
38 ADC_Sample_En <= m_wrdata[0];
4 r6 ~) V8 R _, ]9 v
~* W3 i: j& E7 f3 r2 }39 else
4 H* X9 X4 T+ b' _, i0 }# G p
" O: p: e c8 W+ Z) p40 ADC_Sample_En <= ADC_Sample_En;+ z+ C W# Q! @0 I0 F a3 o
% t- v2 [' o* r3 z$ z
1 x" \- c8 V( \* u+ u" C3 d | ' o. r9 z* X9 i! T% E8 C. ?
\( d* M3 i- v. t采样率的控制采用定时器的方式实现。使用一个计数器持续对系统时钟进行计数,一旦计数满设定时间,则产生一个时钟周期的高脉冲信号,作为ADC采样使能信号。这里,系统时钟周期为20ns,因此,如果要实现采样1K的采样率(采样周期为1ms),则需对系统时钟计数50000次;若实现20K的采样率(采样周期为50us),则需要对系统时钟计数2500次。以此类推,可知改变采样率的实质就是改变计数器的计数最大值,因此,我们要想改变采样速率,也只需要改变采样率控制计数器的计数最大值即可。所以这里,我们设计了两个16位的寄存器,分别存储采样率控制计数器的计数最大值的低16位和高16位,如第14、15行所示。当我们需要修改ADC的采样率时,直接通过串口发送指令,修改这两个寄存器中的内容即可。8 r! R2 |! U- y. {- W" O
0 e2 [/ R, _+ f- n& Q2 H8 x/ F7 ^+ u
这里,小梅哥使用自己设计的一个山寨版Memory Mapped 总线来配置各个寄存器,该总线包含三组信号,分别为:6 N6 K2 Y, E9 ^/ F7 u! Z
5 o( s( F$ m# P. t6 W
写使能信号:m_wr;, j6 v; ^- T7 R5 H+ b
' b9 ~0 W3 p5 o. A* m
写地址信号:m_addr;1 B, z$ ^5 D8 t! S
, {0 @0 G( l6 h$ s& K4 _1 l写数据信号:m_wrdata;
1 f8 |2 g+ D9 U: D) u% q那么,这三组信号是如何配合工作的呢?我们以配置ADC_Sample_Cnt_Max_H和ADC_Sample_Cnt_Max_L这两个寄存器来进行介绍,这里再贴上这部分代码: N# @( P k2 k; _4 n, } `& }% j
3 z# t/ C( a* O6 Y J8 J! x; _6 g3 d' _18 /*-------设置采样分频计数器计数最大值---------*/ ' [) e5 I2 d, P" j+ S1 F% @
, P* o1 G* }; I* k% d2 ]19 always@(posedge Clk or negedge Rst_n)
0 T8 j* |$ c$ [' j9 o7 @% V# Z: l& x) C* v
20 if(!Rst_n)begin
5 J* T) {8 O* `6 K
! S8 R# I2 L# `4 n$ y' `21 ADC_Sample_Cnt_Max_H <= 16'd0;8 W% a. r& a6 U- p8 J7 r) a+ }
5 m: q4 E. u0 b& T6 S5 S22 ADC_Sample_Cnt_Max_L <= 16'd49999;/*默认设置采样率为1K*/+ e" U) M5 w! @1 U6 b
) ^* E3 K' T0 p* j) F4 [9 a( _! {23 end
: U* b# e1 P4 \4 @
1 E( W6 p* K( e24 else if(m_wr && (m_addr == `ADC_S_Cnt_Max_L))//写采样分频计数器计数最大值的低16位
4 e. _5 w: m. t. V) K' `( G0 _3 p- Q! |7 L( z# O7 \; q N& I6 H
25 ADC_Sample_Cnt_Max_L <= m_wrdata;$ I. w: r# X8 Z' m$ |
8 ?* [) o& f/ j* D26 else if(m_wr && (m_addr == `ADC_S_Cnt_Max_H))//写采样分频计数器计数最大值的高16位
: x( X" E8 m: A
9 I* p& @ a# f9 h0 W27 ADC_Sample_Cnt_Max_H <= m_wrdata;
% |4 M' I/ j& f! l$ Z& U% s: _' f; F/ D; k* O& o
28 else begin
+ S1 A8 S; ?2 \" s" t+ G8 O% B+ c: B: N8 S& r5 \8 y6 @8 h
29 ADC_Sample_Cnt_Max_H <= ADC_Sample_Cnt_Max_H;/ t1 g9 T# w# @1 I* Y3 v6 d
; n7 L0 x) u0 `% I3 c
30 ADC_Sample_Cnt_Max_L <= ADC_Sample_Cnt_Max_L;: h9 o" ?0 J \: N4 ]" A
! @# c6 a6 S: B& `* W) |& Y: c. O31 end7 k9 j9 a* e" N( [* H, t. `9 q$ l
" A* e. A7 ^# N! D2 @
' c8 `7 C$ g: K
|
& p0 G& Y% \. S7 W) m3 A6 V复位时,让{ ADC_Sample_Cnt_Max_H,ADC_Sample_Cnt_Max_L }为49999,即设置默认采样率为1K,每当m_wr为高且m_addr等于ADC_Sample_Cnt_Max_H寄存器的地址时,就将m_wrdata的数据更新到ADC_Sample_Cnt_Max_H寄存器中,同理,若当m_wr为高且m_addr等于ADC_Sample_Cnt_Max_L寄存器的地址时,就将m_wrdata的数据更新到ADC_Sample_Cnt_Max_L寄存器中。其他寄存器的配置原理与此相同,因此不再做阐述,相信大家举一反三,便可理解了。9 z! W/ r, {( n
; n8 _; l; J3 p" t5 u% B i( B小梅哥
; U# F* n6 x4 E3 T. M/ [# d) R+ a5 r! F" ^5 |! H
2015年4月8日 于至芯科技 |
|
|