Wire SRAM mailbox polling into main idle loop (M6)
- Add FD pin (A1/PA04) as pull-up input for SRAM write detection - Configure NTAG5 FD pin for SRAM-write-by-RF indication at boot - Replace both idle loops with 200ms FD pin polling - On command received: process via sram::process_command, then reload active pattern from EEPROM into LP5562 - I2C bus swapped between NTAG5 and LP5562 as needed (zero-cost move via release()/new()) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
108
src/main.rs
108
src/main.rs
@@ -19,6 +19,7 @@ mod ntag5;
|
||||
mod pattern;
|
||||
use led::lp5562::{ClockSource, Lp5562, DEFAULT_ADDRESS};
|
||||
use ntag5::Ntag5Link;
|
||||
use ntag5::sram::MailboxState;
|
||||
use pattern::LedMode;
|
||||
|
||||
/// Blink the on-board LED n times (active-low: low=on, high=off)
|
||||
@@ -59,6 +60,9 @@ fn main() -> ! {
|
||||
lp_en.set_high().unwrap();
|
||||
delay.delay_ms(10u32); // Let LP5562 power stabilize
|
||||
|
||||
// NTAG5 FD pin on A1 (PA04) — input with pull-up (FD is open-drain)
|
||||
let fd_pin = pins.a1.into_pull_up_input();
|
||||
|
||||
// I2C on A4 (SDA) / A5 (SCL) at 400 kHz
|
||||
let i2c = bsp::i2c_master(
|
||||
&mut clocks,
|
||||
@@ -113,6 +117,9 @@ fn main() -> ! {
|
||||
}
|
||||
delay.delay_ms(500u32);
|
||||
|
||||
// Configure FD pin for SRAM-write-by-RF indication
|
||||
let _ = ntag.configure_fd_sram_write(); // Best-effort, non-fatal
|
||||
|
||||
// Try reading XBLK library header from upper 1K
|
||||
let mut header_buf = [0u8; pattern::HEADER_SIZE];
|
||||
let eeprom_ok = ntag.read_memory(pattern::LIBRARY_BASE_BLOCK, &mut header_buf).ok()
|
||||
@@ -131,20 +138,56 @@ fn main() -> ! {
|
||||
|
||||
match eeprom_pattern {
|
||||
Some(pat) => {
|
||||
// Reclaim I2C for LP5562
|
||||
let i2c = ntag.release();
|
||||
let mut lp = Lp5562::new(i2c, DEFAULT_ADDRESS);
|
||||
|
||||
// EEPROM pattern loaded — 3 fast blinks
|
||||
blink(&mut led, &mut delay, 3, 80);
|
||||
|
||||
if pattern::load_pattern(&mut lp, &pat, led_current, &mut delay).is_err() {
|
||||
blink(&mut led, &mut delay, 10, 50);
|
||||
// Load pattern into LP5562 (swap I2C to LP5562 then back)
|
||||
{
|
||||
let i2c = ntag.release();
|
||||
let mut lp = Lp5562::new(i2c, DEFAULT_ADDRESS);
|
||||
if pattern::load_pattern(&mut lp, &pat, led_current, &mut delay).is_err() {
|
||||
blink(&mut led, &mut delay, 10, 50);
|
||||
}
|
||||
let i2c = lp.release();
|
||||
ntag = Ntag5Link::new(i2c, ntag5::DEFAULT_ADDRESS);
|
||||
}
|
||||
|
||||
// LP5562 runs autonomously — MCU idles (future: STANDBY)
|
||||
// Mailbox polling loop — LP5562 runs autonomously,
|
||||
// MCU polls FD pin for NFC commands
|
||||
let mut mbox = MailboxState::new();
|
||||
loop {
|
||||
delay.delay_ms(60000u32);
|
||||
delay.delay_ms(200u32);
|
||||
if fd_pin.is_low().unwrap_or(false) {
|
||||
let cmd_ok = ntag5::sram::process_command(
|
||||
&mut ntag, &mut mbox, &mut delay,
|
||||
);
|
||||
if matches!(cmd_ok, Ok(true)) {
|
||||
// Reload LP5562 from current EEPROM state
|
||||
let mut hdr_buf = [0u8; pattern::HEADER_SIZE];
|
||||
if ntag.read_memory(pattern::LIBRARY_BASE_BLOCK, &mut hdr_buf).is_ok() {
|
||||
if let Some(hdr) = pattern::parse_header(&hdr_buf) {
|
||||
led_current = hdr.current;
|
||||
let pat_block = pattern::LIBRARY_BASE_BLOCK
|
||||
+ (pattern::HEADER_SIZE as u16 / 4)
|
||||
+ (hdr.active_index as u16
|
||||
* (pattern::PATTERN_ENTRY_SIZE as u16 / 4));
|
||||
let mut pat_buf = [0u8; pattern::PATTERN_ENTRY_SIZE];
|
||||
if ntag.read_memory(pat_block, &mut pat_buf).is_ok() {
|
||||
if let Some(new_pat) = pattern::parse_pattern_entry(&pat_buf) {
|
||||
// Swap I2C to LP5562 for reprogramming
|
||||
let i2c = ntag.release();
|
||||
let mut lp = Lp5562::new(i2c, DEFAULT_ADDRESS);
|
||||
let _ = pattern::load_pattern(
|
||||
&mut lp, &new_pat, led_current, &mut delay,
|
||||
);
|
||||
let i2c = lp.release();
|
||||
ntag = Ntag5Link::new(i2c, ntag5::DEFAULT_ADDRESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
@@ -219,17 +262,52 @@ fn main() -> ! {
|
||||
let loaded = ntag.read_memory(pat_base_block, &mut pat_buf).ok()
|
||||
.and_then(|()| pattern::parse_pattern_entry(&pat_buf));
|
||||
|
||||
let i2c = ntag.release();
|
||||
let mut lp = Lp5562::new(i2c, DEFAULT_ADDRESS);
|
||||
|
||||
if let Some(pat) = loaded {
|
||||
if pattern::load_pattern(&mut lp, &pat, led_current, &mut delay).is_err() {
|
||||
blink(&mut led, &mut delay, 10, 50);
|
||||
// Load into LP5562 (swap I2C), then swap back for mailbox
|
||||
{
|
||||
let i2c = ntag.release();
|
||||
let mut lp = Lp5562::new(i2c, DEFAULT_ADDRESS);
|
||||
if let Some(pat) = loaded {
|
||||
if pattern::load_pattern(&mut lp, &pat, led_current, &mut delay).is_err() {
|
||||
blink(&mut led, &mut delay, 10, 50);
|
||||
}
|
||||
}
|
||||
let i2c = lp.release();
|
||||
ntag = Ntag5Link::new(i2c, ntag5::DEFAULT_ADDRESS);
|
||||
}
|
||||
|
||||
// Mailbox polling loop (same as EEPROM-loaded path)
|
||||
let mut mbox = MailboxState::new();
|
||||
loop {
|
||||
delay.delay_ms(60000u32);
|
||||
delay.delay_ms(200u32);
|
||||
if fd_pin.is_low().unwrap_or(false) {
|
||||
let cmd_ok = ntag5::sram::process_command(
|
||||
&mut ntag, &mut mbox, &mut delay,
|
||||
);
|
||||
if matches!(cmd_ok, Ok(true)) {
|
||||
let mut hdr_buf = [0u8; pattern::HEADER_SIZE];
|
||||
if ntag.read_memory(pattern::LIBRARY_BASE_BLOCK, &mut hdr_buf).is_ok() {
|
||||
if let Some(hdr) = pattern::parse_header(&hdr_buf) {
|
||||
led_current = hdr.current;
|
||||
let pat_block = pattern::LIBRARY_BASE_BLOCK
|
||||
+ (pattern::HEADER_SIZE as u16 / 4)
|
||||
+ (hdr.active_index as u16
|
||||
* (pattern::PATTERN_ENTRY_SIZE as u16 / 4));
|
||||
let mut pat_buf2 = [0u8; pattern::PATTERN_ENTRY_SIZE];
|
||||
if ntag.read_memory(pat_block, &mut pat_buf2).is_ok() {
|
||||
if let Some(new_pat) = pattern::parse_pattern_entry(&pat_buf2) {
|
||||
let i2c = ntag.release();
|
||||
let mut lp = Lp5562::new(i2c, DEFAULT_ADDRESS);
|
||||
let _ = pattern::load_pattern(
|
||||
&mut lp, &new_pat, led_current, &mut delay,
|
||||
);
|
||||
let i2c = lp.release();
|
||||
ntag = Ntag5Link::new(i2c, ntag5::DEFAULT_ADDRESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Provisioning failed — fall back to hardcoded cycle
|
||||
|
||||
Reference in New Issue
Block a user