Compare commits

..

No commits in common. "0adb0d5c51d0c483fc5e7845d0a26e8159c40e68" and "8a9dde611921e0881b518b34b1390a60949a9d45" have entirely different histories.

3 changed files with 141 additions and 237 deletions

View File

@ -1,6 +1,5 @@
//! Quad-SPI Flash Controller //! Quad-SPI Flash Controller
use crate::{print, println};
use core::marker::PhantomData; use core::marker::PhantomData;
use crate::regs::{RegisterR, RegisterW, RegisterRW}; use crate::regs::{RegisterR, RegisterW, RegisterRW};
use super::slcr; use super::slcr;
@ -11,8 +10,6 @@ mod bytes;
pub use bytes::{BytesTransferExt, BytesTransfer}; pub use bytes::{BytesTransferExt, BytesTransfer};
mod spi_flash_register; mod spi_flash_register;
use spi_flash_register::*; use spi_flash_register::*;
mod transfer;
use transfer::Transfer;
const FLASH_BAUD_RATE: u32 = 50_000_000; const FLASH_BAUD_RATE: u32 = 50_000_000;
/// 16 MB /// 16 MB
@ -27,12 +24,6 @@ const INST_READ: u8 = 0x03;
const INST_WRDI: u8 = 0x04; const INST_WRDI: u8 = 0x04;
/// Instruction: Write Enable /// Instruction: Write Enable
const INST_WREN: u8 = 0x06; const INST_WREN: u8 = 0x06;
/// Instruction: Program page
const INST_PP: u8 = 02;
/// Instruction: Sector Erase
const INST_SE: u8 = 0xD8;
/// Instruction: Erase 4K Block
const INST_BE_4K: u8 = 0x20;
#[derive(Clone)] #[derive(Clone)]
pub enum SpiWord { pub enum SpiWord {
@ -366,40 +357,9 @@ impl Flash<Manual> {
pub fn read_reg<R: SpiFlashRegister>(&mut self) -> R { pub fn read_reg<R: SpiFlashRegister>(&mut self) -> R {
let args = Some(R::inst_code()); let args = Some(R::inst_code());
let transfer = self.transfer(args.into_iter(), 2) let transfer = self.transfer(args.into_iter(), R::transfer_len())
.bytes_transfer(); .bytes_transfer().skip(1);
R::new(transfer.skip(1).next().unwrap()) R::new(transfer)
}
pub fn read_reg_until<R, F, A>(&mut self, f: F) -> A
where
R: SpiFlashRegister,
F: Fn(R) -> Option<A>,
{
let mut result = None;
while result.is_none() {
let args = Some(R::inst_code());
for b in self.transfer(args.into_iter(), 32)
.bytes_transfer().skip(1) {
result = f(R::new(b));
if result.is_none() {
break;
}
}
}
result.unwrap()
}
/// Status Register-1 remains `0x00` immediately after invoking a command.
fn wait_while_sr1_zeroed(&mut self) -> SR1 {
self.read_reg_until::<SR1, _, SR1>(|sr1|
if sr1.is_zeroed() {
None
} else {
Some(sr1)
}
)
} }
/// Read Identification /// Read Identification
@ -418,63 +378,12 @@ impl Flash<Manual> {
.bytes_transfer().skip(6).take(len) .bytes_transfer().skip(6).take(len)
} }
pub fn erase(&mut self, offset: u32) {
let args = Some(((INST_BE_4K as u32) << 24) | (offset as u32));
self.transfer(args.into_iter(), 4);
let sr1 = self.wait_while_sr1_zeroed();
if sr1.e_err() {
println!("E_ERR");
} else if sr1.p_err() {
println!("P_ERR");
} else if sr1.wip() {
print!("Erase in progress");
while self.read_reg::<SR1>().wip() {
print!(".");
}
println!("");
} else {
println!("erased? sr1={:02X}", sr1.inner);
}
}
pub fn program<I: Iterator<Item=u32>>(&mut self, offset: u32, data: I) {
{
let len = 4 + 4 * data.size_hint().0;
let args = Some(SpiWord::W32(((INST_PP as u32) << 24) | (offset as u32)))
.into_iter()
.chain(data.map(SpiWord::W32));
self.transfer(args, len);
}
// let sr1 = self.wait_while_sr1_zeroed();
let sr1 = self.read_reg::<SR1>();
if sr1.e_err() {
println!("E_ERR");
} else if sr1.p_err() {
println!("P_ERR");
} else if sr1.wip() {
println!("Program in progress");
while self.read_reg::<SR1>().wip() {
print!(".");
}
println!("");
} else {
println!("programmed? sr1={:02X}", sr1.inner);
}
}
pub fn write_enabled<F: Fn(&mut Self) -> R, R>(&mut self, f: F) -> R { pub fn write_enabled<F: Fn(&mut Self) -> R, R>(&mut self, f: F) -> R {
// Write Enable // Write Enable
let args = Some(INST_WREN); let args = Some(INST_WREN);
self.transfer(args.into_iter(), 1); self.transfer(args.into_iter(), 1);
self.regs.gpio.modify(|_, w| w.wp_n(true)); self.regs.gpio.modify(|_, w| w.wp_n(true));
let sr1 = self.wait_while_sr1_zeroed(); while !self.read_reg::<SR1>().wel() {}
if !sr1.wel() {
panic!("Cannot write-enable flash");
}
let result = f(self); let result = f(self);
@ -482,6 +391,7 @@ impl Flash<Manual> {
let args = Some(INST_WRDI); let args = Some(INST_WRDI);
self.transfer(args.into_iter(), 1); self.transfer(args.into_iter(), 1);
self.regs.gpio.modify(|_, w| w.wp_n(false)); self.regs.gpio.modify(|_, w| w.wp_n(false));
while self.read_reg::<SR1>().wel() {}
result result
} }
@ -493,4 +403,128 @@ impl Flash<Manual> {
{ {
Transfer::new(self, args, len) Transfer::new(self, args, len)
} }
}
pub struct Transfer<'a, Args: Iterator<Item = W>, W: Into<SpiWord>> {
flash: &'a mut Flash<Manual>,
args: Args,
sent: usize,
received: usize,
len: usize,
}
impl<'a, Args: Iterator<Item = W>, W: Into<SpiWord>> Transfer<'a, Args, W> {
pub fn new(flash: &'a mut Flash<Manual>, args: Args, len: usize) -> Self {
flash.regs.config.modify(|_, w| w.pcs(false));
flash.regs.enable.write(
regs::Enable::zeroed()
.spi_en(true)
);
let mut xfer = Transfer {
flash,
args,
sent: 0,
received: 0,
len,
};
xfer.fill_tx_fifo();
xfer.flash.regs.config.modify(|_, w| w.man_start_com(true));
xfer
}
fn fill_tx_fifo(&mut self) {
while self.sent < self.len && !self.flash.regs.intr_status.read().tx_fifo_full() {
let arg = self.args.next()
.map(|n| n.into())
.unwrap_or(SpiWord::W32(0));
match arg {
SpiWord::W32(w) => {
// println!("txd0 {:08X}", w);
unsafe {
self.flash.regs.txd0.write(w);
}
self.sent += 4;
}
// Only txd0 can be used without flushing
_ => {
if !self.flash.regs.intr_status.read().tx_fifo_not_full() {
// Flush if neccessary
self.flash.regs.config.modify(|_, w| w.man_start_com(true));
self.flash.wait_tx_fifo_flush();
}
match arg {
SpiWord::W8(w) => {
// println!("txd1 {:02X}", w);
unsafe {
self.flash.regs.txd1.write(u32::from(w) << 24);
}
self.sent += 1;
}
SpiWord::W16(w) => {
unsafe {
self.flash.regs.txd2.write(u32::from(w) << 16);
}
self.sent += 2;
}
SpiWord::W24(w) => {
unsafe {
self.flash.regs.txd3.write(w << 8);
}
self.sent += 3;
}
SpiWord::W32(_) => unreachable!(),
}
self.flash.regs.config.modify(|_, w| w.man_start_com(true));
self.flash.wait_tx_fifo_flush();
}
}
}
}
fn can_read(&mut self) -> bool {
self.flash.regs.intr_status.read().rx_fifo_not_empty()
}
fn read(&mut self) -> u32 {
let rx = self.flash.regs.rx_data.read();
self.received += 4;
rx
}
}
impl<'a, Args: Iterator<Item = W>, W: Into<SpiWord>> Drop for Transfer<'a, Args, W> {
fn drop(&mut self) {
// Discard remaining rx_data
while self.can_read() {
self.read();
}
// Stop
self.flash.regs.enable.write(
regs::Enable::zeroed()
.spi_en(false)
);
self.flash.regs.config.modify(|_, w| w
.pcs(true)
.man_start_com(false)
);
}
}
impl<'a, Args: Iterator<Item = W>, W: Into<SpiWord>> Iterator for Transfer<'a, Args, W> {
type Item = u32;
fn next<'s>(&'s mut self) -> Option<u32> {
if self.received >= self.len {
return None;
}
self.fill_tx_fifo();
while !self.can_read() {}
Some(self.read())
}
}

View File

@ -2,13 +2,13 @@ use bit_field::BitField;
pub trait SpiFlashRegister { pub trait SpiFlashRegister {
fn inst_code() -> u8; fn inst_code() -> u8;
fn new(src: u8) -> Self; fn transfer_len() -> usize;
fn new<I: Iterator<Item=u8>>(src: I) -> Self;
} }
macro_rules! u8_register { macro_rules! u8_register {
($name: ident, $doc: tt, $inst_code: expr) => { ($name: ident, $inst_code: expr) => {
#[derive(Clone)] #[derive(Clone)]
#[doc=$doc]
pub struct $name { pub struct $name {
pub inner: u8, pub inner: u8,
} }
@ -18,23 +18,21 @@ macro_rules! u8_register {
$inst_code $inst_code
} }
fn new(src: u8) -> Self { fn transfer_len() -> usize {
$name { 2
inner: src,
}
}
} }
impl $name { fn new<I: Iterator<Item=u8>>(mut src: I) -> Self {
pub fn is_zeroed(&self) -> bool { $name {
self.inner == 0 inner: src.next().unwrap(),
}
} }
} }
}; };
} }
u8_register!(CR, "Configuration Register", 0x35); u8_register!(CR, 0x35);
u8_register!(SR1, "Status Register-1", 0x05); u8_register!(SR1, 0x05);
impl SR1 { impl SR1 {
/// Write In Progress /// Write In Progress
pub fn wip(&self) -> bool { pub fn wip(&self) -> bool {
@ -57,5 +55,4 @@ impl SR1 {
} }
} }
u8_register!(SR2, "Status Register-2", 0x07); u8_register!(SR2, 0x07);
u8_register!(BA, "Bank Address Register", 0xB9);

View File

@ -1,127 +0,0 @@
use crate::regs::{RegisterR, RegisterW, RegisterRW};
use super::regs;
use super::{SpiWord, Flash, Manual};
pub struct Transfer<'a, Args: Iterator<Item = W>, W: Into<SpiWord>> {
flash: &'a mut Flash<Manual>,
args: Args,
sent: usize,
received: usize,
len: usize,
}
impl<'a, Args: Iterator<Item = W>, W: Into<SpiWord>> Transfer<'a, Args, W> {
pub fn new(flash: &'a mut Flash<Manual>, args: Args, len: usize) -> Self {
flash.regs.config.modify(|_, w| w.pcs(false));
flash.regs.enable.write(
regs::Enable::zeroed()
.spi_en(true)
);
let mut xfer = Transfer {
flash,
args,
sent: 0,
received: 0,
len,
};
xfer.fill_tx_fifo();
xfer.flash.regs.config.modify(|_, w| w.man_start_com(true));
xfer
}
fn fill_tx_fifo(&mut self) {
while self.sent < self.len && !self.flash.regs.intr_status.read().tx_fifo_full() {
let arg = self.args.next()
.map(|n| n.into())
.unwrap_or(SpiWord::W32(0));
match arg {
SpiWord::W32(w) => {
// println!("txd0 {:08X}", w);
unsafe {
self.flash.regs.txd0.write(w);
}
self.sent += 4;
}
// Only txd0 can be used without flushing
_ => {
if !self.flash.regs.intr_status.read().tx_fifo_not_full() {
// Flush if necessary
self.flash.regs.config.modify(|_, w| w.man_start_com(true));
self.flash.wait_tx_fifo_flush();
}
match arg {
SpiWord::W8(w) => {
// println!("txd1 {:02X}", w);
unsafe {
self.flash.regs.txd1.write(u32::from(w) << 24);
}
self.sent += 1;
}
SpiWord::W16(w) => {
unsafe {
self.flash.regs.txd2.write(u32::from(w) << 16);
}
self.sent += 2;
}
SpiWord::W24(w) => {
unsafe {
self.flash.regs.txd3.write(w << 8);
}
self.sent += 3;
}
SpiWord::W32(_) => unreachable!(),
}
self.flash.regs.config.modify(|_, w| w.man_start_com(true));
self.flash.wait_tx_fifo_flush();
}
}
}
}
fn can_read(&mut self) -> bool {
self.flash.regs.intr_status.read().rx_fifo_not_empty()
}
fn read(&mut self) -> u32 {
let rx = self.flash.regs.rx_data.read();
self.received += 4;
rx
}
}
impl<'a, Args: Iterator<Item = W>, W: Into<SpiWord>> Drop for Transfer<'a, Args, W> {
fn drop(&mut self) {
// Discard remaining rx_data
while self.can_read() {
self.read();
}
// Stop
self.flash.regs.enable.write(
regs::Enable::zeroed()
.spi_en(false)
);
self.flash.regs.config.modify(|_, w| w
.pcs(true)
.man_start_com(false)
);
}
}
impl<'a, Args: Iterator<Item = W>, W: Into<SpiWord>> Iterator for Transfer<'a, Args, W> {
type Item = u32;
fn next<'s>(&'s mut self) -> Option<u32> {
if self.received >= self.len {
return None;
}
self.fill_tx_fifo();
while !self.can_read() {}
Some(self.read())
}
}