Also designed UART Receiver.
ソフト屋のための SpinalHDL FPGA 設計入門「UART 設計編」の番外編、受信回路の設計です。前回までに UART の送信回路を設計しました。送信回路ができれば受信回路も簡単だろう、受信回路は後回しにしてバス設計でも勉強するか、と思っていたのですが、受信回路には受信回路のノウハウがありそうなので、今日は受信回路を設計してみました。
まずは Git repo
今回も最初に Git repo へのリンクを書いてしまいます。
3月20日修正版
なお、最新版(修正版)はこちらです。併せて御参照ください。
コードの説明
今回もコードの説明を綿密に書いていこうと思ったのですが、やや本業が忙しくなっていることもあり、今回は簡単な説明で許してください。
UART の受信回路のインターフェイスとしては、送信回路と同様に Valid Ready Payload バスを用いることにします。
補足: 前回までに設計した UartCore というクラスの名前を、UartTxCore に変更しました。最初、UartTx と UartRx という 2つの回路を書いて、UartCore にパッケージしてしまおうと思ったのですが、よく考えると、Tx と Rx では独立した Valid Ready Payload が必要なことが分かったので、完全に分離した次第です。AMBA 3 APB の中に納める際には、Tx と Rx をまとめて一つにできると思います。
インターフェイス部分のコードは、こんな感じです。UartTxCore に対して、valid, ready, payload における出力と入力の向きが逆になった点に御注意ください。当たり前と言えばそうなのですが、物事を見る向きが変わると、意外と頭が混乱するものです。
class UartRxCore(
len_data: Int,
clock_rate: HertzNumber,
bit_rate: HertzNumber
) extends Component {
val io = new Bundle {
val valid = out Bool
val ready = in Bool
val payload = out Bits (len_data bits)
val rxd = in Bool
}
FSM(状態遷移)の設計に関しては、以下の点に注意が必要です。
- 送信回路では、ビットレートクロック(ct_timer)に応じて出力 TxD をパタパタしていけば良かったが、受信においては、ビットレートクロックのエッジとエッジの中間付近で RxD を読み込む必要がある。
- そのため、ct_mid という論理を一つ追加した。
- 状態遷移においては、ct_full ではなく ct_mid を使う場合がある。
- stopbit 状態においては、io.ready が True になった段階で idle 状態に戻す。
次に、レジスタ data に RxD を読み込みながらシフトしていく式は、次のように書きました。SpinalHDL ではもっとエレガントな書き方があるように思いますが、まずは自分で考えた式を書いておきます。
data := (data |>> 1) | (io.rxd.asBits << (len_data - 1))
シミュレーション結果
最後にシミュレーションをしてみました。結果(波形)はこんな感じです。(クリックすると拡大できます)
今後の宿題
今後は引き続き、以下のような感じで作業を進めていこうと思っています。
- バスの書き方を勉強
- FIFO の追加(後回しにするかも)
- ソフトコアマイコンに UartApb3 を繋いでみる
おつかれさまでした。