forked from M-Labs/humpback-dds
flash: fix flash read
This commit is contained in:
parent
7e09318919
commit
52986e214f
141
src/flash.rs
141
src/flash.rs
|
@ -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>
|
};
|
||||||
|
if record_length == 0xFFFFFFFF {
|
||||||
|
return (key, string);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut key_string_div = false;
|
||||||
|
for f_addr in (*addr)+4..((*addr)+record_length) {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_flash(addr: &mut u32)
|
||||||
|
-> (net::wire::IpCidr, net::wire::EthernetAddress, nal::Ipv4Addr, String<U64>)
|
||||||
{
|
{
|
||||||
// Data buffer setup
|
let mut cidr = net::wire::IpCidr::Ipv6(
|
||||||
let mut dummy_byte :[u8; 1] = [0x00];
|
net::wire::Ipv6Cidr::SOLICITED_NODE_PREFIX,
|
||||||
let mut dummy_13_bytes :[u8; 13] = [0x00; 13];
|
);
|
||||||
|
let mut eth = net::wire::EthernetAddress::BROADCAST;
|
||||||
// Drive CRESET_B low
|
let mut ip = nal::Ipv4Addr::unspecified();
|
||||||
creset.set_low()
|
let mut name = String::new();
|
||||||
.map_err(|_| FPGAFlashError::NegotiationError)?;
|
loop {
|
||||||
|
let (key, string) = read_flash_str(addr);
|
||||||
// Drive SPI_SS_B low
|
if key.len() == 0 {
|
||||||
ss.set_low()
|
return (cidr, eth, ip, name);
|
||||||
.map_err(|_| FPGAFlashError::NegotiationError)?;
|
}
|
||||||
|
match key.as_str() {
|
||||||
// Wait at least 200ns
|
"CIDR" => cidr = net::wire::IpCidr::from_str(&string).unwrap(),
|
||||||
delay.delay_us(1_u32);
|
"MAC" => eth = net::wire::EthernetAddress::from_str(&string).unwrap(),
|
||||||
|
"BrokerIP" => ip = nal::Ipv4Addr::from_str(&string).unwrap(),
|
||||||
// Drive CRESET_B high
|
"Name" => name = string,
|
||||||
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(())
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -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(())
|
||||||
|
|
||||||
|
}
|
68
src/main.rs
68
src/main.rs
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue