3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

オリジナルZMKファームウェアの作成方法を忘れないようにまとめた

3
Posted at

はじめに

QMKとだいぶ勝手が違って困った。環境が整いすぎてて困ったのでここにまとめていく。

また、オリジナルキーボードのファームウェアの作り方がいまいちまとまってなかったので、自分用にまとめる。

今回はthumbRotary というキーボードを作ったので、これが出てくるところは随時、ご自身のキーボード名に置き換えてください。

thumbRotaryについて

XIAO nRF52840を使った分割無線機ボードです。

Keyballライクな外径にし、左右対象のキー配置で、親指でロータリエンコーダを操作できるものとなっています。

一体型とは異なる部分があるので、一体型を作る場合は適宜公式ドキュメントをご参照ください。

環境構築

1. Githubアカウントを用意する

CICDが自動で回るようになっているので、Githubアカウントが必要です。また、Web上でキーマップを編集する作業をするためにリポジトリを接続する必要があるのもGithubが必要な理由です。

2. テンプレートリポジトリをローカルにクローン

以下のコマンドから、zmkファームウェアのテンプレートをローカルにクローンしてください。

後ほど、Github Actionsを回すためにリモートに紐づけます。

git clone https://github.com/zmkfirmware/unified-zmk-config-template.git zmk-config-thumbRotary

ファームウェア作成

1. 必要ファイルを作成

スクリーンショット 2025-10-01 10.15.55.png

先ほどクローンしたzmk-config-thumbRotaryディレクトリ内が左図です。

手順は主に以下です。

  1. boards/shieldsにキーボード名のドキュメントを追加。
  2. 追加したディレクトリ内に、左右共通のdefconfig, shield, dtsiファイルを追加
  3. 左右それぞれの設定ファイルである、conf, overlayファイルを追加
  4. configディレクトリ内に、info.json, conf, keymapファイルを追加

ちゃんと理解しているわけではないので、詳細な説明は省きます。

2. キーレイアウトを用意

Keyboard Layout Editorを使用してレイアウトを作成します。

Col,Rowでラベルを入れることを忘れないようにする。

スクリーンショット 2025-09-30 19.35.19.png

基盤に実装した形(上図)でまずはレイアウトを作成したが、ファームウェアを作成するにあたって、オーソリニア配列で作成すると扱いやすかったので、以下に変更。

スクリーンショット 2025-10-01 10.20.57.png

Row Dataは以下となった。

["0,0","0,1","0,2","0,3","0,4","0,5",{x:7},"0,6","0,7","0,8","0,9","0,10","0,11"],
["1,0","1,1","1,2","1,3","1,4","1,5",{x:7},"1,6","1,7","1,8","1,9","1,10","1,11"],
["2,0","2,1","2,2","2,3","2,4","2,5",{x:7},"2,6","2,7","2,8","2,9","2,10","2,11"],
["3,0","3,1","3,2","3,3","3,4","3,5","3,6",{x:5},"3,7","3,8","3,9","3,10","3,11","3,12","3,13"]

3. info.jsonを生成

QMK FirmwareのKLE to QMKを利用して、作成したRow Dataをinfo.jsonの形式に変換する。

出力は以下となった。

