Pico三昧(8) Pico C/C++SDKでinterp その2、DeadBeef例題

Joseph Halfmoon

前回からラズパイPicoの特長の一つである interpolator を使いはじめました。今回は、interpolator の内部にある、シフタ、マスク、符号拡張器を制御してみます。RP2040データシートを読むとちょうどいい塩梅に処理例が載っていました。DeadBeefとな。ここでは16進数でちょうど32ビットだからってことみたいですが。

さて参照しているのは 以下のデータシートです。SIOの中に interpolator の説明があり、Lane Operationsという項目の中に 値 0xdeadbeef に対する処理例が記載されています。

RP2040 Datasheet

処理例では、右シフトして、マスクかけて、符号拡張したらこんな感じでしょ、という値が記載されているだけでプログラム例の記載はないので、勝手に相当の処理を実機上で動かしてみました。

処理の流れを冒頭のアイキャッチ画像に図にしてみましたのでご覧くださいまし。

  1. アキュムレータに 0xdeadbeef を入れる
  2. シフタで 0xdeadbeef を右シフト(冒頭画像の例は12ビット)
  3. マスクで 0x000deadb の中間部分を取り出す(冒頭画像の例はMSB=19からLSB=4ビット目を残して他はゼロクリア。)
  4. 符号拡張器で、上記のMSB=19ビット目を符号とみて20ビット目以上にコピー
  5. 最後にBASE(冒頭画像例ではゼロ)と加算し、PEEKで読み出し

ステップ毎にみて行けば処理そのものは簡単です。interpolatorの強みは、一度上記のような処理フローを設定してしまえば、後は 0xdeadbeef だろうと 0x12345678 だろうと、何を突っ込んでも同じフローで処理して結果が出てくるというところだと思います。

実際に作製したソース

ビルド、デバッグ環境などは前回設定したものそのままを使っています。また、上記の処理例そのままではあまりに芸が無いので、マスク処理と符号拡張が連動している様子が分かるように、MSBを動かして結果を観察できるようにしてみました。なお、そのため毎回 interpolator のコンフィギュレーションを行うように書いてしまいました。一度コンフィギュレーションしたらほとんど書き換えないのが本来の使い方だと思うのですが。

#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/interp.h"

volatile int counter = 1;

int main()
{
    const uint LED_PIN = 25;
    gpio_init(LED_PIN);
    gpio_set_dir(LED_PIN, GPIO_OUT);
    stdio_init_all();

    interp_config cfg = interp_default_config();
    printf("Interp training 002\n");
    while (1) {
        printf("TEST LOOP: %d\n", counter++);
        interp_config_set_shift(&cfg, 8);
        interp_config_set_mask(&cfg, 4, 7);
        interp_config_set_signed(&cfg, true);
        interp_set_config(interp0, 0, &cfg);
        interp0->accum[0] = 0xdeadbeef;
        interp0->base[0] = 0;
        printf("deadbeef (8:4:7)->  0x%08x\n", interp0->peek[0]);

        gpio_put(LED_PIN, 1);
        sleep_ms(1000);
    
        for (int i=7; i<20; i++) {
            interp_config_set_shift(&cfg, 12);
            interp_config_set_mask(&cfg, 4, i);
            interp_config_set_signed(&cfg, true);
            interp_set_config(interp0, 0, &cfg);
            interp0->accum[0] = 0xdeadbeef;
            interp0->base[0] = 0;
            printf("deadbeef (12:4:%d)->  0x%08x\n", i, interp0->peek[0]);
        }

        gpio_put(LED_PIN, 0);
        sleep_ms(1000);
    }

    return 0;
}

最初に、右シフト8ビット、マスクで7ビット目から4ビット目をとりだして符号拡張をかけているのがデータシート記載の「オリジナル」の DeadBeef 例です。

forループの中で、右シフト12ビットで、マスクの値を変化させながら符号拡張をかけているのがマスクと符号拡張の連動を見るための例です。

実機動作結果

以下の実機動作結果のうち、(12:4:x)とあるのが、マスクと符号拡張を見るための例です。

TEST LOOP: 6
deadbeef (8:4:7)-> 0xffffffb0
deadbeef (12:4:7)-> 0xffffffd0
deadbeef (12:4:8)-> 0x000000d0
deadbeef (12:4:9)-> 0xfffffed0
deadbeef (12:4:10)-> 0x000002d0
deadbeef (12:4:11)-> 0xfffffad0
deadbeef (12:4:12)-> 0x00000ad0
deadbeef (12:4:13)-> 0xffffead0
deadbeef (12:4:14)-> 0xffffead0
deadbeef (12:4:15)-> 0xffffead0
deadbeef (12:4:16)-> 0xffffead0
deadbeef (12:4:17)-> 0x0001ead0
deadbeef (12:4:18)-> 0xfffdead0
deadbeef (12:4:19)-> 0xfffdead0

12ビット右シフトし、マスクで下位4ビットを0にした後の下20ビットのビットパターンは以下のようです(上16進、下2進)

d e a d 0
1101 1110 1010 1101 0000

上記の実行例で、マスクでのMSBの指定をビット7からビット19まで変化させてみていると、MSBに応じて符号拡張の様子が変化していくのが分かると思います。

演算器部品の動作確認例としては良かったけれど、deadbeef とかあまり目出度いお名前とも思えませぬが、ラズパイの中の人の趣味?

Pico三昧(7) Pico C/C++SDKでinterp その1、popとpeek へ戻る

Pico三昧(9) Pico C/C++SDKでinterp その3,シンプルな線形補間 へ進む