Skip to content

Commit

Permalink
Merge pull request #1 from MoCoMakers/develop
Browse files Browse the repository at this point in the history
 FipsyV2 - MachX02-1200 Integration
  • Loading branch information
mattzamora authored Oct 5, 2024
2 parents 8278bb6 + 8e53dd1 commit a7f8f62
Show file tree
Hide file tree
Showing 18 changed files with 4,099 additions and 304 deletions.
17 changes: 17 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,20 @@ jobs:
- source-path: ./
- name: Streaming
timeout-minutes: 30
unittest:
runs-on: ubuntu-22.04
steps:
- name: Install dependencies
run: |
cd ..
mkdir -p EpoxyDuino AUnit Streaming
curl -fsLS https://github.com/bxparks/EpoxyDuino/archive/v1.6.0.tar.gz | tar -C EpoxyDuino -xz --strip-components=1
curl -fsLS https://github.com/bxparks/AUnit/archive/v1.7.1.tar.gz | tar -C AUnit -xz --strip-components=1
curl -fsLS https://github.com/janelia-arduino/Streaming/archive/6.1.1.tar.gz | tar -C Streaming -xz --strip-components=1
- uses: actions/checkout@v4
- name: Run unit tests
run: |
make -j4
./unittest.out
working-directory: ./unittest
timeout-minutes: 30
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
*.o
*.out
/.vscode
/examples/*/build
24 changes: 21 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# Fipsy FPGA Programmer for ESP32

**esp-fipsy** library allows programming a [Fipsy FPGA breakout board](https://www.mocomakers.com/fipsy-fpga/) from an ESP32 microcontroller.
This library can only program the fuse table; it does not write the Feature Row or FEABITS.
[TcpFipsyLoader](examples/TcpFipsyLoader/) demonstrates how to use this library.
**esp-fipsy** library allows programming a [Fipsy FPGA breakout board](https://www.fipsyfpga.com/) from an ESP32 microcontroller.

This library can be used in the Arduino IDE.

When using this project directly:
1. Visit the documentation for the ESP32 programmer on [https://www.fipsyfpga.com](https://www.fipsyfpga.com)
2. Program the ESP32 as a programmer using the [TcpFipsyLoader](examples/TcpFipsyLoader/). This file demonstrates how to use this library.
3. Once you have the IP address for the ESP32 use the [sendJed.py](scripts/sendJed.py) file to program the device. For example:

```
python sendJed.py --file "C:\Users\myuser\Projects\Fipsy-FPGA-edu\Examples\FipsyV2 - XO2-1200\1. Blinky\project_files\Implementation\FipsyBaseline_Implementation.jed" 192.168.1.194
```

For more information please see: [FipsyFPGA.com](https://www.fipsyfpga.com)




## Acknowledgements

We would like to thank Junxiao (Sunny) Shi - [yoursunny.com](https://yoursunny.com/) for significant contributions to the ESP32 programmer!
83 changes: 43 additions & 40 deletions examples/TcpFipsyLoader/TcpFipsyLoader.ino
Original file line number Diff line number Diff line change
@@ -1,41 +1,45 @@
#include "fipsy.hpp"
#include <Streaming.h>
#include <WiFi.h>

const char* WIFI_SSID = "my-ssid";
const char* WIFI_PASS = "my-pass";

Fipsy fipsy(SPI);
// Choose either Fipsy::FuseTable<343936> for MachX02-1200 or Fipsy::FuseTable<73600> for MachXO2-256. These are the QF values from the .jed file.
// using FipsyClass = Fipsy::FuseTable<73600>;
using FipsyClass = Fipsy::FuseTable<343936>;
FipsyClass fuseTable;

fipsy::Fipsy fpga(SPI);
fipsy::FuseTable fuseTable;
WiFiServer listener(34779);

void
setup() {
Serial.begin(115200);
// Old pinout - 14, 12, 13, 15
// New pinout - sck, miso, mosi, ss
// 18, 19, 23, 5
Serial << "Getting Device ID" << endl;
// 0x012B8043 is for MachXO2-256 and 0x012BA043 is MachXO2-1200HC
uint32_t deviceID = fipsy.getID(18, 19, 23, 5);
Serial << "Device ID: " << endl;
Serial.printf("0x%08lx", deviceID);
Serial.println();


if (!fipsy.begin(18, 19, 23, 5)) {
Serial << "Fipsy not found" << endl;
// Choose either fuseTable.resize(343936) for MachX02-1200 or fuseTable.resize(73600) for MachXO2-256.
// These are the QF values from the .jed file.
// fuseTable.resize(73600);
fuseTable.resize(343936);

// Known alternate pinouts for SPI include:
// 18, 19, 23, 5
// 14, 12, 13, 15
// These pins are sck, miso, mosi, ss
if (!fpga.begin(18, 19, 23, 5)) {
Serial.println("Fipsy not found");
return;
} else {
uint32_t deviceID = fpga.getID();
Serial.print("Device ID: ");
Serial.printf("0x%08lx", deviceID);
Serial.println();
}

WiFi.persistent(false);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) {
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.printf("WiFi failure %d", static_cast<int>(WiFi.status()));
Serial.println();
return;
}
Serial << WiFi.localIP() << endl;
Serial.println(WiFi.localIP());

listener.begin();
}
Expand All @@ -47,36 +51,35 @@ loop() {
return;
}

FipsyClass::JedecError parseError = fuseTable.parseJedec(client);
if (parseError != FipsyClass::JedecError::OK) {
client << "JEDEC parse error: " << static_cast<int>(parseError) << endl;
client << static_cast<int>(parseError) << endl;
auto jc = fipsy::parseJedec(client, fuseTable);
if (!jc) {
client.printf("JEDEC parse error %d", static_cast<int>(jc.error));
client.println();
client.stop();
return;
}
client << "JEDEC OK, fuse checksum: " << _HEX(fuseTable.computeChecksum()) << endl;
client.printf("JEDEC OK, fuse checksum %04" PRIx16 ", features ", fuseTable.computeChecksum());
client.println(jc.features);

if (!fipsy.enable()) {
client << "Cannot enable configuration mode, status: " << _HEX(fipsy.readStatus().v) << endl;
if (!fpga.enable()) {
client.printf("Cannot enable configuration mode, status %08" PRIx32, fpga.readStatus().v);
client.println();
client.stop();
return;
}

uint32_t featureRow0, featureRow1;
uint16_t feabits;
fipsy.readFeatures(featureRow0, featureRow1, feabits);
client << "Feature Row: " << _HEX(featureRow0) << ' ' << _HEX(featureRow1) << endl
<< "FEABITS: " << _HEX(feabits) << endl;
client.print("On-chip features ");
client.println(fpga.readFeatures());

client << "Programming ..." << endl;
client.flush();
if (fuseTable.program(fipsy)) {
client << "Success" << endl;
client.println("Programming ...");
auto result = fpga.program(fuseTable, jc.features);
if (result) {
client.println("Success");
} else {
client << "Failed" << endl;
client.print("Failed ");
client.println(result.error);
}

fipsy.disable();
client.flush();
fpga.disable();
client.stop();
}
4 changes: 2 additions & 2 deletions library.properties
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name=esp-fipsy
version=0.0.20240618
version=0.0.20241004
author=Junxiao Shi
maintainer=Junxiao Shi
sentence=Fipsy FPGA programmer.
paragraph=This library programs MocoMakers Fipsy FPGA chip from ESP32 microcontroller.
category=Device Control
url=https://yoursunny.com
url=https://www.fipsyfpga.com
architectures=esp32
57 changes: 57 additions & 0 deletions scripts/sendJed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
"""
Sends a .jed file to your ESP32
Example Usage:
python sendJed.py 192.168.1.2 --file 'C:\path\to\yourfiqle.jed'
or
python sendJed.py 192.168.1.2 --port 34779 --file 'C:\path\to\yourfile.jed'
"""

import socket
import argparse
import os

def netcat(host, port, content):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, int(port)))
s.sendall(content)
s.shutdown(socket.SHUT_WR)
while True:
data = s.recv(4096)
if not data:
break
print(repr(data.decode('utf-8')))
s.close()

def client(ip, port, filename):
# Check if file exists
if not os.path.isfile(filename):
raise FileNotFoundError(f"File {filename} does not exist.")

# Check if file ends with .jed
if not filename.endswith('.jed'):
raise ValueError("File must end with .jed extension.")

# Check if file has non-zero size
if os.path.getsize(filename) == 0:
raise ValueError("File is empty.")

client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((ip, port))
print("Device connection initiated")

with open(filename, 'rb') as file:
content = file.read()
netcat(ip, port, content)

if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Send a .jed file over TCP and print returned text.')
parser.add_argument('ip', type=str, help='The IP address of the ESP32 server.')
parser.add_argument('--port', type=int, default=34779, help='The port number to connect to (default is 34779).')
parser.add_argument('--file', type=str, required=True, help='The path to the .jed file to send.')

args = parser.parse_args()

client(args.ip, args.port, args.file)
Loading

0 comments on commit a7f8f62

Please sign in to comment.