{
    "keyboard_name": "", 
    "url": "", 
    "maintainer": "qmk", 
    "layouts": {
        "LAYOUT": {
            "layout": [{"label":"0,0", "x":0, "y":0}, {"label":"0,1", "x":1, "y":0}, {"label":"0,2", "x":2, "y":0}, {"label":"0,3", "x":3, "y":0}, {"label":"0,4", "x":4, "y":0}, {"label":"0,5", "x":5, "y":0}, {"label":"0,6", "x":13, "y":0}, {"label":"0,7", "x":14, "y":0}, {"label":"0,8", "x":15, "y":0}, {"label":"0,9", "x":16, "y":0}, {"label":"0,10", "x":17, "y":0}, {"label":"0,11", "x":18, "y":0}, {"label":"1,0", "x":0, "y":1}, {"label":"1,1", "x":1, "y":1}, {"label":"1,2", "x":2, "y":1}, {"label":"1,3", "x":3, "y":1}, {"label":"1,4", "x":4, "y":1}, {"label":"1,5", "x":5, "y":1}, {"label":"1,6", "x":13, "y":1}, {"label":"1,7", "x":14, "y":1}, {"label":"1,8", "x":15, "y":1}, {"label":"1,9", "x":16, "y":1}, {"label":"1,10", "x":17, "y":1}, {"label":"1,11", "x":18, "y":1}, {"label":"2,0", "x":0, "y":2}, {"label":"2,1", "x":1, "y":2}, {"label":"2,2", "x":2, "y":2}, {"label":"2,3", "x":3, "y":2}, {"label":"2,4", "x":4, "y":2}, {"label":"2,5", "x":5, "y":2}, {"label":"2,6", "x":13, "y":2}, {"label":"2,7", "x":14, "y":2}, {"label":"2,8", "x":15, "y":2}, {"label":"2,9", "x":16, "y":2}, {"label":"2,10", "x":17, "y":2}, {"label":"2,11", "x":18, "y":2}, {"label":"3,0", "x":0, "y":3}, {"label":"3,1", "x":1, "y":3}, {"label":"3,2", "x":2, "y":3}, {"label":"3,3", "x":3, "y":3}, {"label":"3,4", "x":4, "y":3}, {"label":"3,5", "x":5, "y":3}, {"label":"3,6", "x":6, "y":3}, {"label":"3,7", "x":12, "y":3}, {"label":"3,8", "x":13, "y":3}, {"label":"3,9", "x":14, "y":3}, {"label":"3,10", "x":15, "y":3}, {"label":"3,11", "x":16, "y":3}, {"label":"3,12", "x":17, "y":3}, {"label":"3,13", "x":18, "y":3}]
        }
    }
}

zmkで使用できるように "label":"0,0"”row”:0, ”col”:0 に変換し、諸々情報を書き加えて以下となった。

{
  "id": "thumbRotary",
  "name": "thumbRotary",
  "keyboard_name": "",
  "url": "",
  "maintainer": "qmk",
  "layouts": {
    "LAYOUT": {
      "layout": [{"row":0, "col":0, "x":0, "y":0}, {"row":0, "col":1, "x":1, "y":0}, {"row":0, "col":2, "x":2, "y":0}, {"row":0, "col":3, "x":3, "y":0}, {"row":0, "col":4, "x":4, "y":0}, {"row":0, "col":5, "x":5, "y":0}, {"row":0, "col":6, "x":13, "y":0}, {"row":0, "col":7, "x":14, "y":0}, {"row":0, "col":8, "x":15, "y":0}, {"row":0, "col":9, "x":16, "y":0}, {"row":0, "col":10, "x":17, "y":0}, {"row":0, "col":11, "x":18, "y":0}, {"row":1, "col":0, "x":0, "y":1}, {"row":1, "col":1, "x":1, "y":1}, {"row":1, "col":2, "x":2, "y":1}, {"row":1, "col":3, "x":3, "y":1}, {"row":1, "col":4, "x":4, "y":1}, {"row":1, "col":5, "x":5, "y":1}, {"row":1, "col":6, "x":13, "y":1}, {"row":1, "col":7, "x":14, "y":1}, {"row":1, "col":8, "x":15, "y":1}, {"row":1, "col":9, "x":16, "y":1}, {"row":1, "col":10, "x":17, "y":1}, {"row":1, "col":11, "x":18, "y":1}, {"row":2, "col":0, "x":0, "y":2}, {"row":2, "col":1, "x":1, "y":2}, {"row":2, "col":2, "x":2, "y":2}, {"row":2, "col":3, "x":3, "y":2}, {"row":2, "col":4, "x":4, "y":2}, {"row":2, "col":5, "x":5, "y":2}, {"row":2, "col":6, "x":13, "y":2}, {"row":2, "col":7, "x":14, "y":2}, {"row":2, "col":8, "x":15, "y":2}, {"row":2, "col":9, "x":16, "y":2}, {"row":2, "col":10, "x":17, "y":2}, {"row":2, "col":11, "x":18, "y":2}, {"row":3, "col":0, "x":0, "y":3}, {"row":3, "col":1, "x":1, "y":3}, {"row":3, "col":2, "x":2, "y":3}, {"row":3, "col":3, "x":3, "y":3}, {"row":3, "col":4, "x":4, "y":3}, {"row":3, "col":5, "x":5, "y":3}, {"row":3, "col":6, "x":6, "y":3}, {"row":3, "col":7, "x":12, "y":3}, {"row":3, "col":8, "x":13, "y":3}, {"row":3, "col":9, "x":14, "y":3}, {"row":3, "col":10, "x":15, "y":3}, {"row":3, "col":11, "x":16, "y":3}, {"row":3, "col":12, "x":17, "y":3}, {"row":3, "col":13, "x":18, "y":3}]
    }
  },
  "sensors": [
    {
      "ref": "left_encoder",
      "name": "encoder_left",
      "identifier": "encoder_left",
      "compatible": "alps,ec11",
      "enabled": false
    },
    {
      "ref": "right_encoder",
      "name": "encoder_right",
      "identifier": "encoder_right",
      "compatible": "alps,ec11",
      "enabled": false
    }
  ]
}

4. configディレクトリのconfとkeymapを生成

以下を参考に合わせて書いてみてください

thumbRotary.conf
    CONFIG_ZMK_BLE=y
    CONFIG_ZMK_USB=y
    
    // 背面のNFCパッドをGPIOとして利用する
    CONFIG_NFCT_PINS_AS_GPIOS=y
    
    // ロータリエンコーダを利用する
    CONFIG_INPUT=y
    CONFIG_EC11=y
    CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y
    
    // マウス操作を使用したいので
    CONFIG_ZMK_POINTING=y
    
    CONFIG_ZMK_BATTERY_REPORTING=y
    
    // 以下バッテリーや接続、レイヤーの状態でXIAO BLEのLEDを変化させるため
    CONFIG_RGBLED_WIDGET=y
    CONFIG_RGBLED_WIDGET_INTERVAL_MS=250
    CONFIG_RGBLED_WIDGET_BATTERY_LEVEL_HIGH=50
    CONFIG_RGBLED_WIDGET_BATTERY_LEVEL_CRITICAL=10
    CONFIG_RGBLED_WIDGET_SHOW_LAYER_CHANGE=n
    
    CONFIG_RGBLED_WIDGET_SHOW_LAYER_COLORS=y
    #num_cyan
    CONFIG_RGBLED_WIDGET_LAYER_1_COLOR=6
    #sym_yellow
    CONFIG_RGBLED_WIDGET_LAYER_2_COLOR=3
    #jis_white
    CONFIG_RGBLED_WIDGET_LAYER_3_COLOR=7
    #jisnum_cyan
    CONFIG_RGBLED_WIDGET_LAYER_4_COLOR=6
    #jissys_yellow
    CONFIG_RGBLED_WIDGET_LAYER_5_COLOR=3
    #macarrow_magenta
    CONFIG_RGBLED_WIDGET_LAYER_6_COLOR=5
    #winarrow_magenta
    CONFIG_RGBLED_WIDGET_LAYER_7_COLOR=5
    #BT_blue
    CONFIG_RGBLED_WIDGET_LAYER_8_COLOR=4
