Kogin - 津軽こぎん刺しと南部菱刺し用図案描写ソフト

津軽こぎん刺しと南部菱刺し用図案描写専用ソフトです。

https://github.com/hanya/kogin

ダウンロードはリリースより https://github.com/hanya/kogin/releases

お試し用のウェブ版は以下より https://hanya.github.io/kogin/src/index.html

図案例

Koginで作成した図案データはSVG画像としてデータを含む形で保存できます。SVG画像はブラウザなどで表示できます。また、データを含む画像ファイルをKoginで読み込むと編集できます。

以下のような図案が作成できます。

{ "output-screen": { "noData": false, "useXLink": true, "gridNumber": false, "monochrome": false, "setBackground": true, "backgroundColor": "#ffffff", "strokeWidth": 16, "leftMargin": 1, "rightMargin": 1, "topMargin": 1, "bottomMargin": 1, "showTitle": false, "showCopyright": false, "lineGrainLineWidth": 8, "overGrainLineWidth": 8, "overWarpLineWidth": 8, "overGrainOffsetRatio": 0.1, "overWarpOffsetRatio": 0.1 }, "output-print": { "noData": false, "useXLink": true, "gridNumber": false, "monochrome": false, "setBackground": false, "backgroundColor": "#ffffff", "strokeWidth": 2, "leftMargin": 1, "rightMargin": 1, "topMargin": 1, "bottomMargin": 1, "showTitle": true, "showCopyright": true, "lineGrainLineWidth": 2, "overGrainLineWidth": 2, "overWarpLineWidth": 2, "overGrainOffsetRatio": 0.1, "overWarpOffsetRatio": 0.1 }, "grid-screen": { "showGrid": true, "overGrid": false, "horiCount": 100, "vertCount": 50, "gridWidth": 14, "gridHeight": 18, "gridLineWidth": 1, "gridLineColor": "#00000020", "gridMajorLineColor": "#00000050", "gridMajorLineFrequency": 5, "gridMajorVertOffset": 1, "gridMajorHoriOffset": 1, "showGridMajorLine": true, "showGridFrame": true, "numberingColor": "#00000050" }, "grid-print": { "showGrid": true, "overGrid": false, "horiCount": 100, "vertCount": 50, "gridWidth": 4, "gridHeight": 5, "gridLineWidth": 0.15, "gridLineColor": "#999999", "gridMajorLineColor": "#000000", "gridMajorLineFrequency": 5, "gridMajorVertOffset": 1, "gridMajorHoriOffset": 1, "showGridMajorLine": true, "showGridFrame": true, "numberingColor": "#000000" }, "bounds": { "useOutputBounds": false, "boundsLeft": 45, "boundsRight": 93, "boundsTop": 24, "boundsBottom": 51 }, "pdf-export": { "useOutputBounds": false, "gridNumber": true, "pageSize": "A4", "landscape": false, "leftMargin": 10, "rightMargin": 10, "topMargin": 17, "bottomMargin": 12 }, "view": { "viewMode": 3, "crosshair": false, "oneToOne": false, "oneToTwo": false, "stitchColor": "#000000", "selectionColor": "#000000ff", "cursorColor": "#ff0000ff", "overlayStitchColor": "#999999", "pivotColor": "#ff0000", "openFromToolbar": "storage", "saveFromToolbar": "templates", "askWhenClosing": false, "zoomValue": 1 } } {"application":"kogin","data":[{"layer":true,"name":"Layer 1","visible":true,"locked":false,"x":0,"y":0,"children":[{"x":1,"y":1,"children":[{"ref":"2-000000","coords":[[14,0],[14,14]]},{"ref":"6-000000","coords":[[12,1],[12,13]]},{"ref":"4-000000","coords":[[10,2],[16,2],[8,3],[18,3],[6,4],[20,4],[4,5],[22,5],[2,6],[24,6],[0,7],[26,7],[2,8],[24,8],[4,9],[22,9],[6,10],[20,10],[8,11],[18,11],[10,12],[16,12]]}]},{"ref":"6-000000","coords":[[9,8],[17,8]]},{"ref":"4-000000","coords":[[11,9],[11,7],[17,9],[17,7]]},{"ref":"2-000000","coords":[[17,10],[13,10],[13,6],[17,6],[15,11],[15,5]]}]}],"defs":{"single":[{"length":"2","colors":["#000000"]},{"length":"4","colors":["#000000"]},{"length":"6","colors":["#000000"]}]},"pivots":[[1,8],[15,15],[31,8],[15,1]],"bbox":[1,1,30,15]} { "title": "型コ 15", "title-en": "katako 15", "creationDate": "2022-11-17 14:01", "author": "", "license": "", "keyword": "", "description": "", "version": "", "copyright": "", "type": "" }

一部だけ表示するような図案も作成できます。

