2021年5月16日日曜日

PicoでPasopia700 USB Keyboard Adaptor

以前AVR 2個でPasopia700用USBキーボードアダプタを作成したが、今回はPicoで試してみる

パソピア700の信号は、前回の解析結果を参考。

今回Pico用に作成した回路図は以下。

AVRの時と違って、ピンの数が多いので入力と出力を別々のピンで処理できる。

DIR信号によって入力・出力が変わる部分は、やはりソフト切替えだと危険なので74LS541で制御させる。

基板に配線してみた。

5VはDIN13ピン経由でパソピア700から入力するが、デバッグ用にACアダプタの電源ラインは残しておく。

Picoを乗せてUSBキーボードを接続するとこんな感じ

Raspberry Pi Picoには、133MHzで動作する2つのコアと、それとは独立に動作するプログラマブルI/O(PIO)を8つ持っている。

今回は2つのコア(Core0とCore1)と2つのPIO(StateMachine0と StateMachine1)を使って、以下の処理を試してみる
(1) Core0でUSBキーボードで押されたキーをバッファに格納
(2) PIO(SM0)でパソピアからの7bitスキャン信号(GPIO10-16)を、CLK立ち上がり時に読み込み、FIFO経由でCore1に7bitスキャン信号を渡す
(3) Core1は7bitスキャン信号に該当するキー入力データを読み込み、FIFO経由でPIO(SM1)に渡す
(4) PIO(SM1)はFIFOから受け取った8bitデータをGPIO2-9に出力
(5) キー入力に変化があった場合、前回保存しておいた7bitスキャン信号に該当するキー入力データを読み込み、SM1経由でGPIO2-9に出力


まずはCore1を起動し、PIOからの7bitデータ読み込みと8bitデータ出力をさせる
int main(void) {
...
    // Start Core1 for multithread
    stdio_init_all();
    multicore_launch_core1(core1_entry);
...
}

uint8_t keyscan;
volatile uint8_t* pPioKeyReturnFifo = (volatile uint8_t*)&pio0->txf[1];

void core1_entry(void) {
...
    while (1) {
        keyscan = (uint8_t)pio_sm_get_blocking(pio0, 0);  // KeyScan
        *pPioKeyReturnFifo = keyStatus[keyscan];  // KeyReturn
    }
}

PIO(SM0)で、7bitスキャン信号を読み取りFIFOバッファに書き込む
.program usbkey_keyscan

.wrap_target
    wait 0 gpio 18 [7]    ; GP18(=DIN11pin=CLK)が0になるまで待つ
    wait 1 gpio 18    ; GP18(=DIN11pin=CLK)が1になるまで待つ
    nop [1]      ; Pinデータを読み込む前にWait
    in pins, 7    ; GPIO10-16の内容を読込み、FIFOバッファにAutoPush
.wrap

% c-sdk {
static inline void usbkey_keyscan_program_init(PIO pio, uint sm, uint offset) {
    pio_gpio_init(pio, 10);
    pio_gpio_init(pio, 11);
    pio_gpio_init(pio, 12);
    pio_gpio_init(pio, 13);
    pio_gpio_init(pio, 14);
    pio_gpio_init(pio, 15);
    pio_gpio_init(pio, 16);
    pio_sm_set_consecutive_pindirs(pio, sm, 10, 7, false);  // GPIO10以降の7pinを入力ピンとしてセット
    pio_sm_config c=usbkey_keyscan_program_get_default_config(offset);
    sm_config_set_in_pins(&c, 10);  // inputの最初のピンをGPIO10に設定
    sm_config_set_in_shift(&c, false, true, 7);  // シフト方向はLeft、7bit入力したらAutoPush
    pio_sm_init(pio, sm, offset, &c);
    pio_sm_set_enabled(pio, sm, true);
}
%}

PIO(SM1)で、FIFOバッファに書き込まれた8bitデータをGPIO2-9に出力
.program usbkey_keyreturn

.wrap_target
    pull block  ; FIFOに入力されるまで待つ
    out pins, 8  ;GPIO2-9にデータを出力
.wrap

% c-sdk {
static inline void usbkey_keyreturn_program_init(PIO pio, uint sm, uint offset) {
    pio_gpio_init(pio, 2);
    pio_gpio_init(pio, 3);
    pio_gpio_init(pio, 4);
    pio_gpio_init(pio, 5);
    pio_gpio_init(pio, 6);
    pio_gpio_init(pio, 7);
    pio_gpio_init(pio, 8);
    pio_gpio_init(pio, 9);
    pio_sm_set_consecutive_pindirs(pio, sm, 2, 8, true);  // GPIO2以降の8pinを出力ピンとしてセット
    pio_sm_config c=usbkey_keyreturn_program_get_default_config(offset);
    sm_config_set_out_pins(&c, 2, 8);  // outputピンをGPIO2-9に設定
    sm_config_set_out_shift (&c, false, false, 32);  // シフト方向はLeft、AutoPullしない
    pio_sm_init(pio, sm, offset, &c);
    pio_sm_set_enabled(pio, sm, true);
}
%}

これでパソピア700に繋いで試してみたところ、キー入力が安定しない。。
テンキー「1」を入力しても、時々「9」が入力されてしまう。

これはAVRの時にもあった現象で、パソピアからのキースキャン信号に対して、リターンが間に合っていないのが原因。
ロジアナで計測してみると、間に合っているときもあるし、間に合っていない時もある。
下の図は、ぎりぎり間に合っていないケース
B0がDIRで、B1がCLK。
DIRがHighになるとパソピア700から7bitスキャン信号が出力される
DIR=Highになってから500nsほどでCLKが立ち上がるので、そのタイミングで7bitスキャン信号を読み込む。
残り500ns程でスキャン信号に合わせてUSBキーの状態を出力しなければならないが、間に合わない場合がある。

Core1側とPIOの間のデータやりとりにFIFOを使っているが、ここで速度のばらつきが発生しているっぽい。
これでは、ちょっと使いものにならない。。

0 件のコメント:

コメントを投稿