thumbRotary.keymap
    #include <behaviors.dtsi>
    #include <dt-bindings/zmk/bt.h>
    #include <dt-bindings/zmk/keys.h>
    #include <dt-bindings/zmk/pointing.h>
    
    #define ZMK_POINTING_DEFAULT_MOVE_VAL 1500
    #define ZMK_POINTING_DEFAULT_SCRL_VAL 80
    
    / {
        behaviors {
            mouse_scroll_x: mouse_scroll_x {
                compatible = "zmk,behavior-sensor-rotate";
                #sensor-binding-cells = <0>;
                bindings = <&msc SCRL_LEFT>, <&msc SCRL_RIGHT>;
    
                tap-ms = <5>;
            };
    
            mouse_scroll_y: mouse_scroll_y {
                compatible = "zmk,behavior-sensor-rotate";
                #sensor-binding-cells = <0>;
                bindings = <&msc SCRL_UP>, <&msc SCRL_DOWN>;
    
                tap-ms = <5>;
            };
    
            mouse_move_y: mouse_move_y {
                compatible = "zmk,behavior-sensor-rotate";
                label = "MOUSE_MOVE_Y";
                #sensor-binding-cells = <0>;
                bindings = <&mmv MOVE_UP>, <&mmv MOVE_DOWN>;
    
                tap-ms = <5>;
            };
    
            mouse_move_x: mouse_move_x {
                compatible = "zmk,behavior-sensor-rotate";
                label = "MOUSE_MOVE_X";
                #sensor-binding-cells = <0>;
                bindings = <&mmv MOVE_RIGHT>, <&mmv MOVE_LEFT>;
    
                tap-ms = <5>;
            };
        };
    
        keymap {
            compatible = "zmk,keymap";
    
            default_layer {
                bindings = <
    &kp ESC         &kp Q             &kp W               &kp E      &kp R      &kp T      &kp Y               &kp U                &kp I      &kp O      &kp P          &kp BACKSPACE
    &kp TAB         &kp A             &kp S               &kp D      &kp F      &kp G      &kp H               &kp J                &kp K      &kp L      &kp SEMICOLON  &kp ENTER
    &kp LEFT_SHIFT  &kp Z             &kp X               &kp C      &kp V      &kp B      &kp N               &kp M                &kp COMMA  &kp DOT    &kp SLASH      &kp RIGHT_SHIFT
    &kp LANG2       &kp LEFT_CONTROL  &lt 2 LEFT_COMMAND  &mkp MCLK  &kp SPACE  &mkp LCLK  &lt 1 LEFT_COMMAND  &lt 1 RIGHT_COMMAND  &mkp RCLK  &kp SPACE  &mkp MCLK      &lt 2 RIGHT_COMMAND  &kp RIGHT_ALT  &kp LANG1
                >;
    
                sensor-bindings = <&mouse_move_x>, <&mouse_move_y>;
            };
    
            layer_1 {
                bindings = <
    &kp GRAVE       &kp NUMBER_1  &kp NUMBER_2    &kp NUMBER_3    &kp NUMBER_4     &kp N5  &kp NUMBER_6  &kp N7     &kp N8     &kp N9            &kp N0             &kp BACKSPACE
    &trans          &trans        &trans          &kp UP_ARROW    &trans           &trans  &trans        &kp MINUS  &kp EQUAL  &kp LEFT_BRACKET  &kp RIGHT_BRACKET  &kp BACKSLASH
    &kp LEFT_SHIFT  &trans        &kp LEFT_ARROW  &kp DOWN_ARROW  &kp RIGHT_ARROW  &trans  &trans        &trans     &trans     &trans            &kp SQT            &kp RIGHT_SHIFT
    &trans          &trans        &trans          &trans          &kp SPACE        &trans  &trans        &trans     &trans     &kp SPACE         &trans             &trans           &trans  &trans
                >;
    
                sensor-bindings = <&mouse_scroll_x>, <&mouse_scroll_y>;
            };
    
            layer_2 {
                bindings = <
    &kp F1  &kp F2  &kp F3  &kp F4  &kp F5  &kp F6      &kp F7          &kp F8          &kp F9      &kp F10  &kp F11  &kp F12
    &trans  &trans  &trans  &trans  &trans  &trans      &trans          &trans          &trans      &trans   &trans   &trans
    &trans  &trans  &trans  &trans  &trans  &trans      &trans          &trans          &trans      &trans   &trans   &trans
    &trans  &trans  &trans  &trans  &trans  &sys_reset  &bt BT_CLR_ALL  &bt BT_CLR_ALL  &sys_reset  &trans   &trans   &trans   &trans  &trans
                >;
            };
        };
    };
    

5. boards/shields/thumbRotaryディレクトリのKconfigファイルを生成

4までで上流のファームウェアが書けたはずなので、ここから分割のそれぞれの設定や、マイコンとの接続部分の設定を書いていきます。

