🏈

Keyball61のマウスポインタのジャンプを回避した

に公開

Keyball61 で時々マウスポインタが意図せずジャンプする現象が出て悩んでいたのですが、抑え込むことができたのでそのまとめです。

デバッグ

rules.mk で CONSOLE_ENABLE = yes とすると、 dprintf() の出力が QMK Toolbox に表示されます。

pmw3360.c
bool pmw3360_motion_burst(pmw3360_motion_t *d) {
#ifdef DEBUG_PMW3360_SCAN_RATE
    pmw3360_scan_perf_task();
#endif
    // Start motion burst if motion burst mode is not started.
    if (!motion_bursting) {
        pmw3360_reg_write(pmw3360_Motion_Burst, 0);
        motion_bursting = true;
    }

    pmw3360_spi_start();
    spi_write(pmw3360_Motion_Burst);
    wait_us(35);
    uint8_t mot = spi_read();
    uint8_t observation = spi_read();
    d->x = spi_read();
    d->x |= spi_read() << 8;
    d->y = spi_read();
    d->y |= spi_read() << 8;
    spi_stop();
    // Required NCS in 500ns after motion burst.
    wait_us(1);
    dprintf("pmw3360_motion_burst: mot:%d, observation:%d, dx:%d, dy:%d\n", mot, observation, d->x, d->y);
    return true;
}

として(この関数はボールが付いている側のProMicroで実行されるので、USBケーブルをボール側に挿して)トラックボールを操作すると QMK Toolbox に以下のように出ます。

> pmw3360_motion_burst: mot:160, observation:63, dx:2, dy:2
> pmw3360_motion_burst: mot:160, observation:63, dx:0, dy:1
> pmw3360_motion_burst: mot:160, observation:63, dx:1, dy:1
> pmw3360_motion_burst: mot:32, observation:63, dx:0, dy:0
> pmw3360_motion_burst: mot:32, observation:63, dx:0, dy:0
> pmw3360_motion_burst: mot:32, observation:63, dx:0, dy:0
> pmw3360_motion_burst: mot:32, observation:63, dx:0, dy:0
> pmw3360_motion_burst: mot:160, observation:63, dx:0, dy:-1
> pmw3360_motion_burst: mot:160, observation:63, dx:0, dy:-2
> pmw3360_motion_burst: mot:160, observation:63, dx:0, dy:-2

トラックボールを操作してないときはひたすら、dx:0, dy:0 の行が出続けます。

動きがない場合の処理を省く

まず、上の観察結果より、動きの有無で mot の値が 160/32 になっているのがわかります。 pmw3360_motion_read() の実装あるいはデータシートの Motion の説明を見ると、最上位ビットで動きの有無を表わしており、動きがなければ無視してしまってよいので以下のようにして観察を続けます。

pmw3360.c
bool pmw3360_motion_burst(pmw3360_motion_t *d) {
#ifdef DEBUG_PMW3360_SCAN_RATE
    pmw3360_scan_perf_task();
#endif
    // Start motion burst if motion burst mode is not started.
    if (!motion_bursting) {
        pmw3360_reg_write(pmw3360_Motion_Burst, 0);
        motion_bursting = true;
    }

    pmw3360_spi_start();
    spi_write(pmw3360_Motion_Burst);
    wait_us(35);
    uint8_t mot = spi_read();
    if (mot & 0x80) { // Motion occurred
        uint8_t observation = spi_read();
        d->x = spi_read();
        d->x |= spi_read() << 8;
        d->y = spi_read();
        d->y |= spi_read() << 8;
        dprintf("pmw3360_motion_burst: mot:%d, observation:%d, dx:%d, dy:%d\n", mot, observation, d->x, d->y);
    }
    spi_stop();
    // Required NCS in 500ns after motion burst.
    wait_us(1);
    return mot & 0x80;
}

異常な動きを観察

トラックボールを操作して QMK Toolbox への出力を見ると、所々で dx, dy の絶対値が大きな値になっており、これがマウスポインタの意図せぬジャンプに繋がっているようです。

> pmw3360_motion_burst: mot:160, observation:63, dx:1, dy:-5
> pmw3360_motion_burst: mot:160, observation:63, dx:2, dy:-6
> pmw3360_motion_burst: mot:160, observation:63, dx:1, dy:-5
> pmw3360_motion_burst: mot:160, observation:63, dx:1, dy:-5
> pmw3360_motion_burst: mot:160, observation:126, dx:256, dy:-265
> pmw3360_motion_burst: mot:160, observation:63, dx:0, dy:-5
> pmw3360_motion_burst: mot:160, observation:63, dx:0, dy:-4
> pmw3360_motion_burst: mot:160, observation:63, dx:-1, dy:-5
> pmw3360_motion_burst: mot:160, observation:63, dx:-2, dy:-2
> pmw3360_motion_burst: mot:160, observation:63, dx:-3, dy:-2
> pmw3360_motion_burst: mot:160, observation:63, dx:-3, dy:-1
> pmw3360_motion_burst: mot:160, observation:63, dx:-3, dy:0
> pmw3360_motion_burst: mot:160, observation:63, dx:-6, dy:0
> pmw3360_motion_burst: mot:160, observation:63, dx:-7, dy:-1
> pmw3360_motion_burst: mot:160, observation:63, dx:-7, dy:0
> pmw3360_motion_burst: mot:160, observation:63, dx:-8, dy:0
> pmw3360_motion_burst: mot:160, observation:63, dx:-9, dy:0
> pmw3360_motion_burst: mot:160, observation:63, dx:-7, dy:0
> pmw3360_motion_burst: mot:160, observation:63, dx:-10, dy:0
> pmw3360_motion_burst: mot:160, observation:63, dx:-11, dy:0
> pmw3360_motion_burst: mot:160, observation:63, dx:-23, dy:2
> pmw3360_motion_burst: mot:160, observation:63, dx:-18, dy:4
> pmw3360_motion_burst: mot:160, observation:63, dx:-15, dy:6
> pmw3360_motion_burst: mot:160, observation:63, dx:-11, dy:6
> pmw3360_motion_burst: mot:160, observation:127, dx:-273, dy:14
> pmw3360_motion_burst: mot:160, observation:63, dx:-7, dy:8
> pmw3360_motion_burst: mot:160, observation:63, dx:-6, dy:9

