Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
158 commits
Select commit Hold shift + click to select a range
66bc59d
perf(avr): add basic-block store-to-load forwarding peephole
begeistert Jun 8, 2026
e67ccd2
feat(avr): codegen for FlashStrAddr + FlashLoadPtr (flash-string-by-r…
begeistert Jun 8, 2026
4d6790c
perf(avr): eliminate dead temporary-register moves (R16/R17)
begeistert Jun 8, 2026
7153db3
fix(avr): stop bytearray index codegen from clobbering R16/R17
begeistert Jun 8, 2026
1e9b4e4
fix(avr): remove remaining R16/R17 scratch clobbers in array/exceptio…
begeistert Jun 8, 2026
20dee28
perf(avr): allocate inline-expanded locals to R4-R15
begeistert Jun 8, 2026
ff8cb25
perf(avr): consume register-homed src2 directly in reg-reg ALU ops
begeistert Jun 8, 2026
ff475a2
perf(avr): destination-targeted in-place codegen for augmented 8-bit ops
begeistert Jun 8, 2026
4be7941
perf(avr): extend in-place augmented codegen to 16-bit reg/SRAM operands
begeistert Jun 9, 2026
a8136c4
perf(avr): shorten in-range conditional branches (drop the RJMP tramp…
begeistert Jun 9, 2026
1920400
perf(avr): size Raw inline-asm blocks for branch shortening
begeistert Jun 9, 2026
9bd4dd6
test(avr): pin SSD1306 flash-table init sequence over I2C
begeistert Jun 9, 2026
32c160d
perf(avr): fuse consecutive same-register immediate ORI/ANDI
begeistert Jun 9, 2026
66837c5
perf(avr): eliminate redundant register reloads across branches
begeistert Jun 9, 2026
54a986a
perf(avr): collapse call-argument park/unpark round-trips
begeistert Jun 9, 2026
7a68c9e
fix(avr): emit CALL/JMP + link with -mrelax (fix far-target relocations)
begeistert Jun 9, 2026
5b77aa6
example(smoothing): Arduino "Smoothing" port + functional tests
begeistert Jun 9, 2026
7d84873
perf(avr): eliminate redundant variable-index array-address (Z) rebuilds
begeistert Jun 10, 2026
28f531b
perf(avr): fuse adjacent same-operand divide and modulo into one __div16
begeistert Jun 10, 2026
0ab82e7
perf(avr): allocate 16-bit temporaries to the R16:R17 register pair
begeistert Jun 10, 2026
9e49f28
test(avr): divmod() 16-bit width fixture and tests
begeistert Jun 10, 2026
a07e78e
perf(avr): fuse the (hi<<8)|lo byte-pack into a direct byte placement
begeistert Jun 10, 2026
76fca6c
test(avr): dsp-stress fixture exercising all codegen optimizations at…
begeistert Jun 10, 2026
830d9c0
example(analog-inout): Arduino AnalogInOutSerial on the native HAL
begeistert Jun 10, 2026
46d2aff
example(analog-inout-mp): AnalogInOutSerial on the MicroPython layer
begeistert Jun 10, 2026
421d699
test(avr): global-init fixture for non-zero global initialization
begeistert Jun 10, 2026
6070549
test(avr): module-alias fixture (import machine as m, time as t)
begeistert Jun 10, 2026
7a87b45
feat(codegen): promote ISR-shared globals to GPIOR registers
begeistert Jun 12, 2026
ac6d843
test(avr): volatile-flag fixture for ISR-shared globals + GPIOR promo…
begeistert Jun 12, 2026
0245477
example(avr): migrate ISR<->main flags from the GPIOR0[n] idiom to pl…
begeistert Jun 12, 2026
7eab928
test(avr): zca-outline + zca-outline-dht fixtures (RFC 0001 Model A)
begeistert Jun 12, 2026
637a3a0
test(avr): zca factory/handle/slot fixtures (RFC 0001 Model B)
begeistert Jun 12, 2026
4b4391c
test(avr): zca-array fixture (RFC 0001 Model B Class[N] instance arrays)
begeistert Jun 12, 2026
de624a0
example(avr): declare 'global _crc_out' in rtos-multitask sensor_task
begeistert Jun 13, 2026
ac45a3f
test(avr): zca-outline-selfcall — outlined method calling a sibling m…
begeistert Jun 13, 2026
7713bb4
refactor(examples): migrate dht-sensor to the outline-friendly stdlib…
begeistert Jun 13, 2026
9f67758
test(avr): update linear-scan test for 16-bit R16:R17 pair allocation
begeistert Jun 13, 2026
03eeedf
feat(avr): lower a locally-caught raise to a jump (no SET/RET)
begeistert Jun 13, 2026
22bb253
refactor(avr): remove the dead SJLJ try/except codegen (setjmp/longjmp)
begeistert Jun 13, 2026
de7933e
perf(avr): lower a constant delay_us() to an inline calibrated loop
begeistert Jun 13, 2026
2de34ad
test(avr): cover ptr(register + offset) address arithmetic
begeistert Jun 13, 2026
c89579a
test(avr): cover runtime-offset pointer .value round-trip
begeistert Jun 13, 2026
4771b83
fix(codegen): reject out-of-range @interrupt vector instead of silent…
begeistert Jun 13, 2026
2c093af
perf(codegen): fuse 8-bit divide/modulo pairs and across DebugLine ma…
begeistert Jun 13, 2026
fc022c8
test(avr): property/differential harness for the register allocator
begeistert Jun 13, 2026
a9eb374
test(avr): cover nested calls, multiple returns, and interrupt safety
begeistert Jun 13, 2026
9ba68d7
test(avr): two-ISR disjoint-region coverage + ISR sweep
begeistert Jun 13, 2026
6ed70ca
test(avr): ISR with a nested call (interrupt-context call-tree disjoi…
begeistert Jun 13, 2026
fc18e17
fix(codegen): ISR context-save must cover R20-R23 and the Z pointer
begeistert Jun 13, 2026
1ee9a32
test(avr): Z-pointer interrupt safety (array-indexing ISR vs main)
begeistert Jun 13, 2026
315bab8
perf(avr): trim ISR context save to registers the handler actually cl…
begeistert Jun 14, 2026
db5fef5
test(avr): cover signed print(int8/int16) regression
begeistert Jun 14, 2026
139790a
test(avr): cover constant floor-mod folding
begeistert Jun 14, 2026
63f7a97
feat(avr): emit signed floor div/mod routines for signed operands
begeistert Jun 14, 2026
13adde9
test(avr): exhaustive signed floor div/mod validation
begeistert Jun 14, 2026
07ee241
test(avr): cover print(int32) over the full range
begeistert Jun 14, 2026
9db24f2
fix(avr): sign-extend arithmetic right shift by whole-byte amounts
begeistert Jun 14, 2026
1612bb9
test(avr): signed arithmetic property + wide-shift coverage
begeistert Jun 14, 2026
3f2f0f5
perf(avr): eliminate dead pure-writes (peephole)
begeistert Jun 14, 2026
4248fd1
docs(avr): record measured result of relaxing in-place to dst != src1
begeistert Jun 14, 2026
e07e8fd
perf(avr): extend the register home pool to R2-R15
begeistert Jun 14, 2026
2fbc1a0
test(avr): cover for-range loop variable and negative step
begeistert Jun 14, 2026
10bfc80
test(avr): cover simultaneous tuple swap/rotate
begeistert Jun 14, 2026
6e636c7
test(avr): cover continue/break in for-range
begeistert Jun 14, 2026
6c27405
test(avr): cover float() builtin cast
begeistert Jun 14, 2026
af93f31
test(avr): cover slice-as-iterable in for-loop
begeistert Jun 14, 2026
a41ad37
test(avr): cover break/continue in unrolled for-each and slice
begeistert Jun 14, 2026
b199d9c
test(avr): cover zip() over two runtime arrays
begeistert Jun 14, 2026
a7d98a9
test(avr): cover break/continue in enumerate()/reversed()
begeistert Jun 14, 2026
e8de650
test(avr): cover break/continue in list-literal for-each
begeistert Jun 15, 2026
166dd3a
test(avr): cover tuple[T, U] return annotation
begeistert Jun 15, 2026
801e18b
test(avr): cover walrus (:=) persistence
begeistert Jun 15, 2026
3414063
fix(avr): emit __mul32 for 32-bit multiply instead of truncating to 8…
begeistert Jun 15, 2026
5edc43b
test(avr): differential 32-bit multiply (low word, with overflow)
begeistert Jun 15, 2026
eb2b8ee
test(avr): for-each over SRAM arrays (uint8/uint16)
begeistert Jun 15, 2026
6719ec8
test(avr): ZCA write-back mutators persist across calls, loops, reset
begeistert Jun 15, 2026
774059b
test(avr): language-fidelity probe battery
begeistert Jun 15, 2026
56bdc44
test(avr): more fidelity probes (shifts, uint16 loops, globals, bytes)
begeistert Jun 15, 2026
693f07e
test(avr): probes for or/and short-circuit conditions, uint32, preced…
begeistert Jun 15, 2026
fefd33a
test(avr): compound and/or/not boolean conditions
begeistert Jun 15, 2026
0610db3
test(avr): and/or return-operand (Python value semantics)
begeistert Jun 15, 2026
6a4260a
test(avr): if/elif statement form with compound and/or conditions
begeistert Jun 15, 2026
baf65d1
test(avr): width casts and direct print of a signed cast
begeistert Jun 15, 2026
1a537c5
test(avr): float arithmetic, int<->float conversions, signed prints
begeistert Jun 15, 2026
e172594
test(avr): signedness through int8 SRAM arrays and function returns
begeistert Jun 15, 2026
c9634bf
test(avr): annotated decl with runtime array index; two SRAM loads
begeistert Jun 15, 2026
f798706
fix(avr): account for array/bytearray ops in linear-scan liveness
begeistert Jun 15, 2026
78f5924
test(avr): inline-computed array index in an expression
begeistert Jun 15, 2026
6beaebb
test(avr): bytearray and uint16 array two-load expressions
begeistert Jun 15, 2026
dc6d648
fix(avr): track IndirectCall/GcAlloc in liveness and as call boundaries
begeistert Jun 15, 2026
9df6822
test(avr): two indirect calls in one expression
begeistert Jun 15, 2026
a1174da
perf(avr): count IndirectCall/GcAlloc operands for R2-R15 allocation
begeistert Jun 15, 2026
3825c84
test(avr): multi-field ZCA mutation and field access
begeistert Jun 15, 2026
9883477
test(avr): multi-field ZCA with a uint16 field
begeistert Jun 15, 2026
54ddf9f
test(avr): enum arithmetic, lists, negative index, slicing
begeistert Jun 15, 2026
acc8ac5
test(avr): aug-assign on instance field, signed compare/abs, enums, l…
begeistert Jun 15, 2026
9dde23c
fix(avr): size-based argument register assignment (wide non-first args)
begeistert Jun 15, 2026
2bab499
test(avr): uint32 as a second argument and as a slot field
begeistert Jun 15, 2026
8cd4b25
test(avr): int32 signed arithmetic and instance-array field access
begeistert Jun 15, 2026
8725ae7
test(avr): uint32 global, bytearray param, bytes iter, uint16 div/mod
begeistert Jun 15, 2026
b748732
test(avr): no-method multi-field struct with a uint16 field
begeistert Jun 15, 2026
2dbb98a
test(avr): method call on an operator-overload result
begeistert Jun 16, 2026
1ce65cb
test(avr): inherited fields resolved in an overridden subclass method
begeistert Jun 16, 2026
6e6fdfb
fix(backend): make ad-hoc codesign idempotent and lock-serialized
begeistert Jun 16, 2026
2b10e02
test(avr): add @property getter/setter fidelity probe
begeistert Jun 16, 2026
643eadb
test(avr): seed MCUSR.PORF for live reset_reason getter
begeistert Jun 16, 2026
1b7f207
test(avr): add abs/min/max wide-value fidelity probe
begeistert Jun 16, 2026
1f3e241
test(avr): probe ternary mixed-width branches and uint16 aug-assign c…
begeistert Jun 16, 2026
b12e9af
test(avr): probe sum() over wide (uint16) elements
begeistert Jun 16, 2026
848a0e4
test(avr): probe indirect call with a wide (uint16) return
begeistert Jun 16, 2026
02611e5
test(avr): probe ternary call branch and arg eval order
begeistert Jun 16, 2026
a4993e2
test(avr): @property stress battery (7 probes)
begeistert Jun 16, 2026
be399cb
test(avr): dunder/inheritance battery + document inheritance limits
begeistert Jun 16, 2026
21bc329
test(avr): un-ignore super().__init__ and super().<method>() probes
begeistert Jun 16, 2026
25d45a3
test(avr): un-ignore multi-level inheritance resolution probe
begeistert Jun 16, 2026
b723ff4
test(avr): un-ignore template-method virtual dispatch probe
begeistert Jun 16, 2026
ac7137f
fix(avr): keep call-passthrough regions inline so deep inheritance re…
begeistert Jun 17, 2026
895c64d
test(avr): regression probe for DHT-style 3-level inheritance
begeistert Jun 17, 2026
38c240d
fix(avr): only outline byte-identical inline regions
begeistert Jun 17, 2026
5fc1022
test(avr): regression probe for 5-level inheritance chain
begeistert Jun 17, 2026
9b8a4e6
fix(avr): zero-extend from the source's real high byte in LoadIntoReg
begeistert Jun 17, 2026
4833780
test(avr): cover integer promotion model and adapt sreg-flags escape …
begeistert Jun 17, 2026
750c50d
test(avr): fidelity probes for floor-div/mod sign, power, swap and ch…
begeistert Jun 17, 2026
936e510
test(avr): fidelity probes for or/and value, bitnot, aug-assign wrap,…
begeistert Jun 17, 2026
22451ba
refactor(fixtures): use '//' for integer division now that '/' is rej…
begeistert Jun 17, 2026
68e2995
test(avr): cover '/' true division returning a float
begeistert Jun 17, 2026
79dd272
test(avr): cover un-annotated slice assignment to an inferred array
begeistert Jun 17, 2026
5d26ad2
test(avr): cover nested @inline closure capturing an enclosing variable
begeistert Jun 17, 2026
d14eb6a
test(avr): cover two-level inline closure capture
begeistert Jun 17, 2026
71982fc
test(avr): cover inline closure write-local, capture-by-ref and nonlocal
begeistert Jun 17, 2026
bad3243
test(avr): cover f-string lowering to print() stream writes
begeistert Jun 17, 2026
5653aea
test(avr): cover uart.write_str/println f-string lowering
begeistert Jun 17, 2026
639da32
test(avr): cover signed/unsigned mixed comparison
begeistert Jun 17, 2026
d85b05c
fix(avr): sign-extend narrow signed values to 32-bit in LoadIntoReg
begeistert Jun 17, 2026
ee039ab
test(avr): f-string format specs and 32-bit signed widening
begeistert Jun 17, 2026
5518dc6
fix(avr): pass and read arguments beyond the 4th (no more silent drop)
begeistert Jun 17, 2026
7236bec
test(avr): 5-arg passing and >R16..R25 argument rejection
begeistert Jun 17, 2026
b08918d
test(avr): lcd.print_str f-string compiles and runs
begeistert Jun 17, 2026
e8d2ea2
test(avr): runtime-indexed local array inside an @inline function
begeistert Jun 17, 2026
403f13d
feat(avr): pass arguments beyond R16..R25 via a fixed SRAM spill region
begeistert Jun 17, 2026
368e69e
test(avr): arguments passed via the SRAM spill region
begeistert Jun 17, 2026
d166700
fix(avr): store spilled arguments before loading register arguments
begeistert Jun 17, 2026
348d9ae
test(avr): spilled argument sourced from a nested call
begeistert Jun 17, 2026
075e471
test(avr): spill argument passing edge cases
begeistert Jun 17, 2026
c4c0b35
test(avr): wide bitwise-not, uint32 runtime div/mod, global array mut…
begeistert Jun 17, 2026
100b2f2
test(avr): augmented assign on instance field and slice with step
begeistert Jun 17, 2026
c55f758
test(avr): runtime divide-by-zero raises ZeroDivisionError
begeistert Jun 17, 2026
c914a0f
test(avr): try/except around a value-context division links and catches
begeistert Jun 17, 2026
a664df4
feat(avr): emit the unhandled-exception runtime for propagated uncaug…
begeistert Jun 17, 2026
774ddc7
test(avr): exception propagation, nested re-propagation, finally, rai…
begeistert Jun 17, 2026
9b7d963
test(avr): try/else, re-raise in except, second except clause
begeistert Jun 17, 2026
a9a3438
test(avr): finally before propagation/return, raise from @inline
begeistert Jun 17, 2026
9367ed0
test(avr): finally runs before break and continue
begeistert Jun 17, 2026
00e63c0
test(avr): exception-model edge cases (all passing, regression coverage)
begeistert Jun 17, 2026
613c7ac
test(avr): return in except handler runs finally; raise from a method
begeistert Jun 17, 2026
46e400c
test(avr): nested finally, constructor raise, bare re-raise, finally …
begeistert Jun 17, 2026
eb6f035
test(avr): bare re-raise preserves the code after the handler clobber…
begeistert Jun 17, 2026
54a85bf
test(avr): more exception-model edge cases (all passing)
begeistert Jun 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions examples/adc-interrupt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ instead of polling. `adc.irq(adc_isr)` registers the handler at the ADC vector,
enables `ADIE`, and sets the global interrupt flag (`SEI`) for you — no
`@interrupt` decorator or `asm("SEI")` needed.

The ISR reads `ADCL` first (which latches `ADCH`), stashes the low byte in
`GPIOR1`, and signals the main loop through bit `GPIOR0[1]`. The main loop prints
the result over UART and kicks off the next conversion.
The ISR reads `ADCL` first (which latches `ADCH`) and publishes the low byte
plus a done flag through two plain module globals. The compiler detects both as
ISR-shared (volatile semantics) and auto-promotes them to `GPIOR` registers, so
the handoff is single-cycle I/O with zero SRAM. The main loop prints the result
over UART and kicks off the next conversion.

## Hardware

Expand All @@ -27,7 +29,7 @@ conversion.
## Key concepts

- `AnalogPin.irq()` — zero-boilerplate ISR registration
- `GPIOR0`/`GPIOR1` general-purpose I/O registers used as atomic flags/storage
- ISR-shared plain globals — auto-promoted to `GPIOR` registers by the compiler
- Reading `ADCL` before `ADCH` to latch a coherent result

## Build & flash
Expand Down
26 changes: 16 additions & 10 deletions examples/adc-interrupt/src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,42 +4,48 @@
# (byte 0x002A / word 0x0015), enables ADIE, and sets SEI -- no
# @interrupt decorator or asm("SEI") needed.
#
# The ISR reads ADCL first (latches ADCH), stores the low byte in GPIOR1,
# and signals the main loop via GPIOR0[1].
# The ISR reads ADCL first (latches ADCH), publishes the low byte and a
# done flag through plain module globals. Both are detected as ISR-shared
# (volatile semantics) and auto-promoted to GPIOR registers, so the
# ISR<->main handoff is single-cycle I/O with zero SRAM.
# Main loop prints the result over UART and triggers the next conversion.
#
# Hardware: Arduino Uno
# - ADC0 = PC0 (analog input)
# - UART TX 9600 baud
#
from pymcu.types import uint8
from pymcu.chips.atmega328p import GPIOR0, GPIOR1, ADCL, ADCH
from pymcu.chips.atmega328p import ADCL, ADCH
from pymcu.hal.uart import UART
from pymcu.hal.adc import AnalogPin

# Written by the ISR, read by main. ISR-shared -> auto-promoted to GPIORs;
# both start at 0 on reset.
sample: uint8 = 0 # latest ADC low byte
done: uint8 = 0 # conversion-complete flag


def adc_isr():
# Must read ADCL first to latch ADCH.
GPIOR1.value = ADCL.value
GPIOR0[1] = 1
global sample, done
sample = ADCL.value
done = 1


def main():
uart = UART(9600)
adc = AnalogPin("PC0")
adc.irq(adc_isr)

GPIOR0[1] = 0
GPIOR1.value = 0
uart.println("ADC IRQ")

# Kick off first conversion
adc.start_conversion()

while True:
if GPIOR0[1] == 1:
GPIOR0[1] = 0
result: uint8 = GPIOR1.value
if done == 1:
done = 0
result: uint8 = sample
uart.write(result)
uart.write('\n')
# Start next conversion
Expand Down
15 changes: 15 additions & 0 deletions examples/analog-inout-mp/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[project]
name = "analog-inout-mp"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
"pymcu-stdlib>=0.1.0",
"pymcu-micropython>=0.1.0a1",
]

[tool.pymcu]
board = "arduino_uno"
frequency = 16000000
sources = "src"
entry = "main.py"
stdlib = ["micropython"]
21 changes: 21 additions & 0 deletions examples/analog-inout-mp/src/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Arduino "AnalogInOutSerial" (03.Analog), ported to PyMCU on the MicroPython
# compatibility layer (machine).
#
# Reads a potentiometer on A0, maps 0-1023 to a 0-255 PWM duty on D6 (OC0A), and
# echoes the duty byte over UART. Exercises machine.ADC, machine.PWM (both Pin
# overloads -- Pin(14) int for A0 and Pin("PD6") string) and machine.UART.
from machine import Pin, ADC, PWM, UART
from pymcu.types import uint8, uint16


def main():
uart = UART(0, 9600)
pot = ADC(Pin(14)) # Pin(14) == A0 == PC0 (int->name overload)
led = PWM(Pin("PD6")) # OC0A PWM output (str overload)
led.init()

while True:
sensor: uint16 = pot.read() # 0..1023
out: uint8 = uint8(sensor >> 2) # map 0..1023 -> 0..255 (Arduino map)
led.duty(out) # analogWrite(D6, out)
uart.write(out) # echo duty byte (sync marker for tests)
8 changes: 8 additions & 0 deletions examples/analog-inout/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[project]
name = "analog-inout"
version = "0.1.0"
[tool.pymcu]
target = "atmega328p"
frequency = 16000000
sources = "src"
entry = "main.py"
19 changes: 19 additions & 0 deletions examples/analog-inout/src/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Arduino "AnalogInOutSerial" (03.Analog), native PyMCU HAL.
# Read A0, map 0-1023 -> 0-255 PWM duty on D6, echo duty over UART.
from pymcu.types import uint8, uint16
from pymcu.hal.uart import UART
from pymcu.hal.adc import AnalogPin
from pymcu.hal.pwm import PWM


def main():
uart = UART(9600)
pot = AnalogPin("PC0")
led = PWM("PD6", 0)
led.start()

while True:
sensor: uint16 = pot.read()
out: uint8 = uint8(sensor >> 2)
led.set_duty(out)
uart.write(out)
83 changes: 0 additions & 83 deletions examples/dht-sensor/src/dht11.py

This file was deleted.

35 changes: 18 additions & 17 deletions examples/dht-sensor/src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
# Demonstrates:
# - Board abstractions: pymcu.boards.arduino_uno
# - Stdlib driver: pymcu.drivers.dht11 (arch-neutral ZCA, same pattern as Pin/UART)
# - Multi-file project: main.py is the only local file; drivers live in the stdlib
# - Multi-file project: main.py is the only local file; the driver lives in the stdlib
#
# sensor = DHT11("PD2") → D2 = "PD2" bound at compile time
# sensor.read() → match __CHIP__.arch → match pin_name (const[str]) → direct protocol
# sensor = DHT11(D2) → D2 = "PD2" bound at compile time
# sensor.read() → match __CHIP__.arch → match pin_name (const[str]) → shared protocol
#
# The driver stores only a const[str] pin name (a scalar field), so DHT11.read() is a
# zero-cost abstraction: the heavy bit-bang protocol lives in one shared _pd_read(bit)
# subroutine, not duplicated per instance.
#
# Wiring:
# DHT11 DATA → Arduino D2 (4.7 kΩ pull-up to +5 V)
Expand All @@ -21,31 +25,28 @@
from pymcu.hal.gpio import Pin
from pymcu.hal.uart import UART
from pymcu.time import delay_ms
from dht11 import DHT11


def nibble_hex(n: uint8) -> uint8:
if n < 10:
return n + 48
return n + 55
from pymcu.drivers.dht11 import DHT11


def main():
uart = UART(9600)
led = Pin(LED_BUILTIN, Pin.OUT)
data_pin = Pin(D2, Pin.IN) # DHT11 data pin — driver switches direction at runtime
sensor = DHT11(data_pin) # ZCA: sensor.pin tracks data_pin.name compile-time
uart = UART(9600)
led = Pin(LED_BUILTIN, Pin.OUT)
sensor = DHT11(D2) # ZCA: stores the const "PD2" name, no per-instance protocol copy

print("DHT11")

while True:
sensor.measure()
# read() returns uint16: high byte = humidity %, low byte = temperature °C.
# 0xFFFF signals a failure (no sensor, timeout or checksum mismatch).
data: uint16 = sensor.read()

if sensor.failed:
if data == 0xFFFF:
print("ERR")
led.low()
else:
print("H:", sensor.humidity, " T:", sensor.temperature, sep="")
humidity: uint8 = uint8(data >> 8)
temperature: uint8 = uint8(data & 0xFF)
print("H:", humidity, " T:", temperature, sep="")
led.high()

delay_ms(2000)
5 changes: 3 additions & 2 deletions examples/i2c-irq/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ Interrupt-driven I2C **peripheral** (TWI slave) at address 0x42.
Configures the TWI hardware as an I2C peripheral and registers an ISR with
`i2c.irq(handler)` (no `@interrupt` decorator or manual `TWIE`/`SEI` writes).
The ISR runs the TWI state machine — inspecting `TWSR`, ACKing each event, and
saving received data bytes to `GPIOR0` for the main loop to print as hex.
saving received data bytes to a plain module global (auto-promoted to a `GPIOR`
register by the compiler) for the main loop to print as hex.

> The ISR **must** re-arm the interrupt by writing `TWCR` with `TWINT=1`
> (`0xC4 = TWINT|TWEA|TWEN`) or the peripheral stalls.
Expand All @@ -26,7 +27,7 @@ saving received data bytes to `GPIOR0` for the main loop to print as hex.
## Key concepts

- TWI peripheral mode + interrupt-driven state machine
- `GPIOR0` as an atomic flag between ISR and main loop
- ISR-shared plain global between ISR and main — auto-promoted to a `GPIOR` register

## Build & flash

Expand Down
23 changes: 16 additions & 7 deletions examples/i2c-irq/src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
# - i2c.irq(handler): register ISR at TWI vector via compile_isr;
# no @interrupt decorator, TWCR.TWIE write, or asm("SEI") needed
# - TWI state machine in the ISR: check TWSR, ACK each event
# - GPIOR0 atomic storage: SBI/CBI are single-cycle IO instructions
# - ISR<->main handoff through a plain module global: detected as
# ISR-shared (volatile semantics) and auto-promoted to a GPIOR
# register, so the received byte moves through single-cycle I/O
#
# Hardware: Arduino Uno as I2C peripheral
# SDA = PC4 (Arduino pin A4) -- controlled by TWI hardware
Expand All @@ -17,22 +19,30 @@
# (bit 7) to re-arm the interrupt; otherwise the peripheral stalls.
# TWCR = 0xC4: TWINT(7)|TWEA(6)|TWEN(2).
#
# Note: a received 0x00 byte is indistinguishable from "no data" in this
# simple demo -- the main loop only reports non-zero bytes.
#
# Output:
# "I2CI\n" -- boot banner
# "XX\n" -- two hex digits for each data byte received from controller
#
from pymcu.types import uint8
from pymcu.chips.atmega328p import TWSR, TWDR, TWCR, GPIOR0
from pymcu.chips.atmega328p import TWSR, TWDR, TWCR
from pymcu.hal.i2c import I2C
from pymcu.hal.uart import UART

# Last received data byte, written by the ISR and consumed by main.
# ISR-shared -> auto-promoted to a GPIOR register; starts at 0 on reset.
rx: uint8 = 0


def on_event():
global rx
status: uint8 = TWSR.value & 0xF8
if status == 0x60: # own SLA+W received, ACK returned
TWCR.value = 0xC4 # TWINT | TWEA | TWEN -- ready for data
elif status == 0x80: # data byte received, ACK returned
GPIOR0[0] = TWDR.value # save byte for main loop
rx = TWDR.value # save byte for main loop
TWCR.value = 0xC4
elif status == 0xA0: # STOP or repeated START received
TWCR.value = 0xC4
Expand All @@ -48,12 +58,11 @@ def main():
# No @interrupt decorator or asm("SEI") needed.
i2c.irq(on_event)

GPIOR0[0] = 0
uart.println("I2CI")

while True:
if GPIOR0[0] != 0:
byte: uint8 = GPIOR0[0]
GPIOR0[0] = 0
if rx != 0:
byte: uint8 = rx
rx = 0
uart.write_hex(byte)
uart.write('\n')
5 changes: 3 additions & 2 deletions examples/interrupt-counter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ External interrupt (INT0) press counter.

`btn.irq(Pin.IRQ_FALLING, int0_isr)` configures the INT0 hardware interrupt on
**PD2** (falling edge), enables the interrupt mask, and sets `SEI` — no manual
`EICRA`/`EIMSK` writes. The ISR sets an atomic flag in `GPIOR0`; the main loop
`EICRA`/`EIMSK` writes. The ISR sets a plain module global — the compiler
detects it as ISR-shared and auto-promotes it to `GPIOR0` — and the main loop
clears it, increments a counter, toggles the LED, and sends the raw count over
UART.

Expand All @@ -20,7 +21,7 @@ UART.
## Key concepts

- `Pin.irq()` for hardware external interrupts
- `GPIOR0` SBI/CBI atomic flag pattern (ISR sets, main clears)
- ISR-shared plain global (ISR sets, main clears) — auto-promoted to `GPIOR0`, compiles to SBI/CBI/IN/OUT

## Build & flash

Expand Down
Loading
Loading