センスチャン基板のSDカードまわりの不具合対応

センスチャンとは?

SPRESENSEマイコンを搭載したスタックチャン派生のロボットです。

センスチャン基板とは?

センスチャン専用に設計した、SPRESENSEの拡張ボードです。
詳細はコチラ

SDカードまわりの不具合

センスチャン基板にはSDカードまわりに不具合がありました。

症状

電源オン時はSDカードを認識できるが、リセットをかけるとSDカードを認識できなくなります。SPRESENSEはUSBケーブルを接続するとリセットがかかる仕組みなので、そうするとSDカードが使えなくなります。ただし、SDカードを抜いて挿入しなおすと正常に認識します。

当然ながら、SPRESENSEの純正拡張ボードではこのような不具合は起こりません。

原因

マイコンのリセット時にSDカードがリセットされずに中途半端な状態になっているのではないかと思われます。機序は明確には特定できていないものの、レベル変換ICが原因ではないかと思われます。SPRESENSEのIO電圧は1.8V、SDカードのIO電圧は3.3Vなので、SDIOにレベル変換が必要であり、純正ボードではSDIO専用のレベル変換IC TXS02612 を使用しています。いっぽう、センスチャン基板では基板サイズと手実装の都合で汎用のレベル変換IC LSF0108 を使用しています。両者を比較すると CLK ラインの等価回路に違いがあります。リセット時にCLKラインが不安定になり、意図しない動作になっている可能性があります。

対策

基板の改修は難しいので、とりあえずソフトウェアでSDIOを明示的にリセットすることにします。

ただし、SPRESENSE のArduino環境は NuttX上で動作しており、SD.begin() は NuttX が SDカードを認識しているかどうかを確認するだけです。そこで、NuttX のコードを漁り、SDIOをリセットする方法を調べました。

nuttx\arch\chip\cxd56_sdhci.h に以下のような関数がありました。

// SDIOを初期化する
// 引数 : 未使用
// 戻り値 : SDIO制御構造体への参照
struct sdio_dev_s *cxd56_sdhci_initialize(int slotno);

// SDIO状態のリセット
// 引数 : SDIO制御構造体
void cxd56_sdio_resetstatus(struct sdio_dev_s *dev);

// ボード挿抜時にドライバに通知する
// 引数 : SDIO制御構造体
void cxd56_sdhci_mediachange(struct sdio_dev_s *dev);
コード
// SDカードのリセット処理
// 戻り値: 結果 (0:未挿入, 正:リセット成功, 負:リセット失敗)
int sdcard_reset()
{
    // Sense-chan基板の設計ミスによる不具合回避のため。
    // SPRESENSEをH/WリセットするとSDカードが認識されなくなることがあるため
    // SDカードのS/Wリセット処理を行う。

    // CDピンをチェック (挿入時 LOW (false) )
    bool cd = cxd56_gpio_read(PIN_SDIO_CD);
    if(cd == true) return 0; // SDカード未挿入

    const char *DEV_FILE = "/dev/mmcsd0"; // SDカードのデバイスファイル
    const char *MNT_DIR  = "/mnt/sd0";    // SDカードのマウントポイント

    // /mnt/sd0 が正常にマウントされていれば何もしない
    struct stat st;
    int ret = stat(MNT_DIR, &st);
    if (ret == 0) return 1; // すでにマウントされている

    // SDIOを初期化し、OSのデバイスドライバに知らせる
    struct sdio_dev_s *sdio = cxd56_sdhci_initialize(0);
    cxd56_sdio_resetstatus(sdio);
    cxd56_sdhci_mediachange(sdio);

    if (stat(DEV_FILE, &st) != 0) return -1; // デバイスファイルが無い
    if (stat(MNT_DIR,  &st) == 0) return  2; // すでにマウントされている

    // マウントする
    ret = mount(DEV_FILE, MNT_DIR, "vfat", 0, NULL);
    if (ret < 0) {
        perror("mount failed");
        return -2; // マウント失敗
    }else{
        return 3; // マウント成功
    }
}

中国の陶磁器の歴史

青字 : 日本での呼称 / 緑字 : 地域 / 赤字 : 年代
: 宋代五大名窯

概要

  • 唐 : 唐三彩
  • 宋 : 白磁青磁
  • 元 : 青花 (染付)
  • 明 : 五彩 (赤絵)
  • 清 : 粉彩

  • 唐三彩 (緑・褐・藍)

北宋

  • 汝窯 (河南) : 青磁 ( 「雨過天青」の色 )
  • 定窯 (河北) : 白磁 ( クリーム色 ) マ・クベの壺はこれ!「北宋だな」
  • 北宋官窯 (河南) : 青磁
  • 鈞窯 (河南) : 殿青釉+紫紅釉
  • 耀州窯 (陝西) : 青磁 (オリーブグリーン、全体に刻文)
  • 磁州窯 (河北, 華北一帯) : 白化粧土+黒泥+掻き落とし (白黒掻落とし)

