HOME
  Security
   Software
    Hardware
  
FPGA
  CPU
   Android
    Raspberry Pi
  
nLite
  Xcode
   etc.
    ALL
  
LINK
BACK
 

[NEW] 2021/12/06

QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法 QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法

(QMK firmware expand I/O for many matrix keyboard、How to use I2C GPIO Expander PCF8574 and PCF8575)

Tags: [電子工作]




● QMK firmwareの関連記事


[NEW] 2021/08/23
QMK firmwareの開発環境を ラズパイや Windows WSLにセットアップする方法
QMK firmwareの開発環境を ラズパイや Windows WSLにセットアップする方法

  ラズパイや Windows WSL環境でカスタマイズ キーボードのファームウェア QMK firmwareの開発環境を構築

[UPDATE] 2022/01/09
BUFFALOの USB テンキーを Pro Microと QMKを使って VIAカスタマイズ キーボードに改造する方法
BUFFALOの USB テンキーを Pro Microと QMKを使って VIAカスタマイズ キーボードに改造する方法

  BUFFALO USB 10-Key keyboard BSTK100 modification by Pro Micro and QMK firmware VIA

[NEW] 2021/08/11
社畜のキーボード「新入社員の同期」を購入してみた!! VIA、QMK、Remapでのカスタマイズに対応
社畜のキーボード「新入社員の同期」を購入してみた!! VIA、QMK、Remapでのカスタマイズに対応

  キー内容が Remap等でカスタマイズ可能な社畜のキーボード「新入社員の同期」を 3500円で購入


● QMK firmwareでキーのマトリクス配線で I/Oピンが足りない場合の解決方法、デコーダ、デマルチプレクサ


[NEW] 2021/11/07
QMK firmwareで I/Oピンが足りない場合にデコーダ、デマルチプレクサを使用して IOを拡張する解決方法
QMK firmwareで I/Oピンが足りない場合にデコーダ、デマルチプレクサを使用して IOを拡張する解決方法

  QMK firmware expand I/O for many matrix keyboard、How to use IO Expander Multiplexer / Demultiplexer / Decoder


● QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法

Tutorial How to Expand IO in QMK firmware with Pro Micro Using I2C GPIO Expander


 市販のキーボードを QMK化する場合、キーのマトリクスの配線が 18+8の合計 26本必要です。
 しかし、Pro Microでは I/Oピンの数が足りません。

 QMK Firmwareは STM32にも対応しているので I/Oピンが多い STM32F103の Blue Pill基板(Red Pill基板、Black Pill基板)を使う選択肢や、同じく I/Oピンの多い RP2040の Raspberry Pi Pico基板を非公式 QMKファームフェアで使う方法が考えられます。

 しかし、Boot Loader等のお手軽さから Pro Microをどうしても使用したいのです。

 Pro Microと同じ ATmega32u4を使った Elite-C V4と言う選択肢は安直なのと、値段が高いのと、結局 IO pinが足りないので却下。

基板種類最大 I/O数
ATmega32u4 Pro Micro18本
ATmega32u4 Elite-C V424本
RP2040 Raspberry Pi Pico基板26本
STM32 Blue Pill基板等33本

 ちなみに良くある Pro Microを 2個使った Split型(左手、右手で独立のキーボード)は市販のキーボードの場合はできません。理由はマトリックスが分離していないから。

 と言う訳で Pro Microで多ピンを使う場合の方法を考えます。

 考え中!
 考え中!
 考え中!
  ・
  ・
  ・
 考えた!(ピコーン!)

 I/Oピンが足りないなら I2Cの GPIOエキスパンダを使えば良いじゃないの!(マリー・アントワネット風に)

 と言う訳で今回は PCF8574(8本)、PCF8575(16本)を使って I/Oピン不足を解決します。
 みんな大好き I2C!(モトネタ無し)

 I2Cは OLEDの配線と共通化できるので消費する I/Oピンを実質 0本とみなせます。

 なお、I2Cには PCF8574(8本)、PCF8575(16本)以外にも下記の品種が手に入りやすいです MCP23017(16本)、TCA9555(16本)、TCA6424(24本)。

