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に表示

構成

1.2. デモの結果

実際のデモの様子

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ライト・リード

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の制御フロー

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制御と出力データ設定のインタフェースを設定

Low 出力

  • ・出力データに0を設定
  • ・出力イネーブルに設定

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)

ビットフィールド名属性初期値説明
0cmd_enRW0x1コマンド送信を有効化
[3:1]addr_lenRW0x3アドレスバイト数(0~4)
[7:4]pad_cntRW0x0ダミーサイクル数
[9:8]cmd_protoRW0x0コマンド送信時のプロトコル
[11:10]addr_protoRW0x0アドレスおよびパディング送信時のプロトコル
[13:12]data_protoRW0x0データ受信時のプロトコル
[15:14]Reserved
[23:16]cmd_codeRW0x3コマンドバイトの値
[31:24]pad_codeRW0x0ダミーサイクル中に送信する最初の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 モードで動作させた結果です。