{ "output-screen": { "noData": false, "useXLink": true, "gridNumber": false, "monochrome": false, "setBackground": true, "backgroundColor": "#ffffff", "strokeWidth": 16, "leftMargin": 1, "rightMargin": 1, "topMargin": 1, "bottomMargin": 1, "showTitle": false, "showCopyright": false, "lineGrainLineWidth": 8, "overGrainLineWidth": 8, "overWarpLineWidth": 8, "overGrainOffsetRatio": 0.1, "overWarpOffsetRatio": 0.1 }, "output-print": { "noData": false, "useXLink": true, "gridNumber": false, "monochrome": false, "setBackground": false, "backgroundColor": "#ffffff", "strokeWidth": 2, "leftMargin": 1, "rightMargin": 1, "topMargin": 1, "bottomMargin": 1, "showTitle": false, "showCopyright": false, "lineGrainLineWidth": 2, "overGrainLineWidth": 2, "overWarpLineWidth": 2, "overGrainOffsetRatio": 0.1, "overWarpOffsetRatio": 0.1 }, "grid-screen": { "showGrid": true, "overGrid": false, "horiCount": 100, "vertCount": 50, "gridWidth": 14, "gridHeight": 18, "gridLineWidth": 1, "gridLineColor": "#00000020", "gridMajorLineColor": "#00000050", "gridMajorLineFrequency": 5, "gridMajorVertOffset": 1, "gridMajorHoriOffset": 1, "showGridMajorLine": true, "showGridFrame": true, "numberingColor": "#00000050" }, "grid-print": { "showGrid": true, "overGrid": false, "horiCount": 100, "vertCount": 50, "gridWidth": 4, "gridHeight": 5, "gridLineWidth": 0.15, "gridLineColor": "#bbbbbb", "gridMajorLineColor": "#000000", "gridMajorLineFrequency": 5, "gridMajorVertOffset": 1, "gridMajorHoriOffset": 1, "showGridMajorLine": true, "showGridFrame": true, "numberingColor": "#000000" }, "bounds": { "useOutputBounds": true, "boundsLeft": 10, "boundsRight": 42, "boundsTop": 25, "boundsBottom": 41 }, "pdf-export": { "useOutputBounds": false, "gridNumber": true, "pageSize": "A4", "landscape": false, "leftMargin": 10, "rightMargin": 10, "topMargin": 17, "bottomMargin": 12, "multibyteFont": "/usr/share/fonts/opentype/ipafont-gothic/ipag.ttf" }, "view": { "viewMode": 3, "crosshair": false, "oneToOne": false, "oneToTwo": false, "stitchColor": "#000000", "selectionColor": "#000000ff", "cursorColor": "#ff0000ff", "overlayStitchColor": "#999999", "pivotColor": "#ff0000", "openFromToolbar": "local", "saveFromToolbar": "templates-save-as", "askWhenClosing": false, "zoomValue": 1, "autoScrollOnTemplates": true } } {"application":"kogin","data":[{"layer":true,"name":"Layer 1","visible":true,"locked":false,"x":0,"y":0,"children":[{"x":9,"y":40,"children":[{"x":1,"y":1,"children":[{"ref":"2-000000","coords":[[14,0],[14,14]]},{"ref":"6-000000","coords":[[12,1],[12,13]]},{"ref":"4-000000","coords":[[10,2],[16,2],[8,3],[18,3],[6,4],[20,4],[4,5],[22,5],[2,6],[24,6],[0,7],[26,7],[2,8],[24,8],[4,9],[22,9],[6,10],[20,10],[8,11],[18,11],[10,12],[16,12]]}]},{"ref":"6-000000","coords":[[9,8],[17,8]]},{"ref":"4-000000","coords":[[11,9],[11,7],[17,9],[17,7]]},{"ref":"2-000000","coords":[[17,10],[13,10],[13,6],[17,6],[15,11],[15,5]]}]},{"x":-7,"y":32,"children":[{"x":1,"y":1,"children":[{"ref":"2-000000","coords":[[14,0],[14,14]]},{"ref":"6-000000","coords":[[12,1],[12,13]]},{"ref":"4-000000","coords":[[10,2],[16,2],[8,3],[18,3],[6,4],[20,4],[4,5],[22,5],[2,6],[24,6],[0,7],[26,7],[2,8],[24,8],[4,9],[22,9],[6,10],[20,10],[8,11],[18,11],[10,12],[16,12]]}]},{"ref":"6-000000","coords":[[9,8],[17,8]]},{"ref":"4-000000","coords":[[11,9],[11,7],[17,9],[17,7]]},{"ref":"2-000000","coords":[[17,10],[13,10],[13,6],[17,6],[15,11],[15,5]]}]},{"x":-23,"y":24,"children":[{"x":1,"y":1,"children":[{"ref":"2-000000","coords":[[14,0],[14,14]]},{"ref":"6-000000","coords":[[12,1],[12,13]]},{"ref":"4-000000","coords":[[10,2],[16,2],[8,3],[18,3],[6,4],[20,4],[4,5],[22,5],[2,6],[24,6],[0,7],[26,7],[2,8],[24,8],[4,9],[22,9],[6,10],[20,10],[8,11],[18,11],[10,12],[16,12]]}]},{"ref":"6-000000","coords":[[9,8],[17,8]]},{"ref":"4-000000","coords":[[11,9],[11,7],[17,9],[17,7]]},{"ref":"2-000000","coords":[[17,10],[13,10],[13,6],[17,6],[15,11],[15,5]]}]},{"x":25,"y":32,"children":[{"x":1,"y":1,"children":[{"ref":"2-000000","coords":[[14,0],[14,14]]},{"ref":"6-000000","coords":[[12,1],[12,13]]},{"ref":"4-000000","coords":[[10,2],[16,2],[8,3],[18,3],[6,4],[20,4],[4,5],[22,5],[2,6],[24,6],[0,7],[26,7],[2,8],[24,8],[4,9],[22,9],[6,10],[20,10],[8,11],[18,11],[10,12],[16,12]]}]},{"ref":"6-000000","coords":[[9,8],[17,8]]},{"ref":"4-000000","coords":[[11,9],[11,7],[17,9],[17,7]]},{"ref":"2-000000","coords":[[17,10],[13,10],[13,6],[17,6],[15,11],[15,5]]}]},{"x":9,"y":24,"children":[{"x":1,"y":1,"children":[{"ref":"2-000000","coords":[[14,0],[14,14]]},{"ref":"6-000000","coords":[[12,1],[12,13]]},{"ref":"4-000000","coords":[[10,2],[16,2],[8,3],[18,3],[6,4],[20,4],[4,5],[22,5],[2,6],[24,6],[0,7],[26,7],[2,8],[24,8],[4,9],[22,9],[6,10],[20,10],[8,11],[18,11],[10,12],[16,12]]}]},{"ref":"6-000000","coords":[[9,8],[17,8]]},{"ref":"4-000000","coords":[[11,9],[11,7],[17,9],[17,7]]},{"ref":"2-000000","coords":[[17,10],[13,10],[13,6],[17,6],[15,11],[15,5]]}]},{"x":-7,"y":16,"children":[{"x":1,"y":1,"children":[{"ref":"2-000000","coords":[[14,0],[14,14]]},{"ref":"6-000000","coords":[[12,1],[12,13]]},{"ref":"4-000000","coords":[[10,2],[16,2],[8,3],[18,3],[6,4],[20,4],[4,5],[22,5],[2,6],[24,6],[0,7],[26,7],[2,8],[24,8],[4,9],[22,9],[6,10],[20,10],[8,11],[18,11],[10,12],[16,12]]}]},{"ref":"6-000000","coords":[[9,8],[17,8]]},{"ref":"4-000000","coords":[[11,9],[11,7],[17,9],[17,7]]},{"ref":"2-000000","coords":[[17,10],[13,10],[13,6],[17,6],[15,11],[15,5]]}]},{"x":41,"y":24,"children":[{"x":1,"y":1,"children":[{"ref":"2-000000","coords":[[14,0],[14,14]]},{"ref":"6-000000","coords":[[12,1],[12,13]]},{"ref":"4-000000","coords":[[10,2],[16,2],[8,3],[18,3],[6,4],[20,4],[4,5],[22,5],[2,6],[24,6],[0,7],[26,7],[2,8],[24,8],[4,9],[22,9],[6,10],[20,10],[8,11],[18,11],[10,12],[16,12]]}]},{"ref":"6-000000","coords":[[9,8],[17,8]]},{"ref":"4-000000","coords":[[11,9],[11,7],[17,9],[17,7]]},{"ref":"2-000000","coords":[[17,10],[13,10],[13,6],[17,6],[15,11],[15,5]]}]},{"x":25,"y":16,"children":[{"x":1,"y":1,"children":[{"ref":"2-000000","coords":[[14,0],[14,14]]},{"ref":"6-000000","coords":[[12,1],[12,13]]},{"ref":"4-000000","coords":[[10,2],[16,2],[8,3],[18,3],[6,4],[20,4],[4,5],[22,5],[2,6],[24,6],[0,7],[26,7],[2,8],[24,8],[4,9],[22,9],[6,10],[20,10],[8,11],[18,11],[10,12],[16,12]]}]},{"ref":"6-000000","coords":[[9,8],[17,8]]},{"ref":"4-000000","coords":[[11,9],[11,7],[17,9],[17,7]]},{"ref":"2-000000","coords":[[17,10],[13,10],[13,6],[17,6],[15,11],[15,5]]}]},{"x":9,"y":8,"children":[{"x":1,"y":1,"children":[{"ref":"2-000000","coords":[[14,0],[14,14]]},{"ref":"6-000000","coords":[[12,1],[12,13]]},{"ref":"4-000000","coords":[[10,2],[16,2],[8,3],[18,3],[6,4],[20,4],[4,5],[22,5],[2,6],[24,6],[0,7],[26,7],[2,8],[24,8],[4,9],[22,9],[6,10],[20,10],[8,11],[18,11],[10,12],[16,12]]}]},{"ref":"6-000000","coords":[[9,8],[17,8]]},{"ref":"4-000000","coords":[[11,9],[11,7],[17,9],[17,7]]},{"ref":"2-000000","coords":[[17,10],[13,10],[13,6],[17,6],[15,11],[15,5]]}]}]}],"defs":{"single":[{"length":"2","colors":["#000000"]},{"length":"4","colors":["#000000"]},{"length":"6","colors":["#000000"]}]},"pivots":[],"bbox":[-22,9,94,47]} { "title": "", "title-en": "", "creationDate": "2023-01-08 10:04", "author": "", "license": "", "keyword": "", "description": "", "version": "", "copyright": "", "type": "" }

