Skip to content

Conversation

@petejohanson
Copy link
Contributor

@petejohanson petejohanson commented Dec 15, 2025

Move to using proper HWMv2 board extensions
https://docs.zephyrproject.org/4.1.0/hardware/porting/board_porting.html#board-extensions

for extending upstream Zephyr boards for use with ZMK. With this change, using upstream Zephyr board IDs directly, e.g. seeeduino_xiao will be stock versions as found upstream. To use a board variant that is tuned for ZMK use, use the zmk variant, e.g. seeeduino_xiao//zmk which is shorthand for seeeduino_xiao/samd21g18a/zmk.

I've updated a few docs as part of this to note the variant change:

PR check-list

  • Branch has a clean commit history
  • Additional tests are included, if changing behaviors/core code that is testable.
  • Proper Copyright + License headers added to applicable files (Generally, we stick to "The ZMK Contributors" for copyrights to help avoid churn when files get edited)
  • Pre-commit used to check formatting of files, commit messages, etc.
  • Includes any necessary documentation changes.

@petejohanson petejohanson force-pushed the core/move-to-hwmv2-extension-approach branch 5 times, most recently from 4d3b61d to 3e42830 Compare December 16, 2025 00:11
@nmunnich
Copy link
Contributor

Re: discussion on user clarity: do you think it might make sense to introduce //zmk variants for our in-tree boards which are also interconnects, and use the base version as something that matches what Zephyr would accept?

So we would have

  • boards which are also keyboards, name without //zmk
  • interconnect boards without tweaks, regardless of being in Zephyr or ZMK name without //zmk
  • interconnect boards with tweaks, name always with //zmk

@petejohanson
Copy link
Contributor Author

Re: discussion on user clarity: do you think it might make sense to introduce //zmk variants for our in-tree boards which are also interconnects, and use the base version as something that matches what Zephyr would accept?