まずは左右を定義するために、shieldに定義を書きます。

Kconfig.shield
    # Copyright (c) 2020 Pete Johanson
    # SPDX-License-Identifier: MIT
    
    config SHIELD_THUMBROTARY_LEFT
    	def_bool $(shields_list_contains,thumbRotary_left)
    
    config SHIELD_THUMBROTARY_RIGHT
    	def_bool $(shields_list_contains,thumbRotary_right)

defconfigには先ほど定義した左右のシールドに対する設定を書きます。

ここでは、左手のデバイスをPCと接続するBLEデバイスとしています。

Kconfig.defconfig
    if SHIELD_THUMBROTARY_LEFT
    
    config ZMK_KEYBOARD_NAME
    	default "tr_l"
    
    config ZMK_SPLIT_BLE_ROLE_CENTRAL
    	default y
    
    endif
    
    if SHIELD_THUMBROTARY_RIGHT
    
    config ZMK_KEYBOARD_NAME
    	default "tr_r"
    	
    endif
    
    if SHIELD_THUMBROTARY_LEFT || SHIELD_THUMBROTARY_RIGHT
    
    config ZMK_SPLIT
    	default y
    
    endif

6. dtsiファイルを生成

このファイルが左右の共通の設定ファイルとなります。

左右で共通する項目はここで定義し、左右で独立で設定するものはoverlayファイルに書きます。

曖昧ですが、physical-layoutでレイアウトを定義した方がいいらしいのでこれで定義しています。

今回はi2cを使用しないので、disabledしています。また、エンコーダはここでは定義してdisabledにしておく。後で左右のoverlayでそれぞれ有効化する。

matrix_transformでRCのcolを逆順にしているのは、KiCadの設計でcolをミスっていたためです。

thumbRotary.dtsi
     /*
     * Copyright (c) 2020 Pete Johanson
     *
     * SPDX-License-Identifier: MIT
     */
    
    #include <dt-bindings/zmk/matrix_transform.h>
    
    / {
    	chosen {
    		zmk,kscan = &kscan0;
    		zmk,physical-layout = &physical_layout0;
    	};
    
    	default_transform: matrix_transform {
    		compatible = "zmk,matrix-transform";
    		columns = <14>;
    		rows = <4>;
        map = <
          RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5)                  RC(0,12) RC(0,11) RC(0,10) RC(0,9) RC(0,8) RC(0,7)
          RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5)                  RC(1,12) RC(1,11) RC(1,10) RC(1,9) RC(1,8) RC(1,7)
          RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5)                  RC(2,12) RC(2,11) RC(2,10) RC(2,9) RC(2,8) RC(2,7)
          RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5)  RC(3,6) RC(3,13) RC(3,12) RC(3,11) RC(3,10) RC(3,9) RC(3,8) RC(3,7)
    		>;
    	};
    
    	physical_layout0: physical_layout_0 { // First physical layout, use different naming for other layouts
    	  compatible = "zmk,physical-layout";
    	  display-name = "Default Layout";
    	  kscan = <&kscan0>; // Label of the kscan node, optional if all layouts use the same
    	  transform = <&default_transform>; // Label of the matrix transform for this layout
    	};
    
    	kscan0: kscan {
    		compatible = "zmk,kscan-gpio-matrix";
    		label = "KSCAN";
    
    		diode-direction = "col2row";
    		row-gpios
    			= <&xiao_d 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>     //Row0
    			, <&xiao_d 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>     //Row1
    			, <&xiao_d 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>     //Row2
    			, <&xiao_d 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>     //Row3
    			;
    	};
    
      left_encoder: encoder_left {
        compatible = "alps,ec11";
        a-gpios = <&gpio0 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
        b-gpios = <&gpio0 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
        steps = <80>;
        status = "disabled";
      };
    
    	right_encoder: encoder_right {
    		compatible = "alps,ec11";
        a-gpios = <&gpio0 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
        b-gpios = <&gpio0 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
        steps = <80>;
        status = "disabled";
    	};
    
      sensors: sensors {
        compatible = "zmk,keymap-sensors";
        sensors = <&left_encoder &right_encoder>;
        triggers-per-rotation = <20>;
      };
    };
    
    &xiao_i2c { status = "disabled"; };

