自作トラックポイント1


さて分割キーボードもひと段落したので次の課題に取り組もうと思う。

トラックポイントを分割キーボードの右側に取り付けたい。

普通のThinkpadキーボードはH,J,Nの間にあるが、狭いし
ちょうど基盤の回路を引いた線が邪魔で穴があけられない。次回Kicadで設計するときは避けるようにしよう。

トラックポイントの生贄

すでに壊れてたので、本物のthinkpadキーボードから部品を拝借。

開封

Trackポイント ハック

上のサイトからどれが何ピンなのか理解する

以降写真撮り忘れたが、

ファームウェアを焼く

トラックポイントの実装

今回はQMKFirmwareにPS2 Mouseで接続する方法が載ってる
https://github.com/qmk/qmk_firmware/blob/master/docs/ja/feature_ps2_mouse.md

マウスホイールの実装

以下は実際に動いたサンプルソース

rules.mk

# トラックポイント接続用設定
PS2_MOUSE_ENABLE = yes
PS2_USE_BUSYWAIT = yes # <- 非推奨だが、空きポートを確保できないためこれで
#PS2_USE_INT = yes
#PS2_USE_USART = yes
OLED_DRIVER_ENABLE = no


# スクロールホイール用
MOUSEKEY_ENABLE = yes
ENCODER_ENABLE = yes

config.h


#pragma once


/*
 * Busywait Version :id=busywait-version
 * Note: This is not recommended, you may encounter jerky movement or unsent inputs. Please use interrupt or USART version if possible.
 */

/*
トラックポイント接続はここでハマった。PORTD,PIND,DDRDと公式ドキュメントに例が載ってるが、
CLOCK_BITの数字がPromicroのピン番号を表しているのかと思ったらそうではなかった。

最後のアルファベットが例えばATMega32U4上のD3ピンに接続したければ最後の一文字を「D」とし
PS2_CLOCK_BIT   3とするということだった。
これがドキュメント見ても理解できず時間を無駄にした。
QMKのドキュメントは説明が全然足りないよ。
 */

#ifdef PS2_USE_BUSYWAIT
#   define PS2_CLOCK_PORT  PORTD
#   define PS2_CLOCK_PIN   PIND
#   define PS2_CLOCK_DDR   DDRD
#   define PS2_CLOCK_BIT   3
#   define PS2_DATA_PORT   PORTB
#   define PS2_DATA_PIN    PINB
#   define PS2_DATA_DDR    DDRB
#   define PS2_DATA_BIT    1
#endif



/*
 * Interrupt Version :id=interrupt-version
 * The following example uses B5 for clock and B6 for data. You can use any INT or PCINT pin for clock, and any pin for data.
 */

#ifdef PS2_USE_INT
#   define PS2_CLOCK_PORT  PORTB
#   define PS2_CLOCK_PIN   PINB
#   define PS2_CLOCK_DDR   DDRB
#   define PS2_CLOCK_BIT   5
#   define PS2_DATA_PORT   PORTB
#   define PS2_DATA_PIN    PINB
#   define PS2_DATA_DDR    DDRB
#   define PS2_DATA_BIT    6

#   define PS2_INT_INIT()  do {    \
       PCICR |= (1<<PCIE0);        \
    } while (0)
#   define PS2_INT_ON()  do {      \
       PCMSK0 |= (1<<PCINT5);      \
    } while (0)
#   define PS2_INT_OFF() do {      \
       PCMSK0 &= ~(1<<PCINT5);     \
    } while (0)
#   define PS2_INT_VECT   PCINT0_vect
#endif

/*
 * USART Version :id=usart-version
 * To use USART on the ATMega32u4, you have to use PD5 for clock and PD2 for data. If one of those are unavailable, you need to use interrupt version.
 *   synchronous, odd parity, 1-bit stop, 8-bit data, sample at falling edge
 *   set DDR of CLOCK as input to be slave
 */

#ifdef PS2_USE_USART
#   define PS2_CLOCK_PORT  PORTD
#   define PS2_CLOCK_PIN   PIND
#   define PS2_CLOCK_DDR   DDRD
#   define PS2_CLOCK_BIT   5
#   define PS2_DATA_PORT   PORTD
#   define PS2_DATA_PIN    PIND
#   define PS2_DATA_DDR    DDRD
#   define PS2_DATA_BIT    2

#   define PS2_USART_INIT() do {   \
       PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT);   \
       PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT);     \
       UCSR1C = ((1 << UMSEL10) |  \
                 (3 << UPM10)   |  \
                 (0 << USBS1)   |  \
                 (3 << UCSZ10)  |  \
                 (0 << UCPOL1));   \
       UCSR1A = 0;                 \
       UBRR1H = 0;                 \
       UBRR1L = 0;                 \
    } while (0)
#   define PS2_USART_RX_INT_ON() do {  \
       UCSR1B = ((1 << RXCIE1) |       \
                 (1 << RXEN1));        \
    } while (0)
#   define PS2_USART_RX_POLL_ON() do { \
       UCSR1B = (1 << RXEN1);          \
    } while (0)
#   define PS2_USART_OFF() do {    \
       UCSR1C = 0;                 \
       UCSR1B &= ~((1 << RXEN1) |  \
                   (1 << TXEN1));  \
    } while (0)
#   define PS2_USART_RX_READY      (UCSR1A & (1<<RXC1))
#   define PS2_USART_RX_DATA       UDR1
#   define PS2_USART_ERROR         (UCSR1A & ((1<<FE1) | (1<<DOR1) | (1<<UPE1)))
#   define PS2_USART_RX_VECT       USART1_RX_vect
#endif


#ifdef ENCODER_ENABLE
#  define ENCODERS_PAD_A { F6 }
#  define ENCODERS_PAD_B { F7 }

#  define ENCODER_RESOLUTION 2

#endif

keymap.c

#include QMK_KEYBOARD_H
#include "keymap.h"

// Defines names for use in layer keycodes and the keymap
enum layer_names {
    _BASE
};

// Defines the keycodes used by our macros in process_record_user
enum custom_keycodes {
    QMKBEST = SAFE_RANGE,
    QMKURL
};

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    /* Base */
    [_BASE] = LAYOUT(
        KC_A, KC_B, \
        KC_C, KC_D \
    )
};



bool process_record_user(uint16_t keycode, keyrecord_t *record) {
  switch (keycode) {

  }
  return true;
}

void matrix_init_user(void) {
    // put your keyboard start-up code here
    // runs once when the firmware starts up
}

void matrix_scan_user(void) {
    // put your looping keyboard code here
    // runs every cycle (a lot)
}

void encoder_update_user(uint8_t index, bool clockwise) {
    // put your scroll wheel

    if (index == 0) { /* First encoder */
        if (clockwise) {
            tap_code(KC_MS_WH_DOWN);
        } else {
            tap_code(KC_MS_WH_UP);
        }
    } else if (index == 1) { /* Second encoder */
        if (clockwise) {
            tap_code(KC_DOWN);
        } else {
            tap_code(KC_UP);
        }
    }
}

ブレッドボードに組み込んだ様子

ごちゃごちゃだけど、キーボードも、トラックポイントもマウスホイールもちゃんと動く。