南宋

  • 景徳鎮 (江西) : 白磁 ( 影青(インチン) )
  • 龍泉窯 (浙江) : 青磁 ( 青っぽい、加飾なし )
  • 哥窯 (浙江) : 白に近い青磁、「金糸鉄線」の貫入
  • 南宋官窯 (浙江) : 青磁釉、貫入、「紫口鉄足」
  • 建窯 (福建) : 曜変天目
  • 吉州窯 (江西) : 木葉天目

  • 景徳鎮 (江西) 官窯 / 民窯
    • 初期 (洪武・永楽) : 青花 (コバルトの青)、釉裏紅 (銅の赤)
    • 前期 (成化) : 豆彩 (五彩の一種、青花で輪郭線 + 上絵付け)
    • 中期 (嘉靖)【民窯の活躍】: 五彩 ( 青花+上絵付け )
      • 金襴手 (五彩+金箔)
      • 古赤絵 (青花なし、赤と緑のみ)
      • 法花 (三彩の流れをくむ、イッチン描き)
    • 後期 (万暦)【民窯の活躍】:
      • 万暦赤絵 (装飾過剰)
      • 芙蓉手 (青花の大皿) → 欧州へ輸出
    • 末期 (明末清初) 【官窯の廃止】
      • 古染付・天啓赤絵 (天啓) 虫食い → 日本へ輸出
      • 祥瑞(しょんずい)・色絵祥瑞 (崇禎) 古染付より精製されている → 日本へ輸出
      • 南京赤絵 (明末清初) 狭義には、天啓赤絵・色絵祥瑞と区別
  • 漳州窯 (福建)
    • 呉州赤絵 (明末) 輸出用に大量生産

  • 景徳鎮 (江西)【官窯の復活】: 粉彩 ← 西洋の七宝
    • 康煕・雍正・乾隆が最盛期

組込み屋でもアプリがしたい!【形四】 第10局

Webアプリ版の形四アプリをリリースしました。ブラウザ上でプレイできます。
アプリの名前は WebKC としました。

WebKC - 形四アプリ

形四とは?

「形四(けいし)」とは、白黒4つのコマで正方形をつくるボードゲームです。
詳しくは下記のWebサイトを参照してください。

プレイしてみる

こちら からどうぞ。

C#版アプリも更新しました。

バグが見つかったのでC#版アプリもv1.2に更新しました。

組込み屋でもアプリがしたい!【形四】 第9局

いよいよWebアプリ版の形四アプリを作っていきます。

基本設計メモ

  • 仕様はすでにある C#版アプリ(KCSharp) と同等とする。
  • 画面表示、UI、ファイル入力の処理は JavaScript で記述する。
  • 局面データ、思考エンジン等の内部ロジックは Rust で記述して WebAssembly にコンパイルする。
  • すでにあるC#版のソースを JavaScript と Rust に移植する。
  • UIの見映えを良くするため、フレームワークに Bootstrap を利用する。
  • PC等の横画面とスマホ等の縦画面でレイアウトを切り替える。
    (横画面なら左に盤、右にボタン類。縦画面なら上に盤、下にボタン類。)

詳細設計メモ (1) UIのデザイン

  • HTML, CSS で記述する。(index.html と webkc.css に記述する)
  • Bootstrap を利用してボタン等を見映えの良いスタイルにする。
  • スマホでも適切に表示されるように下記を head に記述する。
  <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
  • 画面を盤面部とフォーム部(ボタンやセレクト類)に分け、各々をdisplay: flex なdiv要素とする。
  • 横長画面であれば、盤面部とフォーム部は flex-direction: row (横並び) とする。
  • 縦長画面であれば、盤面部とフォーム部は flex-direction: column (縦並び) とする。
  • 盤面部とフォーム部が画面内に収まり、かつPCの画面で盤が大きすぎないように盤の大きさを調整する。
  • これらのレイアウト制御は、後述のJavaScriptにて、document の DOMContentLoaded イベント、および window の resize イベントの際に実行する。

詳細設計メモ (2) UIのロジック

  • JavaScriptで記述する。
  • C#版の FormMain.cs と Kifu.cs から移植する。
  • FormMain.cs (フォームのクラス) から UIの処理を webkc.js に移植する。
  • Kifu.cs (棋譜クラス, 初期局面クラス) を kifu.js に移植する。
  • C#版では、思考エンジンは Task.Run( ) を用いて別スレッドで実行している。
  • JavaScriptは基本的にはシングルスレッドだが、Web Workerを用いれば別スレッドで実行できる。
  • ワーカースレッド側の処理は work.js に記述する。
  • メインスレッドとワーカースレッド間のやりとりは postMessage( ) でおこなう。
  • Rustの構造体は下記のようにして取り込んで使用する。
