因为后面有项目需要实现CPLD和FPGA的UART功能,所以这里记录了最近尝试开发的UART通讯的功能。
基本的思想是:通过CPU和CPLD的进行UART通讯,能够配置和dumpCPLD 的信息。
先上TOP层代码
module testcpld
(
//input a,
input rst_n,
input x_clk,
output reg [1:0] led,
input rs232_rx,
output rs232_tx
);
localparam TIME1MHZ_DIV = 40000_000;
localparam TIME1MHZ_DIV2 = 40000_000;
//mypll __ (.CLKI( ), .CLKOP( ));
reg[1:0] led_temp=2'b10;
reg[1:0] led_temp1;
wire sys_clk;
assign sys_clk =x_clk;
//defparam OSCH_inst.NOM_FREQ = "38.00";
//OSCH OSCH_inst(
//.STDBY(1'b0), // 0=Enabled, 1=Disabled // also Disabled with Bandgap=OFF
//.OSC(sys_clk),
//.SEDSTDBY()
//); // this signal is not required if not // using SED
wire rx_en,tx_en;
wire [7:0] rx_d,tx_d;
wire [3:0] rx_num,tx_num;
wire rx_sel_data,tx_sel_data;
reg baudset=1;
bps_rx bps_rx1(
.sys_clk (sys_clk),
.rst_n(rst_n),
.rx_en(rx_en), //input
.baudset(baudset), //input
.rx_num(rx_num), //output
.rx_sel_data(rx_sel_data) //output
);
bps_tx bps_tx1(
.sys_clk (sys_clk),
.rst_n(rst_n),
.tx_en(tx_en), //input
.baudset(baudset), //input
.tx_num(tx_num), //output
.tx_sel_data(tx_sel_data) //output
);
uart_rx uart_rx1(
.sys_clk (sys_clk),
.rst_n(rst_n),
.uart_rx(rs232_rx), //input
.rx_num(rx_num), //input
.rx_sel_data(rx_sel_data), //input
.rx_en(rx_en), //output
.tx_en(tx_en), //output
.rx_d(rx_d) //output
);
uart_tx uart_tx1(
.sys_clk (sys_clk),
.rst_n(rst_n),
.uart_tx(rs232_tx), //output
.tx_num(tx_num), //input
.tx_sel_data(tx_sel_data), //input
.tx_d(rx_d) //input
);
always @(rx_d)
case(rx_d)
8'h31:
begin
// led = 2'b01;
led_temp<=2'b01;
end
8'h32:
begin
//led = 2'b10;
led_temp<=2'b10;
end
8'h41:
begin
// led = 2'b00;
led_temp<=2'b00;
end
8'h61:
begin
// led = 2'b11;
led_temp<=2'b11;
end
default:
led_temp<=led_temp1;
endcase
always @(posedge sys_clk or negedge rst_n)
begin
if(rst_n==1'b0)
led <= 2'b0;
else
begin
led<=led_temp;
led_temp1<=led_temp;
end
end
endmodule
上rx的波特率设置代码
module bps_rx(
input sys_clk,
input rst_n,
input rx_en,
input baudset,
output reg [3:0] rx_num,
output reg rx_sel_data
);
reg [12:0]bsp_div;
reg [12:0]bsp_div_2;
reg flag;
always @(baudset)
begin
case(baudset)
0:
begin
bsp_div <= 13'd5208;
bsp_div_2 <= 13'd2604;
end
1:
begin
bsp_div <= 13'd434;
bsp_div_2 <= 13'd217;
end
default:
begin
bsp_div <= 13'd5208;
bsp_div_2 <= 13'd2604;
end
endcase
end
always @(posedge sys_clk or negedge rst_n)
begin
if(rst_n==1'b0)
flag <= 0;
else if(rx_en==1)
flag <= 1;
else if (rx_num == 4'd10)
flag <= 0;
end
reg [12:0] cnt;
always @(posedge sys_clk or negedge rst_n)
begin
if(rst_n==1'b0)
cnt <= 13'd0;
else if (cnt<bsp_div && flag)
cnt <= cnt+1'b1;
else
cnt <= 13'd0;
end
always @(posedge sys_clk or negedge rst_n)
begin
if(rst_n==1'b0)
rx_num <= 4'd0;
else if (rx_sel_data && flag)
rx_num <= rx_num+1'b1;
else if (rx_num==4'd10)
rx_num <= 4'd0;
end
always @(posedge sys_clk or negedge rst_n)
begin
if(rst_n==1'b0)
rx_sel_data <= 1'b0;
else if (cnt==bsp_div_2)
rx_sel_data <= 1'b1;
else
rx_sel_data <= 1'b0;
end
endmodule
TX的波特率设置代码
module bps_tx(
input sys_clk,
input rst_n,
input tx_en,
input baudset,
output reg [3:0] tx_num,
output reg tx_sel_data
);
reg [12:0] bsp_div,bsp_div_2;
reg flag;
always @(baudset)
begin
case(baudset)
0:
begin
bsp_div <= 13'd5208;
bsp_div_2 <= 13'd2604;
end
1:
begin
bsp_div <= 13'd434;
bsp_div_2 <= 13'd217;
end
default:
begin
bsp_div <= 13'd5208;
bsp_div_2 <= 13'd2604;
end
endcase
end
always @(posedge sys_clk or negedge rst_n)
begin
if(rst_n==1'b0)
flag <= 0;
else if (tx_en)
flag <= 1;
else if (tx_num ==4'd10)
flag <= 0;
end
reg [12:0] cnt;
always @(posedge sys_clk or negedge rst_n)
begin
if(rst_n==1'b0)
cnt <= 13'd0;
else if (cnt<bsp_div && flag)
cnt <= cnt+1'b1;
else
cnt <= 13'd0;
end
always @(posedge sys_clk or negedge rst_n)
begin
if(rst_n==1'b0)
tx_num <= 4'd0;
else if (tx_sel_data && flag)
tx_num <= tx_num+1'b1;
else if (tx_num==4'd10)
tx_num <= 4'd0;
end
always @(posedge sys_clk or negedge rst_n)
begin
if(rst_n==1'b0)
tx_sel_data <= 1'b0;
else if (cnt==bsp_div_2)
tx_sel_data <= 1'b1;
else
tx_sel_data <= 1'b0;
end
endmodule
rx代码
module uart_rx(
input sys_clk,
input rst_n,
input uart_rx,
input [3:0] rx_num,
input rx_sel_data,
output rx_en,
output reg tx_en,
output reg [7:0] rx_d
);
reg in_data_1,in_data_2;
always @(posedge sys_clk or negedge rst_n)
begin
if(rst_n==1'b0)
begin
in_data_1 <= 1'b1;
in_data_2 <= 1'b1;
end
else
begin
in_data_1 <= uart_rx;
in_data_2 <= in_data_1;
end
end
assign rx_en=in_data_2&(~in_data_1);
reg [7:0] rx_d_r;
always @(posedge sys_clk or negedge rst_n)
begin
if(rst_n==1'b0)
begin
rx_d_r <= 8'd0;
rx_d <= 8'd0;
end
else if(rx_sel_data)
case(rx_num)
0:;
1:rx_d_r[0]<= uart_rx;
2:rx_d_r[1]<= uart_rx;
3:rx_d_r[2]<= uart_rx;
4:rx_d_r[3]<= uart_rx;
5:rx_d_r[4]<= uart_rx;
6:rx_d_r[5]<= uart_rx;
7:rx_d_r[6]<= uart_rx;
8:rx_d_r[7]<= uart_rx;
9:rx_d<= rx_d_r;
default:;
endcase
end
always @(posedge sys_clk or negedge rst_n)
begin
if(rst_n==1'b0)
tx_en <= 0;
else if(rx_num==9&&rx_sel_data)
tx_en <= 1;
else
tx_en <= 0;
end
endmodule
Tx代码
module uart_tx(
input sys_clk,
input rst_n,
output reg uart_tx,
input [3:0] tx_num,
input tx_sel_data,
input [7:0] tx_d
);
always @(posedge sys_clk or negedge rst_n)
begin
if(rst_n==1'b0)
uart_tx <= 1'b1;
else if(tx_sel_data)
case(tx_num)
0:uart_tx<= 1'b0;
1:uart_tx<= tx_d[0];
2:uart_tx<= tx_d[1];
3:uart_tx<= tx_d[2];
4:uart_tx<= tx_d[3];
5:uart_tx<= tx_d[4];
6:uart_tx<= tx_d[5];
7:uart_tx<= tx_d[6];
8:uart_tx<= tx_d[7];
9:uart_tx<= 1'b1;
default:uart_tx<= 1'b1;
endcase
end
endmodule
实现的效果是:
串口输出等于输入。当输入“1”,点LED1,输入“2”,点LED2,输入“a”,点LED1和LED2,输入“A”,灭LED1和LED2。输入其他字符,LED不变
编译遇到的几个问题:
1, case语句中不能直接放多个并行语句,需要用begin+end结构。
case(baudset)
0:
begin
bsp_div <= 13'd5208;
bsp_div_2 <= 13'd2604;
end
endcase 不是end case。
2,baudset 作为module input,不能设置reg,需要用wire型
non-net port baudset cannot be of mode input. VERI-1325
3,case 的default 语句后, 用
default:
led_temp<=led_temp;
不是期望的情况,不知道为什么。