MimasV2 – UART + 7 segment

In the last tutorial we saw how to display any 3 digit number on the 7 segment display.

It has been some time since I last posted. I was busy working with the eZdsp board I had mentioned earlier. I just managed to climb up one of the steep portions of the learning curve. As of now I am comfortable working with it…until next time I have to learn some new concepts.

This tutorial, we will use both the UART and the 7 segment displays. This would serve to cement the concepts involved in them. The objective is to send a string of 3 numbers from the PC through UART and display the same on the 7-segment.

There is no new concepts to cover here. There is only one thing to remember. The transmitter(PC) and the receiver(FPGA) have to agree on one common protocol to send the string of 3 characters. Usually, while sending a string/character through UART, the string is appended with special characters like ‘\n’ and ‘\r’ which tell the receiver when a string ends etc. Most serial emulators provide options to control what characters to append (or none at all) to the end of strings. In this tutorial, I will assume that the transmitter appends only a ‘\r'(carriage return CR) to the end of the string.

Also, the “Hello World” printing part from the UART demo is left as it is. I helps to know whether the program is still alive.

With that decided lets move to the code. I am posting only the top module here. The other files such as bin2BCD.v, BCDto7Seg.v, UART files and the UCF are the same as the previous tutorial’s.

 

top_module.v


`timescale 1ns / 1ps

module top_module(a,b,c,d,e,f,g,h,e1,e2,e3,tx,rx,clk,reset);

output a,b,c,d,e,f,g,h,e1,e2,e3,tx;
input rx,clk,reset;

localparam [1:0] idle=2'b00, data1=2'b01, data2=2'b10, data3=2'b11; /*these are the states of the receiver FSM*/

// Signals for UART submodule
reg rd_uart = 1'b0;
reg wr_uart = 1'b0;
reg [7:0] data_out = 0 ;
wire [7:0] data_in ;
wire full ;
wire empty ;
reg [7:0] data_rx = 0 ;
reg [1:0] rx_state = 0 ;

reg [9:0] disp_num = 0 ; /*this holds the number computed from the individually received digits */
reg [9:0] disp_num1 = 0 ; /*holds the final number to be displayed on 7seg*/
wire [3:0] dig0,dig1,dig2 ; /* rest same as previous tutorial*/
reg [3:0] currentDig ;
reg [1:0] digCnt = 2'd0 ;
reg dig0en,dig1en,dig2en;
assign e1=dig2en; assign e2=dig1en; assign e3=dig0en;
reg [15:0] dispClk = 0 ;

bin2BCD v1({dig2,dig1,dig0},disp_num1);
BCDto7Seg v2(a,b,c,d,e,f,g,h,currentDig);
// Counter to set the time delay
reg [26:0] timer_cnt = 0;
reg timer_timeout = 1'b0;

// Parameters for memory
parameter WIDTH = 8 ,
DEPTH = 16,
ADDR = 4 ;

// Ram & address
reg [ADDR-1:0] address = 0 ;
wire [WIDTH-1:0] arr_mem [DEPTH-1:0];

// Assuming clk frequency 100MHz
parameter CLK_FREQ = 100000000;

// Assigning data to ram memory
assign arr_mem[0] = "H";
assign arr_mem[1] = "e";
assign arr_mem[2] = "l";
assign arr_mem[3] = "l";
assign arr_mem[4] = "o";
assign arr_mem[5] = " ";
assign arr_mem[6] = "W";
assign arr_mem[7] = "o";
assign arr_mem[8] = "r";
assign arr_mem[9] = "l";
assign arr_mem[10] = "d";
assign arr_mem[11] = "!";
assign arr_mem[12] = "\n"; // new line character
assign arr_mem[13] = "\r"; // carriage return character

// Timer logic
always@(posedge clk)
begin
if(!reset)
timer_cnt <= 0;
else if(timer_cnt == CLK_FREQ-1) // 99999999 = 1s , we are setting some delay to display string next time.
begin
timer_timeout <= 1'b1;
timer_cnt <= 0;
end
else if(address == 13)
timer_timeout <= 0;
else
timer_cnt <= timer_cnt + 1'b1;
end

// writing data to uart and incrementing address for memory
always@(posedge clk)
begin
if(!reset)
begin
data_out <= 0;
address <= 0;
end
else if(timer_timeout && ~full)
begin
wr_uart <= 1'b1;
data_out <= arr_mem[address];
address <= address + 1'b1;
if(address == 13)
address <= 0;
end
else
wr_uart <= 1'b0;
end

always @(posedge timer_cnt[10] or negedge reset)
begin
if(!reset)
begin
rx_state<=idle;
disp_num<=0;
disp_num1<=0;
end
else
begin
if(!empty)
begin
rd_uart <= 1'b1;
data_rx ="0" && data_rx<="9") begin rx_state<=data1; /*if received char is between '0' & '9'*/                                                                              disp_num="0" && data_rx<="9") begin rx_state<=data2; disp_num<=4'd10*disp_num + (data_rx-"0"); end
else if(data_rx=="\r") begin rx_state<=idle; disp_num1<=disp_num; disp_num<=0; end /*if '\r' is received - end of string - send to display*/
else begin rx_state<=idle; disp_num="0" && data_rx<="9") begin rx_state<=data3; disp_num<=4'd10*disp_num + (data_rx-"0"); end
else if(data_rx=="\r") begin rx_state<=idle; disp_num1<=disp_num; disp_num<=0; end
else begin rx_state<=idle; disp_num<=0; end
end
data3: begin
if(data_rx!="\r") begin rx_state<=idle; disp_num<=0; end /*this has to be \r only*/
else begin rx_state<=idle; disp_num1<=disp_num; disp_num<=0; end
end
endcase
end
else
rd_uart<=1'b0;
end
end

always @(posedge clk or negedge reset) begin
if(!reset) dispClk <= 16'd0;
else dispClk <= dispClk + 1'b1;
end

always @(posedge dispClk[15]) begin
case (digCnt)
2'd0: begin
digCnt <= 2'd1;
dig2en <= 1'b1;dig1en <= 1'b1;dig0en <= 1'b0;
currentDig <= dig0;
end
2'd1: begin
digCnt <= 2'd2;
if(dig1==4'd0 & dig2==4'd0) begin dig2en <= 1'b1;dig1en <= 1'b1;dig0en <= 1'b1; end
else begin dig2en <= 1'b1;dig1en <= 1'b0;dig0en <= 1'b1; currentDig <= dig1; end
end
2'd2: begin
digCnt <= 2'd0;
if(dig2==4'd0) begin dig2en <= 1'b1;dig1en <= 1'b1;dig0en <= 1'b1; end
else begin dig2en <= 1'b0;dig1en <= 1'b1;dig0en <= 1'b1; currentDig <= dig2; end
end
endcase
end

// Instantiation of uart module
// DIVISOR = 326 for 19200 baudrate, 100MHz sys clock
uart #( .DIVISOR (9'd326),
.DVSR_BIT (4'd9) ,
.Data_Bits (4'd8) ,
.FIFO_Add_Bit (3'd4)
) uart ( .clk (clk),
.rd_uart (rd_uart) ,
.reset (reset) ,
.rx (rx) ,
.w_data (data_out) ,
.wr_uart (wr_uart) ,
.r_data (data_in) ,
.rx_empty (empty) ,
.tx (tx) ,
.tx_full (full)
);

endmodule

 

Once you put this into the FPGA, change the jumper direction. Next open the arduino IDE and select the correct COM port and in the serial monitor set 19200 baud. Make sure the line ending drop down column is set to carriage return(CR). Now you can send any 1/2/3 digit number.

You can find the entire project folder in zip format in my GitHub repo:

https://github.com/Anirudh-R/Mimas-V2/blob/master/uartRx7Seg_11apr17.zip

That is it for this tutorial. Next tutorial, we will see how to generate a PWM signal using the FPGA and how that can be used to generate an audio tone through the onboard audio jack.

Till then.

Anirudh

 

 

 

Author: anirudhr

Electronics hobbyist with special interest in the field of Software Defined Radios, FPGAs and DSP. Beginner but always ready to learn new stuff. Nothing like Hands on experience to teach you something.

Leave a comment