PCF8574 8 bit8-bit I2C/SMBus I/O expander with interrupt
PCF8575 16 bit16-bit I2C/SMBus I/O expander with interrupt
TCA9555 16 bit16-bit I2C/SMBus I/O expander with interrupt weak pull-up & config registers
TCA6424 24 bit24-bit translating I2C/SMBus I/O expander with interrupt reset & config registers
MCP23017 16 bit16-Bit I2C I/O Expander with Serial Interface

● I2Cの GPIO拡張基板モジュール
今回購入


3個セット PCF8574 IO拡張ボード I2C Arduino用 開発ボード
ASIN: B07BW3VL3C
今回購入


PCF8575 IIC I2C I/O 拡張シールドモジュール 16 ビット SMBus I/O ポート新
ASIN: B083ZWQGMS

※ 基板の色が違うだけ

WINGONEER MCP23017-E/SS I2Cインターフェイス16チャンネルIO拡張モジュール互換 C51 IIC入力および出力拡張ボード
ASIN: B081ZYXW88

HiLetgo TCA9548A I2C IIC マルチプレクサ ブレークアウト ボード 8チャンネル 拡張ボード
ASIN: B078W4YLFG

今回購入


ACEIRMC Pro Micro ATmega32U4 5V/16MHz Arduino用 互換マイクロコントローラ Micro USB 開発ボード (3個セット)
ASIN: B08HC9KHJC

KeeYees Pro Micro ATmega32U4 5V/16MHz 互換マイクロコントローラ Micro USB 開発ボード (3個)
ASIN: B07Q4VRT36

KKHMF 2個 Leonardo Pro Micro ATmega32U4 5V/16MHz ブートローダ マイクロ USB Pro Mini 開発ボード Arduinoに対応
ASIN: B081DY1NWW

VKLSVAN Pro Micro USB ATmega32U4 5V/16MHz マイクロコントローラ Micro USB 開発ボード Arduinoに対応
ASIN: B086GPX434

 なお、74HC4051(8本)と 74HC4067(16本)を使っても I/Oピン不足を解決できます。
74HC4051 8 bit8:1 1-channel analog mutliplexer
74HC4067 16 bit16:1 1-channel analog multiplexer

前回購入


8チャンネル74HC4051アナログマルチプレクサーデマルチプレクサーモジュールラズベリーパイ用単極オクタルスローアナログスイッチ
ASIN: B07ZCP69KS
前回購入


Ren He 3個セット CD74HC4067 高速 CMOS 16チャンネル デジタル アナログ マルチプレクサ 多重 ブレイクアウト ボード モジュール Arduinoと互換
ASIN: B0953LPVKJ

注意:黄色の接続ピンは付属しません

ACEIRMC CD74HC4067 16チャンネル アナログデジタルマルチプレクサー ブレークアウトボードモジュール Arduino 2V-6V マイクロコントローラー用 16デバイス RXライン 10個
ASIN: B08XV26WPS


● QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張してみるテスト

FREEWING-JP / qmk_firmware / test_expand_io_i2c
 QMKで キーのマトリクス配線の I/Oピン拡張のテストのソースリスト一式。


● QMK firmwareで matrix.c

QMK - Custom Matrix
 Extra hardware between the keyboard's switches and MCU pins
 ・I/O multiplexer
 ・Line decoder

 QMKは元々 I/Oピンが足りない場合に I/O multiplexerや Line decoderを使う事を想定しています。

rules.mk
CUSTOM_MATRIX = lite        # I2C PCF8574 and PCF8575
SRC += matrix.c
QUANTUM_LIB_SRC += i2c_master.c

matrix.c
void matrix_init_custom(void) {
    // TODO: initialize hardware here
}

bool matrix_scan_custom(matrix_row_t current_matrix[]) {
    bool matrix_has_changed = false;
    // TODO: add matrix scanning routine here
    return matrix_has_changed;
}

● QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張の回路図

 今回は I2Cの GPIOとして NXP社(TI社)の PCF8574と PCF8575を使用します。

 PCF8574、PCF8575を使用して 8+16の I/Oを拡張しています。
 PCF8574で GPIOを 8本に拡張、Col出力として使用
 PCF8575で GPIOを 16本に拡張、Row入力として使用

 PCF8574は Col出力として 8bitのどれか 1本が 'L'に成る様にデコーダとして使用しています。

 PCF8575は Row入力として内部プルアップ有りの入力を指定しています。
 内部プルアップなので、キー入力が無い時は 'H'、キー入力が有る時は 'L'('L'アクティブ)になります。(PCF8574が Col出力として 'L'を出力しているから)

 今回の製作例では Col出力、Row入力共に PCF8574(8bit GPIO)を使用しています。
 (基板同士を連結できて手軽だから)

I2C アドレス(基本)I2C アドレス(Write)I2C アドレス(Read)
Col出力PCF8574(8bit GPIO)0x20(A2=L A1=L A0=L)0x400x41青基板
Row入力PCF8574(8bit GPIO)0x24(A2=H A1=L A0=L)0x480x49赤基板

・QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法
QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法
 色々買ってみた!

QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法
 PCF8575モジュール

QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法
 PCF8574モジュール(青)

QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法
 PCF8574モジュール(赤)

QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法


QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法


QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法
 PCF8574モジュールの青基板は複数の基板を連結できます。
 (終端に赤基板を連結できる)

QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法


QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法
 PCF8575モジュール基板には I2C信号のプルアップ抵抗等の実装が有りません。
 (基板の R1、 R2が I2C信号のプルアップ抵抗の実装場所)

QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法



・QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法
QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法
 とりあえず、OLEDモジュールと PCF8574モジュール、ブザーを配線しました。

QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法
 青基板を Col出力、赤基板を Row入力として使います。
 赤基板側にも I2C信号のプルアップ抵抗(1KΩ)があるので、青基板側の I2C信号のプルアップ抵抗(1KΩ)は取り除いています。

QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法
 裏側の様子。

QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法


QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法


QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法


QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法
 4x4のキーボードを接続して動作確認を行ないました。

QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法


QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法


QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法



・QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法
QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法


QMK firmwareで I/Oピンが足りない場合に I2Cの GPIOエキスパンダを使用して IOを拡張する解決方法
 I2Cの GPIOエキスパンダを使った方法でも QMKキーボードを作成できました!


 下記のソースで動作確認済み

 I2C GPIO+I2C GPIO構成で本当に動くのか不安だったので PoCとして 4x4のキーボードを接続して動作確認を行ないました。
 PoC = Proof of Concept、概念実証、試作開発の前段階における検証

 今回の製作例では Col出力、Row入力共に PCF8574(8bit GPIO)を使用しています。

matrix.c
// Copyright 2021 Y.Sakamoto (@FREEWING-JP)
// SPDX-License-Identifier: GPL-2.0-or-later

#include "matrix.h"
#include "gpio.h"
#include "i2c_master.h"

#if (MATRIX_ROWS <= 8)
#    define ROW_TYPE uint8_t
#elif (MATRIX_ROWS <= 16)
#    define ROW_TYPE uint16_t
#elif (MATRIX_ROWS <= 32)
#    define ROW_TYPE uint32_t
#endif

#define ROW_SHIFTER ((ROW_TYPE)1)

#define PCF857x_I2C_TIMEOUT 1000

#define I2C_WRITE 0x00
#define I2C_READ 0x01

// Col Output PCF8574 (A2=L, A1=L, A0=L)
#define I2C_ADDR_COL 0x20
#define I2C_ADDR_COL_WRITE ((I2C_ADDR_COL << 1) | I2C_WRITE)
#define I2C_ADDR_COL_READ ((I2C_ADDR_COL << 1) | I2C_READ)

// Row Input PCF857x (A2=H, A1=L, A0=L)
#define I2C_ADDR_ROW 0x24
#define I2C_ADDR_ROW_WRITE ((I2C_ADDR_ROW << 1) | I2C_WRITE)
#define I2C_ADDR_ROW_READ ((I2C_ADDR_ROW << 1) | I2C_READ)

// Col Output PCF8574 8bit
static void col_init(void) {
    // All Output 'H'
    uint8_t buf[] = { 0b11111111 };
    i2c_transmit(I2C_ADDR_COL_WRITE, buf, sizeof(buf), PCF857x_I2C_TIMEOUT);
}

