Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,5 @@
*.exe
*.out
*.app

Controller/build/*.*
221 changes: 178 additions & 43 deletions Controller/Controller.ino
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,26 @@
#include <SD.h>
#include <SPI.h>
#include "flashmem.h"
#include "esp_partition.h"

#include <WiFi.h>
#include <WiFiManager.h>
#include <ESPmDNS.h>

#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <AsyncElegantOTA.h>

#include "ESPIcialWebDAV.h"

#define VERSION "VERA ESPIcial V1.0.1"
#define HOSTNAME "X16WebDAV"
#define AP_NAME "X16Connect"
#define AP_PASSWORD "12345678"
#define UP_NAME "X16Update"
#define UP_PASSWORD "12345678"
#define RESET_FILE "/RESETWIFI"
#define VERA_FILE "/VERA.BIN"

#define ESP_BUILTIN_LED 2

Expand Down Expand Up @@ -56,6 +66,9 @@ void switchToESP();
FS& gfs = SD;
//WiFiServerSecure tcp(443); // ToDo: try https
WiFiServer tcp(80);

AsyncWebServer server(8080);

ESPIcialWebDAV dav;
uint32_t startTimeoutSD = 0;

Expand Down Expand Up @@ -226,6 +239,23 @@ void setupWiFi() {
Serial.println("connected...yeey :)");
}


server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(200, "text/plain", VERSION);
});

}

//---------------------------------------------------------------------
// Setup OTA update
//---------------------------------------------------------------------
void setupOTA()
{
AsyncElegantOTA.setID(VERSION);
AsyncElegantOTA.begin(&server); // Start ElegantOTA without username/password
//AsyncElegantOTA.begin(&server, UP_NAME, UP_PASSWORD); // Start ElegantOTA with username/password
server.begin();
Serial.println("Update server started");
}

//---------------------------------------------------------------------
Expand Down Expand Up @@ -269,6 +299,15 @@ void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(ESP_BUILTIN_LED, OUTPUT);

// setup WiFi
setupWiFi();

// setup SebDAV access
setupWebDav();

// setup SebDAV access
setupOTA();

// show reset is done
ENABLE_FPGA_CFG();
digitalWrite(ESP_FPGA_RESET, 0);
Expand All @@ -289,8 +328,8 @@ void setup() {
// variables for FPGA binary transfer
uint8_t header_bytes_read = 0;
uint8_t magic;
uint16_t transfer_size;
uint16_t bytes_transferred = 0;
uint32_t transfer_size;
uint32_t bytes_transferred = 0;

//---------------------------------------------------------------------
// switches SD card access to ESP, start timeout to switch back to FPGA
Expand Down Expand Up @@ -319,49 +358,10 @@ void switchToX16()
}

//---------------------------------------------------------------------
// main loop
// handle serial fpga upload
//---------------------------------------------------------------------
void loop()
void handleSerialUploadFPGA()
{
uint8_t isX16SD = digitalRead(FPGA_SD_EN); // who is in control of the SD card?

if (fpga_configured)
{
dav.handleClient();

// switch back SD card to FPGA when timeout is due
if (startTimeoutSD
&& millis()-startTimeoutSD > 5000
&& !isX16SD)
switchToX16();
}

uint8_t cur_fpga_creset = digitalRead(FPGA_CRESET_B);

if (cur_fpga_creset == 0 && last_fpga_creset == 1)
{
Serial.println("ENABLE_FPGA_CFG()");
// Reset was just asserted
// Make sure that FPGA SPI bus is connected to config flash
fpga_configured = 0;
ENABLE_FPGA_CFG();
} else if (cur_fpga_creset == 1 && fpga_configured == 0 && digitalRead(FPGA_CDONE) == 1) {
// FPGA has finished configuration, switch SD card access to SD card
fpga_configured = 1;

// setup WiFi
setupWiFi();

// setup SebDAV access
setupWebDav();

// give sd card control to X16
ENABLE_FPGA_SD();
switchToX16();
Serial.println("Init done");

}

//
// serial management, for uploading FPGA binary
//
Expand Down Expand Up @@ -411,6 +411,141 @@ void loop()
}
}
}
}


//---------------------------------------------------------------------
// handle file based fpga upload. Checks for file "VERA.BIN"
//---------------------------------------------------------------------
void handleFileUploadFPGA()
{
char buffer[256];

// checking for a vera binary
Serial.println("Checking for VERA update...");
switchToESP();

// no VERA.BIN file? then skip this
if (!gfs.exists(VERA_FILE))
return;

Serial.println("VERA.BIN found. Flashing to FPGA");

// setup flashing FPGA via SPI
digitalWrite(FPGA_CFG_EN, 0); // Disable communication between FPGA and Flash
spi_begin();

cfg_spi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE0));
digitalWrite(cfg_spi->pinSS(), LOW);

bytes_transferred = 0;

// open vera binary
switchToESP();
File f = gfs.open(VERA_FILE);

transfer_size = f.size();
sprintf(buffer, "Vera file size: %d Bytes", transfer_size);
Serial.println(buffer);

// transfer file
while(bytes_transferred < transfer_size)
{
uint8_t len = f.readBytes(buffer, 64);
if (len <= 0)
{
sprintf(buffer, "flashed %d", bytes_transferred);
Serial.println(buffer);
Serial.println("EOF?");
break;
}

for (int n=0; n<len; n++)
{
uint8_t r = cfg_spi->transfer(buffer[n]);
}
digitalWrite(ESP_BUILTIN_LED, (bytes_transferred & 0x200) == 0 ? 0 : 1);
bytes_transferred += len;

delay(10);
if (bytes_transferred % 1024 == 0)
Serial.print(".");
}

Serial.println("");
sprintf(buffer, "flashed %d", bytes_transferred);
Serial.println(buffer);

// cleanup
f.close();
gfs.remove(VERA_FILE);

// ending spi transfer
digitalWrite(cfg_spi->pinSS(), HIGH);
cfg_spi->endTransaction();

// reset VERA
Serial.println("Resetting FPGA");
digitalWrite(FPGA_CFG_EN, 1); // Enable communication between FPGA and Flash
digitalWrite(ESP_FPGA_RESET, 0);
digitalWrite(ESP_BUILTIN_LED, 1);
delay(250);
digitalWrite(ESP_BUILTIN_LED, 0);
digitalWrite(ESP_FPGA_RESET, 1);

digitalWrite(ESP_BUILTIN_LED, 0);
// Release SPI bus
spi_end();

}

//---------------------------------------------------------------------
// main loop
//---------------------------------------------------------------------
void loop()
{
uint8_t isX16SD = digitalRead(FPGA_SD_EN); // who is in control of the SD card?
uint8_t cur_fpga_creset = digitalRead(FPGA_CRESET_B);

//if (fpga_configured)
dav.handleClient();

// switch back SD card to FPGA when timeout is due
if (startTimeoutSD
&& millis()-startTimeoutSD > 5000
&& !isX16SD)
switchToX16();

if (cur_fpga_creset == 0 && last_fpga_creset == 1)
{
// Reset was just asserted
// Make sure that FPGA SPI bus is connected to config flash
fpga_configured = 0;
ENABLE_FPGA_CFG();
} else if (cur_fpga_creset == 1 && fpga_configured == 0 && digitalRead(FPGA_CDONE) == 1) {
// FPGA has finished configuration, switch SD card access to SD card
fpga_configured = 1;

/*// setup WiFi
setupWiFi();

