Skip to main content

Module hal_rp2040

Module hal_rp2040 

Source
Expand description

ATECC HAL implementation for the RP2040.

Backs the [atecc608b::AteccHal] trait by embassy_rp::i2c for normal transactions and by a temporary 100 kHz I2C write to address 0x00 for the ATECC wake token.

§Wake-token rationale

The ATECC608B detects a host-driven wake when SDA is held low for at least tWLO = 60 us. There are two ways to produce that waveform:

  1. GPIO bit-bang: reconfigure SDA as an output, drive it low for the required duration, release.
  2. I2C wake token at 100 kHz (what CryptoAuthLib does in lib/calib/calib_basic.c::calib_wakeup_i2c and every lib/hal/hal_i2c_*.c::hal_i2c_wake): drop the bus to 100 kHz so that the address byte of a regular I2C write to a NACK address (0x00) takes long enough to satisfy tWLO, then issue that write and ignore the inevitable NACK.

We use the second method. The first one ran into stability problems during bring-up: reconfiguring SDA between GPIO output and I2C alternate function created transient transitions that the dormant chip sometimes mis-interpreted as protocol noise, and led to intermittent 0x04 HAL errors on subsequent reads. The CryptoAuthLib method keeps the I2C controller in continuous control of the line and matches the reference implementation byte-for-byte. Restoring the bus to 400 kHz is automatic on the next Rp2040Hal::build_i2c call.

The post-pulse wait (tHTSU, ~4.5 ms before the chip responds to I2C) is the driver’s responsibility, not the HAL’s: crate::tasks indirectly calls atecc608b::wake::wake, which performs pulse_sda_low followed by a delay_us(WAKE_DELAY_US) of its own. Keeping the delay in the driver lets us tune it without recompiling the firmware crate and avoids a duplicated source of truth.

§Resource management

Because the I2C peripheral and the SDA/SCL pins are needed at two different bus frequencies (100 kHz for the wake token, 400 kHz otherwise), this HAL owns the [Peri] singletons directly rather than holding a long-lived I2c instance. Each transaction creates a fresh [I2c] via [Peri::reborrow], performs the operation, and drops the controller. The peripherals are released for the next transaction or for the next wake token.

Structs§

Irqs 🔒
Rp2040Button 🔒
Newtype wrapper that bridges embassy_rp::gpio::Input<'static> to the [Button] trait defined in hsm_firmware_logic.
Rp2040Hal 🔒
ATECC HAL bound to I2C0 on the RP2040.
Rp2040Led 🔒
Newtype wrapper that bridges embassy_rp::gpio::Output<'static> to the [Led] trait defined in hsm_firmware_logic.

Enums§

Rp2040HalError 🔒
Error type returned by the RP2040 HAL.

Constants§

I2C_FREQ_HZ 🔒
I2C bus frequency for normal command traffic. The ATECC608B supports up to 1 MHz; we run at the “fast mode” 400 kHz to match the typical layout constraints of breadboard / 2-layer PCB hardware. Lower if signal integrity is poor.
WAKE_TOKEN_ADDR 🔒
I2C address used to generate the wake token. CryptoAuthLib writes to address 0x00 (general call) so the dormant chip NACKs cleanly. Any address the chip does not respond to would do; sticking to 0x00 matches the reference implementation.
WAKE_TOKEN_FILLER 🔒
Filler byte for the wake-token write. RP2040’s I2C peripheral refuses zero-length writes; one filler byte is enough to make the controller happy, and the byte is never actually clocked out because the address is NACKed.
WAKE_TOKEN_FREQ_HZ 🔒
I2C bus frequency used only for the wake token. CryptoAuthLib drops to 100 kHz so a single byte time on the bus (~90 us address phase) exceeds the chip’s tWLO of 60 us. At 400 kHz an address byte is too short to be seen as a wake token, hence the temporary slowdown.

Functions§

I2C0_IRQ 🔒