マニュアル等

テンプレートレポジトリ

テンプレートを外部の github や gitlab から読み込むことが出来ます。

以下の型コテンプレートレポジトリから読み込むには、テンプレートウィンドウの場所追加ウィンドウに次のように入力します。 https://github.com/hanya/katako

ユーザー: hanya
レポジトリ: katako

レポジトリのディレクトリ内だけを追加したいときは、サブディレクトリも入力してください。

テンプレートの保存場所

作成して保存したテンプレートファイルはユーザーの設定ディレクトリに保存されます。

Windows
User\ユーザー名\AppData\kogin

Linux
~/.config/kogin

Rust で重み付き抽選

重み付き抽選とは、ゲームのアイテムドロップの判定などに使われる選択手法です。

それぞれの選択率がリンゴ (50%)、みかん (20%)、柿 (20%)の場合、この確率に従って乱数で選びます。

Rust では rand クレートの WeightedIndex や rand_distr クレートの WeightedAliasIndex を利用できます。

rand::distributions::WeightedIndex

選択時の計算量は O(log N) です。N は要素数。つまり、要素数が多いと急に遅くなります。初期化時の計算量は O(N) です。

一度のサンプリングで乱数を1つ消費します。

コードより要素数とメモリ使用量の関係を調べます。

// https://docs.rs/rand/0.8.4/src/rand/distributions/weighted_index.rs.html#81-85

