flash: fix flash read

pull/4/head
occheung 2020-10-06 15:03:53 +08:00
parent 7e09318919
commit 52986e214f
3 changed files with 158 additions and 140 deletions

View File

@ -1,91 +1,64 @@
use embedded_hal::{ use heapless::{String, consts::*};
digital::v2::{OutputPin, InputPin}, use smoltcp as net;
blocking::spi::Transfer, use embedded_nal as nal;
blocking::delay::DelayUs, use core::str::FromStr;
};
#[derive(Debug)] unsafe fn read_record_length(addr: u32) -> u32 {
pub enum FPGAFlashError { core::ptr::read(addr as *const u32)
SPICommunicationError,
NegotiationError,
ResetStatusError,
} }
const DATA: &'static [u8] = include_bytes!("../build/top.bin"); unsafe fn read_byte(addr: u32) -> u8 {
core::ptr::read(addr as *const u8)
}
// A public method to flash iCE40 FPGA on Humpback fn read_flash_str(addr: &mut u32) -> (String<U32>, String<U64>) {
pub fn flash_ice40_fpga<SPI: Transfer<u8>, let mut key: String<U32> = String::new();
SS: OutputPin, let mut string: String<U64> = String::new();
RST: OutputPin,
DELAY: DelayUs<u32>, let record_length = unsafe {
DONE: InputPin> read_record_length(*addr)
(mut spi: SPI, mut ss: SS, mut creset: RST, cdone: DONE, mut delay: DELAY) -> Result<(), FPGAFlashError>
{
// Data buffer setup
let mut dummy_byte :[u8; 1] = [0x00];
let mut dummy_13_bytes :[u8; 13] = [0x00; 13];
// Drive CRESET_B low
creset.set_low()
.map_err(|_| FPGAFlashError::NegotiationError)?;
// Drive SPI_SS_B low
ss.set_low()
.map_err(|_| FPGAFlashError::NegotiationError)?;
// Wait at least 200ns
delay.delay_us(1_u32);
// Drive CRESET_B high
creset.set_high()
.map_err(|_| FPGAFlashError::NegotiationError)?;
// Wait at least another 1200us to clear internal config memory
delay.delay_us(1200_u32);
// Before data transmission starts, check if C_DONE is truly low
// If C_DONE is high, the FPGA reset procedure is unsuccessful
match cdone.is_low() {
Ok(true) => {},
_ => return Err(FPGAFlashError::ResetStatusError),
}; };
if record_length == 0xFFFFFFFF {
// Set SPI_SS_B high return (key, string);
ss.set_high()
.map_err(|_| FPGAFlashError::NegotiationError)?;
// Send 8 dummy clock, effectively 1 byte of 0x00
spi.transfer(&mut dummy_byte)
.map_err(|_| FPGAFlashError::SPICommunicationError)?;
// Drive SPI_SS_B low
ss.set_low()
.map_err(|_| FPGAFlashError::NegotiationError)?;
// Send the whole image without interruption
for byte in DATA.into_iter() {
let mut single_byte_slice = [*byte];
spi.transfer(&mut single_byte_slice)
.map_err(|_| FPGAFlashError::SPICommunicationError)?;
} }
// Drive SPI_SS_B high let mut key_string_div = false;
ss.set_high() for f_addr in (*addr)+4..((*addr)+record_length) {
.map_err(|_| FPGAFlashError::NegotiationError)?; if key_string_div {
string.push(unsafe {read_byte(f_addr)} as char).unwrap();
} else {
let c = unsafe {read_byte(f_addr)};
if c == 0 {
key_string_div = true;
} else {
key.push(c as char).unwrap();
}
}
}
*addr += record_length;
(key, string)
}
// Send at another 100 dummy clocks (choosing 13 bytes) pub fn read_flash(addr: &mut u32)
spi.transfer(&mut dummy_13_bytes) -> (net::wire::IpCidr, net::wire::EthernetAddress, nal::Ipv4Addr, String<U64>)
.map_err(|_| FPGAFlashError::SPICommunicationError)?; {
let mut cidr = net::wire::IpCidr::Ipv6(
// Check the CDONE output from FPGA net::wire::Ipv6Cidr::SOLICITED_NODE_PREFIX,
// CDONE needs to be high );
match cdone.is_high() { let mut eth = net::wire::EthernetAddress::BROADCAST;
Ok(true) => {}, let mut ip = nal::Ipv4Addr::unspecified();
_ => return Err(FPGAFlashError::ResetStatusError), let mut name = String::new();
}; loop {
let (key, string) = read_flash_str(addr);
// Send at least another 49 clock cycles to activate IO pins (choosing same 13 bytes) if key.len() == 0 {
spi.transfer(&mut dummy_13_bytes).map_err(|_| FPGAFlashError::SPICommunicationError)?; return (cidr, eth, ip, name);
Ok(()) }
match key.as_str() {
} "CIDR" => cidr = net::wire::IpCidr::from_str(&string).unwrap(),
"MAC" => eth = net::wire::EthernetAddress::from_str(&string).unwrap(),
"BrokerIP" => ip = nal::Ipv4Addr::from_str(&string).unwrap(),
"Name" => name = string,
_ => {},
}
}
}

91
src/fpga.rs Normal file
View File

@ -0,0 +1,91 @@
use embedded_hal::{
digital::v2::{OutputPin, InputPin},
blocking::spi::Transfer,
blocking::delay::DelayUs,
};
#[derive(Debug)]
pub enum FPGAFlashError {
SPICommunicationError,
NegotiationError,
ResetStatusError,
}
const DATA: &'static [u8] = include_bytes!("../build/top.bin");
// A public method to flash iCE40 FPGA on Humpback
pub fn flash_ice40_fpga<SPI: Transfer<u8>,
SS: OutputPin,
RST: OutputPin,
DELAY: DelayUs<u32>,
DONE: InputPin>
(mut spi: SPI, mut ss: SS, mut creset: RST, cdone: DONE, mut delay: DELAY) -> Result<(), FPGAFlashError>
{
// Data buffer setup
let mut dummy_byte :[u8; 1] = [0x00];
let mut dummy_13_bytes :[u8; 13] = [0x00; 13];
// Drive CRESET_B low
creset.set_low()
.map_err(|_| FPGAFlashError::NegotiationError)?;
// Drive SPI_SS_B low
ss.set_low()
.map_err(|_| FPGAFlashError::NegotiationError)?;
// Wait at least 200ns
delay.delay_us(1_u32);
// Drive CRESET_B high
creset.set_high()
.map_err(|_| FPGAFlashError::NegotiationError)?;
// Wait at least another 1200us to clear internal config memory
delay.delay_us(1200_u32);
// Before data transmission starts, check if C_DONE is truly low
// If C_DONE is high, the FPGA reset procedure is unsuccessful
match cdone.is_low() {
Ok(true) => {},
_ => return Err(FPGAFlashError::ResetStatusError),
};
// Set SPI_SS_B high
ss.set_high()
.map_err(|_| FPGAFlashError::NegotiationError)?;
// Send 8 dummy clock, effectively 1 byte of 0x00
spi.transfer(&mut dummy_byte)
.map_err(|_| FPGAFlashError::SPICommunicationError)?;
// Drive SPI_SS_B low
ss.set_low()
.map_err(|_| FPGAFlashError::NegotiationError)?;
// Send the whole image without interruption
for byte in DATA.into_iter() {
let mut single_byte_slice = [*byte];
spi.transfer(&mut single_byte_slice)
.map_err(|_| FPGAFlashError::SPICommunicationError)?;
}
// Drive SPI_SS_B high
ss.set_high()
.map_err(|_| FPGAFlashError::NegotiationError)?;
// Send at another 100 dummy clocks (choosing 13 bytes)
spi.transfer(&mut dummy_13_bytes)
.map_err(|_| FPGAFlashError::SPICommunicationError)?;
// Check the CDONE output from FPGA
// CDONE needs to be high
match cdone.is_high() {
Ok(true) => {},
_ => return Err(FPGAFlashError::ResetStatusError),
};
// Send at least another 49 clock cycles to activate IO pins (choosing same 13 bytes)
spi.transfer(&mut dummy_13_bytes).map_err(|_| FPGAFlashError::SPICommunicationError)?;
Ok(())
}

View File

