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:
- GPIO bit-bang: reconfigure SDA as an output, drive it low for the required duration, release.
- I2C wake token at 100 kHz (what CryptoAuthLib does in
lib/calib/calib_basic.c::calib_wakeup_i2cand everylib/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 satisfytWLO, 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 🔒
- Rp2040
Button 🔒 - Newtype wrapper that bridges
embassy_rp::gpio::Input<'static>to the [Button] trait defined inhsm_firmware_logic. - Rp2040
Hal 🔒 - ATECC HAL bound to I2C0 on the RP2040.
- Rp2040
Led 🔒 - Newtype wrapper that bridges
embassy_rp::gpio::Output<'static>to the [Led] trait defined inhsm_firmware_logic.
Enums§
- Rp2040
HalError 🔒 - 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 to0x00matches 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 🔒 ⚠