forked from M-Labs/humpback-dds
flash: fix flash read
This commit is contained in:
parent
7e09318919
commit
52986e214f
139
src/flash.rs
139
src/flash.rs
@ -1,91 +1,64 @@
|
||||
use embedded_hal::{
|
||||
digital::v2::{OutputPin, InputPin},
|
||||
blocking::spi::Transfer,
|
||||
blocking::delay::DelayUs,
|
||||
};
|
||||
use heapless::{String, consts::*};
|
||||
use smoltcp as net;
|
||||
use embedded_nal as nal;
|
||||
use core::str::FromStr;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum FPGAFlashError {
|
||||
SPICommunicationError,
|
||||
NegotiationError,
|
||||
ResetStatusError,
|
||||
unsafe fn read_record_length(addr: u32) -> u32 {
|
||||
core::ptr::read(addr as *const u32)
|
||||
}
|
||||
|
||||
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
|
||||
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),
|
||||
fn read_flash_str(addr: &mut u32) -> (String<U32>, String<U64>) {
|
||||
let mut key: String<U32> = String::new();
|
||||
let mut string: String<U64> = String::new();
|
||||
|
||||
let record_length = unsafe {
|
||||
read_record_length(*addr)
|
||||
};
|
||||
|
||||
// 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)?;
|
||||
if record_length == 0xFFFFFFFF {
|
||||
return (key, string);
|
||||
}
|
||||
|
||||
// Drive SPI_SS_B high
|
||||
ss.set_high()
|
||||
.map_err(|_| FPGAFlashError::NegotiationError)?;
|
||||
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)
|
||||
}
|
||||
|
||||
// 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(())
|
||||
|
||||
}
|
||||
pub fn read_flash(addr: &mut u32)
|
||||
-> (net::wire::IpCidr, net::wire::EthernetAddress, nal::Ipv4Addr, String<U64>)
|
||||
{
|
||||
let mut cidr = net::wire::IpCidr::Ipv6(
|
||||
net::wire::Ipv6Cidr::SOLICITED_NODE_PREFIX,
|
||||
);
|
||||
let mut eth = net::wire::EthernetAddress::BROADCAST;
|
||||
let mut ip = nal::Ipv4Addr::unspecified();
|
||||
let mut name = String::new();
|
||||
loop {
|
||||
let (key, string) = read_flash_str(addr);
|
||||
if key.len() == 0 {
|
||||
return (cidr, eth, ip, name);
|
||||
}
|
||||
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
91
src/fpga.rs
Normal 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(())
|
||||
|
||||
}
|
68
src/main.rs
68
src/main.rs
@ -10,7 +10,7 @@ use stm32h7xx_hal::ethernet;
|
||||
|
||||
use smoltcp as net;
|
||||
use minimq::{
|
||||
embedded_nal::{ IpAddr, Ipv4Addr },
|
||||
embedded_nal::IpAddr,
|
||||
MqttClient, QoS
|
||||
};
|
||||
|
||||
@ -20,8 +20,6 @@ use rtic::cyccnt::{Instant, U32Ext};
|
||||
|
||||
use heapless::{ String, consts, consts::* };
|
||||
|
||||
use core::convert::TryInto;
|
||||
|
||||
#[macro_use]
|
||||
pub mod bitmask_macro;
|
||||
pub mod spi_slave;
|
||||
@ -32,12 +30,14 @@ pub mod attenuator;
|
||||
pub mod dds;
|
||||
pub mod nal_tcp_client;
|
||||
use crate::nal_tcp_client::{ NetStorage, NetworkStack };
|
||||
pub mod flash;
|
||||
use crate::flash::flash_ice40_fpga;
|
||||
pub mod fpga;
|
||||
use crate::fpga::flash_ice40_fpga;
|
||||
pub mod mqtt_mux;
|
||||
use crate::mqtt_mux::MqttMux;
|
||||
pub mod urukul;
|
||||
use crate::urukul::Urukul;
|
||||
pub mod flash;
|
||||
use crate::flash::read_flash;
|
||||
|
||||
mod logger;
|
||||
|
||||
@ -104,6 +104,12 @@ fn main() -> ! {
|
||||
|
||||
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 gpiob = dp.GPIOB.split(ccdr.peripheral.GPIOB);
|
||||
let gpioc = dp.GPIOC.split(ccdr.peripheral.GPIOC);
|
||||
@ -112,58 +118,6 @@ fn main() -> ! {
|
||||
let gpiof = dp.GPIOF.split(ccdr.peripheral.GPIOF);
|
||||
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:
|
||||
// - FPGA_SPI: SCK (af5)
|
||||
// - ST_LINK SWO (af0)
|
||||
|
Loading…
Reference in New Issue
Block a user