Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ This Arduino Core does **not** contain any BLE functionality. It has been design
* [Adafruit Feather nRF52840 Sense](https://www.adafruit.com/product/4516)
* [Adafruit ItsyBitsy nRF52840 Express](https://www.adafruit.com/product/4481)
* [Ebyte E104-BT5040U](https://www.ebyte.com/en/product-view-news.html?id=1185)
* [nice!nano v2](https://nicekeyboards.com/docs/nice-nano/)
* [XIAO nRF52840 Sense](https://wiki.seeedstudio.com/XIAO_BLE/)

### nRF52833
Expand Down Expand Up @@ -123,6 +124,16 @@ board = ...
1. Install adafruit-nrfutil if not already installed `pip install adafruit-nrfutil`
2. Select adafruit-nrfutil as the firmware uploader in the tools menu.

### Uploading via UF2
Boards with an Adafruit UF2 bootloader, such as the nice!nano v2, can be
programmed as follows:

1. In the Arduino IDE, select `Sketch -> Export Compiled Binary`. UF2 export
requires Python 3 to be available on the system path.
2. Double-press the board's reset button (or briefly connect RST to GND twice)
to enter the UF2 bootloader and wait for the bootloader drive to mount.
3. Copy the exported `.uf2` file to the mounted bootloader drive.

### Uploading via (Nordic) nrfutil (for Nordic bootloader devices only)
1. Install nrfutil if not already installed `pip install nrfutil`
2. Select nrfutil as the firmware uploader in the tools menu.
Expand Down
86 changes: 86 additions & 0 deletions boards.txt
Original file line number Diff line number Diff line change
Expand Up @@ -989,6 +989,92 @@ BT5040.menu.bootloader.none.bootloader.flags=-DUSE_NORDIC_BL
BT5040.menu.bootloader.none.build.bootloader.file=


# Nice Keyboards

nicenano_v2.name=nice!nano v2

nicenano_v2.vid.0=0x239A
nicenano_v2.pid.0=0x80B3
nicenano_v2.vid.1=0x239A
nicenano_v2.pid.1=0x00B3

nicenano_v2.upload.tool=openocd
nicenano_v2.upload.target=nrf52
nicenano_v2.upload.jlink_device=nRF52840_xxAA
nicenano_v2.upload.use_1200bps_touch=true
nicenano_v2.upload.wait_for_upload_port=true
nicenano_v2.upload.maximum_size=1032192
nicenano_v2.upload.maximum_data_size=262144
nicenano_v2.bootloader.tool=openocd

nicenano_v2.build.dfu_pattern={adafruit-nrfutil.dfu_pattern}
nicenano_v2.build.uf2_family=0xADA52840
nicenano_v2.build.mcu=cortex-m4
nicenano_v2.build.f_cpu=64000000
nicenano_v2.build.board=NICE_NANO_V2
nicenano_v2.build.core=nRF5
nicenano_v2.build.variant=nice_nano_v2
nicenano_v2.build.variant_system_lib=
nicenano_v2.build.usb_manufacturer="Nice Keyboards"
nicenano_v2.build.usb_product="nice!nano v2"
nicenano_v2.build.extra_flags=-DNRF52_SERIES -DNRF52840_XXAA {bootloader.flags} {build.flags.usb} -DCONFIG_NIMBLE_CPP_LOG_LEVEL={build.cpp_debug} {build.nimble_flags}
nicenano_v2.build.ldscript=nrf52840_s140_v6_adabl.ld
nicenano_v2.build.lfclk_flags=-DUSE_LFXO
nicenano_v2.build.vid=0x239A
nicenano_v2.build.pid=0x80B3
nicenano_v2.build.float_flags=-mfloat-abi=hard -mfpu=fpv4-sp-d16
nicenano_v2.recipe.objcopy.uf2.pattern="{tools.uf2conv.cmd}" "{runtime.platform.path}/tools/uf2conv.py" -f {build.uf2_family} -o "{build.path}/{build.project_name}.uf2" "{build.path}/{build.project_name}.hex"
nicenano_v2.recipe.output.tmp_file={build.project_name}.uf2
nicenano_v2.recipe.output.save_file={build.project_name}.{build.variant}.uf2

nicenano_v2.menu.role.all=All
nicenano_v2.menu.role.all.build.nimble_flags=
nicenano_v2.menu.role.periph=Peripheral
nicenano_v2.menu.role.periph.build.nimble_flags=-DCONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED -DCONFIG_BT_NIMBLE_ROLE_OBSERVER_DISABLED
nicenano_v2.menu.role.adv=Advertiser
nicenano_v2.menu.role.adv.build.nimble_flags=-DCONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED -DCONFIG_BT_NIMBLE_ROLE_OBSERVER_DISABLED -DCONFIG_BT_NIMBLE_ROLE_PERIPHERAL_DISABLED
nicenano_v2.menu.role.scan=Scanner
nicenano_v2.menu.role.scan.build.nimble_flags=-DCONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED -DCONFIG_BT_NIMBLE_ROLE_PERIPHERAL_DISABLED -DCONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED
nicenano_v2.menu.role.central=Client
nicenano_v2.menu.role.central.build.nimble_flags=-DCONFIG_BT_NIMBLE_ROLE_PERIPHERAL_DISABLED -DCONFIG_BT_NIMBLE_ROLE_BROADCASTER_DISABLED

nicenano_v2.menu.cppDbgLvl.none=None
nicenano_v2.menu.cppDbgLvl.none.build.cpp_debug=0
nicenano_v2.menu.cppDbgLvl.error=Error
nicenano_v2.menu.cppDbgLvl.error.build.cpp_debug=1
nicenano_v2.menu.cppDbgLvl.warn=Warn
nicenano_v2.menu.cppDbgLvl.warn.build.cpp_debug=2
nicenano_v2.menu.cppDbgLvl.info=Info
nicenano_v2.menu.cppDbgLvl.info.build.cpp_debug=3
nicenano_v2.menu.cppDbgLvl.debug=Debug
nicenano_v2.menu.cppDbgLvl.debug.build.cpp_debug=4

nicenano_v2.menu.bootloader.adafruit_ble=Adafruit BLE (s140 v6 softdevice)
nicenano_v2.menu.bootloader.adafruit_ble.bootloader.flags=-DUSE_ADA_BL -DADA_SD_BL
nicenano_v2.menu.bootloader.adafruit_ble.upload.tool=adafruit-nrfutil
nicenano_v2.menu.bootloader.adafruit_ble.upload.protocol=adafruit-nrfutil
nicenano_v2.menu.bootloader.adafruit_ble.upload.maximum_size=827392
nicenano_v2.menu.bootloader.adafruit_ble.upload.maximum_data_size=237568
nicenano_v2.menu.bootloader.adafruit_ble.build.dfu_pattern={adafruit-nrfutil.dfu_pattern}
nicenano_v2.menu.bootloader.adafruit_ble.build.bootloader.file=tools/nrf52840_s140_v6_adabl.hex
nicenano_v2.menu.bootloader.adafruit_ble.build.ldscript=nrf52840_s140_v6_adabl.ld

nicenano_v2.menu.bootloader.adafruit_serial=Adafruit Serial (no softdevice)
nicenano_v2.menu.bootloader.adafruit_serial.bootloader.flags=-DUSE_ADA_BL
nicenano_v2.menu.bootloader.adafruit_serial.upload.tool=adafruit-nrfutil
nicenano_v2.menu.bootloader.adafruit_serial.upload.protocol=adafruit-nrfutil
nicenano_v2.menu.bootloader.adafruit_serial.upload.maximum_size=978944
nicenano_v2.menu.bootloader.adafruit_serial.upload.maximum_data_size=262136
nicenano_v2.menu.bootloader.adafruit_serial.build.dfu_pattern={adafruit-nrfutil.dfu_pattern}
nicenano_v2.menu.bootloader.adafruit_serial.build.bootloader.file=tools/nrf52840_serial_adabl.hex
nicenano_v2.menu.bootloader.adafruit_serial.build.ldscript=nrf52840_serial_adabl.ld

nicenano_v2.menu.bootloader.none=No bootloader
nicenano_v2.menu.bootloader.none.bootloader.flags=
nicenano_v2.menu.bootloader.none.build.bootloader.file=tools/none_bootloader.hex
nicenano_v2.menu.bootloader.none.build.ldscript=nrf52840_xxaa.ld


# Seeedstudio

seeed52840sense.name=Seeed XIAO nRF52840 Sense
Expand Down
4 changes: 3 additions & 1 deletion platform.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ adafruit-nrfutil.dfu_pattern="{tools.adafruit-nrfutil.cmd}" dfu genpkg --dev-typ
none.dfu_pattern.cmd=no_dfu
none.dfu_pattern.cmd.windows=no_dfu.bat
none.dfu_pattern.path={runtime.platform.path}/tools
tools.uf2conv.cmd=python3
tools.uf2conv.cmd.windows=python

nordic.path={build.core.path}/nordic

Expand Down Expand Up @@ -229,4 +231,4 @@ tools.adafruit-nrfutil.upload.pattern="{cmd}" {upload.verbose} dfu serial -pkg "

tools.adafruit-nrfutil.program.params.verbose=--verbose
tools.adafruit-nrfutil.program.params.quiet=
tools.adafruit-nrfutil.program.pattern="{cmd}" {program.verbose} dfu serial -pkg "{build.path}/{build.project_name}.zip" -p {serial.port} -b 115200 --singlebank
tools.adafruit-nrfutil.program.pattern="{cmd}" {program.verbose} dfu serial -pkg "{build.path}/{build.project_name}.zip" -p {serial.port} -b 115200 --singlebank
138 changes: 138 additions & 0 deletions tools/uf2conv.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
#!/usr/bin/env python3

import argparse
import struct
import sys


UF2_MAGIC_START0 = 0x0A324655
UF2_MAGIC_START1 = 0x9E5D5157
UF2_MAGIC_END = 0x0AB16F30
UF2_FLAG_FAMILY_ID_PRESENT = 0x00002000
UF2_PAYLOAD_SIZE = 256


def parse_int(value):
return int(value, 0)


def parse_hex_line(line, line_number):
line = line.strip()
if not line:
return None
if not line.startswith(":"):
raise ValueError(f"line {line_number}: missing ':'")

try:
raw = bytes.fromhex(line[1:])
except ValueError as exc:
raise ValueError(f"line {line_number}: invalid hex") from exc

if len(raw) < 5:
raise ValueError(f"line {line_number}: record is too short")

count = raw[0]
if len(raw) != count + 5:
raise ValueError(f"line {line_number}: record length mismatch")

if (sum(raw) & 0xFF) != 0:
raise ValueError(f"line {line_number}: checksum mismatch")

address = (raw[1] << 8) | raw[2]
record_type = raw[3]
payload = raw[4:4 + count]

required_lengths = {0x01: 0, 0x02: 2, 0x03: 4, 0x04: 2, 0x05: 4}
if record_type in required_lengths:
if count != required_lengths[record_type]:
raise ValueError(f"line {line_number}: invalid record length for type {record_type:#x}")
if address != 0:
raise ValueError(f"line {line_number}: non-zero address for type {record_type:#x}")

return record_type, address, payload
Comment thread
coderabbitai[bot] marked this conversation as resolved.


def read_ihex(filename):
data = {}
upper_address = 0
eof_seen = False

with open(filename, "r", encoding="ascii") as hex_file:
for line_number, line in enumerate(hex_file, 1):
record = parse_hex_line(line, line_number)
if record is None:
continue
if eof_seen:
raise ValueError(f"line {line_number}: record after EOF")

record_type, address, payload = record
if record_type == 0x00:
absolute = upper_address + address
for offset, value in enumerate(payload):
data[absolute + offset] = value
elif record_type == 0x01:
eof_seen = True
elif record_type == 0x02:
upper_address = int.from_bytes(payload, "big") << 4
elif record_type == 0x04:
upper_address = int.from_bytes(payload, "big") << 16
elif record_type in (0x03, 0x05):
continue
else:
raise ValueError(f"line {line_number}: unsupported record type {record_type:#x}")

if not eof_seen:
raise ValueError("input HEX is missing EOF record")
if not data:
raise ValueError("input HEX contains no data records")

return data


def build_blocks(data):
blocks = {}
for address, value in data.items():
block_address = address & ~(UF2_PAYLOAD_SIZE - 1)
if block_address not in blocks:
blocks[block_address] = bytearray([0xFF] * UF2_PAYLOAD_SIZE)
blocks[block_address][address - block_address] = value

return sorted(blocks.items())


def write_uf2(blocks, family_id, output):
total = len(blocks)
with open(output, "wb") as uf2_file:
for index, (address, payload) in enumerate(blocks):
header = struct.pack(
"<IIIIIIII",
UF2_MAGIC_START0,
UF2_MAGIC_START1,
UF2_FLAG_FAMILY_ID_PRESENT,
address,
UF2_PAYLOAD_SIZE,
index,
total,
family_id,
)
block = header + bytes(payload)
block += bytes(512 - len(block) - 4)
block += struct.pack("<I", UF2_MAGIC_END)
uf2_file.write(block)


def main(argv):
parser = argparse.ArgumentParser(description="Convert an Intel HEX file to UF2.")
parser.add_argument("-f", "--family", type=parse_int, required=True, help="UF2 family ID")
parser.add_argument("-o", "--output", required=True, help="output UF2 file")
parser.add_argument("input", help="input Intel HEX file")
args = parser.parse_args(argv)

data = read_ihex(args.input)
blocks = build_blocks(data)
write_uf2(blocks, args.family, args.output)
print(f"Wrote {args.output} ({len(blocks)} UF2 blocks)")


if __name__ == "__main__":
main(sys.argv[1:])
45 changes: 45 additions & 0 deletions variants/nice_nano_v2/variant.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include "variant.h"
#include "wiring_constants.h"
#include "wiring_digital.h"
#include "nrf.h"

const uint32_t g_ADigitalPinMap[] =
{
// nice!nano v2 edge castellations
8, // D0 is P0.08
6, // D1 is P0.06
17, // D2 is P0.17
20, // D3 is P0.20
22, // D4 is P0.22
24, // D5 is P0.24
32, // D6 is P1.00
11, // D7 is P0.11
36, // D8 is P1.04
38, // D9 is P1.06
9, // D10 is P0.09

// Exposed bottom pads
33, // D11 is P1.01
34, // D12 is P1.02
39, // D13 is P1.07

// nice!nano v2 edge castellations
43, // D14 is P1.11
45, // D15 is P1.13
10, // D16 is P0.10
42, // D17 is P1.10
47, // D18 is P1.15
2, // D19 is P0.02 (AIN0)
29, // D20 is P0.29 (AIN5)
31, // D21 is P0.31 (AIN7)

15, // D22 is P0.15 (status LED)
4, // D23 is P0.04 (battery voltage)
13, // D24 is P0.13 (VCC cutoff)
};

void initVariant()
{
pinMode(PIN_LED, OUTPUT);
ledOff(PIN_LED);
}
Loading
Loading