Skip to content

factory_buzzer

The factory_buzzer module is a minimal, synchronous buzzer driver used exclusively within the Factory Application. It provides simple audio feedback — a single short beep — during factory test, firmware flashing, and OTA operations, using a bit-banged square-wave technique that requires no LEDC/PWM peripheral and no FreeRTOS infrastructure.

Scope: This module covers the factory-app-level buzzer only. For the main pendant firmware’s full-featured buzzer (LEDC PWM + FreeRTOS task + tone sequences), see bsp_buzzer.


factory_buzzer is one of several per-board hardware drivers that form the factory application’s thin hardware abstraction layer. It sits alongside factory_buttons, factory_encoder, factory_touch, and factory_lcd_drivers as a direct child of factory_app.

Factory Application

factory_core

app_main · menus · update actions

factory_graphics

gfx_* · snap_*

factory_buttons

buttons_init · button_is_pressed

factory_buzzer

buzzer_init · buzzer_beep_short

factory_encoder

encoder_init · encoder_read

factory_touch

touch_init · touch_read

factory_lcd_drivers

st7796_* · st7262_* · ili9341_*

factory_sdcard

sdcard_mount · sdcard_unmount

custom_bootloader

pibot only · pre-app beeps


The factory buzzer is intentionally minimal. The factory application runs before the main firmware is active and must operate in a stripped-down environment — no RTOS scheduler dependence, no heap pressure, no LEDC timer setup. The bit-bang approach satisfies all these constraints with zero peripheral configuration overhead.

The table below contrasts it with the full bsp_buzzer used by the main pendant firmware:

Aspectfactory_buzzerbsp_buzzer (main app)
Signal generationBit-bang GPIO toggleLEDC hardware PWM
Execution modelSynchronous / blockingFreeRTOS task + queue
InterfacePlain C functionsC++ Buzzer class
Tone controlFixed — 2700 Hz / 40 msbuzzer_tone_t[] sequences
Frequency rangeSingle fixed valueArbitrary per-tone freq_hz
ESP-IDF dependenciesdriver/gpio.h, esp_rom_sys.hLEDC, FreeRTOS, semaphore
Dynamic allocationNonemalloc for tone array
ContextFactory app_main taskAny FreeRTOS task

The module is instantiated once per supported board. Each board’s hw_config.h defines BUZZER_PIN as the GPIO number allocated to the buzzer transducer.

Boards without a physical buzzer set BUZZER_PIN = GPIO_NUM_NC. All ESP32-S3 series boards and the newer ESP32 variants include a GPIO_IS_VALID_GPIO() guard that silently no-ops on such boards. The pibot_pendant_v1_0 is an older variant that predates the guard pattern — its BUZZER_PIN is always a real GPIO, so no guard is needed.

BoardPhysical buzzerGPIO_IS_VALID_GPIO guard
esp32_3248s035c✓✓
esp32_3248s035r✓✓
esp32s3_4827s043c✓✓
esp32s3_8048_touch_lcd_7✓✓
esp32s3_8048s043c✓✓
esp32s3_8048s050c✓✓
esp32s3_8048s070c✓✓
esp32s3_bzm_tft35_gt911✓✓
esp32s3_hmi43v3✓✓
esp32s3_zx3d50ce02s_usrc_4832✓✓
pibot_pendant_v1_0✓✗ (pin always valid)

Each board ships its own copy of buzzer.c under boards/<board>/Factory/main/. The implementations are functionally identical across all guarded boards; the pibot variant simply omits the guards.

boards/
├── esp32_3248s035c/Factory/main/buzzer.c
├── esp32_3248s035r/Factory/main/buzzer.c
├── esp32s3_4827s043c/Factory/main/buzzer.c
├── esp32s3_8048_touch_lcd_7/Factory/main/buzzer.c
├── esp32s3_8048s043c/Factory/main/buzzer.c
├── esp32s3_8048s050c/Factory/main/buzzer.c
├── esp32s3_8048s070c/Factory/main/buzzer.c
├── esp32s3_bzm_tft35_gt911/Factory/main/buzzer.c
├── esp32s3_hmi43v3/Factory/main/buzzer.c
├── esp32s3_zx3d50ce02s_usrc_4832/Factory/main/buzzer.c
└── pibot_pendant_v1_0/
├── Factory/main/buzzer.c ← factory app (no guard)
└── Factory/custom_bootloader/hooks.c ← bootloader-stage beeps

Configures BUZZER_PIN as a push-pull output and drives it low (silent).

  • If BUZZER_PIN == GPIO_NUM_NC, returns immediately without touching any register.
  • Must be called once from app_main before any call to buzzer_beep_short.
  • Uses gpio_config() via a gpio_config_t struct; the internal pin_bit() helper constructs the bitmask safely.

