Last active
June 30, 2020 22:53
-
-
Save bit-hack/62e6d2ee987d9fa06bdadeb6fef15c60 to your computer and use it in GitHub Desktop.
Clean up DADAMachines ICEClass.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Arduino.h> | |
#include <SPI.h> | |
// for the pinPeripheral() function | |
#include <wiring_private.h> | |
#ifndef _ICECLASS_DOPPLER_ | |
#define _ICECLASS_DOPPLER_ | |
#define SPI_FPGA_SPEED 34000000 | |
class ICEClass { | |
public: | |
ICEClass() | |
: SPIfpga(nullptr) | |
, ice_cs(ICE_CS) | |
, ice_mosi(ICE_MOSI) | |
, ice_miso(ICE_MISO) | |
, ice_clk(ICE_CLK) | |
, ice_cdone(ICE_CDONE) | |
, ice_creset(ICE_CRESET) | |
{ | |
} | |
ICEClass(int cs, int mosi, int miso, int clk, int cdone, int creset) | |
: SPIfpga(nullptr) | |
, ice_cs(cs) | |
, ice_mosi(mosi) | |
, ice_miso(miso) | |
, ice_clk(clk) | |
, ice_cdone(cdone) | |
, ice_creset(creset) | |
{ | |
} | |
~ICEClass() { | |
if (SPIfpga) { | |
delete SPIfpga; | |
SPIfpga = nullptr; | |
} | |
} | |
void initSPI() { | |
if (SPIfpga) { | |
delete SPIfpga; | |
SPIfpga = nullptr; | |
} | |
pinMode(ice_cs, OUTPUT); | |
pinMode(ice_clk, OUTPUT); | |
pinMode(ice_mosi, OUTPUT); | |
pinMode(ice_miso, INPUT_PULLUP); | |
SPIfpga = new SPIClass(&sercom5, ice_miso, ice_clk, ice_mosi, | |
SPI_PAD_3_SCK_1, SERCOM_RX_PAD_0); | |
SPIfpga->begin(); | |
// remux Arduino Pins for Hardware SPI | |
pinPeripheral(ice_miso, PIO_SERCOM_ALT); | |
pinPeripheral(ice_mosi, PIO_SERCOM_ALT); | |
pinPeripheral(ice_clk, PIO_SERCOM_ALT); | |
} | |
uint8_t sendSPI8(uint8_t txdata) { | |
// assert chip select | |
digitalWrite(ice_cs, LOW); | |
SPIfpga->beginTransaction(SPISettings(SPI_FPGA_SPEED, MSBFIRST, SPI_MODE0)); | |
const uint8_t rxdata = SPIfpga->transfer(txdata); | |
// de-assert chip select | |
digitalWrite(ice_cs, HIGH); | |
SPIfpga->endTransaction(); | |
return rxdata; | |
} | |
uint16_t sendSPI16(uint16_t txdata) { | |
// assert chip select | |
digitalWrite(ice_cs, LOW); | |
SPIfpga->beginTransaction(SPISettings(SPI_FPGA_SPEED, MSBFIRST, SPI_MODE0)); | |
const uint8_t rxdata1 = SPIfpga->transfer(txdata >> 8); | |
const uint8_t rxdata2 = SPIfpga->transfer(txdata & 0xff); | |
// de-assert chip select | |
digitalWrite(ice_cs, HIGH); | |
SPIfpga->endTransaction(); | |
return (rxdata1 << 8) | rxdata2; | |
} | |
bool upload(const uint8_t *bitstream, | |
const uint32_t bitstream_size) { | |
if (!SPIfpga) { | |
return false; | |
} | |
pinPeripheral(ice_miso, PIO_SERCOM_ALT); | |
pinPeripheral(ice_mosi, PIO_SERCOM_ALT); | |
pinPeripheral(ice_clk, PIO_SERCOM_ALT); | |
pinMode(ice_clk, OUTPUT); | |
pinMode(ice_mosi, OUTPUT); | |
pinMode(ice_creset, OUTPUT); | |
pinMode(ice_cs, OUTPUT); | |
pinMode(ice_cdone, INPUT); | |
// programming ICE40 in "spi slave" configuration | |
// CRESET_B = 0 | |
digitalWrite(ice_creset, LOW); | |
// SPI_CLK = 1 | |
digitalWrite(ice_clk, HIGH); | |
// SPI_SS_B = 0 | |
digitalWrite(ice_cs, LOW); | |
// wait a minimum of 200ns | |
delayMicroseconds(10); | |
// CRESET_B = 1 | |
digitalWrite(ice_creset, HIGH); | |
// wait a minimum of 300us to clear internal configuration memory | |
// note: the pseudo code section suggests 800us for L1k, L4k and 1200us | |
// for L8k devices. | |
// note: "reset waveform 1" suggests a delay of 800us for LP384, LP1k, and | |
// 1200us for LP4k, LP8k. | |
delayMicroseconds(1200); | |
// Send configuration image serially on SPI_SI to iCE40, most significant | |
// bit first, on falling edge of SPI_SCK. Send the entire image, without | |
// interruption. Ensure that SPI_SCK frequency is between 1 mHz and 25 MHz. | |
// Begin HardwareSPI | |
initSPI(); | |
SPIfpga->beginTransaction(SPISettings(SPI_FPGA_SPEED, MSBFIRST, SPI_MODE0)); | |
// the doc suggests a synchronization pattern here but the "iCE40 | |
// Configuration Pseudo-code" section just sends 8 clocks instead. | |
SPIfpga->transfer(0x00); | |
// transfer the bitstream | |
for (int k = 0; k < bitstream_size; k++) { | |
SPIfpga->transfer(bitstream[k]); | |
} | |
// Send a minimum of 49 additional dummy bits and 49 additional SPI_SCK | |
// clock cycles (rising-edge to rising-edge) to active the user-I/O pins. | |
// note: "iCE40 SRAM Configuration Sequence" suggests 100 clocks | |
for (int i = 0; i < (107 / 8); i++) { | |
SPIfpga->transfer(0x00); | |
} | |
// End HardwareSPI | |
SPIfpga->endTransaction(); | |
// check CDONE for success | |
const bool cdone_high = (digitalRead(ice_cdone) == HIGH); | |
// reset the SPI apparatus | |
reset_inout(); | |
return cdone_high; | |
} | |
protected: | |
void reset_inout() { | |
pinMode(ice_clk, INPUT_PULLUP); | |
pinMode(ice_cdone, INPUT_PULLUP); | |
pinMode(ice_mosi, INPUT_PULLUP); | |
pinMode(ice_creset, OUTPUT); | |
// pinMode(ice_cs, OUTPUT); | |
// de-assert chip select | |
digitalWrite(ice_cs, HIGH); | |
} | |
SPIClass *SPIfpga; | |
const uint16_t ice_cs; | |
const uint16_t ice_mosi; | |
const uint16_t ice_miso; | |
const uint16_t ice_clk; | |
const uint16_t ice_cdone; | |
const uint16_t ice_creset; | |
}; | |
#endif /* _ICECLASS_DOPPLER_M4_ */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment