diff options
author | Gentoo <installgentoo@endianness.com> | 2021-07-24 19:13:43 +1000 |
---|---|---|
committer | Gentoo <installgentoo@endianness.com> | 2021-07-24 19:13:43 +1000 |
commit | f131f2526f24bffe3ca640f7e5d69c87cf071bb9 (patch) | |
tree | f63803d69e1b4fc383592c8b3b4152698fdab8c8 | |
download | uart-loopback-f131f2526f24bffe3ca640f7e5d69c87cf071bb9.tar.gz uart-loopback-f131f2526f24bffe3ca640f7e5d69c87cf071bb9.tar.bz2 uart-loopback-f131f2526f24bffe3ca640f7e5d69c87cf071bb9.zip |
initial commit
-rw-r--r-- | Makefile | 34 | ||||
-rw-r--r-- | pins.pcf | 9 | ||||
-rw-r--r-- | top.v | 127 | ||||
-rw-r--r-- | uart_rx_8n1.v | 65 | ||||
-rw-r--r-- | uart_tx_8n1.v | 62 |
5 files changed, 297 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..05819fb --- /dev/null +++ b/Makefile @@ -0,0 +1,34 @@ +PROJ = uart_loopback +DEVICE = hx1k +PKG = tq144 +PCF = pins.pcf + +FILES = top.v uart_tx_8n1.v uart_rx_8n1.v + +.PHONY: all clean burn + +all: $(PROJ).bin + +%.json: $(FILES) + # Lint to catch mistakes +# verilator --lint-only -Wall $(FILES) + # synthesize using Yosys + yosys -ql yosys.log -p "synth_ice40 -top top -json $(PROJ).json" $(FILES) + +%.asc: %.json + # Place and route using nextpnr + nextpnr-ice40 --$(DEVICE) --package $(PKG) --pcf $(PCF) --json $< --asc $@ + +%.rpt: %.asc + # Timing + icetime -d $(DEVICE) -mtr $@ $< + +%.bin: %.asc + # Convert to bitstream using IcePack + icepack $< $@ + +burn: $(PROJ).bin + iceprog $< + +clean: + rm -f *.json *.asc *.bin diff --git a/pins.pcf b/pins.pcf new file mode 100644 index 0000000..e3b914e --- /dev/null +++ b/pins.pcf @@ -0,0 +1,9 @@ +set_io LED1 99 +set_io LED2 98 +set_io LED3 97 +set_io LED4 96 +set_io LED5 95 +set_io hwclk 21 +# FTDI pins for UART +set_io ftdi_tx 8 +set_io ftdi_rx 9 @@ -0,0 +1,127 @@ +/* + * Top module for iCEstick UART + * Blinks all LEDs and transmits a holy message over UART. + * Licence: GPLv3 + */ + +module top(input hwclk, output LED1, output LED2, output LED3, output LED4, output LED5, output ftdi_tx, input ftdi_rx); + /* ~9600Hz clock (12MHz source clock) */ + reg clk_9600 = 1'b0; + reg [9:0] cntr_9600 = 10'b0; + parameter period_9600 = 625; + + /* ~19200Hz clock (12MHz source clock) */ + reg clk_19200 = 1'b0; + reg [8:0] cntr_19200 = 9'b0; + /* Should be 312.5, but 313 is as close as we can get */ + parameter period_19200 = 313; + + /* ~4800Hz clock (12MHz source clock) */ + reg clk_4800 = 1'b0; + reg [10:0] cntr_4800 = 11'b0; + parameter period_4800 = 1250; + + /* Buffer for FIFO */ + reg [31:0] buff = 32'd0; + reg count = 3'b0; + /* Byte buffer to send over UART */ + reg [7:0] uart_txbyte; + /* Idle at first */ + reg uart_send = 1'b0; + /* Set to 1 after byte transmission is complete */ + wire uart_txed; + + /* Byte to recv to */ + wire [7:0] uart_rxbyte; + /* Recv data rather than idle */ + reg uart_recv = 1'b1; + /* Set to 1 after byte retrival is complete */ + wire uart_rxed; + + /* UART transmitter module - 8 bits, no parity, 1 stop bit + 9600 baud byte to be transmitted send on baud clock input: tx completed output: UART tx pin */ + uart_tx_8n1 transmitter(.clk(clk_9600), .txbyte(uart_txbyte), .senddata(uart_send), .txcompleted(uart_txed), .tx(ftdi_tx)); + /* UART reciever module - 8 bits, no parity, 1 stop bit + 9600 baud byte to recieve to recv on baud clock input: rx completed output: UART rx pin */ + uart_rx_8n1 reciever(.clk(clk_9600), .rxbyte(uart_rxbyte), .recvdata(uart_recv), .rxcompleted(uart_rxed), .rx(ftdi_rx)); + + /* LED register */ + reg ledval = 1'b0; + /* Assign ledval to all LEDs */ + assign LED1 = ledval; + assign LED2 = ledval; + assign LED3 = ledval; + assign LED4 = ledval; + assign LED5 = ledval; + + /* Reduced clock generator */ + always @ (posedge hwclk) begin + /* ~9600Hz clock */ + cntr_9600 <= cntr_9600 + 1; + if (cntr_9600 == period_9600) begin + clk_9600 <= ~clk_9600; + cntr_9600 <= 10'b0; + end + + /* ~19200Hz clock */ + cntr_19200 <= cntr_19200 + 1; + if (cntr_19200 == period_19200) begin + clk_19200 <= ~clk_19200; + cntr_19200 <= 9'b0; + end + + /* ~4800Hz clock */ + cntr_4800 <= cntr_4800 + 1; + if (cntr_4800 == period_4800) begin + clk_4800 <= ~clk_4800; + cntr_4800 <= 11'b0; + end + end + + /* Blink leds if we just txed - 1/2 of clock rate of the main loop prevents LEDs from blinking too fast. */ + always @ (posedge clk_4800) begin + if (uart_txed == 1) ledval <= ~ledval; + end + + /* Read/write loop is clocked at ~2x the baud */ + always @ (posedge clk_19200) begin + + + if (uart_rxed == 1 && count < 4) begin + /* garbage */ + buff[count*8+7:count*8] <= uart_rxbyte; + count <= count + 1; + end + + if (count > 0 && uart_send == 0) begin + /* garbage */ + uart_txbyte <= buff[7:0]; + buff <= 8 >> buff; + count <= count - 1; + uart_send <= 1'b1; + end + + /* Stop sending after character has been sent */ + if (uart_txed == 1) uart_send <= 1'b0; + + +/* if (uart_rxed == 1) begin + uart_recv <= 1'b0; + uart_txbyte <= uart_rxbyte; + uart_send <= 1'b1; + end +*/ + /* Stop sending after character has been sent */ +/* if (uart_txed == 1) begin + uart_send <= 1'b0; + uart_recv <= 1'b1; + end + +*/ + + end + +endmodule + + + diff --git a/uart_rx_8n1.v b/uart_rx_8n1.v new file mode 100644 index 0000000..d9963a8 --- /dev/null +++ b/uart_rx_8n1.v @@ -0,0 +1,65 @@ +/* 8n1 UART module - recieve only */ +module uart_rx_8n1(input clk, output[7:0] rxbyte, input recvdata, output rxcompleted, input rx); + /* Parameters */ + parameter STATE_IDLE = 8'd0; + parameter STATE_STARTRX = 8'd1; + parameter STATE_RXING = 8'd2; + parameter STATE_RXDONE = 8'd3; + + /* State variables */ + reg [7:0] state = 8'b0; + reg [7:0] bits_recvd = 8'b0; + reg [7:0] buf_rx = 8'b0; + reg rxdone = 1'b0; + + /* Wiring */ + wire rxbit = rx; + assign rxcompleted = rxdone; + assign rxbyte = buf_rx; + + /* Recieve on clock */ + always @ (posedge clk) begin + /* Recieve data if instructed to (rather than idle) */ + if (recvdata == 1 && state == STATE_IDLE) begin + state <= STATE_STARTRX; + rxdone <= 1'b0; + end + else if (state == STATE_IDLE) begin + /* If not instructed to recieve data, just idle */ + rxdone <= 1'b0; + end + + /* Recieve start bit (low) */ + if (state == STATE_STARTRX) begin + /* Only go into rxing state when rxbit is 0 */ + if (rxbit == 0) begin + state <= STATE_RXING; + /* If the buffer isn't zerod, the last character will still be there */ + buf_rx <= 0; + end + end + + if (state == STATE_RXING && bits_recvd < 8'd8) begin + buf_rx <= buf_rx + ((1 << bits_recvd) * rxbit); + bits_recvd <= bits_recvd + 1; + + end + else if (state == STATE_RXING) begin + /* Recieve stop bit (high) */ + if (rx == 1) begin + state <= STATE_RXDONE; + bits_recvd <= 8'b0; + end + end + + /* RX done */ + if (state == STATE_RXDONE) begin + rxdone <= 1'b1; + state <= STATE_IDLE; + end + end + +endmodule + + + diff --git a/uart_tx_8n1.v b/uart_tx_8n1.v new file mode 100644 index 0000000..f54b4a8 --- /dev/null +++ b/uart_tx_8n1.v @@ -0,0 +1,62 @@ +/* 8n1 UART module - transmit only */ +module uart_tx_8n1(input clk, input[7:0] txbyte, input senddata, output txcompleted, output tx); + /* Parameters */ + parameter STATE_IDLE = 8'd0; + parameter STATE_STARTTX = 8'd1; + parameter STATE_TXING = 8'd2; + parameter STATE_TXDONE = 8'd3; + + /* State variables */ + reg [7:0] state = 8'b0; + reg [7:0] buf_tx = 8'b0; + reg [7:0] bits_sent = 8'b0; + reg txbit = 1'b1; + reg txdone = 1'b0; + + /* Wiring */ + assign tx = txbit; + assign txcompleted = txdone; + + /* Transmit on clock */ + always @ (posedge clk) begin + /* Send data if instructed to (rather than idle) */ + if (senddata == 1 && state == STATE_IDLE) begin + state <= STATE_STARTTX; + buf_tx <= txbyte; + txdone <= 1'b0; + end + else if (state == STATE_IDLE) begin + /* If not instructed to send data, just idle */ + txbit <= 1'b1; + txdone <= 1'b0; + end + + /* Send start bit (low) */ + if (state == STATE_STARTTX) begin + txbit <= 1'b0; + state <= STATE_TXING; + end + + if (state == STATE_TXING && bits_sent < 8'd8) begin + txbit <= buf_tx[0]; + buf_tx <= buf_tx >> 1; + bits_sent <= bits_sent + 1; + end + else if (state == STATE_TXING) begin + /* Send stop bit (high) */ + txbit <= 1'b1; + bits_sent <= 8'b0; + state <= STATE_TXDONE; + end + + /* TX done */ + if (state == STATE_TXDONE) begin + txdone <= 1'b1; + state <= STATE_IDLE; + end + end + +endmodule + + + |