Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

boards: add support for nrf52840-dongle #13146

Merged
merged 1 commit into from
May 8, 2020

Conversation

chrysn
Copy link
Member

@chrysn chrysn commented Jan 16, 2020

Contribution description

This adds board support for he nrf52840-dongle. From the docs that are part of the PR:

The nRF52840-Dongle is a bare USB-stick shaped device that houses barely
anything than the nRF52840 itself, which offers BLE and 802.15.4 and USB
connectivity.

Unlike similar sticks (like the boards_nrf52840-mdk), it features no
dedicated programmer hardware but relies on direct USB communication with a
built-in bootloader.

The board features two LEDs (LD1: green, LD2: RGB), a user (SW1) and a
reset button as well as 15 configurable external pins.

Testing procedure

  • Get a dongle (they're cheap, about 10$ from several distributors

  • Pick any example; particularly funny are those with network support like gcoap.

  • Add this to the Makefile (see later on why this is necessary)

    CFLAGS += -DCONFIG_USB_VID=0x1209
    CFLAGS += -DCONFIG_USB_PID=0x7D00
    
  • Install the nrfutil USB programmer, typically using pip install nrfutil (see doc.txt for when it's not)

  • Plug the device into a USB port with its reset button (the horizontal one) pressed, it'll breathe a red LED

  • Build and flash the example with make BOARD=nrf52840-dongle flash

  • Run make BOARD=nrf52840-term for a USB console, or chat up the network stack that just showed up as a new USB network device :-)

Issues/PRs references

Fixes #12189.
Requires #13148

Open issues

  • Default USB IDs are not available for devices that just out of the box (or by virtue of something like gnrc_netdev_default) ship a USB stack. I'd like to fix this properly with Have usable VID/PIDs for standard situations and prototype ones for examples #12273.
  • The USB UART default might interact badly with examples that expect ethos (running which really makes no sense on such a board, that's what USB Ethernet aka CDC-ECM is for).
  • Pulling things like a USB UART or a USB Ethernet device in by default is relatively unexplored territory in RIOT. I think that it might make sense to have, in parallel to gnrc_netdev_default, a gnrc_netdev_default_host -- which pulls in a by-board picked hostward netdev, whether that's ethos, CDC-ECM or any future semihosted tuntap solution. Having a similar entry point for stdio would make sense as well -- if all stdio examples requested stdio_default, the board could decide whether that's stdio over UART or over USB. (Currently, I'm pulling in stdio_usb_acm when shell is active, which is a good-enough heuristic.)
  • ModemManager might gobble up the serial console for some time due to its heuristics. That's resolved in new versions of ModemManager and acknowledged in the doc.txt.
  • I've written a custom linker script that works with the shipped bootloader. Should this be somehow optional to be usable by people who program it externally? (I think the bootloader is a good default, as it just works out of the box -- and should be reconsidered when flashing own RIOT USB bootloaders becomes a thing).
  • I'm setting FLASHER and FFLAGS and add a preprocessing step (FLASHFILE = $(HEXILFE).zip) which the flasher needs. Should this be factored out into a generic makefiles/tools/nrfutil.inc.mk? (Note that my original hopes of using the same infrastructure to program the Thingy:52 have been swept away in support Thingy:52 bootloader #12829).
    • In particular, this makes building on a murdock impossible right now.
  • Did I (again) fail somewhere in the code style area? I hope that the automated tests that get triggered with the PR will tell me.

Final open question:

  • Is any of that too bad that a few words in the docs (and a plan on how to do it better) would stop this from being mergeable?

[edit: Added open questions on flashing / bootloader]
[edit: Added checkmarks for easier tracking, ticking off ModemManager as all is confirmed now, and adding the murdock trouble miri64 pointed out]

@chrysn chrysn requested a review from miri64 January 16, 2020 17:11
@chrysn
Copy link
Member Author

chrysn commented Jan 16, 2020

Pinging @trickeydan, @benemorius and @maz3max as I can't request you as a reviewers, but you showed interest in the corresponding issue #12189.

@benpicco benpicco added Area: boards Area: Board ports CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Type: new feature The issue requests / The PR implemements a new feature for RIOT labels Jan 16, 2020
@fjmolinas fjmolinas added CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR and removed CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels Jan 17, 2020
@miri64 miri64 removed the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Jan 17, 2020
@miri64
Copy link
Member

miri64 commented Jan 17, 2020

nrfutil seems to be required for building (which surprises me as it supposed only to be the programmer) and it is not installed Murdock, so no use in trying to build this there for now.

@chrysn
Copy link
Member Author

chrysn commented Jan 17, 2020

There is an additional stage before flashing: This programmer expects its input as a zip file, so ${FLASHFILE} = ${HEXFILE}.zip and built using nrfutil. (The idea being that the zip file includes a bit of metadata on what chip and bootloader this is expected to be flashed to, so the bootloader can refuse if need be).

If I use a different name than ${FLASHFILE} for the zip, I'd sidestep that, but possibly confuse people who expect make all to produce the files later passed to the programmer.

Alternatively, install nrfutil on murdock (should be just a matter of pip3 install nrfutil.

Do you prefer either of these options, or see another one?

@chrysn
Copy link
Member Author

chrysn commented Jan 17, 2020

I'm confused by the buildsystem_sanity_check that raised during the build and I thought to have fixed with 27fad13.

I understand that the board directory could reside somewhere else, but this linker script is custom to this board as this board has a particular bootloader, and only that would need this script. Where am I supposed to place that, and how should I refer to it in the Makefile.include?

@miri64
Copy link
Member

miri64 commented Jan 17, 2020

Maybe @fjmolinas can help with that? He introduced that check in #12999.

@fjmolinas
Copy link
Contributor

@chrysn just replace LINKER_SCRIPT ?= $(BOARDSDIR)/$(BOARD)/ldscripts/application.ld by LINKER_SCRIPT ?= $(BOARDSDIR)/nrf52840-dongle/ldscripts/application.ld. Please see #12999 (comment)_ for a more detailed explanation of the reasoning.

@chrysn
Copy link
Member Author

chrysn commented Jan 17, 2020

just replace

Done, still builds & passes the check. Thanks!

@fjmolinas
Copy link
Contributor

I understand that the board directory could reside somewhere else, but this linker script is custom to this board as this board has a particular bootloader, and only that would need this script. Where am I supposed to place that, and how should I refer to it in the Makefile.include?

Even if custom for this BOARD I could solder bins and maybe add another sensor/radio or whatever to it, and might want to extended to a nrf52840-dongle-mine that would be the same board but with this extra sensors or whatever. I would probably use BOARDSDIR to just inherit everything from nrf52840-mdk and add those extra mappings. If that doesn't make sense I can extend my explanation from #12999 (comment)_, I was planning in adding a doc entry but have not found time yet. Also if the error message wasn't clear enough I'm happy to amend it!

Copy link
Member

@miri64 miri64 left a comment

Choose a reason for hiding this comment

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

Some thoughts.

boards/nrf52840-dongle/Makefile.dep Outdated Show resolved Hide resolved
# stdio_uart has already been set.
#
# Maybe have a shell_default like netdev_default?
ifneq (,$(filter shell,$(USEMODULE)))
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure I understand, even with the comment, why this is dependent on the shell.

Copy link
Member Author

Choose a reason for hiding this comment

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

I did seem to have some mixup between stdin and stdio, revisiting that in more detail. (When I wrote this I was unaware that stdin is extra functionality atop of sdio)

The idea was: If an application depends on stdio (whether directly or via shell, but I though I couldn't catch the "directly" case), it will pull in a stdio implementation. A board should be able to provide a default stdio, but may want (kind of like netdev_default does), but an application may still want to use stdio_rtt on a USB-supporting board explicitly.

But as said, I'll go through this again with better awareness of stdio vs stdin.

# stdio_uart has already been set.
#
# Maybe have a shell_default like netdev_default?
ifneq (,$(filter shell,$(USEMODULE)))
Copy link
Member

Choose a reason for hiding this comment

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

What if there is no shell? Is there then no STDIO? I'm not sure we support that concept ^^" (see #10741).

boards/nrf52840-dongle/Makefile.dep Outdated Show resolved Hide resolved
boards/nrf52840-dongle/Makefile.dep Outdated Show resolved Hide resolved
boards/nrf52840-dongle/include/gpio_params.h Outdated Show resolved Hide resolved
boards/nrf52840-dongle/Makefile.include Outdated Show resolved Hide resolved
boards/nrf52840-dongle/Makefile.include Outdated Show resolved Hide resolved
@chrysn
Copy link
Member Author

chrysn commented Jan 17, 2020

Changes with the last fixes:

  • 860a140 removes the automatic USB Ethernet device; running examples over USB rather than wireless now usually entails replacing gnrc_netdev_default with usbus_cdc_ecm (with auto_init_usbus already pulled in by the serial part).
  • ad0d897 does away with the custom linker script in favor of ROM_OFFSET and FW_ROM_LEN

@miri64 miri64 added the State: waiting for other PR State: The PR requires another PR to be merged first label Jan 17, 2020
@haukepetersen haukepetersen dismissed their stale review January 20, 2020 10:38

My finding is addressed properly, so nothing blocking from my side.

@miri64
Copy link
Member

miri64 commented Jan 30, 2020

Please rebase to incorporate #13148.

@chrysn chrysn force-pushed the nrf52840-dongle-2 branch from a020b64 to 490e586 Compare January 31, 2020 10:58
@chrysn
Copy link
Member Author

chrysn commented Jan 31, 2020

Rebased on master (with fixups squashed).

I've looked into the stdio_* situation (which previously was a mess because I mixed up stdin and stdio), at the feather-nrf52840 module, and changed the stio_cdc_acm picking into a DEFAULT_MODULE instead -- this seems to be the way to go currently. As that module doesn't pull in auto_init_usbus automatically, that is made a default module as well, and the behavior described in the board documentation.

I'd prefer a solution where stdio is not expected to be a default module but rather an explicit dependency of modules like shell (that can then get populated in Modules.dep according to a board-specific default implementation, possibly pulling in things like auto_init_usbus), but one step at a time.

Building with make BOARD=nrf52840-dongle DISABLE_MODULE="stdio_cdc_acm" (ie. disabling the automatic USB stdio but leaving auto_init_usbus in there) does raise a missing module error now, but that looks like an unrelated undeclared dependency to investigate.

@miri64
Copy link
Member

miri64 commented Jan 31, 2020

Rebased on master (with fixups squashed).

You could have also squash (so effectively removing) the reverted commit with the revert commit.

Regarding stdio, have you seen #12304?

@chrysn chrysn force-pushed the nrf52840-dongle-2 branch from 915660a to 0aa096d Compare January 31, 2020 14:22
@chrysn
Copy link
Member Author

chrysn commented Jan 31, 2020

Squashed accordingly. I have accumulated some other commits as well that not strictly revert things but change how they're done -- but if I fuse them all, this whole branch might wind up being only one or two commits at all. What's the preferred style here?

I was unaware of #12304, but it looks like lots of thought went in there (and also in #12724), it's aligned with what happens here (in the end, just the notes in this board's documentation can be simplified when #12304 is merged), and confirms the path with both stdio_cdc_acm and auto_init_usbus as default modules.

@kaspar030 kaspar030 changed the title Board support for nrf52840-dongle boards: add support for nrf52840-dongle Jan 31, 2020
@chrysn
Copy link
Member Author

chrysn commented Feb 14, 2020

As I understand, all previous issues are addressed:

Do you see anything left that stands in the way of this being mergable?

@aabadie
Copy link
Contributor

aabadie commented May 8, 2020

You can have FEATURES_REQUIRED += bootloader_nrfutil without USEMODULE += usb_board_reset

+1

@chrysn
Copy link
Member Author

chrysn commented May 8, 2020

You can have FEATURES_REQUIRED += bootloader_nrfutil without USEMODULE += usb_board_reset

That seems like a good way to go (preparing that now) -- right now, this board is only and necessarily used with this bootloader (and in future, this may change). It'll remain to ensure riotboot builds don't fail with that, which is probably the eventual outcome of the https://github.com/RIOT-OS/RIOT/pull/13146/files/981c1411d4dff28848f4ce85d2306ec89b5396d5#diff-62d41b596b7713257c78acbe1b8616fd thread.

USEMODULE += saul_gpio
endif

FEATURES_REQUIRED += bootloader_nrfutil
Copy link
Contributor

@aabadie aabadie May 8, 2020

Choose a reason for hiding this comment

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

Please move this line as suggested below. The bootloader_nrfutil is a convenient build system feature that is only useful when stdio_cdc_acm is used !!

Copy link
Member Author

Choose a reason for hiding this comment

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

Good point, fixed.

Copy link
Member Author

Choose a reason for hiding this comment

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

Argh, sorry, I mixed up your suggestion with the one of benpicco "below" in the issue view. Does 844a0db (modulo points of opinion in the comment) reflect what you meant?

@benpicco
Copy link
Contributor

benpicco commented May 8, 2020

-- running on worker mobi7.inet.haw-hamburg.de thread 11, build number 151701.
make: Entering directory '/tmp/dwq.0.2955577806981107/24b81fb95968c0a882b26cdc9cd38035/tests/gnrc_rpl_srh'
Some feature requirements are blacklisted: bootloader_nrfutil
/tmp/dwq.0.2955577806981107/24b81fb95968c0a882b26cdc9cd38035/tests/gnrc_rpl_srh/../../Makefile.include:876: *** You can let the build continue on expected errors by setting CONTINUE_ON_EXPECTED_ERRORS=1 to the command line.  Stop.
make: Leaving directory '/tmp/dwq.0.2955577806981107/24b81fb95968c0a882b26cdc9cd38035/tests/gnrc_rpl_srh'
-- build directory size: 0

😩

@chrysn
Copy link
Member Author

chrysn commented May 8, 2020

That probably explains why adafruit-clue requires the bootloader feature only when no explicit stdio is set -- the tests set stdio_null and then all is fine for them.

Given we're just doing workarounds here, I'd replicate more or less exactly what the adafruit-clue board is doing (for getting things here out of the way), and open a separate issue on odd workarounds with all the nice things that came up in the comments here but had to be reverted in order to get things to work.

@benpicco
Copy link
Contributor

benpicco commented May 8, 2020

-- running on worker riotbuild thread 1, build number 57630.
make: Entering directory '/tmp/dwq.0.4177377369128673/b42a7eb2a4d96105c5bec84e1ce536c4/bootloaders/riotboot'
Building application "riotboot" for "nrf52840dongle" with MCU "nrf52".

/opt/gcc-arm-none-eabi-9-2019-q4-major/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld: Specified firmware size does not fit in ROM
collect2: error: ld returned 1 exit status
/tmp/dwq.0.4177377369128673/b42a7eb2a4d96105c5bec84e1ce536c4/bootloaders/riotboot/../..//Makefile.include:565: recipe for target '/tmp/dwq.0.4177377369128673/b42a7eb2a4d96105c5bec84e1ce536c4/build/riotboot.elf' failed
make: *** [/tmp/dwq.0.4177377369128673/b42a7eb2a4d96105c5bec84e1ce536c4/build/riotboot.elf] Error 1
make: Leaving directory '/tmp/dwq.0.4177377369128673/b42a7eb2a4d96105c5bec84e1ce536c4/bootloaders/riotboot'
-- build directory size: 720K

😩

@chrysn
Copy link
Member Author

chrysn commented May 8, 2020

OK, but that's something different than directly conflicting -- it just means that the riotboot loader won't fit in the flash with the constraints the nrfutil bootloader is imposing. That, to me, would more lead to a resolution of "We can't satisfy this application's firmware requirements with that build setting", and thus blacklisting that application for that board for memory constraints (with a note that it will probably fit conceptually but needs adaptions to the memory positions).

(Looking at adafruit-clue for guidance won't help here probably, as has a different ROM_OFFSET and bootloader shape).

@benpicco
Copy link
Contributor

benpicco commented May 8, 2020

Well go ahead and add it to BOARD_BLACKLIST then, although that feels like admitting defeat to the build system.

I suspect it has to do with

bootloaders/riotboot/Makefile

# limit riotboot bootloader size
# TODO: Manage to set this variable for boards which already embed a
# bootloader, currently it will be overwritten
ROM_LEN := $(RIOTBOOT_LEN)

# but that's what the minimal working example for the dongle does as well.

ROM_OFFSET = 0x1000
FW_ROM_LEN = 0xdf000
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove this line to fix the remaining Murdock issues.

Copy link
Contributor

@benpicco benpicco May 8, 2020

Choose a reason for hiding this comment

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

And replace it with

ROM_LEN = 0xdf000

?

Copy link
Member Author

Choose a reason for hiding this comment

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

Aehm, as I understand that would not only lead to things not working any more (as the code now thinks it's starting at 0x0 but is flashed to 0x1000, and we're not all PIE yet, are we?), but also (by not limiting FW_ROM_LEN) risk building overly large images that either will fail to flash or worse will overwrite the high portion of the bootloader.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think so because it's handled automatically by the build system (can we stop guessing things and move to the point where this can be merged ?)

Copy link
Contributor

Choose a reason for hiding this comment

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

See here.

Copy link
Member Author

Choose a reason for hiding this comment

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

I just tried, flashing succeeded but the board won't come up. Going for the the blacklisting solution, this should make it passable. (The game of whether this declares its memory wrong or whether the suit/riotboot can't work on exotic-memory-layout bootloaders can be had outside this issue.)

Copy link
Contributor

@benpicco benpicco May 8, 2020

Choose a reason for hiding this comment

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

I think @aabadie was referring to the FW_ROM_LEN line - you should leave the ROM_OFFSET in place.

Copy link
Member Author

Choose a reason for hiding this comment

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

OK, only the FW_ROM_LEN, that does make sense if the information can be passed around somewhere else (eg. in ROM_LEN).

Thanks, that appears to fix it; riotboot and suit example now build, pushing it to murdock.

chrysn added a commit to chrysn-pull-requests/RIOT that referenced this pull request May 8, 2020
@benpicco
Copy link
Contributor

benpicco commented May 8, 2020

Murdock is happy at last 🎉

@chrysn
Copy link
Member Author

chrysn commented May 8, 2020

Finally -- thank you both! So squash all?

@aabadie
Copy link
Contributor

aabadie commented May 8, 2020

So squash all?

Yes please :)

It includes per-board support for the nrfutil programmer used with its
default bootloader; this is not generalized over Adafruit's boards as
they use incompatible versions of nrfutil.
@chrysn chrysn force-pushed the nrf52840-dongle-2 branch from 9c65a86 to 1c0bded Compare May 8, 2020 12:53
@chrysn chrysn requested a review from aabadie May 8, 2020 13:16
Copy link
Contributor

@aabadie aabadie left a comment

Choose a reason for hiding this comment

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

ACK

@aabadie aabadie merged commit c9b83e3 into RIOT-OS:master May 8, 2020
@aabadie
Copy link
Contributor

aabadie commented May 8, 2020

Sorry that this PR took so long to be merged and thank you for your patience @chrysn !

@SemjonWilke
Copy link
Member

Thanks for this port!
So, am I understanding that right, you have to use nrfutil for python2 and you have to press the reset button right before flashing and there is no easy way to avoid this? Anyway with this restrictions I ran examples/default without further ado.

@chrysn chrysn deleted the nrf52840-dongle-2 branch May 8, 2020 17:29
@chrysn
Copy link
Member Author

chrysn commented May 8, 2020

nrfutil needs to be installed (Python 2 or 3 does not matter), as does every other tool in the toolchain. Pressing reset before flashing is necessary at very least for the initial programming (when some arbitrary other program is on there). make flash to reset it into the bootloader could be made to work, but will always to some extent depend on the cooperation of the current program, as unlike on other development kits there is no physical programmer that's connected to the PC.

@SemjonWilke
Copy link
Member

SemjonWilke commented May 8, 2020

nrfutil needs to be installed (Python 2 or 3 does not matter),

I figured out how to use nrfutil for python3 by reading your documentation, my bad.

make flash to reset it into the bootloader could be made to work

I think this feature is very important and should be tackled soon. Can I help with that somehow?
@haukepetersen suggested these boards for a cheap, local testbed with multiple nodes and thus it should be programmable with a script and without physical access.

but will always to some extent depend on the cooperation of the current program

I don't understand which program you mean.
Is there enough to discuss here to open an issue?

@benpicco
Copy link
Contributor

benpicco commented May 8, 2020

make flash to reset it into the bootloader could be made to work, but will always to some extent depend on the cooperation of the current program

The watchdog on nrf5x supports executing a callback before the reset. So if the user desires so, they could set it up to always write the magic value when it fires.
So when RIOT crashes you’d end up in the bootloader again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: boards Area: Board ports CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Type: new feature The issue requests / The PR implemements a new feature for RIOT
Projects
None yet
Development

Successfully merging this pull request may close these issues.

board suggestion: nRF52840-dongle
8 participants