Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
12 years ago

RS232 chargen reset problem

Hello!

I'm actually a software engineer, new to the 'dark arts'! Anyway I'm trying to make a 'chargen' over RS232, and I have succeeded in making it transmit ASCII characters 0x21 to 0x7e.

But I am trying to make it transmit this again each time a button is pressed, to no avail. I am targetting a Cyclone II EP2C8Q208C8N and using a USB-to-RS232 adapter.

When I program the FPGA, the characters are output, then nothing (as expected). But then pressing the reset button does nothing. I have tried running it through ModelSim and found nothing untoward.

Can anyone offer any suggestions? Also I can't post the code because apparently I can't post links :confused:

Thanks,

5 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Apparently if I post an at-sign, even in a CODE block, the forum thinks i'm posting a link, even if I untick "Automatically parse links in text". Anyway I replaced them with *AT*

    
     
    module rs232_send
      (
      input wire SYSCLK, // 50MHz
      input wire RST_B, // reset switch, active low
      output reg UART_TX
      );
     reg  COUNTER, COUNTER_N;
     wire SER_CLK;
     reg  TX_STATE, TX_STATE_N;
     reg  LETTER, LETTER_N;
     wire ENABLE;
     reg UART_TX_N;
     initial
     begin
      COUNTER <= 0;
      TX_STATE <= 0;
      TX_STATE_N <= 0;
      LETTER <= 7'h21; // start with '!' character
      LETTER_N <= 7'h21;
      UART_TX <= 1;
     end
     assign SER_CLK = (COUNTER == 9'd434); // 50MHz / 434 = 115207 (close enough)
     assign ENABLE = (LETTER != 7'h7e);
     always *AT* (posedge SYSCLK or negedge RST_B)
     begin
      if(!RST_B)
      begin
       COUNTER <= 0;
       TX_STATE <= 0;
       LETTER <= 7'h21;
       UART_TX <= 1;
      end
      else
      begin
       COUNTER <=# 1 COUNTER_N;
       TX_STATE <=# 1 TX_STATE_N;
       LETTER <=# 1 LETTER_N;
       UART_TX <=# 1 UART_TX_N;
      end
     end
     always *AT* (*)
     begin
      if(COUNTER == 9'd434)
       COUNTER_N = 0;
      else
       COUNTER_N = COUNTER + 9'h1;
     end
     always  *AT* (*)
     begin
      if(SER_CLK)
      begin
       case(TX_STATE)
         4'd0: UART_TX_N = 0; // start bit
         4'd1: UART_TX_N = LETTER; // first nibble
         4'd2: UART_TX_N = LETTER;
         4'd3: UART_TX_N = LETTER;
         4'd4: UART_TX_N = LETTER;
         4'd5: UART_TX_N = LETTER; // second nibble start
         4'd6: UART_TX_N = LETTER;
         4'd7: UART_TX_N = LETTER;
         4'd8: UART_TX_N = 0; // top bit is always zero, as ASCII is 7-bit
         4'd9: UART_TX_N = 1; // stop bit
         default: UART_TX_N = 1; // idle
        endcase
       end
      else
       UART_TX_N = UART_TX;
     end
     always *AT* (posedge SYSCLK)
     begin
     if(SER_CLK & ENABLE)
     begin
      if(TX_STATE == 4'd9)
      begin
       TX_STATE_N <= 4'h0;
       if(LETTER == 7'h7e)
        LETTER_N <= 7'h21;
       else
        LETTER_N <= LETTER + 7'h1;
      end
      else
      begin
       TX_STATE_N <= TX_STATE + 4'h1;
       LETTER_N <= LETTER;
      end
     end
     end
     endmodule
     
    
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    A simple reason could be your RST_B signal is not correctly assigned to the right fpga pin. Serial communications starts upon fpga programming because registers are initially in the correct state.

    Anyway your code is pretty bad: you'd better synchronizing everything to SYSCLK, namely use a single process always @ (posedge SYSCLK)

    There's no point in triggering on RST_B negedge, when you can simply sample it with the fast sysclk; and assigning registers inside a always @ (*) process is not a recommended practice: how is this supposed to be synthesized in real hardware? Latches? Flip-flops, but which clock?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Thank you for the tips! :) I reworked it a little and removed the always * block, and moved it into a single process, as you suggested. And now it works as expected :D

    
    module rs232_send
    	(
    	input wire SYSCLK, // 50MHz
    	input wire RST_B, // reset switch, active low
    	output reg UART_TX
    	);
    reg  COUNTER;
    wire SER_CLK;
    reg  TX_STATE;
    reg  LETTER;
    wire ENABLE;
    initial
    begin
    	COUNTER <= 0;
    	TX_STATE <= 0;
    	LETTER <= 7'h21; // start with '!' character
    	UART_TX <= 1;
    end
    assign SER_CLK = (COUNTER == 16'd5208); // 50MHz / 5208 = 9600
    assign ENABLE = (LETTER != 7'h7e);
    always *AT* (posedge SYSCLK)
    begin
    	if(!RST_B)
    	begin
    		COUNTER <= 0;
    		TX_STATE <= 4'hA;
    		LETTER <= 7'h21;
    		UART_TX <= 1;
    	end
    	else
    	begin
    		if(!ENABLE)
    			UART_TX <= 1;
    		else if(SER_CLK)
    		begin
    			COUNTER <= 0;
    			case(TX_STATE)
    				4'd0: UART_TX <= 0; // start bit
    				4'd1: UART_TX <= LETTER; // first nibble
    				4'd2: UART_TX <= LETTER;
    				4'd3: UART_TX <= LETTER;
    				4'd4: UART_TX <= LETTER;
    				4'd5: UART_TX <= LETTER; // second nibble start
    				4'd6: UART_TX <= LETTER;
    				4'd7: UART_TX <= LETTER;
    				4'd8: UART_TX <= 0;
    				4'd9: UART_TX <= 1; // stop bit
    				default: UART_TX <= 1; // idle
    			endcase
    			if(TX_STATE == 4'd9)
    			begin
    				TX_STATE <= 4'h0;
    				if(LETTER == 7'h7e)
    					LETTER <= 7'h21;
    				else
    					LETTER <= LETTER + 7'h1;
    			end
    			else
    			begin
    				TX_STATE <= TX_STATE + 4'h1;
    			end
    		end
    		else
    			COUNTER <= COUNTER + 16'h1;
    	end
    end
    endmodule
    

    If there's anything else that's bad about this code, I would be very grateful to hear it.

    Thanks again,
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Ok. Now it's fine.

    You could possibly remove these lines

          if(LETTER == 7'h7e)
    	    LETTER <= 7'h21;
         else
    

    since they are useless: infact when LETTER reaches 7e , ENABLE becomes false and you wouldn't get here any more, until after the RST_B signal has restored LETTER to 7'h21 initial value.

    I'd also replace the if(!ENABLE) statement with the actual test on COUNTER value, because imho it is clearer.

    Please note that your code is already ok as it is. The suggested changes won't affect its functionality but only serves to improve readability and better understanding the way code operates. This may seem not worthy here but it becomes fondamental in a bigger design.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Thanks again for your help and advice. Despite being a simple project in the grand scheme of things, this has taught me a lot :)