FPGAでUARTループバック回路を作成した
https://gyazo.com/9ef7dcdcf09cb9b5a3679e52a9e0a19d
手元のFPGAボード ULX3S で、UARTの練習がてらループバック回路を作成した。
ulx3s-uart-loopback
使用したUARTコア
UARTモジュールは以下のものを利用した。
freecores / osdvu (Open Source Documented UaRT)
CLOCK_DIVIDE の値をシステムクロックとボーレートに合わせる必要があるので、適宜設定する。
code:verilog
// clock rate (25Mhz) / (baud rate (9600) * 4)
parameter CLOCK_DIVIDE = 651;
ソース
ループバック回路はこんな感じ。
code:top.v
// UART ループバック回路
module top(
input clk,
input rx,
output tx,
output wifi_gpio0
);
wire transmit; // Signal to start transmission
wire received; // Signal indicating a byte is received
wire is_receiving; // Indicates receiving status
wire is_transmitting; // Indicates transmitting status
wire recv_error; // Receive error indicator
wire 7:0 rx_byte; // Received byte reg 7:0 tx_byte; // Byte to transmit reg tx_trigger; // Transmission trigger
uart uart_inst (
.clk(clk),
.rst(1'b0),
.rx(rx),
.tx(tx),
.transmit(tx_trigger),
.tx_byte(tx_byte),
.received(received),
.rx_byte(rx_byte),
.is_receiving(is_receiving),
.is_transmitting(is_transmitting),
.recv_error(recv_error)
);
// RX から受信したデータを TX へループバックする
always @(posedge clk) begin
if (received) begin
tx_byte <= rx_byte;
tx_trigger <= 1'b1;
end else if (tx_trigger) begin
tx_trigger <= 1'b0;
end
end
// 理由を忘れたけど wifi_gpio0 のフラグを立てておく必要がある
assign wifi_gpio0 = 1'b1;
endmodule
LPFファイル(タイミング制約設定)は、ULX3Sのオリジナルをダウンロードしてきて、名前をいい感じに修正したり、不要なものを削除したりした。
ULX3SオリジナルのLPFファイル
code:ulx3s_v20.lpf
BLOCK RESETPATHS;
BLOCK ASYNCPATHS;
## ULX3S v2.x.x and v3.0.x
# Clock (25MHz)
LOCATE COMP "clk" SITE "G2";
IOBUF PORT "clk" PULLMODE=NONE IO_TYPE=LVCMOS33;
FREQUENCY PORT "clk" 25 MHZ;
# JTAG and SPI FLASH voltage 3.3V and options to boot from SPI flash
# write to FLASH possible any time from JTAG:
SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 SLAVE_SPI_PORT=DISABLE MASTER_SPI_PORT=ENABLE SLAVE_PARALLEL_PORT=DISABLE;
# write to FLASH possible from user bitstream:
# SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 SLAVE_SPI_PORT=DISABLE MASTER_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE;
## UART
LOCATE COMP "tx" SITE "L4"; # FPGA transmits to ftdi
LOCATE COMP "rx" SITE "M1"; # FPGA receives from ftdi
IOBUF PORT "tx" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "rx" PULLMODE=UP IO_TYPE=LVCMOS33;
## B2 ボタンをリセットボタンとする
LOCATE COMP "rst" SITE "T1";
IOBUF PORT "rst" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
## WiFi ESP-32 "wifi", "usb", "flash" sheet
# wifi_gpio2,4,12,13,14,15 are shared with SD card.
# If any of wifi_gpio2,4,12,13 is used in toplevel, don't use sd_d[].
# If SD is used in 1-bit SPI mode, wifi_gpio4,12 = sd_d1,2 are free, # other pins are shared with GP/GN, and JTAG
LOCATE COMP "wifi_gpio0" SITE "L2";
IOBUF PORT "wifi_gpio0" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
Makefileも用意しておく
code:Makefile
all: ulx3s.bit
clean:
rm -rf uart.json ulx3s_out.config ulx3s.bit
ulx3s.bit: ulx3s_out.config
ecppack ulx3s_out.config ulx3s.bit
ulx3s_out.config: uart.json
nextpnr-ecp5 --85k --json uart.json --lpf ulx3s_v20.lpf --textcfg ulx3s_out.config
uart.json: top.sv
yosys -p "hierarchy -top top" -p "proc; opt" -p "synth_ecp5 -noccu2 -nomux -nodram -json uart.json" top.sv uart.v
prog: ulx3s.bit
fujprog ulx3s.bit
動作確認
以下のコマンドでビルドして実機へ書き込みを行う
code:sh
$ make clean prog
シリアルコンソールへの接続は screen コマンドを利用。
code:sh
$ screen /dev/cu.usbserial-D00084 9600
初回は +++++++++++++++++++++ みたいなゴミが出力されるが、キーボードから入力した文字がいい感じに出力される。
https://gyazo.com/4ab3826a0d849c3fce328859dec2d239
screen を終了するには、Ctrl-a k を押すと「本当に終了するか?」と聞かれるので、そこで y を押して終了。
初回に表示される ++++++++++++++++++++++++++++++++ は、FPGAへの書き込み時にUARTのバッファにたまったゴミのなのかな? screen を終了した後に再度開くとゴミは表示されない。
https://gyazo.com/9ef7dcdcf09cb9b5a3679e52a9e0a19d