diff --git a/examples/Brain/program_esp32_uart/program_esp32_uart.ino b/examples/Brain/program_esp32_uart/program_esp32_uart.ino index 62b89b2..7fbed13 100644 --- a/examples/Brain/program_esp32_uart/program_esp32_uart.ino +++ b/examples/Brain/program_esp32_uart/program_esp32_uart.ino @@ -47,9 +47,8 @@ void setup() { while (!Serial) delay(10); Serial.println("Tester Brains: Programming ESP with UART!"); - Brain.begin(); - Brain.usbh_setVBus(true); // enable VBUS for power - + // sync: wait for Brain.begin() called in core1 before accessing SD or other peripherals + while (!Brain.inited()) delay(10); while ( !Brain.esp32_begin(&ESP32BootROM, ESP32_BAUDRATE) ) { // retry syncing delay(100); @@ -77,3 +76,61 @@ void setup() { 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(0, "No USB attached"); + Brain.LCD_printf(1, "Plug your device"); +} + +// core1's loop: process usb host task on core1 +void loop1() { + if ( Brain.esp32_s3_inReset() ){ + // Note: S3 has an USB-OTG errata + // https://www.espressif.com/sites/default/files/documentation/esp32-s3_errata_en.pdf + // which is walkarounded by idf/arduino-esp32 to always mux JTAG to USB for + // uploading and/or power on. Afterwards USB-OTG will be set up if selected + // so. However rp2040 USBH is running too fast and can actually retrieve + // device/configuration descriptor of JTAG before the OTG is fully setup. + // We delay a bit here + delay(500); + + Brain.esp32_s3_clearReset(); + } + + Brain.USBHost.task(); + yield(); +} + +//--------------------------------------------------------------------+ +// 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"); +} + +} diff --git a/examples/Brain/program_nrf52840/program_nrf52840.ino b/examples/Brain/program_nrf52840/program_nrf52840.ino index f33e8fc..1d56f9c 100644 --- a/examples/Brain/program_nrf52840/program_nrf52840.ino +++ b/examples/Brain/program_nrf52840/program_nrf52840.ino @@ -17,11 +17,7 @@ #include "Adafruit_TestBed_Brains.h" -// RP2040 Boot VID/PID -#define BOOT_VID 0x2e8a -#define BOOT_PID 0x0003 - -// file path on SDCard to prograom +// file path on SDCard to program #define TEST_FILE_PATH "nrf/feather_nrf52840/bleblink.bin" // DAP interface for nRF5x @@ -66,8 +62,10 @@ void setup() { // erase chip before programming Brain.dap_eraseChip(); + // for nrf52840 don't use crc32 as it is not supported. + // Note: verify is with reading back increase programming time by 2x uint32_t ms = millis(); - size_t copied_bytes = Brain.dap_programFlash(TEST_FILE_PATH, 0); + size_t copied_bytes = Brain.dap_programFlash(TEST_FILE_PATH, 0, true, false); ms = millis() - ms; print_speed(copied_bytes, ms); @@ -110,9 +108,7 @@ void tuh_mount_cb (uint8_t dev_addr) uint16_t vid, pid; tuh_vid_pid_get(dev_addr, &vid, &pid); - if ( !(vid == BOOT_VID && pid == BOOT_PID) ) { - Brain.LCD_printf(1, "UnkDev %04x:%04x", vid, pid); - } + Brain.LCD_printf("USBID %04x:%04x", vid, pid); } /// Invoked when device is unmounted (bus reset/unplugged) diff --git a/examples/Brain/program_nrf52840_from_sdcard/.pico_rp2040_tinyusb.test.only b/examples/Brain/program_nrf52840_from_sdcard/.pico_rp2040_tinyusb.test.only new file mode 100644 index 0000000..e69de29 diff --git a/examples/Brain/program_nrf52840_from_sdcard/bleblink.bin b/examples/Brain/program_nrf52840_from_sdcard/bleblink.bin new file mode 100644 index 0000000..451fb0f Binary files /dev/null and b/examples/Brain/program_nrf52840_from_sdcard/bleblink.bin differ diff --git a/examples/Brain/program_nrf52840_from_sdcard/program_nrf52840_from_sdcard.ino b/examples/Brain/program_nrf52840_from_sdcard/program_nrf52840_from_sdcard.ino new file mode 100644 index 0000000..1d56f9c --- /dev/null +++ b/examples/Brain/program_nrf52840_from_sdcard/program_nrf52840_from_sdcard.ino @@ -0,0 +1,121 @@ +// This sketch program SAMD with bin file from SDCard using Adafruit_DAP +// Hardware wiring: +// - Brain's header Reset <-> Target Reset +// - Brain's header SWDIO <-> Target SWDIO +// - Brain's header SWCLK <-> Target SWCLK +// - Brain's USB host to Target USB + +// required for Host MSC block device +#include "SdFat.h" + +// required for USB host +#include "pio_usb.h" +#include "Adafruit_TinyUSB.h" + +// required for DAP programming +#include "Adafruit_DAP.h" + +#include "Adafruit_TestBed_Brains.h" + +// file path on SDCard to program +#define TEST_FILE_PATH "nrf/feather_nrf52840/bleblink.bin" + +// DAP interface for nRF5x +Adafruit_DAP_nRF5x dap; + +//--------------------------------------------------------------------+ +// Setup and Loop on Core0 +//--------------------------------------------------------------------+ + +void print_speed(size_t count, uint32_t ms) { + Brain.LCD_printf(0, "%.01fKB in %.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: nRF52840 programming !"); + + // sync: wait for Brain.usbh_begin() called in core1 before accessing SD or other peripherals + while (!Brain.usbh_inited()) delay(10); + + Brain.SD_begin(SD_SCK_MHZ(16)); + + // 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_SIZE); + } + + Brain.targetReset(); + + Brain.dap_begin(&dap); + Brain.dap_connect(); + + Brain.dap_unprotectBoot(); + + // erase chip before programming + Brain.dap_eraseChip(); + + // for nrf52840 don't use crc32 as it is not supported. + // Note: verify is with reading back increase programming time by 2x + uint32_t ms = millis(); + size_t copied_bytes = Brain.dap_programFlash(TEST_FILE_PATH, 0, true, false); + ms = millis() - ms; + print_speed(copied_bytes, ms); + + Brain.dap_protectBoot(); + Brain.dap_disconnect(); + + 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) +{ + uint16_t vid, pid; + tuh_vid_pid_get(dev_addr, &vid, &pid); + + 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"); +} + +} diff --git a/examples/Brain/read_nrf52840_to_sdcard/.pico_rp2040_tinyusb.test.only b/examples/Brain/read_nrf52840_to_sdcard/.pico_rp2040_tinyusb.test.only new file mode 100644 index 0000000..e69de29 diff --git a/examples/Brain/read_nrf52840_to_sdcard/read_nrf52840_to_sdcard.ino b/examples/Brain/read_nrf52840_to_sdcard/read_nrf52840_to_sdcard.ino new file mode 100644 index 0000000..a19e5b2 --- /dev/null +++ b/examples/Brain/read_nrf52840_to_sdcard/read_nrf52840_to_sdcard.ino @@ -0,0 +1,112 @@ +// This sketch program SAMD with bin file from SDCard using Adafruit_DAP +// Hardware wiring: +// - Brain's header Reset <-> Target Reset +// - Brain's header SWDIO <-> Target SWDIO +// - Brain's header SWCLK <-> Target SWCLK +// - Brain's USB host to Target USB + +// required for Host MSC block device +#include "SdFat.h" + +// required for USB host +#include "pio_usb.h" +#include "Adafruit_TinyUSB.h" + +// required for DAP programming +#include "Adafruit_DAP.h" + +#include "Adafruit_TestBed_Brains.h" + +// file path on SDCard to hold nrf52840 binary +#define READ_FILE_PATH "nrf/readback.bin" +#define READ_SIZE (1024u*1024u) // 1 MB + +// DAP interface for nRF5x +Adafruit_DAP_nRF5x dap; + +//--------------------------------------------------------------------+ +// Setup and Loop on Core0 +//--------------------------------------------------------------------+ + +void print_speed(size_t count, uint32_t ms) { + Brain.LCD_printf(0, "%.01fKB in %.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: Reading nRF52840 to SD Card!"); + + // sync: wait for Brain.usbh_begin() called in core1 before accessing SD or other peripherals + while (!Brain.usbh_inited()) delay(10); + + Brain.SD_begin(SD_SCK_MHZ(16)); + + // 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_SIZE); + } + + Brain.targetReset(); + Brain.dap_begin(&dap); + Brain.dap_connect(); + + uint32_t ms = millis(); + size_t nbytes = Brain.dap_readFlash(READ_FILE_PATH, 0, READ_SIZE); + ms = millis() - ms; + print_speed(nbytes, ms); + + Brain.dap_disconnect(); + 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) +{ + uint16_t vid, pid; + tuh_vid_pid_get(dev_addr, &vid, &pid); + + 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"); +} + +} diff --git a/src/Adafruit_TestBed_Brains.cpp b/src/Adafruit_TestBed_Brains.cpp index 3d09d5a..4164101 100644 --- a/src/Adafruit_TestBed_Brains.cpp +++ b/src/Adafruit_TestBed_Brains.cpp @@ -262,9 +262,9 @@ bool Adafruit_TestBed_Brains::dap_unprotectBoot(void) { return false; } - LCD_printf("Unlock chip..."); + Serial.println("Unlock chip..."); bool ret = dap->unprotectBoot(); - LCD_printf(ret ? "OK" : "Failed"); + Serial.println(ret ? "OK" : "Failed"); return ret; } @@ -273,9 +273,9 @@ bool Adafruit_TestBed_Brains::dap_protectBoot(void) { return false; } - LCD_printf("Lock chip..."); + Serial.println("Lock chip..."); bool ret = dap->protectBoot(); - LCD_printf(ret ? "OK" : "Failed"); + Serial.println(ret ? "OK" : "Failed"); return ret; } @@ -296,14 +296,15 @@ bool Adafruit_TestBed_Brains::dap_eraseChip(void) { dap->erase(); ms = millis() - ms; - LCD_printf("done in %.02fs", ms / 1000.0F); + LCD_printf("Erased in %.02fs", ms / 1000.0F); } return true; } size_t Adafruit_TestBed_Brains::dap_programFlash(const char *fpath, - uint32_t addr) { + uint32_t addr, bool do_verify, + bool do_crc32) { if (!dap) { return 0; } @@ -346,7 +347,8 @@ size_t Adafruit_TestBed_Brains::dap_programFlash(const char *fpath, return 0; } - LCD_printf("Programming.."); + LCD_printf("Programming..."); + uint32_t ms = millis(); BrainCRC32 crc32; dap->program_start(addr, fsize); @@ -354,22 +356,42 @@ size_t Adafruit_TestBed_Brains::dap_programFlash(const char *fpath, uint32_t addr_tmp = addr; while (fsrc.available()) { memset(buf, 0xff, bufsize); // empty it out - uint32_t rd_count = fsrc.read(buf, bufsize); setLED(HIGH); - dap->programBlock(addr_tmp, buf, bufsize); - crc32.add(buf, rd_count); - setLED(LOW); + + // don't verify each write if we use crc32 + if (!dap->programFlash(addr_tmp, buf, bufsize, !do_crc32 && do_verify)) { + Serial.printf("Failed to program block at %08lX\n", addr_tmp); + free(buf); + fsrc.close(); + return addr_tmp - addr; + } + + if (do_crc32) { + crc32.add(buf, rd_count); + } addr_tmp += bufsize; + + setLED(LOW); } - uint32_t target_crc = dap->computeFlashCRC32(addr, fsize); + Serial.printf("Programming end, t = %lu ms\r\n", millis(), millis() - ms); - if (target_crc != crc32.get()) { - LCD_printf("CRC Failed"); - Serial.printf("CRC mismtached: %08lX != %08lX\n", crc32.get(), target_crc); + if (do_crc32) { + ms = millis(); + Serial.printf("CRC32 start\r\n", ms); + uint32_t target_crc = dap->computeFlashCRC32(addr, fsize); + Serial.printf("CRC32 end, t = %lu ms\r\n", millis(), millis() - ms); + + if (target_crc != crc32.get()) { + LCD_printf("CRC Failed"); + Serial.printf("CRC mismtached: %08lX != %08lX\n", crc32.get(), + target_crc); + } else { + LCD_printf("Done!"); + } } else { LCD_printf("Done!"); } @@ -380,6 +402,49 @@ size_t Adafruit_TestBed_Brains::dap_programFlash(const char *fpath, return fsize; } +size_t Adafruit_TestBed_Brains::dap_readFlash(const char *fpath, uint32_t addr, + size_t size) { + if (!dap) { + return 0; + } + + size_t bufsize = 4096; + uint8_t *buf = (uint8_t *)malloc(bufsize); + if (!buf) { + return 0; + } + + File32 fsrc = SD.open(fpath, O_CREAT | O_WRONLY); + if (!fsrc) { + Serial.printf("SD: cannot open file: %s\r\n", fpath); + return 0; + } + + LCD_printf("Reading..."); + + size_t remain = size; + while (remain) { + uint32_t count = min(remain, bufsize); + + setLED(HIGH); + if (!dap->dap_read_block(addr, buf, (int)count)) { + Serial.printf("Failed to read block at %08lX\n", addr); + break; + } + setLED(LOW); + + fsrc.write(buf, count); + + addr += count; + remain -= count; + } + + fsrc.close(); + LCD_printf("Done!"); + + return size - remain; +} + //--------------------------------------------------------------------+ // SD Card //--------------------------------------------------------------------+ diff --git a/src/Adafruit_TestBed_Brains.h b/src/Adafruit_TestBed_Brains.h index 926b139..fe8146f 100644 --- a/src/Adafruit_TestBed_Brains.h +++ b/src/Adafruit_TestBed_Brains.h @@ -49,8 +49,6 @@ class Adafruit_TestBed_Brains : public Adafruit_TestBed { bool usbh_mountFS(uint8_t dev_addr); bool usbh_umountFS(uint8_t dev_addr); - // Target - //--------------------------------------------------------------------+ // RP2040 Target //--------------------------------------------------------------------+ @@ -75,7 +73,12 @@ class Adafruit_TestBed_Brains : public Adafruit_TestBed { // program dap target with file from SDCard // return number of programmed bytes - size_t dap_programFlash(const char *fpath, uint32_t addr); + // Note: if do_crc32 is false, we will verify each write by reading back + size_t dap_programFlash(const char *fpath, uint32_t addr, + bool do_verify = true, bool do_crc32 = true); + + // read dap target flash to file on SDCard + size_t dap_readFlash(const char *fpath, uint32_t addr, size_t size); //--------------------------------------------------------------------+ // Public Variables