Emits a single short beep using a bit-banged square wave.

ParameterValueDerivation
Frequency2700 HzBEEP_FREQ_HZ
Duration40 msBEEP_DURATION_MS
Half-period≈ 185 µs1 000 000 / (2 × 2700)
Cycle count108(2700 × 40) / 1000
  • If BUZZER_PIN == GPIO_NUM_NC, returns immediately.
  • Blocking: occupies the calling task for ≈ 40 ms. In the factory application this is acceptable — the call is made from app_main before any LVGL scheduler starts and no real-time constraint applies at that point.

static uint64_t pin_bit(gpio_num_t pin) (internal)

Section titled “static uint64_t pin_bit(gpio_num_t pin) (internal)”

Returns the 64-bit GPIO bitmask required by gpio_config_t.pin_bit_mask. Returns 0 for invalid (negative) pins, preventing undefined behaviour from a negative shift count inside gpio_config().

static uint64_t pin_bit(gpio_num_t pin)
{
return GPIO_IS_VALID_GPIO(pin) ? (1ULL << pin) : 0ULL;
}

This helper does not appear in the pibot_pendant_v1_0 variant because that board unconditionally shifts a known-valid GPIO number.


← 185 µs →← 185 µs →
GPIO ____| HIGH | LOW | HIGH ...
× 108 cycles ≈ 40 ms total
ESP32 GPIO driverbuzzer_beep_short()factory app_mainESP32 GPIO driverbuzzer_beep_short()factory app_mainesp_rom_delay_us(185 µs)esp_rom_delay_us(185 µs)loop[108 cycles (~40 ms total)]buzzer_beep_short()gpio_set_level(BUZZER_PIN, 1)gpio_set_level(BUZZER_PIN, 0)return

No

Yes

No

Yes

app_main

buzzer_init

other hardware init

buttons · touch · display · encoder

GPIO_IS_VALID_GPIO

BUZZER_PIN ?

return - no-op

gpio_config push-pull output

set level LOW

Buzzer ready

User action / update event

buzzer_beep_short

GPIO_IS_VALID_GPIO

BUZZER_PIN ?

return - no-op

Generate 108 square-wave cycles

≈ 40 ms at 2700 Hz

return to caller


Custom Bootloader Variant (pibot_pendant_v1_0 only)

Section titled “Custom Bootloader Variant (pibot_pendant_v1_0 only)”

The pibot_pendant_v1_0 board ships a custom ESP-IDF bootloader component (Factory/custom_bootloader/hooks.c) that contains its own independent buzzer primitives. These execute at the bootloader stage — before the IDF application framework initialises — and therefore cannot share code or peripherals with the factory app layer.

The implementation uses gpio_ll_set_level() (direct register access) rather than gpio_set_level() to avoid any driver framework dependency.

FunctionFrequencyDurationPurpose
buzzer_tone(freq_hz, duration_ms)ConfigurableConfigurableGeneric bit-bang primitive
beep_short()2700 Hz100 msAcknowledges BTN3 press in recovery
beep_confirm()2700 Hz + 3200 Hz150 ms + 150 msConfirms OTA reset success

No

Yes

Timeout

Released

bootloader_after_init

Init GPIO:

buzzer → output

BTN3 → input + pull-up

Wait 100 ms - pull-up stabilise

BTN3 pressed?

Normal boot - no beep

beep_short

2700 Hz / 100 ms

acknowledge

Wait for BTN3 release

max 5 s

backup_and_erase_otadata

beep_confirm

2700 Hz + 3200 Hz

success

Software reset

factory partition boots

The bootloader variant is deliberately self-contained. It shares the same BUZZER_PIN definition via hw_config.h but is compiled as a separate ESP-IDF bootloader component and linked into the bootloader image, not into the factory application binary.


factory_buzzer

hw_config.h

BUZZER_PIN

driver/gpio.h

gpio_config · gpio_set_level

esp_rom_sys.h

esp_rom_delay_us

bsp_buzzer

main app - not used by factory

factory_buzzer is a leaf driver with no inter-module runtime dependencies. The only runtime relationship is that factory_core calls buzzer_beep_short() at action-confirmation points within app_main.


ModuleRelationship
bsp_buzzerMain application buzzer — LEDC + FreeRTOS; entirely separate subsystem, not used in factory context
factory_appParent; app_main calls buzzer_init() at startup and buzzer_beep_short() to confirm actions
factory_buttonsSibling input driver; both are initialised together in app_main
factory_hardware_driversSibling group containing the equivalent buzzer, buttons, encoder, and touch for the ESP32-S3 board family
custom_bootloaderpibot_pendant_v1_0 only — provides an independent register-level buzzer for pre-application recovery signalling