作者:chenzhufly QQ:36886052
1、 硬件环境
硬件平台:Embest SoC --LarkBoard
软件平台:开发板-linux-3.10.31
Quartus 14.0
2、代码结构
我不生产代码,我只是代码的搬运工,代码来源于网络,分享与网络。但还是需要做一些修改才能使用,慢慢来吧,结构还是不错的,我们一起学习学习。
主要有三个文件uart_top.v,uart_xmit. v,uart_rcv. v,结构如下:
1)uart_top.v是串口逻辑模块的顶层文件,负责管理串口的发送和接收
2)uart_xmit. v为串口的发送模块
3)uart_rcv. v位串口的接收模块
3、代码分析
1)uart_top.v
可以清楚的看到在,在接收模块和发送模块的前端都加了fifo模块,深度为256个字节。
- `timescale 1 ns / 10 ps
-
- `define BAUD_DIV 6875
-
- module uart_top
- (
-
- // Global signal definition
- input rst ,
- input sys_clk ,
- input pci_clk ,
-
- input pci_wren ,
- input [7:0] pci_wrdat ,
- input pci_rden ,
- output [7:0] pci_rddat ,
-
- // Local bus register
- input SEND_CMD ,
- input RCV_EN ,
- output RCV_IRQ ,
- input PARITY_BIT_EN ,
- input PARITY_SEL ,
- output PARITY_ERROR ,
- //output uart_ok ,
- output xmit_busy ,
- output xmit_ok ,
- output xmit_fifo_empty ,
- output rcv_fifo_empty ,
-
- // Uart interface
- input rxd ,
- output txd
- );
-
- wire xmit_fifo_rden;
- wire [7:0] xmit_fifo_rddat;
-
- wire rcv_fifo_wren;
- wire [7:0] rcv_fifo_wrdat;
- //wire rcv_fifo_empty;
-
- /*---------------------------------------------------------------------
- -- transmit module instantiation
- ----------------------------------------------------------------------*/
-
- T_FIFO_256x8 xmit_fifo_256x8
- (
- .din (pci_wrdat ),
- .rd_clk (sys_clk ),
- .rd_en (xmit_fifo_rden ),
- .rst (1'b0 ),
- .wr_clk (pci_clk ),
- .wr_en (pci_wren ),
- .almost_empty ( ),
- .almost_full ( ),
- .dout (xmit_fifo_rddat),
- .empty (xmit_fifo_empty),
- .full ( )
- );
-
- uart_xmit uart_xmit_inst
- (
- .sys_clk (sys_clk ),
- .rst (rst ),
-
- // PCI command interface
- .SEND_CMD (SEND_CMD ),
- .PARITY_BIT_EN (PARITY_BIT_EN ), // parity bit enable or not, 1 = enable, 0 = disable;
- .PARITY_SEL (PARITY_SEL ), // determine ODD/EVEN parity, 1 = ODD, 1 = EVEN;
-
- // UART command data fifofer interface
- .fifo_rden (xmit_fifo_rden ),
- .fifo_rddat (xmit_fifo_rddat),
- .fifo_empty (xmit_fifo_empty),
-
- // UART status interface
- .uart_busy (xmit_busy ),
- .uart_ok (xmit_ok ),
-
- // UART interface
- .txd (txd )
- );
-
- /*---------------------------------------------------------------------
- -- receive module instantiation
- ----------------------------------------------------------------------*/
-
- T_FIFO_256x8 rcv_fifo_256x8
- (
- .din (rcv_fifo_wrdat ),
- .rd_clk (sys_clk ),
- .rd_en (pci_rden ),
- .rst (1'b0 ),
- .wr_clk (sys_clk ),
- .wr_en (rcv_fifo_wren ),
- .almost_empty ( ),
- .almost_full ( ),
- .dout (pci_rddat ),
- .empty (rcv_fifo_empty ),
- .full ( )
- );
-
- uart_rcv uart_rcv_inst
- (
- .sys_clk (sys_clk ),
- .rst (rst ),
-
- // PCI command interface
- .RCV_EN (RCV_EN ),
- .RCV_IRQ (RCV_IRQ ),
- .PARITY_BIT_EN (PARITY_BIT_EN ), // parity bit enable or not, 1 = enable, 0 = disable;
- .PARITY_SEL (PARITY_SEL ), // determine ODD/EVEN parity, 1 = ODD, 1 = EVEN;
- .PARITY_ERROR (PARITY_ERROR ),
-
- // UART command data fifofer interface
- .fifo_wren (rcv_fifo_wren ),
- .fifo_wrdat (rcv_fifo_wrdat ),
- .fifo_empty (rcv_fifo_empty ),
-
- // UART interface, which should be registered before internal access
- .rxd (rxd )
-
- );
-
- endmodule
- `timescale 1 ns / 10 ps
-
- `define BAUD_DIV 6875
-
- module uart_xmit
- (
- input sys_clk ,
- input rst ,
-
- // PCI command interface
- input SEND_CMD ,
- input PARITY_BIT_EN , // parity bit enable or not, 1 = enable, 0 = disable;
- input PARITY_SEL , // determine ODD/EVEN parity, 1 = ODD, 1 = EVEN;
-
- // UART command data fifofer interface
- output reg fifo_rden ,
- input [7:0] fifo_rddat ,
- input fifo_empty ,
-
- // UART status interface
- output reg uart_busy ,
- output reg uart_ok ,
-
- // UART interface
- output reg txd
-
- );
-
- parameter frame_idle = 3'b000, frame_putchar = 3'b001, frame_bit_call = 3'b010, frame_done = 3'b011;
- parameter bit_idle = 3'b000, bit_start = 3'b001, bit_xmit = 3'b010, bit_parity = 3'b011, bit_stop = 3'b100;
-
- reg [2:0] cur_frame;
- reg [2:0] next_frame;
-
- reg [2:0] cur_bit;
- reg [2:0] next_bit;
-
- reg [7:0] xmit_char;
- reg xmit_start;
- reg xmit_done;
-
- reg [3:0] bit_cnt;
- reg bit_over;
- reg [15:0] baud_cnt;
- reg shift_en;
-
- /*---------------------------------------------------------------------
- -- uart byte frame state control state machine
- ----------------------------------------------------------------------*/
- always [url=home.php?mod=space&uid=496176]@[/url] ( * )
- begin
- case ( cur_frame )
- frame_idle:
- if ( SEND_CMD == 1'b1 ) // put frame char when pci send command event detected
- //if ( fifo_empty == 1'b0 )
- next_frame <= frame_putchar;
- else
- next_frame <= frame_idle;
- frame_putchar:
- //if ( char_over == 1'b1 )
- if ( fifo_empty == 1'b1 )
- next_frame <= frame_done;
- else
- next_frame <= frame_bit_call;
- frame_bit_call:
- if ( xmit_done == 1'b0 )
- next_frame <= frame_bit_call;
- else if ( fifo_empty == 1'b1 )
- next_frame <= frame_idle;
- else
- next_frame <= frame_putchar;
- //if ( xmit_done == 1'b1 )
- // next_frame <= frame_putchar;
- //else
- // next_frame <= frame_bit_call;
- frame_done:
- next_frame <= frame_idle;
- default:
- next_frame <= frame_idle;
- endcase
- end
-
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- cur_frame <= frame_idle;
- else
- cur_frame <= next_frame;
- end
-
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- xmit_start <= 1'b0;
- else
- if ( cur_frame == frame_putchar )
- xmit_start <= 1'b1;
- else
- xmit_start <= 1'b0;
- end
-
- /*---------------------------------------------------------------------
- -- uart byte frame state control state machine
- ----------------------------------------------------------------------*/
- always @ ( * )
- begin
- case ( cur_bit )
- bit_idle:
- if ( xmit_start == 1'b1 )
- next_bit <= bit_start;
- else
- next_bit <= bit_idle;
- bit_start:
- if ( shift_en == 1'b1 )
- next_bit <= bit_xmit;
- else
- next_bit <= bit_start;
- bit_xmit:
- if ( bit_over == 1'b0 )
- next_bit <= bit_xmit;
- else if ( PARITY_BIT_EN == 1'b1 )
- next_bit <= bit_parity;
- else
- next_bit <= bit_stop;
- bit_parity:
- if ( shift_en == 1'b0 )
- next_bit <= bit_parity;
- else
- next_bit <= bit_stop;
- bit_stop:
- if ( shift_en == 1'b1 )
- next_bit <= bit_idle;
- else
- next_bit <= bit_stop;
- default:
- next_bit <= bit_idle;
- endcase
- end
-
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- cur_bit <= bit_idle;
- else
- cur_bit <= next_bit;
- end
-
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- xmit_done <= 1'b0;
- else
- if ( cur_bit == bit_stop && shift_en == 1'b1 )
- xmit_done <= 1'b1;
- else
- xmit_done <= 1'b0;
- end
-
- /*---------------------------------------------------------------------
- -- bit counter control
- ----------------------------------------------------------------------*/
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- bit_cnt <= 4'h0;
- else
- if ( cur_bit == bit_idle )
- bit_cnt <= 4'h0;
- else if ( shift_en == 1'b1 )
- bit_cnt <= bit_cnt + 1'b1;
- end
-
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- bit_over <= 1'b0;
- else
- if ( cur_bit == bit_idle )
- bit_over <= 1'b0;
- else if ( bit_cnt == 4'h9 )
- bit_over <= 1'b1;
- end
-
- /*---------------------------------------------------------------------
- -- baud rate control
- ----------------------------------------------------------------------*/
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- baud_cnt <= 16'b0_0000_0000;
- else
- if ( cur_bit == bit_idle || baud_cnt == `BAUD_DIV )
- baud_cnt <= 16'b0_0000_0000;
- else
- baud_cnt <= baud_cnt + 1'b1;
- end
-
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- shift_en <= 1'b0;
- else
- if ( baud_cnt == `BAUD_DIV )
- shift_en <= 1'b1;
- else
- shift_en <= 1'b0;
- end
-
- /*---------------------------------------------------------------------
- -- UART fifo interface
- ----------------------------------------------------------------------*/
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- fifo_rden <= 1'b0;
- else
- fifo_rden <= xmit_start;
- end
-
- /*---------------------------------------------------------------------
- -- TXD controll logic
- ----------------------------------------------------------------------*/
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- xmit_char <= 8'h00;
- else
- if ( cur_bit == bit_start )
- xmit_char <= fifo_rddat;
- else if ( cur_bit == bit_xmit && shift_en == 1'b1 )
- // xmit_char <= { xmit_char[6:0], xmit_char[7] };
- xmit_char <= { xmit_char[0], xmit_char[7:1] };
- end
-
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- txd <= 1'b1;
- else if ( shift_en == 1'b1 )
- case ( cur_bit )
- bit_start :
- txd <= 1'b0;
- bit_xmit:
- // txd <= xmit_char[7];
- txd <= xmit_char[0];
- bit_parity:
- txd <= ( xmit_char[7] ^ xmit_char[6] ^ xmit_char[5] ^ xmit_char[4] ^
- xmit_char[3] ^ xmit_char[2] ^ xmit_char[1] ^ xmit_char[0] ) ^ (~PARITY_SEL);
- default:
- txd <= 1'b1;
- endcase
- end
-
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- uart_ok <= 1'b0;
- else
- if ( SEND_CMD == 1'b1 )
- uart_ok <= 1'b0;
- else if ( fifo_empty == 1'b1 && xmit_done == 1'b1 )
- uart_ok <= 1'b1;
- end
-
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- uart_busy <= 1'b0;
- else
- if ( cur_frame == frame_idle )
- uart_busy <= 1'b0;
- else if ( fifo_empty == 1'b0 )
- uart_busy <= 1'b1;
- end
-
-
- endmodule
串口接收协议的解析和处理
- `timescale 1 ns / 10 ps
-
- `define BAUD_DIV 6875
-
- module uart_rcv
- (
- input sys_clk ,
- input rst ,
-
- // PCI command interface
- input RCV_EN ,
- output RCV_IRQ ,
- input PARITY_BIT_EN , // parity bit enable or not, 1 = enable, 0 = disable;
- input PARITY_SEL , // determine ODD/EVEN parity, 1 = ODD, 1 = EVEN;
- output reg PARITY_ERROR ,
-
- // UART command data fifofer interface
- output reg fifo_wren ,
- output reg [7:0] fifo_wrdat ,
- input fifo_empty ,
-
- // UART interface, which should be registered before internal access
- input rxd
-
- );
-
- reg rxd_reg;
- reg rxd_reg_sft;
- reg [7:0] rxd_s0_cnt;
- reg [7:0] rxd_s1_cnt;
- reg rxd_anti_glitch;
-
- reg [2:0] cur_bit;
- reg [2:0] next_bit;
- reg [7:0] rcv_char;
- reg start_event;
- reg start_event_dly;
- reg [3:0] bit_cnt;
- reg bit_over;
- reg [15:0] baud_cnt;
- reg shift_en;
- reg sample_en;
-
- parameter bit_idle = 3'b000, bit_start = 3'b001, bit_rcv = 3'b010, bit_parity = 3'b011, bit_stop = 3'b100;
-
- /*---------------------------------------------------------------------
- -- rxd anti-glitch control
- ----------------------------------------------------------------------*/
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- rxd_s0_cnt <= 0;
- else
- if ( rxd == 1'b1 )
- rxd_s0_cnt <= 0;
- else if ( rxd_s0_cnt[4] == 1'b0 )
- rxd_s0_cnt <= rxd_s0_cnt + 1'b1;
- end
-
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- rxd_s1_cnt <= 0;
- else
- if ( rxd == 1'b0 )
- rxd_s1_cnt <= 0;
- else if ( rxd_s1_cnt[4] == 1'b0 )
- rxd_s1_cnt <= rxd_s1_cnt + 1'b1;
- end
-
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- rxd_anti_glitch <= 1'b1;
- else
- if ( rxd_s0_cnt[4] == 1'b1 )
- rxd_anti_glitch <= 1'b0;
- else if ( rxd_s1_cnt[4] == 1'b1 )
- rxd_anti_glitch <= 1'b1;
- end
-
- /*---------------------------------------------------------------------
- -- start bit detection
- ----------------------------------------------------------------------*/
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- begin
- rxd_reg <= 1'b1;
- rxd_reg_sft <= 1'b1;
- end
- else
- begin
- rxd_reg <= rxd_anti_glitch;
- rxd_reg_sft <= rxd_reg;
- end
- end
-
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- start_event <= 1'b0;
- else
- if ( rxd_reg == 1'b0 && rxd_reg_sft == 1'b1 &&
- ( cur_bit == bit_idle || cur_bit == bit_stop ) )
- start_event <= 1'b1;
- else
- start_event <= 1'b0;
- end
-
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- start_event_dly <= 1'b0;
- else
- start_event_dly <= start_event;
- end
-
- /*---------------------------------------------------------------------
- -- uart byte frame state control state machine
- ----------------------------------------------------------------------*/
- always @ ( * )
- begin
- case ( cur_bit )
- bit_idle:
- if ( start_event == 1'b1 )
- next_bit <= bit_start;
- else
- next_bit <= bit_idle;
- bit_start:
- if ( shift_en == 1'b1 )
- next_bit <= bit_rcv;
- else
- next_bit <= bit_start;
- bit_rcv:
- if ( bit_over == 1'b0 )
- next_bit <= bit_rcv;
- else if ( PARITY_BIT_EN == 1'b1 )
- next_bit <= bit_parity;
- else
- next_bit <= bit_stop;
- bit_parity:
- if ( shift_en == 1'b0 )
- next_bit <= bit_parity;
- else
- next_bit <= bit_stop;
- bit_stop:
- //if ( shift_en == 1'b1 )
- // next_bit <= bit_idle;
- //else
- // next_bit <= bit_stop;
- if ( start_event == 1'b1 ) // Caution!!! start_event will occur in bit_stop phase
- next_bit <= bit_start;
- else if ( shift_en == 1'b1 )
- next_bit <= bit_idle;
- else
- next_bit <= bit_stop;
- default:
- next_bit <= bit_idle;
- endcase
- end
-
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- cur_bit <= bit_idle;
- else
- cur_bit <= next_bit;
- end
-
-
- /*---------------------------------------------------------------------
- -- bit counter control
- ----------------------------------------------------------------------*/
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- bit_cnt <= 4'h0;
- else
- if ( cur_bit == bit_idle || ( cur_bit == bit_stop && start_event == 1'b1 ) )
- bit_cnt <= 4'h0;
- //else if ( shift_en == 1'b1 )
- else if ( shift_en == 1'b1 && start_event_dly == 1'b0 ) // modified by andrew, 2007-5-24 11:46
- bit_cnt <= bit_cnt + 1'b1;
- end
-
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- bit_over <= 1'b0;
- else
- if ( cur_bit == bit_idle || ( cur_bit == bit_stop && start_event == 1'b1 ) )
- bit_over <= 1'b0;
- else if ( bit_cnt == 4'h9 )
- bit_over <= 1'b1;
- end
-
- /*---------------------------------------------------------------------
- -- baud rate control
- ----------------------------------------------------------------------*/
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- baud_cnt <= 9'b0_0000_0000;
- else
- //if ( cur_bit == bit_idle || baud_cnt == `BAUD_DIV )
- if ( cur_bit == bit_idle ||
- ( cur_bit == bit_stop && start_event == 1'b1 ) ||
- baud_cnt == `BAUD_DIV ) // to avoid error to be accumulated!!!!!
- baud_cnt <= 9'b0_0000_0000;
- else
- baud_cnt <= baud_cnt + 1'b1;
- end
-
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- shift_en <= 1'b0;
- else
- if ( baud_cnt == `BAUD_DIV )
- shift_en <= 1'b1;
- else
- shift_en <= 1'b0;
- end
-
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- sample_en <= 1'b0;
- else
- if ( baud_cnt == (`BAUD_DIV >> 1) )
- sample_en <= 1'b1;
- else
- sample_en <= 1'b0;
- end
-
-
- /*---------------------------------------------------------------------
- -- Character received from uart interface
- ----------------------------------------------------------------------*/
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- rcv_char <= 8'h00;
- else
- if ( cur_bit == bit_rcv && sample_en == 1'b1 )
- //rcv_char <= { rcv_char[6:0], rxd_reg };
- rcv_char <= { rxd_reg, rcv_char[7:1] };
- end
-
- /*
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- PARITY_ERROR <= 1'b0;
- else
- if ( cur_bit == bit_parity && shift_en == 1'b1 )
- PARITY_ERROR <= ( rxd_reg == ( getchar[7] ^ getchar[6] ^ getchar[5] ^ getchar[4] ^
- getchar[3] ^ getchar[2] ^ getchar[1] ^ getchar[0] ) ^ (~PARITY_SEL)
- ) ? 1'b0 : 1'b1;
- end
- */
-
- /*---------------------------------------------------------------------
- -- FIFO control logic
- ----------------------------------------------------------------------*/
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- fifo_wren <= 1'b0;
- else
- if ( cur_bit == bit_stop && ( shift_en == 1'b1 || start_event == 1'b1 ) )
- fifo_wren <= 1'b1;
- else
- fifo_wren <= 1'b0;
- end
-
- always @ ( negedge rst or posedge sys_clk )
- begin
- if ( rst == 1'b0 )
- fifo_wrdat <= 0;
- else
- fifo_wrdat <= rcv_char;
- end
-
- assign RCV_IRQ = ~fifo_empty;
-
- endmodule
4、小结
1)这里主要展示了一下串口模块的逻辑和结构,不过还需要进一步的仿真和测试;
2)中断处理部分还没加进来。
本帖最后由 chenzhufly 于 2015-6-1 00:51 编辑