BLEberry + CANboss in einer Firmware: eine Berry-REPL über BLE
(Nordic UART Service) kombiniert mit einem CANopen-Knoten
(CANopenNode via CANboss' lib/canopen) — plus Firmware-Store:
Firmware-Dateien werden per Web-Bluetooth aus dem Browser in den
Flash des STM32WBA6 geladen (512-KiB-Partition) und von dort
streamend per SDO-Block-Download ins CANopen-Netz eingespielt
(CiA-302-Programm-Download, Default 0x1F50:1).
Browser (webapp/index.html)
│ Web-BLE: fwxfer-GATT-Service (Chunks + Kommandos)
▼
STM32WBA65I-DK1 ──[interner Flash: fwstore, 2 Slots à ~256 KiB]
│ canBLEberry: BLE-REPL (Berry) + CANopenNode (Master, Node 127)
│ SPI (Arduino-Header) → MCP2518FD (Classic-CAN-Betrieb)
▼
CANopen-Netz ── SDO-Block-Download → Bootloader des Zielknotens (0x1F50:1)
| Rolle | Teil |
|---|---|
| MCU/BLE | STM32WBA65I-DK1 (stm32wba65i_dk1) oder Nucleo-WBA65RI (nucleo_wba65ri) |
| CAN-Controller | MCP2518FD an SPI — Referenz: Soldered „CAN Transceiver MCP2518 board" (solde.red/333020, Reichelt DEBO CAN MCP2518); alternativ MikroE MCP2518FD Click o. ä. |
| DK1 Arduino-Header | Soldered-Board | Anmerkung |
|---|---|---|
D13 (SCK) |
SCK |
|
D12 (MISO) |
SDO |
Slave-Out → Master-In |
D11 (MOSI) |
SDI |
|
D10 (CS) |
SCN |
Chip-Select (nCS) |
D2 |
INT |
der kombinierte INT, nicht INT0/INT1 |
5V |
VCC |
5 V zwingend: der ATA6561-Transceiver hängt direkt an VCC; der Onboard-LDO macht daraus 3,3 V für den MCP2518FD → SPI-Pegel sind trotzdem 3,3 V, kein Levelshifter nötig |
GND |
GND |
|
| — | CANH/CANL |
Schraubklemme zum Bus; Lötjumper JP1 schließen, wenn das Modul ein Busende ist (120 Ω) |
Quarz des Moduls: 40 MHz (passt zum Overlay-Default osc-freq);
CLKO/INT0/INT1 bleiben frei. Anderen Quarz im Overlay unter osc-freq
eintragen.
Das On-Chip-CAN wäre beim STM32WBA nicht vorhanden — genau deshalb der
SPI-Controller. Für das PIC32-BZ6-Curiosity-Board (BLE + mikroBUS,
Microchip-Zephyr-Fork) ist derselbe Aufbau als Phase 2 vorgesehen:
MCP2518FD Click in mikroBUS-Sockel 1 (sercom4), eigenes Overlay,
eigenes west-Manifest gegen Zephyr4Microchip/zephyr.
mkdir canbleberry-ws && cd canbleberry-ws
git clone <url> canbleberry
west init -l canbleberry
west update # holt zephyr v4.4.2, hal_stm32, berry, CANboss (+CANopenNode-Submodul)
west zephyr-export
pip install -r zephyr/scripts/requirements-base.txt
west blobs fetch hal_stm32 # BLE-LinkLayer fuer STM32WBA
west build -b stm32wba65i_dk1 canbleberry
west flash # braucht STM32CubeProgrammerDie App läuft ohne Bootloader ab 0x0; die obersten 512 KiB des
2-MiB-Flash sind die fwstore-Partition (Overlay).
Das Board advertised als canBLEberry. Zusätzlich zu den
BLEberry-Funktionen (led(), millis(), pinmode() …) gibt es:
od_nodes() # bekannte Knoten
od_read(16, 0x1017, 0) # SDO lesen
od_write(16, 0x2101, 0, 300, 2) # SDO schreiben
fw_list() # Firmware-Slots anzeigen
fw_send(0, 16) # Slot 0 -> Node 16 (0x1F50:1)
fw_send(0, 16, 0x1F50, 1) # dito, Index/Sub explizit
fw_erase(0)help() zeigt die komplette Übersicht.
webapp/index.html über HTTPS oder http://localhost öffnen
(Web-BLE-Anforderung; lokal z. B. python3 -m http.server im
webapp/-Ordner, dann Chrome/Edge):
- Verbinden → Gerät
canBLEberrywählen. - Datei wählen, Slot wählen → Hochladen (Fortschritt + CRC32- Verifikation auf dem Gerät; halbe Uploads werden nie gültig).
- In der Slot-Tabelle → Node: Image per SDO-Streaming an den Zielknoten (Node-ID/Index/Sub einstellbar, Fortschritt live).
| Service | UUID(s) | Zweck |
|---|---|---|
| NUS (REPL) | Nordic 6e400001-b5a3-… |
Berry-REPL für Standard-Terminal-Apps |
| fwxfer | 6f572a01/02/03-4f9e-4d8c-a9d1-c9f0be6ac000 |
binärer Firmware-Upload + Steuerkommandos |
| jsonapi | 6f572b01/02/03-4f9e-4d8c-a9d1-c9f0be6ac000 |
NDJSON-Interface (CANboss lib/jsonapi): {"gtwa":…}, {"mon":…}, {"fw":…} |
Die REPL bleibt auf den Nordic-UUIDs (nRF Toolbox & Co. funktionieren unverändert); Webapp-Verkehr läuft über die eigenen Services.
Der jsonapi-Service (src/jsonapi_ble.c) transportiert dasselbe
NDJSON-Protokoll wie CANboss' apps/gateway über USB: RX-Characteristic
nimmt Requests (Bytestrom, \n-getrennt), die TX-Notifications liefern
Antworten und Events. Damit gehen aus der Webapp direkt
CiA-309-3-Kommandos und PDO-Monitoring:
{"gtwa": ["0 preop", "[1] 16 r 0x1017 0 u16", "0 start"]}
{"mon": {"add": ["0x181"], "rate": 100}} → {"pdo": {"cob":385,"d":"…","t":…}}
{"repl": "od_read(16, 0x1017, 0)"} → {"repl": ["1000"]}, {"repl": {"ok": true}}{"repl": …} läuft in einer zweiten Berry-VM (CANboss'
canboss_berry-Schicht mit od_*, plus fw_* und Board-I/O) —
getrennt von der interaktiven NUS-REPL-VM; die Ausgabe wird in
berry_port.c anhand des laufenden Threads dem richtigen Kanal
zugestellt.
Als fw-Backend hängt der Flash-fwstore auch am jsonapi (gleiche
Slots wie fwxfer). Für Uploads über BLE ist der binäre fwxfer-Weg
effizienter (kein Base64); fw send/prog funktionieren über beide.
Hinweis: Das CANopenNode-Gateway, od_* in der REPL und fw_send
teilen sich den einen SDO-Client — gleichzeitige SDO-Zugriffe aus REPL
und Webapp vermeiden.
Service 6f572a01-4f9e-4d8c-a9d1-c9f0be6ac000,
Control-Char …2a02… (Write + Notify, ASCII), Data-Char …2a03…
(Write Without Response, rohe Chunks).
| Kommando | Antwort(en) |
|---|---|
INFO |
INFO <slots> <slotcap> <ackwin> |
LIST |
je Slot SLOT <i> <size> <crc32> <name> bzw. SLOT <i> -, dann OK LIST |
BEGIN <slot> <size> [name] |
OK BEGIN …; danach Chunks auf Data-Char, Gerät sendet ACK <total> je 4 KiB |
END <crc32hex> |
OK END <crc32> oder ERR crc … |
ABORT |
OK ABORT |
ERASE <slot> |
OK ERASE <slot> |
SEND <slot> <node> [idx] [sub] |
PROG <sent> <total> …, dann OK SEND / ERR send … |
-
Der SDO-Client von CANopenNode läuft mit Block-Transfer (
CO_CONFIG_SDO_CLI_BLOCK, aktiviert übersrc/CO_driver_custom.h; die nötigen#ifndef-Guards liegen in CANboss'lib/canopen/port/CO_driver_target.h). -
cb_co_sdo_write_stream()(neu in CANbosslib/canopen/co_node.c) füttert den Transfer häppchenweise per Callback aus derfwstore-Partition — es liegt also nie das ganze Image im RAM. -
Grobe Richtwerte: 256 KiB @ 500 kbit/s ≈ 15–30 s, @ 250 kbit/s ≈ 30–60 s (Block-Transfer; segmentiert wäre ~5–8× langsamer).
-
Die Gegenstelle braucht einen CANopen-Bootloader, der
0x1F50:1(Program data) als Download akzeptiert. Die Sequenz drumherum (0x1F51Program control: stop/clear/start) lässt sich per REPL scripten, z. B.:od_write(16, 0x1F51, 1, 0, 1) # Program stop od_write(16, 0x1F51, 1, 3, 1) # Program clear fw_send(0, 16) # Image streamen od_write(16, 0x1F51, 1, 1, 1) # Program start
- Erstbuild gegen Zephyr v4.4.2 (BLEberry lief bisher auf
Zephyr
main; NUS-API und Board sind in v4.4.2 identisch vorhanden, PSA/mbedtls-Details können abweichen). Alternativ Manifest auf neueren Zephyr pinnen. - Flash-Schreiben während aktiver BLE-Verbindung auf STM32WBA (Arbitrierung LinkLayer ↔ Flash-Controller) unter Last testen; ggf. Connection-Intervall/Supervision-Timeout anpassen.
- MCP2518FD-Click/Shield-Pinout gegen Overlay prüfen (INT auf D2).
- Web-BLE-Durchsatz: realistisch ~5–20 KiB/s; 256 KiB ≈ 15–60 s.
- Phase 2: Overlay +
west-mchp.ymlfürpic32wm_bz6204_curiosity(Microchip-Forkmchp_pic32cxbz_v420, MCP2518FD ansercom4, mikroBUS-Sockel 1), bis Microchip On-Chip-CAN-FD nachliefert.
- BLEberry — Ursprung von
REPL/NUS-Terminal (
src/nus_io.c,berry_*,bb_runtime.c) - CANboss — CANopen-Schicht,
Berry-OD-Bindings, Master-OD,
lib/jsonapi(NDJSON-Protokoll) undapps/gateway(dasselbe Interface über USB/WebSerial); für canBLEberry erweitert umcb_co_sdo_write_stream(),canboss_berry_register()und die GTWA-Anbindung inco_node