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