@typecad/mcu-atmega328p 0.1.0-alpha.1
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 +461 -0
- package/dist/arduino-map.d.ts +15 -0
- package/dist/arduino-map.js +37 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +31 -0
- package/dist/mcu.d.ts +3 -0
- package/dist/mcu.js +143 -0
- package/dist/peripherals.d.ts +104 -0
- package/dist/peripherals.js +180 -0
- package/dist/pins.d.ts +40 -0
- package/dist/pins.js +63 -0
- package/package.json +60 -0
- package/src/arduino-map.ts +42 -0
- package/src/index.ts +39 -0
- package/src/mcu.ts +164 -0
- package/src/peripherals.ts +216 -0
- package/src/pins.ts +74 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 typecad0
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
# @typecad/mcu-atmega328p
|
|
2
|
+
|
|
3
|
+
MCU definition package for the **ATmega328P** microcontroller. Provides datasheet-level pin definitions, hardware peripheral descriptions, and framework pin mappings used by the TypeCAD transpiler and board packages.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Purpose
|
|
8
|
+
|
|
9
|
+
MCU packages (`@typecad/mcu-*`) are the **hardware abstraction layer between the chip and the framework**. They answer three fundamental questions:
|
|
10
|
+
|
|
11
|
+
1. **What pins exist on this chip?** — Exports typed `Pin` objects using canonical port names from the MCU datasheet (e.g. `PD0`, `PB5`, `PC0`).
|
|
12
|
+
2. **What peripherals are built into the silicon?** — Describes the hardware peripherals the MCU provides: how many I2C/SPI/UART controllers, ADC channels, timers, PWM capabilities, etc.
|
|
13
|
+
3. **How do port names map to framework pin numbers?** — Provides lookup tables so the transpiler can resolve `Pin.fromPort('PB5')` → Arduino pin `13`.
|
|
14
|
+
|
|
15
|
+
MCU packages are **framework-agnostic**. They don't know about Arduino, PlatformIO, or any specific board — they only know the chip itself. Board packages (e.g. `@typecad/board-arduino-uno`) import from MCU packages and add board-specific aliases, wiring, and metadata.
|
|
16
|
+
|
|
17
|
+
### Package Layering
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
┌─────────────────────────────────────────────────┐
|
|
21
|
+
│ User sketch │
|
|
22
|
+
│ import { D13, LED, UART0 } from '@typecad/...' │
|
|
23
|
+
└──────────────────────┬──────────────────────────┘
|
|
24
|
+
│ imports from
|
|
25
|
+
┌──────────────────────▼──────────────────────────┐
|
|
26
|
+
│ Board package (board-arduino-uno) │
|
|
27
|
+
│ • Arduino pin aliases (D0–D13, A0–A5) │
|
|
28
|
+
│ • Convenience aliases (LED, SDA, SCL, TX, RX) │
|
|
29
|
+
│ • Peripheral instances (I2C0, SPI0, UART0) │
|
|
30
|
+
│ • BoardDefinition (board-level metadata) │
|
|
31
|
+
│ • Timing, interrupt, and utility functions │
|
|
32
|
+
└──────────────────────┬──────────────────────────┘
|
|
33
|
+
│ imports pins + peripherals from
|
|
34
|
+
┌──────────────────────▼──────────────────────────┐
|
|
35
|
+
│ MCU package (mcu-atmega328p) ◄── THIS PACKAGE│
|
|
36
|
+
│ • Datasheet pin definitions (PD0–PD7, etc.) │
|
|
37
|
+
│ • Hardware peripheral descriptions (I2C, SPI, │
|
|
38
|
+
│ UART, ADC, timers, PWM) │
|
|
39
|
+
│ • Framework pin mappings (ARDUINO_PIN_MAP) │
|
|
40
|
+
└──────────────────────┬──────────────────────────┘
|
|
41
|
+
│ depends on
|
|
42
|
+
┌──────────────────────▼──────────────────────────┐
|
|
43
|
+
│ Core / HAL / Schema │
|
|
44
|
+
│ Pin, Pin.fromPort(), type definitions │
|
|
45
|
+
└─────────────────────────────────────────────────┘
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## What's Inside
|
|
51
|
+
|
|
52
|
+
### `src/pins.ts` — Datasheet Pin Definitions
|
|
53
|
+
|
|
54
|
+
Exports one `Pin` constant per GPIO port on the ATmega328P, using [`Pin.fromPort()`](../hal/src/gpio.ts:201) with the canonical port name from the datasheet:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { Pin } from '@typecad/hal';
|
|
58
|
+
|
|
59
|
+
export const PD0 = Pin.fromPort('PD0'); // Port D, bit 0
|
|
60
|
+
export const PD1 = Pin.fromPort('PD1'); // Port D, bit 1
|
|
61
|
+
// ...
|
|
62
|
+
export const PB5 = Pin.fromPort('PB5'); // Port B, bit 5
|
|
63
|
+
export const PC0 = Pin.fromPort('PC0'); // Port C, bit 0
|
|
64
|
+
// ...
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Why `Pin.fromPort()` instead of `new Pin(number)`?**
|
|
68
|
+
|
|
69
|
+
- `Pin.fromPort('PB5')` stores the port name as the canonical identity. The transpiler resolves it to the correct framework pin number at compile time using the pin mapping.
|
|
70
|
+
- `new Pin(13)` hardcodes a framework-specific pin number, which breaks if the same chip is used with a different framework or board variant.
|
|
71
|
+
- Port names are universal — `PB5` means the same physical pin on every ATmega328P board, whether it's an Arduino Uno, a Pro Mini, or a bare DIP-28 on a breadboard.
|
|
72
|
+
|
|
73
|
+
### `src/arduino-map.ts` — Arduino Pin Mapping
|
|
74
|
+
|
|
75
|
+
Maps MCU port names to Arduino framework pin numbers:
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
export const ARDUINO_PIN_MAP: Readonly<Record<string, number>> = {
|
|
79
|
+
PD0: 0, PD1: 1, PD2: 2, PD3: 3,
|
|
80
|
+
PD4: 4, PD5: 5, PD6: 6, PD7: 7,
|
|
81
|
+
PB0: 8, PB1: 9, PB2: 10, PB3: 11,
|
|
82
|
+
PB4: 12, PB5: 13,
|
|
83
|
+
PC0: 14, PC1: 15, PC2: 16, PC3: 17,
|
|
84
|
+
PC4: 18, PC5: 19,
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export const ARDUINO_ANALOG_OFFSET = 14;
|
|
88
|
+
|
|
89
|
+
export const ARDUINO_PIN_REVERSE: Readonly<Record<number, string>> = { ... };
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
This mapping is **per-chip**, not per-board. An ATtiny85 has `A2 = PB4` while the ATmega328P has `A2 = PC2`. That's why it lives in the MCU package, not in the framework or board package.
|
|
93
|
+
|
|
94
|
+
### `src/index.ts` — Barrel Export
|
|
95
|
+
|
|
96
|
+
Re-exports everything from `pins.ts` and `arduino-map.ts`.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Hardware Peripherals
|
|
101
|
+
|
|
102
|
+
The ATmega328P has a fixed set of hardware peripherals baked into the silicon. These are properties of the **chip**, not the board — every ATmega328P has exactly the same peripheral count regardless of what board it's soldered to.
|
|
103
|
+
|
|
104
|
+
### ATmega328P Peripheral Summary
|
|
105
|
+
|
|
106
|
+
| Peripheral | Count | Details |
|
|
107
|
+
|---|---|---|
|
|
108
|
+
| **UART** | 1 | USART0 — full-duplex serial, TX/RX on PD1/PD0 |
|
|
109
|
+
| **I2C** (TWI) | 1 | Two-Wire Interface — SDA on PC4, SCL on PC5 |
|
|
110
|
+
| **SPI** | 1 | MOSI on PB3, MISO on PB4, SCK on PB5, SS on PB2 |
|
|
111
|
+
| **ADC** | 1 | 10-bit, 6 channels on PC0–PC5 (plus temperature + VBG) |
|
|
112
|
+
| **Timers** | 3 | Timer0 (8-bit, system), Timer1 (16-bit), Timer2 (8-bit) |
|
|
113
|
+
| **PWM** | 6 channels | From Timer0 (OC0A/OC0B), Timer1 (OC1A/OC1B), Timer2 (OC2A/OC2B) |
|
|
114
|
+
| **External Interrupts** | 2 | INT0 on PD2, INT1 on PD3 |
|
|
115
|
+
| **Watchdog** | 1 | Independent watchdog timer |
|
|
116
|
+
|
|
117
|
+
### Peripheral-to-Pin Mapping
|
|
118
|
+
|
|
119
|
+
The MCU datasheet defines which pins are hardwired to each peripheral. This mapping is fixed by the silicon:
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
UART0: TX = PD1, RX = PD0
|
|
123
|
+
I2C0: SDA = PC4, SCL = PC5
|
|
124
|
+
SPI0: MOSI = PB3, MISO = PB4, SCK = PB5, SS = PB2
|
|
125
|
+
ADC0: CH0 = PC0, CH1 = PC1, CH2 = PC2, CH3 = PC3, CH4 = PC4, CH5 = PC5
|
|
126
|
+
PWM: OC0A = PD6, OC0B = PD5 (Timer0)
|
|
127
|
+
OC1A = PB1, OC1B = PB2 (Timer1)
|
|
128
|
+
OC2A = PB3, OC2B = PD3 (Timer2)
|
|
129
|
+
EXTI: INT0 = PD2, INT1 = PD3
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Board packages consume this information when building their [`BoardDefinition`](../board-arduino-uno/src/index.ts:46) manifest. The board definition adds board-level concerns (which peripheral aliases to use, which pins are exposed as headers, memory specs, build flags) on top of the MCU's hardware facts.
|
|
133
|
+
|
|
134
|
+
### Why Peripherals Belong in MCU Packages
|
|
135
|
+
|
|
136
|
+
The number of I2C controllers, UART ports, and ADC channels is determined by the silicon die:
|
|
137
|
+
|
|
138
|
+
- **Same chip, different boards** — An ATmega328P on an Arduino Uno, Pro Mini, or bare breadboard all have exactly 1 UART, 1 I2C, 1 SPI, and 3 timers. Duplicating this in every board package is redundant and error-prone.
|
|
139
|
+
- **Transpiler validation** — The transpiler uses peripheral counts to detect bus conflicts (e.g., two I2C devices on the same bus) and pin-capability mismatches (e.g., calling `pwm()` on a non-PWM pin). These checks are chip-level, not board-level.
|
|
140
|
+
- **Peripheral instances** — When user code creates `new I2CBus(i2cName(0))`, the instance number `0` refers to the MCU's I2C0 peripheral. The MCU package defines how many instances exist.
|
|
141
|
+
|
|
142
|
+
Currently, the peripheral definitions are strictly separated from board-level concerns. The MCU package exports a structured peripheral description that board packages import and extend.
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
// src/peripherals.ts in an MCU package
|
|
146
|
+
export const UART_INSTANCES: readonly PeripheralInstance[] = [
|
|
147
|
+
{ instance: 0, defaultPins: { tx: 'PD1', rx: 'PD0' } },
|
|
148
|
+
];
|
|
149
|
+
// ... (I2C, SPI, ADC, etc.)
|
|
150
|
+
|
|
151
|
+
export const MCU_PERIPHERALS = {
|
|
152
|
+
uart: [...UART_INSTANCES],
|
|
153
|
+
i2c: [...I2C_INSTANCES],
|
|
154
|
+
spi: [...SPI_INSTANCES],
|
|
155
|
+
// ...
|
|
156
|
+
} as const;
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Board packages then reference the MCU's peripheral data rather than duplicating it:
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
// In a board package
|
|
163
|
+
import { MCU_PERIPHERALS } from '@typecad/mcu-atmega328p';
|
|
164
|
+
|
|
165
|
+
export const ArduinoUno: BoardDefinition = {
|
|
166
|
+
// ...
|
|
167
|
+
peripherals: {
|
|
168
|
+
...MCU_PERIPHERALS,
|
|
169
|
+
aliases: { UART0: 'Serial', I2C0: 'Wire', SPI0: 'SPI' }, // board-specific
|
|
170
|
+
// board-specific overrides (e.g., reference voltages) go here
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Auto-Generated HAL Instances
|
|
176
|
+
|
|
177
|
+
MCU packages also export the concrete HAL instances (`UART0`, `I2C0`, etc.) corresponding to their physical peripherals. To minimize boilerplate and prevent mismatches, these are auto-generated from the peripheral definition arrays using `createHALInstances` from `@typecad/hal`:
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
import { createHALInstances, SerialPort, serialName } from '@typecad/hal';
|
|
181
|
+
|
|
182
|
+
/** UART/Serial instances */
|
|
183
|
+
export const [UART0] = createHALInstances(UART_INSTANCES, i => new SerialPort(serialName(i)));
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Because `createHALInstances` returns a mapped array, you simply destructure exactly the instances you've defined in the array. This single line dynamically creates the correct HAL objects and ensures `UART0` is strongly typed and statically exported.
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## How Board Packages Use This
|
|
192
|
+
|
|
193
|
+
The [`@typecad/board-arduino-uno`](../board-arduino-uno/src/pins.ts) package demonstrates the pattern:
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
// Re-export datasheet pins from the MCU package
|
|
197
|
+
export {
|
|
198
|
+
PD0, PD1, PD2, PD3, PD4, PD5, PD6, PD7,
|
|
199
|
+
PB0, PB1, PB2, PB3, PB4, PB5,
|
|
200
|
+
PC0, PC1, PC2, PC3, PC4, PC5,
|
|
201
|
+
} from '@typecad/mcu-atmega328p';
|
|
202
|
+
|
|
203
|
+
// Import for local aliasing
|
|
204
|
+
import { PD0, PB5, PC4, PC5, /* ... */ } from '@typecad/mcu-atmega328p';
|
|
205
|
+
|
|
206
|
+
// Board-specific aliases
|
|
207
|
+
export const D13 = PB5; // Arduino digital pin 13
|
|
208
|
+
export const A0 = PC0; // Arduino analog pin A0
|
|
209
|
+
export const LED = PB5; // On-board LED
|
|
210
|
+
export const SDA = PC4; // I2C data
|
|
211
|
+
export const SCL = PC5; // I2C clock
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
The board package also provides the [`BoardDefinition`](../board-arduino-uno/src/index.ts:46) manifest with pin capabilities, peripheral assignments, memory specs, and build configuration.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Creating a New `mcu-*` Package
|
|
219
|
+
|
|
220
|
+
Follow these steps to create an MCU package for a new microcontroller.
|
|
221
|
+
|
|
222
|
+
### 1. Scaffold the Package
|
|
223
|
+
|
|
224
|
+
```
|
|
225
|
+
packages/mcu-<chip>/
|
|
226
|
+
├── package.json
|
|
227
|
+
├── tsconfig.json
|
|
228
|
+
└── src/
|
|
229
|
+
├── index.ts
|
|
230
|
+
├── pins.ts
|
|
231
|
+
├── peripherals.ts ← hardware peripheral descriptions
|
|
232
|
+
└── arduino-map.ts (or other framework mappings)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### 2. `package.json`
|
|
236
|
+
|
|
237
|
+
```json
|
|
238
|
+
{
|
|
239
|
+
"name": "@typecad/mcu-<chip>",
|
|
240
|
+
"version": "0.1.0",
|
|
241
|
+
"description": "TypeCAD MCU definition for <ChipName>",
|
|
242
|
+
"type": "commonjs",
|
|
243
|
+
"main": "./dist/index.js",
|
|
244
|
+
"types": "./dist/index.d.ts",
|
|
245
|
+
"exports": {
|
|
246
|
+
".": {
|
|
247
|
+
"types": "./dist/index.d.ts",
|
|
248
|
+
"default": "./dist/index.js"
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
"files": ["dist"],
|
|
252
|
+
"scripts": {
|
|
253
|
+
"build": "tsc"
|
|
254
|
+
},
|
|
255
|
+
"dependencies": {
|
|
256
|
+
"@typecad/cuttlefish": "*",
|
|
257
|
+
"@typecad/hal": "*"
|
|
258
|
+
},
|
|
259
|
+
"license": "MIT"
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### 3. `tsconfig.json`
|
|
264
|
+
|
|
265
|
+
```json
|
|
266
|
+
{
|
|
267
|
+
"compilerOptions": {
|
|
268
|
+
"composite": true,
|
|
269
|
+
"target": "ES2021",
|
|
270
|
+
"module": "Node16",
|
|
271
|
+
"moduleResolution": "Node16",
|
|
272
|
+
"strict": true,
|
|
273
|
+
"declaration": true,
|
|
274
|
+
"declarationMap": true,
|
|
275
|
+
"sourceMap": true,
|
|
276
|
+
"rootDir": "src",
|
|
277
|
+
"outDir": "dist"
|
|
278
|
+
},
|
|
279
|
+
"include": ["src/**/*.ts"],
|
|
280
|
+
"references": [
|
|
281
|
+
{ "path": "../cuttlefish" },
|
|
282
|
+
{ "path": "../hal" }
|
|
283
|
+
]
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### 4. `src/pins.ts` — Define Pins from the Datasheet
|
|
288
|
+
|
|
289
|
+
Open the MCU datasheet and find the GPIO port table. Create one `Pin.fromPort()` export per GPIO pin:
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
import { Pin } from '@typecad/hal';
|
|
293
|
+
|
|
294
|
+
// Port A — 8-bit bidirectional I/O port
|
|
295
|
+
export const PA0 = Pin.fromPort('PA0');
|
|
296
|
+
export const PA1 = Pin.fromPort('PA1');
|
|
297
|
+
// ... up to PA7
|
|
298
|
+
|
|
299
|
+
// Port B — 8-bit bidirectional I/O port
|
|
300
|
+
export const PB0 = Pin.fromPort('PB0');
|
|
301
|
+
// ...
|
|
302
|
+
|
|
303
|
+
// Port C — etc.
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
**Guidelines:**
|
|
307
|
+
|
|
308
|
+
- **Use datasheet port names** (`PD0`, `PB5`, `PC0`) — these are the canonical identifiers.
|
|
309
|
+
- **Include ALL GPIO pins** on the chip, even if some are shared with crystal oscillators or reset pins. Add a comment noting any restrictions (e.g. `// PB6/PB7 are crystal oscillator on Uno, not GPIO`).
|
|
310
|
+
- **Do NOT include power, ground, or purely analog-only pins** that have no GPIO capability.
|
|
311
|
+
- **Do NOT create board-specific aliases** (like `LED` or `D13`) — those belong in board packages.
|
|
312
|
+
|
|
313
|
+
### 5. `src/peripherals.ts` — Describe Hardware Peripherals
|
|
314
|
+
|
|
315
|
+
Open the datasheet's peripheral overview chapter. Document every hardware peripheral built into the silicon using definition arrays, and auto-generate the concrete HAL instances:
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
import { PeripheralInstance } from '@typecad/cuttlefish/api/schema';
|
|
319
|
+
import { createHALInstances, SerialPort, serialName } from '@typecad/hal';
|
|
320
|
+
|
|
321
|
+
export const UART_INSTANCES: readonly PeripheralInstance[] = [
|
|
322
|
+
{ instance: 0, pins: { tx: 'PA0', rx: 'PA1' } },
|
|
323
|
+
{ instance: 1, pins: { tx: 'PA2', rx: 'PA3' } },
|
|
324
|
+
] as const;
|
|
325
|
+
|
|
326
|
+
// ... define I2C, SPI, etc.
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Hardware peripherals on the <ChipName>.
|
|
330
|
+
* Source: <ChipName> datasheet, Section X — Peripheral Description
|
|
331
|
+
*/
|
|
332
|
+
export const MCU_PERIPHERALS = {
|
|
333
|
+
uart: [...UART_INSTANCES],
|
|
334
|
+
// ...
|
|
335
|
+
} as const;
|
|
336
|
+
|
|
337
|
+
// Auto-generate HAL objects
|
|
338
|
+
export const [UART0, UART1] = createHALInstances(UART_INSTANCES, i => new SerialPort(serialName(i)));
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
**What to include:**
|
|
342
|
+
|
|
343
|
+
- **Instance count** — How many of each peripheral the silicon provides (e.g., ESP32 has 3 I2C, 4 SPI, 3 UART; ATmega328P has 1 of each). Update the destructuring arrays to match exactly the available instances.
|
|
344
|
+
- **Pin assignments** — Which MCU port pins are hardwired to each peripheral function. These are fixed by the silicon and cannot be changed.
|
|
345
|
+
- **Capabilities** — Resolution (ADC/DAC bits), timer widths, max frequencies, etc.
|
|
346
|
+
- **Alternate pin functions** — If the chip supports pin muxing (like ESP32's GPIO matrix), document the default and alternate pin assignments.
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
**What NOT to include:**
|
|
350
|
+
|
|
351
|
+
- **Board-specific aliases** — `UART0 → 'Serial'` is an Arduino convention, not a chip property.
|
|
352
|
+
- **Reference voltages** — These depend on the board's power supply (5V vs 3.3V), not the silicon.
|
|
353
|
+
- **Framework-specific names** — `Wire`, `SPI`, `Serial` are Arduino names; other frameworks use different names.
|
|
354
|
+
|
|
355
|
+
### 6. `src/arduino-map.ts` — Add Framework Pin Mappings (if applicable)
|
|
356
|
+
|
|
357
|
+
If the chip is used with the Arduino framework, provide the port-name-to-Arduino-pin-number mapping:
|
|
358
|
+
|
|
359
|
+
```typescript
|
|
360
|
+
/**
|
|
361
|
+
* Arduino pin number for each MCU port name.
|
|
362
|
+
* Source: Arduino <variant>/pins_arduino.h
|
|
363
|
+
*/
|
|
364
|
+
export const ARDUINO_PIN_MAP: Readonly<Record<string, number>> = {
|
|
365
|
+
PA0: 0, PA1: 1, // ...
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
/** Offset where analog pin numbering starts. */
|
|
369
|
+
export const ARDUINO_ANALOG_OFFSET = 14;
|
|
370
|
+
|
|
371
|
+
/** Reverse map: Arduino pin number → MCU port name. */
|
|
372
|
+
export const ARDUINO_PIN_REVERSE: Readonly<Record<number, string>> = {};
|
|
373
|
+
for (const [port, num] of Object.entries(ARDUINO_PIN_MAP)) {
|
|
374
|
+
(ARDUINO_PIN_REVERSE as Record<number, string>)[num] = port;
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
**Source this from the actual Arduino core variant header** (e.g. `variants/standard/pins_arduino.h` for ATmega328P). Do not guess — wrong mappings cause silent hardware bugs.
|
|
379
|
+
|
|
380
|
+
If the chip supports multiple Arduino board variants with different pin mappings, export the most common one as `ARDUINO_PIN_MAP` and add additional named maps as needed (e.g., `ARDUINO_PIN_MAP_PRO_MINI`).
|
|
381
|
+
|
|
382
|
+
### 7. `src/index.ts` — Barrel Export
|
|
383
|
+
|
|
384
|
+
```typescript
|
|
385
|
+
export * from './pins';
|
|
386
|
+
export * from './peripherals';
|
|
387
|
+
export * from './arduino-map';
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### 8. Add to Workspace
|
|
391
|
+
|
|
392
|
+
In the monorepo root `pnpm-workspace.yaml`, the package is automatically included if it's under `packages/`. Make sure to:
|
|
393
|
+
|
|
394
|
+
1. Run `pnpm install` from the workspace root to link the new package.
|
|
395
|
+
2. Reference it from any board package that uses this MCU:
|
|
396
|
+
```json
|
|
397
|
+
// packages/board-<board>/package.json
|
|
398
|
+
{
|
|
399
|
+
"dependencies": {
|
|
400
|
+
"@typecad/mcu-<chip>": "*"
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
---
|
|
406
|
+
|
|
407
|
+
## When to Create an MCU Package vs. a Board Package
|
|
408
|
+
|
|
409
|
+
| Scenario | Create |
|
|
410
|
+
|---|---|
|
|
411
|
+
| New microcontroller chip (e.g. ATtiny85, STM32F103) | `mcu-*` package |
|
|
412
|
+
| New board using an existing chip (e.g. Arduino Nano with ATmega328P) | `board-*` package only — reuse the `mcu-atmega328p` package |
|
|
413
|
+
| New board with a new chip | Both — `mcu-*` for the chip, `board-*` for the board |
|
|
414
|
+
| Chip used with a non-Arduino framework | Add framework mapping to existing `mcu-*` package |
|
|
415
|
+
|
|
416
|
+
### Key Principles
|
|
417
|
+
|
|
418
|
+
- **One MCU package per chip family.** The ATmega328P has one package shared by Arduino Uno, Pro Mini, Nano, and any custom board.
|
|
419
|
+
- **Pin names are datasheet port names.** `PD0` means the same thing on every ATmega328P board. Board-specific names like `RX` or `D0` go in the board package.
|
|
420
|
+
- **Peripheral counts are silicon facts.** The number of UART/I2C/SPI controllers is determined by the chip die, not the board. Document them once in the MCU package.
|
|
421
|
+
- **Framework mappings are per-chip, not per-board.** The Arduino pin mapping for ATmega328P is the same whether it's on an Uno or a Pro Mini. Only the board package changes (different aliases, different peripheral wiring).
|
|
422
|
+
- **MCU packages have no runtime code.** Everything is resolved at transpile time. The `Pin.fromPort()` calls exist only for the type system and transpiler — they produce no C++ output.
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
## ATmega328P Pin Reference
|
|
427
|
+
|
|
428
|
+
| Port | DIP-28 Pin | Arduino Pin | Peripheral Functions | Notes |
|
|
429
|
+
|------|-----------|-------------|---------------------|-------|
|
|
430
|
+
| PC6 | 1 | — | RESET | Reset pin (usually not GPIO) |
|
|
431
|
+
| PD0 | 2 | D0 / RX | UART0 RX | INT0 (external interrupt) |
|
|
432
|
+
| PD1 | 3 | D1 / TX | UART0 TX | INT1 (external interrupt) |
|
|
433
|
+
| PD2 | 4 | D2 | INT0 | External interrupt 0 |
|
|
434
|
+
| PD3 | 5 | D3~ | INT1, OC2B | PWM (Timer2) |
|
|
435
|
+
| PD4 | 6 | D4 | — | — |
|
|
436
|
+
| VCC | 7, 20 | — | — | Power |
|
|
437
|
+
| GND | 8, 22 | — | — | Ground |
|
|
438
|
+
| PB6 | 9 | — | TOSC1 | Crystal oscillator |
|
|
439
|
+
| PB7 | 10 | — | TOSC2 | Crystal oscillator |
|
|
440
|
+
| PD5 | 11 | D5~ | OC0B | PWM (Timer0) |
|
|
441
|
+
| PD6 | 12 | D6~ | OC0A | PWM (Timer0) |
|
|
442
|
+
| PD7 | 13 | D7 | — | — |
|
|
443
|
+
| PB0 | 14 | D8 | — | — |
|
|
444
|
+
| PB1 | 15 | D9~ | OC1A | PWM (Timer1) |
|
|
445
|
+
| PB2 | 16 | D10~ | OC1B, SPI SS | PWM (Timer1) |
|
|
446
|
+
| PB3 | 17 | D11~ | OC2A, SPI MOSI | PWM (Timer2) |
|
|
447
|
+
| PB4 | 18 | D12 | SPI MISO | — |
|
|
448
|
+
| PB5 | 19 | D13 | SPI SCK | On-board LED |
|
|
449
|
+
| AVCC | 21 | — | — | Analog power supply |
|
|
450
|
+
| PC0 | 23 | A0 / D14 | ADC ch0 | — |
|
|
451
|
+
| PC1 | 24 | A1 / D15 | ADC ch1 | — |
|
|
452
|
+
| PC2 | 25 | A2 / D16 | ADC ch2 | — |
|
|
453
|
+
| PC3 | 26 | A3 / D17 | ADC ch3 | — |
|
|
454
|
+
| PC4 | 27 | A4 / SDA | ADC ch4, I2C SDA | — |
|
|
455
|
+
| PC5 | 28 | A5 / SCL | ADC ch5, I2C SCL | — |
|
|
456
|
+
|
|
457
|
+
---
|
|
458
|
+
|
|
459
|
+
## License
|
|
460
|
+
|
|
461
|
+
MIT
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Arduino pin number for each MCU port name.
|
|
3
|
+
* Port name → Arduino digital/analog pin number.
|
|
4
|
+
*/
|
|
5
|
+
export declare const ARDUINO_PIN_MAP: Readonly<Record<string, number>>;
|
|
6
|
+
/**
|
|
7
|
+
* The offset where analog pin numbering starts.
|
|
8
|
+
* Arduino analogRead(A0) maps to pin 14 on ATmega328P.
|
|
9
|
+
*/
|
|
10
|
+
export declare const ARDUINO_ANALOG_OFFSET = 14;
|
|
11
|
+
/**
|
|
12
|
+
* Reverse map: Arduino pin number → MCU port name.
|
|
13
|
+
* Used by the transpiler to resolve bare names like D13 → PB5.
|
|
14
|
+
*/
|
|
15
|
+
export declare const ARDUINO_PIN_REVERSE: Readonly<Record<number, string>>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// @typecad/mcu-atmega328p — Arduino core pin mapping
|
|
3
|
+
//
|
|
4
|
+
// Maps MCU port names to Arduino framework pin numbers.
|
|
5
|
+
// Source: Arduino AVR core, variants/standard/pins_arduino.h
|
|
6
|
+
//
|
|
7
|
+
// This mapping is per-chip — an ATtiny85 has A2=PB4 while ATmega328P has
|
|
8
|
+
// A2=PC2. It lives in the MCU package, NOT in the framework package.
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
/**
|
|
11
|
+
* Arduino pin number for each MCU port name.
|
|
12
|
+
* Port name → Arduino digital/analog pin number.
|
|
13
|
+
*/
|
|
14
|
+
export const ARDUINO_PIN_MAP = {
|
|
15
|
+
// Port D — Arduino digital pins 0–7
|
|
16
|
+
PD0: 0, PD1: 1, PD2: 2, PD3: 3,
|
|
17
|
+
PD4: 4, PD5: 5, PD6: 6, PD7: 7,
|
|
18
|
+
// Port B — Arduino digital pins 8–13
|
|
19
|
+
PB0: 8, PB1: 9, PB2: 10, PB3: 11,
|
|
20
|
+
PB4: 12, PB5: 13,
|
|
21
|
+
// Port C — Arduino analog pins A0–A5 (pin numbers 14–19)
|
|
22
|
+
PC0: 14, PC1: 15, PC2: 16, PC3: 17,
|
|
23
|
+
PC4: 18, PC5: 19,
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* The offset where analog pin numbering starts.
|
|
27
|
+
* Arduino analogRead(A0) maps to pin 14 on ATmega328P.
|
|
28
|
+
*/
|
|
29
|
+
export const ARDUINO_ANALOG_OFFSET = 14;
|
|
30
|
+
/**
|
|
31
|
+
* Reverse map: Arduino pin number → MCU port name.
|
|
32
|
+
* Used by the transpiler to resolve bare names like D13 → PB5.
|
|
33
|
+
*/
|
|
34
|
+
export const ARDUINO_PIN_REVERSE = {};
|
|
35
|
+
for (const [port, num] of Object.entries(ARDUINO_PIN_MAP)) {
|
|
36
|
+
ARDUINO_PIN_REVERSE[num] = port;
|
|
37
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export * from './pins.js';
|
|
2
|
+
export * from './peripherals.js';
|
|
3
|
+
export * from './mcu.js';
|
|
4
|
+
export * from './arduino-map.js';
|
|
5
|
+
/**
|
|
6
|
+
* Structured manifest consumed by the TypeCAD CLI for contract-based
|
|
7
|
+
* board generation. Provides pin names and peripheral instance names
|
|
8
|
+
* without requiring the CLI to text-scrape compiled output.
|
|
9
|
+
*/
|
|
10
|
+
export declare const TypeCADManifest: {
|
|
11
|
+
/** All MCU port-level pin names (e.g. 'PB5', 'PC4'). */
|
|
12
|
+
readonly pinNames: readonly ["PD0", "PD1", "PD2", "PD3", "PD4", "PD5", "PD6", "PD7", "PB0", "PB1", "PB2", "PB3", "PB4", "PB5", "PB6", "PB7", "PC0", "PC1", "PC2", "PC3", "PC4", "PC5", "PC6"];
|
|
13
|
+
/** All HAL peripheral instance names exported from this package. */
|
|
14
|
+
readonly peripheralNames: readonly ["I2C0", "SPI0", "UART0"];
|
|
15
|
+
};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// @typecad/mcu-atmega328p — MCU definition package
|
|
3
|
+
//
|
|
4
|
+
// Provides datasheet-level pin definitions, hardware peripheral descriptions,
|
|
5
|
+
// and framework pin mappings for the ATmega328P microcontroller.
|
|
6
|
+
// Board packages (e.g. board-arduino-uno) import from here and add
|
|
7
|
+
// board-specific aliases and wiring.
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// Re-export all pin definitions
|
|
10
|
+
export * from './pins.js';
|
|
11
|
+
// Re-export hardware peripheral descriptions
|
|
12
|
+
export * from './peripherals.js';
|
|
13
|
+
// Re-export MCU definition
|
|
14
|
+
export * from './mcu.js';
|
|
15
|
+
// Re-export Arduino pin mapping (used by transpiler and framework strategy)
|
|
16
|
+
export * from './arduino-map.js';
|
|
17
|
+
/**
|
|
18
|
+
* Structured manifest consumed by the TypeCAD CLI for contract-based
|
|
19
|
+
* board generation. Provides pin names and peripheral instance names
|
|
20
|
+
* without requiring the CLI to text-scrape compiled output.
|
|
21
|
+
*/
|
|
22
|
+
export const TypeCADManifest = {
|
|
23
|
+
/** All MCU port-level pin names (e.g. 'PB5', 'PC4'). */
|
|
24
|
+
pinNames: [
|
|
25
|
+
'PD0', 'PD1', 'PD2', 'PD3', 'PD4', 'PD5', 'PD6', 'PD7',
|
|
26
|
+
'PB0', 'PB1', 'PB2', 'PB3', 'PB4', 'PB5', 'PB6', 'PB7',
|
|
27
|
+
'PC0', 'PC1', 'PC2', 'PC3', 'PC4', 'PC5', 'PC6'
|
|
28
|
+
],
|
|
29
|
+
/** All HAL peripheral instance names exported from this package. */
|
|
30
|
+
peripheralNames: ['I2C0', 'SPI0', 'UART0'],
|
|
31
|
+
};
|
package/dist/mcu.d.ts
ADDED