Skip to content

Commit

Permalink
Even better support for Adafruit bootloader
Browse files Browse the repository at this point in the history
  • Loading branch information
ffenix113 committed Feb 16, 2024
1 parent de4a266 commit 53de1f2
Show file tree
Hide file tree
Showing 8 changed files with 235 additions and 131 deletions.
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,16 @@ This project is being developed based on [nRF52840 Dongle](https://www.nordicsem
Initial goal of the project is to support nRF52840 based devices, with expansion to nRF53 series.

* nRF52840 Dongle
* Arduino Nano 33 BLE (Sense) - experimental. Probably also other Bossac bootloader devices on nrf52840 as well.
* Early experimental support for boards with Adafruit bootloader. Please read note below.
* Arduino Nano 33 BLE (Sense). Probably also other Bossac bootloader devices on nrf52840 as well.
* Support for boards with Adafruit bootloader. Please read note below.

Experimental support is provided for Adafruit bootloader.
This means that any device running Adafruit bootloader could try to build the firmware with this tool,
but it cannot be guaranteed that generated firmware will work properly on the device.
Support is provided for Adafruit bootloader, but is not comprehensevily tested.
This means that any device running Adafruit bootloader will run the firmware generated by this tool,
but it cannot be fully guaranteed that the firmware will work properly on the device in all conditions.

Support was tested on my two boards with Adafruit bootloader(Arduino Nano 33 BLE & Seeed Xiao), and simple firmware was working correctly.

For Adafruit bootloader a UF2 file will be generated, which then can be flashed normally through drag-and-drop.

User can change configuration that allows bootloader support in `cli/types/board/known_boards.go`.

Expand Down
2 changes: 1 addition & 1 deletion cli/config/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ type General struct {
}

type Board struct {
Bootloader string
Bootloader *string
Debug *extenders.DebugConfig
IsRouter bool `yaml:"is_router"`
LEDs []devicetree.LED
Expand Down
19 changes: 15 additions & 4 deletions cli/generate/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,17 +92,24 @@ func (g *Generator) Generate(workDir string, device *config.Device) error {

func getExtenders(device *config.Device) ([]generator.Extender, error) {
var providedExtenders []generator.Extender

uniqueExtenders := map[string]struct{}{}

forcedBootloader := device.Board.Bootloader != ""
bootloaderConfig, bootloaderName := getBootloaderConfig(device.General.Board, device.Board.Bootloader)
forcedBootloader := device.Board.Bootloader != nil

var bootloaderName string
if forcedBootloader {
bootloaderName = *device.Board.Bootloader
}

bootloaderConfig, bootloaderName := getBootloaderConfig(device.General.Board, bootloaderName)
log.Printf("Device: %q, selected bootloader: %q, forced bootloader: %t\n",
device.General.Board,
bootloaderName,
forcedBootloader)

if forcedBootloader && bootloaderConfig == nil {
return nil, fmt.Errorf("Bootloader %q was forced, but is not found in known bootloaders", device.Board.Bootloader)
return nil, fmt.Errorf("Bootloader %q was forced, but is not found in known bootloaders", *device.Board.Bootloader)
}

if bootloaderConfig != nil {
Expand Down Expand Up @@ -133,6 +140,10 @@ func getExtenders(device *config.Device) ([]generator.Extender, error) {

if device.Board.Debug != nil && device.Board.Debug.Enabled {
providedExtenders = append(providedExtenders, extenders.NewDebugUARTLog(*device.Board.Debug))

if device.Board.Debug.Console == extenders.DebugConsoleUSB {
providedExtenders = append(providedExtenders, extenders.NewUSBUART())
}
}

if len(device.Board.UART) != 0 {
Expand Down Expand Up @@ -185,5 +196,5 @@ func getBootloaderConfig(boardName, bootloader string) (*board.Bootloader, strin
return board.BootloaderConfig(bootloader), bootloader
}

return board.BoardBootloaderConfig(boardName)
return board.BootloaderConfigFromBoard(boardName)
}
27 changes: 7 additions & 20 deletions cli/templates/src/extenders/pm_static.yml.tpl
Original file line number Diff line number Diff line change
@@ -1,20 +1,7 @@
# This file is based on
# https://github.com/martelmy/NCS_examples/blob/3cd874c68e13565ca89a082c67af54f48b704192/zigbee/light_bulb_dongle/pm_static_nrf52840dongle_nrf52840.yml
# , based on the answer here:
# https://devzone.nordicsemi.com/f/nordic-q-a/87169/zigbee-example-for-nrf52840-dongle/364086
#
# Thank you Marte Myrvold(https://github.com/martelmy)

{{- $flash := .AdditionalContext.Flash }}
{{- $sram := .AdditionalContext.SRAM }}

EMPTY_0:
address: {{formatHex $flash.Address}}
end_address: {{ formatHex $flash.EndAddress }}
region: flash_primary
size: {{ formatHex $flash.Size }}
EMPTY_1:
address: {{ formatHex $sram.Address }}
end_address: {{ formatHex $sram.EndAddress }}
region: sram_primary
size: {{ formatHex $sram.Size }}
{{- range .AdditionalContext }}
{{ .Name }}:
address: {{formatHex .Address}}
end_address: {{ formatHex .EndAddress }}
region: {{ if .Region }}{{.Region}}{{else}}flash_primary{{end}}
size: {{ formatHex .Size }}
{{- end}}
167 changes: 92 additions & 75 deletions cli/types/board/known_boards.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,39 @@ package board

import (
"slices"
"strconv"

"github.com/ffenix113/zigbee_home/cli/types/appconfig"
)

type Bootloader struct {
PM *PMConfig
PM []Section
Config []appconfig.ConfigValue
}

const (
RegionFlashPrimary = "flash_primary"
RegionSramPrimary = "sram_primary"
)

type Section struct {
Name string
Address int
Size int
}

type PMConfig struct {
Flash Section
SRAM Section
Region string
}

func (s Section) EndAddress() int {
return s.Address + s.Size
}

func BoardBootloaderConfig(board string) (*Bootloader, string) {
func BootloaderConfigFromBoard(board string) (*Bootloader, string) {
var boardBootloader string
for bootloader, boards := range bootloaderBoards {

for bootloader, boards := range bootloaderBoards() {
if _, found := slices.BinarySearch(boards, board); found {
boardBootloader = bootloader

break
}
}
Expand All @@ -40,10 +45,10 @@ func BoardBootloaderConfig(board string) (*Bootloader, string) {
func BootloaderConfig(bootloader string) *Bootloader {
// By default will return nil, if `bootloader` is empty.
// This would be enough to not include any bootloader configuration
return knownBootloaders[bootloader]
return knownBootloaders()[bootloader]
}

var bootloaderBoards = func() map[string][]string {
func bootloaderBoards() map[string][]string {
// Values in this map can be added in any order,
// as they will be ordered on the next step.
bootloadersMap := map[string][]string{
Expand All @@ -55,82 +60,94 @@ var bootloaderBoards = func() map[string][]string {
},
"adafruit_nrf52_sd132": {},
"adafruit_nrf52_sd140_v6": {},
"adafruit_nrf52_sd140_v7": {},
"adafruit_nrf52_sd140_v7": {
"xiao_ble",
},
}

for _, boards := range bootloadersMap {
slices.Sort(boards)
}

return bootloadersMap
}()

var knownBootloaders = map[string]*Bootloader{
"nrf52_legacy": { // Legacy NRF52 bootloader, provided with nRF5 SDK. Also used in nRF52840 Dongle till now for some reason.
PM: &PMConfig{
Flash: Section{
Address: 0xe0000,
Size: 0x20000,
},
SRAM: Section{
Address: 0x20000000,
Size: 0x400,
},
},
},
"arduino": { // Bossac bootloader
PM: &PMConfig{
Flash: Section{
Address: 0x0,
Size: 0x10000,
}

func knownBootloaders() map[string]*Bootloader {
adafruitConfig := func(appStartAddr int) *Bootloader {
appStartAddrHex := "0x" + strconv.FormatInt(int64(appStartAddr), 16)

return &Bootloader{
PM: []Section{
{
Name: "empty_app_offset",
Address: 0x0,
Size: appStartAddr,
Region: RegionFlashPrimary,
},
{
// This section is needed because without it
// the app will be from appStartAddr till 0xf7000,
// which is right in the middle of bootloader.
// Next section will be for zboss and it will start
// at 0xf7000, which will overwrite part of bootloader
// resulting in a dead board after power-cycle,
// but can be resurected if bootloader is re-flashed.
Name: "empty_after_zboss_offset",
Address: 0xf4000,
Size: 0xc000,
Region: RegionFlashPrimary,
},
},
// App is launching and starting to work without SRAM config,
// so we will not define it(for now at least).
// Maybe there will be issues in the future, and they will be fixed here.
},
},
"adafruit_nrf52_sd132": {
PM: &PMConfig{
// https://infocenter.nordicsemi.com/topic/sdk_nrf5_v17.1.0/lib_bootloader.html, "Memory layout" section
Flash: Section{
Address: 0x0,
Size: 0x26000,
Config: []appconfig.ConfigValue{
appconfig.NewValue("CONFIG_BUILD_OUTPUT_UF2").Required(appconfig.Yes),
// This option is to prevent use of default flash load offset.
// May be specific to some boards, but we need it just to be safe.
appconfig.NewValue("CONFIG_BOOTLOADER_BOSSA").Required(appconfig.No),
appconfig.NewValue("CONFIG_FLASH_LOAD_OFFSET").Required(appStartAddrHex),
},
},
Config: []appconfig.ConfigValue{
appconfig.NewValue("CONFIG_BUILD_OUTPUT_UF2").Required(appconfig.Yes),
appconfig.NewValue("CONFIG_BOOTLOADER_BOSSA").Required(appconfig.No),
appconfig.NewValue("CONFIG_FLASH_LOAD_OFFSET").Required("0x26000"),
},
},
"adafruit_nrf52_sd140_v6": {
PM: &PMConfig{
// https://infocenter.nordicsemi.com/topic/sdk_nrf5_v17.1.0/lib_bootloader.html, "Memory layout" section
Flash: Section{
Address: 0x0,
Size: 0x26000,
}
}

return map[string]*Bootloader{
// Legacy NRF52 bootloader, provided with nRF5 SDK. Also used in nRF52840 Dongle till now for some reason.
"nrf52_legacy": {
// This configuration is based on
// https://github.com/martelmy/NCS_examples/blob/3cd874c68e13565ca89a082c67af54f48b704192/zigbee/light_bulb_dongle/pm_static_nrf52840dongle_nrf52840.yml
// , based on the answer here:
// https://devzone.nordicsemi.com/f/nordic-q-a/87169/zigbee-example-for-nrf52840-dongle/364086
//
// Thank you Marte Myrvold(https://github.com/martelmy)
PM: []Section{
{
Name: "empty_bootloader",
Address: 0xe0000,
Size: 0x20000,
Region: RegionFlashPrimary,
},
{
Name: "empty_sram_bootloader",
Address: 0x20000000,
Size: 0x400,
Region: RegionSramPrimary,
},
},
},
Config: []appconfig.ConfigValue{
appconfig.NewValue("CONFIG_BUILD_OUTPUT_UF2").Required(appconfig.Yes),
// This option is to prevent use of default flash load offset.
// May be specific to some boards, but we need it just to be safe.
appconfig.NewValue("CONFIG_BOOTLOADER_BOSSA").Required(appconfig.No),
appconfig.NewValue("CONFIG_FLASH_LOAD_OFFSET").Required("0x26000"),
},
},
"adafruit_nrf52_sd140_v7": {
PM: &PMConfig{
// https://infocenter.nordicsemi.com/topic/sdk_nrf5_v17.1.0/lib_bootloader.html, "Memory layout" section
Flash: Section{
Address: 0x0,
Size: 0x27000,
// Bossac bootloader
"arduino": {
PM: []Section{
{
Name: "empty_before_app",
Address: 0x0,
Size: 0x10000,
Region: RegionFlashPrimary,
},
// App is launching and starting to work without SRAM config,
// so we will not define it(for now at least).
// Maybe there will be issues in the future, and they will be fixed here.
},
},
Config: []appconfig.ConfigValue{
appconfig.NewValue("CONFIG_BUILD_OUTPUT_UF2").Required(appconfig.Yes),
appconfig.NewValue("CONFIG_BOOTLOADER_BOSSA").Required(appconfig.No),
appconfig.NewValue("CONFIG_FLASH_LOAD_OFFSET").Required("0x27000"),
},
},
"adafruit_nrf52_sd132": adafruitConfig(0x26000),
"adafruit_nrf52_sd140_v6": adafruitConfig(0x26000),
"adafruit_nrf52_sd140_v7": adafruitConfig(0x27000),
}
}
28 changes: 25 additions & 3 deletions cli/zigbee.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@

general:
# Defines how much time a loop will sleep after each iteration.
# Note: This does not necesseraly mean that each 2 minutes
# sensor values will be updated. Currently all sensors are polled
# synchronously, which means that if there are 3 sensors defined
# and each needs 5 seconds to obtain the result then it will take
# (3 * 5)s + runevery, which in this case will be 1m15s.
runevery: 1m
# Board name, as defined in Zephyr.
board: nrf52840dongle_nrf52840

# This paths are necessary to build the generated firmware.
Expand All @@ -26,7 +32,7 @@ general:
# Currently `nrfutil`, `mcuboot` and `west`
# are defined(but not equally tested). Nrfutil works though.
flasher: nrfutil
# Flasheroptions are flasher-specific options
# Flasheroptions are flasher-specific options.
flasheroptions:
port: /dev/ttyACM1

Expand All @@ -45,17 +51,31 @@ board:
# placed correctly in memory. This setting can help in above situations.
# Also this option can be used to try and support boards that
# are not labeled as officialy supported.
#
# Note: if this field is present - this will force bootloader
# to be selected one, even if the value is empty string.
#bootloader: nrf52_legacy

# This option will add UART loging functionality.
# User can choose which console to use(usb or uart).
# UART has to be defined either in default device tree,
# or in `board.uart` section.
# Quite limited for now, but can be easily extended
debug:
debug:
# Enable logging and possibly LEDs
# for debugging.
enabled: false
# Console is where logs will be spit out.
# Choices are:
# * usb - no need to define any other configuration for `usb`.
# * uart1, uart2, ... - this either should be already defined for used board,
# or be defined in `uart` section.
console: uart0
# LEDs will use LED to show some board state(i.e. power, connection, etc).
# Leds used here MUST be always defined in `leds`, even if they already
# present in board definition.
leds:
# If false - leds will not be enabled to signal state.
enabled: true
# Define led which will be used to show that the board is powered.
power: led_green
Expand All @@ -78,11 +98,13 @@ board:
pin: 31
uart:
- id: uart0
# Pins are optional, if this is existing uart interface.
tx: 1.03
rx: 1.10
leds:
- id: led_green
pin:
# The `pin` section is optional, if led is already present in board definition.
pin:
port: 0
pin: 6
inverted: true
Expand Down

0 comments on commit 53de1f2

Please sign in to comment.