Matrix - inpudiy/zmk-guide GitHub Wiki
В этой части рассматривается процесс описания физической матрицы для разных вариантов распиновки.
Matrix transform
Начнём с того, что создадим файл с форматом имяплаты.dtsi
в директории /board/shield/имяплаты
. Вставим эту строку в начало для импорта нужного файла:
#include <dt-bindings/zmk/matrix_transform.h>
Следующим шагом зададим имя трансформации — можно указать несколько, если есть разные варианты количества клавиш. В нашем случае вариант один, поэтому просто напишем &default_transform;
.
#include <dt-bindings/zmk/matrix_transform.h>
/ {
chosen {
zmk,kscan = &kscan0;
zmk,matrix-transform = &default_transform;
};
Опускаемся ниже и описываем эту трансформацию. Обращаемся к ней по имени, указываем метод трансформации, а именно "zmk,matrix-transform"
, и задаём количество колонок и рядов:
default_transform: keymap_transform_0 {
compatible = "zmk,matrix-transform";
columns = <12>;
rows = <4>;
};
Почему 12 колонок и 4 ряда? Потому что на каждой половинке, в нашем случае, по 6 колонок, а рядов и там, и там по 4 штуки. Описав первые 6 колонок в левой половинке, мы затем укажем, на сколько выполнить смещение для правой половинки. Станет понятнее, когда мы начнем их описывать. Пока для удобства можем в этом же блоке с помощью комментариев указать, как примерно будет выглядеть матрица с номерами клавиш:
// | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 |
// | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 |
// | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 |
// | SW21 | SW20 | SW19 | | SW19 | SW20 | SW21 |
Как видно, номера клавиш доходят до 21 на левой половинке и снова начинаются с 1 на другой половинке.
Следующий шаг — создание map, чтобы указать, в какой колонке и ряду находится каждая клавиша. Здесь используется конструкция вида RC(0,5)
, где первое число — номер ряда (row), а второе — номер колонки (col). Вот пример для такой матрицы:
map = <
RC(0,5) RC(0,4) RC(0,3) RC(0,2) RC(0,1) RC(0,0) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11)
RC(1,5) RC(1,4) RC(1,3) RC(1,2) RC(1,1) RC(1,0) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11)
RC(2,5) RC(2,4) RC(2,3) RC(2,2) RC(2,1) RC(2,0) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11)
RC(3,2) RC(3,1) RC(3,0) RC(3,6) RC(3,7) RC(3,8)
>;
Теперь наш файл целиком выглядит так:
#include <dt-bindings/zmk/matrix_transform.h>
/ {
chosen {
zmk,kscan = &kscan0;
zmk,matrix-transform = &default_transform;
};
default_transform: keymap_transform_0 {
compatible = "zmk,matrix-transform";
columns = <12>;
rows = <4>;
// | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 |
// | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 |
// | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 |
// | SW21 | SW20 | SW19 | | SW19 | SW20 | SW21 |
map = <
RC(0,5) RC(0,4) RC(0,3) RC(0,2) RC(0,1) RC(0,0) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11)
RC(1,5) RC(1,4) RC(1,3) RC(1,2) RC(1,1) RC(1,0) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11)
RC(2,5) RC(2,4) RC(2,3) RC(2,2) RC(2,1) RC(2,0) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11)
RC(3,2) RC(3,1) RC(3,0) RC(3,6) RC(3,7) RC(3,8)
>;
};
};
Gpio-matrix
После создания матрицы нам необходимо описать, куда подключаются ряды и колонки. Для этого нужно посмотреть на номера пинов. Рассмотрим пример отладочной платы формата Pro Micro.
Нас интересуют именно синие цифры — их мы и будем указывать. Для понимания давайте разберём несколько примеров.
Одинаковая распиновка
В первом примере рассмотрим вариант с col2row (ток подаётся на колонки и считывается с рядов), где на каждой половинке ряды и колонки подключены к одинаковым пинам.
Создаём блок для gpio-matrix и указываем направление диодов:
kscan0: kscan {
compatible = "zmk,kscan-gpio-matrix";
diode-direction = "col2row";
wakeup-source;
};
Следующим шагом ниже описываем подключение рядов, поскольку для них не требуется смещение, и их номера совпадают на обеих половинках:
row-gpios =
<&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // row1
, <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // row2
, <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // row3
, <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // row4
;
В конечном счёте с такой распиновкой основной файл выглядит вот так:
#include <dt-bindings/zmk/matrix_transform.h>
/ {
chosen {
zmk,kscan = &kscan0;
zmk,matrix-transform = &default_transform;
};
default_transform: keymap_transform_0 {
compatible = "zmk,matrix-transform";
columns = <12>;
rows = <4>;
// | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 |
// | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 |
// | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 |
// | SW21 | SW20 | SW19 | | SW19 | SW20 | SW21 |
map = <
RC(0,5) RC(0,4) RC(0,3) RC(0,2) RC(0,1) RC(0,0) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11)
RC(1,5) RC(1,4) RC(1,3) RC(1,2) RC(1,1) RC(1,0) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11)
RC(2,5) RC(2,4) RC(2,3) RC(2,2) RC(2,1) RC(2,0) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11)
RC(3,2) RC(3,1) RC(3,0) RC(3,6) RC(3,7) RC(3,8)
>;
};
kscan0: kscan {
compatible = "zmk,kscan-gpio-matrix";
diode-direction = "col2row";
wakeup-source;
row-gpios =
<&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // row1
, <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // row2
, <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // row3
, <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // row4
;
};
};
Теперь нам нужно в этой же директории создать файлы, в которых будут указаны пины для каждой половинки.
Начнём с левой и создадим файл имяплаты_left.overlay
. В нём укажем распиновку для левой половинки:
#include "имяплаты.dtsi"
&kscan0 {
col-gpios
= <&pro_micro 19 GPIO_ACTIVE_HIGH> // col1
, <&pro_micro 18 GPIO_ACTIVE_HIGH> // col2
, <&pro_micro 15 GPIO_ACTIVE_HIGH> // col3
, <&pro_micro 14 GPIO_ACTIVE_HIGH> // col4
, <&pro_micro 16 GPIO_ACTIVE_HIGH> // col5
, <&pro_micro 10 GPIO_ACTIVE_HIGH> // col6
;
};
Теперь создадим такой же файл только для правой половинки.
#include "имяплаты.dtsi"
&kscan0 {
col-gpios
= <&pro_micro 19 GPIO_ACTIVE_HIGH> // col7
, <&pro_micro 18 GPIO_ACTIVE_HIGH> // col8
, <&pro_micro 15 GPIO_ACTIVE_HIGH> // col9
, <&pro_micro 14 GPIO_ACTIVE_HIGH> // col10
, <&pro_micro 16 GPIO_ACTIVE_HIGH> // col11
, <&pro_micro 10 GPIO_ACTIVE_HIGH> // col12
;
};
Поскольку мы указали 12 колонок, нужно обозначить, на сколько мы сместили колонки, чтобы начать с 7-й. Для этого между #include "имяплаты.dtsi"
и &kscan0 {
вставляем вот этот блок:
&default_transform {
col-offset = <6>;
};
И теперь файл для правой половинки выглядит вот так:
#include "имяплаты.dtsi"
&default_transform {
col-offset = <6>;
};
&kscan0 {
col-gpios
= <&pro_micro 19 GPIO_ACTIVE_HIGH> // col7
, <&pro_micro 18 GPIO_ACTIVE_HIGH> // col8
, <&pro_micro 15 GPIO_ACTIVE_HIGH> // col9
, <&pro_micro 14 GPIO_ACTIVE_HIGH> // col10
, <&pro_micro 16 GPIO_ACTIVE_HIGH> // col11
, <&pro_micro 10 GPIO_ACTIVE_HIGH> // col12
;
};
Разная распиновка
Во втором случае у нас на каждой половинке колонки и ряды подключены к разным пинам. Теперь нам нужно указывать и ряды, и колонки для каждой из них в .overlay
файлах. Поэтому основной .dtsi
файл теперь выглядит так:
#include <dt-bindings/zmk/matrix_transform.h>
/ {
kscan0: kscan0 {
compatible = "zmk,kscan-gpio-matrix";
diode-direction = "col2row";
wakeup-source;
};
chosen {
zmk,kscan = &kscan0;
zmk,matrix-transform = &default_transform;
};
default_transform: keymap_transform_0 {
compatible = "zmk,matrix-transform";
columns = <12>;
rows = <4>;
map = <
RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11)
RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11)
RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11)
RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8)
>;
};
};
В overlay-файлах теперь всё указывается индивидуально. Вот пример для левой половинки:
#include "имяплаты.dtsi"
&kscan0 {
col-gpios
= <&pro_micro 4 GPIO_ACTIVE_HIGH> // col0
, <&pro_micro 5 GPIO_ACTIVE_HIGH> // col1
, <&pro_micro 6 GPIO_ACTIVE_HIGH> // col2
, <&pro_micro 8 GPIO_ACTIVE_HIGH> // col3
, <&pro_micro 9 GPIO_ACTIVE_HIGH> // col4
, <&pro_micro 2 GPIO_ACTIVE_HIGH> // col5
;
row-gpios
= <&pro_micro 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // row0
, <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // row1
, <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // row2
, <&pro_micro 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // row3
;
};
И пример для правой половинки:
#include "имяплаты.dtsi"
&default_transform {
col-offset = <6>;
};
&kscan0 {
col-gpios
= <&pro_micro 21 GPIO_ACTIVE_HIGH> // col6
, <&pro_micro 10 GPIO_ACTIVE_HIGH> // col7
, <&pro_micro 16 GPIO_ACTIVE_HIGH> // col8
, <&pro_micro 15 GPIO_ACTIVE_HIGH> // col9
, <&pro_micro 18 GPIO_ACTIVE_HIGH> // col10
, <&pro_micro 19 GPIO_ACTIVE_HIGH> // col11
;
row-gpios
= <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // row0
, <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // row1
, <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // row2
, <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // row3
;
};
Разница между col2row и row2col
В случае с col2row катод диода подключён к строке, а в случае с row2col — к колонке. Поэтому необходимо немного изменить тип пинов. Подробнее это описано здесь.
Вот как описывать пины в случае col2row:
&kscan0 {
col-gpios
= <&pro_micro 21 GPIO_ACTIVE_HIGH> // col6
, <&pro_micro 10 GPIO_ACTIVE_HIGH> // col7
, <&pro_micro 16 GPIO_ACTIVE_HIGH> // col8
, <&pro_micro 15 GPIO_ACTIVE_HIGH> // col9
, <&pro_micro 18 GPIO_ACTIVE_HIGH> // col10
, <&pro_micro 19 GPIO_ACTIVE_HIGH> // col11
;
row-gpios
= <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // row0
, <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // row1
, <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // row2
, <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // row3
;
};
А вот как это выглядит для row2col — здесь GPIO_PULL_DOWN
указывается для колонок:
&kscan0 {
col-gpios =
<&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
, <&pro_micro 18 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
, <&pro_micro 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
, <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
, <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
, <&pro_micro 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
;
row-gpios =
<&pro_micro 5 GPIO_ACTIVE_HIGH>
, <&pro_micro 6 GPIO_ACTIVE_HIGH>
, <&pro_micro 7 GPIO_ACTIVE_HIGH>
, <&pro_micro 8 GPIO_ACTIVE_HIGH>
;
};