Skip to content

Instantly share code, notes, and snippets.

@bit-hack
Last active June 30, 2020 22:53
Show Gist options
  • Save bit-hack/62e6d2ee987d9fa06bdadeb6fef15c60 to your computer and use it in GitHub Desktop.
Save bit-hack/62e6d2ee987d9fa06bdadeb6fef15c60 to your computer and use it in GitHub Desktop.
Clean up DADAMachines ICEClass.h
#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