fpga config: included into lib

pull/4/head
occheung 2020-09-17 11:21:24 +08:00
parent 89f9b48073
commit e994000df1
2 changed files with 103 additions and 57 deletions

View File

@ -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();

99
src/flash.rs Normal file
View File

@ -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<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, 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(())
}