usecrate::protocol::START_BYTE; usecrate::transport::Transport; use spidev::{SpiModeFlags, Spidev, SpidevOptions}; use std::io; use std::io::{Read, Write}; use std::path::Path; use std::thread; use std::time::{Duration, Instant};
// RT500RM 18.7.2.9.1 SPI In-System Programming - Introduction // "The application processor (namely, host) can use the feature nIRQ pin to improve the // communication performance between it and the boot ROM, which can be enabled by the SetProperty // <nIRQ pin tag> <nIRQ pin> command. // // Once being enabled, the host waits until it catches a negative edge on the nIRQ pin before // reading any data from the boot ROM, and it also needs to suspend until the nIRQ pin is HIGH // before sending any commands/data to the boot ROM." // // Note that this is documented on the SPI interface, but it also applies to I2C.
impl Transport for SpiTransport { fn read(&mutself, buf: &mut [u8], deadline: Instant) -> io::Result<()> { self.wait_for_read(deadline)?;
// NOTE: Given that self.spi is a SPI initiator, it doesn't really make sense to consider // deadline here, since we will perform the transfer immediately. let n = self.spi.read(buf)?; if n != buf.len() { // This should never happen. return Err(io::Error::other(format!( "spidev short read: {} != {}",
n,
buf.len()
)));
}
Ok(())
}
// From 18.7.2.6.8 Host read ACK(5a,a1) packet timing restriction: // """ // If not use the IRQ pin for the In-System Programming protocol, the host // needs to follow the below data fetching timing for ACK from the device. // // 1. After sending out the command, the host needs to wait for at least 100us // before polling the start byte 0x5A of the ACK packet sent out by the // device; If fetching data is not 0x5A, delay 100us, and do polling to // reread 0x5A. // 2. For the ACK packet 0x5A, 0xA1, after the host receives the 0x5A, a 50us // delay must add before fetching the 0xA1 from the device. // """ // // The guidance above applies to ReadAck(), but we choose to apply it here to // any packet which starts with a sync byte.
// First read the start byte. let start_buf = buf.get_mut(0..1).unwrap(); // length checked on entry loop { if Instant::now() > deadline { return Err(io::Error::new(
io::ErrorKind::TimedOut, "Timed out waiting for start byte",
));
};
// NOTE: Given that self.spi is a SPI initiator, it doesn't really make sense to consider // deadline here, since we will perform the transfer immediately. let n = self.spi.write(buf)?; if n != buf.len() { // This should never happen. return Err(io::Error::other(format!( "spidev short write: {} != {}",
n,
buf.len()
)));
}
Ok(())
}
fn set_irq_line(&mutself, line: &gpio_cdev::Line) -> io::Result<()> { // TODO: Change to line.events(..., EventRequestFlags::BOTH_EDGES, ...) and handle events, // taking stale events into consideration. let irq_line = line
.request(gpio_cdev::LineRequestFlags::INPUT, 0, GPIO_CONSUMER_LABEL)
.map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
format!("Error opening GPIO line event handle: {}", err),
)
})?; self.irq_line = Some(irq_line);
Ok(())
}
}
// RT500RM 18.7.2.9.1 Introduction // "needs to be configured to Mode 3 and 8 data bits mode" let options = SpidevOptions::new()
.bits_per_word(8)
.max_speed_hz(max_speed_hz)
.mode(SpiModeFlags::SPI_MODE_3)
.build();
spi.configure(&options)?;
Ok(Self {
spi,
irq_line: None,
})
}
fn is_polling(&self) -> bool { // If we are not using the IRQn feature, then we are using polling mode. self.irq_line.is_none()
}
fn wait_for_read(&mutself, deadline: Instant) -> io::Result<()> { // "the host waits until it catches a negative edge on the nIRQ pin before reading any data // from the boot ROM," // TODO(b/409399041): Polling the value is not safe for read: we _must_ look for a falling // edge. self.wait_for_irq_line(false, deadline)
}
fn wait_for_write(&mutself, deadline: Instant) -> io::Result<()> { // "...and it also needs to suspend until the nIRQ pin is HIGH before sending any // commands/data to the boot ROM." self.wait_for_irq_line(true, deadline)
}
/// Waits for the irq_line to transition to the given level (false=low; true=high). /// /// Does nothing and returns immediately if the irq line is not configured (polling mode). fn wait_for_irq_line(&mutself, desired_level: bool, deadline: Instant) -> io::Result<()> { iflet Some(irq_line) = &self.irq_line { loop { if Instant::now() > deadline { return Err(io::Error::new(
io::ErrorKind::TimedOut, "Timed out waiting for IRQ line",
));
} // TODO(b/409399041): Polling the value is not safe for read: we _must_ look for a // falling edge. let current_level: bool = irq_line
.get_value()
.map_err(|_| io::Error::other("Failed to get irq line state"))?
!= 0; if current_level == desired_level { break;
}
}
}
Ok(())
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-06-28)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.