// Row Input PCF8574 8bit / PCF8575 16bit
static void row_init(void) {
#if (MATRIX_ROWS <= 8)
    // Row Input PCF8574 8bit
    // All Input Pull Up
    uint8_t buf[] = { 0b11111111 };
    i2c_transmit(I2C_ADDR_ROW_WRITE, buf, sizeof(buf), PCF857x_I2C_TIMEOUT);
#elif (MATRIX_ROWS <= 16)
    // Row Input PCF8575 16bit
    // All Input Pull Up
    uint8_t buf[] = { 0b11111111, 0b11111111 };
    i2c_transmit(I2C_ADDR_ROW_WRITE, buf, sizeof(buf), PCF857x_I2C_TIMEOUT);
#elif (MATRIX_ROWS <= 32)
    TODO()
#endif
}

// Col Output PCF8574 8bit
static void select_col(uint8_t col) {
    // Col Output 'L'
    uint8_t colByte = ~(1 << col);
    uint8_t buf[] = { colByte };
    i2c_transmit(I2C_ADDR_COL_WRITE, buf, sizeof(buf), PCF857x_I2C_TIMEOUT);
}

// Row Input PCF8574 8bit / PCF8575 16bit
static ROW_TYPE read_rows(void) {
#if (MATRIX_ROWS <= 8)
    // Row Input PCF8574 8bit
    uint8_t buf[1];
    i2c_receive(I2C_ADDR_ROW_READ, buf, sizeof(buf), PCF857x_I2C_TIMEOUT);
    return ~buf[0];
#elif (MATRIX_ROWS <= 16)
    // Row Input PCF8575 16bit
    uint8_t buf[2];
    i2c_receive(I2C_ADDR_ROW_READ, buf, sizeof(buf), PCF857x_I2C_TIMEOUT);
    return ~((buf[1] << 8) | buf[0]);
#elif (MATRIX_ROWS <= 32)
    TODO()
#endif
}

void matrix_init_custom(void) {
    i2c_init();
    col_init();
    row_init();
}

// MATRIX_ROWS = 4
// MATRIX_COLS = 4
// matrix_row_t = uint8_t
bool matrix_scan_custom(matrix_row_t current_matrix[]) {
    // Scan Keyboard Matrix
    ROW_TYPE tmp[MATRIX_COLS];
    ROW_TYPE* pt = tmp;
    for (uint8_t col = 0; col < MATRIX_COLS; ++col) {
        // MSB = col 7, LSB = col 0
        select_col(col);
        matrix_io_delay();

        *pt++ = read_rows();
    }
    col_init();

    // Check Keyboard Matrix has Changed
    bool matrix_has_changed = false;
    matrix_row_t* p = current_matrix;
    for (uint8_t row = 0; row < MATRIX_ROWS; ++row) {

        ROW_TYPE and_row = (ROW_SHIFTER << row);
        matrix_row_t now_rows = 0;
        int8_t col = MATRIX_COLS;
        while (--col >= 0) {
            now_rows <<= 1;
            now_rows |= ((tmp[col] & and_row) ? 1 : 0);
        }

        if (*p != now_rows) {
            *p = now_rows;
            matrix_has_changed = true;
        }
        ++p;
    }

    return matrix_has_changed;
}

config.h
// Copyright 2021 Y.Sakamoto (@FREEWING-JP)
// SPDX-License-Identifier: GPL-2.0-or-later

/* key matrix size */
#define MATRIX_ROWS 4
#define MATRIX_COLS 4

/*
 * Keyboard Matrix Assignments
 *
 * Change this to how you wired your keyboard
 * COLS: AVR pins used for columns, left to right
 * ROWS: AVR pins used for rows, top to bottom
 * DIODE_DIRECTION: COL2ROW = COL = Anode (+), ROW = Cathode (-, marked on diode)
 *                  ROW2COL = ROW = Anode (+), COL = Cathode (-, marked on diode)
 *
 */
#define MATRIX_ROW_PINS { NO_PIN, NO_PIN, NO_PIN, NO_PIN }
#define MATRIX_COL_PINS { NO_PIN, NO_PIN, NO_PIN, NO_PIN }
 // #define UNUSED_PINS

