STEP 1411 — Tang Nano 9K BME280 Phase 2 code-only prep
目的
藤本さん directive 「(P2-prep) 推奨」 選択で 実行。 STEP 1410 Phase 1 の I2C master stub を 完全実装 + BME280 read sequence + PC 側 Bosch datasheet 補正演算 を **BME280 hardware 未購入 の 状態** で code-complete で 用意。 BME280 到着後 は 別 STEP で 30 秒 で 実測 差替 が 可能な 状態。
実装
Files (7、 hardware/phase-c/09-tang-nano-9k-bme280-phase2-prep/)
| File | Lines | Purpose |
|---|---|---|
i2c_master.v | ~330 | 単一 master I2C 状態機 (START/WRITE/READ/STOP/RESTART/ACK/NACK/timeout) |
bme280_reader.v | ~330 | BME280 read シーケンス state machine (chip_id → ctrl_hum/meas → wait 50ms → calib TP 26B → calib H 7B → raw 8B) |
bme280_top.v | ~300 | Top: I2C + reader + UART packet emitter 統合、 open-drain 疑似 wiring、 double-buffer snapshot |
uart_tx.v | ~75 | Phase 1 STEP 1410 copy (差分なし) |
tang_nano_9k.cst | ~30 | Pins: clk 52, LED1-4 10/11/13/14, uart_tx 17, i2c_scl 33, i2c_sda 34 |
build.tcl | ~25 | Gowin V1.9.12.02_SP2 TCL build |
pc_bme280_reader.py | ~230 | pyserial recv + Bosch 補正演算 (T/H/P 全 datasheet 式) + human-readable print |
UART packet format
# BME280 検出時 (~109 chars/sec):
BME:C=60,E=0000,TP=<52 hex>,H=<14 hex>,R=<16 hex>\r\n
# BME280 未検出時 (~24 chars/sec):
BME:C=00,E=<4 hex>,NO_ACK\r\n
# 意味:
# C = chip_id (0x60 期待、 0x00 なら chip_id read 失敗)
# E = error_count (16-bit NACK/timeout 累計)
# TP = 26 バイト calib_tp (0x88-0xA1、 温度 + 圧力 補正係数)
# H = 7 バイト calib_h (0xE1-0xE7、 湿度 補正係数)
# R = 8 バイト raw (0xF7-0xFE、 生 ADC 値 T+P+H)
Verify 結果 (2026-08-26 実測)
Build (Gowin V1.9.12.02_SP2) PASS
- Logic: 1,179/8,640 LUT (14%) — Phase 1 の 7 倍 (I2C master + reader FSM の 追加)
- Register: 939/6,693 (15%)
- CLS: 1,086/4,320 (26%)
- Bitstream: 2,070,608 bytes (impl/pnr/bme280_top.fs、 Tang Nano 9K 固定サイズ)
- Warning: TA1132 (clock SDC unconstrained、 cosmetic)
- 初回 build error → fix: unpacked array port (`output reg [7:0] calib_tp [0:25]`) を Gowin synth が 拒否 (EX3373/EX3998) → **packed vector (`[207:0]`) に refactor** で pass。 top module 側 も byte-select (`buf_calib_tp[idx*8 +: 8]`) で対応
SRAM Program (Tang Nano 9K 書込) — 藤本さん USB 抜き挿し 後 PASS
- 初回試行:
Cable failed to open via the channel(FTDI driver state stuck、 STEP 1410 pyserial 使用後 の Windows FTDI stack 異常 推定) - 藤本さん 「抜き差し完了致しました」 directive → FTDI 全 channel OK 復帰 (Serial Converter A/B + Composite + COM9 全 OK)
- SRAM Program 再試行: 成功、 User Code
0x00000853(STEP 1410) →0x000053D7(STEP 1411 identity)、 Status0x0003F020(Ready)、 Cost 3.45 秒
PC recv (BME280 未 wired NO_ACK verify) PASS
python pc_bme280_reader.py --port COM9 --duration 6- 6/6 NO_ACK packet PASS in 6 秒 (1/sec 完全一致):
[ 1] NO_ACK chip=00 err_count=0x0000 (no BME280 detected) [ 2] NO_ACK chip=00 err_count=0x0000 (no BME280 detected) ... [ 6] NO_ACK chip=00 err_count=0x0000 (no BME280 detected) - 意味: I2C master state machine が I2C transaction を 発行 → BME280 未接続 で NACK 受領 → reader FSM が P_ERROR に 遷移 → UART emitter が chip_id=0x00 + status=NO_ACK packet を 生成 → PC 側 parser が 認識 = I2C master + reader + UART emit の chain が 全 動作
- verdict: PASS (BME280 なし で 検証可能な 範囲 全 完了、 scaffold 正常性 verify)
NO_ACK 状態 の err_count が 0x0000 の 理由 (honest 観察)
- bme280_top.v の double-buffer は
snapshot_validpulse (成功時のみ assert) で latch する 設計 - BME280 未接続 =
snapshot_validpulse ゼロ =buf_err初期値 (0) の まま - 実 err_count (bme280_reader.v 内、 NACK 毎に 増加) は 有効だが、 buffer には 反映されない
- Fix candidate (v0.2、 別 STEP): (a) error 発生時 も latch する 別 pulse 追加、 or (b) buf_err を bypass し 直接 error_count を emit
- 現状 は spike scope で 「NO_ACK 検出」 は 動作、 err_count 表示 は cosmetic 改善余地
BME280 wiring (Phase 2 実行時)
Tang Nano 9K BME280 module (Akizuki 109421)
───────────── ─────────────────────────────
pin 33 (SCL) ────► SCL (with 10 kΩ pull-up to 3.3V)
pin 34 (SDA) ◄──► SDA (with 10 kΩ pull-up to 3.3V)
3.3V ────► VDD
GND ────► GND
SDO → GND (I2C address = 0x76)
CSB → 3.3V (I2C mode enable)
LED 表示
| LED | Pin | 意味 (active-LOW = 0 で 点灯) |
|---|---|---|
| LED1 | 10 | ~1.6 Hz heartbeat (board 生きている 証拠) |
| LED2 | 11 | UART TX busy (1 秒毎 短パルス) |
| LED3 | 13 | BME280 chip_ok (点灯 = 検出済、 消灯 = 未検出) |
| LED4 | 14 | error_count[0] トグル (NACK 増加毎 に 反転) |
Honest scope (8 条)
本 STEP 1411 の 限界
- BME280 hardware 未購入 = 実測データ ゼロ、 code-only prep のみ
- SRAM Program 未実行 = FTDI cable driver state issue で 本 session 内 で は program 不可、 USB re-plug 後 別 STEP で 実行
- UART 実測 未確認 = SRAM Program 未実行 = NO_ACK packet 出力 の 実 verify 未
- I2C master untested vs real slave = simulation なし、 実 BME280 との hardware handshake は 別途 verify 必要
- PC 側 補正演算 untested = 実 calib coeff + raw なし で 演算 path unit test 未
- I2C address 想定 = 0x76 (Akizuki 109421 SDO=GND default) 前提、 module 個体差で 0x77 の 可能性 =
BME_ADDR_W/R修正 + rebuild 必要 - Bosch 補正 double 実装 = pure Python float 使用、 Bosch datasheet の 32-bit fixed-point Q 実装 と 若干 の 数値差 の 可能性 (実用上 は 気にならない tolerance)
- novelty ゼロ = BME280 wire-up は 電子工作 定番 (Adafruit lib / Arduino sketch 多数)、 novelty 主張なし
次段候補 (defer、 藤本さん judgment 待ち)
- SRAM Program 再試行 = USB re-plug 後
programmer_cli.exe --operation_index 2実行、 NO_ACK packet 出力 確認 (BME280 なし 想定 verify) - BME280 発注 = 秋月 通販コード 109421 (¥1,180) + jumper 4 本 + 10 kΩ 抵抗 2 本 (~¥2,000 目安)
- Phase 2 実測差替 = BME280 到着 → 物理配線 → SRAM Program →
pc_bme280_reader.pyで 実測 T/H/P 表示、 STEP 1407 mock 値 と 比較 (別 STEP 1412+) - Phase 3 = benchtop-mcp v0.9-alpha に real hardware 統合 (serialbridge subprocess で
pc_bme280_reader.pyinvoke、bme280-env-a1mock → real 差替、 hardware_available:True flag)
関連
- STEP 1410 — Phase 1 UART/I2C scaffold (直接の 前段)
- STEP 1407 — benchtop-mcp v0.8 mock (差替対象)
- STEP 1406 — 秋月 25 SKU wire-up 候補
- STEP 1409 — rei-scout × Akizuki catalog
- Source:
hardware/phase-c/09-tang-nano-9k-bme280-phase2-prep/