import init, {Position, Move, Board, DaiPunch} from "./pkg/webkc_rust.js";
  • Rustの構造体は、init() の完了を待ってから使用すること。(new することも含む)
  • Rustの構造体はpostMessage( )で送ることができない。
  • Rust側でシリアライズ / デシリアライズ するのがエレガントぽいが、
    今回は通常のオブジェクトに値を積み替えて送ることにする。
  • Rustの構造体のコピーには、Rust側で定義した clone_js() を用いる。(後述)
  • 盤面の canvas のイベントは、マウスとタッチに両対応するため、pointerdown イベントを受ける。
  • C# の MessageBox の移植には、alert() は見栄えがあまり良くないので、Bootstrap の div class="modal fade" を使用する。
  • div class="modal fade" は index.html の body の末尾あたりに記述し、JavaScript で show() する。

詳細設計メモ (3) 内部ロジック

  • Rustで記述してWebAssembly (WASM) にコンパイルする。
  • JavaScript側から呼び出すためのラッパ ./pkg/webkc_rust.js が生成される。
  • Board.cs (位置構造体, 着手構造体, 盤面構造体, 大パンチ判定クラス) を board.rs に移植する。
  • Engine.cs, Engine_AB_SKR.cs (思考エンジンクラス) をengine.rs に移植する。
  • JavaScript側に公開する構造体には #[wasm_bindgen] を指定する。
  • 位置構造体, 着手構造体には、Clone, Copy, PartialEq, Eq をderiveする。
  • 盤面構造体には、Clone, Copy をderiveする。
  • clone() はJavaScript側には公開されないので、clone_js() でラップして公開する。
  • JavaScriptからオブジェクトを引数で渡すときは参照渡しとする。
  • JavaScript側には公開できないが Rust側では pub にしたいメソッドは、implブロックを分ける。
  • Rustの構造体の関連定数 (pub const で定義される、クラス定数のようなもの) は、
    JavaScriptに対応する概念がないので、JavaScript側に公開する構造体には持たせられない。
  • 必要であれば、Rust側で定数として定義して、関数を経由してJavaScript側に取得させる。
  • C#版では、再帰関数内でListを生成するコストを避けるため、静的に確保した配列をSpanで切り出して渡している。
  • Rustで同様の記述をすると、自己借用 (self の二重可変借用) のためコンパイルエラーとなる。
  • ひとまず、構造を大きく変えずに対応するため、ローカルで配列を定義する形に変更する。
  • C#版では、EngineクラスをEngine_AB_SKRクラスが継承している。
  • Rustでは、ひとまず一体物のEngine構造体として実装する。(Rustには継承がないので。)
  • C#版では着手の変数名を move としているが、Rust では move は予約語であることに注意。

Rustの開発環境について

Rust / WebAssembly の開発環境については下記の記事を参照。

wasm-packのインストール
cargo install wasm-pack
プロジェクトの作成
cargo new --lib プロジェクト名
コンパイル
wasm-pack build --target web
クレートの追加

例えば乱数発生器のクレート rand をプロジェクトに追加するには、

cargo add rand

これにより Cargo.toml の [dependencies] に記述が追加される。

組込み屋でもアプリがしたい!【形四】 第8局

C#版の形四アプリがひとまずリリースできたので、次はWebアプリ版を作りたいと思います。Webアプリ版はJavaScriptとRustで作成します。画面表示やUIなどはJavaScriptで、思考エンジンなど内部のロジックはRustで記述します。いずれもC#のソースを移植する形で進めます。

まずその前に、C#版の形四アプリのソースを整理しました。画面表示・UIと内部ロジックをできるだけ分離し、またクラス間の結合も粗になるように修正しました。

  • 画面表示・UI : FormMainクラス, Kifuクラス
  • 内部ロジック : Engineクラス, Position構造体, Move構造体, Board構造体, DaiPunchクラス

KCSharp ver 1.1 をリリース

機能追加
  • 直前の着手を示す矢印を、先手(黒)と後手(白)で色分け
変更
  • 大パンチ判定をFormMainクラスからDaiPunchクラスに分離
  • Board構造体からKifuクラスへの依存を排除
  • 不要なコードの削除、定数名の変更などソースの整理

ソース

組込み屋でもアプリがしたい!【形四】 第7局

無駄なメモリ消費を低減

画面を更新するたびに無駄にBitmapオブジェクトを生成してメモリ使用量が増大していたのを、最初に生成したBitmapオブジェクトを使い回すように修正しました。

アルゴリズムの最適化

無駄に同じ計算を繰り返している箇所のメモ化や、頻繁に発生する除算・剰余のテーブル化など、高速化の工夫をほどこしました。

正式バージョンをリリース!

正式バージョンとして v1.0 をリリースしました。

組込み屋でもアプリがしたい!【形四】 第6局

UIの機能追加とバグ修正

本家の「形四96番勝負」とほぼ同等となるように機能を追加しました。
具体的には「戻る」/「進む」ボタンの追加と、大パンチ/大ピンチの表示、および96番勝負のデータです。


KCSharp ver 0.6

機能追加
  • 戻る/進む ボタンを追加
  • 大パンチ/大ピンチの表示を追加
  • 96番勝負のデータを追加
バグ修正
  • UI操作の不整合を修正

ソースはこちら