Forum Discussion
uart communications
Hey, I'm doing a project involving the DE2 FPGA, where I need to communicate with a pc via a serial interface. I have checked the pin assignments file and noticed there are only 2 pins associated with UART: UART_TXD and UART_RXD.
I want to write my code in verilog, rather than running a soft core proccessor and using the NIOS 2 development suit to code c for it. My question is, how can I negotiate a clockspeed using just these two pins? I've been over most of the documentation I can find and there is nothing relevant that I can find. Thanks in advance for any help.14 Replies
- Altera_Forum
Honored Contributor
ok then how bout the inputs....must i connect normal switch as inputs from the altera de-2 board
https://www.alteraforum.com/forum/attachment.php?attachmentid=5225 i have attached the picture of the pin assignment...im new in the rs232 section soe ur advise on wat input must i put is really valuable...is it the normal switch in altera de-2 which is from SW0 to SW17 ?? and for the Tx busy if its not connected in external wat output shall i assign since Tx will be assign externally to UART pin...pls Advise - Altera_Forum
Honored Contributor
I don't exactly understand the question. TxD_busy is nothing to connect at the external UART interface. It's an internal signal to inform the data source when the UART is ready to accept the next character.
- Altera_Forum
Honored Contributor
I come across a coding in verilog for the UART....
Just tat when i connect to the ALTERA DE-2 board i seem to stuck on the Tx busy OUTPUT...as by the pin assignmnt i assign PIN B_25 but how bout Tx busy for the output...wat shall i assign???... this is my coding.. // RS-232 TX module //`define DEBUG // in DEBUG mode, we output one bit per clock cycle (useful for faster simulations) module one(clk, TxD_start, TxD_data, TxD, TxD_busy); input clk, TxD_start; input [7:0] TxD_data; output TxD, TxD_busy; parameter ClkFrequency = 25000000; // 25MHz parameter Baud = 115200; parameter RegisterInputData = 1; // in RegisterInputData mode, the input doesn't have to stay valid while the character is been transmitted // Baud generator parameter BaudGeneratorAccWidth = 16; reg [BaudGeneratorAccWidth:0] BaudGeneratorAcc; `ifdef DEBUG wire [BaudGeneratorAccWidth:0] BaudGeneratorInc = 17'h10000; `else wire [BaudGeneratorAccWidth:0] BaudGeneratorInc = ((Baud<<(BaudGeneratorAccWidth-4))+(ClkFrequency>>5))/(ClkFrequency>>4); `endif wire BaudTick = BaudGeneratorAcc[BaudGeneratorAccWidth]; wire TxD_busy; always @(posedge clk) if(TxD_busy) BaudGeneratorAcc <= BaudGeneratorAcc[BaudGeneratorAccWidth-1:0] + BaudGeneratorInc; // Transmitter state machine reg [3:0] state; wire TxD_ready = (state==0); assign TxD_busy = ~TxD_ready; reg [7:0] TxD_dataReg; always @(posedge clk) if(TxD_ready & TxD_start) TxD_dataReg <= TxD_data; wire [7:0] TxD_dataD = RegisterInputData ? TxD_dataReg : TxD_data; always @(posedge clk) case(state) 4'b0000: if(TxD_start) state <= 4'b0001; 4'b0001: if(BaudTick) state <= 4'b0100; 4'b0100: if(BaudTick) state <= 4'b1000; // start 4'b1000: if(BaudTick) state <= 4'b1001; // bit 0 4'b1001: if(BaudTick) state <= 4'b1010; // bit 1 4'b1010: if(BaudTick) state <= 4'b1011; // bit 2 4'b1011: if(BaudTick) state <= 4'b1100; // bit 3 4'b1100: if(BaudTick) state <= 4'b1101; // bit 4 4'b1101: if(BaudTick) state <= 4'b1110; // bit 5 4'b1110: if(BaudTick) state <= 4'b1111; // bit 6 4'b1111: if(BaudTick) state <= 4'b0010; // bit 7 4'b0010: if(BaudTick) state <= 4'b0011; // stop1 4'b0011: if(BaudTick) state <= 4'b0000; // stop2 default: if(BaudTick) state <= 4'b0000; endcase // Output mux reg muxbit; always @( * ) case(state[2:0]) 3'd0: muxbit <= TxD_dataD[0]; 3'd1: muxbit <= TxD_dataD[1]; 3'd2: muxbit <= TxD_dataD[2]; 3'd3: muxbit <= TxD_dataD[3]; 3'd4: muxbit <= TxD_dataD[4]; 3'd5: muxbit <= TxD_dataD[5]; 3'd6: muxbit <= TxD_dataD[6]; 3'd7: muxbit <= TxD_dataD[7]; endcase // Put together the start, data and stop bits reg TxD; always @(posedge clk) TxD <= (state<4) | (state[3] & muxbit); // register the output to make it glitch free endmodule - Altera_Forum
Honored Contributor
Hey all, I finally solved my problem today. Using a multimeter, oscillascope, 2 different serial cables and a soldering iron.
problems: a) although the cable i was using, was the right one, it didn't work in my 25 pin rs232 port. The computer lab has 9 pin sockets, so that is fine. b) my code had a few bugs. Below is my completed working code, for archive purposes. Thanks for all your help.
thats 9600 baud, 1 stop bit, no parity to send a 40 bit stringmodule test(input CLOCK_50, output LEDR, output UART_TXD, input UART_RXD, input SW ); wire serial_clk; new_clock pll(.inclk0(CLOCK_50), .c0(serial_clock)); reg waiter = 12'b0000000000000; //counter to reduce clock rate //reg waiter = 13'b0000000000000; //counter to reduce clock rate reg state = 4'b0000; //current state. 0 = start bit, 1-8 = data bits, 9 = stop bit, other = ended reg data = 1'b1; //start high = idle state reg clk_new = 0; //changes the state of an led every time a bit is sent reg origData = 48'h00_4F_4C_4C_45_48; //HELLO in ascii, little endian reg currData; reg started = 0; assign LEDR = data; //led outputs current data bit assign LEDR = SW; //led outputs status of a switch assign LEDR = clk_new; //led shows when new bit is sent assign UART_TXD = data; //assert the transmit wire to the data bit always @(posedge serial_clock) //every clock tick begin //if (waiter == 27'b111111111111111111111111111) //1/2 times a second if (waiter == 12'b1100_0011_0100) //9600 times a second (aprox) begin waiter <= 12'b000000000000; //reset counter if (started == 0) //have we not started yet? begin if (SW) //start if switch 0 is high begin started <= 1; currData <= origData; //set the current data register to be the original data register end end else //we have started begin clk_new <= !clk_new; //change clock led if (currData == 48'd0 && state == 4'h0) //end of transmit begin data <= 1'b1; //idle bit if (!SW) //if switch 0 is low, then reset to not started begin started <= 1'b0; end end else begin if (state == 4'h0) //start bit begin data <= 1'b0; end else if(state == 4'h9) //stop bit begin data <= 1'b1; end else if(state < 4'h9) //data bits begin data <= currData; //get first bit currData <= currData >> 1; //right shift, so as first bit is the next bit to send end if (state == 4'h9) //update state begin state <= 4'h0; end else begin state <= state + 1'b1; end end //end data left to transmit end //end started == 1 end //end if (waiter == ...) else begin waiter <= waiter + 1'b1; //inc waiter end end //end always @... endmodule - Altera_Forum
Honored Contributor
Hello,
in the first example, the polarity has been correct for "logic-level" RS232, which is iverted by the MAX232 driver. Now polarity is incorrect. Apart from that, the module is now sending the intended two characters at corrcet baudrate, LSB "9" first, as I could see by Quartus internal simulator. I append my test vector file. Regards, Frank - Altera_Forum
Honored Contributor
I'd suggest removing the inverter from your TxD signal again. Unless there's another external inversion going on, normally I'd expect the TTL/CMOS level signal to idle high and the RS232 level signal to idle negative. From what you said in an earlier post, this would also mean that the transmit LED would be off when idle, which makes sense.
- Altera_Forum
Honored Contributor
hmm, ok, thanks for the clock info, I've corrected it to:
if (waiter == 13'b1010001011000) //9600 times a second (aprox) I'm using: http://www.maplin.co.uk/module.aspx?moduleno=97733&doy=12m2 and http://www.maplin.co.uk/module.aspx?moduleno=97872&doy=12m2 and its not working. So if your sure it can be done with that cable, then there must be something up with my timing code, as I have the UART_TXD light flashing as it should. Any more ideas about what could be wrong. I'm running hyperterminal set to 9600bps, 1 stop bit, no parity bit, no flow control. Listening on port COM1. And when I switch switch 0 on the fpga hyperterminal picks up nothing. my latest code is:module test5(input CLOCK_50, output LEDR, output UART_TXD, input UART_RXD, input SW ); reg waiter = 13'b0000000000000; //counter to reduce clock rate //reg waiter = 13'b0000000000000; //counter to reduce clock rate reg state = 4'b0000; //current state. 0 = start bit, 1-8 = data bits, 9 = stop bit, other = ended reg data = 1'b1; //start high = idle state reg clk_new = 0; //changes the state of an led every time a bit is sent reg origData = 16'b0101001100111001; //S 9 in ascii reg currData; reg started = 0; assign LEDR = data; //led outputs current data bit assign LEDR = SW; //led outputs status of a switch assign LEDR = clk_new; //led shows when new bit is sent assign UART_TXD = !data; //assert the transmit wire to the data bit always @(posedge CLOCK_50) //every clock tick begin //if (waiter == 27'b111111111111111111111111111) //1/2 times a second if (waiter == 13'b1010001011000) //9600 times a second (aprox) begin if (started == 0) //have we not started yet? begin if (SW) //start if switch 0 is high begin started = 1; currData = origData; //set the current data register to be the original data register end end else //we have started begin clk_new = !clk_new; //change clock led waiter = 13'b0000000000000; //reset counter if (currData == 16'b0000000000000000 && state == 4'h0) //end of transmit begin data = 1'b1; //idle bit if (!SW) //if switch 0 is low, then reset to not started begin started = 1'b0; end end else begin if (state == 4'h0) //start bit begin data = 1'b0; end else if(state == 4'h9) //stop bit begin data = 1'b1; end else if(state < 4'h9) //data bits begin data = (currData & 1'b1); //get first bit currData = currData >> 1; //right shift, so as first bit is the next bit to send end if (state == 4'h9) //update state begin state = 4'h0; end else begin state = state + 1'b1; end end //end data left to transmit end //end started == 1 end //end if (waiter == ...) waiter = waiter + 1'b1; //inc waiter end //end always @... endmodule - Altera_Forum
Honored Contributor
Hello,
I see the misunderstanding. 50 MHz clock oszillator isn't 50*2^20 like MByte, it is really 50e6. Or Terasic would be the first company to introduce a binary 50 MHz crystal. But you don't need a nullmodem cable. I had written this first, but corrected after a few minutes. Regards, Frank - Altera_Forum
Honored Contributor
thanks.
Ok my clock is 50mhz which = 52428800hz now i want 9600 baud so: 52428800 / 9600 = 5461.3333333333333333333333333333 so using 5461 as my divisor, which = 1010101010101 or am I doing something stupid. Sinec I do require a null modem cable, i'm fairly sure that getting one will fix my problems, and make this work. I have arranged to pick one up tommorrow. I'll get back to you once i've tried the cable. - Altera_Forum
Honored Contributor
Hello,
I mentioned the decimal constant syntax, cause I was searching for an explanation why you didn't calculate the correct baud rate divider, but set it 4,6 % too slow. But I think you should be able to set the value also using binary constants. DE2 can be connected to PC with a straigth (1:1) RS232 cable, DE2 has TX at pin 2, A PC at Pin 3. Regards, Frank