Skip to main content

Bring-Up Sequence

Work through these 10 steps in order. Each step has an expected serial output — do not proceed until you see it.


What: Flash the blink example. Confirm the board is alive and the serial port works.

Expected output:

I (xxx) main: Turning on LED
I (xxx) main: Turning off LED

Step 2 — I2C Scanner

What: Wire the DS3231. Run the I2C scanner from the I2C concepts doc.

Expected output:

Scanning I2C bus...
Found device at 0x68

Stop if: Nothing appears at 0x68. Check VCC (3.3 V), SDA→GPIO21, SCL→GPIO18, and that pull-ups are present on the breakout.


Step 3 — RTC Read

What: Call rtc_init() and rtc_get_time(). Print the result.

Expected output:

I (xxx) rtc: Time from RTC: 00:00:00 (or last set time if battery was inserted)
I (xxx) rtc: Temperature: 23.0°C

If the time reads 00:00:00 on Jan 1 2000, the RTC lost power (no battery or first use). This is fine — it will be set by NTP on first WiFi connect.


Step 4 — Button Test

What: Wire all 6 buttons. Run the polling test from the buttons wiring doc.

Expected output (press each button):

BTN_UP pressed
BTN_DOWN pressed
BTN_SELECT pressed
BTN_BACK pressed
BTN_SNOOZE pressed
BTN_DISMISS pressed

Step 5 — LittleFS Mount

What: Flash the LittleFS partition image with esptool.py write_flash (see the Audio Storage page). Call lfs_init() and lfs_list_alarms().

Expected output:

I (xxx) lfs: LittleFS mounted at /lfs
I (xxx) lfs: alarm.wav found, size 1234567 bytes

Stop if: "Failed to mount LittleFS partition 'lfs'". Confirm the lfs partition label in partitions.csv matches the driver config, and that the LittleFS image was flashed to the correct offset.


Step 6 — Display Init

What: Wire the display adapter. Call display_init().

Expected output:

I (xxx) display: BUSY LOW — display ready
I (xxx) display: Full refresh complete

The screen should show a blank white frame.

Stop if: "BUSY stuck HIGH after 5s". Check RST→GPIO4, BUSY→GPIO3, VCC on adapter.


Step 7 — Audio Playback

What: Wire the MAX98357A. Play alarm.wav at startup.

Expected output:

I (xxx) audio: Playing /lfs/alarms/alarm.wav
I (xxx) audio: Sample rate: 44100 Hz, channels: 1

Expected behaviour: Audio plays from the speaker.

Stop if: Silent. Check DIN→GPIO17, VIN→5V, SD pin state.


Step 8 — NTP Sync + RTC Write-Back

What: Connect to WiFi, sync NTP, write back to RTC.

Expected output:

I (xxx) wifi: Connected to MyNetwork
I (xxx) ntp: Synced: Wed Apr 16 14:32:00 2025
I (xxx) rtc: RTC updated from NTP

After this, call rtc_get_time() — it should return today's actual date and time.


Step 9 — Full Firmware

What: Flash the complete application (all tasks, state machine, alarm manager).

Expected output:

I (xxx) app: NVS init OK
I (xxx) lfs: LittleFS mounted at /lfs
I (xxx) rtc: System clock set: Wed Apr 16 14:32:00 2025
I (xxx) display: Clock screen rendered
I (xxx) wifi: Connecting...
I (xxx) wifi: Connected
I (xxx) ntp: Synced

Expected behaviour:

  • Clock displays current time
  • Buttons navigate menus
  • Setting an alarm 2 minutes out causes it to fire
  • Audio plays on alarm fire

Proceed to Step 10 to verify the discrete backup circuit, then to the smoke test to validate all behaviour.


Step 10 — Discrete Backup Circuit

What: Wire the ATtiny85 backup circuit (see the battery backup wiring guide). Program the DS3231 Alarm 1 to fire in 2 minutes, then disconnect USB.

Expected behaviour:

  • ATtiny wakes on DS3231 SQW interrupt
  • Buzzer sounds within 1 second of the alarm time
  • Pressing SNOOZE stops the buzzer (refires after ~9 minutes)
  • Pressing DISMISS stops the buzzer permanently

Stop if: Buzzer does not sound. Check AA supply voltage at ATtiny VCC (should be 2.7–3.2 V), SQW idle level (should be HIGH, ~3.3 V), and that the DS3231 alarm registers were written before USB was disconnected.