// setup SebDAV access
setupWebDav();

// setup SebDAV access
setupOTA();
*/
handleFileUploadFPGA();

// give sd card control to X16
switchToX16();
Serial.println("Init done");


}

// handle serial upload to FPGA
handleSerialUploadFPGA();

// make led blink
digitalWrite(ESP_BUILTIN_LED, (millis() & 0x200) == 0 ? 0 : 1);
Expand Down
50 changes: 41 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ and retro enthusiasts to add to their own designs.

Key features of the ESPIcial include:

* Easy update interface for both ESP32 and FPGA through USB C connector
* Easy WebDAV access to the SD card via WiFi
* OTA capability for the ESP32 firmware via WiFi
* Update via SD card for FPGA
* Backup update interface for ESP32 and FPGA through USB C connector via serial
* Supports all video and audio features of the original VERA
* 640x480 @60Hz Resolution
* Video output
Expand Down Expand Up @@ -58,21 +61,50 @@ Once the ESP32 board is added to Arduino, use these settings for building the fi

### Building Firmware

Press the checkmark button on the Arduino IDE to build the firmware. This may take a few
minutes to complete.
Install the following libraries:
* WiFiMulti_Generic
* WiFiManager
* MDNS_Generic
* ESPAsyncTCP
* ESPAsyncWebCerver
* AsyncElegantOTA
Press the checkmark button on the Arduino IDE to build the firmware. This may take a few minutes to complete.