7. 左右の固有ファイルを生成

今回のキーボードは左右で完全に対称となるので、confファイルに定義するのは左右の名前だけです。

ここで命名を極端に短くしている理由ですが、初めthumbRotary_LEFT などにしていたときに、名前が長いというように理由でビルドエラーが発生したからです。

thumbRotary_left.conf
    CONFIG_ZMK_KEYBOARD_NAME="tr_l"
thumbRotary_right.conf
    CONFIG_ZMK_KEYBOARD_NAME="tr_r"

overlayファイルに、col-gpiosをそれぞれ定義していますが、ここは同じなのでdtsiに書いても良かったなと思っています。個人的な理解では多分dtsiに書いても動きます。

また、それぞれdtsiでdisabledしていたロータリエンコーダの使用する方をokayとして使用できるように設定しています。

rightのoverlayではdefault_transformでオフセットを設定しています。これを設定しないとキーマップがうまくバインドされないので、左右分割の場合はオフセットを設定するようにしましょう。

thumbRotary_left.overlay
    #include "thumbRotary.dtsi"
    
    &kscan0 {
    	col-gpios
    		= <&xiao_d 4 GPIO_ACTIVE_HIGH>	//Col0
    		, <&xiao_d 5 GPIO_ACTIVE_HIGH>  //Col1
    		, <&xiao_d 6 GPIO_ACTIVE_HIGH>  //Col2
    		, <&xiao_d 7 GPIO_ACTIVE_HIGH>  //Col3
    		, <&xiao_d 8 GPIO_ACTIVE_HIGH>  //Col4
    		, <&xiao_d 9 GPIO_ACTIVE_HIGH>  //Col5
            , <&xiao_d 10 GPIO_ACTIVE_HIGH> //Col6
    		;
    };
    
    &left_encoder {
      status = "okay";
    };
thumbRotary_right.overlay
    #include "thumbRotary.dtsi"
    
    &kscan0 {
    	col-gpios
    		= <&xiao_d 4 GPIO_ACTIVE_HIGH>	//Col0
    		, <&xiao_d 5 GPIO_ACTIVE_HIGH>  //Col1
    		, <&xiao_d 6 GPIO_ACTIVE_HIGH>  //Col2
    		, <&xiao_d 7 GPIO_ACTIVE_HIGH>  //Col3
    		, <&xiao_d 8 GPIO_ACTIVE_HIGH>  //Col4
    		, <&xiao_d 9 GPIO_ACTIVE_HIGH>  //Col5
            , <&xiao_d 10 GPIO_ACTIVE_HIGH> //Col6
    		;
    };
    
    &default_transform { // Offset of 3 because the left side has 3 columns
        col-offset = <7>;
    };
    
    &right_encoder {
      status = "okay";
    };

8. build.yamlを編集

これが最後です。

左右分割基盤なので、シールドを2つ追加します。

加えて、rgbled_adapter を追加しているのは、confで書いたXIAOのLEDを動作させるためです。

build.yaml
    ---
    include:
      - board: seeeduino_xiao_ble
        shield: thumbRotary_left rgbled_adapter
      - board: seeeduino_xiao_ble
        shield: thumbRotary_right rgbled_adapter

9. git pushしてActionsのビルドを確認

ここまできたらプッシュしてGithub Actionsでビルドが通る確認しましょう。

特に抜け漏れがなければ通るかと思います。

この記事はファームウェアの作成の備忘録となるため、書き込みについては別の方の記事を参考にしてください。

参考文献

XIAO nRF52840 と ZMK で1キーだけのキーボードを作る

小市民、キーボードを設計する。 ② 〜ZMK Firmware構築〜|mame

Zonkeyキーボード購入者のための「はじめてのZMKキーマップ編集」入門記事|Zonkey製作者(Goya)

roBa ZMK firmwareでロータリーエンコーダにマウススクロールを割り当てる - Qiita

Introduction to ZMK | ZMK Firmware

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?