[SpinalHDL] UART 受信回路も設計してみた

(更新

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))

シミュレーション結果

最後にシミュレーションをしてみました。結果(波形)はこんな感じです。(クリックすると拡大できます)

今後の宿題

今後は引き続き、以下のような感じで作業を進めていこうと思っています。

おつかれさまでした。