pub struct WeightedIndex<X: SampleUniform + PartialOrd> {
    cumulative_weights: Vec<X>,
    total_weight: X,
    weight_distribution: X::Sampler,
}

X は重みを指定する値の型です。
cumulative_weights のサイズは要素数と同じです。つまり、メモリ量は O(N) です。

rand_distr::weighted_alias::WeightedAliasIndex

選択時の計算量は O(1) です。初期化時の計算量は O(N) です。要素数が多いと事前に用意するデータが大きくなりメモリ消費量が増えます。

一度のサンプリングで乱数を2つ消費します。

同様にコードを確認します。

// https://docs.rs/rand_distr/0.4.2/src/rand_distr/weighted_alias.rs.html#72-77

pub struct WeightedAliasIndex<W: AliasableWeight> {
    aliases: Box<[u32]>,
    no_alias_odds: Box<[W]>,
    uniform_index: Uniform<u32>,
    uniform_within_weight_sum: Uniform<W>,
}

W は重みを指定する数値の型です。
no_alias_odds の要素数は N です。
aliases の要素数は N なので(ドキュメントより)、WeightedIndex とのメモリ量の差は sizeof(u32) * N です。

乱数の使用数調査

コードを見ると WeightedAliasIndex は一度のサンプリングで2つの乱数を消費しているようなので、以下のようにして乱数の消費数を調べます。

use rand::Rng;
use rand::distributions::{Distribution, WeightedIndex};
use rand_core::{Error, RngCore, SeedableRng};
use rand_pcg::Lcg64Xsh32;
use rand_distr::weighted_alias::WeightedAliasIndex;

/// Couting wrapper.
struct CountRnd {
    rng: Lcg64Xsh32,
    count_u32: usize,
}

impl CountRnd {
    pub fn new(seed: u64) -> Self {
        Self {
            rng: Lcg64Xsh32::seed_from_u64(seed),
            count_u32: 0,
        }
    }

    pub fn count_u32(&self) -> usize {
        self.count_u32
    }

    pub fn reset_count(&mut self) {
        self.count_u32 = 0;
    }
}

impl RngCore for CountRnd {
    fn next_u32(&mut self) -> u32 {
        self.count_u32 += 1;
        self.rng.next_u32()
    }

    fn next_u64(&mut self) -> u64 {
        self.rng.next_u64()
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        self.rng.fill_bytes(dest)
    }

    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        self.rng.try_fill_bytes(dest)
    }
}


fn main() {
    let mut rng = CountRnd::new(1234);

    let items = ['a', 'b', 'c'];
    let weights = [20, 10, 10];

    let dist = WeightedIndex::new(&weights.clone()).unwrap();
    for _ in 0..100 {
        let _i = items[dist.sample(&mut rng)];
    }
    println!("count: {}", rng.count_u32()); // 100
    rng.reset_count();


    let dist = WeightedAliasIndex::new(weights.to_vec()).unwrap();
    for _ in 0..100 {
        let _i = items[dist.sample(&mut rng)];
    }
    println!("count: {}", rng.count_u32()); // 200
}

二倍消費していることが分かります。

Rust では乱数を使用するときによく使われるクレートに重み付き抽選が実装されています。
抽選対象の確率から分布が作成され、その分布に与えられた乱数から抽選されます。
RngCore トレイトを実装している乱数生成器ならどれでも使用できます。

高速に判定したい場合はメモリの使用量に問題なければ WeightedAliasIndex を使えます。
しかし、一度のサンプリングで乱数を2つ消費したくなければ WeightedIndex を使いましょう。

RPi pico ハードウェア

Rpi pico の回路図をみながらパッドに引き出されていないピンなどを調べる。

ピンアウト

RP2040 MCU は GPIO 0-29 あるが一部のピンはパッドに引き出されていない。表にまとめた。テストポイントについて同時に記載した。

ピン TP 説明
GPIO23 TP4 レギュレータ PS 端子
GPIO24 - 分圧済みVBUS
GPIO25 TP5 緑 LED
GPIO29 - ADC3 VSYS/3 ※
- TP1 GND
USB_DM TP2 USB_DM
USB_DP TP3 USB_DP
- TP6 BOOTSEL

GPIO24 は USB OVCUR DET 機能を持つ。つまりデバイスモードで USB DET として使えないため、自分で検出する必要がある。

※ VSYS が供給されていて 3V3 が供給されないとき (3V3_EN LOW)、GPIO29_ADC3 のダイオードからのリークを減らすために使用。

レギュレータ

RT6150B-33GQW が載っている。Back-Boost コンバータなので 1.8-5.5V の範囲を供給すると 3.3V を出力する。昇圧、降圧共に可能。

USB コネクタの VBUS とレギュレータ入力の間にダイオードが入っているため、低圧の供給は VSYS からがよい。

EN ピンが HIGH で有効、LOW で無効。3V3_EN パッドにとして引き出されている。3V3 パッドから電源を供給して Pico のレギュレータを停止させたいときなどに使える。