/* COL2ROW, ROW2COL */
 // #define DIODE_DIRECTION COL2ROW

/*
 * the delay in microseconds when between changing matrix pin state and reading values
 */
#define MATRIX_IO_DELAY 30 // 30us, 8*30us = 8us = 0.240ms



Tags: [電子工作]

●関連するコンテンツ(この記事を読んだ人は、次の記事も読んでいます)

BUFFALOの USB テンキーを Pro Microと QMKを使って VIAカスタマイズ キーボードに改造する方法
BUFFALOの USB テンキーを Pro Microと QMKを使って VIAカスタマイズ キーボードに改造する方法

  BUFFALO USB 10-Key keyboard BSTK100 modification by Pro Micro and QMK firmware VIA

QMK firmwareの開発環境を ラズパイや Windows WSLにセットアップする方法
QMK firmwareの開発環境を ラズパイや Windows WSLにセットアップする方法

  ラズパイや Windows WSL環境でカスタマイズ キーボードのファームウェア QMK firmwareの開発環境を構築

QMK firmwareでプログラムのサイズを小さくするテクニック、ケチケチ プログラミングの方法
QMK firmwareでプログラムのサイズを小さくするテクニック、ケチケチ プログラミングの方法

  QMK firmware How to Reduce Program Size、Reducing QMK firmware size

QMK firmwareで I/Oピンが足りない場合にデコーダ、デマルチプレクサを使用して IOを拡張する解決方法
QMK firmwareで I/Oピンが足りない場合にデコーダ、デマルチプレクサを使用して IOを拡張する解決方法

  QMK firmware expand I/O for many matrix keyboard、How to use IO Expander Multiplexer / Demultiplexer / Decoder

QMK firmwareで本当の自作キーボードを簡単に作る方法
QMK firmwareで本当の自作キーボードを簡単に作る方法

  QMK firmware easily create 4x4 matrix own original keyboard

QMK firmwareで Audio機能を試してみる
QMK firmwareで Audio機能を試してみる

  QMK firmware test Audio function with Piezo buzzer

QMK firmwareで OLED機能で SSD1306を試してみる
QMK firmwareで OLED機能で SSD1306を試してみる

  QMK firmware test OLED Driver with SSD1306

QMK firmwareで Analog Stick機能で PSP2000用アナログ ジョイスティックを試してみる
QMK firmwareで Analog Stick機能で PSP2000用アナログ ジョイスティックを試してみる

  QMK firmware test Analog Joystick function with PSP2000 Analog Stick

最新の QMK firmwareで new_keyboard.shのコマンドが動かなくなったのを修正する方法
最新の QMK firmwareで new_keyboard.shのコマンドが動かなくなったのを修正する方法

  QMK Bugfix Create New Keyboard new_keyboard.sh command No such file or directory Error

QMK firmwareの Githubを forkした自分のリモートに pushすると怒られて pushできない場合の対応方法
QMK firmwareの Githubを forkした自分のリモートに pushすると怒られて pushできない場合の対応方法

  refusing to allow an OAuth App to create or update workflow `.github/workflows/api.yml` without `workflow` scope

中華製の格安なプログラマブル USBキーボードを買ってみた QMK VIAとは別物
中華製の格安なプログラマブル USBキーボードを買ってみた QMK VIAとは別物

  中華製のプログラマブル USBキーボード KeyboardSetter.exe

社畜のキーボード「新入社員の同期」を購入してみた!! VIA、QMK、Remapでのカスタマイズに対応
社畜のキーボード「新入社員の同期」を購入してみた!! VIA、QMK、Remapでのカスタマイズに対応

  キー内容が Remap等でカスタマイズ可能な社畜のキーボード「新入社員の同期」を 3500円で購入




[HOME] | [BACK]
リンクフリー(連絡不要、ただしトップページ以外は Web構成の変更で移動する場合があります)
Copyright (c) 2021 FREE WING,Y.Sakamoto
Powered by 猫屋敷工房 & HTML Generator

http://www.neko.ne.jp/~freewing/hardware/qmk_firmware_test_matrix_expand_io_i2c_pcf8574_pcf8575/