### Updating the ESP32 Firmware
### Connecting the ESPIcial to your WiFi

Make sure the X16 is powered on and USB-C on the ESPIcial is NOT connected!
If no WiFi credentials are configured the ESPIcial will create a temporary AP for 60 seconds namend "X16Connect" and provide a captive portal. There you can select your WiFi AP and enter the password. Be aware that the portal is not encrypted, but the credentials will be, once connected.

If you want to reset credentials or connect to a different network, create a file named "RESETWIFI" in the root folder of the SD card.
At each reset the ESPIcial checks for this file and if found, deletes credentials and creates the temporary AP again for 60 seconds.

### Using WebDAV

Connect your webdav client to http://x16webdav. Mount share via file explorer on Windows 10+ or various options on Linux.

This will give you direct access to the SD card via WiFi. Control of the SD card is shared with the X16. With every request via WebDAV the ESPIcial will get the SD card exclusively for at least 5 seconds. Each request within that time will extend access by 5 seconds. So 5 seconds after the last request control of the SD card is returned to the X16.

While the ESPIcial has control over the SD card the X16 won't see the SD card and any file access will end with a "device not present" error.

### Updating the ESP32 Firmware via OTA

The ESP32 Firmware can be updated via WiFi by connecting to http://x16webdav:8080/update and uploading a sketch in compiled binary form.

### Updating the FPGA Firmware via SD card

You can place a file named VERA.BIN in the root folder of the SD card. At each reset the ESPIcial checks if this file exists and updates the FPGA.
The LED is blinking quickly during this time.

### Updating the ESP32 Firmware via Arduino IDE

The ESP32 Firmware can be updated directly from the Arduino IDE by pressing the "Upload" button.

### Updating the FPGA Firmware
### Updating the FPGA Firmware via serial

The ESP32 Firmware contains an interface that allows the FPGA bitstream to be updated over
the USB C serial interface. A Python script, `espi_update_fpga.py` is included here to facilitate
this. The script requires PySerial to communicate with the ESP32 firmware.
The ESP32 Firmware contains an interface that allows the FPGA bitstream to be updated over the USB C serial interface. A Python script, `espi_update_fpga.py` is included here to facilitate this. The script requires PySerial to communicate with the ESP32 firmware.

Obtain a VERA firmware and execute the following:

`python espi_update_fpga.py /dev/ttyS3 ~/vera.bin`

Replace `/dev/ttyS3` with the path to the serial port device on your computer (could be `COM3` on Windows) and replace `~/vera.bin` with the path to the VERA bitstream.
Replace `/dev/ttyS3` with the path to the serial port device on your computer (could be `COMx` on Windows) and replace `~/vera.bin` with the path to the VERA bitstream.