dw3000_hw.c
ESP-IDF GPIO/IRQ backend for the DW3000 decadriver — implements dw3000_hw.h.
Overview
ESP-IDF GPIO/IRQ backend for the DW3000 decadriver — implements dw3000_hw.h. Replaces the Zephyr deps/dw3000/platform/dw3000_hw.c (not compiled here). IRQ mirrors the Zephyr design: the GPIO ISR wakes a dedicated high-priority task (pinned to core 1) that calls dwt_isr() while the IRQ line stays high — dwt_isr does SPI, so it cannot run in true ISR context. Also provides the cycle-counter diag symbols that dwt_uwb_driver/dw3000/dw3000_device.c references (Xtensa CCOUNT via esp_cpu_get_cycle_count).
depends on board_pins.h
API
Fuint32_t dw3000_dwt_cyccnt(void)
Return the current CPU cycle count, used as the DW3000 driver's cycle-counter timebase on this port.
Fvoid dw3000_hw_mark_asleep(void)
Mark the DW3000 as asleep. Does not itself put the chip to sleep; only updates local state.
Fbool dw3000_hw_is_asleep(void)
Return whether the DW3000 is currently marked asleep.
Fint dw3000_hw_init(void)
Initialize the DW3000 hardware port: configure the reset line as input (relying on an external pull-up, driven low only when active) and the wakeup line as output held high, then initialize SPI. Returns the result of dw3000_spi_init(); 0 on success.
Fstatic void IRAM_ATTR dw3000_gpio_isr(void *arg)
GPIO interrupt handler for the DW3000 IRQ line. Runs in IRAM. Latches the cycle count at interrupt time into g_dw_cyc_gpio, then signals s_irq_sem; yields to a higher-priority task if the semaphore give woke one.
Fstatic void dw3000_isr_task(void *arg)
Background task that services DW3000 interrupts: blocks on the IRQ semaphore, then calls dwt_isr() in a loop for as long as the IRQ line stays asserted. Records cycle-count timestamps (g_dw_cyc_work, g_dw_cyc_isrdone) around the service loop for latency diagnostics. Runs for the lifetime of the program; never returns.
Fint dw3000_hw_init_interrupt(void)
Configure the DW3000 IRQ GPIO, install the shared ISR service, and start the pinned ISR worker task. Idempotent: safe to call more than once, the ISR service and worker task are each created only once. The worker task runs on core 1 at priority 23 (above esp_timer and Thread) so DS-TWR slot callbacks (RX/TX-done) are not delayed by preemption; it is bursty and mostly blocked on the IRQ semaphore. Leaves the interrupt enabled. Returns 0 on success, -1 if the ISR service failed to install.
Fvoid dw3000_hw_interrupt_enable(void)
Re-enable the DW3000 IRQ GPIO interrupt after a prior disable. No-op if already enabled.
Fvoid dw3000_hw_interrupt_disable(void)
Disable the DW3000 IRQ GPIO interrupt. No-op if already disabled.
Fbool dw3000_hw_interrupt_is_enabled(void)
Return whether the DW3000 IRQ GPIO interrupt is currently enabled.
Fvoid dw3000_hw_reset(void)
Hardware-reset the DW3000 by pulsing the RESET pin low then releasing it to hi-Z. Blocks for about 3 ms total to let the chip climb to IDLE_RC. Clears the asleep flag.
Fvoid dw3000_hw_wakeup(void)
Wake the DW3000 from sleep if marked asleep; no-op otherwise. Drives the wake sequence over SPI, waits for the INIT_RC-to-IDLE_RC startup delay, clears the asleep flag, then polls dwt_checkidlerc() (up to ~5 ms) and logs an error if the chip never reaches IDLE_RC.
Fvoid dw3000_hw_wakeup_pin_low(void)
Drive the DW3000 WAKEUP pin low.
Fvoid dw3000_hw_fini(void)
Tear down the DW3000 hardware port: disable the IRQ line if enabled and finalize the SPI bus. Safe to call after dw3000_hw_init; leaves s_irq_enabled cleared.