PS モード 説明
0 PFM 出力全体でおよそ効率が良い
1 PWM リップルが少ないが低出力で効率が悪い

データシート[1]によると効率は以下のようになっている。

20210816114541

左図の PFM モードでは低電流 (1-60 mA) では効率が 67-73% である。
右図の PWM モードでは低電流で効率が 77% 未満に収まっている。
それ以上の出力電流でもさほどの差は見られない。そのため、リップルが問題にならなければ PFM モードでよい。

ADC などでリップルが問題になる場合、変換中のみ PWM モードに切り替えるとよい (4.3. Using the ADC [2] 参照)。

[1]: https://www.richtek.com/assets/product_file/RT6150A=RT6150B/DS6150AB-06.pdf
[2]: https://datasheets.raspberrypi.org/pico/pico-datasheet.pdf#%5B%7B%22num%22%3A20%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C115%2C359.05%2Cnull%5D

GDB Python スクリプトでビットを表示

マイコンではレジスタでビットフラグが多用されているが、慣れていないと gdb の x コマンドでメモリの値を読み出してもどのビットがセットされているか分かりにくい。

GDB Python スクリプトでなんとかできそうだったが情報が少なかったので残しておく。

Python スクリプトから GDB の機能を実行する方法は以下に記載がある。

Python コード埋め込み

gdbinit ファイルを -x オプションで読み込むと、設定や独自の定義のコマンドが利用できる。

この設定ファイルに Python のコードを埋め込める。python ... end の間に Python のコードを書ける。

python
# Python code
end

Python コード実行

python 命令で Python のコードを実行できる。

python call_func()

定義コマンドの中で実行するなら引数を渡すこともできる。

define xbits
    python bits($arg0)
end

引数は $arg0, $arg1, ... など。

ビット表示

アドレスを引数として受け取るとそのアドレスの値を x コマンドの出力から得て、ビットとして表示する xbits およびそのエイリアス xt を作成した。

python

def _bits_extend(value, max, min):
    vs = []
    vs.append("")
    for i in range(min, max + 1)[::-1]:
        if (value & (1 << i)) > 0:
            vs.append(" 1")
        else:
            vs.append(" 0")
    vs.append("")
    return "|".join(vs)

def bits(arg0):
    addr, tvalue = gdb.execute('x {}'.format(arg0), to_string=True).rstrip().split("\t")
    value = int(tvalue, 16)
    s = []
    s.append("{}\t{}".format(addr, tvalue))
    s.append("|31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|")
    s.append(_bits_extend(value, 31, 16))
    #s.append("")
    s.append("|15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0|")
    s.append(_bits_extend(value, 15, 0))
    print("\n".join(s))

end


define xbits
    python bits($arg0)
end

alias -a xt = xbits

実行結果

(gdb) xt 0x50110000
0x50110000:	0x00000000
|31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|
| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0|
|15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0|
| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0|

このように各ビットがひと目で分かる。

ブラウザでビットフラグを表示

数値をビットに展開して表示するページを作成しました。10進数および0xから始まる16進数を入力できます。

bs2_default_padded_checksummed.S の作り方

2nd ブートファイルをフラッシュの先頭に置いてブートさせる場合、pico-sdk 以外から bs2_default_padded_checksummed.S ファイルを使用したい場合があります。
以下のようにしてビルドできます。

cd pico-sdk
mkdir build
cd build
cmake ..
#cd src/rp2_common/boot_stage2
make bs2_default_padded_checksummed_asm

pico-sdk/build/src/rp2_common/boot_stage2/bs2_default_padded_checksummed.S にファイルが作成されます。リンク時に指定します。

このようにリンク先のターゲット無しでビルドすると boot2_generic_03h.S ファイルがコンパイルされます。

make 時にターゲットとして bs2_default_padded_checksummed_asm を指定しないと bin ファイルや S ファイルは生成されません。

RP2040 PIO レジスタと Pico SDK 覚え書き

詳細はデータシート参照のこと

レジスタと対応する SDK の関数たち。

レジスタと関連なし

    • pio0
      • pio ブロック 0
    • pio1
      • pio ブロック 1
    • pio_get_default_sm_config
      • デフォルト値を持つ pio_sm_config 構造体を返す
    • pio_sm_set_config
      • ステートマシンの設定をステートマシンに適用する
    • pio_get_index
    • pio_gpio_init
      • 出力のために GPIO を設定する
      • output に必要だ
      • input のみなら設定しなくてもステートマシンからピンの状態を読み出せる
    • pio_get_dreq
      • TX または RX の DREQ (Data Request) を返す
      • DREQ は System DREQ Table (RP2040 リファレンス参照) で定義されている番号
    • pio_sm_claim
      • ステートマシンに印をつける。すでに印がついている場合はパニックする
      • ライブラリで同時使用などを検出するために利用できる
      • レジスタと関係なし
    • pio_claim_sm_mask
      • マスクで指定したステートマシンに印をつける
      • レジスタと関係なし
    • pio_sm_unclaim
    • pio_claim_unused_sm
      • 印がついていないステートマシンを探す
      • すべてのステートマシンが使用されている場合に引数でパニックさせることもできる
      • レジスタと関係なし
    • pio_sm_is_claimed
      • 印がついているかどうか確認する
      • レジスタと関係なし

