RP2040 PIO 覚え書き
RP2040 データシートを読んだまとめ
https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf
元の文書は改変配布禁止ですので翻訳はできません。ただの覚え書きです。
レジスタタイプについての説明は Appendix A: Register Field Types にある。
目次
- PIO ブロックの概要
- レジスタ
- FIFO
- 自動プッシュと自動プル
- ピン割り当て
- サイドセット
- IRQ
- 入力同期
- ラッピング
- ストール
- 指令、ディレクティブ
- 値
- 式
- コメント
- ラベル
- 命令、インストラクション
- 疑似命令
- nop
- 動作クロック
- 命令実行
- 初期化
- 節約方法
- インラインアウト
PIO ブロックの概要
RP2040 の PIO は2つのブロックがあり、それぞれ4つずつのステートマシンがある。
このステートマシンがそれぞれ個別に利用でき同時に8つのステートマシンが動作できる。
- 動作周波数はシステムクロックを分割したもので、最大周波数はシステムクロックと同じ
- GPIO のピンを PIO から使う場合、利用するピンに関して設定しておく
- コアとのデータやり取りは TX/RX FIFO を介して行う
- コアから見て TX が送信、RX が受信(ステートマシン側から見ると逆)
命令用のメモリは PIO ブロックごとに 32 命令分ある。これを4つのステートマシンで共有する。
そのため、各ステートマシンで走らせるコードはできるだけ小さくしたい。
レジスタ
すべて 32-bit。
FIFO
- FIFO はステートマシンごとに TX 4 本、RX 4 本
- 方向を設定すると TX 8 本または RX 8 本にできる
- SHIFTCTRL_FJOIN で一方通行にして 8 本利用できる
- 通信の TX と RX を別々のステートマシンで実装する場合などに有効
- 4:4, 0:8, 8:0 のどれかの組み合わせのみ可
- 0 本の側で PULL や PUSH すると stall する
自動プッシュと自動プル
有効にしておくと IN や OUT 命令で入力または出力でシフトしたビット数のカウントがしきい値に達すると、自動的に次のデータを対応した PUSH または PULL してくれる。
SHIFTCTRL_PULL_THRESHやSHIFTCTRL_PUSH_THRESHレジスタでしきい値を設定する。
SHIFTCTRL_AUTOPULLやSHIFTCTRL_AUTOPUSHレジスタで有効にする。
ピン割り当て
IN, OUT, SET, サイドセットの4つの GPIO ピンの操作はそれぞれのベースピンレジスタ設定を基準にしてピンが決まる。
ベースピン 7、ピン指定 3 のとき、実際のピンは PIN 10 となる
WAIT GPIO のみベースが適用されない。
- OUT 命令は最大 32 ビットまで書き込める。Destination にしたがって PINS または PINDIRS に適用される。
- 最下位ビットが PINCTRL_OUT_BASE から PINCTRL_OUT_COUNT だけのピンにマッピングされ、GPIO31 を越えるとラップされる。
- SET 命令は最大 5 ビットまで書き込める。Destination にしたがって PINS または PINDIRS に適用される。
- 最下位ビットが PINCTRL_SET_BASE から PINCTRL_SET_COUNT だけのピンにマッピングされ、GPIO31 を越えるとラップされる。
- サイドセットは最大 5 ビットまで書き込める。EXECCTRL_SIDE_PINDIR にしたがって PINS または PINDIRS に適用される。
- 最下位ビットが PINCTRL_SIDESET_BASE から PINCTRL_SIDESET_COUNT だけのピンにマッピングされる。EXECCTRL_SIDE_ENが設定されているときは - 1。
サイドセットが OUT/SET 命令と同じサイクルで重複した場合、重なった範囲でサイドセットが優先される。
サイドセット
命令実行と同時にピンのレベルまたは向きを操作する。命令を節約、2つ以上のピン操作が速くなる
- サイドセットはディレイと指定フィールドを共有しており、どちらかに使用するビット数をPINCTRL_SIDESET_COUNTで指定する
- 一度に最大5ピンまで操作できるが、その時はディレイが使えない
- .side_set 1 opt などと opt がつくとサイドセットが含まれていない命令がある
- このとき、サイドセットの有無の判定に MSB 1ビットがフラグとして使われる
- .side_set 1 opt なら 2 ビットがサイドセットに使われ、残りの 3 ビットがディレイ
- ディレイを 7 サイクルまで使用したければ 3 ビットをディレイに、サイドセットは最大で 2 ピン。
- 命令1つ+7サイクルディレイで8サイクル消費など
- サイドセットはSIDESET_COUNTで指定されたビット数だけ MSB 側を使用する
- 命令がストールしてもサイドセットはすぐに有効
- SIDESET_BASE で指定されたピンが最初のサイドセットピン
- サイドセットに使っているビットのうち LSB が SIDESET_BASE に相当する
入力同期
ピンには 2 フリップフロップ同期回路がある。ピンの入力を安定にするためのものだが、このせいで入力サンプリングは 2 サイクル遅れる。
IN 命令の実行が遅れるわけではなく、ピンへの入力のレベルが変わったとき、サンプリングされて確定するのが 2 サイクル遅れる。
ピンごとにこの同期回路をバイパスでき、INPUT_SYNC_BYPASS レジスタで設定する。
ラッピング
.wrap_target ... .wrap の間で自動的にゼロサイクルジャンプしてくれる機能。
- ラッピングの命令数はゼロのため、命令メモリを節約できる
- サイクル数はゼロ
- レジスタで繰り返し範囲のアドレス設定を行う
- ステートマシンごとに1つだけ使用できる
ストール
ストールすると停止状態になる。ストールする条件は以下のものがある。
- WAIT 命令の条件が満たされていない時、ピンの変化待ちなど
- ブロックありの PULL で TX FIFO が空のとき、ブロックありの PUSH で RX FIFO が一杯のとき
- IRQ WAIT 命令でフラグがセットされているときのクリア待ち
- 自動プルが有効の時の OUT 命令、OSR がしきい値に達していて TX FIFO が空の時
- 自動プッシュが有効の時の IN 命令、ISR がしきい値に達していて RX FIFO が一杯のとき
プログラムカウンタは進まない。ディレイが指定されている時はストールがクリアされるまでディレイも消費されない。
指令、ディレクティブ
.define ( PUBLIC ) <symbol> <value>
整数シンボル名 <symbol> を定義して値 <value> を割り当てる。.define が最初のプログラムより前に記載されるとすべてのプログラムに対してグローバルとなる。それ以外ではプログラムローカルとなる。PUBLIC が指定されている場合、シンボルが出力に含まれる。
.program <name>
新しいプログラム <name> を開始する。名前はコード中で使用されるため、アルファベットまたは数字、アンダースコアかつ数字で始まらないこと。プログラムは次の .program が出現するまでの範囲。PIO 命令はこの中でのみ有効。
.origin <offset>
プログラムを読み込む PIO 命令メモリのオフセットを指定するオプション指令。
プログラム外では無効。
.side_set <count> (opt) (pindirs)
<count> はサイドセットのビット数を指定する。opt が指定された場合、side <value>が命令に対してオプションとなる(追加で1ビットがフラグとして必要)。pindirs を指定すると値はピンの向きの変更に適用される。プログラム中の最初の命令の前で有効。
.wrap_target
プログラムごとに最大一つ。.wrap との間を繰り返すために使う。プログラム外では無効。
.wrap
プログラムごとに最大一つ。.wrap_target との間を繰り返すために使う。プログラム外では無効。
.lang_opt <lang> <name> <option>
特定の言語用ジェネレータのためのオプション。プログラム外では無効。
.word <value>
プログラムに16ビット直値を入れる。プログラム外では無効。
値
(-)0-9 (10進数、符号付き), 0x1 (16進数), 0b1 (2進数)
.define されたシンボル
ラベル
(式) (括弧が必要)
式
式 + 式、式 - 式、式 * 式、式 / 式、- 式、:: 式 (ビット逆転)、値
コメント
// または ; から行末まで。
/* */ の C 言語のコメントも可能。
ラベル
( PUBLIC ) <value>:
PUBLIC はオプション。ラベルは自動的に .define に置き換えられる。
命令、インストラクション
<instruction> ( side <side_set_value ) ([<delay_value>]) <instruction>: 命令 <side_set_value>: 命令の開始時にサイドセットピンに値を適用する。 .side_set が指定されていないと無効。サイドセットがオプションの場合は指定が無くてもよいが、 オプションでない場合は必要。side_set_value は .side_set で指定したビット数に合っていること。 <delay_value>: 命令の終了後にディレイを追加する。ディレイは 0-31 (5-bit) だが .side_set によりビット数が減る。delay_value が指定されないとディレイは無し。
命令、キーワード、指令は大文字と小文字を区別しない。
命令の記載説明のコンマはオプション。命令の記載時にコンマは無くても良い。
すべての PIO 命令は1クロックサイクルで実行される。
命令の挙動を PIO レジスタで切り替えることが多々あるので注意が必要。
Bit | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
JMP | 0 | 0 | 0 | Delay/side-set | Condition | Address | ||||||||||
WAIT | 0 | 0 | 1 | Delay/side-set | Pol | Source | Index | |||||||||
IN | 0 | 1 | 0 | Delay/side-set | Source | Bit count | ||||||||||
OUT | 0 | 1 | 1 | Delay/side-set | Destination | Bit count | ||||||||||
PUSH | 1 | 0 | 0 | Delay/side-set | 0 | IfF | Blk | 0 | 0 | 0 | 0 | 0 | ||||
PULL | 1 | 0 | 0 | Delay/side-set | 1 | IfE | Blk | 0 | 0 | 0 | 0 | 0 | ||||
MOV | 1 | 0 | 1 | Delay/side-set | Destination | Op | Source | |||||||||
IRQ | 1 | 1 | 0 | Delay/side-set | 0 | Clr | Wait | Index | ||||||||
SET | 1 | 1 | 1 | Delay/side-set | Destination | Data |
PUSH と PULL 命令の違いは 7 ビット目。
ディレイとサイドセットはフィールドを共有しているが、使用するビット数をレジスタで変更できる。
JMP
Bit | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
JMP | 0 | 0 | 0 | Delay/side-set | Condition | Address |
- Condition
- 000: 条件なしでいつもジャンプ
- 001: !X: X がゼロ(X否定)
- 010: X--: X がゼロでない、後置デクリメント(分岐と関係なくデクリメントされる)
- 011: !Y: Y がゼロ(Y否定)
- 100: Y--: Y がゼロでない、後置デクリメント(分岐と関係なくデクリメントされる)
- 101: X!=Y: XとYは一致しない
- 110: PIN: PIN の入力が 1 でジャンプ、ピンは JMP_PIN レジスタで指定
- 111: !OSRE: OSRE が空でない
- Address: ジャンプ先の命令アドレス。PIO 命令メモリ中の絶対アドレス指定。
Condition が真のとき、プログラムカウンタを Address にする。真でないときは何もしない。
Condition に関係なくディレイは実行される。条件判定されてプログラムカウンタが更新された後でディレイが実行される。
JMP PIN は JMP_PIN レジスタで選択した GPIO で判定される。
デクリメントしない判定方法は無い。ピンの入力がゼロの判定も無い。
後置デクリメント x-- または y-- でループさせる場合、レジスタの数値 + 1 回ループする。
つまり do {} while (x--); となる。
jmp ( <cond> ) <target> <cond>: Condition, オプション <target>: ラベルまたは、最初の命令の位置をゼロとしてそこからのオフセット値
WAIT
Bit | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
WAIT | 0 | 0 | 1 | Delay/side-set | Pol | Source | Index |
- Polarity:
- 1: 1 を待つ
- 0: 0 を待つ
- Source: 待つ値
- Index: 確認するピンまたはビット指定
WAIT 1 IRQ は割り込みコントローラにフラグがあり、システムの IRQ ハンドラと競合することがあるため注意。
wait <polarity> gpio <gpio_num> wait <polarity> pin <pin_num> wait <plarity> irq <irq_num> ( rel ) <polarity>: Polarity 指定、0 または 1 <pin_num>: 入力ピン番号、入力マッピングで決まる <gpio_num>: 実際の GPIO ピン番号 <irq_num> ( rel ): 待つ irq 番号で 0-7。rel が指定されると実際の irq 番号(irq_num10)は 下位2ビットがステートマシンの irq 番号 sm_num10 との合計(irq_num10 + sm_num10)に置き換えられる。
IN
Bit | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
IN | 0 | 1 | 0 | Delay/side-set | Source | Bit count |
- Source:
- 000: PINS
- 001: X
- 010: Y
- 011: NULL: 不要なビットをシフトで捨てる時など
- 100: Reserved
- 101: Reserved
- 110: ISR
- 111: OSR
- Bit count: ISR にシフト入力するビット数。1-32ビット、32は00000として表現される
Source から Bit count だけシフトして ISR に入力される。シフト方向はステートマシンごとに SHIFTCTRL_IN_SHIFTDIR で指定する。入力シフトカウントが Bit count だけ増加する、最大 32。
自動プッシュが有効のとき、しきい値(SHIFTCTRL_PUSH_THRESH)に達していると ISR のデータが RX FIFO へ送られる。
自動プッシュは実行サイクル数への影響なし。
自動プッシュが発生したときに RX FIFO が一杯なら stall する。
自動プッシュが行われると ISR の内容はすべてのビットがゼロになり、入力シフトカウントはクリアされる。
IN 命令ではソースデータの Bit count の最下位が使用される。Bit count + PINCTRL_IN_BASE から入力される。
まず、ISR が設定に従って左または右にシフトされ、その空きにデータビットが入力される。ビットオーダーはシフト方向に影響されない。
in <source>, <bit_count> <source>: 上記の Source <bit_count>: シフトするビット数 (1-32)
OUT
Bit | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
OUT | 0 | 1 | 1 | Delay/side-set | Destination | Bit count |
- Destination
- 000: PINS:
- 001: X
- 010: Y
- 011: NULL: データを捨てる時
- 100: PINDIRS
- 101: PC
- 110: ISR (さらに、ISR シフトカウンタを Bit count にする)
- 111: EXEC (OSR シフトデータを命令として実行)
- Bit count: OSR からシフト出力するビット数。1-32ビット、32 は00000として表現
Bit count だけ OSR からシフトしてそのビットを Destination に書き込む。出力シフトカウンタが Bit count だけ増加する、上限は 32。
OSR から Bit count で指定されたビットが Destination に書き込まれ、残りのビットはすべてゼロ。
SHIFTCTRL_OUT_SHIFTDIRが右のとき下位ビット、左のときは上位ビット。
PINS および PINDIRS は OUT ピンマッピングを使用する。
自動プルが有効の時、SHIFTCTRL_PULL_THRESH に達していると TX FIFO から OSR へ自動的に読み込まれる。出力シフトカウントはゼロにクリアされる。TX FIFO が空のときは stall する。
自動プルが発生しても 1 サイクルで実行される。
OUT EXEC ではまず OUT が実行され、つぎのサイクルで OSR からの命令が実行される。最初の OUT 実行ではディレイサイクルが無視されるが、実行される命令では通常通りに実行される。
OUT PC では OSR から取り出したアドレスへ無条件にジャンプする。
out <destination>, <bit_count> <destination>: 上記の Destination <bit_count>: シフトするビット数 (1-32)
PUSH
Bit | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
PUSH | 1 | 0 | 0 | Delay/side-set | 0 | IfF | Blk | 0 | 0 | 0 | 0 | 0 |
ISR のデータを RX FIFO に 32-bit ワードとして書き込む。書き込み後に ISR はゼロクリアされる。
- IfFull: 1 のとき、入力シフトカウントがしきい値 SHIFTCTRL_PUSH_THRESH (自動プッシュと同じレジスタ)に達していなければ何もしない。
- Block: 1 のとき、RX FIFO が一杯ならストールする。
PIO アセンブラはデフォルトで Block ビットを設定する。Block ビットが設定されていなければ PUSH は RX FIFO が一杯でもストールせず、すぐに次の命令に進む。このとき、FIFO の状態や内容は変化しない。しかし、ISR はゼロクリアされ、FDEBUG_RXSTALL フラグが設定される (RX FIFO が一杯の時のブロッキング PUSH や自動プッシュと同じ挙動)。
push ( iffull ) push ( iffull ) block push ( iffull ) noblock iffull: 上記の IfFull == 1 と等価。指定されていないとき、デフォルトの IfFull == 1 block: 上記の Block == 1と等価。ブロック指定がなければこれがデフォルト値。 noblock: 上記の Block == 0 と等価
PULL
Bit | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
PULL | 1 | 0 | 0 | Delay/side-set | 1 | IfE | Blk | 0 | 0 | 0 | 0 | 0 |
TX FIFO から OSR へ 32-bit ワードを読み込む。
- IfEmpty: 1 なら出力シフトカウントがしきい値 SHIFTCTRL_PULL_THRESH (自動プルと同じレジスタ) になるまで何もしない
- Block: 1 なら TX FIFO が空でストールする。0 なら空の FIFO からプルすると X から OSR にコピーする
ブロックしない PULL のとき、空の FIFO からプルしようとすると、MOV OSR, X と同じ挙動になる。つまり、X から OSR にデータがコピーされる。
ブロックしない場合、デフォルト値を X に指定しておくか、PULL NOBLOCK の後に MOV X, OSR としてデータを戻してやると、最後の FIFO のデータを次のデータまで使用できる。
pull ( ifempty ) pull ( ifempty ) block pull ( ifempty ) noblock ifempty: 上記の IfEmpty == 1と等価。指定がなければデフォルトは IfEmpty == 0 block: 上記の Block == 1 と等価。ブロック指定がなければこれがデフォルト。 noblock: Block == 0 と等価。
MOV
Bit | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
MOV | 1 | 0 | 1 | Delay/side-set | Destination | Op | Source |
- Destination
- 000: PINS
- 001: X
- 010: Y
- 011: Reserved
- 100: EXEC: 命令として実行
- 101: PC: 無条件ジャンプする。
- 110: ISR
- 111: OSR
- Operation
- 00: None: 何もせずに転送
- 01: Invert: ビット反転 (ビット補数)、! または NOT
- 10: Bit-reverse: ビット逆転 (上位と下位を逆転)、 ::
- 11: Reserved
- Source
- 000: PINS
- 001: X
- 010: Y
- 011: NULL
- 100: Reserved
- 101: STATUS
- 110: ISR
- 111: OSR
Source から Destination へデータをコピーする。
MOV EXEC は OUT EXEC と同じ挙動で、レジスタの内容を命令として実行する。
MOV 命令は 1 サイクルで実行され、Source の中の命令が次のサイクルで実行される。
MOV EXEC のディレイは無視されるが、次に実行される命令のディレイは普通通り。
STATUS ソースは EXECCTRL_STATUS_SEL で設定され、FIFO が一杯や空などのステートマシンの状態を示す、すべてのビットが 1 または 0 の値。
MOV は Operation 引数で指定された方法でデータを加工してから転送できる。Invert は Source のビットのそれぞれの 論理 NOT を Destination に送る。
mov <destination>, ( op ) <source> <destination>: 上記の Destination <op>: 指定する場合、 NOT は ! または ~ で指定、ビット逆転は :: で指定。 <source>: 上記の Source
IRQ
Bit | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
IRQ | 1 | 1 | 0 | Delay/side-set | 0 | Clr | Wait | Index |
Index 引数で指定された IRQ フラグをセットまたはクリアする。
- Clear: 1 のとき Index で指定されたフラグを raise させずにクリアする。Clear ビットが指定されたとき Wait ビットは効果なし。
- Wait: 1 のとき raise されたフラグが下がるまで待つ。
- Index
IRQフラグ 0-3 はシステムの割り込みに割り当て可能。
Wait がセットされていると Delay サイクルは、ウェイトが解消されるまで始まらない。
IRQ ではフラグをセットせずにウェイトだけ行えないため、フラグの確認でウェイトだけするなら WAIT 命令を使う。
irq <irq_num> ( _rel ) irq set <irq_num> ( _rel ) irq nowait <irq_num> ( _rel ) irq wait <irq_num> ( _rel ) irq clear <irq_num> ( _rel ) <irq_num> ( rel ): ウェイトする IRQ 番号 (0-7) を指定。rel が指定されていると、 実際の IRQ 番号は、IRQ 番号 (irq_num10) の下位 2 ビットを ステートマシン ID (sm_num10) との和(irq_num10 + sm_num10)に置き換えられる。 irq: ウェイト無しで IRQ をセット irq set: ウェイト無しで IRQ をセット irq nowait: ウェイト無しで IRQ をセット irq wait: IRQ をセット、そのフラグがクリアされるまでウェイト irq clear: IRQ フラグをクリア
SET
Bit | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
SET | 1 | 1 | 1 | Delay/side-set | Destination | Data |
- Destination
- 000: PINS
- 001: X (下位5ビットに Data が書き込まれ、他のビットは 0 にクリアされる)
- 010: Y (下位5ビットに Data が書き込まれ、他のビットは 0 にクリアされる)
- 011: Reserved
- 100: PINDIRS: ピンの向きを設定、1 で出力、0 で入力
- 101: Reserved
- 110: Reserved
- 111: Reserved
- Data: ピンまたはレジスタに書き込まれる直値
直値 Data を Destination に書き込む。
制御信号のクロックやチップセレクト、ループカウンタの初期化などに使用できる。
Data は 5 ビットのデータをスクラッチレジスタに設定でき、0-31 の値は 32 回の繰り返しに使える。
SET および OUT ピンのマッピングは独立している。
set <destination>, <value> <destination>: 上記の値 <value>: 設定される値 (0-31)
疑似命令
nop
MOV Y, Y に置き換えられる。何も起きない。ディレイのみを稼ぐ時やサイドセットなどに使用できる。
MOV Y, Y は Y レジスタの値を Y レジスタに未加工で送るため、実質何も変化しないで 1 サイクル消費する。ディレイやサイドセットは普通の命令と同じ様に指定できる。
動作クロック
基本のシステムクロックを分割して利用する。最小分割数は1、つまりシステムクロックと同値。
- クロックはステートマシンごとに指定可能。
- n: 16-bit 整数
- f: 8-bit 小数部
- 動作クロック = システムクロック/(n + f / 256)
RPi pico の SDK ではデフォルトの動作周波数が 125MHz となっている。大抵はこれをベースに PIO ステートマシンの動作クロックを決める。
命令実行
命令メモリから実行される以外に以下の方法で命令を実行させられる。
- SM0_INSTR (0-3) レジスタに書き込んだ命令は即座に実行される
- MOV EXEC Source、Source から読み込んだ命令を実行
- MOV EXEC OSR なら OUT EXEC と同じ
- 他に X, Y, ISR などがまともなソースとして使える
- OUT EXEC、OSR から読み込んだ命令を実行
MOV EXEC/OUT EXEC 共にその命令が実行されてから、ソースからの命令が実行される。
初期化
ステートマシンの設定はレジスタで行うが、SDK に関数として用意されている。
ピンの入出力の方向や初期値の設定を行う関数も用意されている。関数では SET 命令を実行するため、pioasm で命令を記述したときと同じ結果が得られる。
初期化の命令分だけ命令メモリが節約できる。
自分でコア側から命令を実行させるには、SM0_INSTR レジスタに書き込むと即座に実行される。
節約方法
命令メモリは 32 しかないので、できるだけ命令数を節約したい。以下のような方法がある。
KiCAD ポリゴン中の円弧
KiCAD 6ではポリゴン中に円弧を入れられるようになりました。
これまでのポリゴンは xy 座標の連続で指定していましたが、円弧の座標を書くのは大変でした。
6では3点指定で円弧を入れられます。6ではまだGUIから利用できません(7で予定あり)。
以下のようにすると、フットプリント中の禁止領域を円弧で指定できます。
(zone (net 0) (net_name "") (layer "B.Cu") (tstamp d6719619-49e0-4c29-83e6-0d9954bbcd05) (hatch none 0.508) (connect_pads (clearance 0)) (min_thickness 0.254) (keepout (tracks allowed) (vias not_allowed) (pads allowed ) (copperpour not_allowed) (footprints allowed)) (fill (thermal_gap 0.508) (thermal_bridge_width 0.508)) (polygon (pts (arc (start 0 -7.4) (mid 7.4 0) (end 0 7.4)) (arc (start 0 7.4) (mid -7.4 0) (end 0 -7.4)) ) ) )
上の例では2つの円弧をつなげて円状の禁止領域を設定しています。
GUIでの表示は円弧が32分割程度の線分に変換されます。編集しなければ円弧のまま保存できます。
円弧は始点、中点、終点の三点で指定する形式のため、ポリゴンの途中に入れても完全に座標を一致させられます。つまり、単純な角丸のような図形を簡単に描けます。
独自形状のパッドをポリゴンで描く場合にも円弧を入れられます。
KiCAD アクションプラグインの作成
KiCAD 5 からアクションプラグインとして Python スクリプトを Pcbnew のツール - 外部スクリプトから実行できます。
そのプラグインの作り方を見てみます。以下の文章を参考にしてください。
- アドオンパッケージ作成
- Pcbnew プラグインの開発
- pcbnew.ActionPlugin クラス
- pcbnew.ActionPlugin クラスのソースコード
- pcbnew.KiCadPlugin クラス(ActionPlugin の親クラス)のソースコード
- API リファレンス
プラグインの配置
プラグインファイルはツール - 外部スクリプト - プラグインの場所を開く、から表示されるディレクトリに配置します。
プラグインは Python スクリプトで、pcbnew.ActionPlugin クラスを継承した独自のクラスを用意しておき、そこから register メソッドを呼び出してプラグインを認識させます。
ActionPlugin クラスのソースコードを読むと分かりますが、多くのクラスメソッドはインスタンス変数の中身をそのまま返しています。つまり、自分でメソッドの中身を実装しなくとも、初期化時にインスタンス変数に与えれば勝手にやってくれます。
name, category, description の3つのインスタンス変数は defaults メソッドの中で初期化され、このメソッドは ActionPlugin の初期化時に自動的に呼ばれます。
必要に応じて icon_file_name, dark_icon_file_name, show_toolbar_button の3つの変数もdefaultsメソッド内で指定しましょう。
# test_script.py import pcbnew class TestPlugin(pcbnew.ActionPlugin): def defaults(self): self.name = "test plugin" self.category = "Undefined" self.description = "This is a test plugin." def Run(self): print("Do something") TestPlugin().register()
ユーザーがプラグインを実行すると Run メソッドが呼ばれます。ここからプラグインの動作を実装します。
プラグインの読み込み時に register メソッドが呼ばれるようにしておきます。このメソッドは ActionPlugin クラスの親クラス KiCadPlugin クラスが実装していますが、内容は気にする必要はありません。
ファイル名が Python のモジュール名と同じになっているような場合、メニューに表示されません。これはモジュールの読み込みの都合ですが、どうしてもメニューに表示されない場合はシンタックスエラーまたはファイル名を疑ってみてください。
COSMO 25番刺しゅう糸の色を検索
刺しゅう糸の色のおよその当たりをつけるために検索できるページを作成。
https://hanya.github.io/cosmo_search/
RGB値を入力するとカタログから抽出した色範囲で検索します。 RGB値の比較では検索結果がいまいちだったのでXYZおよびLab色空間でも比較、検索します。 当たりをつけたら実際の糸を見て選んでください。
マイコンの静電容量タッチセンサーピン数メモ
相互容量式静電容量検出可能なマイコンの検出ピン数メモ
ピンは通信(I2CやUARTなど)やVBUS検出で1-2本程度利用できる数が減少
RX130
USB なし
1.8-5.5V
Package | CTSU | MPN |
---|---|---|
LQFP100 | 36 | R5F5130 |
LQFP80 | 36 | |
LQFP64 | 32 | |
LQFP48 | 24 |
RX140
USB なし
1.8-5.5V
ROM 128KB
Package | CTSU2SL | MPN |
---|---|---|
LQFP80 | 36 | |
LQFP64 | 32 | |
LQFP48 | 24 |
ROM 64KB
Package | CTSU2L | MPN |
---|---|---|
LQFP80 | 12 | |
LQFP64 | 12 | |
LQFP48 | 12 |
ROMサイズによりモジュールが異なる。
RX231
1.8-5.5V
Package | CTSU | MPN |
---|---|---|
LQFP100 | 24 | R5F5231 |
LQFP64 | 10 | |
LQFP48 | 6 |
RA2A1
1.6-5.5V
Package | CTSU | MPN |
---|---|---|
LQFP64 | 26 | R7FA2A1AB3CFM |
QFN48 | 16 | R7FA2A1AB3CNE |
USB なし
Package | CTSU | MPN |
---|---|---|
LQFP32 | 11 | R7FA2A1AB3CFJ |
RA2E1
USB なし
1.6-5.5V
Package | CTSU | MPN |
---|---|---|
LQFP64 | 30(CFC18) | |
LQFP48 | 20(CFC15) | |
LQFP32 | 11(CFC11) |
RA2L1
USB なし
1.6-5.5V
Package | CTSU | MPN |
---|---|---|
LQFP100 | 32 | |
LQFP80 | 32 | |
LQFP64 | 30 | |
LQFP48 | 20 |
RA4M1
1.6-5.5V
Package | CTSU | MPN |
---|---|---|
LQFP100 | 27 | R7FA4M1AB3CFP |
LQFP64 | 24 | R7FA4M1AB3CFM |
LQFP48 | 15 | R7FA4M1AB3CFL |
CapSense 3rd と 4th の差
https://community.cypress.com/docs/DOC-9285
- 4thの方がS/Nが上げやすい
- PSoC 4100では相互容量式が使えない(4100Sではない)
ATSAMD5X
1.71-3.63V
Package | CTSU | MPN |
---|---|---|
VQFN48 | 22 | |
TQFP64 | 32 |
キーボードの行列数
行: 5 + 1(ファンクション)
列: 15(60%) + 3(矢印など) + 4(テンキー)
60%: 20 = 5 + 15
TKL: 24 = 5 + 1 + 15 + 3
100%: 28 = 5 + 1 + 15 + 3 + 4
60%分割: 左 12 = 5 + 7、右 13 = 5 + 8
rand_xorshift crate を使う
Rust の rand クレートはゲームなどでは遅く、他の疑似乱数生成器を使います。
rand_xorshift は Xorshift を実装しており、生成速度や周期の点で大抵のゲームでは十分です。
最近は rand_pcg など PCG も人気のようです、使い方は同じです。
クレート依存性を記述しておきます。
# Cargo.toml [dependencies] rand = "0.7" rand_xorshift = "0.2"
rand::Rng トレイトのメソッドを使いたいときには明示的に use してください。
use rand_xorshift; use rand::{Rng, SeedableRng}; fn main() { // ゲームなどでは時刻などで初期化することが多い // デバッグなどでシードを固定すると楽になる let mut rng = rand_xorshift::XorShiftRng::seed_from_u64(1234567890); // use rand::Rng してあるので gen_range が呼べる let mut rand: i32 = rng.gen_range(0, 100); }
攻撃時の命中判定を行うには、Rng::gen_bool メソッドが便利です。
// 80% 確率で命中 if rand.gen_bool(0.8) { // 命中 }
gen_bool はベルヌーイ分布を生成して利用しています[1]。同じ確率判定を繰り返して使うには、分布を保持しておくと分布を毎回生成するリソース分だけ節約できます。
fn by_sample() { let player_attack_prob = 0.95; let player_attack_distr = rand::distributions::Bernoulli::new(player_attack_prob).unwrap(); let mut rng = rand_xorshift::XorShiftRng::seed_from_u64(123456); let mut hit = 0; for _ in 0..1_000_000_000 { if rng.sample(player_attack_distr) { // 又は // if player_attack_distr.sample(rng) { hit += 1; } } println!("{}", hit + 100); } // イテレータにして利用する方法、シンプルに見える fn by_sample_iter() { let player_attack_prob = 0.95; let player_attack_distr = rand::distributions::Bernoulli::new(player_attack_prob).unwrap(); let rng = rand_xorshift::XorShiftRng::seed_from_u64(123456); // sample_iter は rng と player_attack_distr が move let mut player_attack_prob_iter = rng.sample_iter(player_attack_distr); let mut hit = 0; for _ in 0..1000000000 { if player_attack_prob_iter.next().unwrap() { hit += 1; } } println!("{}", hit + 100); }
イテレータを生成する sample_iter メソッドは乱数生成器と分布を take するので、乱数生成器を他でも使いまわす場合にはこの方法が利用できません。
イテレータにしても10億回程度の実行回数では誤差程度の時間しか変わりません。
Rng::gen_range は以下と同じです[2]。分布を毎回生成する分だけ節約できます。
use rand::distributions::{Distribution, Uniform}; let mut rng = rand_xorshift::XorShiftRng::seed_from_u64(1234567890); let uniform_samples = Uniform::from(0..total_prob); let mut rand: i32 = uniform_samples.sample(&mut rng);
Mozc に新しい元号「令和」を追加する方法
4/1 具体的な編集方法を追記。
Mozc に新しい元号を追加するには、以下のファイルに変更が必要です。
- src/rewriter/date_rewriter.cc, 日付変換
「今日」などで変換したときに表示される元号入りの日時を追加します。
date_rewriter.cc の L1242 辺りに追加します。
1989, "平成", "へいせい", }, { 2019, "令和", "れいわ", }
- src/data/symbol/symbol.tsv, 単漢字変換、㍻など、2019年に発表される新元号は U+32FF
symbol.tsv 辺りに追加します。
記号 ㋿ れいわ ねんごう 年号 OTHER
- src/data/unicode/UnicodeData.txt, 単漢字文字の属性指定
U+32FF の位置に追加します。
32FF;SQUARE ERA NAME REIWA;So;0;L;<square> 4EE4 548C;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME REIWA;;;;
<square>
の後の二つの数値は「令」と「和」の文字コードです。
unicode/Blocks.txt では以下に含まれているため修正の必要はありません。
3200..32FF; Enclosed CJK Letters and Months
2019年4月現在、mozc が利用しているユニコードデータは 6.0 (2010)です。
- data/dictionary_oss/dictionaryXX.txt, 変換辞書
普通に変換候補として表示されるように追加します。
平成の場合、以下のようになっています。
# dictionary07.txt へいせい 1916 1916 1598 平成 へいせい 1920 1920 6206 平成
1916 と 1920 は data/dictionary_oss/id.def に記載されている POS インデックスです。
# id.def 1916 名詞,固有名詞,一般,*,*,*,* 1920 名詞,固有名詞,地域,一般,*,*,*
3つめの数字はコストです。コストは単語の出現率です。新語では定義できないため、平成と同じような数値を指定すればよいと思われます。
#dictionary08.txt れいわ 1847 1847 8251 例話 れいわ 1916 1916 1598 令和 れいわ 1920 1920 6206 令和