Merge pull request #11 from adafruit/brain-esp32
Support Brain to program esp32
This commit is contained in:
commit
84329baa36
11 changed files with 935 additions and 21 deletions
186
examples/Brain/program_esp32_cdc/program_esp32_cdc.ino
Normal file
186
examples/Brain/program_esp32_cdc/program_esp32_cdc.ino
Normal file
|
|
@ -0,0 +1,186 @@
|
||||||
|
// This sketch program ESP32 by flashing bin file from SD Card
|
||||||
|
// Hardware wiring:
|
||||||
|
// - Brain GPIO28 <-> ESP32 IO0
|
||||||
|
// - Brain Reset <-> ESP32 Enable
|
||||||
|
// - Brain TX/RX <-> ESP32 RX/TX
|
||||||
|
|
||||||
|
// required for Host MSC block device
|
||||||
|
#include "SdFat.h"
|
||||||
|
|
||||||
|
// required for USB host
|
||||||
|
#include "pio_usb.h"
|
||||||
|
#include "Adafruit_TinyUSB.h"
|
||||||
|
|
||||||
|
#include "Adafruit_TestBed_Brains.h"
|
||||||
|
|
||||||
|
#define ESP32_RESET 27
|
||||||
|
#define ESP32_IO0 28
|
||||||
|
|
||||||
|
// false for ESP32 (default)
|
||||||
|
// true for later chips such as S2, S3, H2, C3
|
||||||
|
#define ESP32_SUPPORTS_ENCRYPTED_FLASH true
|
||||||
|
|
||||||
|
//#define ESP32_BAUDRATE 921600
|
||||||
|
#define ESP32_BAUDRATE 115200
|
||||||
|
|
||||||
|
// CDC Host object
|
||||||
|
Adafruit_USBH_CDC SerialHost;
|
||||||
|
|
||||||
|
// Defined an boot rom object that use UART Serial1
|
||||||
|
ESP32BootROMClass ESP32BootROM(SerialHost, ESP32_IO0, ESP32_RESET, ESP32_SUPPORTS_ENCRYPTED_FLASH);
|
||||||
|
|
||||||
|
// Bin files on SDCard to program
|
||||||
|
// These files can be found in raspi-tester (or compiled from Arduino sketch)
|
||||||
|
#define BIN_FEATHER_ESP32S2 0
|
||||||
|
#define BIN_FEATHER_ESP32S3 1
|
||||||
|
|
||||||
|
#define BIN_FILES BIN_FEATHER_ESP32S3 // select which bins to flash either Feather ESP32 S2 or S3
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint32_t addr;
|
||||||
|
const char* fpath;
|
||||||
|
} bin_files [] =
|
||||||
|
{
|
||||||
|
#if BIN_FILES == BIN_FEATHER_ESP32S2
|
||||||
|
{ 0x1000 , "esp32s2/PID5000/esp32s2_feather_test.ino.bootloader.bin" },
|
||||||
|
{ 0x8000 , "esp32s2/PID5000/esp32s2_feather_test.ino.partitions.bin" },
|
||||||
|
{ 0xe000 , "esp32s2/PID5000/boot_app0.bin" },
|
||||||
|
{ 0x10000 , "esp32s2/PID5000/esp32s2_feather_test.ino.bin" },
|
||||||
|
{ 0x2d0000, "esp32s2/PID5000/tinyuf2.bin" },
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BIN_FILES == BIN_FEATHER_ESP32S3
|
||||||
|
{ 0x0000 , "esp32s3/PID5477/esp32s3_feather_test.ino.bootloader.bin" },
|
||||||
|
{ 0x8000 , "esp32s3/PID5477/esp32s3_feather_test.ino.partitions.bin" },
|
||||||
|
{ 0xe000 , "esp32s3/PID5477/boot_app0.bin" },
|
||||||
|
{ 0x10000 , "esp32s3/PID5477/esp32s3_feather_test.ino.bin" },
|
||||||
|
{ 0x2d0000, "esp32s3/PID5477/tinyuf2.bin" },
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
BIN_FILES_COUNT = sizeof(bin_files)/sizeof(bin_files[0])
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Setup and Loop on Core0
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
void prepare_sd(void) {
|
||||||
|
if (!Brain.SD_detected()) {
|
||||||
|
Brain.LCD_printf(0, "No SD Card");
|
||||||
|
while ( !Brain.SD_detected() ) delay(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !Brain.SD_begin(SD_SCK_MHZ(16)) ) {
|
||||||
|
Brain.LCD_printf(0, "SD init failed");
|
||||||
|
while(1) delay(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
Brain.LCD_printf(0, "SD mounted");
|
||||||
|
|
||||||
|
// Print out file on SD if Serial is connected
|
||||||
|
if (Serial) {
|
||||||
|
Serial.println();
|
||||||
|
Serial.println("SD Contents:");
|
||||||
|
Serial.printf("Card size = %0.1f GB\n", 0.000000512 * Brain.SD.card()->sectorCount());
|
||||||
|
Brain.SD.ls(LS_R | LS_DATE | LS_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_speed(size_t count, uint32_t ms) {
|
||||||
|
Brain.LCD_printf(0, "%.01fKB %.01fs", count/1000.0F, ms / 1000.0F);
|
||||||
|
|
||||||
|
Serial.printf("Completed %u bytes in %.02f seconds.\r\n", count, ms / 1000.0F);
|
||||||
|
Serial.printf("Speed : %.02f KB/s\r\n", (count / 1000.0F) / (ms / 1000.0F));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
while (!Serial) delay(10);
|
||||||
|
Serial.println("Tester Brains: Programming ESP32 with UART!");
|
||||||
|
|
||||||
|
// sync: wait for Brain.begin() called in core1 before accessing SD or other peripherals
|
||||||
|
while (!Brain.inited()) delay(10);
|
||||||
|
|
||||||
|
// prepare SD Card
|
||||||
|
prepare_sd();
|
||||||
|
|
||||||
|
while ( !Brain.esp32_begin(&ESP32BootROM, ESP32_BAUDRATE) ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writing bin files
|
||||||
|
size_t total_bytes = 0;
|
||||||
|
uint32_t ms = millis();
|
||||||
|
for(size_t i=0; i<BIN_FILES_COUNT; i++) {
|
||||||
|
Brain.LCD_printf("Flashing file %u", i);
|
||||||
|
size_t wr_count = Brain.essp32_programFlash(bin_files[i].fpath, bin_files[i].addr);
|
||||||
|
total_bytes += wr_count;
|
||||||
|
if (!wr_count) {
|
||||||
|
Brain.LCD_printf_error("Failed to flash");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print_speed(total_bytes, millis() - ms);
|
||||||
|
|
||||||
|
Brain.esp32_end();
|
||||||
|
|
||||||
|
// reset ESP32 to run new firmware
|
||||||
|
Brain.targetReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Setup and Loop on Core1
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
// call usbh_begin() here to make pio usb background task run on core1
|
||||||
|
// NOTE: Brain.begin() should be called here as well to prevent race condition
|
||||||
|
void setup1() {
|
||||||
|
Brain.begin();
|
||||||
|
Brain.usbh_begin();
|
||||||
|
|
||||||
|
// Since we only support 1 CDC interface with Tester (also CFG_TUH_CDC = 1)
|
||||||
|
// the index will always be 0 for SerialHost
|
||||||
|
// SerialHost.setInterfaceIndex(0);
|
||||||
|
SerialHost.begin(115200);
|
||||||
|
|
||||||
|
Brain.LCD_printf(0, "No USB attached");
|
||||||
|
Brain.LCD_printf(1, "Plug your device");
|
||||||
|
}
|
||||||
|
|
||||||
|
// core1's loop: process usb host task on core1
|
||||||
|
void loop1() {
|
||||||
|
Brain.USBHost.task();
|
||||||
|
|
||||||
|
// periodically flush SerialHost if connected
|
||||||
|
if ( SerialHost && SerialHost.connected() ) {
|
||||||
|
SerialHost.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// TinyUSB Host callbacks
|
||||||
|
// Note: running in the same core where Brain.USBHost.task() is called
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
// Invoked when device is mounted (configured)
|
||||||
|
void tuh_mount_cb (uint8_t daddr)
|
||||||
|
{
|
||||||
|
uint16_t vid, pid;
|
||||||
|
tuh_vid_pid_get(daddr, &vid, &pid);
|
||||||
|
|
||||||
|
Serial.printf("Device attached, address = %d\r\n", daddr);
|
||||||
|
Brain.LCD_printf("USBID %04x:%04x", vid, pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invoked when device is unmounted (bus reset/unplugged)
|
||||||
|
void tuh_umount_cb(uint8_t dev_addr)
|
||||||
|
{
|
||||||
|
(void) dev_addr;
|
||||||
|
Brain.LCD_printf(1, "No USB Device");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
155
examples/Brain/program_esp32_uart/program_esp32_uart.ino
Normal file
155
examples/Brain/program_esp32_uart/program_esp32_uart.ino
Normal file
|
|
@ -0,0 +1,155 @@
|
||||||
|
// This sketch program ESP32 by flashing bin file from SD Card
|
||||||
|
// Hardware wiring:
|
||||||
|
// - Brain GPIO28 <-> ESP32 IO0
|
||||||
|
// - Brain Reset <-> ESP32 Enable
|
||||||
|
// - Brain TX/RX <-> ESP32 RX/TX
|
||||||
|
|
||||||
|
// required for Host MSC block device
|
||||||
|
#include "SdFat.h"
|
||||||
|
|
||||||
|
// required for USB host
|
||||||
|
#include "pio_usb.h"
|
||||||
|
#include "Adafruit_TinyUSB.h"
|
||||||
|
|
||||||
|
#include "Adafruit_TestBed_Brains.h"
|
||||||
|
|
||||||
|
#define ESP32_RESET 27
|
||||||
|
#define ESP32_IO0 28
|
||||||
|
|
||||||
|
// false for ESP32 (default)
|
||||||
|
// true for later chips such as S2, S3, H2, C3
|
||||||
|
#define ESP32_SUPPORTS_ENCRYPTED_FLASH false
|
||||||
|
|
||||||
|
#define ESP32_BAUDRATE 921600
|
||||||
|
// #define ESP32_BAUDRATE 115200
|
||||||
|
|
||||||
|
// Bin files on SDCard to program
|
||||||
|
// These files can be generated by any of Arduino sketches
|
||||||
|
// The example use WiFiAccessPoint sketch, which we can verify its running image
|
||||||
|
// by simply scan for existence of ssid "YourAP"
|
||||||
|
struct {
|
||||||
|
uint32_t addr;
|
||||||
|
const char* fpath;
|
||||||
|
} bin_files [] = {
|
||||||
|
{ 0x1000 , "esp32/WiFiAccessPoint/WiFiAccessPoint.ino.bootloader.bin" },
|
||||||
|
{ 0x8000 , "esp32/WiFiAccessPoint/WiFiAccessPoint.ino.partitions.bin" },
|
||||||
|
{ 0xe000 , "esp32/WiFiAccessPoint/boot_app0.bin" },
|
||||||
|
{ 0x10000 , "esp32/WiFiAccessPoint/WiFiAccessPoint.ino.bin" },
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
BIN_FILES_COUNT = sizeof(bin_files)/sizeof(bin_files[0])
|
||||||
|
};
|
||||||
|
|
||||||
|
// Defined an boot rom object that use UART Serial1
|
||||||
|
ESP32BootROMClass ESP32BootROM(Serial1, ESP32_IO0, ESP32_RESET, ESP32_SUPPORTS_ENCRYPTED_FLASH);
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Setup and Loop on Core0
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
void prepare_sd(void) {
|
||||||
|
if (!Brain.SD_detected()) {
|
||||||
|
Brain.LCD_printf(0, "No SD Card");
|
||||||
|
while ( !Brain.SD_detected() ) delay(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !Brain.SD_begin(SD_SCK_MHZ(16)) ) {
|
||||||
|
Brain.LCD_printf(0, "SD init failed");
|
||||||
|
while(1) delay(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
Brain.LCD_printf(0, "SD mounted");
|
||||||
|
|
||||||
|
// Print out file on SD if Serial is connected
|
||||||
|
if (Serial) {
|
||||||
|
Serial.println();
|
||||||
|
Serial.println("SD Contents:");
|
||||||
|
Serial.printf("Card size = %0.1f GB\n", 0.000000512 * Brain.SD.card()->sectorCount());
|
||||||
|
Brain.SD.ls(LS_R | LS_DATE | LS_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_speed(size_t count, uint32_t ms) {
|
||||||
|
Brain.LCD_printf(0, "%.01fKB %.01fs", count/1000.0F, ms / 1000.0F);
|
||||||
|
|
||||||
|
Serial.printf("Completed %u bytes in %.02f seconds.\r\n", count, ms / 1000.0F);
|
||||||
|
Serial.printf("Speed : %.02f KB/s\r\n", (count / 1000.0F) / (ms / 1000.0F));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
while (!Serial) delay(10);
|
||||||
|
Serial.println("Tester Brains: Programming ESP32 with UART!");
|
||||||
|
|
||||||
|
// sync: wait for Brain.begin() called in core1 before accessing SD or other peripherals
|
||||||
|
while (!Brain.inited()) delay(10);
|
||||||
|
|
||||||
|
// prepare SD Card
|
||||||
|
prepare_sd();
|
||||||
|
|
||||||
|
while ( !Brain.esp32_begin(&ESP32BootROM, ESP32_BAUDRATE) ) {
|
||||||
|
// retry syncing
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writing bin files
|
||||||
|
size_t total_bytes = 0;
|
||||||
|
uint32_t ms = millis();
|
||||||
|
for(size_t i=0; i<BIN_FILES_COUNT; i++) {
|
||||||
|
Brain.LCD_printf("Flashing file %u", i);
|
||||||
|
size_t wr_count = Brain.essp32_programFlash(bin_files[i].fpath, bin_files[i].addr);
|
||||||
|
total_bytes += wr_count;
|
||||||
|
if (!wr_count) {
|
||||||
|
Brain.LCD_printf_error("Failed to flash");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print_speed(total_bytes, millis() - ms);
|
||||||
|
|
||||||
|
Brain.esp32_end();
|
||||||
|
|
||||||
|
// reset ESP32 to run new firmware
|
||||||
|
Brain.targetReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Setup and Loop on Core1
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
// call usbh_begin() here to make pio usb background task run on core1
|
||||||
|
// NOTE: Brain.begin() should be called here as well to prevent race condition
|
||||||
|
void setup1() {
|
||||||
|
Brain.begin();
|
||||||
|
Brain.usbh_begin();
|
||||||
|
|
||||||
|
Brain.LCD_printf(1, "No USB Device");
|
||||||
|
}
|
||||||
|
|
||||||
|
// core1's loop: process usb host task on core1
|
||||||
|
void loop1() {
|
||||||
|
Brain.USBHost.task();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// TinyUSB Host callbacks
|
||||||
|
// Note: running in the same core where Brain.USBHost.task() is called
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
// Invoked when device is mounted (configured)
|
||||||
|
void tuh_mount_cb (uint8_t dev_addr)
|
||||||
|
{
|
||||||
|
(void) dev_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invoked when device is unmounted (bus reset/unplugged)
|
||||||
|
void tuh_umount_cb(uint8_t dev_addr)
|
||||||
|
{
|
||||||
|
(void) dev_addr;
|
||||||
|
Brain.LCD_printf(1, "No USB Device");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -59,7 +59,8 @@ void setup1() {
|
||||||
|
|
||||||
// Since we only support 1 CDC interface with Tester (also CFG_TUH_CDC = 1)
|
// Since we only support 1 CDC interface with Tester (also CFG_TUH_CDC = 1)
|
||||||
// the index will always be 0 for SerialHost
|
// the index will always be 0 for SerialHost
|
||||||
SerialHost.begin(0);
|
// SerialHost.setInterfaceIndex(0);
|
||||||
|
SerialHost.begin(115200);
|
||||||
|
|
||||||
Brain.LCD_printf(0, "No USB attached");
|
Brain.LCD_printf(0, "No USB attached");
|
||||||
Brain.LCD_printf(1, "Plug your device");
|
Brain.LCD_printf(1, "Plug your device");
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,7 @@ Adafruit_TestBed_Brains::Adafruit_TestBed_Brains() {
|
||||||
_target_swdclk = 3;
|
_target_swdclk = 3;
|
||||||
|
|
||||||
dap = NULL;
|
dap = NULL;
|
||||||
|
esp32boot = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Adafruit_TestBed_Brains::begin(void) {
|
void Adafruit_TestBed_Brains::begin(void) {
|
||||||
|
|
@ -389,6 +390,114 @@ size_t Adafruit_TestBed_Brains::dap_programFlash(const char *fpath,
|
||||||
return fsize;
|
return fsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// ESP32 Target
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
bool Adafruit_TestBed_Brains::esp32_begin(ESP32BootROMClass *bootrom,
|
||||||
|
uint32_t baudrate) {
|
||||||
|
esp32boot = bootrom;
|
||||||
|
|
||||||
|
LCD_printf("Syncing ESP32");
|
||||||
|
bool ret = esp32boot->begin(baudrate);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
LCD_printf("Synced OK");
|
||||||
|
} else {
|
||||||
|
LCD_printf_error("Sync failed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Adafruit_TestBed_Brains::esp32_end(void) {
|
||||||
|
esp32boot->endFlash(false);
|
||||||
|
esp32boot->end();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Adafruit_TestBed_Brains::essp32_programFlash(const char *fpath,
|
||||||
|
uint32_t addr) {
|
||||||
|
if (!esp32boot) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum { MAX_PAYLOAD_SIZE = 1024 };
|
||||||
|
|
||||||
|
uint8_t *buf = (uint8_t *)malloc(MAX_PAYLOAD_SIZE);
|
||||||
|
if (!buf) {
|
||||||
|
LCD_printf_error("No memory %u\n", MAX_PAYLOAD_SIZE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
File32 fsrc = SD.open(fpath);
|
||||||
|
if (!fsrc) {
|
||||||
|
Serial.printf("SD: cannot open file: %s\r\n", fpath);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
uint32_t fsize = fsrc.fileSize();
|
||||||
|
uint32_t total_count = 0;
|
||||||
|
|
||||||
|
if (!esp32boot->beginFlash(addr, fsize, MAX_PAYLOAD_SIZE)) {
|
||||||
|
LCD_printf_error("beginFlash failed!");
|
||||||
|
} else {
|
||||||
|
LCD_printf("#Packets %u", fsize / MAX_PAYLOAD_SIZE);
|
||||||
|
|
||||||
|
MD5Builder md5;
|
||||||
|
md5.begin();
|
||||||
|
|
||||||
|
//------------- Flashing -------------//
|
||||||
|
while (fsrc.available()) {
|
||||||
|
memset(buf, 0xff, MAX_PAYLOAD_SIZE); // empty it out
|
||||||
|
uint32_t rd_count = fsrc.read(buf, MAX_PAYLOAD_SIZE);
|
||||||
|
|
||||||
|
setLED(HIGH);
|
||||||
|
Serial.printf("#");
|
||||||
|
if (!esp32boot->dataFlash(buf, MAX_PAYLOAD_SIZE)) {
|
||||||
|
LCD_printf_error("Failed to flash");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
setLED(LOW);
|
||||||
|
|
||||||
|
md5.add(buf, rd_count);
|
||||||
|
total_count += rd_count;
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
//------------- MD5 verification -------------//
|
||||||
|
md5.calculate();
|
||||||
|
Serial.printf("md5 = %s\r\n", md5.toString().c_str());
|
||||||
|
|
||||||
|
uint8_t file_md5[16];
|
||||||
|
md5.getBytes(file_md5);
|
||||||
|
|
||||||
|
uint8_t esp_md5[16];
|
||||||
|
esp32boot->md5Flash(addr, fsize, esp_md5);
|
||||||
|
|
||||||
|
if (0 == memcmp(file_md5, esp_md5, 16)) {
|
||||||
|
LCD_printf("MD5 matched");
|
||||||
|
} else {
|
||||||
|
LCD_printf_error("MD5 mismatched!!");
|
||||||
|
|
||||||
|
Serial.printf("File: ");
|
||||||
|
for (size_t i = 0; i < 16; i++) {
|
||||||
|
Serial.printf("%02X ", file_md5[i]);
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
Serial.printf("ESP : ");
|
||||||
|
for (size_t i = 0; i < 16; i++) {
|
||||||
|
Serial.printf("%02X ", esp_md5[i]);
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
fsrc.close();
|
||||||
|
|
||||||
|
return total_count;
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// SD Card
|
// SD Card
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
@ -511,27 +620,28 @@ void Adafruit_TestBed_Brains::lcd_write(uint8_t linenum, char linebuf[17]) {
|
||||||
_lcd_line = 1 - linenum;
|
_lcd_line = 1 - linenum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define _LCD_PRINTF(_line, _format) \
|
||||||
|
do { \
|
||||||
|
char linebuf[17]; \
|
||||||
|
va_list ap; \
|
||||||
|
va_start(ap, _format); \
|
||||||
|
vsnprintf(linebuf, sizeof(linebuf), _format, ap); \
|
||||||
|
va_end(ap); \
|
||||||
|
lcd_write(_line, linebuf); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
void Adafruit_TestBed_Brains::LCD_printf(uint8_t linenum, const char format[],
|
void Adafruit_TestBed_Brains::LCD_printf(uint8_t linenum, const char format[],
|
||||||
...) {
|
...) {
|
||||||
char linebuf[17];
|
_LCD_PRINTF(linenum, format);
|
||||||
|
|
||||||
va_list ap;
|
|
||||||
va_start(ap, format);
|
|
||||||
vsnprintf(linebuf, sizeof(linebuf), format, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
lcd_write(linenum, linebuf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Adafruit_TestBed_Brains::LCD_printf(const char format[], ...) {
|
void Adafruit_TestBed_Brains::LCD_printf(const char format[], ...) {
|
||||||
char linebuf[17];
|
_LCD_PRINTF(_lcd_line, format);
|
||||||
|
}
|
||||||
|
|
||||||
va_list ap;
|
void Adafruit_TestBed_Brains::LCD_printf_error(const char format[], ...) {
|
||||||
va_start(ap, format);
|
setColor(0xFF0000);
|
||||||
vsnprintf(linebuf, sizeof(linebuf), format, ap);
|
_LCD_PRINTF(_lcd_line, format);
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
lcd_write(_lcd_line, linebuf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Adafruit_TestBed_Brains::LCD_info(const char *msg1, const char *msg2) {
|
void Adafruit_TestBed_Brains::LCD_info(const char *msg1, const char *msg2) {
|
||||||
|
|
@ -10,6 +10,9 @@
|
||||||
#include "Adafruit_DAP.h"
|
#include "Adafruit_DAP.h"
|
||||||
#include "Adafruit_TinyUSB.h"
|
#include "Adafruit_TinyUSB.h"
|
||||||
|
|
||||||
|
#include "ESP32BootROM.h"
|
||||||
|
#include "MD5Builder.h"
|
||||||
|
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
/*!
|
/*!
|
||||||
@brief A helper class for making RP2040 "Tester Brains"
|
@brief A helper class for making RP2040 "Tester Brains"
|
||||||
|
|
@ -21,12 +24,17 @@ public:
|
||||||
void begin(void);
|
void begin(void);
|
||||||
bool inited(void);
|
bool inited(void);
|
||||||
|
|
||||||
// LCD
|
//------------- LCD -------------//
|
||||||
// printf on specified line
|
|
||||||
|
// printf on specific line
|
||||||
void LCD_printf(uint8_t linenum, const char format[], ...);
|
void LCD_printf(uint8_t linenum, const char format[], ...);
|
||||||
|
|
||||||
// printf on next line
|
// printf on next line
|
||||||
void LCD_printf(const char format[], ...);
|
void LCD_printf(const char format[], ...);
|
||||||
|
|
||||||
|
// printf on error (RGB = RED)
|
||||||
|
void LCD_printf_error(const char format[], ...);
|
||||||
|
|
||||||
void LCD_error(const char *errmsg1, const char *errmsg2);
|
void LCD_error(const char *errmsg1, const char *errmsg2);
|
||||||
void LCD_info(const char *msg1, const char *msg2);
|
void LCD_info(const char *msg1, const char *msg2);
|
||||||
|
|
||||||
|
|
@ -46,7 +54,9 @@ public:
|
||||||
// Target
|
// Target
|
||||||
void targetReset(uint32_t reset_ms = 20);
|
void targetReset(uint32_t reset_ms = 20);
|
||||||
|
|
||||||
//------------- RP2040 target -------------//
|
//--------------------------------------------------------------------+
|
||||||
|
// RP2040 Target
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
// reset rp2040 target to Boot ROM
|
// reset rp2040 target to Boot ROM
|
||||||
void rp2040_targetResetBootRom(int bootsel_pin = 28, uint32_t reset_ms = 20);
|
void rp2040_targetResetBootRom(int bootsel_pin = 28, uint32_t reset_ms = 20);
|
||||||
|
|
||||||
|
|
@ -54,7 +64,9 @@ public:
|
||||||
// return number of copied bytes (typically uf2 file size)
|
// return number of copied bytes (typically uf2 file size)
|
||||||
size_t rp2040_programUF2(const char *fpath);
|
size_t rp2040_programUF2(const char *fpath);
|
||||||
|
|
||||||
//------------- SAMD21 target -------------//
|
//--------------------------------------------------------------------+
|
||||||
|
// DAP (samd21/51, nrf5x, stm32f4 etc..) Target
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
bool dap_begin(Adafruit_DAP *dp);
|
bool dap_begin(Adafruit_DAP *dp);
|
||||||
bool dap_connect(void);
|
bool dap_connect(void);
|
||||||
void dap_disconnect(void);
|
void dap_disconnect(void);
|
||||||
|
|
@ -68,7 +80,21 @@ public:
|
||||||
// return number of programmed bytes
|
// return number of programmed bytes
|
||||||
size_t dap_programFlash(const char *fpath, uint32_t addr);
|
size_t dap_programFlash(const char *fpath, uint32_t addr);
|
||||||
|
|
||||||
//------------- Public Variables -------------//
|
//--------------------------------------------------------------------+
|
||||||
|
// ESP32 Target
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
bool esp32_begin(ESP32BootROMClass *bootrom, uint32_t baudrate);
|
||||||
|
void esp32_end(void);
|
||||||
|
|
||||||
|
// program esp32 target with file from SDCard
|
||||||
|
// return number of programmed bytes
|
||||||
|
size_t essp32_programFlash(const char *fpath, uint32_t addr);
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Public Variables
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
LiquidCrystal lcd = LiquidCrystal(7, 8, 9, 10, 11, 12);
|
LiquidCrystal lcd = LiquidCrystal(7, 8, 9, 10, 11, 12);
|
||||||
SdFat SD;
|
SdFat SD;
|
||||||
SdSpiConfig SD_CONFIG = SdSpiConfig(17, SHARED_SPI, SD_SCK_MHZ(16));
|
SdSpiConfig SD_CONFIG = SdSpiConfig(17, SHARED_SPI, SD_SCK_MHZ(16));
|
||||||
|
|
@ -80,8 +106,12 @@ public:
|
||||||
FatVolume USBH_FS;
|
FatVolume USBH_FS;
|
||||||
Adafruit_USBH_MSC_BlockDevice USBH_BlockDev;
|
Adafruit_USBH_MSC_BlockDevice USBH_BlockDev;
|
||||||
|
|
||||||
|
// Dap
|
||||||
Adafruit_DAP *dap;
|
Adafruit_DAP *dap;
|
||||||
|
|
||||||
|
// ESP32 ROM
|
||||||
|
ESP32BootROMClass *esp32boot;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _inited;
|
bool _inited;
|
||||||
uint8_t _lcd_line;
|
uint8_t _lcd_line;
|
||||||
373
src/ESP32BootROM.cpp
Normal file
373
src/ESP32BootROM.cpp
Normal file
|
|
@ -0,0 +1,373 @@
|
||||||
|
/*
|
||||||
|
ESP32BootROM - part of the Firmware Updater for the
|
||||||
|
Arduino MKR WiFi 1010, Arduino MKR Vidor 4000, and Arduino UNO WiFi Rev.2.
|
||||||
|
|
||||||
|
Copyright (c) 2018 Arduino SA. All rights reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ESP32BootROM.h"
|
||||||
|
|
||||||
|
#define DEBUG 0
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
#define DBG_PRINTF(...) Serial.printf(__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define DBG_PRINTF(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum {
|
||||||
|
// Commands supported by ESP8266 ROM bootloader
|
||||||
|
ESP_FLASH_BEGIN = 0x02,
|
||||||
|
ESP_FLASH_DATA = 0x03,
|
||||||
|
ESP_FLASH_END = 0x04,
|
||||||
|
ESP_MEM_BEGIN = 0x05,
|
||||||
|
ESP_MEM_END = 0x06,
|
||||||
|
ESP_MEM_DATA = 0x07,
|
||||||
|
ESP_SYNC = 0x08,
|
||||||
|
ESP_WRITE_REG = 0x09,
|
||||||
|
ESP_READ_REG = 0x0A,
|
||||||
|
|
||||||
|
// Some comands supported by ESP32 and later chips ROM bootloader (or -8266 w/
|
||||||
|
// stub)
|
||||||
|
ESP_SPI_SET_PARAMS = 0x0B,
|
||||||
|
ESP_SPI_ATTACH = 0x0D,
|
||||||
|
ESP_READ_FLASH_SLOW = 0x0E, // ROM only, much slower than the stub flash read
|
||||||
|
ESP_CHANGE_BAUDRATE = 0x0F,
|
||||||
|
ESP_FLASH_DEFL_BEGIN = 0x10,
|
||||||
|
ESP_FLASH_DEFL_DATA = 0x11,
|
||||||
|
ESP_FLASH_DEFL_END = 0x12,
|
||||||
|
ESP_SPI_FLASH_MD5 = 0x13,
|
||||||
|
|
||||||
|
// Commands supported by ESP32-S2 and later chips ROM bootloader only
|
||||||
|
ESP_GET_SECURITY_INFO = 0x14,
|
||||||
|
|
||||||
|
// Some commands supported by stub only
|
||||||
|
ESP_ERASE_FLASH = 0xD0,
|
||||||
|
ESP_ERASE_REGION = 0xD1,
|
||||||
|
ESP_READ_FLASH = 0xD2,
|
||||||
|
ESP_RUN_USER_CODE = 0xD3,
|
||||||
|
|
||||||
|
// Flash encryption encrypted data command
|
||||||
|
ESP_FLASH_ENCRYPT_DATA = 0xD4,
|
||||||
|
|
||||||
|
// Response code(s) sent by ROM
|
||||||
|
ROM_INVALID_RECV_MSG = 0x05, // response if an invalid message is received
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
// Maximum block sized for RAM and Flash writes, respectively.
|
||||||
|
ESP_RAM_BLOCK = 0x1800,
|
||||||
|
|
||||||
|
FLASH_WRITE_SIZE = 0x400,
|
||||||
|
|
||||||
|
// Default baudrate. The ROM auto-bauds, so we can use more or less whatever
|
||||||
|
// we want.
|
||||||
|
ESP_ROM_BAUD = 115200,
|
||||||
|
|
||||||
|
// First byte of the application image
|
||||||
|
ESP_IMAGE_MAGIC = 0xE9,
|
||||||
|
|
||||||
|
// Initial state for the checksum routine
|
||||||
|
ESP_CHECKSUM_MAGIC = 0xEF,
|
||||||
|
|
||||||
|
// Flash sector size, minimum unit of erase.
|
||||||
|
// FLASH_SECTOR_SIZE = 0x1000,
|
||||||
|
|
||||||
|
UART_DATE_REG_ADDR = 0x60000078,
|
||||||
|
|
||||||
|
// This ROM address has a different value on each chip model
|
||||||
|
CHIP_DETECT_MAGIC_REG_ADDR = 0x40001000,
|
||||||
|
|
||||||
|
UART_CLKDIV_MASK = 0xFFFFF,
|
||||||
|
|
||||||
|
// Memory addresses
|
||||||
|
IROM_MAP_START = 0x40200000,
|
||||||
|
IROM_MAP_END = 0x40300000,
|
||||||
|
|
||||||
|
// The number of bytes in the UART response that signify command status
|
||||||
|
// STATUS_BYTES_LENGTH = 2,
|
||||||
|
|
||||||
|
// Bootloader flashing offset
|
||||||
|
// BOOTLOADER_FLASH_OFFSET = 0x0,
|
||||||
|
|
||||||
|
// ROM supports an encrypted flashing mode
|
||||||
|
// SUPPORTS_ENCRYPTED_FLASH = False,
|
||||||
|
|
||||||
|
// Response to ESP_SYNC might indicate that flasher stub is running
|
||||||
|
// instead of the ROM bootloader
|
||||||
|
// sync_stub_detected = False,
|
||||||
|
|
||||||
|
// Device PIDs
|
||||||
|
USB_JTAG_SERIAL_PID = 0x1001
|
||||||
|
};
|
||||||
|
|
||||||
|
ESP32BootROMClass::ESP32BootROMClass(HardwareSerial &serial, int gpio0Pin,
|
||||||
|
int resetnPin, bool supportsEncryptedFlash)
|
||||||
|
: _serial(&serial), _gpio0Pin(gpio0Pin), _resetnPin(resetnPin),
|
||||||
|
_supports_encrypted_flash(supportsEncryptedFlash) {}
|
||||||
|
|
||||||
|
int ESP32BootROMClass::begin(unsigned long baudrate) {
|
||||||
|
_serial->begin(115200);
|
||||||
|
|
||||||
|
pinMode(_gpio0Pin, OUTPUT);
|
||||||
|
pinMode(_resetnPin, OUTPUT);
|
||||||
|
|
||||||
|
digitalWrite(_gpio0Pin, LOW);
|
||||||
|
digitalWrite(_resetnPin, LOW);
|
||||||
|
delay(10);
|
||||||
|
|
||||||
|
digitalWrite(_resetnPin, HIGH);
|
||||||
|
delay(50);
|
||||||
|
|
||||||
|
// Wait for serial, needed if using with SerialHost (host cdc)
|
||||||
|
while (!_serial) {
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(50); // additional delay for SerialHost connected
|
||||||
|
digitalWrite(_gpio0Pin, HIGH);
|
||||||
|
|
||||||
|
int synced = 0;
|
||||||
|
|
||||||
|
for (int retries = 0; !synced && (retries < 10); retries++) {
|
||||||
|
Serial.println("Trying to sync");
|
||||||
|
synced = sync();
|
||||||
|
}
|
||||||
|
if (!synced) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println("Synced!");
|
||||||
|
|
||||||
|
if (baudrate != 115200) {
|
||||||
|
if (!changeBaudrate(baudrate)) {
|
||||||
|
Serial.print("Failed to change baudrate");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// _serial->end();
|
||||||
|
delay(100);
|
||||||
|
Serial.println("Updating local Serial baudrate");
|
||||||
|
_serial->begin(baudrate);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!spiAttach()) {
|
||||||
|
Serial.println("Failed to attach SPI");
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP32BootROMClass::end() {
|
||||||
|
//_serial->end();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ESP32BootROMClass::sync() {
|
||||||
|
const uint8_t data[] = {0x07, 0x07, 0x12, 0x20, 0x55, 0x55, 0x55, 0x55, 0x55,
|
||||||
|
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
|
||||||
|
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
|
||||||
|
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
|
||||||
|
|
||||||
|
command(ESP_SYNC, data, sizeof(data));
|
||||||
|
|
||||||
|
int results[8];
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
results[i] = response(0x08, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (results[0] == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ESP32BootROMClass::changeBaudrate(unsigned long baudrate) {
|
||||||
|
const uint32_t data[2] = {baudrate, 0};
|
||||||
|
|
||||||
|
command(ESP_CHANGE_BAUDRATE, data, sizeof(data));
|
||||||
|
|
||||||
|
return (response(0x0f, 3000) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ESP32BootROMClass::spiAttach() {
|
||||||
|
const uint8_t data[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
|
command(ESP_SPI_ATTACH, data, sizeof(data));
|
||||||
|
|
||||||
|
return (response(0x0d, 3000) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ESP32BootROMClass::beginFlash(uint32_t offset, uint32_t size,
|
||||||
|
uint32_t chunkSize) {
|
||||||
|
|
||||||
|
const uint32_t data[] = {size, size / chunkSize, chunkSize, offset, 0};
|
||||||
|
uint16_t const len = _supports_encrypted_flash ? 20 : 16;
|
||||||
|
|
||||||
|
command(ESP_FLASH_BEGIN, data, len);
|
||||||
|
|
||||||
|
_flashSequenceNumber = 0;
|
||||||
|
_chunkSize = chunkSize;
|
||||||
|
|
||||||
|
return (response(0x02, 120000) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ESP32BootROMClass::dataFlash(const void *data, uint32_t length) {
|
||||||
|
uint32_t cmdData[4 + (_chunkSize / 4)];
|
||||||
|
|
||||||
|
cmdData[0] = length;
|
||||||
|
cmdData[1] = _flashSequenceNumber++;
|
||||||
|
cmdData[2] = 0;
|
||||||
|
cmdData[3] = 0;
|
||||||
|
|
||||||
|
memcpy(&cmdData[4], data, length);
|
||||||
|
|
||||||
|
if (length < _chunkSize) {
|
||||||
|
memset(&cmdData[4 + (length / 4)], 0xff, _chunkSize - length);
|
||||||
|
}
|
||||||
|
|
||||||
|
command(ESP_FLASH_DATA, cmdData, sizeof(cmdData));
|
||||||
|
|
||||||
|
return (response(0x03, 3000) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ESP32BootROMClass::endFlash(uint32_t reboot) {
|
||||||
|
const uint32_t data[1] = {reboot};
|
||||||
|
|
||||||
|
command(ESP_FLASH_END, data, sizeof(data));
|
||||||
|
|
||||||
|
return (response(0x04, 3000) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ESP32BootROMClass::md5Flash(uint32_t offset, uint32_t size,
|
||||||
|
uint8_t *result) {
|
||||||
|
const uint32_t data[4] = {offset, size, 0, 0};
|
||||||
|
|
||||||
|
command(ESP_SPI_FLASH_MD5, data, sizeof(data));
|
||||||
|
|
||||||
|
uint8_t asciiResult[32];
|
||||||
|
|
||||||
|
if (response(0x13, 3000, asciiResult) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char temp[3] = {0, 0, 0};
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
temp[0] = asciiResult[i * 2];
|
||||||
|
temp[1] = asciiResult[i * 2 + 1];
|
||||||
|
|
||||||
|
result[i] = strtoul(temp, NULL, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP32BootROMClass::command(int opcode, const void *data, uint16_t length) {
|
||||||
|
uint32_t checksum = 0;
|
||||||
|
|
||||||
|
if (opcode == ESP_FLASH_DATA) {
|
||||||
|
checksum = 0xef; // seed
|
||||||
|
|
||||||
|
for (uint16_t i = 16; i < length; i++) {
|
||||||
|
checksum ^= ((const uint8_t *)data)[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DBG_PRINTF("=> c0 00 %02x %02x %02x ", opcode, length & 0x00ff, length >> 8);
|
||||||
|
|
||||||
|
_serial->write(0xc0);
|
||||||
|
_serial->write((uint8_t)0x00); // direction
|
||||||
|
_serial->write(opcode);
|
||||||
|
_serial->write((uint8_t *)&length, sizeof(length));
|
||||||
|
writeEscapedBytes((uint8_t *)&checksum, sizeof(checksum));
|
||||||
|
writeEscapedBytes((uint8_t *)data, length);
|
||||||
|
_serial->write(0xc0);
|
||||||
|
_serial->flush();
|
||||||
|
|
||||||
|
DBG_PRINTF("c0\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int ESP32BootROMClass::response(int opcode, unsigned long timeout, void *body) {
|
||||||
|
uint8_t data[10 + 256];
|
||||||
|
uint16_t index = 0;
|
||||||
|
|
||||||
|
uint8_t responseLength = 4;
|
||||||
|
|
||||||
|
unsigned long start = millis();
|
||||||
|
while ((millis() - start) < timeout) {
|
||||||
|
if (_serial->available()) {
|
||||||
|
data[index] = _serial->read();
|
||||||
|
|
||||||
|
if (index == 3) {
|
||||||
|
responseLength = data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
if (index >= (uint16_t)(10 + responseLength)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
if (index) {
|
||||||
|
Serial.print("<= ");
|
||||||
|
for (int i = 0; i < index; i++) {
|
||||||
|
Serial.printf("%02x ", data[i]);
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (index != (uint16_t)(10 + responseLength)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[0] != 0xc0 || data[1] != 0x01 || data[2] != opcode ||
|
||||||
|
data[responseLength + 5] != 0x00 || data[responseLength + 6] != 0x00 ||
|
||||||
|
data[responseLength + 9] != 0xc0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body) {
|
||||||
|
memcpy(body, &data[9], responseLength - 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
return data[responseLength + 5];
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP32BootROMClass::writeEscapedBytes(const uint8_t *data,
|
||||||
|
uint16_t length) {
|
||||||
|
uint16_t written = 0;
|
||||||
|
|
||||||
|
while (written < length) {
|
||||||
|
uint8_t b = data[written++];
|
||||||
|
|
||||||
|
if (b == 0xdb) {
|
||||||
|
_serial->write(0xdb);
|
||||||
|
_serial->write(0xdd);
|
||||||
|
|
||||||
|
DBG_PRINTF("db db ");
|
||||||
|
} else if (b == 0xc0) {
|
||||||
|
_serial->write(0xdb);
|
||||||
|
_serial->write(0xdc);
|
||||||
|
|
||||||
|
DBG_PRINTF("db dc ");
|
||||||
|
} else {
|
||||||
|
_serial->write(b);
|
||||||
|
DBG_PRINTF("%02x ", b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
59
src/ESP32BootROM.h
Normal file
59
src/ESP32BootROM.h
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
ESP32BootROM - part of the Firmware Updater for the
|
||||||
|
Arduino MKR WiFi 1010, Arduino MKR Vidor 4000, and Arduino UNO WiFi Rev.2.
|
||||||
|
|
||||||
|
Copyright (c) 2018 Arduino SA. All rights reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
class ESP32BootROMClass {
|
||||||
|
public:
|
||||||
|
// supportsEncryptedFlash must be set to
|
||||||
|
// - false for ESP32 (default)
|
||||||
|
// - true for later chips such as S2, S3, H2, C3
|
||||||
|
ESP32BootROMClass(HardwareSerial &hwSerial, int gpio0Pin, int resetnPin,
|
||||||
|
bool supportsEncryptedFlash = false);
|
||||||
|
|
||||||
|
int begin(unsigned long baudrate);
|
||||||
|
void end();
|
||||||
|
|
||||||
|
int beginFlash(uint32_t offset, uint32_t size, uint32_t chunkSize);
|
||||||
|
int dataFlash(const void *data, uint32_t length);
|
||||||
|
int endFlash(uint32_t reboot);
|
||||||
|
|
||||||
|
int md5Flash(uint32_t offset, uint32_t size, uint8_t *result);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int sync();
|
||||||
|
int changeBaudrate(unsigned long baudrate);
|
||||||
|
int spiAttach();
|
||||||
|
|
||||||
|
void command(int opcode, const void *data, uint16_t length);
|
||||||
|
int response(int opcode, unsigned long timeout, void *body = NULL);
|
||||||
|
|
||||||
|
void writeEscapedBytes(const uint8_t *data, uint16_t length);
|
||||||
|
|
||||||
|
private:
|
||||||
|
HardwareSerial *_serial;
|
||||||
|
int _gpio0Pin;
|
||||||
|
int _resetnPin;
|
||||||
|
bool _supports_encrypted_flash;
|
||||||
|
|
||||||
|
uint32_t _flashSequenceNumber;
|
||||||
|
uint32_t _chunkSize;
|
||||||
|
};
|
||||||
Loading…
Reference in a new issue