From e994000df1f0f3319b8ee172b3c7913f1c2faee1 Mon Sep 17 00:00:00 2001 From: occheung Date: Thu, 17 Sep 2020 11:21:24 +0800 Subject: [PATCH] fpga config: included into lib --- examples/fpga_config.rs | 61 ++----------------------- src/flash.rs | 99 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 57 deletions(-) create mode 100644 src/flash.rs diff --git a/examples/fpga_config.rs b/examples/fpga_config.rs index 18ddfe2..996406f 100644 --- a/examples/fpga_config.rs +++ b/examples/fpga_config.rs @@ -17,6 +17,8 @@ use cortex_m_rt::entry; use core::ptr; use nb::block; +use firmware::flash::flash_ice40_fpga; + #[path = "util/logger.rs"] mod logger; @@ -74,65 +76,10 @@ fn main() -> ! { &ccdr.clocks, ); - // Data buffer setup - let mut dummy_byte :[u8; 1] = [0x00]; - let mut dummy_13_bytes :[u8; 13] = [0x00; 13]; - - // Drive CRESET_B low - fpga_creset.set_low().unwrap(); - - // Drive SPI_SS_B low - fpga_ss.set_low().unwrap(); - - // Wait at least 200ns - delay.delay_us(1_u16); - - // Drive CRESET_B high - fpga_creset.set_high().unwrap(); - - // Wait at least another 1200us to clear internal config memory - delay.delay_us(1200_u16); - - // Before data transmission starts, check if C_DONE is truly dine - match fpga_cdone.is_high() { - Ok(false) => debug!("Reset successful!"), - Ok(_) => debug!("Reset unsuccessful!"), - Err(_) => debug!("Reset error!"), - }; - - // Set SPI_SS_B high - fpga_ss.set_high().unwrap(); - - // Send 8 dummy clock, effectively 1 byte of 0x00 - fpga_cfg_spi.transfer(&mut dummy_byte).unwrap(); - - // Drive SPI_SS_B low - fpga_ss.set_low().unwrap(); - - // Send the whole image without interruption + // Pre-load the configuration bytes let config_data = include_bytes!("../build/top.bin"); - for byte in config_data.into_iter() { - block!(fpga_cfg_spi.send(*byte)).unwrap(); - block!(fpga_cfg_spi.read()).unwrap(); - } - - // Drive SPI_SS_B high - fpga_ss.set_high().unwrap(); - - // Send at another 100 dummy clocks (choosing 13 bytes) - fpga_cfg_spi.transfer(&mut dummy_13_bytes).unwrap(); - - // Check the CDONE output from FPGA - if !(fpga_cdone.is_high().unwrap()) { - debug!("ERROR!"); - } - else { - debug!("Configuration successful!"); - // Send at least another 49 clock cycles to activate IO pins (choosing same 13 bytes) - fpga_cfg_spi.transfer(&mut dummy_13_bytes).unwrap(); - debug!("User I/O pins activated."); - } + flash_ice40_fpga(fpga_cfg_spi, fpga_ss, fpga_creset, fpga_cdone, delay, config_data)?; loop { nop(); diff --git a/src/flash.rs b/src/flash.rs new file mode 100644 index 0000000..ee6c166 --- /dev/null +++ b/src/flash.rs @@ -0,0 +1,99 @@ +use embedded_hal::{ + digital::v2::{OutputPin, InputPin}, + blocking::spi::Transfer, + blocking::delay::{DelayMs, DelayUs}, +}; + +use cortex_m; +use cortex_m::asm::nop; +use cortex_m_rt::entry; + +use core::ptr; +use nb::block; + +use log::{warn, debug}; + +pub enum FPGAFlashError { + SPICommunicationError, + NegotiationError, + ResetStatusError, +} + +// 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, data: &[u8]) -> 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), + }; + + debug!("Configuration successful!"); + // 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)?; + debug!("User I/O pins activated."); + Ok(()) + +} \ No newline at end of file