CTRL

  • CTRL
    • PIO コントロールレジスタ
    • ステートマシンごとに指定できる
    • CLKDIV_RESTART
      • ステートマシンの動作クロックを再起動
    • SM_RESTART
      • ステートマシンを初期化して再起動
    • SM_ENABLE
      • ステートマシンの有効/無効を切り替え
    • pio_sm_init
      • ステートマシンを初期化する
    • pio_sm_set_enabled
      • 指定したステートマシンを有効/無効にする
    • pio_set_sm_mask_enabled
      • マスクで指定したステートマシンを有効/無効にする
    • pio_enable_sm_mask_in_sync
      • マスクで指定したステートマシンを同期して開始する
      • pio_set_sm_mask_enabled の次に pio_clkdiv_restart_sm_mask を呼ぶのと同じ結果
    • pio_sm_restart
      • 指定したステートマシンを再起動する
      • ステートマシンの状態は初期化される
    • pio_restart_sm_mask
      • マスクで指定したステートマシンを再起動する
    • pio_sm_clkdiv_restart
      • クロック分割器を再起動する
    • pio_clkdiv_restart_sm_mask
      • 複数のステートマシンのクロック分割器を再起動する
      • 複数のステートマシンを同期させられる

FSTAT

  • FSTAT
    • FIFO ステータスレジスタ
    • ステートマシンごとにステータスが確認できる
    • TXEMPTY
      • TX が空
    • TXFULL
      • TX が一杯
    • RXEMPTY
      • RX が空
    • RXFULL
      • RX が一杯
    • pio_sm_is_rx_fifo_full
      • RX FIFO が一杯かどうか確認する
    • pio_sm_is_rx_fifo_empty
      • RX FIFO が空かどうか確認する
    • pio_sm_get_rx_fifo_level
    • pio_sm_is_tx_fifo_full
      • TX FIFO が一杯かどうか確認する
    • pio_sm_is_tx_fifo_empty
      • TX FIFO が空かどうか確認する
    • pio_sm_get_tx_fifo_level

FDEBUG

  • FDEBUG
    • FIFO デバッグレジスタ
    • 1 を書き込んでクリアできる。
    • TXSTALL
      • ブロック PULL またはオートプルが有効の OUT により TX FIFO が空でストール中
    • TXOVER
      • TX FIFO がオーバーフロー。
    • RXUNDER
      • RX FIFO がアンダーフロー。
    • RXSTALL
      • ブロック PULL またはオートプッシュが有効の IN により RX FIFO が一杯でストール中

FLEVEL

  • FLEVEL
    • FIFO レベル
    • FIFO の埋まり具合
    • RX3, TX3, RX2, TX2, RX1, TX1, RX0, TX0

TXF0, TXF1, TXF2, TXF3

  • TXF0, TXF1, TXF2, TXF3
    • TX FIFO へのアクセス
    • 一杯の FIFO への書き込みは無効で FDEBUG_TXOVER エラーフラグがセットされる
    • pio_sm_put
      • TX FIFO に書き込む、何も確認しない
    • pio_sm_put_blocking
      • TX FIFO に書き込む、一杯の場合は空きができるまで待つ
    • pio_sm_get
      • RX FIFO から読み出す、何も確認しない、空の RX FIFO から読み出した場合の動作は未定義
    • pio_sm_get_blocking
      • RX FIFO から読み出す、空の場合はデータが入ってくるまで待つ
    • pio_sm_drain_tx_fifo
      • TX FIFO を空にする
      • TX FIFO が空になるまで PULL 命令を実行する

RXF0, RXF1, RXF2, RXF3

  • RXF0, RXF1, RXF2, RXF3
    • RX FIFO へのアクセス
    • 空の FIFO からの読み込みは無効で FDEBUG_RXUNDER エラーフラグがセットされる
    • 空の FIFO を読み出した結果は未定義

IRQ

  • IRQ
    • ステートマシン IRQ フラグレジスタ。1 を書き込んでクリアできる。
    • ステートマシンと IRQ フラグの関連性はなく、どのステートマシンもすべての IRQ フラグにアクセスできる。
    • 下位 4 つの IRQ はシステムの割り込みに設定できる。
    • pio_interrupt_get
      • 指定した IRQ がセットされているかどうか返す
    • pio_interrupt_clear
      • 指定した IRQ をクリアする

IRQ_FORCE

  • IRQ_FORCE
    • 1 を書き込むとそのビットに相当する IRQ がアサートされる。
    • INTF レジスタとは別で、INTF はステートマシンから見えない。
    • レジスタタイプが WF (書き込みフィールド) のため読み出し不可、操作のためのフィールド

INPUT_SYNC_BYPASS

  • INPUT_SYNC_BYPASS
    • GPIO 入力の 2-フリップフロップ同期回路をバイパスする。
    • 同期しつつ相当高速にしたい場合に使用する。

DBG_PADOUT

  • DBG_PADOUT
    • 現在 PIO が駆動している GPIO の状態を読み出す。

DBG_PADOE

  • DBG_PADOE
    • 現在 PIO の出力が有効な (方向) GPIO の状態を読み出す。

DBG_CFGINFO

  • DBG_CFGINFO
    • チップごとに異なるパラメータ
    • IMEM_SIZE
      • 命令メモリのサイズ
    • SM_COUNT
      • PIO ブロックごとのステートマシン数
    • FIFO_DEPTH
      • TX/RX FIFO の深さ。FIFO を統合するとこの数値の2倍

