@typecad/framework-zephyr 1.0.0-alpha.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +100 -0
- package/dist/async/timer-polyfill.d.ts +10 -0
- package/dist/async/timer-polyfill.js +95 -0
- package/dist/chips/controllers.d.ts +21 -0
- package/dist/chips/controllers.js +66 -0
- package/dist/chips/esp32.d.ts +2 -0
- package/dist/chips/esp32.js +59 -0
- package/dist/chips/esp32s3.d.ts +2 -0
- package/dist/chips/esp32s3.js +54 -0
- package/dist/chips/index.d.ts +15 -0
- package/dist/chips/index.js +45 -0
- package/dist/chips/resolve.d.ts +9 -0
- package/dist/chips/resolve.js +121 -0
- package/dist/chips/types.d.ts +154 -0
- package/dist/chips/types.js +14 -0
- package/dist/chips/xiao-ble.d.ts +2 -0
- package/dist/chips/xiao-ble.js +61 -0
- package/dist/debug-codegen.d.ts +33 -0
- package/dist/debug-codegen.js +162 -0
- package/dist/display/gfx.d.ts +17 -0
- package/dist/display/gfx.js +171 -0
- package/dist/display/index.d.ts +20 -0
- package/dist/display/index.js +53 -0
- package/dist/display/profiles.d.ts +25 -0
- package/dist/display/profiles.js +41 -0
- package/dist/display/touch-adapter.d.ts +9 -0
- package/dist/display/touch-adapter.js +95 -0
- package/dist/display/ui-adapter.d.ts +21 -0
- package/dist/display/ui-adapter.js +534 -0
- package/dist/dt-config/kconfig.d.ts +27 -0
- package/dist/dt-config/kconfig.js +283 -0
- package/dist/dt-config/overlay.d.ts +35 -0
- package/dist/dt-config/overlay.js +246 -0
- package/dist/framework.manifest.d.ts +98 -0
- package/dist/framework.manifest.js +525 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +12 -0
- package/dist/lowering/adc.d.ts +19 -0
- package/dist/lowering/adc.js +76 -0
- package/dist/lowering/ble.d.ts +20 -0
- package/dist/lowering/ble.js +419 -0
- package/dist/lowering/board.d.ts +9 -0
- package/dist/lowering/board.js +33 -0
- package/dist/lowering/gpio.d.ts +12 -0
- package/dist/lowering/gpio.js +123 -0
- package/dist/lowering/http.d.ts +23 -0
- package/dist/lowering/http.js +482 -0
- package/dist/lowering/i2c.d.ts +15 -0
- package/dist/lowering/i2c.js +114 -0
- package/dist/lowering/index.d.ts +29 -0
- package/dist/lowering/index.js +93 -0
- package/dist/lowering/interrupts.d.ts +21 -0
- package/dist/lowering/interrupts.js +91 -0
- package/dist/lowering/mqtt.d.ts +19 -0
- package/dist/lowering/mqtt.js +366 -0
- package/dist/lowering/power.d.ts +9 -0
- package/dist/lowering/power.js +64 -0
- package/dist/lowering/preferences.d.ts +23 -0
- package/dist/lowering/preferences.js +345 -0
- package/dist/lowering/pulse.d.ts +7 -0
- package/dist/lowering/pulse.js +82 -0
- package/dist/lowering/pwm.d.ts +15 -0
- package/dist/lowering/pwm.js +59 -0
- package/dist/lowering/random.d.ts +18 -0
- package/dist/lowering/random.js +129 -0
- package/dist/lowering/spi.d.ts +17 -0
- package/dist/lowering/spi.js +113 -0
- package/dist/lowering/timing.d.ts +9 -0
- package/dist/lowering/timing.js +63 -0
- package/dist/lowering/tone.d.ts +10 -0
- package/dist/lowering/tone.js +50 -0
- package/dist/lowering/uart.d.ts +15 -0
- package/dist/lowering/uart.js +102 -0
- package/dist/lowering/util.d.ts +4 -0
- package/dist/lowering/util.js +12 -0
- package/dist/lowering/wdt.d.ts +15 -0
- package/dist/lowering/wdt.js +80 -0
- package/dist/lowering/wifi.d.ts +21 -0
- package/dist/lowering/wifi.js +447 -0
- package/dist/lowering/worker-backing.d.ts +14 -0
- package/dist/lowering/worker-backing.js +79 -0
- package/dist/lowering/worker.d.ts +6 -0
- package/dist/lowering/worker.js +14 -0
- package/dist/strategy.d.ts +168 -0
- package/dist/strategy.js +1094 -0
- package/dist/toolchain/debug-config.d.ts +82 -0
- package/dist/toolchain/debug-config.js +359 -0
- package/dist/toolchain/index.d.ts +73 -0
- package/dist/toolchain/index.js +427 -0
- package/dist/toolchain/scaffold.d.ts +15 -0
- package/dist/toolchain/scaffold.js +196 -0
- package/dist/toolchain/west-discover.d.ts +40 -0
- package/dist/toolchain/west-discover.js +203 -0
- package/dist/toolchain/west-spawn.d.ts +39 -0
- package/dist/toolchain/west-spawn.js +117 -0
- package/package.json +82 -0
- package/src/async/timer-polyfill.ts +107 -0
- package/src/chips/controllers.ts +74 -0
- package/src/chips/esp32.ts +62 -0
- package/src/chips/esp32s3.ts +57 -0
- package/src/chips/index.ts +54 -0
- package/src/chips/resolve.ts +146 -0
- package/src/chips/types.ts +163 -0
- package/src/chips/xiao-ble.ts +64 -0
- package/src/debug-codegen.ts +207 -0
- package/src/display/gfx.ts +190 -0
- package/src/display/index.ts +70 -0
- package/src/display/profiles.ts +63 -0
- package/src/display/touch-adapter.ts +100 -0
- package/src/display/ui-adapter.ts +558 -0
- package/src/dt-config/kconfig.ts +308 -0
- package/src/dt-config/overlay.ts +293 -0
- package/src/framework.manifest.ts +545 -0
- package/src/index.ts +23 -0
- package/src/lowering/adc.ts +102 -0
- package/src/lowering/ble.ts +426 -0
- package/src/lowering/board.ts +38 -0
- package/src/lowering/gpio.ts +148 -0
- package/src/lowering/http.ts +488 -0
- package/src/lowering/i2c.ts +126 -0
- package/src/lowering/index.ts +86 -0
- package/src/lowering/interrupts.ts +114 -0
- package/src/lowering/mqtt.ts +371 -0
- package/src/lowering/power.ts +70 -0
- package/src/lowering/preferences.ts +354 -0
- package/src/lowering/pulse.ts +93 -0
- package/src/lowering/pwm.ts +74 -0
- package/src/lowering/random.ts +135 -0
- package/src/lowering/spi.ts +124 -0
- package/src/lowering/timing.ts +72 -0
- package/src/lowering/tone.ts +60 -0
- package/src/lowering/uart.ts +111 -0
- package/src/lowering/util.ts +12 -0
- package/src/lowering/wdt.ts +84 -0
- package/src/lowering/wifi.ts +452 -0
- package/src/lowering/worker-backing.ts +94 -0
- package/src/lowering/worker.ts +17 -0
- package/src/strategy.ts +1265 -0
- package/src/toolchain/debug-config.ts +399 -0
- package/src/toolchain/index.ts +459 -0
- package/src/toolchain/scaffold.ts +196 -0
- package/src/toolchain/west-discover.ts +233 -0
- package/src/toolchain/west-spawn.ts +141 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Espressif ESP32 (esp32_devkitc) — Zephyr board descriptor
|
|
3
|
+
//
|
|
4
|
+
// Board target: `esp32_devkitc` (mainline Zephyr,
|
|
5
|
+
// boards/espressif/esp32_devkitc). Programmed over USB via the esptool runner
|
|
6
|
+
// (see toolchain/index.ts), the same flash path as the ESP32-S3.
|
|
7
|
+
//
|
|
8
|
+
// GPIO is split across TWO devicetree controllers — `gpio0` (pins 0–31) and
|
|
9
|
+
// `gpio1` (pins 32–39) — so this descriptor lists both in `gpioControllers`.
|
|
10
|
+
// The lowering routes each HAL pin to its owning controller at runtime; see
|
|
11
|
+
// chips/controllers.ts. (Same shape as the S3, but the ESP32's highest GPIO is
|
|
12
|
+
// 39, not 48 — `gpio1` has ngpios=8, not 17.)
|
|
13
|
+
//
|
|
14
|
+
// Minimal-by-design: the only DT facts carried here are the ones a compile-time
|
|
15
|
+
// DT macro cannot reach — the runtime pin→controller split, plus the `sw0`
|
|
16
|
+
// alias for the BOOT button (used by the devicetree-spec GPIO path). Every other
|
|
17
|
+
// DT fact (UART/I2C/SPI/`wdt` nodelabels) is resolved by Zephyr's own
|
|
18
|
+
// devicetree via emitted DT_NODELABEL macros, not hand-copied here.
|
|
19
|
+
//
|
|
20
|
+
// Verified against the Zephyr board DTS:
|
|
21
|
+
// boards/espressif/esp32_devkitc/esp32_devkitc_procpu.dts
|
|
22
|
+
// aliases { sw0 = &button0; } → button_0: pin 0 on gpio0, active-low + pull-up
|
|
23
|
+
// &gpio0/&gpio1 { status = "okay" } (esp32_devkitc_procpu.dts:64-70)
|
|
24
|
+
// &wifi { status = "okay" } (esp32_devkitc_procpu.dts:143-145)
|
|
25
|
+
// GPIO controller coverage:
|
|
26
|
+
// dts/xtensa/espressif/esp32/esp32_common.dtsi:314-337
|
|
27
|
+
// gpio0: ngpios = <32> (pins 0–31)
|
|
28
|
+
// gpio1: ngpios = <8> (pins 32–39)
|
|
29
|
+
//
|
|
30
|
+
// Note: GPIO 34–39 are input-only pads on ESP32 silicon (not modeled here —
|
|
31
|
+
// the DT does not encode output restrictions per pin; an output config on those
|
|
32
|
+
// pins fails at runtime against the raw controller, which is the expected
|
|
33
|
+
// silicon-accurate behavior).
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
import type { ZephyrChipDescriptor } from './types.js';
|
|
37
|
+
|
|
38
|
+
export const ESP32_DEVKITC: ZephyrChipDescriptor = {
|
|
39
|
+
id: 'esp32_devkitc',
|
|
40
|
+
soc: 'esp32',
|
|
41
|
+
gpioController: 'gpio0',
|
|
42
|
+
gpioControllers: [
|
|
43
|
+
{ nodelabel: 'gpio0', minPin: 0, maxPin: 31 },
|
|
44
|
+
{ nodelabel: 'gpio1', minPin: 32, maxPin: 39 },
|
|
45
|
+
],
|
|
46
|
+
gpio: {
|
|
47
|
+
// The BOOT button (GPIO0) is the board's only DT-aliased GPIO. Listed so a
|
|
48
|
+
// program reading/interrupting pin 0 goes through the polarity-correct
|
|
49
|
+
// devicetree-spec path (GPIO_ACTIVE_LOW honored by the DT flags).
|
|
50
|
+
dtSpecs: [
|
|
51
|
+
{ pin: 0, dtSpec: 'sw0' }, // BOOT button (GPIO0)
|
|
52
|
+
],
|
|
53
|
+
interruptPins: [
|
|
54
|
+
{ pin: 0, dtSpec: 'sw0' }, // BOOT button (GPIO0)
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
// WiFi: the ESP32 has a 2.4GHz radio; conn_mgr + the esp32 wifi driver
|
|
58
|
+
// (CONFIG_WIFI_ESP32) provide connectivity. WIFI_ESP32 depends on !SMP, and
|
|
59
|
+
// the ESP32 is AMP (dual-image procpu/appcpu), not SMP, by default — so the
|
|
60
|
+
// dependency is satisfied. Omitted on radioless targets.
|
|
61
|
+
wifi: { supported: true },
|
|
62
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Espressif ESP32-S3 (esp32s3_devkitc) — Zephyr board descriptor
|
|
3
|
+
//
|
|
4
|
+
// Board target: `esp32s3_devkitc` (mainline Zephyr,
|
|
5
|
+
// boards/espressif/esp32s3_devkitc). Programmed over USB via the esptool
|
|
6
|
+
// runner (see toolchain/index.ts), unlike the J-Link/nrfjprog path used for
|
|
7
|
+
// the XIAO nRF52840.
|
|
8
|
+
//
|
|
9
|
+
// GPIO is split across TWO devicetree controllers — `gpio0` (pins 0–31) and
|
|
10
|
+
// `gpio1` (pins 32–48) — so this descriptor lists both in `gpioControllers`.
|
|
11
|
+
// The lowering routes each HAL pin to its owning controller at runtime; see
|
|
12
|
+
// chips/controllers.ts.
|
|
13
|
+
//
|
|
14
|
+
// Minimal-by-design: the only DT facts carried here are the ones a
|
|
15
|
+
// compile-time DT macro cannot reach — the runtime pin→controller split, plus
|
|
16
|
+
// the `sw0` alias for the BOOT button (used by the devicetree-spec GPIO path).
|
|
17
|
+
// Every other DT fact (UART/I2C/SPI/`wdt` nodelabels) is resolved by Zephyr's
|
|
18
|
+
// own devicetree via emitted DT_NODELABEL macros, not hand-copied here.
|
|
19
|
+
//
|
|
20
|
+
// Verified against the Zephyr board DTS:
|
|
21
|
+
// boards/espressif/esp32s3_devkitc/esp32s3_devkitc_procpu.dts
|
|
22
|
+
// aliases { sw0 = &button0; } → button_0: pin 0 on gpio0, active-low + pull-up
|
|
23
|
+
// (the DevKitC board DTS defines no led0 alias — the onboard RGB is a WS2812
|
|
24
|
+
// on GPIO38, not a plain GPIO LED, so it is intentionally NOT listed here.)
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
|
|
27
|
+
import type { ZephyrChipDescriptor } from './types.js';
|
|
28
|
+
|
|
29
|
+
export const ESP32S3_DEVKITC: ZephyrChipDescriptor = {
|
|
30
|
+
id: 'esp32s3_devkitc',
|
|
31
|
+
soc: 'esp32s3',
|
|
32
|
+
gpioController: 'gpio0',
|
|
33
|
+
gpioControllers: [
|
|
34
|
+
{ nodelabel: 'gpio0', minPin: 0, maxPin: 31 },
|
|
35
|
+
{ nodelabel: 'gpio1', minPin: 32, maxPin: 48 },
|
|
36
|
+
],
|
|
37
|
+
gpio: {
|
|
38
|
+
// The BOOT button (GPIO0) is the board's only DT-aliased GPIO. Listed so a
|
|
39
|
+
// program reading/interrupting pin 0 goes through the polarity-correct
|
|
40
|
+
// devicetree-spec path (GPIO_ACTIVE_LOW honored by the DT flags). Every
|
|
41
|
+
// other GPIO pin uses the raw-controller path against its owning controller.
|
|
42
|
+
dtSpecs: [
|
|
43
|
+
{ pin: 0, dtSpec: 'sw0' }, // BOOT button (GPIO0)
|
|
44
|
+
],
|
|
45
|
+
interruptPins: [
|
|
46
|
+
{ pin: 0, dtSpec: 'sw0' }, // BOOT button (GPIO0)
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
// UART/I2C/SPI/`wdt` are intentionally omitted: their devicetree nodelabels
|
|
50
|
+
// (uart0/uart1/uart2, i2c0/i2c1, spi2/spi3, wdt0) are resolved by Zephyr's
|
|
51
|
+
// devicetree at compile time and don't need to be carried as data here. ADC is
|
|
52
|
+
// omitted as well — added when a demo needs analog reads, with the verified
|
|
53
|
+
// ESP32-S3 ADC1/ADC2 pin→channel map.
|
|
54
|
+
// WiFi: the ESP32-S3 has a 2.4GHz radio; conn_mgr + the esp32 wifi driver
|
|
55
|
+
// (CONFIG_WIFI_ESP32) provide connectivity. Omitted on radioless targets.
|
|
56
|
+
wifi: { supported: true },
|
|
57
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Chip descriptor registry — maps Zephyr board target → ZephyrChipDescriptor
|
|
3
|
+
//
|
|
4
|
+
// Mirrors framework-esp32/src/chips/index.ts: a module-level activeChip,
|
|
5
|
+
// setActiveChip/getActiveChip, and chipForTarget resolving from
|
|
6
|
+
// frameworkData.buildTarget. The strategy calls setActiveChip during profile
|
|
7
|
+
// resolution so the lowering reads a single cached descriptor.
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
import type { ZephyrChipDescriptor } from './types.js';
|
|
11
|
+
import { XIAO_BLE } from './xiao-ble.js';
|
|
12
|
+
import { ESP32S3_DEVKITC } from './esp32s3.js';
|
|
13
|
+
import { ESP32_DEVKITC } from './esp32.js';
|
|
14
|
+
|
|
15
|
+
export { XIAO_BLE, ESP32S3_DEVKITC, ESP32_DEVKITC };
|
|
16
|
+
export type { ZephyrChipDescriptor, ZephyrGpioDtSpec } from './types.js';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Default chip used when no buildTarget is supplied. The XIAO nRF52840 is the
|
|
20
|
+
* canonical MVP target; subsequent board additions extend the switch below.
|
|
21
|
+
*/
|
|
22
|
+
const DEFAULT_CHIP: ZephyrChipDescriptor = XIAO_BLE;
|
|
23
|
+
|
|
24
|
+
let activeChip: ZephyrChipDescriptor = DEFAULT_CHIP;
|
|
25
|
+
|
|
26
|
+
export function setActiveChip(d: ZephyrChipDescriptor): void {
|
|
27
|
+
activeChip = d;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function getActiveChip(): ZephyrChipDescriptor {
|
|
31
|
+
return activeChip;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Resolve a chip descriptor from the Zephyr board target string
|
|
36
|
+
* (frameworkData.buildTarget / frameworkData.target). Accepts the bare board
|
|
37
|
+
* id ('xiao_ble', 'esp32s3_devkitc', 'esp32_devkitc') or a board/qualifier
|
|
38
|
+
* path ('esp32s3_devkitc/esp32s3/procpu', 'esp32_devkitc/esp32/procpu').
|
|
39
|
+
*/
|
|
40
|
+
export function chipForTarget(target?: string): ZephyrChipDescriptor {
|
|
41
|
+
const t = (target ?? '').trim().toLowerCase();
|
|
42
|
+
const boardId = t.split('/')[0];
|
|
43
|
+
switch (boardId) {
|
|
44
|
+
case 'xiao_ble':
|
|
45
|
+
return XIAO_BLE;
|
|
46
|
+
case 'esp32s3_devkitc':
|
|
47
|
+
return ESP32S3_DEVKITC;
|
|
48
|
+
case 'esp32_devkitc':
|
|
49
|
+
return ESP32_DEVKITC;
|
|
50
|
+
case '':
|
|
51
|
+
default:
|
|
52
|
+
return DEFAULT_CHIP;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Derive ZephyrChipDescriptor from board/MCU package constants
|
|
3
|
+
//
|
|
4
|
+
// The board constants resolver extracts flat dot-path scalars from the board
|
|
5
|
+
// and MCU definition files. This utility reconstructs the structured
|
|
6
|
+
// ZephyrChipDescriptor from those flat keys, merging SoC-level defaults
|
|
7
|
+
// (from the MCU package's zephyr field) with board-level overrides (from the
|
|
8
|
+
// board package's zephyr field).
|
|
9
|
+
//
|
|
10
|
+
// When a board package carries Zephyr config, this path replaces the
|
|
11
|
+
// hardcoded chip descriptor registry. When it doesn't (legacy), chipForTarget
|
|
12
|
+
// still works as the fallback.
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
import type { BoardConstants } from '@typecad/cuttlefish/api/shared';
|
|
16
|
+
import type {
|
|
17
|
+
ZephyrChipDescriptor,
|
|
18
|
+
ZephyrGpioDtSpec,
|
|
19
|
+
ZephyrGpioController,
|
|
20
|
+
ZephyrBusController,
|
|
21
|
+
ZephyrPwmSpec,
|
|
22
|
+
ZephyrInterruptPin,
|
|
23
|
+
ZephyrAdcChannel,
|
|
24
|
+
} from './types.js';
|
|
25
|
+
|
|
26
|
+
/** Collect an indexed array of objects reconstructed from flat dot-path keys. */
|
|
27
|
+
function collectIndexed<T>(
|
|
28
|
+
bc: BoardConstants,
|
|
29
|
+
prefix: string,
|
|
30
|
+
build: (bc: BoardConstants, index: number) => T | null,
|
|
31
|
+
): T[] {
|
|
32
|
+
const result: T[] = [];
|
|
33
|
+
for (let i = 0; i < 256; i++) {
|
|
34
|
+
const checkKey = `${prefix}.${i}`;
|
|
35
|
+
let hasAny = false;
|
|
36
|
+
for (const [k] of bc) {
|
|
37
|
+
if (k.startsWith(checkKey)) { hasAny = true; break; }
|
|
38
|
+
}
|
|
39
|
+
if (!hasAny) break;
|
|
40
|
+
const item = build(bc, i);
|
|
41
|
+
if (item) result.push(item);
|
|
42
|
+
}
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function collectBusControllers(
|
|
47
|
+
bc: BoardConstants,
|
|
48
|
+
prefix: string,
|
|
49
|
+
): ZephyrBusController[] {
|
|
50
|
+
return collectIndexed<ZephyrBusController>(bc, prefix, (m, i) => {
|
|
51
|
+
const nodeLabel = m.get(`${prefix}.${i}.nodeLabel`) as string;
|
|
52
|
+
return nodeLabel ? { nodeLabel } : null;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Try to derive a ZephyrChipDescriptor from board/MCU package constants.
|
|
58
|
+
*
|
|
59
|
+
* Returns null when no zephyr info is available in the board constants
|
|
60
|
+
* (the caller should fall back to the hardcoded chipForTarget registry).
|
|
61
|
+
*/
|
|
62
|
+
export function resolveChipFromBoard(
|
|
63
|
+
bc: BoardConstants | undefined,
|
|
64
|
+
): ZephyrChipDescriptor | null {
|
|
65
|
+
if (!bc) return null;
|
|
66
|
+
|
|
67
|
+
const boardTarget = bc.get('build.frameworks.zephyr') as string | undefined;
|
|
68
|
+
if (!boardTarget) return null;
|
|
69
|
+
|
|
70
|
+
const zGpioController = bc.get('zephyr.gpioController') as string | undefined;
|
|
71
|
+
const soc = (bc.get('mcu.id') as string) ?? '';
|
|
72
|
+
|
|
73
|
+
// ── Build mutable sub-objects, then construct the final descriptor ──────
|
|
74
|
+
|
|
75
|
+
const gc = collectIndexed<ZephyrGpioController>(bc, 'zephyr.gpioControllers', (m, i) => {
|
|
76
|
+
const nodelabel = m.get(`zephyr.gpioControllers.${i}.nodelabel`) as string;
|
|
77
|
+
const minPin = m.get(`zephyr.gpioControllers.${i}.minPin`) as number;
|
|
78
|
+
const maxPin = m.get(`zephyr.gpioControllers.${i}.maxPin`) as number;
|
|
79
|
+
if (nodelabel != null && minPin != null && maxPin != null) {
|
|
80
|
+
return { nodelabel, minPin, maxPin };
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const dtSpecs = collectIndexed<ZephyrGpioDtSpec>(bc, 'zephyr.gpio.dtSpecs', (m, i) => {
|
|
86
|
+
const pin = m.get(`zephyr.gpio.dtSpecs.${i}.pin`) as number;
|
|
87
|
+
const dtSpec = m.get(`zephyr.gpio.dtSpecs.${i}.dtSpec`) as string;
|
|
88
|
+
if (pin != null && dtSpec) return { pin, dtSpec };
|
|
89
|
+
return null;
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const intPins = collectIndexed<ZephyrInterruptPin>(bc, 'zephyr.gpio.interruptPins', (m, i) => {
|
|
93
|
+
const pin = m.get(`zephyr.gpio.interruptPins.${i}.pin`) as number;
|
|
94
|
+
const dtSpec = m.get(`zephyr.gpio.interruptPins.${i}.dtSpec`) as string;
|
|
95
|
+
if (pin != null && dtSpec) return { pin, dtSpec };
|
|
96
|
+
return null;
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const i2cControllers = collectBusControllers(bc, 'zephyr.i2c.controllers');
|
|
100
|
+
const spiControllers = collectBusControllers(bc, 'zephyr.spi.controllers');
|
|
101
|
+
const uartControllers = collectBusControllers(bc, 'zephyr.uart.controllers');
|
|
102
|
+
|
|
103
|
+
const pwmSpecs = collectIndexed<ZephyrPwmSpec>(bc, 'zephyr.pwm.specs', (m, i) => {
|
|
104
|
+
const pin = m.get(`zephyr.pwm.specs.${i}.pin`) as number;
|
|
105
|
+
const dtSpec = m.get(`zephyr.pwm.specs.${i}.dtSpec`) as string;
|
|
106
|
+
if (pin != null && dtSpec) return { pin, dtSpec };
|
|
107
|
+
return null;
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const adcNodeLabel = bc.get('zephyr.adc.nodeLabel') as string | undefined;
|
|
111
|
+
const adcResolution = bc.get('zephyr.adc.resolution') as number | undefined;
|
|
112
|
+
const adcVref = bc.get('zephyr.adc.vrefMv') as number | undefined;
|
|
113
|
+
const adcChannels = collectIndexed<ZephyrAdcChannel>(bc, 'zephyr.adc.channels', (m, i) => {
|
|
114
|
+
const pin = m.get(`zephyr.adc.channels.${i}.pin`) as number;
|
|
115
|
+
const channel = m.get(`zephyr.adc.channels.${i}.channel`) as number;
|
|
116
|
+
if (pin != null && channel != null) return { pin, channel };
|
|
117
|
+
return null;
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const wdtNodeLabel = bc.get('zephyr.wdt.nodeLabel') as string | undefined;
|
|
121
|
+
const wifiSupported = bc.get('zephyr.wifi.supported') as boolean | undefined;
|
|
122
|
+
|
|
123
|
+
// ── Construct the final readonly descriptor ─────────────────────────────
|
|
124
|
+
|
|
125
|
+
const gpio: ZephyrChipDescriptor['gpio'] = {
|
|
126
|
+
dtSpecs,
|
|
127
|
+
...(intPins.length > 0 ? { interruptPins: intPins } : {}),
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
id: boardTarget,
|
|
132
|
+
soc,
|
|
133
|
+
gpioController: zGpioController ?? 'gpio0',
|
|
134
|
+
...(gc.length > 0 ? { gpioControllers: gc } : {}),
|
|
135
|
+
gpio,
|
|
136
|
+
...(i2cControllers.length > 0 ? { i2c: { controllers: i2cControllers } } : {}),
|
|
137
|
+
...(spiControllers.length > 0 ? { spi: { controllers: spiControllers } } : {}),
|
|
138
|
+
...(uartControllers.length > 0 ? { uart: { controllers: uartControllers } } : {}),
|
|
139
|
+
...(pwmSpecs.length > 0 ? { pwm: { specs: pwmSpecs } } : {}),
|
|
140
|
+
...(adcNodeLabel || adcResolution != null || adcVref != null || adcChannels.length > 0
|
|
141
|
+
? { adc: { nodeLabel: adcNodeLabel ?? 'adc', resolution: adcResolution ?? 12, vrefMv: adcVref ?? 3000, channels: adcChannels } }
|
|
142
|
+
: {}),
|
|
143
|
+
...(wdtNodeLabel ? { wdt: { nodeLabel: wdtNodeLabel } } : {}),
|
|
144
|
+
...(wifiSupported ? { wifi: { supported: true as const } } : {}),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Zephyr chip descriptor — pure-data model
|
|
3
|
+
//
|
|
4
|
+
// Mirrors the per-framework chip-descriptor pattern established by
|
|
5
|
+
// framework-esp32 (Esp32ChipDescriptor) and framework-avr (AVRChipDescriptor):
|
|
6
|
+
// the framework owns its own device-tree-derived descriptor, keyed off the
|
|
7
|
+
// Zephyr board target string in frameworkData.buildTarget. The board/MCU
|
|
8
|
+
// packages are deliberately NOT read at emit time (see the framework-package
|
|
9
|
+
// data-flow split); this descriptor is the source the lowering reads.
|
|
10
|
+
//
|
|
11
|
+
// No behavior — the lowering code in src/lowering/*.ts reads getActiveChip()
|
|
12
|
+
// to resolve pins to devicetree specs and raw-controller fallbacks.
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A GPIO pin described as a devicetree spec.
|
|
17
|
+
*
|
|
18
|
+
* Zephyr addresses GPIO via `struct gpio_dt_spec` resolved from devicetree
|
|
19
|
+
* aliases/labels (e.g. DT_ALIAS(led0)). The dtSpec form is preferred because
|
|
20
|
+
* `gpio_pin_set_dt()` honors the node's polarity flags — so an active-low LED
|
|
21
|
+
* (logical 1 = LED on) is handled by the DT `GPIO_ACTIVE_LOW` flag, not by the
|
|
22
|
+
* generated C++.
|
|
23
|
+
*/
|
|
24
|
+
export interface ZephyrGpioDtSpec {
|
|
25
|
+
/** GPIO number — matches the HAL op `pin` field (P0.X → X, P1.X → 32+X). */
|
|
26
|
+
readonly pin: number;
|
|
27
|
+
/**
|
|
28
|
+
* Devicetree alias/nodelabel macro, e.g. `led0`, `sw0`, `led1`.
|
|
29
|
+
* Emitted as `GPIO_DT_SPEC_GET(DT_ALIAS(<dtSpec>), gpios)`.
|
|
30
|
+
*/
|
|
31
|
+
readonly dtSpec: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* A GPIO controller devicetree node, and the HAL pin-number range it owns.
|
|
36
|
+
*
|
|
37
|
+
* Most SoCs expose a single GPIO controller (nRF52840: `gpio0` owns every
|
|
38
|
+
* pin). SoCs that split GPIO across multiple devicetree nodes — e.g. the
|
|
39
|
+
* ESP32-S3 (`gpio0`: pins 0–31, `gpio1`: pins 32–48) — list one entry per
|
|
40
|
+
* controller so the lowering can route a HAL pin to the owning controller at
|
|
41
|
+
* runtime. Pin numbers match the HAL op `pin` field.
|
|
42
|
+
*/
|
|
43
|
+
export interface ZephyrGpioController {
|
|
44
|
+
/** Devicetree nodelabel, e.g. 'gpio0', 'gpio1'. */
|
|
45
|
+
readonly nodelabel: string;
|
|
46
|
+
/** First HAL pin number owned by this controller (inclusive). */
|
|
47
|
+
readonly minPin: number;
|
|
48
|
+
/** Last HAL pin number owned by this controller (inclusive). */
|
|
49
|
+
readonly maxPin: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* A bus controller (I2C / SPI / UART) described by its devicetree nodelabel.
|
|
54
|
+
*
|
|
55
|
+
* Zephyr resolves the `const struct device*` at compile time via
|
|
56
|
+
* `DEVICE_DT_GET(DT_NODELABEL(<nodeLabel>))`, so unlike ESP-IDF there is no
|
|
57
|
+
* lazy handle resolution — the lowering emits the macro directly.
|
|
58
|
+
*/
|
|
59
|
+
export interface ZephyrBusController {
|
|
60
|
+
/** Devicetree nodelabel, e.g. 'i2c1', 'spi2', 'uart0'. */
|
|
61
|
+
readonly nodeLabel: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* A PWM channel described as a devicetree spec.
|
|
66
|
+
*
|
|
67
|
+
* Emitted as `struct pwm_dt_spec __tc_pwm<N> = PWM_DT_SPEC_GET(DT_ALIAS(<dtSpec>))`.
|
|
68
|
+
* `pwm_set_pulse_dt(&__tc_pwm<N>, pulse_ns)` honors the spec's period/polarity.
|
|
69
|
+
*/
|
|
70
|
+
export interface ZephyrPwmSpec {
|
|
71
|
+
/** GPIO number (matches the HAL op `pin` field). */
|
|
72
|
+
readonly pin: number;
|
|
73
|
+
/** Devicetree alias, e.g. 'pwm-led0'. */
|
|
74
|
+
readonly dtSpec: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* A GPIO pin usable as an interrupt source.
|
|
79
|
+
*
|
|
80
|
+
* Emitted as `struct gpio_dt_spec __tc_int<N> = GPIO_DT_SPEC_GET(DT_ALIAS(<dtSpec>), gpios)`
|
|
81
|
+
* + a `struct gpio_callback` registered via `gpio_add_callback`.
|
|
82
|
+
*/
|
|
83
|
+
export interface ZephyrInterruptPin {
|
|
84
|
+
/** GPIO number (matches the HAL op `pin` field). */
|
|
85
|
+
readonly pin: number;
|
|
86
|
+
/** Devicetree alias, e.g. 'sw0', or a nodelabel. */
|
|
87
|
+
readonly dtSpec: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* An ADC channel: which SAADC input a given HAL pin maps to.
|
|
92
|
+
*
|
|
93
|
+
* The XIAO nRF52840 has no pre-declared ADC channel nodes in devicetree, so the
|
|
94
|
+
* lowering emits `adc_channel_setup` against `DEVICE_DT_GET(DT_NODELABEL(adc))`
|
|
95
|
+
* using the `channel` index here (SAADC AIN0–AIN7).
|
|
96
|
+
*/
|
|
97
|
+
export interface ZephyrAdcChannel {
|
|
98
|
+
/** GPIO number (matches the HAL op `pin` field). */
|
|
99
|
+
readonly pin: number;
|
|
100
|
+
/** SAADC channel index (AIN0–AIN7). */
|
|
101
|
+
readonly channel: number;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Pure-data descriptor for a Zephyr board + its SoC's peripheral layout.
|
|
106
|
+
*/
|
|
107
|
+
export interface ZephyrChipDescriptor {
|
|
108
|
+
/** Zephyr board target (the `west build -b <id>` argument), e.g. 'xiao_ble'. */
|
|
109
|
+
readonly id: string;
|
|
110
|
+
/** SoC family, e.g. 'nrf52840'. */
|
|
111
|
+
readonly soc: string;
|
|
112
|
+
/**
|
|
113
|
+
* Default GPIO controller nodelabel for the raw-pin fallback. Pins not in
|
|
114
|
+
* `gpio.dtSpecs` are addressed via
|
|
115
|
+
* `DEVICE_DT_GET(DT_NODELABEL(<gpioController>))` + gpio_pin_*_raw().
|
|
116
|
+
*
|
|
117
|
+
* For SoCs that split GPIO across multiple devicetree nodes, `gpioControllers`
|
|
118
|
+
* overrides this per pin range; this field is then only the out-of-range
|
|
119
|
+
* fallback (so a single-controller board is unaffected by it).
|
|
120
|
+
*/
|
|
121
|
+
readonly gpioController: string;
|
|
122
|
+
/**
|
|
123
|
+
* Per-range GPIO controllers for SoCs that split GPIO across multiple
|
|
124
|
+
* devicetree nodes (ESP32-S3: `gpio0` 0–31, `gpio1` 32–48). When present, the
|
|
125
|
+
* lowering routes a HAL pin to its owning controller at runtime via the
|
|
126
|
+
* emitted `__tc_gpio_dev(pin)` dispatcher; `gpioController` is the fallback.
|
|
127
|
+
* Omit on single-controller SoCs (nRF52840, RP2040, …) — every pin is on the
|
|
128
|
+
* one controller described by `gpioController`.
|
|
129
|
+
*/
|
|
130
|
+
readonly gpioControllers?: readonly ZephyrGpioController[];
|
|
131
|
+
/** GPIO pins with devicetree specs (LEDs, buttons, board-defined pins). */
|
|
132
|
+
readonly gpio: {
|
|
133
|
+
readonly dtSpecs: readonly ZephyrGpioDtSpec[];
|
|
134
|
+
/** Interrupt-capable pins with DT specs (buttons etc.). */
|
|
135
|
+
readonly interruptPins?: readonly ZephyrInterruptPin[];
|
|
136
|
+
};
|
|
137
|
+
/** I2C controllers (board-wired). Index 0 = the primary bus. */
|
|
138
|
+
readonly i2c?: { readonly controllers: readonly ZephyrBusController[] };
|
|
139
|
+
/** SPI controllers (board-wired). Index 0 = the primary bus. */
|
|
140
|
+
readonly spi?: { readonly controllers: readonly ZephyrBusController[] };
|
|
141
|
+
/** UART controllers (board-wired). Index 0 = the primary port. */
|
|
142
|
+
readonly uart?: { readonly controllers: readonly ZephyrBusController[] };
|
|
143
|
+
/** PWM channels with DT specs. */
|
|
144
|
+
readonly pwm?: { readonly specs: readonly ZephyrPwmSpec[] };
|
|
145
|
+
/** ADC: the SAADC node label + the pin→channel map. */
|
|
146
|
+
readonly adc?: {
|
|
147
|
+
readonly nodeLabel: string;
|
|
148
|
+
readonly channels: readonly ZephyrAdcChannel[];
|
|
149
|
+
/** Reference voltage in millivolts (nRF internal = 3000 for VDD/4 + gain 1/4… use 3000). */
|
|
150
|
+
readonly vrefMv: number;
|
|
151
|
+
/** ADC resolution in bits. */
|
|
152
|
+
readonly resolution: number;
|
|
153
|
+
};
|
|
154
|
+
/** Watchdog node label, e.g. 'wdt0'. */
|
|
155
|
+
readonly wdt?: { readonly nodeLabel: string };
|
|
156
|
+
/**
|
|
157
|
+
* WiFi capability marker. Present only on chips with a WiFi radio (ESP32-S3).
|
|
158
|
+
* Read by profileDiagnostics to flag wifi.* usage on chips without a radio.
|
|
159
|
+
* Omit on radioless chips (nRF52840) — its absence is the "no WiFi" signal.
|
|
160
|
+
*/
|
|
161
|
+
readonly wifi?: { readonly supported: true };
|
|
162
|
+
}
|
|
163
|
+
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Seeed Studio XIAO nRF52840 — Zephyr board descriptor
|
|
3
|
+
//
|
|
4
|
+
// Board target: `xiao_ble` (mainline Zephyr, boards/seeed/xiao_ble).
|
|
5
|
+
// The onboard user LED is active-low and exposed as the DT alias `led0`.
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
|
|
8
|
+
import type { ZephyrChipDescriptor } from './types.js';
|
|
9
|
+
|
|
10
|
+
export const XIAO_BLE: ZephyrChipDescriptor = {
|
|
11
|
+
id: 'xiao_ble',
|
|
12
|
+
soc: 'nrf52840',
|
|
13
|
+
gpioController: 'gpio0',
|
|
14
|
+
gpio: {
|
|
15
|
+
dtSpecs: [
|
|
16
|
+
// Onboard RGB LEDs — active-low (GPIO_ACTIVE_LOW in xiao_ble_common.dtsi).
|
|
17
|
+
// Verified against the board's `aliases { led0 = &led0; led1 = &led1; led2 = &led2; }`.
|
|
18
|
+
{ pin: 26, dtSpec: 'led0' }, // Red (P0.26)
|
|
19
|
+
{ pin: 30, dtSpec: 'led1' }, // Green (P0.30)
|
|
20
|
+
{ pin: 6, dtSpec: 'led2' }, // Blue (P0.06)
|
|
21
|
+
],
|
|
22
|
+
// The XIAO nRF52840 has a user button on P0.04, but mainline Zephyr's
|
|
23
|
+
// xiao_ble board (verified against Zephyr 4.3.99) does NOT expose it as a
|
|
24
|
+
// DT `sw0` alias — there is no gpio-keys node in xiao_ble.dts. Emitting
|
|
25
|
+
// GPIO_DT_SPEC_GET(DT_ALIAS(sw0), gpios) therefore fails to compile
|
|
26
|
+
// ('DT_N_ALIAS_sw0_... was not declared'). Until a button node + alias is
|
|
27
|
+
// added (via an overlay or an upstream board update), interruptPins stays
|
|
28
|
+
// empty: attachInterrupt on this board lowers to the no-DT-spec comment
|
|
29
|
+
// fallback rather than a hard compile error.
|
|
30
|
+
interruptPins: [],
|
|
31
|
+
},
|
|
32
|
+
// The XIAO connector wiring (from seeed_xiao_connector.dtsi + xiao_ble-pinctrl.dtsi):
|
|
33
|
+
// xiao_i2c → i2c1 (SDA P0.04/D4, SCL P0.05/D5)
|
|
34
|
+
// xiao_spi → spi2 (SCK P1.13/D8, MOSI P1.15/D10, MISO P1.14/D9)
|
|
35
|
+
// xiao_serial → uart0 (TX P1.11/D6, RX P1.12/D7)
|
|
36
|
+
// The board DTS leaves i2c0/spi0/spi1 disabled (shared instances).
|
|
37
|
+
i2c: {
|
|
38
|
+
controllers: [{ nodeLabel: 'i2c1' }],
|
|
39
|
+
},
|
|
40
|
+
spi: {
|
|
41
|
+
controllers: [{ nodeLabel: 'spi2' }],
|
|
42
|
+
},
|
|
43
|
+
uart: {
|
|
44
|
+
controllers: [{ nodeLabel: 'uart0' }],
|
|
45
|
+
},
|
|
46
|
+
pwm: {
|
|
47
|
+
// pwm-led0 drives the board PWM LED (PWM_OUT0 on P0.17, inverted).
|
|
48
|
+
specs: [{ pin: 17, dtSpec: 'pwm-led0' }],
|
|
49
|
+
},
|
|
50
|
+
adc: {
|
|
51
|
+
// SAADC node is `adc`; no pre-declared channels. XIAO D0–D3 = AIN0–AIN3
|
|
52
|
+
// (P0.02/P0.03/P0.28/P0.29). Internal VREF ~0.6V with VDD/4 gain ⇒ 3000mV.
|
|
53
|
+
nodeLabel: 'adc',
|
|
54
|
+
resolution: 12,
|
|
55
|
+
vrefMv: 3000,
|
|
56
|
+
channels: [
|
|
57
|
+
{ pin: 2, channel: 0 }, // P0.02 / D0 / AIN0
|
|
58
|
+
{ pin: 3, channel: 1 }, // P0.03 / D1 / AIN1
|
|
59
|
+
{ pin: 28, channel: 2 }, // P0.28 / D2 / AIN2
|
|
60
|
+
{ pin: 29, channel: 3 }, // P0.29 / D3 / AIN3
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
wdt: { nodeLabel: 'wdt0' },
|
|
64
|
+
};
|