- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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,Link Copied
5 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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?- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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,
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks again for your help and advice. Despite being a simple project in the grand scheme of things, this has taught me a lot :)

Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page