Skip to content

Bug Report: alarm.pin.PinAlarm Mis-maps to Incorrect Pins on ESP32 Feather #10498

@keen101

Description

@keen101

Bug Report: alarm.pin.PinAlarm Mis-maps to Incorrect Pins on ESP32 Feather
Description

alarm.pin.PinAlarm consistently fails to wake the board on the configured pin. Instead, it wakes up on a completely different, incorrect, and seemingly random pin. This behavior has been observed with multiple confirmed RTC-capable GPIOs and appears to be a fundamental bug in the core alarm module's handling of the PinAlarm configuration.

Board Information

Board Name: Adafruit Feather HUZZAH32 with ESP32 (identified via serial console)

CircuitPython Version: 9.2.8 on 2025-05-28

CircuitPython Build: CircuitPython for the Adafruit Feather HUZZAH32 with ESP32

Hardware Setup

Adafruit Feather HUZZAH32 with ESP32

Adafruit Adalogger FeatherWing (with PCF8523 RTC) and microSD card inserted.

A wire connected from the INT pin on the Adalogger FeatherWing to the specified GPIO on the Feather board.

No other connections were made to the tested pins. The RTC INT output is an open-drain, active-low signal.

Reproduction Steps

Flash the above-mentioned CircuitPython firmware to the board.

Connect a wire from the Adalogger FeatherWing INT pin to the GPIO pin to be tested.

Upload the provided code.py to the board, ensuring the RTC_INTERRUPT_PIN constant is set to the correct pin.

Open the serial console to monitor the output.

Observe the wake-up behavior after the board enters deep sleep.

Expected Behavior

The board should wake up from deep sleep, and the alarm.wake_alarm.pin should report the exact pin that was configured in the alarm.pin.PinAlarm call.

Actual Behavior (Examples)

In all three tests, the PinAlarm wakes the board on a different pin.

Test 1: Configured GPIO32

Configured Pin: microcontroller.pin.GPIO32 (board.D32)

Actual Wakeup Pin: microcontroller.pin.GPIO9