INSTR_MEM0, INSTR_MEM1, ... INSTR_MEM30, INSTR_MEM31

  • INSTR_MEM0, INSTR_MEM1, ... INSTR_MEM30, INSTR_MEM31
    • 命令メモリ、書き込み専用
    • pio_can_add_program
      • 指定のプログラムが命令メモリに入るかどうか確認する
    • pio_can_add_program_at_offset
      • 指定のプログラムが命令メモリの指定の位置からメモリに入るかどうか確認する
    • pio_remove_program
      • 命令メモリからオフセットを開始位置として指定のプログラムを削除する
    • pio_clear_instruction_memory
      • 命令メモリを空にする

SM0_CLKDIV, SM1_CLKDIV, SM2_CLKDIV, SM3_CLKDIV

  • SM0_CLKDIV, SM1_CLKDIV, SM2_CLKDIV, SM3_CLKDIV
    • クロック分割レジスタ
    • 周波数 = クロック周波数 / (CLKDIV_INT + CLKDIV_FRAC / 256)
    • INT
      • 整数部。0 は 65536 とみなされる。INT が 0 の時は FRAC もゼロのこと
    • FRAC
      • 小数部
    • sm_config_set_clkdiv_int_frac
      • クロック分割の整数部と小数部を設定する
    • sm_config_set_clkdiv
      • クロック分割を設定する、整数部と小数部に分割して設定される
    • pio_sm_set_clkdiv_int_frac
      • クロック分割の整数部と小数部を設定する
    • pio_sm_set_clkdiv
      • クロック分割を設定する、整数部と小数部に分割して設定される

SM0_EXECCTRL, SM1_EXECCTRL, SM2_EXECCTRL, SM3_EXECCTRL

  • SM0_EXECCTRL, SM1_EXECCTRL, SM2_EXECCTRL, SM3_EXECCTRL
    • 動作と挙動設定
    • EXEC_STALLED
      • 1 のとき、SMx_INSTR に書き込まれた命令がストール
    • SIDE_EN
      • 1 のとき、Delay/Side-set フィールドの MSB がサイドセットの有効/無効を表す
      • サイドセットをオプションにできるが、サイドセットのビット数が減る
    • SIDE_PINDIR
      • 1 のとき、データはピンの方向指定となる (このとき、ピンの値の設定はできない、どちらか一方のみ)
    • JMP_PIN
    • OUT_EN_SEL
      • インライン OUT を有効にするためのデータビットを指定
    • INLINE_OUT_EN
      • 1 のとき、データの 1 つのビットを補助的な書き込み有効設定に使用する。
      • 複数のステートマシンが同時に同じピンに出力する場合、インラインアウト指定になっているステートマシンからの出力が、インラインアウト指定なしのステートマシンからの出力より優先される。
      • 複数のステートマシンでインラインアウトが指定されている場合、ステートマシン番号の大きな方が優先される。これはインラインアウトの指定の無い場合の優先順位と同じ。
      • https://www.raspberrypi.org/forums/viewtopic.php?t=313962
    • OUT_STICKY
      • OUT_EN_SELで指定したビットがゼロでも、インラインアウトで最後に指定されたピンへの OUT/SET が継続的にアサートされる
    • WRAP_TOP
      • WRAP_TOP は終了インデックス。WRAP_BOTTOM との間を繰り返す
      • 命令がジャンプの場合、ジャンプの条件が真ならジャンプが優先される
      • pioasm では .wrap_target で生成される
    • WRAP_BOTTOM
      • WRAP_BOTTOM は開始インデックス。WRAP_TOP との間を繰り返す
      • pioams では .wrap で生成される
    • STATUS_SEL
      • MOV x, STATUS 命令で比較される
      • 0x0: TX FIFO レベル < N ならすべて 1、他はすべてゼロ
      • 0x1: RX FIFO レベル < N ならすべて 1、他はすべてゼロ
    • STATUS_N
      • 比較用 N
    • sm_config_set_out_special
      • 特別な OUT 動作について設定する
    • sm_config_set_wrap
      • ラップアドレスを設定する
    • sm_config_set_jmp_pin
      • JMP PIN で使用される GPIO ピンを設定する
      • ピンは絶対番号で指定する、ピンマッピングのベースに影響を受けない
    • sm_config_set_mov_status
      • MOV STATUS で使用する条件と N を設定する
    • pio_sm_is_exec_stalled
      • pio_sm_exec で実行された命令がストール状態かどうか返す
    • pio_sm_set_wrap
      • ラップアドレスを設定する

SM0_SHIFTCTRL, SM1_SHIFTCTRL, SM2_SHIFTCTRL, SM3_SHIFTCTRL

  • SM0_SHIFTCTRL, SM1_SHIFTCTRL, SM2_SHIFTCTRL, SM3_SHIFTCTRL
    • 入出力シフトレジスタの動作制御
    • FJOIN_RX
      • TX FIFO を RX FIFO にマージする。FIFO はクリアされる
    • FJOIN_TX
      • RX FIFO を TX FIFO にマージする。FIFO はクリアされる
    • PULL_THRESH
      • オートプルまたは条件付きプル (PULL IFEMPTY) 動作までにシフトアウトされるビット数。0 は 32 と解釈される
    • PUSH_THRESH
      • オートプッシュまたは条件付きプッシュ (PUSH IFFULL) 動作までにシフトインされるビット数。0 は 32 と解釈される
    • OUT_SHIFTDIR
      • 1 のとき右シフト、0 のとき左シフト
    • IN_SHIFTDIR
      • 1 のとき右シフト(データは左から入る)、0 のとき左シフト
    • AUTOPULL
      • 出力シフトレジスタが空になったとき、自動的にプルされる
      • OUT 命令で出力シフトカウンタが PULL_THRESH に到達または超えた時
    • AUTOPUSH
      • 入力シフトレジスタに入力があったとき、自動的にプッシュされる
      • IN 命令で入力シフトカウンタが PUSH_THRESH に到達または超えた時
    • sm_config_set_fifo_join
      • FIFO をマージ/マージ解除する
    • sm_config_set_in_shift
      • IN 命令でのシフトに関する設定を行う
      • シフト方向、オートプッシュやそのしきい値
    • sm_config_set_out_shift
      • OUT 命令でのシフトに関する設定を行う
      • シフト方向、オートプルやそのしきい値
    • pio_sm_clear_fifos
      • TX と RX FIFO の内容をクリアする
      • FJOIN_RX と FJOIN_TX レジスタ操作で実装されている

