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 core::ptr;
|
||||||
use nb::block;
|
use nb::block;
|
||||||
|
|
||||||
|
use firmware::flash::flash_ice40_fpga;
|
||||||
|
|
||||||
#[path = "util/logger.rs"]
|
#[path = "util/logger.rs"]
|
||||||
mod logger;
|
mod logger;
|
||||||
|
|
||||||
@ -74,65 +76,10 @@ fn main() -> ! {
|
|||||||
&ccdr.clocks,
|
&ccdr.clocks,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Data buffer setup
|
// Pre-load the configuration bytes
|
||||||
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
|
|
||||||
let config_data = include_bytes!("../build/top.bin");
|
let config_data = include_bytes!("../build/top.bin");
|
||||||
|
|
||||||
for byte in config_data.into_iter() {
|
flash_ice40_fpga(fpga_cfg_spi, fpga_ss, fpga_creset, fpga_cdone, delay, config_data)?;
|
||||||
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.");
|
|
||||||
}
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
nop();
|
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