From 52986e214fb07f6a56cdc7d1b2f4dd9cd17463c5 Mon Sep 17 00:00:00 2001 From: occheung Date: Tue, 6 Oct 2020 15:03:53 +0800 Subject: [PATCH] flash: fix flash read --- src/flash.rs | 139 +++++++++++++++++++++------------------------------ src/fpga.rs | 91 +++++++++++++++++++++++++++++++++ src/main.rs | 68 ++++--------------------- 3 files changed, 158 insertions(+), 140 deletions(-) create mode 100644 src/fpga.rs diff --git a/src/flash.rs b/src/flash.rs index 374f371..d3ce0f6 100644 --- a/src/flash.rs +++ b/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, - SS: OutputPin, - RST: OutputPin, - DELAY: DelayUs, - 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, String) { + let mut key: String = String::new(); + let mut string: String = 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(()) - -} \ No newline at end of file +pub fn read_flash(addr: &mut u32) + -> (net::wire::IpCidr, net::wire::EthernetAddress, nal::Ipv4Addr, String) +{ + 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, + _ => {}, + } + } +} diff --git a/src/fpga.rs b/src/fpga.rs new file mode 100644 index 0000000..36c19a9 --- /dev/null +++ b/src/fpga.rs @@ -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, + SS: OutputPin, + RST: OutputPin, + DELAY: DelayUs, + 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(()) + +} diff --git a/src/main.rs b/src/main.rs index d79ded0..0b8df43 100644 --- a/src/main.rs +++ b/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 = 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)