fpga config: included into lib
This commit is contained in:
parent
89f9b48073
commit
e994000df1
@ -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
99
src/flash.rs
Normal 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(())
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user