add flashing FPGA via SPI
This commit is contained in:
parent
6b6e79ddfc
commit
233d53372e
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
@ -0,0 +1,12 @@
|
||||||
|
# Generated by Yosys 0.9+3521 (git sha1 12132b6850, g++ 9.3.0 -fPIC -Os)
|
||||||
|
|
||||||
|
.model top
|
||||||
|
.inputs key
|
||||||
|
.outputs led
|
||||||
|
.names $false
|
||||||
|
.names $true
|
||||||
|
1
|
||||||
|
.names $undef
|
||||||
|
.names $true led
|
||||||
|
1 1
|
||||||
|
.end
|
|
@ -0,0 +1,26 @@
|
||||||
|
# Project setup
|
||||||
|
PROJ = blinky
|
||||||
|
BUILD = ./build
|
||||||
|
DEVICE = 8k
|
||||||
|
FOOTPRINT = ct256
|
||||||
|
|
||||||
|
# Files
|
||||||
|
FILES = top.v
|
||||||
|
|
||||||
|
.PHONY: all clean burn
|
||||||
|
|
||||||
|
all:
|
||||||
|
# if build folder doesn't exist, create it
|
||||||
|
mkdir -p $(BUILD)
|
||||||
|
# synthesize using Yosys
|
||||||
|
yosys -p "synth_ice40 -top top -blif $(BUILD)/$(PROJ).blif" $(FILES)
|
||||||
|
# Place and route using arachne
|
||||||
|
arachne-pnr -d $(DEVICE) -P $(FOOTPRINT) -o $(BUILD)/$(PROJ).asc -p pinmap.pcf $(BUILD)/$(PROJ).blif
|
||||||
|
# Convert to bitstream using IcePack
|
||||||
|
icepack $(BUILD)/$(PROJ).asc $(BUILD)/$(PROJ).bin
|
||||||
|
|
||||||
|
burn:
|
||||||
|
iceprog $(BUILD)/$(PROJ).bin
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm build/*
|
|
@ -0,0 +1,69 @@
|
||||||
|
# example.pcf
|
||||||
|
set_io --warn-no-port HW_CLK R9
|
||||||
|
|
||||||
|
set_io --warn-no-port LED T15
|
||||||
|
set_io --warn-no-port KEY T16
|
||||||
|
|
||||||
|
# set_io --warn-no-port io0 R6
|
||||||
|
# set_io --warn-no-port io1 T8
|
||||||
|
# set_io --warn-no-port io2 T5
|
||||||
|
# set_io --warn-no-port io3 R9
|
||||||
|
# set_io --warn-no-port io4 R5
|
||||||
|
# set_io --warn-no-port io5 T9
|
||||||
|
# set_io --warn-no-port io6 T3
|
||||||
|
# set_io --warn-no-port io7 R10
|
||||||
|
# set_io --warn-no-port io8 R3
|
||||||
|
# set_io --warn-no-port io9 T10
|
||||||
|
# set_io --warn-no-port io10 T2
|
||||||
|
# set_io --warn-no-port io11 T11
|
||||||
|
# set_io --warn-no-port io12 R2
|
||||||
|
# set_io --warn-no-port io13 T13
|
||||||
|
# set_io --warn-no-port io14 T1
|
||||||
|
# set_io --warn-no-port io15 T14
|
||||||
|
|
||||||
|
|
||||||
|
set_io --warn-no-port ADC_DAT[0] J15
|
||||||
|
set_io --warn-no-port ADC_DAT[1] K16
|
||||||
|
set_io --warn-no-port ADC_DAT[2] K15
|
||||||
|
set_io --warn-no-port ADC_DAT[3] L16
|
||||||
|
set_io --warn-no-port ADC_DAT[4] M16
|
||||||
|
set_io --warn-no-port ADC_DAT[5] M15
|
||||||
|
set_io --warn-no-port ADC_DAT[6] N16
|
||||||
|
set_io --warn-no-port ADC_DAT[7] P16
|
||||||
|
set_io --warn-no-port ADC_CLK P15
|
||||||
|
|
||||||
|
|
||||||
|
set_io --warn-no-port FSMC_ADD[0] A9
|
||||||
|
set_io --warn-no-port FSMC_ADD[1] B9
|
||||||
|
set_io --warn-no-port FSMC_ADD[2] A10
|
||||||
|
set_io --warn-no-port FSMC_ADD[3] C10
|
||||||
|
set_io --warn-no-port FSMC_ADD[4] C9
|
||||||
|
set_io --warn-no-port FSMC_ADD[5] C8
|
||||||
|
set_io --warn-no-port FSMC_ADD[6] C7
|
||||||
|
set_io --warn-no-port FSMC_ADD[7] C11
|
||||||
|
|
||||||
|
set_io --warn-no-port FSMC_DAT[0] B10
|
||||||
|
set_io --warn-no-port FSMC_DAT[1] A11
|
||||||
|
set_io --warn-no-port FSMC_DAT[2] B11
|
||||||
|
set_io --warn-no-port FSMC_DAT[3] B12
|
||||||
|
set_io --warn-no-port FSMC_DAT[4] A1
|
||||||
|
set_io --warn-no-port FSMC_DAT[5] A2
|
||||||
|
set_io --warn-no-port FSMC_DAT[6] C3
|
||||||
|
set_io --warn-no-port FSMC_DAT[7] B3
|
||||||
|
set_io --warn-no-port FSMC_DAT[8] B4
|
||||||
|
set_io --warn-no-port FSMC_DAT[9] A5
|
||||||
|
set_io --warn-no-port FSMC_DAT[10] B5
|
||||||
|
set_io --warn-no-port FSMC_DAT[11] A6
|
||||||
|
set_io --warn-no-port FSMC_DAT[12] B6
|
||||||
|
set_io --warn-no-port FSMC_DAT[13] A7
|
||||||
|
set_io --warn-no-port FSMC_DAT[14] B7
|
||||||
|
set_io --warn-no-port FSMC_DAT[15] B8
|
||||||
|
|
||||||
|
set_io --warn-no-port FSMC_NL C14
|
||||||
|
set_io --warn-no-port FSMC_NWAIT B15
|
||||||
|
set_io --warn-no-port FSMC_NOE B14
|
||||||
|
set_io --warn-no-port FSMC_NWE A15
|
||||||
|
set_io --warn-no-port FSMC_NBL[0] C13
|
||||||
|
set_io --warn-no-port FSMC_NBL[1] C12
|
||||||
|
set_io --warn-no-port FSMC_NE1 A16
|
||||||
|
set_io --warn-no-port FSMC_CLK B13
|
|
@ -0,0 +1,59 @@
|
||||||
|
module top (
|
||||||
|
HW_CLK,
|
||||||
|
LED,
|
||||||
|
KEY,
|
||||||
|
ADC_CLK,
|
||||||
|
ADC_DAT,
|
||||||
|
FSMC_CLK,
|
||||||
|
FSMC_ADD,
|
||||||
|
FSMC_DAT,
|
||||||
|
FSMC_NL,
|
||||||
|
FSMC_NWAIT,
|
||||||
|
FSMC_NOE,
|
||||||
|
FSMC_NWE,
|
||||||
|
FSMC_NBL,
|
||||||
|
FSMC_NE1
|
||||||
|
);
|
||||||
|
|
||||||
|
/* I/O */
|
||||||
|
input HW_CLK;
|
||||||
|
input KEY;
|
||||||
|
output LED;
|
||||||
|
|
||||||
|
input FSMC_NL;
|
||||||
|
input FSMC_NWAIT;
|
||||||
|
input FSMC_NOE;
|
||||||
|
input FSMC_NWE;
|
||||||
|
input FSMC_NE1;
|
||||||
|
input [1:0]FSMC_NBL;
|
||||||
|
input FSMC_CLK;
|
||||||
|
input [7:0]FSMC_ADD;
|
||||||
|
output [15:0]FSMC_DAT;
|
||||||
|
|
||||||
|
output ADC_CLK;
|
||||||
|
input [7:0]ADC_DAT;
|
||||||
|
|
||||||
|
reg [7:0] adc_result = 8'b0;
|
||||||
|
|
||||||
|
/* Counter register */
|
||||||
|
reg [31:0] counter = 32'b0;
|
||||||
|
/* LED drivers */
|
||||||
|
assign LED = counter[24];
|
||||||
|
// assign LED = ~KEY;
|
||||||
|
|
||||||
|
/* always */
|
||||||
|
always @ (posedge HW_CLK) begin
|
||||||
|
counter <= counter + 1;
|
||||||
|
|
||||||
|
FSMC_DAT = 200;
|
||||||
|
|
||||||
|
ADC_CLK = ~ADC_CLK;
|
||||||
|
end
|
||||||
|
|
||||||
|
always @ (posedge ADC_CLK) begin
|
||||||
|
adc_result = ADC_DAT;
|
||||||
|
|
||||||
|
// FSMC_DAT = 200;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,92 @@
|
||||||
|
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!("../FPGA/build/blinky.bin");
|
||||||
|
// const DATA: &'static [u8] = include_bytes!("../build/top.bin");
|
||||||
|
|
||||||
|
// 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) -> 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(())
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue