use crate::domain::chip::ChipSpec;
use crate::domain::{
bad_block::BadBlockStrategy, EraseRequest, FlashOperation, OobMode, Progress, ReadRequest,
WriteRequest,
};
use crate::error::{Error, Result};
use crate::infrastructure::flash_protocol::commands::*;
use crate::infrastructure::programmer::ch341a::protocol::pins;
use crate::infrastructure::programmer::Programmer;
pub struct MicrowireEeprom<P: Programmer> {
programmer: P,
_spec: ChipSpec,
address_bits: u8,
_word_size: u8, }
impl<P: Programmer> MicrowireEeprom<P> {
pub fn new(programmer: P, spec: ChipSpec) -> Self {
let capacity = spec.capacity.as_bytes();
let address_bits = match capacity {
32 => 7, 128 => 7, 256 => 9, 512 => 9, 1024 => 11, 2048 => 11, _ => 9,
};
Self {
programmer,
_spec: spec,
address_bits,
_word_size: 8,
}
}
fn pulse_clk(&mut self) -> Result<()> {
self.programmer.gpio_set(pins::CLK, true)?;
self.programmer.gpio_set(pins::CLK, false)
}
fn send_bit(&mut self, bit: bool) -> Result<()> {
self.programmer.gpio_set(pins::DOUT, bit)?;
self.pulse_clk()
}
fn read_bit(&mut self) -> Result<bool> {
self.programmer.gpio_set(pins::CLK, true)?;
let bit = self.programmer.gpio_get(pins::DIN)?;
self.programmer.gpio_set(pins::CLK, false)?;
Ok(bit)
}
fn send_bits(&mut self, value: u32, count: u8) -> Result<()> {
for i in (0..count).rev() {
let bit = (value >> i) & 1 != 0;
self.send_bit(bit)?;
}
Ok(())
}
fn read_bits(&mut self, count: u8) -> Result<u32> {
let mut value = 0u32;
for _ in 0..count {
let bit = self.read_bit()?;
value = (value << 1) | (if bit { 1 } else { 0 });
}
Ok(value)
}
fn start(&mut self) -> Result<()> {
self.programmer.gpio_set(pins::CS, true)?;
self.send_bit(true)
}
fn stop(&mut self) -> Result<()> {
self.programmer.gpio_set(pins::CS, false)?;
self.programmer.gpio_set(pins::DOUT, false)
}
fn write_enable(&mut self, enable: bool) -> Result<()> {
self.start()?;
let op = MW_OP_EWEN; self.send_bits(op as u32, 2)?;
let addr = if enable {
0b11 << (self.address_bits - 2)
} else {
0
};
self.send_bits(addr, self.address_bits)?;
self.stop()
}
fn wait_ready(&mut self) -> Result<()> {
self.programmer.gpio_set(pins::CS, true)?;
let mut ready = false;
for _ in 0..1000 {
if self.programmer.gpio_get(pins::DIN)? {
ready = true;
break;
}
}
self.stop()?;
if !ready {
return Err(Error::Timeout);
}
Ok(())
}
}
impl<P: Programmer> FlashOperation for MicrowireEeprom<P> {
fn read(&mut self, request: ReadRequest, on_progress: &dyn Fn(Progress)) -> Result<Vec<u8>> {
let address = request.address.as_u32();
let length = request.length as usize;
let mut data = Vec::with_capacity(length);
for i in 0..length {
let curr_addr = address + i as u32;
let mut attempts = 0;
let byte = loop {
let res = (|| -> Result<u8> {
self.start()?;
self.send_bits(MW_OP_READ as u32, 2)?;
self.send_bits(curr_addr, self.address_bits)?;
let b = self.read_bits(8)? as u8;
self.stop()?;
Ok(b)
})();
match res {
Ok(b) => break b,
Err(e) => {
if attempts < request.retry_count {
attempts += 1;
log::warn!(
"Read error at 0x{:08X}, retrying (attempt {}): {}",
curr_addr,
attempts,
e
);
self.stop().ok(); continue;
} else {
return Err(e);
}
}
}
};
data.push(byte);
if i % 16 == 0 {
on_progress(Progress::new(i as u64, length as u64));
}
}
on_progress(Progress::new(length as u64, length as u64));
Ok(data)
}
fn write(&mut self, request: WriteRequest, on_progress: &dyn Fn(Progress)) -> Result<()> {
let address = request.address.as_u32();
let data = request.data;
self.write_enable(true)?;
for i in 0..data.len() {
let curr_addr = address + i as u32;
self.start()?;
self.send_bits(MW_OP_WRITE as u32, 2)?;
self.send_bits(curr_addr, self.address_bits)?;
self.send_bits(data[i] as u32, 8)?;
self.stop()?;
self.wait_ready()?;
if i % 4 == 0 {
on_progress(Progress::new(i as u64, data.len() as u64));
}
}
self.write_enable(false)?;
on_progress(Progress::new(data.len() as u64, data.len() as u64));
if request.verify {
let verify_req = ReadRequest {
address: request.address,
length: request.data.len() as u32,
use_ecc: false,
ignore_ecc_errors: false,
oob_mode: OobMode::None,
bad_block_strategy: BadBlockStrategy::Fail,
bbt: None,
retry_count: request.retry_count,
};
let read_back = self.read(verify_req, &|_| {})?;
if read_back != request.data {
for (i, (&actual, &expected)) in
read_back.iter().zip(request.data.iter()).enumerate()
{
if actual != expected {
return Err(Error::VerificationFailed {
address: request.address.as_u32() + i as u32,
expected,
actual,
});
}
}
}
}
Ok(())
}
fn erase(&mut self, request: EraseRequest, on_progress: &dyn Fn(Progress)) -> Result<()> {
let fill_data = vec![0xFF; request.length as usize];
let write_req = WriteRequest {
address: request.address,
data: &fill_data,
verify: false,
use_ecc: false,
ignore_ecc_errors: false,
oob_mode: OobMode::None,
bad_block_strategy: BadBlockStrategy::Fail,
bbt: None,
retry_count: 0,
};
self.write(write_req, on_progress)
}
}