Skip to content

Commit 30044e3

Browse files
committed
Major additions to the WebAssembly port, including PWM, Neopixel, and improved DigitalIO and AnalogIO support.
1 parent e470fb0 commit 30044e3

57 files changed

Lines changed: 3746 additions & 2086 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

ports/wasm/BUILD_FLAG_ANALYSIS.md

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# WASM Port Build Flag Analysis
2+
3+
## Current Flag Hierarchy Issues
4+
5+
### File Structure
6+
```
7+
mpconfigport.h # Port-wide C defines (MICROPY_* and CIRCUITPY_*)
8+
mpconfigport.mk # Port-wide Makefile flags (CIRCUITPY_*)
9+
variants/mpconfigvariant_common.h # Common variant C defines (MICROPY_*)
10+
variants/*/mpconfigvariant.h # Variant-specific C defines
11+
variants/*/mpconfigvariant.mk # Variant-specific Makefile flags
12+
```
13+
14+
### Current Redundancies
15+
16+
1. **MICROPY flags in variant_common.h vs mpconfigport.h**
17+
- Many MICROPY_* flags are set in both places
18+
- mpconfigvariant_common.h is included by mpconfigvariant.h, which is included by mpconfigport.h
19+
- Creates potential for conflicts and confusion
20+
21+
2. **CIRCUITPY flags split across .mk files**
22+
- Module enables (CIRCUITPY_ANALOGIO, etc.) in mpconfigport.mk
23+
- But some could be variant-specific
24+
25+
3. **Filesystem flags**
26+
- Currently set conditionally in Makefile based on USE_SUPERVISOR_WASM
27+
- Could be in mpconfigvariant.mk instead
28+
29+
## Proposed Clean Structure
30+
31+
### Principle: Clearer Separation of Concerns
32+
33+
**mpconfigport.h** - Port-wide hardware/platform defines only
34+
- Platform capabilities (WASM-specific)
35+
- Hardware interfaces available
36+
- NOT variant-specific settings
37+
38+
**mpconfigport.mk** - Port-wide CircuitPython modules
39+
- CIRCUITPY_* flags for modules available to ALL variants
40+
- Common build settings
41+
42+
**variants/mpconfigvariant.mk** - Variant-specific build flags
43+
- USE_SUPERVISOR_WASM (integrated only)
44+
- Variant-specific CIRCUITPY_* overrides
45+
- Filesystem type selection
46+
47+
**variants/mpconfigvariant_common.h** - ELIMINATE or MINIMIZE
48+
- Move MICROPY_* flags to mpconfigport.h unless variant-specific
49+
- Keep only if truly shared between variants but not port-wide
50+
51+
**variants/*/mpconfigvariant.h** - Variant-specific feature flags
52+
- Feature toggles (CIRCUITPY_STATUS_BAR, etc.)
53+
- Variant-specific MICROPY_* overrides
54+
55+
## Specific Recommendations
56+
57+
### 1. Move from mpconfigvariant_common.h → mpconfigport.h:
58+
- MICROPY_FLOAT_IMPL (port-wide: always double in WASM)
59+
- MICROPY_READER_VFS (port-wide: always enabled)
60+
- MICROPY_PY_SYS_* flags (port-wide platform features)
61+
- MICROPY_REPL_* flags (REPL features for all variants)
62+
63+
### 2. Keep in variant files:
64+
- CIRCUITPY_STATUS_BAR (varies by variant)
65+
- USE_SUPERVISOR_WASM (integrated only)
66+
- Future: memory limits, optional features
67+
68+
### 3. Filesystem Configuration Flow:
69+
```
70+
variants/integrated/mpconfigvariant.mk:
71+
USE_SUPERVISOR_WASM = 1
72+
73+
Makefile:
74+
ifeq ($(USE_SUPERVISOR_WASM),1)
75+
INTERNAL_FLASH_FILESYSTEM = 0
76+
...
77+
include ../../supervisor/supervisor.mk
78+
# Override filesystem.c with filesystem_wasm.c
79+
else
80+
# Minimal supervisor
81+
endif
82+
```
83+
84+
## Benefits
85+
86+
1. **Clearer ownership** - Each file has a clear purpose
87+
2. **Less duplication** - Settings appear in one logical place
88+
3. **Easier variant creation** - Variants only override what they need
89+
4. **Better maintainability** - Easier to track which flags affect what
90+
5. **Follows CircuitPython patterns** - Similar to other ports
91+
92+
## Implementation Order
93+
94+
1. ✅ Eliminate supervisor_wasm.mk (use conditional logic in Makefile)
95+
2. Review and consolidate mpconfigvariant_common.h → mpconfigport.h
96+
3. Move filesystem flags to variants/*/mpconfigvariant.mk
97+
4. Document remaining flag purposes in comments

ports/wasm/COMMON_HAL_AUDIT.md

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
# common_hal Function Implementation Audit
2+
3+
## Overview
4+
5+
This document audits the implementation of `common_hal_*` functions in the CircuitPython WASM port for digitalio and microcontroller modules, identifying gaps and misimplementations from early development.
6+
7+
## Module: digitalio/DigitalInOut
8+
9+
### Required Functions (from shared-bindings/digitalio/DigitalInOut.h)
10+
11+
| Function | Status | Notes |
12+
|----------|--------|-------|
13+
| `common_hal_digitalio_validate_pin()` |**FIXED** | Was returning hardcoded `&pin_GPIO0`, now uses `validate_obj_is_free_pin()` |
14+
| `common_hal_digitalio_digitalinout_construct()` |**FIXED** | Was missing `claim_pin()` call, now added |
15+
| `common_hal_digitalio_digitalinout_deinit()` | ✅ Implemented | Correctly releases pin and resets state |
16+
| `common_hal_digitalio_digitalinout_deinited()` | ✅ Implemented | Checks if `self->pin == NULL` |
17+
| `common_hal_digitalio_digitalinout_switch_to_input()` | ✅ Implemented | Sets direction and pull resistors |
18+
| `common_hal_digitalio_digitalinout_switch_to_output()` | ✅ Implemented | Sets direction, value, and drive mode |
19+
| `common_hal_digitalio_digitalinout_get_direction()` | ✅ Implemented | Returns INPUT or OUTPUT |
20+
| `common_hal_digitalio_digitalinout_set_value()` | ✅ Implemented | Sets output value |
21+
| `common_hal_digitalio_digitalinout_get_value()` | ✅ Implemented | Gets value with pull resistor simulation |
22+
| `common_hal_digitalio_digitalinout_set_drive_mode()` | ✅ Implemented | Sets push-pull or open-drain |
23+
| `common_hal_digitalio_digitalinout_get_drive_mode()` | ✅ Implemented | Gets current drive mode |
24+
| `common_hal_digitalio_digitalinout_set_pull()` | ✅ Implemented | Sets pull resistor |
25+
| `common_hal_digitalio_digitalinout_get_pull()` | ✅ Implemented | Gets current pull setting |
26+
| `common_hal_digitalio_digitalinout_never_reset()` |**NEWLY IMPLEMENTED** | Marks GPIO state and pin as never_reset |
27+
| `common_hal_digitalio_digitalinout_get_reg()` | ✅ Implemented | Returns NULL (not supported in WASM) |
28+
| `common_hal_digitalio_has_reg_op()` | ✅ Implemented | Returns false (not supported in WASM) |
29+
30+
### Bugs Fixed
31+
32+
#### Bug #1: validate_pin() Always Returned GPIO0
33+
**File:** `common-hal/digitalio/DigitalInOut.c` line 48-50
34+
35+
**Before:**
36+
```c
37+
const mcu_pin_obj_t *common_hal_digitalio_validate_pin(mp_obj_t obj) {
38+
return &pin_GPIO0; // ❌ WRONG!
39+
}
40+
```
41+
42+
**After:**
43+
```c
44+
const mcu_pin_obj_t *common_hal_digitalio_validate_pin(mp_obj_t obj) {
45+
return validate_obj_is_free_pin(obj, MP_QSTR_pin); // ✅ CORRECT
46+
}
47+
```
48+
49+
**Impact:** Critical - All DigitalInOut objects were using GPIO0, causing pin interference.
50+
51+
#### Bug #2: Missing claim_pin() Call
52+
**File:** `common-hal/digitalio/DigitalInOut.c` line 57-59
53+
54+
**Before:**
55+
```c
56+
digitalinout_result_t common_hal_digitalio_digitalinout_construct(...) {
57+
self->pin = pin; // ❌ No claim!
58+
...
59+
}
60+
```
61+
62+
**After:**
63+
```c
64+
digitalinout_result_t common_hal_digitalio_digitalinout_construct(...) {
65+
claim_pin(pin); // ✅ Claim the pin
66+
self->pin = pin;
67+
...
68+
}
69+
```
70+
71+
**Impact:** Medium - Pin reuse conflicts not detected.
72+
73+
## Module: microcontroller/Pin
74+
75+
### Required Functions (from shared-bindings/microcontroller/Pin.h)
76+
77+
| Function | Status | Notes |
78+
|----------|--------|-------|
79+
| `common_hal_mcu_pin_is_free()` | ✅ Implemented | Checks `!pin->claimed` |
80+
| `common_hal_never_reset_pin()` | ✅ Implemented | Calls `never_reset_pin_number()` |
81+
| `common_hal_reset_pin()` | ✅ Implemented | Calls `reset_pin_number()` |
82+
| `common_hal_mcu_pin_number()` | ✅ Implemented | Returns `pin->number` |
83+
| `common_hal_mcu_pin_claim()` | ✅ Implemented | Calls `claim_pin()` |
84+
| `common_hal_mcu_pin_claim_number()` |**NEWLY IMPLEMENTED** | Claims pin by number |
85+
| `common_hal_mcu_pin_reset_number()` | ✅ Implemented | Calls `reset_pin_number()` |
86+
87+
### Implementation Complete
88+
89+
All required microcontroller/Pin functions are now implemented, including the previously missing `common_hal_mcu_pin_claim_number()`.
90+
91+
**Implementation added:**
92+
```c
93+
void common_hal_mcu_pin_claim_number(uint8_t pin_no) {
94+
if (pin_no >= 64) {
95+
return;
96+
}
97+
all_pins[pin_no]->claimed = true;
98+
}
99+
```
100+
101+
**File:** `common-hal/microcontroller/Pin.c` line 252-257
102+
103+
## Module: analogio/AnalogIn
104+
105+
### Required Functions (from shared-bindings/analogio/AnalogIn.h)
106+
107+
| Function | Status | Notes |
108+
|----------|--------|-------|
109+
| `common_hal_analogio_analogin_validate_pin()` | ✅ **NEWLY ADDED** | Was completely missing |
110+
| `common_hal_analogio_analogin_construct()` | ✅ Implemented | Properly calls `claim_pin()` |
111+
| `common_hal_analogio_analogin_deinit()` | ✅ Implemented | Correctly releases pin and resets state |
112+
| `common_hal_analogio_analogin_deinited()` | ✅ Implemented | Checks if `self->pin == NULL` |
113+
| `common_hal_analogio_analogin_get_value()` | ✅ Implemented | Returns ADC value from state array |
114+
| `common_hal_analogio_analogin_get_reference_voltage()` | ✅ Implemented | Returns 3.3V reference |
115+
116+
### Missing Implementation (Fixed)
117+
118+
#### Missing: common_hal_analogio_analogin_validate_pin()
119+
120+
This function was completely absent from AnalogIn.c.
121+
122+
**Added implementation:**
123+
```c
124+
const mcu_pin_obj_t *common_hal_analogio_analogin_validate_pin(mp_obj_t obj) {
125+
return validate_obj_is_free_pin(obj, MP_QSTR_pin);
126+
}
127+
```
128+
129+
**File:** `common-hal/analogio/AnalogIn.c` line 38-40
130+
131+
**Impact:** Without this function, pin validation wasn't working properly. Similar pattern to the digitalio bug.
132+
133+
## Module: analogio/AnalogOut
134+
135+
### Required Functions (from shared-bindings/analogio/AnalogOut.h)
136+
137+
| Function | Status | Notes |
138+
|----------|--------|-------|
139+
| `common_hal_analogio_analogout_construct()` | ✅ Implemented | Properly calls `claim_pin()` |
140+
| `common_hal_analogio_analogout_deinit()` | ✅ Implemented | Correctly releases pin and resets state |
141+
| `common_hal_analogio_analogout_deinited()` | ✅ Implemented | Checks if `self->pin == NULL` |
142+
| `common_hal_analogio_analogout_set_value()` | ✅ Implemented | Sets DAC value in state array |
143+
144+
**Note:** AnalogOut does not have a validate_pin function (validation happens in shared-bindings).
145+
146+
## Module: microcontroller/__init__
147+
148+
### Required Functions
149+
150+
Most microcontroller/__init__ functions are implemented correctly in `common-hal/microcontroller/__init__.c`:
151+
-`common_hal_mcu_delay_us()`
152+
-`common_hal_mcu_disable_interrupts()`
153+
-`common_hal_mcu_enable_interrupts()`
154+
-`common_hal_mcu_on_next_reset()`
155+
-`common_hal_mcu_reset()`
156+
- ✅ Various reset reason functions
157+
158+
No issues identified in this module.
159+
160+
## Summary of Issues Found
161+
162+
### Critical (Fixed)
163+
1.**digitalio validate_pin()** - Was hardcoded to GPIO0
164+
2.**digitalio construct()** - Missing claim_pin() call
165+
166+
### High Priority (Completed)
167+
3.**digitalio never_reset()** - Was stub, now fully implemented
168+
4.**pwmio never_reset()** - Was stub, now fully implemented
169+
170+
### Low Priority (Completed)
171+
5.**microcontroller claim_number()** - Now implemented
172+
173+
## Recommendations
174+
175+
### Completed
176+
- ✅ Fix digitalio validate_pin() to use proper validation
177+
- ✅ Add claim_pin() call to digitalio construct()
178+
- ✅ Implement never_reset for digitalio
179+
- ✅ Implement never_reset for pwmio
180+
181+
### All Recommendations Completed
182+
- ✅ All required common_hal functions now properly implemented
183+
184+
## Testing
185+
186+
All critical and high-priority issues have been fixed and tested:
187+
- ✅ Multiple GPIO pins work independently
188+
- ✅ Pin validation works correctly
189+
- ✅ Pin claiming prevents conflicts
190+
- ✅ never_reset preserves state across soft resets
191+
- ✅ All existing functionality maintained
192+
193+
## Related Documentation
194+
195+
- [DIGITALIO_BUG_FIX.md](DIGITALIO_BUG_FIX.md) - Detailed analysis of digitalio bugs
196+
- [NEVER_RESET_IMPLEMENTATION.md](NEVER_RESET_IMPLEMENTATION.md) - I2C/UART never_reset details
197+
- [NEVER_RESET_STATUS.md](NEVER_RESET_STATUS.md) - Complete never_reset status across all modules
198+
199+
## Conclusion
200+
201+
The early digitalio, analogio, and microcontroller implementations had gaps and bugs from before the WASM port development team fully understood CircuitPython integration patterns. All identified issues have been resolved:
202+
203+
### Critical Bugs Fixed
204+
1.**digitalio validate_pin() hardcoded to GPIO0** - All pins mapped to same hardware → Now uses proper validation
205+
2.**digitalio Missing claim_pin() call** - Pin conflicts not detected → Now properly claims pins
206+
3.**analogio validate_pin() completely missing** - Pin validation non-functional → Now properly implemented
207+
208+
### Improvements Implemented
209+
4.**digitalio never_reset** - Stub implementation → Full functionality for GPIO preservation
210+
5.**pwmio never_reset** - Stub implementation → Full functionality for PWM preservation
211+
6.**microcontroller claim_number** - Missing function → Now implemented
212+
213+
The WASM port now correctly implements **ALL** required common_hal functions for digitalio, analogio, and microcontroller modules with proper CircuitPython integration patterns.
214+
215+
## Author
216+
217+
CircuitPython WASM Port Development (2025)

0 commit comments

Comments
 (0)