@ -10,7 +10,7 @@ use stm32h7xx_hal::ethernet;
use smoltcp as net; use smoltcp as net;
use minimq::{ use minimq::{
embedded_nal::{ IpAddr, Ipv4Addr }, embedded_nal::IpAddr,
MqttClient, QoS MqttClient, QoS
}; };
@ -20,8 +20,6 @@ use rtic::cyccnt::{Instant, U32Ext};
use heapless::{ String, consts, consts::* }; use heapless::{ String, consts, consts::* };
use core::convert::TryInto;
#[macro_use] #[macro_use]
pub mod bitmask_macro; pub mod bitmask_macro;
pub mod spi_slave; pub mod spi_slave;
@ -32,12 +30,14 @@ pub mod attenuator;
pub mod dds; pub mod dds;
pub mod nal_tcp_client; pub mod nal_tcp_client;
use crate::nal_tcp_client::{ NetStorage, NetworkStack }; use crate::nal_tcp_client::{ NetStorage, NetworkStack };
pub mod flash; pub mod fpga;
use crate::flash::flash_ice40_fpga; use crate::fpga::flash_ice40_fpga;
pub mod mqtt_mux; pub mod mqtt_mux;
use crate::mqtt_mux::MqttMux; use crate::mqtt_mux::MqttMux;
pub mod urukul; pub mod urukul;
use crate::urukul::Urukul; use crate::urukul::Urukul;
pub mod flash;
use crate::flash::read_flash;
mod logger; mod logger;
@ -104,6 +104,12 @@ fn main() -> ! {
cp.DWT.enable_cycle_counter(); cp.DWT.enable_cycle_counter();
// Acquire client/broker IP Address, client MAC address from flash memory
let (ipv4_addr_cidr, mac_addr, broker_ipv4_addr, device_name) = {
let mut addr = 0x08100000;
read_flash(&mut addr)
};
let gpioa = dp.GPIOA.split(ccdr.peripheral.GPIOA); let gpioa = dp.GPIOA.split(ccdr.peripheral.GPIOA);
let gpiob = dp.GPIOB.split(ccdr.peripheral.GPIOB); let gpiob = dp.GPIOB.split(ccdr.peripheral.GPIOB);
let gpioc = dp.GPIOC.split(ccdr.peripheral.GPIOC); let gpioc = dp.GPIOC.split(ccdr.peripheral.GPIOC);
@ -112,58 +118,6 @@ fn main() -> ! {
let gpiof = dp.GPIOF.split(ccdr.peripheral.GPIOF); let gpiof = dp.GPIOF.split(ccdr.peripheral.GPIOF);
let gpiog = dp.GPIOG.split(ccdr.peripheral.GPIOG); let gpiog = dp.GPIOG.split(ccdr.peripheral.GPIOG);
// Acquire client/broker IP Address, client MAC address from flash memory
let ipv4_addr_cidr = unsafe {
let ipv4_bits = core::ptr::read(0x08100000 as *const u64);
net::wire::IpCidr::new(
net::wire::IpAddress::v4(
((ipv4_bits >> 32) & 0xFF).try_into().unwrap(),
((ipv4_bits >> 24) & 0xFF).try_into().unwrap(),
((ipv4_bits >> 16) & 0xFF).try_into().unwrap(),
((ipv4_bits >> 8) & 0xFF).try_into().unwrap()
),
((ipv4_bits >> 0) & 0xFF).try_into().unwrap()
)
};
let mac_addr = unsafe {
let mac_bits = core::ptr::read(0x08100020 as *const u64);
net::wire::EthernetAddress([
((mac_bits >> 40) & 0xFF).try_into().unwrap(),
((mac_bits >> 32) & 0xFF).try_into().unwrap(),
((mac_bits >> 24) & 0xFF).try_into().unwrap(),
((mac_bits >> 16) & 0xFF).try_into().unwrap(),
((mac_bits >> 8) & 0xFF).try_into().unwrap(),
(mac_bits & 0xFF).try_into().unwrap(),
])
};
let broker_ipv4_addr = unsafe {
let ipv4_bits = core::ptr::read(0x08100040 as *const u64);
Ipv4Addr::new(
((ipv4_bits >> 24) & 0xFF).try_into().unwrap(),
((ipv4_bits >> 16) & 0xFF).try_into().unwrap(),
((ipv4_bits >> 8) & 0xFF).try_into().unwrap(),
((ipv4_bits >> 0) & 0xFF).try_into().unwrap()
)
};
let device_name: String<U32> = unsafe {
let mut name = String::new();
let mut addr = 0x08100060;
loop {
let c = core::ptr::read(addr as *const u8);
if c == 4 {
break;
} else {
name.push(c as char).unwrap();
addr += 1;
}
}
name
};
// Note: ITM doesn't work beyond this, due to a pin conflict between: // Note: ITM doesn't work beyond this, due to a pin conflict between:
// - FPGA_SPI: SCK (af5) // - FPGA_SPI: SCK (af5)
// - ST_LINK SWO (af0) // - ST_LINK SWO (af0)