@typecad/framework-zephyr 1.0.0-alpha.12 → 1.0.0-alpha.14
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/README.md +13 -1
- package/dist/chips/controllers.d.ts +28 -8
- package/dist/chips/controllers.js +49 -12
- package/dist/chips/resolve.js +32 -6
- package/dist/chips/types.d.ts +63 -12
- package/dist/chips/xiao-ble.js +12 -0
- package/dist/display/index.d.ts +1 -1
- package/dist/display/index.js +1 -1
- package/dist/display/profiles.d.ts +8 -0
- package/dist/display/profiles.js +19 -0
- package/dist/display/ui-adapter.d.ts +4 -0
- package/dist/display/ui-adapter.js +46 -0
- package/dist/dt-config/kconfig.d.ts +11 -0
- package/dist/dt-config/kconfig.js +1 -1
- package/dist/dt-config/overlay.d.ts +8 -1
- package/dist/dt-config/overlay.js +104 -1
- package/dist/framework.manifest.d.ts +20 -30
- package/dist/framework.manifest.js +12 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -0
- package/dist/lowering/adc.d.ts +7 -4
- package/dist/lowering/adc.js +25 -11
- package/dist/lowering/gpio.js +15 -8
- package/dist/lowering/mqtt.js +9 -1
- package/dist/lowering/pulse.js +7 -7
- package/dist/lowering/pwm.d.ts +21 -3
- package/dist/lowering/pwm.js +28 -4
- package/dist/lowering/spi.js +2 -2
- package/dist/lowering/tone.js +3 -2
- package/dist/lowering/wifi.js +28 -5
- package/dist/strategy.d.ts +20 -0
- package/dist/strategy.js +295 -119
- package/dist/toolchain/debug-config.d.ts +43 -2
- package/dist/toolchain/debug-config.js +129 -17
- package/dist/toolchain/index.d.ts +14 -1
- package/dist/toolchain/index.js +146 -20
- package/dist/toolchain/scaffold.d.ts +9 -0
- package/dist/toolchain/scaffold.js +84 -19
- package/dist/toolchain/west-discover.d.ts +4 -1
- package/dist/toolchain/west-discover.js +2 -0
- package/dist/toolchain/west-spawn.js +17 -5
- package/package.json +5 -5
- package/src/chips/controllers.ts +61 -12
- package/src/chips/resolve.ts +32 -5
- package/src/chips/types.ts +63 -12
- package/src/chips/xiao-ble.ts +82 -70
- package/src/display/index.ts +1 -1
- package/src/display/profiles.ts +23 -0
- package/src/display/ui-adapter.ts +51 -0
- package/src/dt-config/kconfig.ts +12 -1
- package/src/dt-config/overlay.ts +123 -0
- package/src/framework.manifest.ts +12 -3
- package/src/index.ts +6 -0
- package/src/lowering/adc.ts +28 -12
- package/src/lowering/gpio.ts +15 -8
- package/src/lowering/mqtt.ts +9 -1
- package/src/lowering/pulse.ts +7 -7
- package/src/lowering/pwm.ts +29 -4
- package/src/lowering/spi.ts +2 -2
- package/src/lowering/tone.ts +3 -3
- package/src/lowering/wifi.ts +29 -5
- package/src/strategy.ts +320 -123
- package/src/toolchain/debug-config.ts +137 -14
- package/src/toolchain/index.ts +645 -513
- package/src/toolchain/scaffold.ts +81 -17
- package/src/toolchain/west-discover.ts +321 -316
- package/src/toolchain/west-spawn.ts +17 -5
|
@@ -11,7 +11,18 @@
|
|
|
11
11
|
// library headers into .d.ts; Zephyr does it by enabling DT nodes + Kconfig.)
|
|
12
12
|
// ---------------------------------------------------------------------------
|
|
13
13
|
import { PANEL_CONTROLLER_DEFAULTS, panelControllerFor } from '../display/profiles.js';
|
|
14
|
-
export function generateOverlay(chip, usage, display, wiring, touch) {
|
|
14
|
+
export function generateOverlay(chip, usage, display, wiring, touch, diagnostics = []) {
|
|
15
|
+
// An I2C touch controller with no explicit bus pins: the overlay enables
|
|
16
|
+
// i2c0 and instantiates the node, but nothing remuxes the controller to
|
|
17
|
+
// the wired SDA/SCL (the board's default I2C pins rarely match a
|
|
18
|
+
// breakout). Every I2C read then fails and touch silently does nothing —
|
|
19
|
+
// surface it at build time instead of leaving it to a multimeter.
|
|
20
|
+
if (touch && touch.controller !== 'xpt2046' && (touch.sda === undefined || touch.scl === undefined)) {
|
|
21
|
+
diagnostics.push({
|
|
22
|
+
severity: "warning",
|
|
23
|
+
message: `touch: I2C controller '${touch.controller}' has no sda/scl pins in cuttlefish.config.ts — the overlay enables the bus without a pin assignment, so the controller may never answer. Add touch.sda and touch.scl (the board's default I2C pins are rarely the wired ones).`,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
15
26
|
const lines = [
|
|
16
27
|
'/* Auto-generated by @typecad/framework-zephyr from cuttlefish.config.ts. */',
|
|
17
28
|
'/* Enables peripherals the program uses. West merges this over the board DT. */',
|
|
@@ -42,6 +53,24 @@ export function generateOverlay(chip, usage, display, wiring, touch) {
|
|
|
42
53
|
for (const c of chip.uart.controllers)
|
|
43
54
|
block(c.nodeLabel);
|
|
44
55
|
}
|
|
56
|
+
// PWM: synthesized specs (controller + channel, no board-shipped alias) get
|
|
57
|
+
// a pwm-leds consumer node + tc-pwm<pin> alias here — the lowering addresses
|
|
58
|
+
// the channel as PWM_DT_SPEC_GET(DT_ALIAS(tc-pwm<pin>)), so the alias must
|
|
59
|
+
// exist in the merged DT. pwmDtAlias (lowering/pwm.ts) derives the same
|
|
60
|
+
// name from the pin; the two sides cannot drift. Filtered to the pins the
|
|
61
|
+
// program actually drives (pwmUsedPins) so the DT carries no dead channels;
|
|
62
|
+
// an undefined list (prepare-time overlay) emits all specs.
|
|
63
|
+
if (usage.usesPwm && chip.pwm) {
|
|
64
|
+
emitPwmNodes(lines, chip, usage.pwmUsedPins);
|
|
65
|
+
}
|
|
66
|
+
// ADC: enable the ADC device node, and on SoCs whose channels carry a
|
|
67
|
+
// pinctrl label (STM32: the pad stays in GPIO mode unless the ADC node's
|
|
68
|
+
// pinctrl-0 muxes it analog), rewrite pinctrl-0 to exactly the channels the
|
|
69
|
+
// program reads. DT assignment replaces the whole property — the board
|
|
70
|
+
// default (one pad) is deliberately dropped in favor of the used set.
|
|
71
|
+
if (usage.usesAdc && chip.adc) {
|
|
72
|
+
emitAdcNode(lines, chip, usage.adcReadPins);
|
|
73
|
+
}
|
|
45
74
|
// DAC: enable the chip's DAC device node when the program uses dac.*. The
|
|
46
75
|
// lowering references DEVICE_DT_GET(DT_NODELABEL(<dac.device>)).
|
|
47
76
|
if (usage.usesDac && chip.dac) {
|
|
@@ -95,6 +124,73 @@ export function generateOverlay(chip, usage, display, wiring, touch) {
|
|
|
95
124
|
}
|
|
96
125
|
return lines.join('\n');
|
|
97
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* Emit the pwm-leds consumer node + aliases for synthesized PWM specs.
|
|
129
|
+
*
|
|
130
|
+
* A board DTS may enable a PWM controller (`pwm4`) without aliasing any
|
|
131
|
+
* channel — the STM32 pattern — while the lowering addresses channels via
|
|
132
|
+
* DT_ALIAS. Each synthesized spec gets a `pwm-leds` child whose `pwms` cell
|
|
133
|
+
* binds the controller+channel (+ period/polarity), and a `tc-pwm<pin>`
|
|
134
|
+
* alias pointing at it. Alias/label names are valid DT identifiers (lowercase
|
|
135
|
+
* alphanumerics + dash/underscore).
|
|
136
|
+
*/
|
|
137
|
+
function emitPwmNodes(lines, chip, usedPins) {
|
|
138
|
+
const synthesized = (chip.pwm?.specs ?? []).filter((s) => s.controller && s.channel != null && !s.dtSpec).filter((s) => !usedPins || usedPins.includes(s.pin));
|
|
139
|
+
if (synthesized.length === 0)
|
|
140
|
+
return;
|
|
141
|
+
// Enable each distinct PWM controller node (idempotent when already okay).
|
|
142
|
+
for (const controller of [...new Set(synthesized.map((s) => s.controller))]) {
|
|
143
|
+
lines.push(`&${controller} {`);
|
|
144
|
+
lines.push(' status = "okay";');
|
|
145
|
+
lines.push('};');
|
|
146
|
+
lines.push('');
|
|
147
|
+
}
|
|
148
|
+
lines.push('/ {');
|
|
149
|
+
lines.push(' tc_pwm_leds: tc-pwm-leds {');
|
|
150
|
+
lines.push(' compatible = "pwm-leds";');
|
|
151
|
+
for (const s of synthesized) {
|
|
152
|
+
// 20 ms / 50 Hz default — the servo convention; the duty scaling in the
|
|
153
|
+
// lowering normalizes 0-255 against whatever period is baked in.
|
|
154
|
+
const period = s.periodNs ?? 20_000_000;
|
|
155
|
+
const polarity = s.polarity ?? 'PWM_POLARITY_NORMAL';
|
|
156
|
+
lines.push(` tc_pwm_${s.pin}: pwm-led-${s.pin} {`);
|
|
157
|
+
lines.push(` pwms = <&${s.controller} ${s.channel} ${period} ${polarity}>;`);
|
|
158
|
+
lines.push(' };');
|
|
159
|
+
}
|
|
160
|
+
lines.push(' };');
|
|
161
|
+
lines.push(' aliases {');
|
|
162
|
+
for (const s of synthesized) {
|
|
163
|
+
lines.push(` tc-pwm${s.pin} = &tc_pwm_${s.pin};`);
|
|
164
|
+
}
|
|
165
|
+
lines.push(' };');
|
|
166
|
+
lines.push('};');
|
|
167
|
+
lines.push('');
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Emit the ADC device-node enable (+ optional pinctrl override). The pinctrl
|
|
171
|
+
* override applies only when the descriptor's channels carry pinctrl labels
|
|
172
|
+
* AND the caller knows which pins the program reads (compile-time regen scans
|
|
173
|
+
* the emitted `__tc_adc<N>_setup()` calls); the prepare-time overlay omits it
|
|
174
|
+
* and the compile regen rewrites the file before west runs.
|
|
175
|
+
*/
|
|
176
|
+
function emitAdcNode(lines, chip, readPins) {
|
|
177
|
+
const adc = chip.adc;
|
|
178
|
+
const labeled = adc.channels.filter((c) => c.pinctrl);
|
|
179
|
+
const used = labeled.filter((c) => !readPins || readPins.includes(c.pin));
|
|
180
|
+
if (labeled.length > 0 && used.length > 0) {
|
|
181
|
+
lines.push(`&${adc.nodeLabel} {`);
|
|
182
|
+
lines.push(' status = "okay";');
|
|
183
|
+
lines.push(` pinctrl-0 = <${used.map((c) => `&${c.pinctrl}`).join(' ')}>;`);
|
|
184
|
+
lines.push(' pinctrl-names = "default";');
|
|
185
|
+
lines.push('};');
|
|
186
|
+
lines.push('');
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
lines.push(`&${adc.nodeLabel} {`);
|
|
190
|
+
lines.push(' status = "okay";');
|
|
191
|
+
lines.push('};');
|
|
192
|
+
lines.push('');
|
|
193
|
+
}
|
|
98
194
|
/**
|
|
99
195
|
* Emit a display DT node definition. The node is attached to the profile's SPI
|
|
100
196
|
* controller (default spi2, the ESP32's first user SPI controller) via a MIPI
|
|
@@ -177,6 +273,13 @@ function emitDisplayNode(lines, display, wiring, spiTouchCs) {
|
|
|
177
273
|
lines.push(` ${display.dtLabel}: display@0 {`);
|
|
178
274
|
lines.push(` compatible = "${compatible}";`);
|
|
179
275
|
lines.push(' reg = <0>;');
|
|
276
|
+
if (wiring?.tearingEffectPin !== undefined) {
|
|
277
|
+
const tePin = wiring.tearingEffectPin;
|
|
278
|
+
// Tearing-effect input on the display node: GPIO_DT_SPEC_GET(
|
|
279
|
+
// DT_NODELABEL(display0), te_gpios) in the adapter. Opt-in —
|
|
280
|
+
// most modules don't break the TE pad out.
|
|
281
|
+
lines.push(` te-gpios = <&${gpioController(tePin)} ${tePin} GPIO_ACTIVE_HIGH>;`);
|
|
282
|
+
}
|
|
180
283
|
lines.push(` mipi-max-frequency = <${freq}>;`);
|
|
181
284
|
lines.push(' mipi-mode = "MIPI_DBI_MODE_SPI_4WIRE";');
|
|
182
285
|
// Required by the lcd-controller binding (Zephyr 4.x): 0 = RGB565,
|
|
@@ -1,41 +1,31 @@
|
|
|
1
1
|
declare const _default: {
|
|
2
|
-
hal: {
|
|
3
|
-
[x: string]: {
|
|
4
|
-
supported: boolean;
|
|
5
|
-
ops: Record<string, "stub" | "polyfill" | "supported" | "unsupported" | "probe-inconclusive">;
|
|
6
|
-
partialCoverage: boolean;
|
|
7
|
-
unsupportedReason?: string | undefined;
|
|
8
|
-
};
|
|
9
|
-
raw?: unknown;
|
|
10
|
-
} & {
|
|
11
|
-
[k: string]: {
|
|
12
|
-
supported: boolean;
|
|
13
|
-
ops: Record<string, "stub" | "polyfill" | "supported" | "unsupported" | "probe-inconclusive">;
|
|
14
|
-
partialCoverage: boolean;
|
|
15
|
-
unsupportedReason?: string | undefined;
|
|
16
|
-
};
|
|
17
|
-
};
|
|
18
|
-
packageName: string;
|
|
19
2
|
schemaVersion: 1;
|
|
20
3
|
frameworkId: string;
|
|
4
|
+
packageName: string;
|
|
21
5
|
canonical: boolean;
|
|
22
6
|
displayName: string;
|
|
23
7
|
description: string;
|
|
24
8
|
implementationMode: "from-scratch" | "extends-canonical" | "extends-other";
|
|
25
9
|
entrypoint: {
|
|
26
|
-
sourceExtension: "cpp" | "ino" | "cc" | "h";
|
|
27
10
|
entrypointFunctionName: string;
|
|
28
11
|
requiresLoopFunction: boolean;
|
|
12
|
+
sourceExtension: "cpp" | "ino" | "cc" | "h";
|
|
29
13
|
generateHeaderFile: boolean;
|
|
30
14
|
overrideBaseName?: string | undefined;
|
|
31
15
|
outputSubdirectory?: string | undefined;
|
|
32
16
|
customBridgeShim?: string | undefined;
|
|
33
17
|
};
|
|
34
18
|
profile: {
|
|
19
|
+
targets: string[];
|
|
35
20
|
forcedIncludes: string[];
|
|
36
21
|
symbolAliases: Record<string, string>;
|
|
37
|
-
targets: string[];
|
|
38
22
|
};
|
|
23
|
+
hal: Record<string, {
|
|
24
|
+
supported: boolean;
|
|
25
|
+
ops: Record<string, "unsupported" | "supported" | "polyfill" | "probe-inconclusive" | "stub">;
|
|
26
|
+
partialCoverage: boolean;
|
|
27
|
+
unsupportedReason?: string | undefined;
|
|
28
|
+
}>;
|
|
39
29
|
polyfills: {
|
|
40
30
|
emitted: {
|
|
41
31
|
id: string;
|
|
@@ -59,20 +49,20 @@ declare const _default: {
|
|
|
59
49
|
reexportedFrom?: string | undefined;
|
|
60
50
|
};
|
|
61
51
|
typeEmission: {
|
|
62
|
-
|
|
52
|
+
normalizeCppType: boolean;
|
|
53
|
+
mathHeader: "<math.h>" | "none" | "<Arduino.h>";
|
|
63
54
|
needsStdString: boolean;
|
|
64
55
|
needsStdVector: boolean;
|
|
56
|
+
needsIostream: boolean;
|
|
65
57
|
needsStdFunction: boolean;
|
|
66
|
-
mathHeader: "none" | "<math.h>" | "<Arduino.h>";
|
|
67
|
-
normalizeCppType: boolean;
|
|
68
58
|
stdlibSupport: {
|
|
69
59
|
hasVector: boolean;
|
|
70
60
|
hasString: boolean;
|
|
71
61
|
hasIostream: boolean;
|
|
72
62
|
hasExceptions: boolean;
|
|
73
63
|
hasRTTI: boolean;
|
|
74
|
-
recommendedArrayImpl: "
|
|
75
|
-
recommendedStringImpl: "
|
|
64
|
+
recommendedArrayImpl: "static_array" | "std_vector";
|
|
65
|
+
recommendedStringImpl: "static_string" | "std_string";
|
|
76
66
|
};
|
|
77
67
|
};
|
|
78
68
|
ambientTypes: string[];
|
|
@@ -80,12 +70,6 @@ declare const _default: {
|
|
|
80
70
|
hardwareTestGroups: string[];
|
|
81
71
|
halResolutionTests: string[];
|
|
82
72
|
};
|
|
83
|
-
doctor?: {
|
|
84
|
-
available: boolean;
|
|
85
|
-
} | undefined;
|
|
86
|
-
licenses?: {
|
|
87
|
-
available: boolean;
|
|
88
|
-
} | undefined;
|
|
89
73
|
basedOn?: string | undefined;
|
|
90
74
|
inheritsStrategyId?: string | undefined;
|
|
91
75
|
libraryResolution?: {
|
|
@@ -95,6 +79,12 @@ declare const _default: {
|
|
|
95
79
|
tryGenerateLibDecl: boolean;
|
|
96
80
|
reexportedFrom?: string | undefined;
|
|
97
81
|
} | undefined;
|
|
82
|
+
doctor?: {
|
|
83
|
+
available: boolean;
|
|
84
|
+
} | undefined;
|
|
85
|
+
licenses?: {
|
|
86
|
+
available: boolean;
|
|
87
|
+
} | undefined;
|
|
98
88
|
compat?: {
|
|
99
89
|
zephyr?: string | undefined;
|
|
100
90
|
} | undefined;
|
|
@@ -45,8 +45,16 @@ export default defineFrameworkManifest({
|
|
|
45
45
|
profile: {
|
|
46
46
|
// Informational list of supported board targets. The manifest validator
|
|
47
47
|
// never iterates this; chipForTarget (src/chips/index.ts) is the real
|
|
48
|
-
// resolver. ESP32-S3 + plain ESP32 added alongside the nRF52840 MVP target
|
|
49
|
-
|
|
48
|
+
// resolver. ESP32-S3 + plain ESP32 added alongside the nRF52840 MVP target;
|
|
49
|
+
// rpi_pico / rpi_pico2 / esp32c3 / esp32c6 / blackpill_f411ce resolve via
|
|
50
|
+
// the board packages' zephyr chip data (resolveChipFromBoard), not the
|
|
51
|
+
// hardcoded chip registry.
|
|
52
|
+
targets: [
|
|
53
|
+
'xiao_ble', 'esp32s3_devkitc', 'esp32_devkitc',
|
|
54
|
+
'rpi_pico', 'rpi_pico2/rp2350a/m33',
|
|
55
|
+
'esp32c3_devkitm/esp32c3', 'esp32c6_devkitc/esp32c6/hpcore',
|
|
56
|
+
'blackpill_f411ce/stm32f411xe',
|
|
57
|
+
],
|
|
50
58
|
forcedIncludes: ['<zephyr/kernel.h>', '<zephyr/drivers/gpio.h>', '<cstdint>'],
|
|
51
59
|
symbolAliases: {},
|
|
52
60
|
},
|
|
@@ -204,7 +212,8 @@ export default defineFrameworkManifest({
|
|
|
204
212
|
},
|
|
205
213
|
},
|
|
206
214
|
// ── Partial: WiFi (STA connect + scan + config via conn_mgr/net_mgmt) ────
|
|
207
|
-
// ESP32
|
|
215
|
+
// ESP32 family only (esp32, esp32s3, esp32c3, esp32c6) — profileDiagnostics
|
|
216
|
+
// flags wifi usage on radioless chips (nRF52840, RP2040/RP2350).
|
|
208
217
|
// AP mode, credential persistence, static IP, and event callbacks deferred.
|
|
209
218
|
wifi: {
|
|
210
219
|
supported: true,
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { ZephyrStrategy as FrameworkStrategy } from './strategy.js';
|
|
2
2
|
export { ZephyrStrategy } from './strategy.js';
|
|
3
3
|
export { Toolchain } from './toolchain/index.js';
|
|
4
|
+
export { writeProjectDebugArtifacts } from './toolchain/debug-config.js';
|
|
4
5
|
export { runDoctor as doctor } from './doctor.js';
|
|
5
6
|
export { runLicensesPresenter as licenses } from './licenses.js';
|
|
6
7
|
export { chipForTarget, setActiveChip, getActiveChip, XIAO_BLE, } from './chips/index.js';
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,11 @@
|
|
|
8
8
|
export { ZephyrStrategy as FrameworkStrategy } from './strategy.js';
|
|
9
9
|
export { ZephyrStrategy } from './strategy.js';
|
|
10
10
|
export { Toolchain } from './toolchain/index.js';
|
|
11
|
+
// Create-time starter debug artifacts. The `cuttlefish create` flow reads this
|
|
12
|
+
// optional named export off the loaded framework module (same loader pattern
|
|
13
|
+
// as doctor/licenses) and calls it for freshly scaffolded projects, so F5 in
|
|
14
|
+
// VS Code works before the first build. No-ops for non-GDB targets.
|
|
15
|
+
export { writeProjectDebugArtifacts } from './toolchain/debug-config.js';
|
|
11
16
|
// `cuttlefish doctor` — verify the installed Zephyr is reachable + inside the
|
|
12
17
|
// declared compat range, and preview board-target normalization. Re-exported
|
|
13
18
|
// under the dispatcher-facing alias `doctor` so the loader picks it up as
|
package/dist/lowering/adc.d.ts
CHANGED
|
@@ -4,11 +4,14 @@ import type { ZephyrChipDescriptor } from '../chips/types.js';
|
|
|
4
4
|
export declare function adcChannelForPin(chip: ZephyrChipDescriptor, pin: number): number;
|
|
5
5
|
/**
|
|
6
6
|
* Emit the per-channel ADC setup state. One block per channel in the chip
|
|
7
|
-
* descriptor
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* descriptor that the PROGRAM ACTUALLY READS (`usedPins`) — an unread
|
|
8
|
+
* channel's `static` setup function would trip -Wunused-function in the
|
|
9
|
+
* single generated TU. When `usedPins` is omitted (probe paths with no
|
|
10
|
+
* program), every descriptor channel is emitted. Each block is guarded by a
|
|
11
|
+
* `static bool __tc_adc<N>_ready` so the first read configures it and
|
|
12
|
+
* subsequent reads skip. Called from shimLines when the program uses ADC.
|
|
10
13
|
*/
|
|
11
|
-
export declare function adcInitLines(chip: ZephyrChipDescriptor): string[];
|
|
14
|
+
export declare function adcInitLines(chip: ZephyrChipDescriptor, usedPins?: ReadonlySet<number>): string[];
|
|
12
15
|
/**
|
|
13
16
|
* Resolve a HAL adc.* op to Zephyr C++.
|
|
14
17
|
* Returns `{ code }` for statement ops, `{ expression }` for value-returning ops.
|
package/dist/lowering/adc.js
CHANGED
|
@@ -18,19 +18,30 @@ export function adcChannelForPin(chip, pin) {
|
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
20
|
* Emit the per-channel ADC setup state. One block per channel in the chip
|
|
21
|
-
* descriptor
|
|
22
|
-
*
|
|
23
|
-
*
|
|
21
|
+
* descriptor that the PROGRAM ACTUALLY READS (`usedPins`) — an unread
|
|
22
|
+
* channel's `static` setup function would trip -Wunused-function in the
|
|
23
|
+
* single generated TU. When `usedPins` is omitted (probe paths with no
|
|
24
|
+
* program), every descriptor channel is emitted. Each block is guarded by a
|
|
25
|
+
* `static bool __tc_adc<N>_ready` so the first read configures it and
|
|
26
|
+
* subsequent reads skip. Called from shimLines when the program uses ADC.
|
|
24
27
|
*/
|
|
25
|
-
export function adcInitLines(chip) {
|
|
28
|
+
export function adcInitLines(chip, usedPins) {
|
|
26
29
|
const dev = `DEVICE_DT_GET(DT_NODELABEL(${chip.adc?.nodeLabel ?? 'adc'}))`;
|
|
27
30
|
const res = chip.adc?.resolution ?? 12;
|
|
28
31
|
const vref = chip.adc?.vrefMv ?? 3000;
|
|
32
|
+
// Gain/reference are SoC-specific: the nRF SAADC scheme (gain 1/4 against
|
|
33
|
+
// the 0.6V internal ref, vref-mv 3000 = VDD) is the default; the STM32
|
|
34
|
+
// driver requires exactly ADC_GAIN_1 + ADC_REF_INTERNAL (Zephyr maps
|
|
35
|
+
// "internal" to the VREF+ pad) with vref-mv = VDDA. The descriptor carries
|
|
36
|
+
// the SoC's pair so the emitted channel setup validates in the driver.
|
|
37
|
+
const gain = chip.adc?.gain ?? 'ADC_GAIN_1_4';
|
|
38
|
+
const reference = chip.adc?.reference ?? 'ADC_REF_INTERNAL';
|
|
39
|
+
const channels = (chip.adc?.channels ?? []).filter((c) => !usedPins || usedPins.has(c.pin));
|
|
29
40
|
const lines = ['// CUTTLEFISH_ADC_BEGIN'];
|
|
30
41
|
lines.push(`static const struct device* __tc_adc_dev = ${dev};`);
|
|
31
|
-
for (const c of
|
|
42
|
+
for (const c of channels) {
|
|
32
43
|
const n = c.channel;
|
|
33
|
-
lines.push(`static bool __tc_adc${n}_ready = false;`, `static void __tc_adc${n}_setup(void) {`, ` if (__tc_adc${n}_ready) return;`, ` const struct adc_channel_cfg cfg = {`, ` .gain =
|
|
44
|
+
lines.push(`static bool __tc_adc${n}_ready = false;`, `static void __tc_adc${n}_setup(void) {`, ` if (__tc_adc${n}_ready) return;`, ` const struct adc_channel_cfg cfg = {`, ` .gain = ${gain},`, ` .reference = ${reference},`, ` .acquisition_time = ADC_ACQ_TIME_DEFAULT,`, ` .channel_id = ${n},`, ` .differential = 0,`, ` };`, ` adc_channel_setup(__tc_adc_dev, &cfg);`, ` __tc_adc${n}_ready = true;`, `}`);
|
|
34
45
|
}
|
|
35
46
|
lines.push(`#define __TC_ADC_VREF_MV ${vref}`);
|
|
36
47
|
lines.push(`#define __TC_ADC_RESOLUTION ${res}`);
|
|
@@ -45,6 +56,8 @@ export function lowerAdc(op, chip) {
|
|
|
45
56
|
const o = op;
|
|
46
57
|
const res = chip.adc?.resolution ?? 12;
|
|
47
58
|
const vref = chip.adc?.vrefMv ?? 3000;
|
|
59
|
+
const gain = chip.adc?.gain ?? 'ADC_GAIN_1_4';
|
|
60
|
+
const reference = chip.adc?.reference ?? 'ADC_REF_INTERNAL';
|
|
48
61
|
switch (op.operation) {
|
|
49
62
|
case 'adc.read': {
|
|
50
63
|
const ch = adcChannelForPin(chip, o.pin);
|
|
@@ -55,10 +68,11 @@ export function lowerAdc(op, chip) {
|
|
|
55
68
|
}
|
|
56
69
|
case 'adc.read_voltage': {
|
|
57
70
|
const ch = adcChannelForPin(chip, o.pin);
|
|
58
|
-
// Read raw, convert to millivolts via adc_raw_to_millivolts
|
|
59
|
-
//
|
|
71
|
+
// Read raw, convert to millivolts via adc_raw_to_millivolts with the
|
|
72
|
+
// descriptor's gain (raw_to_millivolts divides out the gain the channel
|
|
73
|
+
// was set up with). Returns mV as int.
|
|
60
74
|
return {
|
|
61
|
-
expression: `({ __tc_adc${ch}_setup(); int16_t __b = 0; struct adc_sequence __s = { .channels = BIT(${ch}), .buffer = &__b, .buffer_size = sizeof(__b), .resolution = ${res} }; adc_read(__tc_adc_dev, &__s); int32_t __v = __b; adc_raw_to_millivolts(${vref},
|
|
75
|
+
expression: `({ __tc_adc${ch}_setup(); int16_t __b = 0; struct adc_sequence __s = { .channels = BIT(${ch}), .buffer = &__b, .buffer_size = sizeof(__b), .resolution = ${res} }; adc_read(__tc_adc_dev, &__s); int32_t __v = __b; adc_raw_to_millivolts(${vref}, ${gain}, ${res}, &__v); __v; })`,
|
|
62
76
|
};
|
|
63
77
|
}
|
|
64
78
|
case 'adc.get_resolution':
|
|
@@ -66,9 +80,9 @@ export function lowerAdc(op, chip) {
|
|
|
66
80
|
case 'adc.set_reference':
|
|
67
81
|
// Zephyr configures the reference at channel-setup time; runtime switching
|
|
68
82
|
// would require re-setup. Record the intent as a no-op statement.
|
|
69
|
-
return { code: `/* adc.set_reference(${o.reference}): configured at channel setup (
|
|
83
|
+
return { code: `/* adc.set_reference(${o.reference}): configured at channel setup (${reference}) */` };
|
|
70
84
|
case 'adc.get_reference':
|
|
71
|
-
return { expression: `0 /* DEFAULT (
|
|
85
|
+
return { expression: `0 /* DEFAULT (${reference}) */` };
|
|
72
86
|
default:
|
|
73
87
|
throw new Error(`framework-zephyr does not yet support HAL op \`${op.operation}\`. ` +
|
|
74
88
|
`Open an issue or use rawCpp() to emit it manually.`);
|
package/dist/lowering/gpio.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
// The manifest validator's probe (which sends {operation, pin:0} with no
|
|
15
15
|
// port) hits this path, so it must return a lowered result, not undefined.
|
|
16
16
|
// ---------------------------------------------------------------------------
|
|
17
|
-
import { controllerNodelabelForPin } from '../chips/controllers.js';
|
|
17
|
+
import { controllerNodelabelForPin, controllerRawPinForPin } from '../chips/controllers.js';
|
|
18
18
|
/** The C identifier emitted for a pin's gpio_dt_spec variable. */
|
|
19
19
|
export function dtSpecVarName(dtSpec) {
|
|
20
20
|
return `__tc_dt_${dtSpec}`;
|
|
@@ -99,23 +99,30 @@ function lowerGpioRaw(op, chip) {
|
|
|
99
99
|
const o = op;
|
|
100
100
|
const pin = o.pin;
|
|
101
101
|
// Resolve the owning controller by pin range (ESP32-S3 splits GPIO across
|
|
102
|
-
// gpio0/gpio1). For single-controller SoCs
|
|
102
|
+
// gpio0/gpio1; STM32 across gpioa/gpiob/gpioc). For single-controller SoCs
|
|
103
|
+
// this is just chip.gpioController. The raw API takes the PORT-RELATIVE
|
|
104
|
+
// index (STM32 gpiob is 0-15), not the global HAL pin number.
|
|
103
105
|
const controller = `DEVICE_DT_GET(DT_NODELABEL(${controllerNodelabelForPin(chip, pin)}))`;
|
|
106
|
+
const rawPin = controllerRawPinForPin(chip, pin);
|
|
104
107
|
switch (op.operation) {
|
|
105
108
|
case 'gpio.set_mode': {
|
|
106
|
-
return { code: `gpio_pin_configure(${controller}, ${
|
|
109
|
+
return { code: `gpio_pin_configure(${controller}, ${rawPin}, ${flagsForMode(o.mode)});` };
|
|
107
110
|
}
|
|
108
111
|
case 'gpio.write': {
|
|
109
112
|
const v = o.value;
|
|
110
113
|
const rhs = typeof v === 'string' ? `((${v}) ? 1 : 0)` : v ? 1 : 0;
|
|
111
|
-
return { code: `gpio_pin_set_raw(${controller}, ${
|
|
114
|
+
return { code: `gpio_pin_set_raw(${controller}, ${rawPin}, ${rhs});` };
|
|
112
115
|
}
|
|
113
116
|
case 'gpio.read':
|
|
114
|
-
return { expression: `gpio_pin_get_raw(${controller}, ${
|
|
117
|
+
return { expression: `gpio_pin_get_raw(${controller}, ${rawPin})` };
|
|
115
118
|
case 'gpio.toggle':
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
+
// Native atomic toggle — never read-modify-write. gpio_pin_get_raw on
|
|
120
|
+
// a direction-only output reads the input latch, which is undefined on
|
|
121
|
+
// SoCs that don't latch it. Zephyr's toggle API has no _raw variant —
|
|
122
|
+
// gpio_pin_toggle is the driver-level atomic toggle, and for pins
|
|
123
|
+
// configured without GPIO_ACTIVE_LOW the logical level equals the
|
|
124
|
+
// physical one, so it matches the get_raw/set_raw used elsewhere.
|
|
125
|
+
return { code: `gpio_pin_toggle(${controller}, ${rawPin});` };
|
|
119
126
|
default:
|
|
120
127
|
throw new Error(`framework-zephyr does not yet support HAL op \`${op.operation}\`. ` +
|
|
121
128
|
`Open an issue or use rawCpp() to emit it manually.`);
|
package/dist/lowering/mqtt.js
CHANGED
|
@@ -290,7 +290,15 @@ export function mqttInitLines() {
|
|
|
290
290
|
` (void)k_thread_create(&__tc_mqtt.poll_thread, __tc_mqtt_stack,`,
|
|
291
291
|
` K_THREAD_STACK_SIZEOF(__tc_mqtt_stack),`,
|
|
292
292
|
` __tc_mqtt_poll_thread, nullptr, nullptr, nullptr,`,
|
|
293
|
-
` 5, 0,
|
|
293
|
+
` 5, 0, K_FOREVER);`,
|
|
294
|
+
`#ifdef CONFIG_SMP`,
|
|
295
|
+
` // On SMP targets park the poll thread on the app core so the network`,
|
|
296
|
+
` // stack never competes with the main/UI thread for core 0. k_thread_cpu_pin`,
|
|
297
|
+
` // is SMP-only; the pin happens before k_thread_start (which is why the`,
|
|
298
|
+
` // thread is created K_FOREVER). Compiles away on !SMP builds.`,
|
|
299
|
+
` (void)k_thread_cpu_pin(&__tc_mqtt.poll_thread, 1);`,
|
|
300
|
+
`#endif`,
|
|
301
|
+
` k_thread_start(&__tc_mqtt.poll_thread);`,
|
|
294
302
|
`}`,
|
|
295
303
|
``,
|
|
296
304
|
`static inline void __tc_mqtt_set_on_message(__tc_mqtt_msg_cb_t fn) {`,
|
package/dist/lowering/pulse.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// implementations (no hardware pulse capture on nRF for the HAL surface); they
|
|
8
8
|
// are correct but not high-precision.
|
|
9
9
|
// ---------------------------------------------------------------------------
|
|
10
|
-
import { controllerNodelabelForPin } from '../chips/controllers.js';
|
|
10
|
+
import { controllerNodelabelForPin, controllerRawPinForPin } from '../chips/controllers.js';
|
|
11
11
|
/** `DEVICE_DT_GET(DT_NODELABEL(<owning-controller>))` for a HAL pin. */
|
|
12
12
|
function devForPin(chip, pin) {
|
|
13
13
|
return `DEVICE_DT_GET(DT_NODELABEL(${controllerNodelabelForPin(chip, pin)}))`;
|
|
@@ -23,9 +23,9 @@ export function lowerPulseOrShift(op, chip) {
|
|
|
23
23
|
// for the start edge is bounded by the timeout; the measurement of the
|
|
24
24
|
// pulse itself is intentionally unbounded (that IS the pulse length).
|
|
25
25
|
// Returns -1 (0) if the start edge never arrives within the timeout.
|
|
26
|
-
const pin = o.pin;
|
|
26
|
+
const pin = controllerRawPinForPin(chip, o.pin);
|
|
27
27
|
const want = o.value;
|
|
28
|
-
const dev = devForPin(chip, pin);
|
|
28
|
+
const dev = devForPin(chip, o.pin);
|
|
29
29
|
const timeout = o.timeout ?? 1_000_000; // default 1s in us
|
|
30
30
|
return {
|
|
31
31
|
expression: `({ int64_t __max = static_cast<int64_t>(${timeout} / 1000); int64_t __t0 = k_uptime_get(); bool __ok = true; while (gpio_pin_get_raw(${dev}, ${pin}) != ${want}) { if ((k_uptime_get() - __t0) > __max) { __ok = false; break; } } int32_t __ret = 0; if (__ok) { int64_t __start = k_uptime_get(); while (gpio_pin_get_raw(${dev}, ${pin}) == ${want}) { } __ret = static_cast<int32_t>((k_uptime_get() - __start) * 1000); } __ret; })`,
|
|
@@ -36,9 +36,9 @@ export function lowerPulseOrShift(op, chip) {
|
|
|
36
36
|
// with NO timeout (the comment claimed "no overflow concern" but the
|
|
37
37
|
// real risk was hanging the thread on a stuck pin). Apply the same
|
|
38
38
|
// timeout-bounded start-edge wait as pulse.in (bug Q5).
|
|
39
|
-
const pin = o.pin;
|
|
39
|
+
const pin = controllerRawPinForPin(chip, o.pin);
|
|
40
40
|
const want = o.value;
|
|
41
|
-
const dev = devForPin(chip, pin);
|
|
41
|
+
const dev = devForPin(chip, o.pin);
|
|
42
42
|
const timeout = o.timeout ?? 3_000_000; // default 3s in us (long pulses)
|
|
43
43
|
return {
|
|
44
44
|
expression: `({ int64_t __max = static_cast<int64_t>(${timeout} / 1000); int64_t __t0 = k_uptime_get(); bool __ok = true; while (gpio_pin_get_raw(${dev}, ${pin}) != ${want}) { if ((k_uptime_get() - __t0) > __max) { __ok = false; break; } } int32_t __ret = 0; if (__ok) { int64_t __start = k_uptime_get(); while (gpio_pin_get_raw(${dev}, ${pin}) == ${want}) { } __ret = static_cast<int32_t>((k_uptime_get() - __start) * 1000); } __ret; })`,
|
|
@@ -57,7 +57,7 @@ export function lowerPulseOrShift(op, chip) {
|
|
|
57
57
|
const test = msbFirst ? '(__i >= 0)' : '(__i < 8)';
|
|
58
58
|
const step = msbFirst ? '__i--' : '__i++';
|
|
59
59
|
return {
|
|
60
|
-
code: `for (int __i = ${init}; ${test}; ${step}) { gpio_pin_set_raw(${dataDev}, ${dataPin}, (${o.value} >> __i) & 1); gpio_pin_set_raw(${clockDev}, ${clockPin}, 1); k_busy_wait(1); gpio_pin_set_raw(${clockDev}, ${clockPin}, 0); }`,
|
|
60
|
+
code: `for (int __i = ${init}; ${test}; ${step}) { gpio_pin_set_raw(${dataDev}, ${controllerRawPinForPin(chip, dataPin)}, (${o.value} >> __i) & 1); gpio_pin_set_raw(${clockDev}, ${controllerRawPinForPin(chip, clockPin)}, 1); k_busy_wait(1); gpio_pin_set_raw(${clockDev}, ${controllerRawPinForPin(chip, clockPin)}, 0); }`,
|
|
61
61
|
};
|
|
62
62
|
}
|
|
63
63
|
case 'shift.in': {
|
|
@@ -72,7 +72,7 @@ export function lowerPulseOrShift(op, chip) {
|
|
|
72
72
|
const step = msbFirst ? '__i--' : '__i++';
|
|
73
73
|
const accum = msbFirst ? '__v = (__v << 1)' : '__v |= (bit << __i)';
|
|
74
74
|
return {
|
|
75
|
-
expression: `({ uint8_t __v = 0; for (int __i = ${init}; ${test}; ${step}) { gpio_pin_set_raw(${clockDev}, ${clockPin}, 1); k_busy_wait(1); int bit = gpio_pin_get_raw(${dataDev}, ${dataPin}); gpio_pin_set_raw(${clockDev}, ${clockPin}, 0); ${accum}; } __v; })`,
|
|
75
|
+
expression: `({ uint8_t __v = 0; for (int __i = ${init}; ${test}; ${step}) { gpio_pin_set_raw(${clockDev}, ${controllerRawPinForPin(chip, clockPin)}, 1); k_busy_wait(1); int bit = gpio_pin_get_raw(${dataDev}, ${controllerRawPinForPin(chip, dataPin)}); gpio_pin_set_raw(${clockDev}, ${controllerRawPinForPin(chip, clockPin)}, 0); ${accum}; } __v; })`,
|
|
76
76
|
};
|
|
77
77
|
}
|
|
78
78
|
default:
|
package/dist/lowering/pwm.d.ts
CHANGED
|
@@ -1,10 +1,28 @@
|
|
|
1
1
|
import type { HALOpIR } from '@typecad/cuttlefish/api/shared';
|
|
2
|
-
import type { ZephyrChipDescriptor } from '../chips/types.js';
|
|
2
|
+
import type { ZephyrChipDescriptor, ZephyrPwmSpec } from '../chips/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* The DT alias a PWM spec is addressed by. Board-shipped specs carry their
|
|
5
|
+
* alias in `dtSpec`; synthesized specs (controller + channel) get a
|
|
6
|
+
* `tc-pwm<pin>` alias that the overlay generator creates in
|
|
7
|
+
* <board>.overlay — both sides derive the name from the pin so they agree.
|
|
8
|
+
*/
|
|
9
|
+
export declare function pwmDtAlias(spec: ZephyrPwmSpec): string;
|
|
10
|
+
/**
|
|
11
|
+
* The C macro token for a spec's alias. Zephyr's devicetree macros replace
|
|
12
|
+
* dashes in alias names with underscores (`pwm-led0` in DTS is
|
|
13
|
+
* DT_ALIAS(pwm_led0) in C) — the dashed spelling is a subtraction
|
|
14
|
+
* expression and fails to compile (caught by the blackpill E2E west build).
|
|
15
|
+
*/
|
|
16
|
+
export declare function pwmDtAliasToken(spec: ZephyrPwmSpec): string;
|
|
3
17
|
/**
|
|
4
18
|
* Emit the per-channel PWM spec declarations. One per spec in the chip
|
|
5
|
-
* descriptor
|
|
19
|
+
* descriptor that the PROGRAM ACTUALLY DRIVES (`usedPins`) — a spec for an
|
|
20
|
+
* untouched pin is unused code in the emitted TU (and would need a dead DT
|
|
21
|
+
* alias in the overlay). When `usedPins` is omitted (probe paths with no
|
|
22
|
+
* program), every spec is emitted. Called from shimLines when the program
|
|
23
|
+
* uses PWM.
|
|
6
24
|
*/
|
|
7
|
-
export declare function pwmInitLines(chip: ZephyrChipDescriptor): string[];
|
|
25
|
+
export declare function pwmInitLines(chip: ZephyrChipDescriptor, usedPins?: ReadonlySet<number>): string[];
|
|
8
26
|
/**
|
|
9
27
|
* Resolve a HAL pwm.* op to Zephyr C++.
|
|
10
28
|
* Returns `{ code }` for statement ops, `{ expression }` for value-returning ops.
|
package/dist/lowering/pwm.js
CHANGED
|
@@ -6,22 +6,46 @@
|
|
|
6
6
|
// `pwm_set_pulse_dt` / `pwm_set_dt`. Duty is scaled from the Arduino-style
|
|
7
7
|
// 0–255 (or 0–1023) range to nanoseconds against the spec's period.
|
|
8
8
|
// ---------------------------------------------------------------------------
|
|
9
|
+
/**
|
|
10
|
+
* The DT alias a PWM spec is addressed by. Board-shipped specs carry their
|
|
11
|
+
* alias in `dtSpec`; synthesized specs (controller + channel) get a
|
|
12
|
+
* `tc-pwm<pin>` alias that the overlay generator creates in
|
|
13
|
+
* <board>.overlay — both sides derive the name from the pin so they agree.
|
|
14
|
+
*/
|
|
15
|
+
export function pwmDtAlias(spec) {
|
|
16
|
+
return spec.dtSpec ?? `tc-pwm${spec.pin}`;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The C macro token for a spec's alias. Zephyr's devicetree macros replace
|
|
20
|
+
* dashes in alias names with underscores (`pwm-led0` in DTS is
|
|
21
|
+
* DT_ALIAS(pwm_led0) in C) — the dashed spelling is a subtraction
|
|
22
|
+
* expression and fails to compile (caught by the blackpill E2E west build).
|
|
23
|
+
*/
|
|
24
|
+
export function pwmDtAliasToken(spec) {
|
|
25
|
+
return pwmDtAlias(spec).replace(/-/g, '_');
|
|
26
|
+
}
|
|
9
27
|
/** Look up a PWM spec by HAL pin number. */
|
|
10
28
|
function findPwmSpec(chip, pin) {
|
|
11
29
|
return chip.pwm?.specs.find((s) => s.pin === pin);
|
|
12
30
|
}
|
|
13
31
|
/** The C variable name emitted for a PWM channel's spec. */
|
|
14
32
|
function pwmVarName(spec) {
|
|
15
|
-
return `__tc_pwm_${spec
|
|
33
|
+
return `__tc_pwm_${pwmDtAliasToken(spec)}`;
|
|
16
34
|
}
|
|
17
35
|
/**
|
|
18
36
|
* Emit the per-channel PWM spec declarations. One per spec in the chip
|
|
19
|
-
* descriptor
|
|
37
|
+
* descriptor that the PROGRAM ACTUALLY DRIVES (`usedPins`) — a spec for an
|
|
38
|
+
* untouched pin is unused code in the emitted TU (and would need a dead DT
|
|
39
|
+
* alias in the overlay). When `usedPins` is omitted (probe paths with no
|
|
40
|
+
* program), every spec is emitted. Called from shimLines when the program
|
|
41
|
+
* uses PWM.
|
|
20
42
|
*/
|
|
21
|
-
export function pwmInitLines(chip) {
|
|
43
|
+
export function pwmInitLines(chip, usedPins) {
|
|
22
44
|
const lines = ['// CUTTLEFISH_PWM_BEGIN'];
|
|
23
45
|
for (const spec of chip.pwm?.specs ?? []) {
|
|
24
|
-
|
|
46
|
+
if (usedPins && !usedPins.has(spec.pin))
|
|
47
|
+
continue;
|
|
48
|
+
lines.push(`static const struct pwm_dt_spec ${pwmVarName(spec)} = PWM_DT_SPEC_GET(DT_ALIAS(${pwmDtAliasToken(spec)}));`);
|
|
25
49
|
}
|
|
26
50
|
lines.push('// CUTTLEFISH_PWM_END');
|
|
27
51
|
return lines;
|
package/dist/lowering/spi.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// DEVICE_DT_GET(DT_NODELABEL(spi2)) and call spi_transceive directly.
|
|
13
13
|
// ---------------------------------------------------------------------------
|
|
14
14
|
import { parseControllerIndex } from './util.js';
|
|
15
|
-
import { controllerNodelabelForPin } from '../chips/controllers.js';
|
|
15
|
+
import { controllerNodelabelForPin, controllerRawPinForPin } from '../chips/controllers.js';
|
|
16
16
|
/** The C variable prefix for a controller's state. */
|
|
17
17
|
function prefix(idx) {
|
|
18
18
|
return `__tc_spi${idx}`;
|
|
@@ -103,7 +103,7 @@ export function lowerSpi(op, chip) {
|
|
|
103
103
|
const val = op.operation === 'spi.cs_low' ? 0 : 1;
|
|
104
104
|
const gpioController = controllerNodelabelForPin(chip, o.pin);
|
|
105
105
|
return {
|
|
106
|
-
code: `gpio_pin_set_raw(DEVICE_DT_GET(DT_NODELABEL(${gpioController})), ${o.pin}, ${val});`,
|
|
106
|
+
code: `gpio_pin_set_raw(DEVICE_DT_GET(DT_NODELABEL(${gpioController})), ${controllerRawPinForPin(chip, o.pin)}, ${val});`,
|
|
107
107
|
};
|
|
108
108
|
}
|
|
109
109
|
default:
|
package/dist/lowering/tone.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
// matching the synchronous Arduino tone() semantics. For non-blocking tone,
|
|
12
12
|
// a workqueue would be needed (deferred).
|
|
13
13
|
// ---------------------------------------------------------------------------
|
|
14
|
+
import { pwmDtAliasToken } from './pwm.js';
|
|
14
15
|
/**
|
|
15
16
|
* Resolve a HAL tone.* op to Zephyr C++ via PWM.
|
|
16
17
|
* Returns `{ code }` for statement ops, `{ expression }` for value-returning ops.
|
|
@@ -26,7 +27,7 @@ export function lowerTone(op, chip) {
|
|
|
26
27
|
if (!spec) {
|
|
27
28
|
return { code: `/* tone.play(${o.frequency}): no PWM spec in chip descriptor */` };
|
|
28
29
|
}
|
|
29
|
-
const v = `__tc_pwm_${spec
|
|
30
|
+
const v = `__tc_pwm_${pwmDtAliasToken(spec)}`;
|
|
30
31
|
const freq = o.frequency;
|
|
31
32
|
const duration = o.duration;
|
|
32
33
|
const setTone = `uint32_t __period = (${freq} > 0) ? (1000000000ULL / static_cast<uint64_t>(${freq})) : 0; pwm_set_dt(&${v}, __period, __period / 2);`;
|
|
@@ -40,7 +41,7 @@ export function lowerTone(op, chip) {
|
|
|
40
41
|
const spec = chip.pwm?.specs[0];
|
|
41
42
|
if (!spec)
|
|
42
43
|
return { code: `/* tone.stop: no PWM spec */` };
|
|
43
|
-
const v = `__tc_pwm_${spec
|
|
44
|
+
const v = `__tc_pwm_${pwmDtAliasToken(spec)}`;
|
|
44
45
|
return { code: `pwm_set_pulse_dt(&${v}, 0);` };
|
|
45
46
|
}
|
|
46
47
|
default:
|