I have been debating this internally for quite some time now. There guiding principles, as I see them, for this discussion, should be:

  • Clean expectation setting for users of ZMK, that is as intuitive as possible, and as well documented/supported by tooling as possible where things are less intuitive.
  • Promote flexibility and re-use (e.g. right now it's hard to build a Zephyr sample for something like the nice!60, since the ZMK specific headers, etc cause problems) that allows boards to be used very flexibly, we can easily use upstream boards for various users without random things dragged in that break things, etc.
  • Minimizing breakage, or at least consolidating it into one release (we're already going to have this with the planned v0.4, so further refactors in main to satisfy the first two bullets are worth it now, IMHO)

So we would have

* boards which are also keyboards, name without //zmk

So... If we do this, we perpetuate the existing challenges here, where you can't flash basic Zephyr samples to our "keyboard boards" from ZMK, without hacking apart the .dts files temporarily. Not a huge deal, but if we're putting in this effort, it might be worth improving this. I find this useful for targetted "get this display working" or "test the RGB" or "verify this sensor".

* interconnect boards without tweaks, regardless of being in Zephyr or ZMK name without //zmk

Define "tweaks" here. At a minimum, we usually have the following changes that differ from upstream:

  • Enabling one or more HID transports.
  • Defining settings storage (many upstream boards do this, but not all, and many of those do so with an MCUBoot style partition setup) in devicetree and enabling related Kconfig OOTB for those boards.
  • (Newer) Bootloader/retained boot mode setup by default.
* interconnect boards with tweaks, name always with //zmk

If we do this, I think we may introduce confusing for users, surrounding when and when not to use a zmk variant specifier.

Appreciate you helping brainstorm and nail this down!

@nmunnich
Copy link
Contributor

I 100% agree with the guiding principles.

So... If we do this, we perpetuate the existing challenges here, where you can't flash basic Zephyr samples to our "keyboard boards" from ZMK, without hacking apart the .dts files temporarily. Not a huge deal, but if we're putting in this effort, it might be worth improving this. I find this useful for targetted "get this display working" or "test the RGB" or "verify this sensor".

I could certainly be convinced to have //zmk variants for all of our boards, so that we could flash Zephyr samples to them. My concern here is mainly around out-of-tree boards. I think for boards which are also interconnects, we can generally be convinced to add them in-tree of ZMK, if Zephyr does not accept them already, so my expectation is that out-of-tree boards are mostly just keyboards. Considering how much chaos and inconsistency there already is around out-of-tree boards, I see some value in keeping the expected definition for such boards simpler. I could really go either way, though.

Define "tweaks" here.

Essentially what you listed, though we also usually disable the UART node. I see an extra benefit of the separation as making it much easier to upstream boards to Zephyr since the definition has already been written, if a board gains popularity/prominence enough that it would be accepted.

If we do this, I think we may introduce confusing for users, surrounding when and when not to use a zmk variant specifier.

I actually see the opposite: End users would be taught "If you have a board+shield combo, your board always has a //zmk at the end", without needing to look things up. The finer details would be more for advanced users.

@petejohanson
Copy link
Contributor Author

I 100% agree with the guiding principles.

So... If we do this, we perpetuate the existing challenges here, where you can't flash basic Zephyr samples to our "keyboard boards" from ZMK, without hacking apart the .dts files temporarily. Not a huge deal, but if we're putting in this effort, it might be worth improving this. I find this useful for targetted "get this display working" or "test the RGB" or "verify this sensor".

I could certainly be convinced to have //zmk variants for all of our boards, so that we could flash Zephyr samples to them. My concern here is mainly around out-of-tree boards. I think for boards which are also interconnects, we can generally be convinced to add them in-tree of ZMK, if Zephyr does not accept them already, so my expectation is that out-of-tree boards are mostly just keyboards. Considering how much chaos and inconsistency there already is around out-of-tree boards, I see some value in keeping the expected definition for such boards simpler. I could really go either way, though.

Having tried this just the past couple days while playing with my stm32c0pad prototype, I can definitely say that having a "Zephyr compatible" based board for it was really helpful, and that adding a zmk variant was not a significant additional effort.

Not that I think we should expect everyone to do this with every board definition, but it might be nice to document it as an option for folks to follow.

Not sure how best to communicate this to users though? For sure, listing the //zmk variant in the .zmk.yml files is a good first start, with integration with the ZMK CLI helping here.

Define "tweaks" here.

Essentially what you listed, though we also usually disable the UART node. I see an extra benefit of the separation as making it much easier to upstream boards to Zephyr since the definition has already been written, if a board gains popularity/prominence enough that it would be accepted.

👍

If we do this, I think we may introduce confusing for users, surrounding when and when not to use a zmk variant specifier.

I actually see the opposite: End users would be taught "If you have a board+shield combo, your board always has a //zmk at the end", without needing to look things up. The finer details would be more for advanced users.

I think my only real concern here, is where we draw the line for "accepting boards that support some interconnect", if we want to have that really be consistent/enforced.... The lemon controllers ? Halcyon? How about the tenth random RP2040 board we theoretically support? I'd love to have some planning around what that really looks like.

I do think that your proposed "user expectation" does seem like it would be nice to get to. How do we do so?

@nmunnich
Copy link
Contributor

nmunnich commented Dec 26, 2025

Not that I think we should expect everyone to do this with every board definition, but it might be nice to document it as an option for folks to follow.

Not sure how best to communicate this to users though? For sure, listing the //zmk variant in the .zmk.yml files is a good first start, with integration with the ZMK CLI helping here.

I do think that your proposed "user expectation" does seem like it would be nice to get to. How do we do so?

Proposed plan:

  • All in-tree boards get a //zmk variant
  • We introduce a Kconfig flag that gets set in the variants (CONFIG_ZMK?). During build time we have the ZMK app check for this flag and throw a warning in the build process, something like "You are building ZMK firmware with a board that is missing ZMK-specific tweaks. You may experience some unexpected behavior. Have you checked if there is a <your_board>//zmk variant of your board?"
  • The blog post and docs are updated to have //zmk everywhere, and we add a "patch note" to the blog post
  • Probably we should adjust our supported hardware script to list boards which don't have in-tree shields as well.
  • We add a "New board" page under hardware integration, which essentially states "Go to Zephyr and follow their instructions exactly to create a Zephyr board. <before continuing, here are some helpful Zephyr sample apps that you can flash to your board to ensure things are working at this point> Then return here for instructions on making a //zmk variant of your board with ZMK-specific tweaks allowing for Studio etc. If your board is a keyboard, once you've made the //zmk variant, take guidance (but don't follow exactly) the steps in the new shield guide to add a kscan etc."

I think my only real concern here, is where we draw the line for "accepting boards that support some interconnect", if we want to have that really be consistent/enforced.... The lemon controllers ? Halcyon? How about the tenth random RP2040 board we theoretically support? I'd love to have some planning around what that really looks like.

I edited this reply to open #3172 for this discussion instead, for better organisation.

@petejohanson
Copy link
Contributor Author

Proposed plan:

* All in-tree boards get a //zmk variant

Including "complete keyboards", that only ever are used with ZMK? We refactor so they can be used with Zephyr directly with the "stock" variant?

@caksoylar
Copy link
Contributor

It seems that (some?) board extensions are currently broken on main:

> west build -b sparkfun_pro_micro_rp2040 -d build/rp2040-test -- -DSHIELD=naked60
> grep CONFIG_ZMK_USB build/rp2040-test/zephyr/.config
# CONFIG_ZMK_USB is not set

@carrefinho also reported that board extensions are not applied on all boards whose name starts with vendor name, like adafruit_kb2040, boardsource_blok.

Do we want to fix that or get this in quicker?

@petejohanson petejohanson force-pushed the core/move-to-hwmv2-extension-approach branch 2 times, most recently from 70cdfc3 to ec64c30 Compare January 6, 2026 08:01
@petejohanson
Copy link
Contributor Author

It seems that (some?) board extensions are currently broken on main:

> west build -b sparkfun_pro_micro_rp2040 -d build/rp2040-test -- -DSHIELD=naked60
> grep CONFIG_ZMK_USB build/rp2040-test/zephyr/.config
# CONFIG_ZMK_USB is not set

@carrefinho also reported that board extensions are not applied on all boards whose name starts with vendor name, like adafruit_kb2040, boardsource_blok.

Do we want to fix that or get this in quicker?

We'll fix that here. Anyone with issues can pin to v0.3 in the meantime.

@petejohanson
Copy link
Contributor Author

Ok, I've just pushed fixes for the nRFMicro to create a "vanilla" board definition for it in the app/module/ directory, that's completely ZMK-free, and then use the same HWMv2 extension approach to add ZMK variants.

With this. you can now do:

west build -p -d build/nrfmicro_hello_world -b nrfmicro/nrf52840 samples/hello_world -- -DBOARD_ROOT=/home/peter/git/zmk/app/module

from within the Zephyr repo. I'm not sure that this whole process is completely necessary for every in-tree keyboard board, e.g. nice!60, I think there we would only have the /zmk variant for those living in their existing location in app/boards/.

@petejohanson petejohanson force-pushed the core/move-to-hwmv2-extension-approach branch 5 times, most recently from f6acf6b to 62c0d9e Compare January 9, 2026 08:51
@petejohanson petejohanson force-pushed the core/move-to-hwmv2-extension-approach branch 5 times, most recently from 052735d to 34740d0 Compare January 15, 2026 00:15
@petejohanson petejohanson force-pushed the core/move-to-hwmv2-extension-approach branch from c63a6a2 to b01c46b Compare January 15, 2026 18:41
Move to using proper HWMv2 board extensions
https://docs.zephyrproject.org/4.1.0/hardware/porting/board_porting.html#board-extensions

for extending upstream Zephyr boards for use with ZMK. With this change,
using upstream Zephyr board IDs directly, e.g. `seeeduino_xiao` will be
stock versions as found upstream. To use a board variant that is tuned
for ZMK use, use the `zmk` variant, e.g. `seeeduino_xiao//zmk` which is
shorthand for `seeeduino_xiao/samd21g18a/zmk`.
@petejohanson petejohanson force-pushed the core/move-to-hwmv2-extension-approach branch from b01c46b to e4ac223 Compare January 15, 2026 18:58
For consistency, adjust the nRFMicro board definition to offer a
"vanilla" Zephyr board, and then ZMK variants, e.g.
`nrfmicro/nrf52840/zmk`.
…oard

For consistency, adjust the bluemicro840 board definition to offer a
"vanilla" Zephyr board, and then ZMK variant, e.g. `bluemicro840//zmk`.
Make the standard Tofu65 board ID be `tofu65/rp2040/zmk` or
`tofu65//zmk` by shorthand.
Make the standard BDN9 board ID be `bdn9/stm32f072xb/zmk` or
`bdn9//zmk` by shorthand.
Make the standard Puchi BLE board ID be `puchi_ble/nrf52840/zmk` or
`puchi_ble//zmk` by shorthand.
Make the standard Adv360 Pro board ID be `adv360pro_left/nrf52840/zmk` or
`adv360pro_left//zmk` by shorthand and for right as well.
Make the standard nRF52840 M2 board ID be `nrf52840_m2/nrf52840/zmk` or
`nrf52840_m2//zmk` by shorthand.
Make the standard Pillbug board ID be `pillbug/nrf52840/zmk` or
`pillbug//zmk` by shorthand.
Make the standard s40nc board ID be `s40nc/nrf52840/zmk` or
`s40nc//zmk` by shorthand.
Make the standard nice!60 board ID be `nice60/nrf52840/zmk` or
`nice60//zmk` by shorthand.
Make the standard planck board ID be `planck/stm32f303xc/zmk` or
`planck//zmk` by shorthand.
Make the standard preonic board ID be `preonic/stm32f303xc/zmk` or
`preonic//zmk` by shorthand.
Make the standard ferris board ID be `ferris/stm32f072xb/zmk` or
`ferris//zmk` by shorthand.
Make the standard Proton-C board ID be `proton_c/stm32f303xc/zmk` or
`proton_c//zmk` by shorthand.
Make the standard Corneish Zen board ID be `corneish_zen_left/nrf52840/zmk` or
`corneish_zen_left//zmk` by shorthand and for right as well.
Make the standard nice!nano board ID be `nice_nano/nrf52840/zmk` or
`nice_nano//zmk` by shorthand.
Make the standard mikoto board ID be `mikoto/nrf52840/zmk` or
`mikoto//zmk` by shorthand.
Make the standard Polarity Works board IDs be `zmk` variants.
@petejohanson petejohanson force-pushed the core/move-to-hwmv2-extension-approach branch 2 times, most recently from ff6c6da to a6796b1 Compare January 16, 2026 21:11
* Update Zephyr 4.1 blog post to mention ZMK variants
* Add note to hardware support page about variants
@petejohanson petejohanson force-pushed the core/move-to-hwmv2-extension-approach branch from a6796b1 to 28f29f4 Compare January 16, 2026 21:14
@petejohanson petejohanson marked this pull request as ready for review January 16, 2026 21:24
@petejohanson petejohanson requested review from a team as code owners January 16, 2026 21:24
for (const configuration of combinedUnique) {
console.log(idx++);
console.log(configuration);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leftover debug code

* SPDX-License-Identifier: MIT
*/

#include <../boards/adafruit/kb2040/adafruit_kb2040.dts>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What directory are all these includes relative to?

qualifier: nrf52840
- name: flipped_zmk
qualifier: nrf52840
- name: zmk
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is having two variants with the same name okay?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On most of the other boards, the ZMK-specific configs were pulled out into a board extension. Was putting these in the base board definition here intentional?

Copy link
Contributor

@nmunnich nmunnich Jan 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Building this one with the tester I get

CMake Warning at /workspaces/zmk/zephyr/cmake/modules/dts.cmake:425 (message):
  dtc raised one or more warnings:

  /workspaces/zmk/app/build/zephyr/zephyr.dts:39.26-42.5: Warning
  (simple_bus_reg): /soc/memory@20000000: simple-bus unit address format
  error, expected "20000004"

Doesn't occur on the non //zmk version. No idea about the effects, haven't delved deep at all. Seems to apply to some of the others as well

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants