Skip to content

Latest commit

 

History

History
201 lines (163 loc) · 13.3 KB

CHANGELOG.md

File metadata and controls

201 lines (163 loc) · 13.3 KB

Changelog — pymcu-circuitpython

0.1.0b1 (re-frozen from main, 2026-09-30)

Beta 1 ships from main at 4fa38d6 today. One commit landed since the 2026-09-29 re-freeze:

Hardware validation

Two unmodified Adafruit libraries ran through this layer on a real Arduino Uno with the beta 1 compiler: adafruit_ssd1306 (with adafruit_framebuf and adafruit_bus_device, over busio.I2C) and adafruit_hcsr04 (its own simpletest). Every other Adafruit library figure for this release comes from compilation and the AVR emulator, not from a board.

Tests

  • corpus: re-baselined every program's size after pymcu-compiler's RFC 0013 phase 0 fix (every object of static duration is now zeroed at boot, matching what a real ATmega328P needs and an emulator that always started fresh state at zero used to hide). A program that keeps static state in SRAM pays the clear loop once, about +24 bytes (02_button_pullup 178 to 204, 21_digitalio_context 170 to 194), plus 2 bytes per register that homes static state (03_pwm_fade, 04_servo_sweep up to +38 bytes). A handful of programs moved down instead, from unrelated compiler work landed since the last baseline.

0.1.0b1 (re-frozen from main, 2026-09-29)

Beta 1 ships from main at f8677cc today. Three commits landed since the 2026-09-26 re-freeze:

Fixed

  • corpus: 42_except_as_e_args (try: raise RuntimeError("Timed out") except RuntimeError as e: print(e.args[0])) is re-baselined from 384 to 460 bytes. The growth is real and accepted, not a regression, and not related to floats: this program prints no float. Before pymcu-compiler's fix (79c7d411/3a0623c7/23135d73), e.args[0] on a raise with no message printed garbage, the interrupt vector table's own bytes, instead of raising IndexError: tuple index out of range the way CPython does. The fix adds that check, the "tuple index out of range" string, and an E:IndexError dispatcher entry. This program's own raise RuntimeError("Timed out") always carries a message, so its args[0] never actually raises, but the compiler cannot prove that no reachable raise in the program reaches this handler without one, so every handler reading e.args[0] pays for the check regardless. A follow-up fix in the same window (print(e.args[0]) no longer asking twice whether the raise carried a message) trimmed 6 bytes back off (466 to 460).
  • corpus: every program that prints a float is re-baselined after pymcu-compiler's float print policy fix (two fixed decimals, silently wrong, replaced by MicroPython's real algorithm): 4 corpus programs grow by roughly 4 KB each, the cost of the first _f32_repr/_f32_scale call in a program that did not already pay for a string-formatting runtime.

Tests

  • corpus: pwmio's variable-frequency PWM idiom (32_pwm_variable_frequency, the CircuitPython buzzer pattern of retuning an exact Timer1 channel at run time while keeping its duty cycle) now builds instead of being pinned as a refusal, and a sibling program pins the still-refused case (two exact-frequency channels sharing Timer1's ICR1). Both measured against pymcu-compiler main's stdlib, both front ends.

0.1.0b1 (re-frozen from main, 2026-09-26)

Beta 1 was first frozen on 2026-09-15 and the freeze was re-taken from main on 2026-09-26. These entries and the section below it are one release, split only by when the work landed.

Fixed

  • busio: I2C.writeto, readfrom_into and writeto_then_readfrom ignored the HAL's return values, so a NACKed transaction looked like a successful one and a try/except Exception around the call never ran — the dark-display field report. They now raise OSError with upstream's messages — [Errno 19] No such device for a NACKed address, [Errno 5] Input/output error for a failed START or a NACKed data byte — after sending STOP. That is the contract adafruit_bus_device.I2CDevice expects, so an absent device surfaces as its ValueError("No I2C device at address: 0x.."). The checks live in shared _i2c_writeto/_i2c_readfrom bodies rather than expanding at every call site, and the slice bounds reach them as compile-time constants, so the raise costs the display driver a fraction of what a per-site expansion did.
  • bitbangio: I2C follows the same contract on the software bus, reading the ACK bit the HAL bit-bang returns (0 = ACK).

0.1.0b1 (as frozen at 552e44c on 2026-09-15)

Beta 1: this layer moves out of alpha alongside the frontend (pymcu-compiler/pymcu-stdlib 0.1.0b1) and the AVR backend (pymcu-avr 0.1.0b1), since AVR is the only chip family with real CircuitPython hardware to compare against. Coverage on RP2040/RP2350 tracks the ARM backend, which stays alpha; keypad.KeyMatrix (#13) and the storage/os modules (#16) are out of beta 1 by decision.

Added

  • boards: adafruit_trinket, and pico as an alias of raspberry_pi_pico
  • microcontroller: disable_interrupts and enable_interrupts
  • a micropython module, providing const and nothing else
  • a sys module, providing implementation.name and nothing else
  • boards: board.I2C(), board.SPI() and board.UART() on the AVR Arduino boards (#7)
  • pulseio: PulseIn and PulseOut (#9)
  • servo: adafruit_motor.servo, so an angle lands on its pulse width (#8)
  • bitbangio: the same buses as busio, driven in software on any pins (#10)
  • rainbowio: colorwheel(pos), the colour at a position on the wheel (#15)
  • countio: Counter, the edges that arrived on a pin (#11)
  • keypad: Keys and Event, which button changed and which way (#13)
  • boards: board.I2C(), board.SPI() and board.UART() are back (#7)
  • rotaryio: IncrementalEncoder, where a two-track knob has turned to (#12)
  • boards: the bare 8-pin ATtinys answer to board.Dn
  • neopixel_write: the low-level one-wire write, as CircuitPython spells it
  • analogio,countio,digitalio,keypad,pwmio,rotaryio: exit matches upstream's (self, *args) arity
  • busio: start/end and configure() become keyword-only, matching upstream
  • bitbangio: start/end/configure() become keyword-only; write()'s buffer is spelled buf, and configure()'s baudrate default matches upstream's 100000
  • pulseio: PulseIn.bool answers len(pulses) > 0; exit matches upstream's arity
  • watchdog: WatchDogTimer is exported as the type of microcontroller.watchdog
  • microcontroller: implement RunMode and on_next_reset
  • keypad: Event gains timestamp, EventQueue is public, bool added

Fixed

  • microcontroller: cpu.frequency returns the clock instead of failing to compile
  • remove two MicroPython spellings and move WatchDogMode where upstream keeps it
  • alarm: the tail is written as the else it already logically is
  • net: refuse on a chip with no radio, and say that is the reason
  • pwmio: PWMOut.frequency reprograms the timer, and is refused without variable_frequency (#5)
  • pwmio: deinit() releases the pin as an input (PyMCU#296)
  • pwmio: the constructor leaves the start to the HAL (PyMCU#296)
  • pwmio: duty_cycle goes to the HAL as the 16-bit value it is (#30)
  • digitalio: deinit() releases the pin without pull, and switch_to_output sets the level first (PyMCU#309)
  • analogio: the value covers the whole range, the reference is the chip's, and AnalogOut is refused where there is no DAC (#21)
  • busio: every parameter reaches the hardware or is refused, and a read has a deadline (#22, #23, #24)
  • pwmio: frequency reports what the pin emits, and the first parameter is pin (#18)
  • time, supervisor, nvm, watchdog: four values that were not the part's (#26, #25, #16, #19)
  • microcontroller: uid refused rather than eight zeros, cpus has a length (#27)
  • alarm: wait on several alarms, and say which one fired (#20)
  • time: sleep() folds to one calibrated delay for a literal duration (#26)
  • microcontroller: len(nvm) is a literal again, because a slice of nvm needs one (#16)
  • digitalio: switch_to_output's value default is False, as upstream spells it
  • micropython: const()'s parameter is named expr, as upstream spells it
  • rainbowio: colorwheel()'s parameter is named n, as upstream spells it
  • watchdog: move WatchDogTimer into watchdog.py, breaking the import cycle

Changed

  • time: sleep() written with plain locals now that a constant survives one (PyMCU#327)

Documentation

  • the README describes the modules and the spellings that exist (#29)
  • neopixel_write joins the supported module table
  • corpus: triage the refused programs
  • readme: document the API surface this class of AVR chip will not provide
  • parity: regenerate the parity report

Tests

  • the conftest stubs CHIP as an object, pymcu.hal.irq, FREQ and the layer's own module names (#6)
  • the conftest binds TIMEBASE like FREQ (PyMCU#295)
  • the analogio mocks follow the HAL's ADC and DAC, and the tests measure what changed (#21)
  • the busio mocks follow the HAL, and the tests measure what reaches the hardware (#22, #23, #24, #7)
  • pulse mocks that behave like the HAL, and refuse like it (#9)
  • the PWM mock reports the frequency the pin emits (#18, #8)
  • soft I2C and SPI mocks that log what they clocked out (#10)
  • an edge-counter mock that refuses a single edge where the pin cannot tell (#11)
  • the four values, and an EEPROM mock that has a size (#26, #25, #16, #19)
  • the mock clock advances, because alarm waits on it (#20)
  • add a corpus of user-style programs with expected build outcomes and size gates
  • add CircuitPython API parity suite
  • parity: resolve symbolic stub defaults and accept exit(self, *args)
  • parity: allowlist real gaps tracked as GitHub issues
  • corpus: create the template's src directory, which git does not keep empty
  • corpus: resolve the pymcu driver from PyMCU's own repo venv, not a user project
  • corpus: flip four fixed programs to build, refresh all sizes

CI

  • add API parity and corpus GitHub Actions workflows

Reverted

  • board.I2C(), board.SPI() and board.UART(), which miscompile busio (#7)

0.1.0a2 — 2026-08-18

Everything the PyPI 0.1.0a1 layer (June) predates. With the 0.1.0a10 compiler, the canonical CircuitPython nvm pattern works end-to-end: microcontroller.nvm[0:4] = b'...' and print(microcontroller.nvm[0:4]) print the real CPython bytearray repr, verified against EEPROM on a real Arduino Uno.

New

  • microcontroller.nvm: EEPROM-backed persistent byte storage.
  • microcontroller.watchdog (WatchDogTimer) and microcontroller.cpu.reset_reason / ResetReason.
  • RP2040 support: board/digitalio/busio dispatch by architecture.

Changed

  • NeoPixel moved to its own library (pymcu-lib-neopixel).

Requires

  • pymcu-compiler >= 0.1.0a10 for the nvm slice forms; single-byte nvm[i] access works with earlier compilers.