summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGentoo <installgentoo@endianness.com>2021-07-24 19:13:43 +1000
committerGentoo <installgentoo@endianness.com>2021-07-24 19:13:43 +1000
commitf131f2526f24bffe3ca640f7e5d69c87cf071bb9 (patch)
treef63803d69e1b4fc383592c8b3b4152698fdab8c8
downloaduart-loopback-f131f2526f24bffe3ca640f7e5d69c87cf071bb9.tar.gz
uart-loopback-f131f2526f24bffe3ca640f7e5d69c87cf071bb9.tar.bz2
uart-loopback-f131f2526f24bffe3ca640f7e5d69c87cf071bb9.zip
initial commit
-rw-r--r--Makefile34
-rw-r--r--pins.pcf9
-rw-r--r--top.v127
-rw-r--r--uart_rx_8n1.v65
-rw-r--r--uart_tx_8n1.v62
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
diff --git a/top.v b/top.v
new file mode 100644
index 0000000..d4da4e9
--- /dev/null
+++ b/top.v
@@ -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
+
+
+