Serial Output (from user's earlier test):

Board woke up! Wake reason: PinAlarm on microcontroller.pin.GPIO9 (RTC INT)
MISMATCH: Configured for board.D32, but woke up on microcontroller.pin.GPIO9!
Test 2: Configured GPIO27

Configured Pin: microcontroller.pin.GPIO27 (board.D27)

Actual Wakeup Pin: board.TX (microcontroller.pin.GPIO1)

Serial Output (from user's full log):

...
Adalogger PCF8523 RTC found and initialized.


Board woke up! Wake reason: PinAlarm on board.TX (RTC INT)
  MISMATCH: Configured for board.D27, but woke up on board.TX!
Current RTC time: 2025-07-17 23:03:56
RTC reports it lost power! Time will need to be set.

Wake Count: 1
Current Mode: INITIAL_FREQUENT_WAKEUPS
...
Test 3: Configured GPIO4

Configured Pin: microcontroller.pin.GPIO4 (board.A5)

Actual Wakeup Pin: microcontroller.pin.GPIO10

Serial Output (from user's full log):

...
Adalogger PCF8523 RTC found and initialized.


Board woke up! Wake reason: PinAlarm on microcontroller.pin.GPIO10 (RTC INT)
  MISMATCH: Configured for board.A5, but woke up on microcontroller.pin.GPIO10!
Current RTC time: 2025-07-17 23:10:58
RTC reports it lost power! Time will need to be set.

Wake Count: 2
Current Mode: INITIAL_FREQUENT_WAKEUPS
...
Code to Reproduce

Python

import board
import digitalio
import time
import microcontroller
import busio
from adafruit_pcf8523.pcf8523 import PCF8523
import adafruit_datetime as datetime
import alarm

# --- Configuration ---
# Change this to GPIO32, GPIO27, or GPIO4 for testing
# Example: RTC_INTERRUPT_PIN = microcontroller.pin.GPIO27
RTC_INTERRUPT_PIN = microcontroller.pin.GPIO4

INITIAL_DEEP_SLEEP_SECONDS = 5
INITIAL_FREQUENT_WAKEUPS_COUNT = 3

NORMAL_ULP_TIMER_BACKUP_SECONDS = 75
RTC_ALARM_INTERVAL_SECONDS = 60 

# --- Onboard LED Setup ---
try:
    led = digitalio.DigitalInOut(board.LED)
except AttributeError:
    try:
        led = digitalio.DigitalInOut(board.GPIO13)
    except AttributeError:
        while True:
            time.sleep(1)
led.direction = digitalio.Direction.OUTPUT

# Explicitly define GPIO3 (RX) and GPIO1 (TX) for control
try:
    gpio3_rx = digitalio.DigitalInOut(microcontroller.pin.GPIO3)
    gpio3_rx.direction = digitalio.Direction.INPUT
    gpio3_rx.pull = digitalio.Pull.UP
except Exception:
    gpio3_rx = None
try:
    gpio1_tx = digitalio.DigitalInOut(microcontroller.pin.GPIO1)
    gpio1_tx.direction = digitalio.Direction.INPUT
    gpio1_tx.pull = digitalio.Pull.UP
except Exception:
    gpio1_tx = None

def run_blink_code(num_blinks=3, blink_duration=0.2):
    for i in range(num_blinks):
        led.value = True
        time.sleep(blink_duration)
        led.value = False
        time.sleep(blink_duration)

# --- RTC Setup (for Adalogger FeatherWing with PCF8523) ---
try:
    i2c = busio.I2C(board.SCL, board.SDA)
    rtc = PCF8523(i2c)
except Exception:
    rtc = None

# --- Main Program Logic ---
wake_alarm = alarm.wake_alarm
if wake_alarm:
    if isinstance(wake_alarm, alarm.pin.PinAlarm):
        actual_wake_pin = wake_alarm.pin
    
try:
    if len(alarm.sleep_memory) < 1:
        alarm.sleep_memory = bytearray(1)
    wake_count = alarm.sleep_memory[0]
except Exception:
    wake_count = 0

if wake_count < INITIAL_FREQUENT_WAKEUPS_COUNT:
    current_mode = "INITIAL_FREQUENT_WAKEUPS"
    sleep_duration_seconds = INITIAL_DEEP_SLEEP_SECONDS
else:
    current_mode = "NORMAL_OPERATION"
    sleep_duration_seconds = NORMAL_ULP_TIMER_BACKUP_SECONDS

if current_mode == "INITIAL_FREQUENT_WAKEUPS":
    run_blink_code(num_blinks=1, blink_duration=0.2)
elif current_mode == "NORMAL_OPERATION":
    run_blink_code(num_blinks=3, blink_duration=0.2)

# --- Configure Wakeup Sources ---
alarms_to_set = []
ulp_timer_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + sleep_duration_seconds)
alarms_to_set.append(ulp_timer_alarm)

if rtc and current_mode == "NORMAL_OPERATION":
    rtc.alarm_status = False
    now_struct_time = rtc.datetime
    next_alarm_minute = (now_struct_time.tm_min + 1) % 60
    next_alarm_hour = now_struct_time.tm_hour
    if next_alarm_minute == 0:
        next_alarm_hour = (next_alarm_hour + 1) % 24
    alarm_time_struct = time.struct_time((
        now_struct_time.tm_year, now_struct_time.tm_mon, now_struct_time.tm_mday,
        next_alarm_hour, next_alarm_minute, 0,
        now_struct_time.tm_wday, -1, -1
    ))
    rtc.alarm = (alarm_time_struct, "minutely")
    rtc.alarm_enable = True
elif rtc and current_mode == "INITIAL_FREQUENT_WAKEUPS":
    rtc.alarm_enable = False

rtc_pin_alarm = alarm.pin.PinAlarm(RTC_INTERRUPT_PIN, value=False)
alarms_to_set.append(rtc_pin_alarm)

wake_count += 1
alarm.sleep_memory[0] = wake_count & 0xFF

if gpio3_rx:
    gpio3_rx.deinit()
if gpio1_tx:
    gpio1_tx.deinit()
led.deinit()

time.sleep(1)
alarm.exit_and_deep_sleep_until_alarms(*alarms_to_set)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions