eFabless MPW で作成した Caravel SoCの事前評価

Marmot 温度センサーデモ



バージョン:2025/02/25

目次:

  1. 温度センサーデモの構成
  2. I2C制御による温度の取得
  3. GPIO制御による7セグLEDの表示
  4. デュアル/クアッドモードでのQSPIフラッシュの動作

1. 温度センサーデモの構成

1.1. デモの概要

目的。

MarmotがサポートしているI2C, GPIO, SPI の動作の確認(今回、SPIは除外

処理内容
  1. I2C経由でBME280からデータを取得
  2. 取得データから温度を計算
  3. GPIO経由で温度を7セグLEDに表示
構成

Caravel

1.2. デモの結果

実際のデモの様子

Caravel

2. I2C制御による温度の取得

2.1. Marmotの I2C 仕様

Marmot の I2Cコントローラの仕様
  • • SiFive 社 Freedom E310 の I2Cとほぼ同じ仕様と思われる
    I2Cの仕様は、Freedom E310 マニュアルに記載なし
    このため、Freedom のI2Cを参考に作成
  • • Freedom は、OpenCore I2CをChiselで記述したもの
  • • Freedom の実装ソースは以下にある

https://github.com/sifive/sifive-blocks/tree/a0da03f5a500917e71002a4b427893a49decc775/src/main/scala/devices/i2c

I2C 初期化
I2C0_REG(OC_I2C_PRER_LO) = 0x0f; I2C0_REG(OC_I2C_PRER_HI) = 0x0; I2C0_REG(OC_I2C_CTR) = OC_I2C_EN;

ピンクの線: プリスケーラーの設定

黄色の線: I2Cのイネーブル

2.2. Marmotの I2C 制御

Marmot の I2Cライト・リード

Caravel

2.3. 温度センサー BME280の仕様

BME280の特徴
  • • 温度.湿度.気圧の取得が可能
  • • I2C インタフェース
資料
資料 場所
ドキュメント https://www.bosch-sensortec.com/products/environmental-sensors/humidity-sensors-bme280
サンプルコード https://github.com/boschsensortec/BME280_SensorAPI
ソース実装の方針
  • • サンプルコードを参考に実装
  • • 補正の処理はサンプルコードをそのまま移植

2.4. BME280の制御

BME280の制御フロー

Caravel

3. GPIO制御による7セグLEDの表示

3.1. Marmot のGPIO仕様

GPIOの仕様は、Freedom FE310 Manual

Chapter 10 Figure 10で確認

  1. GPIO の選択
    • • IOF_EN が0 のとき、GPIO
    • • IOF_EN が 1 のとき、ペリフェラル(IO Function)
  2. GPIO からの入力
    • • IE が 1 のとき、IOF_VAL から値が入力できる
    • • IE が 0 のとき、IOF_VAL は常に 0
  3. GPIO からの出力
    • • OUT_XOR が 0 のとき、OVALの値がそのまま出力
    • • OUT_XOR が 1 のとき、OVALの値が反転して出力
  4. GPIO の出力イネーブル
    • • OE が 1 のとき、出力が有効になる
    • • OE が 0 のとき、出力されない(Hi-Z

3.2. 7セグメントLED制御 TM1637の仕様と対応方針

資料:以下に英語版が存在

https://github.com/revolunet/tm1637/blob/master/datasheet-en.pdf

特徴
  • • CLKとDIOの2本で通信
  • • DIO は双方向のため、バスの衝突を避ける必要あり
  • • データシートに出力オフのタイミング規定がなく制御方法が不明

=> I2Cのようなオープンドレイン制御を想定?

Linuxでのgpio-i2c ドライバのような制御を行う
  • • 1を出力する場合、出力オフ・プルアップ抵抗でHigh
  • • 0を出力する場合、プッシュプルでのLow出力

3.3. TM1637をGPIOで制御する方法

GPIO に OE制御と出力データ設定のインタフェースを設定

  1. Low 出力
    • • 出力データに0を設定
    • • 出力イネーブルに設定
  2. High 出力
    • • 出力ディスエーブルに設定
    • → 外部のプルアップでHighになる

4. デュアル/クアッドモードでのQSPIフラッシュの動作

このテストでは、以下の条件で実施しました:
  • • W25Q32JVSIQ を使用しました。このフラッシュは QPI モードをサポートしており、QE ビットはデフォルトで 1 に設定されています。
  • • QPI モードで Fast Read を使用しました。

4.1. SPI0 IO0-3ピンを双方向モードに設定

reg_mprj_io_13 = GPIO_MODE_USER_STD_BIDIRECTIONAL; // IO3 reg_mprj_io_12 = GPIO_MODE_USER_STD_BIDIRECTIONAL; // IO2 reg_mprj_io_11 = GPIO_MODE_USER_STD_BIDIRECTIONAL; // IO1 reg_mprj_io_10 = GPIO_MODE_USER_STD_BIDIRECTIONAL; // IO0

4.2. SPIフラッシュをデュアル/クアッドモードに設定

  1. QSPIフラッシュのデータシートに従って、SPIフラッシュの命令フォーマットレジスタを設定する。

SPIフラッシュ命令フォーマットレジスタ(ffmt)

ビット フィールド名 属性 初期値 説明
0 cmd_en RW 0x1 コマンド送信を有効化
[3:1] addr_len RW 0x3 アドレスバイト数(0~4)
[7:4] pad_cnt RW 0x0 ダミーサイクル数
[9:8] cmd_proto RW 0x0 コマンド送信時のプロトコル
[11:10] addr_proto RW 0x0 アドレスおよびパディング送信時のプロトコル
[13:12] data_proto RW 0x0 データ受信時のプロトコル
[15:14] Reserved
[23:16] cmd_code RW 0x3 コマンドバイトの値
[31:24] pad_code RW 0x0 ダミーサイクル中に送信する最初の8ビット

例えば、以下のコードは SPI フラッシュの命令フォーマットレジスタを QPI モードで Fast Read を使用するように設定します。

// Set XIP access to Quad mode dummy = SPI_INSN_CMD_EN | SPI_INSN_ADDR_LEN(0x3) | SPI_INSN_PAD_CNT(0x2) | SPI_INSN_CMD_PROTO(SPI_PROTO_Q) | SPI_INSN_ADDR_PROTO(SPI_PROTO_Q) | SPI_INSN_DATA_PROTO(SPI_PROTO_Q) | SPI_INSN_CMD_CODE(0x0b) // Fast read | SPI_INSN_PAD_CODE(0x00); while (_REG32(spi_base_addr, SPI_REG_RFMT) != dummy) { _REG32(spi_base_addr, SPI_REG_RFMT) = dummy; }
  1. SPI フラッシュに QPI モードで動作させるコマンドを送信します。
// Set SPI Flash to Quad mode while (_REG32(spi_base_addr, SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); // Wait until TX FIFO not full _REG32(spi_base_addr, SPI_REG_TXFIFO) = CMD_ENTER_QUAD_MODE; // 0x38

注意: この関数はQSPIフラッシュではなく、ITIM(Instruction Tightly Integrated Memory)上で実行する必要がある。

__attribute__ ((section (".text_itim"))) void init_spi(uint32_t spi_base_addr) { volatile uint32_t dummy; asm volatile ("fence\n\t" "fence.i"); // Set SPI clock while (_REG32(spi_base_addr, SPI_REG_SCKDIV) != SCKDIV) { _REG32(spi_base_addr, SPI_REG_SCKDIV) = SCKDIV; } // Disable XIP mode while (_REG32(spi_base_addr, SPI_REG_RCTRL) != 0x0) { _REG32(spi_base_addr, SPI_REG_RCTRL) = 0x0; } // Set SPI Flash to Quad mode while (_REG32(spi_base_addr, SPI_REG_TXFIFO) & SPI_TXFIFO_FULL); // Wait until TX FIFO not full _REG32(spi_base_addr, SPI_REG_TXFIFO) = CMD_ENTER_QUAD_MODE; // Set XIP access to Quad mode dummy = SPI_INSN_CMD_EN | SPI_INSN_ADDR_LEN(0x3) | SPI_INSN_PAD_CNT(0x2) | SPI_INSN_CMD_PROTO(SPI_PROTO_Q) | SPI_INSN_ADDR_PROTO(SPI_PROTO_Q) | SPI_INSN_DATA_PROTO(SPI_PROTO_Q) | SPI_INSN_CMD_CODE(0x0b) // Fast read | SPI_INSN_PAD_CODE(0x00); while (_REG32(spi_base_addr, SPI_REG_RFMT) != dummy) { _REG32(spi_base_addr, SPI_REG_RFMT) = dummy; } // Enable XIP mode while (_REG32(spi_base_addr, SPI_REG_RCTRL) != SPI_FCTRL_EN) { _REG32(spi_base_addr, SPI_REG_RCTRL) = SPI_FCTRL_EN; } }

4.3. 結果

以下は、QSPI フラッシュを QPI モードで動作させた結果です。

Quad mode