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

Add board: Seeed XIAO BLE #2591

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open

Conversation

ssievert42
Copy link
Contributor

@ssievert42 ssievert42 commented Jan 5, 2025

This adds support for the Seeed XIAO BLE, a tiny development board with a nRF52840 and 2 MB of external flash.

The board definition file is based on this one by Espruino forums user parasquid.

Some goodies that are included as well:

  • the build generates an UF2 image, that can be flashed to the board when it is in bootloader mode, without needing to install anything on the host (connect via USB, double press the reset button, then copy the file to the USB drive that appears)
  • automagically built UF2 image with GitHub actions
  • E.rebootToDFU() triggers a reboot to UF2 bootloader mode

@ssievert42 ssievert42 changed the title add board: Seeed XIAO BLE Add board: Seeed XIAO BLE Jan 6, 2025
@gfwilliams
Copy link
Member

Thanks - this looks great!

Do you think it'd be possible to change jswrap_espruino_rebootToUF2 just to use jswrap_espruino_rebootToDFU though? There's already the stuff in there for it so all you'd have to do is rename jshRebootToUF2Bootloader to jshRebootToDFU in jshardware.c and change the "ifdef" : "STM32F4", line to "#if" : "defined(STM32F4) || defined(ESPR_HAS_BOOTLOADER_UF2)",

@ssievert42 ssievert42 force-pushed the xiaoble branch 4 times, most recently from 6fc4180 to 44d2473 Compare January 6, 2025 17:05
@ssievert42
Copy link
Contributor Author

Thanks for the feedback!
I've now dropped E.rebootToUF2() in favor of E.rebootToDFU(), mentioned the UF2 bootloader mode in the docs of E.rebootToDFU() and changed the other stuff as you suggested - no need to have two functions with slightly different names that basically do the same thing :)

@ssievert42
Copy link
Contributor Author

Does the board definition file need to use pinutils.generate_pins()?
I don't remember why I decided to change get_pins() to not use pinutils.generate_pins(), but I think the reason was to have pin names that are the same as the ones printed on the board.

"link": ["https://www.seeedstudio.com/Seeed-XIAO-BLE-nRF52840-p-5201.html"],
"default_console": "EV_USBSERIAL",
"variables": 14000, # How many variables are allocated for Espruino to use. RAM will be overflowed if this number is too high and code won't compile.
"binary_name": "espruino_%v_xiaoble.hex",
Copy link
Member

Choose a reason for hiding this comment

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

What happens if this is .uf2? It may be you don't need the ifdef XIAOBLE ... proj: $(PROJ_NAME).uf2 line if it is...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hardcoding only the XIAOBLE to create a UF2 in that makefile does seem rather hacky...
Turns out I needed to change a bit more; something kept adding ".hex" to the end of the binary name.
See d40b0ca for what I did to make this work :)

@@ -2887,6 +2887,14 @@ void jshReboot() {
NVIC_SystemReset();
}

#ifdef ESPR_HAS_BOOTLOADER_UF2
Copy link
Member

Choose a reason for hiding this comment

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

This looks great, thanks! Please could you add a comment in https://github.com/espruino/Espruino/blob/master/README_BuildProcess.md#infomakefile-definitions though? I'm trying to keep all the defines documented somewhere

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added 👍
Reminder for future me: Do this for BLE private address support as well.

src/jsflash.c Outdated
@@ -1374,6 +1374,7 @@ JsVar *jsfGetBootCodeFromFlash(bool isReset) {

bool jsfLoadBootCodeFromFlash(bool isReset) {
// Load code in .bootFirst at first boot UNLESS BTN1 IS HELD DOWN (BTN3 for Dickens)
#ifndef ESPR_NO_BOOT_JS
Copy link
Member

Choose a reason for hiding this comment

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

It's a shame the board doesn't have a button so this is needed - but I feel like it's very unlikely anyone would make a custom build that includes this?

Maybe you could:

  • Make the UF2 include the flash area used for saved code so it always overwrites it
  • Make a special UF2 that just overwrites the saved code area to allow you to clear it if you want to?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

but I feel like it's very unlikely anyone would make a custom build that includes this

Yeah, you're probably right.
The board does have a (reset) button; pressing it just immediately resets the board...

Make the UF2 include the flash area used for saved code

Probably not an option if saved code is on SPI flash though 🙈
(And I really want to use those 2 MB of external flash.)

Make a special UF2 that just overwrites the saved code area

I'd rather have something that allows recovering other data saved to storage, but I guess this will be the way to go if you don't like the "pull a magic pin to ground on boot" thing I added with my latest push.

@gfwilliams
Copy link
Member

Thanks for those changes to UF2 reboot - that looks really good.

Does the board definition file need to use pinutils.generate_pins()? ... I think the reason was to have pin names that are the same as the ones printed on the board.

No, that's fine - generate_pins was just a utility function to generate a bunch of contiguous pins. If you want to renumber the pins so they match the board what you've done is the right way to handle it.

@ssievert42
Copy link
Contributor Author

ssievert42 commented Jan 14, 2025

Thanks for the review!
I think I've addressed most of your comments;
The changes I just pushed do the following:

  • if the "binary_name" in a board definition file ends with ".uf2", we build an UF2 image and pass chip.part (in the case of the XIAOBLE NRF52840) to the uf2conf.py script as the "familyID" argument
  • drop ESPR_NO_BOOT_JS from my previous stuff in this PR
  • add ESPR_SKIP_BOOT_JS_PIN to set a pin that can be pulled to ground on boot to skip running boot js (seems to work reasonably well, even without adding a delay between setting the pin mode and reading the pin value)

If you think that the whole skipping boot js stuff is not that good of an idea I'll just drop that for now and look into the other recovery option you suggested, where we'd have an "I messed up and want to reset my board" build.

@gfwilliams
Copy link
Member

Thanks! This is looking really good.

ESPR_SKIP_BOOT_JS_PIN

As D1 is configured as the button in the bootloader anyway, could we not just add BTN1' : { 'pin' : 'D1' , 'inverted' : 1} to the BOARD.py file, and this would have exactly the same effect, without having to have ESPR_SKIP_BOOT_JS_PIN? There are some other things we do (like clearing bonded peers) if booted with BTN1 held down so it might be preferable to do that route?

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.

2 participants