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