SM0_ADDR, SM1_ADDR, SM2_ADDR, SM3_ADDR

  • SM0_ADDR, SM1_ADDR, SM2_ADDR, SM3_ADDR
    • 現在の命令アドレス
    • pio_sm_get_pc
      • 現在のプログラムカウンタ (命令アドレス) を設定する
  • SM0_INSTR, SM1_INSTR, SM2_INSTR, SM3_INSTR
    • 現在ステートマシンに割り当てられている命令
    • このレジスタに書き込むとすぐに実行され、復帰する
    • pio_sm_exec
      • 命令を即座に実行する
    • pio_sm_exec_wait_blocking
      • 命令を即座に実行して完了するまで待つ

SM0_PINCTRL, SM1_PINCTRL, SM2_PINCTRL, SM3_PINCTRL

  • SM0_PINCTRL, SM1_PINCTRL, SM2_PINCTRL, SM3_PINCTRL
    • ステートマシンのピン制御
    • SIDESET_COUNT
      • サイドセットに使用する Delay/Side-set フィールドの MSB 側のビット数
      • 0 (すべてディレイ、サイドセットなし) から 5 (すべてサイドセット、ディレイなし)
    • SET_COUNT
      • SET でアサートされるピン数、0-5
    • OUT_COUNT
      • OUT PINS, OUT PINDIRS, MOV PINS 命令でアサートされるピン数、0-32
    • IN_BASE
      • ステートマシンの IN データバスの最下位ビットにマップされるピン
      • 上位のビットのピンは連続的にマップされる
      • ピン番号の 32 の剰余が使われるので、32 は 0 番ピン
    • SIDESET_BASE
      • サイドセットの一番小さな番号のピンを指定
      • サイドセット指定の最下位ビットがこのピンに相当する。より上位のビットはより大きな番号のピンに相当する
    • SET_BASE
      • SET PINS または SET PINDIRS 命令の一番小さな番号のピンを指定
      • このピンに書き込まれるのは SET のデータの最下位ビット
    • OUT_BASE
      • OUT PINS または OUT PINDIRS または MOV PINS 命令の一番小さな番号のピンを指定
      • このピンに書き込まれるデータは OUT または MOV のデータの最下位ビット
    • sm_config_set_out_pins
      • OUT ピンについて設定する
    • sm_config_set_set_pins
      • SET ピンについて設定する
    • sm_config_set_in_pins
      • IN ピンについて設定する
    • sm_config_set_sideset_pins
      • サイドセットピンについて設定する
    • sm_config_set_sideset
      • サイドセットについて設定する
      • サイドセットに使われるビット数、サイドセットがオプションかどうか、ピンの方向設定に使用するかどうか
    • pio_sm_set_out_pins
      • OUT ピンについて設定する
    • pio_sm_set_set_pins
      • SET ピンについて設定する
    • pio_sm_set_in_pins
      • IN ピンについて設定する
    • pio_sm_set_sideset_pins
      • サイドセットピンについて設定する
    • pio_sm_set_pins
      • すべての 32 ピンについて設定する
      • SET 命令で実行される
      • 初期値の設定に使用できる、実行中のステートマシンに対して使用すべきではない
    • pio_sm_set_pins_with_mask
      • マスクで選択したピンについて値を設定する、後はマスクしない pio_sm_set_pins 関数と同じ
    • pio_sm_set_pindirs_with_mask
      • マスクで選択したピンについてピンの方向を設定する
      • SET 命令で実行される
    • pio_sm_set_consecutive_pindirs
      • 連続したピンについてピンの方向を同じ方向に設定する
      • SET 命令で実行される

INTR

  • INTR
    • 割り込みソースの有効/無効

IRQ0_INTE

  • IRQ0_INTE
    • irq0 用の割り込み有効/無効

IRQ0_INTF

  • IRQ0_INTF
    • irq0 用の割り込み強制

IRQ0_INTS

  • IRQ0_INTS
    • irq0 用のマスクと強制の後のステータス

irq1 は省略。
PIO ブロックごとに irq0 と irq1 があり、これら2つはシステムの割り込み。
それぞれの irq はソースを選択できる。

    • pio_set_irq0_source_enabled
      • irq0 のソースのうち一つを有効/無効にする
    • pio_set_irq1_source_enabled
      • irq1 のソースのうち一つを有効/無効にする
    • pio_set_irq0_source_mask_enabled
      • irq0 のマスクで指定したソースすべてを有効/無効にする
    • pio_set_irq1_source_mask_enabled
      • irq1 のマスクで指定したソースすべてを有効/無効にする
    • pio_set_irqn_source_enabled
      • irqn のソースのうち一つを有効/無効にする
    • pio_set_irqn_source_mask_enabled
      • irqn のマスクで指定したソースすべてを有効/無効にする