RP2040 PIO 覚え書き

RP2040 データシートを読んだまとめ
https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf

元の文書は改変配布禁止ですので翻訳はできません。ただの覚え書きです。

レジスタタイプについての説明は Appendix A: Register Field Types にある。

目次

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レジスタで有効にする。

自動プッシュは RX FIFO が一杯のときはストールする。
自動プルは TX FIFO が空の時はプルしない。

ピン割り当て

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 に相当する

IRQ

8つの IRQ があり、ステートマシンからすべてにアクセスできる。そのうち 0-3 の IRQ はシステムの割り込みに使用できる。

  • ステートマシンからシステムの割り込みをアサートできる
  • 2つのステートマシンを同期させる
  • IRQ フラグは IRQ と WAIT 命令で利用できる。

入力同期

ピンには 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 15141312111098 76543210
JMP000 Delay/side-set Condition Address
WAIT001 Delay/side-set Pol Source Index
IN010 Delay/side-set Source Bit count
OUT011 Delay/side-set Destination Bit count
PUSH100 Delay/side-set 0IfFBlk 00000
PULL100 Delay/side-set 1IfEBlk 00000
MOV101 Delay/side-set Destination Op Source
IRQ110 Delay/side-set 0 Clr Wait Index
SET111 Delay/side-set Destination Data

PUSH と PULL 命令の違いは 7 ビット目。
ディレイとサイドセットはフィールドを共有しているが、使用するビット数をレジスタで変更できる。

JMP

Bit 15141312111098 76543210
JMP000 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 15141312111098 76543210
WAIT001 Delay/side-set Pol Source Index

  • Polarity:
    • 1: 1 を待つ
    • 0: 0 を待つ
  • Source: 待つ値
    • 00: GPIO: Index で指定されるシステム GPIO 入力。ピン番号は絶対位置指定でステートマシンの入力マッピングに影響を受けない
    • 01: PIN: Index で指定される入力ピン。ピンは入力マッピング + Index で決まる。
    • 10: IRQ: Index で指定された PIO IRQ フラグ
    • 11: Reserved
  • 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 15141312111098 76543210
IN010 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 15141312111098 76543210
OUT011 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 15141312111098 76543210
PUSH100 Delay/side-set 0IfFBlk 00000

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 15141312111098 76543210
PULL100 Delay/side-set 1IfEBlk 00000

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 15141312111098 76543210
MOV101 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 15141312111098 76543210
IRQ110 Delay/side-set 0 Clr Wait Index

Index 引数で指定された IRQ フラグをセットまたはクリアする。

  • Clear: 1 のとき Index で指定されたフラグを raise させずにクリアする。Clear ビットが指定されたとき Wait ビットは効果なし。
  • Wait: 1 のとき raise されたフラグが下がるまで待つ。
  • Index
    • 下位 3 ビットで 0-7 の IRQ を指定。これらは Clear ビットでセット/クリアできる。
    • MSB が設定されているとき、ステートマシン ID (0-3 ビット) が IRQ インデックスに追加される。
    • 下位 2 ビットのみがステートマシン ID と加算されて適用される。
    • ビット 2 (下位3ビット目) は影響を受けない。
    • 同じプログラムを複数のステートマシンで実行するときや複数のステートマシンを同期させるために使える

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 15141312111098 76543210
SET111 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 しかないので、できるだけ命令数を節約したい。以下のような方法がある。

  • ラップで繰り返し
    • .wrap_target ... .wrap の間で自動的に繰り返してくれるため JMP 1つが節約できる。
    • ジャンプ位置はレジスタの設定が必要
    • 一つしか使えないため、ほぼ全体を繰り返すときによく使う
    • pioasm アセンブラはデフォルトでラップしてくれるため、宣言しなくともラップデータが出力される
  • サイドセット
    • ピンの操作の一部をサイドセットで行うと、OUT 命令が節約できる
    • nop とサイドセットを組み合わせることもあるので節約にならないことも多い
    • クロックをサイドセットで出力することが多いので節約に使えない
  • 自動プル/自動プッシュ
    • 読み込みビット数が固定のときは自動プル/自動プッシュで1つ節約
    • 実際には他の用途で使う
    • 長いディレイが必要な時に困る
  • ピンの初期化を SDK の関数などで行う

インラインアウト

レジスタの説明だけでは分かりにくいが、リファレンス中で説明されていない。
以下に説明がある。

OUT_EN_SEL, INLINE_OUT_EN, OUT_STICKY の 3 つのレジスタで設定する。
複数のステートマシンで出力ピンが重なった時に優先的に出力させたい時に使える。
ステートマシンの番号が大きい方の出力結果が優先される。
インラインアウトが指定されると、指定されていないステートマシンよりも優先順位が上がる。しかし、インラインアウトが指定されているステートマシン同士では大きい番号の方が優先される。

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 のツール - 外部スクリプトから実行できます。

そのプラグインの作り方を見てみます。以下の文章を参考にしてください。

プラグインの配置

プラグインファイルはツール - 外部スクリプト - プラグインの場所を開く、から表示されるディレクトリに配置します。

プラグイン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

PSoC 4000S

USB なし
4th CapSense
1.71-5.5V

Package CTSU MPN
QFN24 19
32 27 CY8C402
QFN40 34
48 36

PSoc 4100S

USB なし
4th CapSense
1.71-5.5V

Package CTSU MPN
44 36 CY8C412
48 36

PSoC 4200L

3rd CapSense
1.71-5.5V

Package CTSU MPN
48 38 CY8C424
64 53

USB のないラインナップもあるので注意

PSoc 4700S

USB なし
4th CapSense
1.7-5.5V

Package CTSU MPN
48 36 Cy8C47
QFN24 19

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.ccL1242 辺りに追加します。

    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    令和