observation の値ですが、データシートの Observation の説明だと OB[5:0] の6bit(0 <= observation <= 63) で値を表現し、 OB6 は SROM が動作してるかどうかを示しているとあり、SROMは使っていないので63より大きな値は異常値と考えられます。一方で上の観察より observation が 63 を越えたときに dx, dy の異常値が現れているので、observation > 63 を無視すると問題が回避できそうです。

なお、observation > 63 ならば dx, dy も異常値かというとそうでもなくて、ボールを右下方向に回したときには

> pmw3360_motion_burst: mot:160, observation:63, dx:21, dy:17
> pmw3360_motion_burst: mot:160, observation:63, dx:19, dy:17
> pmw3360_motion_burst: mot:160, observation:63, dx:19, dy:16
> pmw3360_motion_burst: mot:160, observation:126, dx:32, dy:32
> pmw3360_motion_burst: mot:160, observation:63, dx:17, dy:16
> pmw3360_motion_burst: mot:160, observation:63, dx:16, dy:16
> pmw3360_motion_burst: mot:160, observation:63, dx:15, dy:15
> pmw3360_motion_burst: mot:160, observation:63, dx:15, dy:14
> pmw3360_motion_burst: mot:160, observation:63, dx:10, dy:11
> pmw3360_motion_burst: mot:160, observation:63, dx:13, dy:14
> pmw3360_motion_burst: mot:160, observation:126, dx:50, dy:50
> pmw3360_motion_burst: mot:160, observation:63, dx:16, dy:16
> pmw3360_motion_burst: mot:160, observation:63, dx:10, dy:10
> pmw3360_motion_burst: mot:160, observation:63, dx:10, dy:9
> pmw3360_motion_burst: mot:160, observation:63, dx:9, dy:8

のような感じでやや大きめの値が入っているが異常でもなさそうでした(推測ですが負の値の足し上げで問題が出ているのではという気が何となくしています)。いずれにせよ全体の動き検出の回数に対して observation > 63 の割合は低いので、この場合も含めて無視してしまってもよさそうです。

異常値を無視

observation の値でフィルタリングすることで、マウスポインタのジャンプが解消しました。最終的なコードは以下の通り:

pmw3360.c
bool pmw3360_motion_burst(pmw3360_motion_t *d) {
#ifdef DEBUG_PMW3360_SCAN_RATE
    pmw3360_scan_perf_task();
#endif
    // Start motion burst if motion burst mode is not started.
    if (!motion_bursting) {
        pmw3360_reg_write(pmw3360_Motion_Burst, 0);
        motion_bursting = true;
    }

    pmw3360_spi_start();
    spi_write(pmw3360_Motion_Burst);
    wait_us(35);
    uint8_t mot = spi_read();
    uint8_t observation = spi_read();
    bool moved = mot & 0x80 && observation <= 0x3f;
    if (moved) {
        d->x = spi_read();
        d->x |= spi_read() << 8;
        d->y = spi_read();
        d->y |= spi_read() << 8;
#if defined(CONSOLE_ENABLE)
        //dprintf("pmw3360_motion_burst: mot:%d, observation:%d, dx:%d, dy:%d\n", mot, observation, d->x, d->y);
#endif
    }
    spi_stop();
    // Required NCS in 500ns after motion burst.
    wait_us(1);
    return moved;
}

まとめ

私のKeyball61で起きていた、マウスポインタが意図せずジャンプする問題をファームの実装変更で回避しました。

ちなみに私は Keyball44 も一台持っているのですが、

  • Keyball44 の方では observation の値が 63 を越える現象は観測されませんでした。
  • Keyball61 で、問題が起きていない Keyball44 のセンサー基板、トラックボールケース、トラックボール、ProMicro をそれぞれ換装しても状況変わりませんでした。

という状況でした。また、似たような事象の報告

を見つけて、L字コンスルーの潰れのチェックやハンダ付けのやり直しもしたのですが解消できず、ソフトウェア的な回避をしました。

  • 私の Keyball61 の基板の個体の問題(ハンダ付けなど組み立てが悪い可能性も含め)
  • 他の Keyball61 個体でも起き得る問題

のどちらかはわかっていない(Keyball61は一台しか持ってないので個体差の確認はできていない)のですが、誰かの役に立つ可能性もないとは限らないのでまとめてみました。

Discussion