RP2040のPIOのJMP, MOV, PUSHとかの解説(C言語向け)
RP2040(Raspberry Pi Pico)のPIOのJMPやMOVといったアセンブラのような命令について解説します。
1. JMP
条件によって設定したラベル位置に処理を移動させます。
JMP 例
loop: ; ラベルloopを設定(名前は自由に付けれる) ~その他処理~ jmp !x loop ; レジスタXが0の場合、ラベルloopに処理をジャンプします。
命令は次のフォーマットで記述します。
jmp (<条件>) <ラベル>
かっこ()は省略可を意味します。(『jmp <ラベル>』と書くことも可能ということ)
条件が成立(true)する場合に、ラベルにジャンプします。条件は次の8パターンの書き方があります。
条件 | 動作 |
---|---|
記載なし | 条件は常に成立(true)となり、常にラベルにジャンプします。 |
!x | レジスタXが0の場合、ラベルにジャンプします。 |
x-- | レジスタXが0では無い場合、ラベルにジャンプします。ついでにレジスタxの値を1引きます。 |
!y | レジスタYが0の場合、ラベルにジャンプします。 |
y-- | レジスタYが0では無い場合、ラベルにジャンプします。ついでにレジスタyの値を1引きます。 |
x!=y | レジスタXとYが違う値の場合、ラベルにジャンプします。 |
pin | あらかじめsm_config_set_jmp_pin関数で設定しておいたGPIOピンがHレベルの場合、ラベルにジャンプします。 |
!OSRE | OUTシフトレジスタが空でなければ、ラベルにジャンプします。(OUTシフトレジスタにはPULL命令によってTX FIFOから32bitのデータが格納される) |
2. WAIT
条件が成立するまで待機します。遅延命令を付けた場合は、条件成立直後に遅延処理が実施されます。WAIT 例
wait 1 gpio 28 ; GPIO28が1(Hレベル)になるまで待機します。
命令は次のフォーマットで記述します。
wait <polarity> gpio <GPIO番号>
又は
wait <polarity> pin <pin番号>
又は
wait <polarity> irq <irq番号> (rel)
polarityには1か0が入ります。
1の場合、指定のGPIO等がHレベル(1)となるまで待機します。
0の場合、指定のGPIO等がLレベル(0)となるまで待機します。
かっこ()は省略可を意味します。
対象 | 動作 |
---|---|
gpio | 指定のGPIO番号の入力値(1:Hレベル 0:Lレベル)によって待機するか否かが決まります。 |
pin |
あらかじめsm_config_set_in_pin関数で設定した入力ピン番号の値(1:Hレベル 0:Lレベル)によって、待機するか否かが決まります。 例えば次のようにGPIO16をベースの入力ピンと設定していた場合、 sm_config_set_in_pin(&c, 16); 『wait 1 pin 2』によってGPIO18がHレベルになるまで待機します。(ベースをGPIO16としたので、16 + 2 = でGPIO18が対象となる) |
irq |
IRQ番号のフラグよって、待機するか否かが決まります。IRQフラグはIRQ命令で立てたりクリアします。
|
3. IN
あらかじめステートマシン用に設定しておいたGPIOやX,Yレジスタ等から、INシフトレジスタに値を移します。IN 例
in pins 1 ; sm_config_set_in_pin関数で設定したGPIOピンの値(H:1 or L:0)を1bit読み、
; ISR(INシフトレジスタ)に値を格納します。
; sm_config_set_in_shift関数で、INシフトレジスタに
; 右シフトで入れるか、左シフトで入れるかを設定しておきます。
命令は次のフォーマットで記述します。
in <読込元>, <読込ビット数>
あらかじめsm_config_set_in_shift関数で読込元のデータをINシフトレジスタへ右シフトで入れるか、左シフトで入れるかを設定しておきます。
読込元は次の6パターンの書き方があります。
読込元 | 動作 |
---|---|
pins | あらかじめsm_config_set_in_pin関数で設定しておいたGPIOピンからINシフトレジスタに指定のビット数だけ読み込みます。 |
x | レジスタXからINシフトレジスタに指定のビット数だけ読み込みます。 |
y | レジスタYからINシフトレジスタに指定のビット数だけ読み込みます。 |
null | 指定のビット数分、ゼロを読み込みます。INシフトレジスタを好きなビット数だけ0ビットで埋めることができます。 |
isr | INシフトレジスタからINシフトレジスタに指定のビット数だけ読み込みます。 |
osr | OUTシフトレジスタからINシフトレジスタに指定のビット数だけ読み込みます。 |
sm_config_set_in_shift関数で自動pushを有効にできます。この自動pushが有効の場合、IN命令で各読込元から読み込んで、push閾値(これもsm_config_set_in_shift関数で設定)に達すると、INシフトレジスタの内容をRX FIFOに移動します(pushの動作)。自動pushが行われてもIN命令は関係なく1クロックで動作します。また、この自動pushの際にRX FIFOの空きが無い場合は、空きができるまで待機状態となります。自動pushではINシフトレジスタの値を全てゼロにクリアします(入力シフトカウントもゼロクリアします)。
4. OUT
あらかじめステートマシン用に設定しておいたGPIOやX,Yレジスタ等へ、OUTシフトレジスタの値を移します。OUT 例
out pins 3 ; OSR(OUTシフトレジスタ)の最下位3ビットを、
; sm_config_set_out_pin関数で設定したGPIOピンへ書き込みます。
; 例えば、あらかじめsm_config_set_out_pin関数で
; GPIO0~2までを使用すると設定しておけば
; GPIO0~2に最下位3ビットの値(H/L)が出力されます。
命令は次のフォーマットで記述します。
out <書込先>, <書込ビット数>
書込先は次の8パターンの書き方があります。
書込先 | 動作 |
---|---|
pins | OUTシフトレジスタから指定のビット数だけ、あらかじめsm_config_set_out_pin関数で設定しておいたGPIOピンへデータを移します。 |
x | OUTシフトレジスタから指定のビット数だけ、レジスタXへデータを移します。 |
y | OUTシフトレジスタから指定のビット数だけ、レジスタYへデータを移します。 |
null | 指定のビット数分、破棄できます。 |
pindirs | 指定のビット数分、PINの入力/出力設定(pio_sm_set_pindirs_with_mask関数等で実施)にデータを移します。 |
pc | 指定のビット数分、pc(program counter)にデータを移すので、そのアドレスに処理がジャンプします。 |
isr | OUTシフトレジスタから指定のビット数だけ、isr(INシフトレジスタ)にデータを移します。 |
EXEC | OUTシフトレジスタの値が命令データとして取り出され、次のクロックで実行されます。 |
sm_config_set_out_shift関数で自動pullを有効にできます。この自動pullが有効の場合、OUT命令で各書込先へデータを移して、pull閾値(これもsm_config_set_out_shift関数で設定)に達すると、TX FIFOからOUTシフトレジスタに値を移動します(pullの動作)。自動pullが行われてもOUT命令は関係なく1クロックで動作します。また、この自動pullの際にTX FIFOが空だった場合、データが入るまで待機状態となります。(また、出力シフトカウントはゼロクリアされます)。
5. PUSH
ISR(INシフトレジスタ)の内容をRX FIFOに移動します。(INシフトレジスタはゼロになります)PUSH 例
push ; 現状のISR(INシフトレジスタ)の値をRX FIFOに移動します。
; ただし、RX FIFOの空きがない場合は、空きができるまで待機状態となります。
命令は次のフォーマットとなります。
push (iffull)
push (iffull) block
push (iffull) noblock
かっこ()は省略可を意味します。(『push』と書くことも可能ということ)
次のような動作となります。
書き方 | 動作 |
---|---|
push | 現状のISR(INシフトレジスタ)の値をRX FIFOに移動します。ただし、RX FIFOの空きがない場合は、空きができるまで待機状態となります。 |
push iffull | sm_config_set_in_shift関数で設定したpush閾値を超えていない場合、何もしません。push閾値を超えている場合に、現状のISR(INシフトレジスタ)の値をRX FIFOに移動します。ただし、RX FIFOの空きがない場合は、空きができるまで待機状態となります。 |
push block | 『push』と同様です。blockはデフォルトで有効状態なので、push実行時、RX FIFOの空きがない場合は、空きができるまで待機状態となります。 |
push noblock | 現状のISR(INシフトレジスタ)の値をRX FIFOに移動します。ただし、RX FIFOの空きがない場合は、値を破棄して次の命令に進みます。 |
sm_config_set_in_shift関数で自動pushを有効にできます。この自動pushが有効の場合、push閾値(これもsm_config_set_in_shift関数で設定)に達すると、INシフトレジスタの内容をRX FIFOに移動します(pushの動作)。
6. PULL
TX FIFOから32bitのデータをOSR(OUTシフトレジスタ)に移動します。PULL 例
pull ; TX FIFOから32bitのデータをOSR(OUTシフトレジスタ)に移動します。
; ただし、TX FIFOが空の場合、データが入るまで待機状態となります。
命令は次のフォーマットとなります。
pull (ifempty)
pull (ifempty) block
pull (ifempty) noblock
かっこ()は省略可を意味します。(『pull』と書くことも可能ということ)
次のような動作となります。
書き方 | 動作 |
---|---|
pull | TX FIFOから32bitのデータをOSR(OUTシフトレジスタ)に移動します。ただし、TX FIFOが空の場合、データが入るまで待機状態となります。 |
pull ifempty | sm_config_set_out_shift関数で設定したpull閾値を超えていない場合、何もしません。pull閾値を超えている場合に、TX FIFOから32bitのデータをOSR(OUTシフトレジスタ)に移動します。 |
pull block | 『pull』と同様です。blockはデフォルトで有効状態なので、pull実行時、TX FIFOが空の場合、データが入るまで待機状態となります。 |
pull noblock | TX FIFOから32bitのデータをOSR(OUTシフトレジスタ)に移動します。ただし、TX FIFOが空の場合は、レジスタXの値が入ります。(TX FIFOが空の場合、『mov x, osr』と同じ効果が得られる) |
sm_config_set_out_shift関数で自動pullを有効にできます。この自動pullが有効の場合、pull閾値(これもsm_config_set_out_shift関数で設定)に達すると、TX FIFOからOUTシフトレジスタに値を移動します(pullの動作)。
7. MOV
データを指定の読込元から指定の宛先にコピーします。MOV 例
mov pins, x ; あらかじめsm_config_set_out_pin関数で設定しておいた
; GPIOピンに、Xレジスタの値をコピーします。
mov x, pins ; あらかじめsm_config_set_in_pin関数で設定しておいた
; GPIOピンの値(H:1/L:0)を、Xレジスタにコピーします。
命令は次のフォーマットとなります。
mov 宛先, (op) 読込元
かっこ()は省略可を意味します。(『mov 宛先, 読込元』と書くことも可能ということ)
宛先には次が入ります。
宛先 | 宛先/動作 |
---|---|
pins | sm_config_set_out_pin関数で設定しておいたGPIO |
x | レジスタX |
y | レジスタY |
exec | コピーしたデータを命令として実行します。MOVの次のクロックで命令が実行されます。 |
pc | pc(program counter)にコピーします。そのアドレスに処理が移動(JMP)します。 |
isr | isr(INシフトレジスタ) |
osr | osr(OUTシフトレジスタ) |
(op) には次が入ります。
(op) | 動作 |
---|---|
(省略) | 値をそのままコピーします。 |
『!』 または 『~』 | ビット反転してコピーします。 |
『::』 | ビット順を逆に並び変えてコピーします。 |
読込元には次が入ります。
読込元 | 読込元/動作 |
---|---|
pins | sm_config_set_in_pin関数で設定しておいたGPIO |
x | レジスタX |
y | レジスタY |
null | 0がコピーされます。 |
status | ? (本家pdfを参照してください) |
isr | isr(INシフトレジスタ) |
osr | osr(OUTシフトレジスタ) |
8. IRQ
割り込みフラグを立てます。またはフラグを下げます(クリア)。IRQ 例
irq 2 ; IRQ2番のフラグを立てます。
命令は次のフォーマットとなります。
irq IRQ番号 (_rel)
irq set IRQ番号 (_rel)
irq nowait IRQ番号 (_rel)
irq wait IRQ番号 (_rel)
irq clear IRQ番号 (_rel)
かっこ()は省略可を意味します。(『irq IRQ番号』と書くことも可能ということ)
IRQ番号は0-7の間で指定します。0-7はステートマシン間で共有できます。また、0-3はシステムレベルで共有できます。(irq_set_exclusive_handler関数、pio_set_irq0_source_enabled関数等で設定。詳細は別で記述予定です)
命令分 | 動作 |
---|---|
irq IRQ番号 | IRQ番号のフラグを立てます。IRQ番号は0-7までを指定します。 |
irq IRQ番号 _rel | IRQ番号のフラグを立てます。IRQ番号は0-7までを指定します。_relがある場合、ステートマシン番号が足され、その値を4で割った余りの数が対象の番号となります。例えば、ステートマシン2番を使用している場合で、IRQ番号が1の場合は、(2 + 1) % 4 = 3 でIRQ3番が、ステートマシン3番を使用している場合で、IRQ番号が2の場合は、(3 + 2) % 4 = 1 で IRQ1番が、対象のIRQ番号になります。 |
irq set IRQ番号 | 『irq IRQ番号』と同様です。 |
irq nowait IRQ番号 | 『irq IRQ番号』と同様です。 |
irq wait IRQ番号 | IRQ番号のフラグを立てます。この後、このフラグが下がるまで待機します。 |
irq clear IRQ番号 | IRQ番号のフラグを下げます。(クリアします) |
9. SET
5bitの値(0~31)を指定の宛先に書き込みます。SET 例
set x, 27 ; レジスタXに27を入れます。
命令は次のフォーマットとなります。
set 宛先 値
値は0-31の間で指定します。
指定可能な宛先は次のようになります。
宛先(書き方) | 宛先/動作 |
---|---|
pins | あらかじめsm_config_set_set_pin関数で設定しておいたGPIOピン |
x | レジスタX |
y | レジスタY |
pindirs | PINの入力/出力設定(pio_sm_set_pindirs_with_mask関数等で実施) |
すべてのPIO命令は1クロックで実行されます。Picoのクロックスピードは125Mhzですが、ステートマシンには分周期があり、最大65536除算した値[(125Mhz / 65536) = 1907Hz]まで速度を落とすことができます。(sm_config_set_clkdiv関数で設定)
すべてのPIO命令には最後尾に遅延命令[数値]が付けられます。(例:『out x, 1 [7]』:7クロック分何もしない)
コメント
コメントを投稿