Compare commits
236 commits
itsybitsy-
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c6f2a0cc4c | ||
|
|
b138cd1ba1 | ||
|
|
5b4034b0f9 | ||
|
|
0332ed1117 | ||
|
|
6bfd594148 | ||
|
|
ab3624e73b | ||
|
|
2b71fa7422 | ||
|
|
6d16513e79 | ||
|
|
8045dd5c78 | ||
|
|
0b408468ce | ||
|
|
759bdeb282 | ||
|
|
1130b8c29d | ||
|
|
45816d8d0a | ||
|
|
d75faf6081 | ||
|
|
d48670064b | ||
|
|
4125a29235 | ||
|
|
7657c315e3 | ||
|
|
64fc7e33c9 | ||
|
|
cd2ecc5b76 | ||
|
|
bbc2afadf4 | ||
|
|
e0d3b19e47 | ||
|
|
4fb2c089bc | ||
|
|
1805552376 | ||
|
|
948b602102 | ||
|
|
00ea80fce2 | ||
|
|
f3f79e1384 | ||
|
|
0de33c2804 | ||
|
|
228169cbe5 | ||
|
|
d37a36ff29 | ||
|
|
d02093a1b1 | ||
|
|
f13cdaa159 | ||
|
|
87f1fa0d9d | ||
|
|
28fda00cce | ||
|
|
991d04d7a6 | ||
|
|
38c0a286f5 | ||
|
|
293c7f8be2 | ||
|
|
dc494b2be1 | ||
|
|
4b29b6a223 | ||
|
|
26be867d87 | ||
|
|
0bd60196b2 | ||
|
|
e47a9febec | ||
|
|
c5216f28cd | ||
|
|
8ffa1d6ff9 | ||
|
|
fcf8557dd0 | ||
|
|
0daa066f41 | ||
|
|
9a1477f407 | ||
|
|
c25bc452fd | ||
|
|
31c20caf2c | ||
|
|
d379e56c4f | ||
|
|
6e53893034 | ||
|
|
4b31541dc4 | ||
|
|
3930a02dac | ||
|
|
db9ba914b4 | ||
|
|
f6aee1c29a | ||
|
|
b4249f1614 | ||
|
|
c90c7cd375 | ||
|
|
b65bd1fd88 | ||
|
|
6f3b5e73f6 | ||
|
|
782efbfe5a | ||
|
|
c3e647b801 | ||
|
|
2e5afb8b32 | ||
|
|
ce1d1ec7b0 | ||
|
|
5ad6ac8fb6 | ||
|
|
b77e95352f | ||
|
|
31792680b3 | ||
|
|
0cf64c14cf | ||
|
|
92764d6ef1 | ||
|
|
fbe4f207c8 | ||
|
|
689440a95f | ||
|
|
0f8bf4c029 | ||
|
|
3417e50633 | ||
|
|
bfbcf9b7c6 | ||
|
|
03823d562f | ||
|
|
17575513c3 | ||
|
|
0b6ce61c5b | ||
|
|
91f6f7cc72 | ||
|
|
984926b7d8 | ||
|
|
f7ea00b74b | ||
|
|
d19c9f6e4d | ||
|
|
6e013b1c11 | ||
|
|
829d921b35 | ||
|
|
30d2ead4cb | ||
|
|
98ca14c68f | ||
|
|
e631a58b30 | ||
|
|
d4a945f967 | ||
|
|
41eae0f21a | ||
|
|
b5a2854854 | ||
|
|
387a95c819 | ||
|
|
8c7ba727e5 | ||
|
|
e02f558ca8 | ||
|
|
76e28d0e6d | ||
|
|
fd4ecd9b87 | ||
|
|
dfca31499c | ||
|
|
2df3903e52 | ||
|
|
68a73923f5 | ||
|
|
94910676de | ||
|
|
4fa35fbbc7 | ||
|
|
cfd5014475 | ||
|
|
62ffc063d3 | ||
|
|
108db070d7 | ||
|
|
05c4ca3e10 | ||
|
|
30e01cd273 | ||
|
|
6d727217b7 | ||
|
|
fd3acf6fe3 | ||
|
|
125166afde | ||
|
|
5bcbd821b2 | ||
|
|
6fb3ea8bc7 | ||
|
|
b7bd917be0 | ||
|
|
b183a5b31b | ||
|
|
2e8e572dca | ||
|
|
039fb89810 | ||
|
|
33d8bb52d3 | ||
|
|
1bb697f951 | ||
|
|
eabef3a42a | ||
|
|
6e930676c1 | ||
|
|
58c6faceb7 | ||
|
|
008240300b | ||
|
|
0a3dabfc2f | ||
|
|
6d649f4812 | ||
|
|
cfd77f443e | ||
|
|
4325321100 | ||
|
|
566cb691bb | ||
|
|
a9e5d3ed88 | ||
|
|
81b139c124 | ||
|
|
4a1cf8ecde | ||
|
|
3de56de16b | ||
|
|
fcf3f29586 | ||
|
|
442a5d3744 | ||
|
|
70197ab53b | ||
|
|
564de5050d | ||
|
|
e4623a8095 | ||
|
|
9855be25fe | ||
|
|
09fd788cbb | ||
|
|
69a55bde9e | ||
|
|
72c94939c8 | ||
|
|
7145cd3bf4 | ||
|
|
d25855653a | ||
|
|
be5221f5a0 | ||
|
|
16c367c107 | ||
|
|
30417d6e10 | ||
|
|
a357d3bfce | ||
|
|
84329baa36 | ||
|
|
bea8465a25 | ||
|
|
1be22d3c2c | ||
|
|
df276b1594 | ||
|
|
14d129d08f | ||
|
|
8f4e4f0ddc | ||
|
|
ee9cc6589f | ||
|
|
02ab42e8be | ||
|
|
29e185c9a6 | ||
|
|
b3580bd02d | ||
|
|
7ef4d6d655 | ||
|
|
91c795d4d2 | ||
|
|
f72c47ffe5 | ||
|
|
81766d7f69 | ||
|
|
9667f0f50c | ||
|
|
e77271e4cf | ||
|
|
a7a2a43908 | ||
|
|
fb2d296679 | ||
|
|
2901bb7a88 | ||
|
|
c28c813666 | ||
|
|
2054f9085e | ||
|
|
5db9ed17d7 | ||
|
|
1079cd7524 | ||
|
|
93d664335d | ||
|
|
8f5c84d20a | ||
|
|
9a69342718 | ||
|
|
a3857ba7dd | ||
|
|
681f50a485 | ||
|
|
e2e21f2308 | ||
|
|
c24fd98806 | ||
|
|
16dc03cb18 | ||
|
|
c67e87f382 | ||
|
|
856dcea0fa | ||
|
|
aad8faa22c | ||
|
|
22cbaf7473 | ||
|
|
13f612a8f0 | ||
|
|
70c3183faf | ||
|
|
6f15521221 | ||
|
|
cf3f297107 | ||
|
|
576538f417 | ||
|
|
3fa9e557d4 | ||
|
|
f8b23617d0 | ||
|
|
c17d145714 | ||
|
|
f6e4d40a70 | ||
|
|
f42817953a | ||
|
|
c7de9daf30 | ||
|
|
e29ed40826 | ||
|
|
7c7d452554 | ||
|
|
262522e74d | ||
|
|
3d01f48db0 | ||
|
|
e52fc9d3ee | ||
|
|
9468e851ec | ||
|
|
e5e716e0c5 | ||
|
|
6fab3c4141 | ||
|
|
93ae8208b3 | ||
|
|
c5f5a3ca97 | ||
|
|
b339a8f581 | ||
|
|
318098f2f3 | ||
|
|
7db6f028a3 | ||
|
|
3c634eed83 | ||
|
|
289bf97e08 | ||
|
|
df6d5cf4a9 | ||
|
|
e32eb136b4 | ||
|
|
005d0ec682 | ||
|
|
ef23040a8d | ||
|
|
c3c90b162c | ||
|
|
371afba0a8 | ||
|
|
17ac30aea6 | ||
|
|
e4755effed | ||
|
|
944a44ca30 | ||
|
|
ad4dd677c9 | ||
|
|
bc16fe6403 | ||
|
|
baf06e3510 | ||
|
|
e27446e680 | ||
|
|
0180a5bd2e | ||
|
|
ef243ed57b | ||
|
|
845304a483 | ||
|
|
91fb1ee2df | ||
|
|
7a4055caef | ||
|
|
8118449d7a | ||
|
|
7aa7a8cbe1 | ||
|
|
902e2c1b86 | ||
|
|
4ae8eee9c3 | ||
|
|
c38b33aaf0 | ||
|
|
19e8abf9ab | ||
|
|
93ba78434f | ||
|
|
45e59c4146 | ||
|
|
bd55cf66b0 | ||
|
|
1236733f7c | ||
|
|
5532886d3e | ||
|
|
c8defb341f | ||
|
|
b90e218b85 | ||
|
|
20748d7de0 | ||
|
|
9ed4a31b7a | ||
|
|
17906622bc |
89 changed files with 359958 additions and 68 deletions
28
.github/workflows/githubci.yml
vendored
28
.github/workflows/githubci.yml
vendored
|
|
@ -5,13 +5,25 @@ on: [pull_request, push, repository_dispatch]
|
|||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arduino-platform:
|
||||
- 'main_platforms'
|
||||
# for rp2040 brain
|
||||
- 'pico_rp2040_tinyusb'
|
||||
|
||||
steps:
|
||||
- uses: actions/setup-python@v1
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Run pre-commit
|
||||
uses: pre-commit/action@v3.0.0
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
repository: adafruit/ci-arduino
|
||||
path: ci
|
||||
|
|
@ -19,11 +31,11 @@ jobs:
|
|||
- name: pre-install
|
||||
run: bash ci/actions_install.sh
|
||||
|
||||
- name: test platforms
|
||||
run: python3 ci/build_platform.py main_platforms
|
||||
|
||||
- name: clang
|
||||
run: python3 ci/run-clang-format.py -e "ci/*" -e "bin/*" -r .
|
||||
run: python3 ci/run-clang-format.py -e "ci/*" -e "bin/*" -r .
|
||||
|
||||
- name: test platforms
|
||||
run: python3 ci/build_platform.py ${{ matrix.arduino-platform }}
|
||||
|
||||
- name: doxygen
|
||||
env:
|
||||
|
|
|
|||
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
.idea
|
||||
.pio
|
||||
25
.pre-commit-config.yaml
Normal file
25
.pre-commit-config.yaml
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# SPDX-FileCopyrightText: 2020 Diego Elio Pettenò
|
||||
#
|
||||
# SPDX-License-Identifier: Unlicense
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.4.0
|
||||
hooks:
|
||||
- id: check-yaml
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: v15.0.7
|
||||
hooks:
|
||||
- id: clang-format
|
||||
exclude: ^(examples/.*.ino)
|
||||
types_or: [c++, c, header]
|
||||
|
||||
- repo: https://github.com/codespell-project/codespell
|
||||
rev: v2.2.4
|
||||
hooks:
|
||||
- id: codespell
|
||||
exclude: ^(tools/esp_stub.py)
|
||||
args: [-w]
|
||||
|
|
@ -6,7 +6,7 @@ Used internally for making testers, to reduce code replication!
|
|||
|
||||
Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit!
|
||||
|
||||
Written by Limor Fried for Adafruit Industries.
|
||||
Written by Limor Fried for Adafruit Industries.
|
||||
BSD license, check license.txt for more information
|
||||
All text above must be included in any redistribution
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ Examples of unacceptable behavior by participants include:
|
|||
|
||||
The goal of the standards and moderation guidelines outlined here is to build
|
||||
and maintain a respectful community. We ask that you don’t just aim to be
|
||||
"technically unimpeachable", but rather try to be your best self.
|
||||
"technically unimpeachable", but rather try to be your best self.
|
||||
|
||||
We value many things beyond technical expertise, including collaboration and
|
||||
supporting others within our community. Providing a positive experience for
|
||||
|
|
|
|||
0
examples/Brain/brain_test/.pico_rp2040_tinyusb.test.only
Normal file
0
examples/Brain/brain_test/.pico_rp2040_tinyusb.test.only
Normal file
0
examples/Brain/brain_test/.pico_rp2350_tinyusb.test.only
Normal file
0
examples/Brain/brain_test/.pico_rp2350_tinyusb.test.only
Normal file
51
examples/Brain/brain_test/brain_test.ino
Normal file
51
examples/Brain/brain_test/brain_test.ino
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// Testing basic peripherals on Brain
|
||||
|
||||
// required for Host MSC block device
|
||||
#include "SdFat_Adafruit_Fork.h"
|
||||
|
||||
// required for USB host
|
||||
#include "pio_usb.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
#include "Adafruit_TestBed_Brains.h"
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
while (!Serial) delay(10);
|
||||
Serial.println("Hello world, Tester Brains self test!");
|
||||
|
||||
Brain.begin();
|
||||
Brain.LCD_printf(0, "RP2040 Tester Brain");
|
||||
Brain.LCD_printf(1, __DATE__ __TIME__);
|
||||
}
|
||||
|
||||
uint8_t i=0;
|
||||
void loop() {
|
||||
if (i == 0) {
|
||||
// approx once every 2 seconds
|
||||
Brain.LCD_printf(0, "Testing: %d", millis()/1000);
|
||||
Brain.printI2CBusScan();
|
||||
|
||||
if (Brain.SD_detected()) {
|
||||
Serial.print("SD inserted...");
|
||||
if (! Brain.SD.begin(17, SD_SCK_MHZ(16))) {
|
||||
Serial.println("Could not init SD!");
|
||||
return;
|
||||
}
|
||||
uint32_t SDsize = Brain.SD.card()->sectorCount();
|
||||
if (SDsize == 0) {
|
||||
Serial.println("Can't determine the card size");
|
||||
return;
|
||||
}
|
||||
Serial.printf("Card size = %0.1f GB\n", 0.000000512 * (float)SDsize);
|
||||
Serial.println("Files found (date time size name):");
|
||||
Brain.SD.ls(LS_R | LS_DATE | LS_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
Brain.setColor(Brain.Wheel(i));
|
||||
//Brain.beepNblink();
|
||||
|
||||
i++;
|
||||
delay(10);
|
||||
}
|
||||
151
examples/Brain/program_esp_cdc/esp_binaries.h
Normal file
151
examples/Brain/program_esp_cdc/esp_binaries.h
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2023 Ha Thach (tinyusb.org) for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef ESP_BINARIES_H_
|
||||
#define ESP_BINARIES_H_
|
||||
|
||||
// Configuration: select which bins to flash
|
||||
#define BIN_FILES BIN_C6_BLINK_IO8
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// LIST OF BINARIES
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
#define BIN_ESP32_NINA_1_7_4 0 // nina 1.7.4
|
||||
#define BIN_ESP32_WIFI_AP_SKETCH 1 // esp32 AP with ssdi "YourAP"
|
||||
#define BIN_FEATHER_ESP32_V2_BLINKY 2 // Feather esp32 v2 blinky sketch
|
||||
|
||||
#define BIN_FEATHER_S2 10 // Feather esp32s2 factory firmware
|
||||
#define BIN_FEATHER_S3 11 // Feather esp32s3 factory firmware
|
||||
#define BIN_METRO_S2 12 // Metro esp32s2 factory firmware
|
||||
|
||||
#define BIN_DEVKIT_S2 20 // Espressif s2 devkit
|
||||
#define BIN_DEVKIT_S3 21 // Espressif s3 devkit
|
||||
|
||||
#define BIN_FEATHER_8266_BLINKY 30 // Feather esp8266 blinky sketch
|
||||
|
||||
#define BIN_C6_BLINK_IO8 40 // Blink sketch for C6 with LED on IO8
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Binaries include
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
#if BIN_FILES == BIN_ESP32_WIFI_AP_SKETCH
|
||||
#include "esp_binaries/wifi_ap_binaries.h"
|
||||
|
||||
#elif BIN_FILES == BIN_FEATHER_ESP32_V2_BLINKY
|
||||
#include "esp_binaries/feather_esp32_v2_blinky_binaries.h"
|
||||
|
||||
#elif BIN_FILES == BIN_NINA_1_7_4
|
||||
#include "esp_binaries/nina_1_7_4_binaries.h"
|
||||
|
||||
#elif BIN_FILES == BIN_FEATHER_S2
|
||||
#include "esp_binaries/feather_esp32s2_binaries.h"
|
||||
|
||||
#elif BIN_FILES == BIN_METRO_S2
|
||||
#include "esp_binaries/metro_esp32s2_binaries.h"
|
||||
|
||||
#elif BIN_FILES == BIN_FEATHER_S3
|
||||
#include "esp_binaries/feather_esp32s3_binaries.h"
|
||||
|
||||
#elif BIN_FILES == BIN_DEVKIT_S2
|
||||
#include "esp_binaries/esp32s2_devkit_binaries.h"
|
||||
|
||||
#elif BIN_FILES == BIN_DEVKIT_S3
|
||||
#include "esp_binaries/esp32s3_devkit_binaries.h"
|
||||
|
||||
#elif BIN_FILES == BIN_FEATHER_8266_BLINKY
|
||||
#include "esp_binaries/feather_esp8266_blinky.h"
|
||||
|
||||
#elif BIN_FILES == BIN_C6_BLINK_IO8
|
||||
#include "esp_binaries/c6_blink_io8.h"
|
||||
|
||||
#else
|
||||
#error "Please select BIN_FILES in esp_binaries.h"
|
||||
|
||||
#endif
|
||||
|
||||
struct {
|
||||
uint32_t addr;
|
||||
esp32_zipfile_t const *zfile;
|
||||
} bin_files[] = {
|
||||
#if BIN_FILES == BIN_NINA_1_7_4
|
||||
{0x00000, &NINA_W102_1_7_4},
|
||||
|
||||
#elif BIN_FILES == BIN_FEATHER_ESP32_V2_BLINKY
|
||||
{0x1000, &feather_esp32v2_blinky_bootloader},
|
||||
{0x8000, &feather_esp32v2_blinky_partitions},
|
||||
{0xe000, &boot_app0},
|
||||
{0x10000, &feather_esp32v2_blinky},
|
||||
|
||||
#elif BIN_FILES == BIN_FEATHER_S2
|
||||
{0x1000, &esp32s2_feather_test_ino_bootloader},
|
||||
{0x8000, &esp32s2_feather_test_ino_partitions},
|
||||
{0xe000, &boot_app0},
|
||||
{0x10000, &esp32s2_feather_test_ino},
|
||||
{0x2d0000, &tinyuf2},
|
||||
|
||||
#elif BIN_FILES == BIN_METRO_S2
|
||||
{0x1000, &selftest_ino_bootloader},
|
||||
{0x8000, &selftest_ino_partitions},
|
||||
{0xe000, &boot_app0},
|
||||
{0x10000, &selftest_ino},
|
||||
{0x2d0000, &tinyuf2},
|
||||
|
||||
#elif BIN_FILES == BIN_FEATHER_S3
|
||||
{0x0000, &esp32s3_feather_test_ino_bootloader},
|
||||
{0x8000, &esp32s3_feather_test_ino_partitions},
|
||||
{0xe000, &boot_app0},
|
||||
{0x10000, &esp32s3_feather_test_ino},
|
||||
{0x2d0000, &tinyuf2},
|
||||
|
||||
#elif BIN_FILES == BIN_DEVKIT_S2
|
||||
{0x1000, &Blink_ino_bootloader},
|
||||
{0x8000, &Blink_ino_partitions},
|
||||
{0xe000, &boot_app0},
|
||||
{0x10000, &Blink_ino},
|
||||
|
||||
#elif BIN_FILES == BIN_DEVKIT_S3
|
||||
{0x0000, &Blink_ino_bootloader},
|
||||
{0x8000, &Blink_ino_partitions},
|
||||
{0xe000, &boot_app0},
|
||||
{0x10000, &Blink_ino},
|
||||
|
||||
#elif BIN_FILES == BIN_FEATHER_8266_BLINKY
|
||||
{0x0000, &Blink_ino},
|
||||
|
||||
#elif BIN_FILES == BIN_C6_BLINK_IO8
|
||||
{0x00000, &c6_blink_io8_bootloader},
|
||||
{0x8000, &c6_blink_io8_partitions},
|
||||
{0xe000, &boot_app0},
|
||||
{0x10000, &c6_blink_io8},
|
||||
|
||||
#else
|
||||
#error "Please select BIN_FILES in esp_binaries.h"
|
||||
#endif
|
||||
};
|
||||
|
||||
enum { BIN_FILES_COUNT = sizeof(bin_files) / sizeof(bin_files[0]) };
|
||||
|
||||
#endif
|
||||
10840
examples/Brain/program_esp_cdc/esp_binaries/c6_blink_io8.h
Normal file
10840
examples/Brain/program_esp_cdc/esp_binaries/c6_blink_io8.h
Normal file
File diff suppressed because it is too large
Load diff
11085
examples/Brain/program_esp_cdc/esp_binaries/esp32s2_devkit_binaries.h
Normal file
11085
examples/Brain/program_esp_cdc/esp_binaries/esp32s2_devkit_binaries.h
Normal file
File diff suppressed because it is too large
Load diff
12317
examples/Brain/program_esp_cdc/esp_binaries/esp32s3_devkit_binaries.h
Normal file
12317
examples/Brain/program_esp_cdc/esp_binaries/esp32s3_devkit_binaries.h
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
23271
examples/Brain/program_esp_cdc/esp_binaries/feather_esp32s2_binaries.h
Normal file
23271
examples/Brain/program_esp_cdc/esp_binaries/feather_esp32s2_binaries.h
Normal file
File diff suppressed because it is too large
Load diff
23344
examples/Brain/program_esp_cdc/esp_binaries/feather_esp32s3_binaries.h
Normal file
23344
examples/Brain/program_esp_cdc/esp_binaries/feather_esp32s3_binaries.h
Normal file
File diff suppressed because it is too large
Load diff
16347
examples/Brain/program_esp_cdc/esp_binaries/feather_esp8266_blinky.h
Normal file
16347
examples/Brain/program_esp_cdc/esp_binaries/feather_esp8266_blinky.h
Normal file
File diff suppressed because it is too large
Load diff
22156
examples/Brain/program_esp_cdc/esp_binaries/metro_esp32s2_binaries.h
Normal file
22156
examples/Brain/program_esp_cdc/esp_binaries/metro_esp32s2_binaries.h
Normal file
File diff suppressed because it is too large
Load diff
181
examples/Brain/program_esp_cdc/program_esp_cdc.ino
Normal file
181
examples/Brain/program_esp_cdc/program_esp_cdc.ino
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
// This sketch program ESP32 by flashing bin file via Serial Host.
|
||||
// Hardware wiring is a bit different between S2/S3 and ESP32 + USB-to-UART chip
|
||||
// For S2/S3 with native USB
|
||||
// - Brain GPIO28 <-> ESP32 IO0
|
||||
// - Brain Reset <-> ESP32 Enable
|
||||
// - Brain USB Host <-> ESP32 native usb
|
||||
// For ESP32 with USB-to-UART chip
|
||||
// - Brain USB Host <-> ESP32 native usb
|
||||
// - There is no need to connect IO0/Reset since we will use DTR/RTS to reset ESP32
|
||||
|
||||
// required for Host MSC block device
|
||||
#include "SdFat_Adafruit_Fork.h"
|
||||
|
||||
// required for USB host
|
||||
#include "pio_usb.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
#include "Adafruit_TestBed_Brains.h"
|
||||
|
||||
// Change BIN_FILES in esp_binaries.h header to select which binaries to flash
|
||||
// bin_files[] is defined accordingly
|
||||
#include "esp_binaries.h"
|
||||
|
||||
// 1 if programming ESP32-S2/S3 via native USB
|
||||
// 0 if programming ESP32/8266 via USB-to-UART chip such as FTDI/CP210x/CH9102f
|
||||
#define ESP32_NATIVE_USB 1
|
||||
|
||||
#define ESP32_RESET 27
|
||||
#define ESP32_IO0 28
|
||||
|
||||
// Note: baudrate does not matter if programming S2/S3 native USB
|
||||
// But does matter if programming ESP32/8266 via USB-to-UART chip
|
||||
#define ESP32_BAUDRATE (115200*8)
|
||||
|
||||
// CDC Host object
|
||||
Adafruit_USBH_CDC SerialHost;
|
||||
|
||||
#if ESP32_NATIVE_USB
|
||||
// Declare BootROM with IO0 and Reset will use GPIO for bootloader reset
|
||||
// This is typically for programming ESP32-S2/S3 via native USB
|
||||
ESP32BootROMClass ESP32BootROM(SerialHost, ESP32_IO0, ESP32_RESET);
|
||||
#else
|
||||
// Defined an boot rom object that use SerialHost
|
||||
// Declare BootROM without IO0 and Reset will use SerialHost.setDtrRts() for bootloader reset
|
||||
// This is for programming ESP32/8266 via USB-to-UART chip such as FTDI/CP210x/CH9102f
|
||||
ESP32BootROMClass ESP32BootROM(SerialHost);
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup and Loop on Core0
|
||||
//--------------------------------------------------------------------+
|
||||
void print_speed(size_t count, uint32_t ms) {
|
||||
float count_k = count / 1000.0F;
|
||||
float sec = ms / 1000.0F;
|
||||
float speed = count_k / sec;
|
||||
Brain.LCD_printf(0, "%.01fKB %.01fs", count_k, sec);
|
||||
Brain.LCD_printf(1, "Spd: %.01f KB/s", speed);
|
||||
}
|
||||
|
||||
// Reset using DTR/RTS
|
||||
void reset_with_dtr_rts(uint32_t ms) {
|
||||
SerialHost.setDtrRts(false, true);
|
||||
delay(ms);
|
||||
SerialHost.setDtrRts(false, false);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
while (!Serial) delay(10);
|
||||
Serial.println("Tester Brains: Programming ESP32 with SerialHost!");
|
||||
|
||||
// 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)) {
|
||||
delay(100);
|
||||
}
|
||||
|
||||
// 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);
|
||||
Serial.printf("File %s\r\n", bin_files[i].zfile->name);
|
||||
size_t wr_count = Brain.esp32_programFlashDefl(bin_files[i].zfile, 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(); // reset using Reset pin GPIO27
|
||||
|
||||
// Reset using DTR if GPIO27 is not connected
|
||||
reset_with_dtr_rts(20);
|
||||
}
|
||||
|
||||
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.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() {
|
||||
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();
|
||||
|
||||
// periodically flush SerialHost if connected
|
||||
if (SerialHost && SerialHost.connected()) {
|
||||
SerialHost.flush();
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
// Invoked when a device with CDC interface is mounted
|
||||
// idx is index of cdc interface in the internal pool.
|
||||
void tuh_cdc_mount_cb(uint8_t idx) {
|
||||
// bind SerialHost object to this interface index
|
||||
SerialHost.mount(idx);
|
||||
}
|
||||
|
||||
// Invoked when a device with CDC interface is unmounted
|
||||
void tuh_cdc_umount_cb(uint8_t idx) {
|
||||
// unbind SerialHost if this interface is unmounted
|
||||
SerialHost.umount(idx);
|
||||
}
|
||||
}
|
||||
142
examples/Brain/program_esp_uart/esp_binaries.h
Normal file
142
examples/Brain/program_esp_uart/esp_binaries.h
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2023 Ha Thach (tinyusb.org) for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef ESP_BINARIES_H_
|
||||
#define ESP_BINARIES_H_
|
||||
|
||||
// Configuration: select which bins to flash
|
||||
#define BIN_FILES BIN_C6_BLINK_IO8
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// LIST OF BINARIES
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
#define BIN_ESP32_NINA_1_7_4 0 // nina 1.7.4
|
||||
#define BIN_ESP32_WIFI_AP_SKETCH 1 // esp32 AP with ssdi "YourAP"
|
||||
|
||||
#define BIN_FEATHER_S2 10 // Feather esp32s2 factory firmware
|
||||
#define BIN_FEATHER_S3 11 // Feather esp32s3 factory firmware
|
||||
#define BIN_METRO_S2 12 // Metro esp32s2 factory firmware
|
||||
|
||||
#define BIN_DEVKIT_S2 20 // Espressif s2 devkit
|
||||
#define BIN_DEVKIT_S3 21 // Espressif s3 devkit
|
||||
|
||||
#define BIN_ESP8266 30 // Espressif esp8266
|
||||
|
||||
#define BIN_C6_BLINK_IO8 40 // Blink sketch for C6 with LED on IO8
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Binaries include
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
#if BIN_FILES == BIN_ESP32_WIFI_AP_SKETCH
|
||||
#include "esp_binaries/wifi_ap_binaries.h"
|
||||
|
||||
#elif BIN_FILES == BIN_NINA_1_7_4
|
||||
#include "esp_binaries/nina_1_7_4_binaries.h"
|
||||
|
||||
#elif BIN_FILES == BIN_FEATHER_S2
|
||||
#include "esp_binaries/feather_esp32s2_binaries.h"
|
||||
|
||||
#elif BIN_FILES == BIN_METRO_S2
|
||||
#include "esp_binaries/metro_esp32s2_binaries.h"
|
||||
|
||||
#elif BIN_FILES == BIN_FEATHER_S3
|
||||
#include "esp_binaries/feather_esp32s3_binaries.h"
|
||||
|
||||
#elif BIN_FILES == BIN_DEVKIT_S2
|
||||
#include "esp_binaries/esp32s2_devkit_binaries.h"
|
||||
|
||||
#elif BIN_FILES == BIN_DEVKIT_S3
|
||||
#include "esp_binaries/esp32s3_devkit_binaries.h"
|
||||
|
||||
#elif BIN_FILES == BIN_ESP8266
|
||||
#include "esp_binaries/esp8266_binaries.h"
|
||||
|
||||
#elif BIN_FILES == BIN_C6_BLINK_IO8
|
||||
#include "esp_binaries/c6_blink_io8.h"
|
||||
|
||||
#else
|
||||
#error "Please select BIN_FILES in esp_binaries.h"
|
||||
|
||||
#endif
|
||||
|
||||
struct {
|
||||
uint32_t addr;
|
||||
esp32_zipfile_t const *zfile;
|
||||
} bin_files[] = {
|
||||
#if BIN_FILES == BIN_NINA_1_7_4
|
||||
{0x00000, &NINA_W102_1_7_4},
|
||||
|
||||
#elif BIN_FILES == BIN_FEATHER_S2
|
||||
{0x1000, &esp32s2_feather_test_ino_bootloader},
|
||||
{0x8000, &esp32s2_feather_test_ino_partitions},
|
||||
{0xe000, &boot_app0},
|
||||
{0x10000, &esp32s2_feather_test_ino},
|
||||
{0x2d0000, &tinyuf2},
|
||||
|
||||
#elif BIN_FILES == BIN_METRO_S2
|
||||
{0x1000, &selftest_ino_bootloader},
|
||||
{0x8000, &selftest_ino_partitions},
|
||||
{0xe000, &boot_app0},
|
||||
{0x10000, &selftest_ino},
|
||||
{0x2d0000, &tinyuf2},
|
||||
|
||||
#elif BIN_FILES == BIN_FEATHER_S3
|
||||
{0x0000, &esp32s3_feather_test_ino_bootloader},
|
||||
{0x8000, &esp32s3_feather_test_ino_partitions},
|
||||
{0xe000, &boot_app0},
|
||||
{0x10000, &esp32s3_feather_test_ino},
|
||||
{0x2d0000, &tinyuf2},
|
||||
|
||||
#elif BIN_FILES == BIN_DEVKIT_S2
|
||||
{0x1000, &Blink_ino_bootloader},
|
||||
{0x8000, &Blink_ino_partitions},
|
||||
{0xe000, &boot_app0},
|
||||
{0x10000, &Blink_ino},
|
||||
|
||||
#elif BIN_FILES == BIN_DEVKIT_S3
|
||||
{0x0000, &Blink_ino_bootloader},
|
||||
{0x8000, &Blink_ino_partitions},
|
||||
{0xe000, &boot_app0},
|
||||
{0x10000, &Blink_ino},
|
||||
|
||||
#elif BIN_FILES == BIN_ESP8266
|
||||
{0x00000, &esp8266_blink_io0},
|
||||
|
||||
#elif BIN_FILES == BIN_C6_BLINK_IO8
|
||||
{0x00000, &c6_blink_io8_bootloader},
|
||||
{0x8000, &c6_blink_io8_partitions},
|
||||
{0xe000, &boot_app0},
|
||||
{0x10000, &c6_blink_io8},
|
||||
|
||||
#else
|
||||
#error "Please select BIN_FILES in esp_binaries.h"
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
enum { BIN_FILES_COUNT = sizeof(bin_files) / sizeof(bin_files[0]) };
|
||||
|
||||
#endif
|
||||
10840
examples/Brain/program_esp_uart/esp_binaries/c6_blink_io8.h
Normal file
10840
examples/Brain/program_esp_uart/esp_binaries/c6_blink_io8.h
Normal file
File diff suppressed because it is too large
Load diff
11085
examples/Brain/program_esp_uart/esp_binaries/esp32s2_devkit_binaries.h
Normal file
11085
examples/Brain/program_esp_uart/esp_binaries/esp32s2_devkit_binaries.h
Normal file
File diff suppressed because it is too large
Load diff
12317
examples/Brain/program_esp_uart/esp_binaries/esp32s3_devkit_binaries.h
Normal file
12317
examples/Brain/program_esp_uart/esp_binaries/esp32s3_devkit_binaries.h
Normal file
File diff suppressed because it is too large
Load diff
16344
examples/Brain/program_esp_uart/esp_binaries/esp8266_binaries.h
Normal file
16344
examples/Brain/program_esp_uart/esp_binaries/esp8266_binaries.h
Normal file
File diff suppressed because it is too large
Load diff
23271
examples/Brain/program_esp_uart/esp_binaries/feather_esp32s2_binaries.h
Normal file
23271
examples/Brain/program_esp_uart/esp_binaries/feather_esp32s2_binaries.h
Normal file
File diff suppressed because it is too large
Load diff
23344
examples/Brain/program_esp_uart/esp_binaries/feather_esp32s3_binaries.h
Normal file
23344
examples/Brain/program_esp_uart/esp_binaries/feather_esp32s3_binaries.h
Normal file
File diff suppressed because it is too large
Load diff
22156
examples/Brain/program_esp_uart/esp_binaries/metro_esp32s2_binaries.h
Normal file
22156
examples/Brain/program_esp_uart/esp_binaries/metro_esp32s2_binaries.h
Normal file
File diff suppressed because it is too large
Load diff
52833
examples/Brain/program_esp_uart/esp_binaries/nina_1_7_4_binaries.h
Normal file
52833
examples/Brain/program_esp_uart/esp_binaries/nina_1_7_4_binaries.h
Normal file
File diff suppressed because it is too large
Load diff
40424
examples/Brain/program_esp_uart/esp_binaries/wifi_ap_binaries.h
Normal file
40424
examples/Brain/program_esp_uart/esp_binaries/wifi_ap_binaries.h
Normal file
File diff suppressed because it is too large
Load diff
134
examples/Brain/program_esp_uart/program_esp_uart.ino
Normal file
134
examples/Brain/program_esp_uart/program_esp_uart.ino
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
// This sketch program ESP32 by flashing bin file from on-flash (with .h header)
|
||||
// Supported/tested ESP MCU are: ESP32, ESP32-S2, ESP32-S3, ESP8266
|
||||
// Hardware wiring:
|
||||
// - Brain GPIO28 <-> ESP32 IO0
|
||||
// - Brain Reset <-> ESP32 Enable
|
||||
// - Brain TX/RX <-> ESP32 RX/TX
|
||||
|
||||
// required for Host MSC block device
|
||||
#include "SdFat_Adafruit_Fork.h"
|
||||
|
||||
// required for USB host
|
||||
#include "pio_usb.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
#include "Adafruit_TestBed_Brains.h"
|
||||
|
||||
// Change BIN_FILES in esp_binaries.h header to select which binaries to flash
|
||||
// bin_files[] is defined accordingly
|
||||
#include "esp_binaries.h"
|
||||
|
||||
#define ESP32_RESET 27
|
||||
#define ESP32_IO0 28
|
||||
|
||||
#define ESP32_BAUDRATE 2000000
|
||||
//#define ESP32_BAUDRATE 1500000
|
||||
//#define ESP32_BAUDRATE 921600
|
||||
//#define ESP32_BAUDRATE 115200
|
||||
|
||||
|
||||
// Defined an boot rom object that use UART Serial1
|
||||
ESP32BootROMClass ESP32BootROM(Serial1, ESP32_IO0, ESP32_RESET);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup and Loop on Core0
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void print_speed(size_t count, uint32_t ms) {
|
||||
float count_k = count / 1000.0F;
|
||||
float sec = ms / 1000.0F;
|
||||
float speed = count_k / sec;
|
||||
Brain.LCD_printf(0, "%.01fKB %.01fs", count_k, sec);
|
||||
Brain.LCD_printf(1, "Spd: %.01f KB/s", speed);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
while (!Serial) delay(10);
|
||||
Serial.println("Tester Brains: Programming ESP with UART!");
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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(0, "Flashing file %u", i);
|
||||
Serial.printf("File: %s\r\n", bin_files[i].zfile->name);
|
||||
size_t wr_count = Brain.esp32_programFlashDefl(bin_files[i].zfile, 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(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");
|
||||
}
|
||||
|
||||
}
|
||||
BIN
examples/Brain/program_nrf52840/bleblink.bin
Normal file
BIN
examples/Brain/program_nrf52840/bleblink.bin
Normal file
Binary file not shown.
121
examples/Brain/program_nrf52840/program_nrf52840.ino
Normal file
121
examples/Brain/program_nrf52840/program_nrf52840.ino
Normal file
|
|
@ -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_Adafruit_Fork.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");
|
||||
}
|
||||
|
||||
}
|
||||
BIN
examples/Brain/program_nrf52840_from_sdcard/bleblink.bin
Normal file
BIN
examples/Brain/program_nrf52840_from_sdcard/bleblink.bin
Normal file
Binary file not shown.
|
|
@ -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_Adafruit_Fork.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");
|
||||
}
|
||||
|
||||
}
|
||||
BIN
examples/Brain/program_rp2/metro_rp2350_cdc_msc.uf2
Normal file
BIN
examples/Brain/program_rp2/metro_rp2350_cdc_msc.uf2
Normal file
Binary file not shown.
7043
examples/Brain/program_rp2/metro_rp2350_cdc_msc.uf2.h
Normal file
7043
examples/Brain/program_rp2/metro_rp2350_cdc_msc.uf2.h
Normal file
File diff suppressed because it is too large
Load diff
135
examples/Brain/program_rp2/program_rp2.ino
Normal file
135
examples/Brain/program_rp2/program_rp2.ino
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
// This sketch program rp2040 by copying UF2 file from SDCard to
|
||||
// rp2040 bootrom
|
||||
// Hardware wiring:
|
||||
// - Brain's Target GPIO28 to RP2 bootsel
|
||||
// - Brain's Target Reset to RP2 Reset
|
||||
// - Brain's USB host to RP2040 USB interface
|
||||
|
||||
// required for Host MSC block device
|
||||
#include "SdFat_Adafruit_Fork.h"
|
||||
|
||||
// required for USB host
|
||||
#include "pio_usb.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
#include "Adafruit_TestBed_Brains.h"
|
||||
|
||||
// firmware.h is converted using tools/file2carray.py e.g
|
||||
// python tools/file2carray.py cdc_msc.uf2
|
||||
// above command will generate cdc_msc.uf2.h with bindata, bindata_len
|
||||
#include "metro_rp2350_cdc_msc.uf2.h"
|
||||
|
||||
// RP2040 Boot VID/PID
|
||||
#define BOOT_VID 0x2e8a
|
||||
#define BOOT_PID_RP2040 0x0003
|
||||
#define BOOT_PID_RP2350 0x000f
|
||||
|
||||
// If USB filesystem is mounted
|
||||
volatile bool is_usbfs_mounted = false;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup and Loop on Core0
|
||||
//--------------------------------------------------------------------+
|
||||
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("Program RP2 by copy UF2 from Internal Flash to Bootloader!");
|
||||
|
||||
// sync: wait for Brain.begin() called in core1 before accessing SD or other peripherals
|
||||
while (!Brain.inited()) delay(10);
|
||||
|
||||
// wait for USB filesystem is mounted. USB host bit-banging and task is
|
||||
// processed on core1
|
||||
while (!is_usbfs_mounted) delay(10);
|
||||
|
||||
// Copy UF2 file
|
||||
Brain.LCD_printf(0, "Copying firmware");
|
||||
Serial.println("Copying UF2 from Flash to USBHFS");
|
||||
|
||||
uint32_t ms = millis();
|
||||
size_t copied_bytes = Brain.rp2_programUF2(bindata, bindata_len);
|
||||
print_speed(copied_bytes, millis() - ms);
|
||||
|
||||
// wait for rp2040 boot rom to reset
|
||||
// while (is_usbfs_mounted) delay(10);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
Serial.flush();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// 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");
|
||||
|
||||
// reset rp2040 target into Boot Rom, default bootsel = 28, reset duration = 10 ms
|
||||
Brain.rp2_targetResetBootRom();
|
||||
}
|
||||
|
||||
// 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
|
||||
//--------------------------------------------------------------------+
|
||||
bool is_rp2_bootloader(uint16_t vid, uint16_t pid) {
|
||||
return (vid == BOOT_VID && (pid == BOOT_PID_RP2040 || pid == BOOT_PID_RP2350));
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (!is_rp2_bootloader(vid, pid)) {
|
||||
Brain.LCD_printf(1, "UnkDev %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");
|
||||
}
|
||||
|
||||
// Invoked when a device with MassStorage interface is mounted
|
||||
void tuh_msc_mount_cb(uint8_t dev_addr) {
|
||||
uint16_t vid, pid;
|
||||
tuh_vid_pid_get(dev_addr, &vid, &pid);
|
||||
|
||||
if (is_rp2_bootloader(vid, pid)) {
|
||||
is_usbfs_mounted = Brain.usbh_mountFS(dev_addr);
|
||||
if (is_usbfs_mounted) {
|
||||
uint16_t rp2variant = (pid == BOOT_PID_RP2040 ? 2040 : 2350);
|
||||
Brain.LCD_printf(1, "RP%u Bootldr", rp2variant);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Invoked when a device with MassStorage interface is unmounted
|
||||
void tuh_msc_umount_cb(uint8_t dev_addr) {
|
||||
is_usbfs_mounted = false;
|
||||
Brain.usbh_umountFS(dev_addr);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
// This sketch program rp2040 by copying UF2 file from SDCard to
|
||||
// rp2040 bootrom
|
||||
// Hardware wiring:
|
||||
// - Brain's Target GPIO28 to RP2040 bootsel
|
||||
// - Brain's Target Reset to RP2040 Reset
|
||||
// - Brain's USB host to RP2040 USB interface
|
||||
|
||||
// required for Host MSC block device
|
||||
#include "SdFat_Adafruit_Fork.h"
|
||||
|
||||
// required for USB host
|
||||
#include "pio_usb.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
#include "Adafruit_TestBed_Brains.h"
|
||||
|
||||
// RP2040 Boot VID/PID
|
||||
#define BOOT_VID 0x2e8a
|
||||
#define BOOT_PID 0x0003
|
||||
|
||||
// UF2 file path on SDCard to copy
|
||||
// #define UF2_FILE_PATH "pico/adafruit-circuitpython-raspberry_pi_pico-en_US-7.3.3.uf2"
|
||||
//#define UF2_FILE_PATH "pico/blink.uf2"
|
||||
#define UF2_FILE_PATH "pico/tinyusb_dev_cdc_msc.uf2"
|
||||
|
||||
// If USB filesystem is mounted
|
||||
volatile bool is_usbfs_mounted = false;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// 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: UF2 copy from SD to USBH FS test!");
|
||||
|
||||
// sync: wait for Brain.begin() called in core1 before accessing SD or other peripherals
|
||||
while (!Brain.inited()) delay(10);
|
||||
|
||||
// prepare SD Card
|
||||
prepare_sd();
|
||||
|
||||
// wait for USB filesystem is mounted. USB host bit-banging and task is
|
||||
// processed on core1
|
||||
while (!is_usbfs_mounted) delay(10);
|
||||
|
||||
// Copy UF2 file
|
||||
Brain.LCD_printf(0, "Copying UF2 file");
|
||||
Serial.println("Copying from SD to USBHFS: " UF2_FILE_PATH);
|
||||
|
||||
uint32_t ms = millis();
|
||||
size_t copied_bytes = Brain.rp2_programUF2(UF2_FILE_PATH);
|
||||
|
||||
print_speed(copied_bytes, millis() - ms);
|
||||
|
||||
// wait for rp2040 boot rom to reset
|
||||
// while (is_usbfs_mounted) delay(10);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
Serial.flush();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// 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");
|
||||
|
||||
// reset rp2040 target into Boot Rom, default bootsel = 28, reset duration = 10 ms
|
||||
Brain.rp2_targetResetBootRom();
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
if ( !(vid == BOOT_VID && pid == BOOT_PID) ) {
|
||||
Brain.LCD_printf(1, "UnkDev %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");
|
||||
}
|
||||
|
||||
// Invoked when a device with MassStorage interface is mounted
|
||||
void tuh_msc_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 ) {
|
||||
is_usbfs_mounted = Brain.usbh_mountFS(dev_addr);
|
||||
if (is_usbfs_mounted) {
|
||||
Brain.LCD_printf(1, "RP2 Boot mounted");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Invoked when a device with MassStorage interface is unmounted
|
||||
void tuh_msc_umount_cb(uint8_t dev_addr)
|
||||
{
|
||||
is_usbfs_mounted = false;
|
||||
Brain.usbh_umountFS(dev_addr);
|
||||
}
|
||||
|
||||
}
|
||||
BIN
examples/Brain/program_rp2_from_sdcard/tinyusb_dev_cdc_msc.uf2
Normal file
BIN
examples/Brain/program_rp2_from_sdcard/tinyusb_dev_cdc_msc.uf2
Normal file
Binary file not shown.
BIN
examples/Brain/program_samd21/3505test.BIN
Normal file
BIN
examples/Brain/program_samd21/3505test.BIN
Normal file
Binary file not shown.
126
examples/Brain/program_samd21/program_samd21.ino
Normal file
126
examples/Brain/program_samd21/program_samd21.ino
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
// 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_Adafruit_Fork.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"
|
||||
|
||||
// RP2040 Boot VID/PID
|
||||
#define BOOT_VID 0x2e8a
|
||||
#define BOOT_PID 0x0003
|
||||
|
||||
// file path on SDCard to prograom
|
||||
#define TEST_FILE_PATH "samd21/metro/3505test.bin"
|
||||
//#define TESTFILECRC 0x9709b384
|
||||
|
||||
// DAP interface for SAM21
|
||||
Adafruit_DAP_SAM 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: SAMD21 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();
|
||||
|
||||
uint32_t ms = millis();
|
||||
size_t copied_bytes = Brain.dap_programFlash(TEST_FILE_PATH, 0);
|
||||
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);
|
||||
|
||||
if ( !(vid == BOOT_VID && pid == BOOT_PID) ) {
|
||||
Brain.LCD_printf(1, "UnkDev %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");
|
||||
}
|
||||
|
||||
}
|
||||
BIN
examples/Brain/program_samd51/3382test.bin
Normal file
BIN
examples/Brain/program_samd51/3382test.bin
Normal file
Binary file not shown.
126
examples/Brain/program_samd51/program_samd51.ino
Normal file
126
examples/Brain/program_samd51/program_samd51.ino
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
// 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_Adafruit_Fork.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"
|
||||
|
||||
// RP2040 Boot VID/PID
|
||||
#define BOOT_VID 0x2e8a
|
||||
#define BOOT_PID 0x0003
|
||||
|
||||
// file path on SDCard to prograom
|
||||
#define TEST_FILE_PATH "samd51/metro/3382test.bin"
|
||||
//#define TESTFILECRC 0xB38619E4
|
||||
|
||||
// DAP interface for SAMD51
|
||||
Adafruit_DAP_SAMx5 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: SAMD51 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();
|
||||
|
||||
uint32_t ms = millis();
|
||||
size_t copied_bytes = Brain.dap_programFlash(TEST_FILE_PATH, 0);
|
||||
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);
|
||||
|
||||
if ( !(vid == BOOT_VID && pid == BOOT_PID) ) {
|
||||
Brain.LCD_printf(1, "UnkDev %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");
|
||||
}
|
||||
|
||||
}
|
||||
125
examples/Brain/program_stm32f405/program_stm32f405.ino
Normal file
125
examples/Brain/program_stm32f405/program_stm32f405.ino
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
// 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_Adafruit_Fork.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"
|
||||
|
||||
// RP2040 Boot VID/PID
|
||||
#define BOOT_VID 0x2e8a
|
||||
#define BOOT_PID 0x0003
|
||||
|
||||
// file path on SDCard to prograom
|
||||
#define TEST_FILE_PATH "stm32f4/feather_stm32f405/tinyuf2-feather_stm32f405_express.bin"
|
||||
|
||||
// DAP interface for nRF5x
|
||||
Adafruit_DAP_STM32 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: STM32F405 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();
|
||||
|
||||
uint32_t ms = millis();
|
||||
size_t copied_bytes = Brain.dap_programFlash(TEST_FILE_PATH, 0);
|
||||
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);
|
||||
|
||||
if ( !(vid == BOOT_VID && pid == BOOT_PID) ) {
|
||||
Brain.LCD_printf(1, "UnkDev %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");
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
|
|
@ -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_Adafruit_Fork.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");
|
||||
}
|
||||
|
||||
}
|
||||
115
examples/Brain/usbh_hub_test/usbh_hub_test.ino
Normal file
115
examples/Brain/usbh_hub_test/usbh_hub_test.ino
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
// Testing USB host hardware on Brain by printing out VID/PID of attached device
|
||||
// to LCD. Also determine if device support MSC or HID
|
||||
|
||||
// required for Host MSC block device
|
||||
#include "SdFat_Adafruit_Fork.h"
|
||||
|
||||
// required for USB host
|
||||
#include "pio_usb.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
#include "Adafruit_TestBed_Brains.h"
|
||||
|
||||
typedef struct {
|
||||
uint16_t vid;
|
||||
uint16_t pid;
|
||||
bool mounted;
|
||||
} dev_info_t;
|
||||
|
||||
// CFG_TUH_DEVICE_MAX is defined by tusb_config header
|
||||
dev_info_t dev_info[CFG_TUH_DEVICE_MAX] = { 0 };
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup and Loop on Core0
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void setup() {
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Scan and print VID/PID
|
||||
uint8_t dev_count = 0;
|
||||
for(uint8_t daddr=1; daddr < CFG_TUH_DEVICE_MAX+1; daddr++) {
|
||||
dev_info_t const* dev = &dev_info[daddr-1];
|
||||
|
||||
if ( dev->mounted ) {
|
||||
dev_count++;
|
||||
Brain.LCD_printf("[%u] %04X:%04X", daddr, dev->vid, dev->pid);
|
||||
}
|
||||
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
if ( dev_count == 0 ) {
|
||||
Brain.LCD_printf(0, "No USB attached");
|
||||
Brain.LCD_printf(1, "Plug your device");
|
||||
}else {
|
||||
Brain.LCD_printf("Devices num: %u", dev_count);
|
||||
delay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup and Loop on Core1
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// call usbh_begin() hrere to make pio usb background task run on core1
|
||||
// NOTE: Brain.begin() should be called here as well to prevent race condition
|
||||
void setup1() {
|
||||
Serial.begin(115200);
|
||||
// while (!Serial) delay(10);
|
||||
|
||||
Serial.println("Tester Brains USB Host test!");
|
||||
|
||||
// Init Brain peripherals
|
||||
Brain.begin();
|
||||
|
||||
// Init Brain USB Host
|
||||
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()
|
||||
{
|
||||
Brain.USBHost.task();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// TinyUSB Host callbacks
|
||||
//--------------------------------------------------------------------+
|
||||
extern "C" {
|
||||
|
||||
// Invoked when device is mounted (configured)
|
||||
void tuh_mount_cb (uint8_t daddr)
|
||||
{
|
||||
dev_info_t* dev = &dev_info[daddr-1];
|
||||
dev->mounted = true;
|
||||
|
||||
tuh_vid_pid_get(daddr, &dev->vid, &dev->pid);
|
||||
|
||||
Serial.printf("Device attached, address = %d\r\n", daddr);
|
||||
}
|
||||
|
||||
/// Invoked when device is unmounted (bus reset/unplugged)
|
||||
void tuh_umount_cb(uint8_t daddr)
|
||||
{
|
||||
dev_info_t* dev = &dev_info[daddr-1];
|
||||
dev->mounted = false;
|
||||
|
||||
Serial.printf("Device removed, address = %d\r\n", daddr);
|
||||
}
|
||||
|
||||
// Invoked when a device with CDC interface is mounted
|
||||
// idx is index of cdc interface in the internal pool.
|
||||
void tuh_cdc_mount_cb(uint8_t idx) {
|
||||
}
|
||||
|
||||
// Invoked when a device with CDC interface is unmounted
|
||||
void tuh_cdc_umount_cb(uint8_t idx) {
|
||||
}
|
||||
|
||||
}
|
||||
0
examples/Brain/usbh_test/.pico_rp2040_tinyusb.test.only
Normal file
0
examples/Brain/usbh_test/.pico_rp2040_tinyusb.test.only
Normal file
0
examples/Brain/usbh_test/.pico_rp2350_tinyusb.test.only
Normal file
0
examples/Brain/usbh_test/.pico_rp2350_tinyusb.test.only
Normal file
125
examples/Brain/usbh_test/usbh_test.ino
Normal file
125
examples/Brain/usbh_test/usbh_test.ino
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
// Testing USB host hardware on Brain by printing out VID/PID of attached device
|
||||
// to LCD. Also determine if device support MSC or HID
|
||||
|
||||
// required for Host MSC block device
|
||||
#include "SdFat_Adafruit_Fork.h"
|
||||
|
||||
// required for USB host
|
||||
#include "pio_usb.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
#include "Adafruit_TestBed_Brains.h"
|
||||
|
||||
// CDC Host object
|
||||
Adafruit_USBH_CDC SerialHost;
|
||||
|
||||
enum {
|
||||
COLOR_NO_DEV = 0x00000ff,
|
||||
COLOR_MOUNTED = 0x00ff00,
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup and Loop on Core0
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void setup() {
|
||||
}
|
||||
|
||||
void loop() {
|
||||
uint8_t buf[64];
|
||||
|
||||
// Serial -> SerialHost
|
||||
if (Serial.available()) {
|
||||
size_t count = Serial.read(buf, sizeof(buf));
|
||||
if ( SerialHost && SerialHost.connected() ) {
|
||||
SerialHost.write(buf, count);
|
||||
SerialHost.flush();
|
||||
}
|
||||
}
|
||||
|
||||
// SerialHost -> Serial
|
||||
if ( SerialHost.connected() && SerialHost.available() ) {
|
||||
size_t count = SerialHost.read(buf, sizeof(buf));
|
||||
Serial.write(buf, count);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup and Loop on Core1
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// call usbh_begin() hrere to make pio usb background task run on core1
|
||||
// NOTE: Brain.begin() should be called here as well to prevent race condition
|
||||
void setup1() {
|
||||
Serial.begin(115200);
|
||||
while (!Serial) delay(10);
|
||||
|
||||
Serial.println("Tester Brains USB Host test!");
|
||||
|
||||
// Init Brain peripherals
|
||||
Brain.begin();
|
||||
|
||||
// Init Brain USB Host
|
||||
Brain.usbh_begin();
|
||||
|
||||
Brain.setColor(COLOR_NO_DEV);
|
||||
|
||||
// Since we only support 1 CDC interface with Tester (also CFG_TUH_CDC = 1)
|
||||
// the index will always be 0 for SerialHost
|
||||
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
|
||||
//--------------------------------------------------------------------+
|
||||
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.setColor(COLOR_MOUNTED);
|
||||
Brain.LCD_printf(0, "USBID %04x:%04x", vid, pid);
|
||||
Brain.LCD_printf(1, "MS %u HID %u CDC %u", tuh_msc_mounted(daddr), tuh_hid_instance_count(daddr), SerialHost.mounted());
|
||||
}
|
||||
|
||||
/// Invoked when device is unmounted (bus reset/unplugged)
|
||||
void tuh_umount_cb(uint8_t daddr)
|
||||
{
|
||||
Serial.printf("Device removed, address = %d\r\n", daddr);
|
||||
Brain.setColor(COLOR_NO_DEV);
|
||||
Brain.LCD_printf(0, "No USB attached");
|
||||
Brain.LCD_printf(1, "Plug your device");
|
||||
}
|
||||
|
||||
// Invoked when a device with CDC interface is mounted
|
||||
// idx is index of cdc interface in the internal pool.
|
||||
void tuh_cdc_mount_cb(uint8_t idx) {
|
||||
// bind SerialHost object to this interface index
|
||||
SerialHost.mount(idx);
|
||||
}
|
||||
|
||||
// Invoked when a device with CDC interface is unmounted
|
||||
void tuh_cdc_umount_cb(uint8_t idx) {
|
||||
// unbind SerialHost if this interface is unmounted
|
||||
SerialHost.umount(idx);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -4,15 +4,19 @@ extern Adafruit_TestBed TB;
|
|||
#define DEFAULT_I2C_PORT &Wire
|
||||
|
||||
// Some boards have TWO I2C ports, how nifty. We should scan both
|
||||
#if defined(ARDUINO_ADAFRUIT_KB2040_RP2040) \
|
||||
#if defined(ARDUINO_ARCH_RP2040) \
|
||||
|| defined(ARDUINO_ADAFRUIT_QTPY_ESP32S2) \
|
||||
|| defined(ARDUINO_ADAFRUIT_QTPY_ESP32_PICO)
|
||||
|| defined(ARDUINO_ADAFRUIT_QTPY_ESP32S3_NOPSRAM) \
|
||||
|| defined(ARDUINO_ADAFRUIT_QTPY_ESP32S3_N4R2) \
|
||||
|| defined(ARDUINO_ADAFRUIT_QTPY_ESP32_PICO) \
|
||||
|| defined(ARDUINO_SAM_DUE) \
|
||||
|| defined(ARDUINO_ARCH_RENESAS_UNO)
|
||||
#define SECONDARY_I2C_PORT &Wire1
|
||||
#endif
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
|
||||
// Wait for Serial port to open
|
||||
while (!Serial) {
|
||||
delay(10);
|
||||
|
|
@ -21,6 +25,8 @@ void setup() {
|
|||
Serial.println("Adafruit I2C Scanner");
|
||||
|
||||
#if defined(ARDUINO_ADAFRUIT_QTPY_ESP32S2) || \
|
||||
defined(ARDUINO_ADAFRUIT_QTPY_ESP32S3_NOPSRAM) || \
|
||||
defined(ARDUINO_ADAFRUIT_QTPY_ESP32S3_N4R2) || \
|
||||
defined(ARDUINO_ADAFRUIT_QTPY_ESP32_PICO)
|
||||
// ESP32 is kinda odd in that secondary ports must be manually
|
||||
// assigned their pins with setPins()!
|
||||
|
|
@ -28,25 +34,44 @@ void setup() {
|
|||
#endif
|
||||
|
||||
#if defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S2)
|
||||
// turn on the I2C power by setting pin
|
||||
pinMode(7, OUTPUT);
|
||||
digitalWrite(7, LOW);
|
||||
// turn on the I2C power by setting pin to opposite of 'rest state'
|
||||
pinMode(PIN_I2C_POWER, INPUT);
|
||||
delay(1);
|
||||
bool polarity = digitalRead(PIN_I2C_POWER);
|
||||
pinMode(PIN_I2C_POWER, OUTPUT);
|
||||
digitalWrite(PIN_I2C_POWER, !polarity);
|
||||
#endif
|
||||
|
||||
#if defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S2_TFT)
|
||||
pinMode(TFT_I2C_POWER, OUTPUT);
|
||||
digitalWrite(TFT_I2C_POWER, HIGH);
|
||||
#endif
|
||||
|
||||
#if defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S2_REVTFT)
|
||||
pinMode(TFT_I2C_POWER, OUTPUT);
|
||||
digitalWrite(TFT_I2C_POWER, HIGH);
|
||||
#endif
|
||||
|
||||
#if defined(ADAFRUIT_FEATHER_ESP32_V2)
|
||||
// Turn on the I2C power by pulling pin HIGH.
|
||||
pinMode(NEOPIXEL_I2C_POWER, OUTPUT);
|
||||
digitalWrite(NEOPIXEL_I2C_POWER, HIGH);
|
||||
#endif
|
||||
}
|
||||
|
||||
void loop() {
|
||||
Serial.println("");
|
||||
Serial.println("");
|
||||
|
||||
Serial.print("Default port ");
|
||||
|
||||
Serial.print("Default port (Wire) ");
|
||||
TB.theWire = DEFAULT_I2C_PORT;
|
||||
TB.printI2CBusScan();
|
||||
|
||||
#if defined(SECONDARY_I2C_PORT)
|
||||
Serial.print("Secondary port ");
|
||||
Serial.print("Secondary port (Wire1) ");
|
||||
TB.theWire = SECONDARY_I2C_PORT;
|
||||
TB.printI2CBusScan();
|
||||
#endif
|
||||
|
||||
delay(3000); // wait 3 seconds
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,12 +22,14 @@ void loop(void) {
|
|||
|
||||
if (! TB.testPullup(A5) || ! TB.testPullup(A4)) {
|
||||
Serial.println("Waiting for I2C pullups");
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("I2C pullups OK"); // pullups cool - next up!
|
||||
|
||||
if (!TB.scanI2CBus(0x62)) {
|
||||
Serial.println("I2C 0x62 not found");
|
||||
return;
|
||||
}
|
||||
Serial.println("I2C 0x62 found");
|
||||
|
||||
|
|
@ -52,7 +54,7 @@ void loop(void) {
|
|||
Serial.println("I2C 0x63 not found");
|
||||
}
|
||||
Serial.println("I2C 0x63 found");
|
||||
|
||||
|
||||
Serial.println("Test OK!");
|
||||
//TB.beepNblink();
|
||||
delay(500);
|
||||
|
|
|
|||
BIN
examples/program_esp32_uart_from_sdcard/NINA_W102-1.7.5.bin.gz
Normal file
BIN
examples/program_esp32_uart_from_sdcard/NINA_W102-1.7.5.bin.gz
Normal file
Binary file not shown.
30
examples/program_esp32_uart_from_sdcard/esp_binaries.h
Normal file
30
examples/program_esp32_uart_from_sdcard/esp_binaries.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
// Generated by tools/esp_compress.py
|
||||
#define ESP_BINARIES_COUNT (1)
|
||||
|
||||
// const esp32_zipfile_t NINA_W102_1_7_5
|
||||
|
||||
const esp32_zipfile_t NINA_W102_1_7_5 = {
|
||||
.name = "NINA_W102-1.7.5.bin.gz",
|
||||
.data = NULL,
|
||||
.compressed_len = 634996,
|
||||
.uncompressed_len = 1160192,
|
||||
.md5 =
|
||||
{
|
||||
0x07,
|
||||
0x7c,
|
||||
0xec,
|
||||
0x6d,
|
||||
0xaa,
|
||||
0x68,
|
||||
0x13,
|
||||
0xc5,
|
||||
0xa4,
|
||||
0x68,
|
||||
0x0f,
|
||||
0x45,
|
||||
0xc9,
|
||||
0xd8,
|
||||
0x77,
|
||||
0x6b,
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
/* This sketch run on SAMD21/SAMD51 to program ESP32 by flashing bin file from SD Card
|
||||
* Supported/tested ESP MCU are: ESP32, ESP32-S2, ESP32-S3, ESP8266
|
||||
* Hardware wiring:
|
||||
* - TB D2 <-> ESP32 IO0
|
||||
* - TB D3 <-> ESP32 Enable
|
||||
* - TB TX/RX <-> ESP32 RX/TX
|
||||
*
|
||||
* How to run this example:
|
||||
* 0. Define ESP32_RESET, ESP32_IO0, SD_CS, SD_DETECT in this sketch according to your hardware setup
|
||||
* 1. Generate compressed binary and its metadata (len, md5 etc..) by running:
|
||||
* python3 tools/esp_compress.py --sd <directory_of_bin_files>
|
||||
* For example: python tools/esp_compress.py --sd .
|
||||
* 2. .bin.gz (e.g NINA_W102-1.7.5.bin.gz) and esp_binaries.h will be generated in the same directory
|
||||
* 3. Copy esp_binaries.h to this example directory
|
||||
* 4. Copy .bin.gz files to SD Card within BIN_DIR (defined in this sketch)
|
||||
* 5. Insert SD Card to board
|
||||
* 6. Upload this sketch to board
|
||||
*
|
||||
* Note: for convenience, this example included generated 'NINA_W102-1.7.5.bin.gz' and 'esp_binaries.h'
|
||||
* from https://github.com/adafruit/nina-fw/releases/tag/1.7.5 in this example directory.
|
||||
*/
|
||||
|
||||
#include "SdFat_Adafruit_Fork.h"
|
||||
|
||||
// #include "Adafruit_TinyUSB.h"
|
||||
#include "Adafruit_TestBed.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Hardware Configuration
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// These are defined in airlift-capable board such PyPortal, PyBadge, etc.
|
||||
#if defined(ESP32_GPIO0) && defined(ESP32_RESETN)
|
||||
#define ESP32_RESET ESP32_RESETN
|
||||
#define ESP32_IO0 ESP32_GPIO0
|
||||
#else
|
||||
#define ESP32_RESET 2
|
||||
#define ESP32_IO0 3
|
||||
#endif
|
||||
|
||||
#if defined(ARDUINO_PYPORTAL_M4)
|
||||
#define SD_CS 32
|
||||
#define SD_DETECT 33
|
||||
#else
|
||||
#define SD_CS 4
|
||||
#define SD_DETECT 5 // optional
|
||||
#endif
|
||||
|
||||
#define ESP32_BAUDRATE 2000000
|
||||
//#define ESP32_BAUDRATE 1500000
|
||||
//#define ESP32_BAUDRATE 921600
|
||||
//#define ESP32_BAUDRATE 115200
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Binaries and Path
|
||||
//--------------------------------------------------------------------+
|
||||
#define BIN_DIR "/" // SD card's directory that contains bin files
|
||||
#include "esp_binaries.h"
|
||||
|
||||
struct {
|
||||
uint32_t addr;
|
||||
esp32_zipfile_t const *zfile;
|
||||
} bin_files[] = {
|
||||
{0x00000, &NINA_W102_1_7_5}
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
SdFat SD;
|
||||
File32 fbin;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Implementation
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void print_speed(size_t count, uint32_t ms) {
|
||||
float count_k = count / 1000.0F;
|
||||
float sec = ms / 1000.0F;
|
||||
float speed = count_k / sec;
|
||||
|
||||
Serial.print(count_k); Serial.print("KB "); Serial.print(sec); Serial.println("s");
|
||||
Serial.print("Spd: "); Serial.print(speed); Serial.println(" KB/s");
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
while (!Serial) delay(10);
|
||||
Serial.println("TestBed: Programming ESP32 with UART!");
|
||||
|
||||
#ifdef SD_DETECT
|
||||
pinMode(SD_DETECT, INPUT_PULLUP);
|
||||
if (digitalRead(SD_DETECT) == LOW) {
|
||||
Serial.println("SD Card not inserted");
|
||||
while (1) delay(10);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!SD.begin(SD_CS, SD_SCK_MHZ(12))) {
|
||||
Serial.println("SD Card init failed");
|
||||
while (1) delay(10);
|
||||
}
|
||||
Serial.println("SD Card init OK");
|
||||
|
||||
TB.begin();
|
||||
while ( !TB.esp32_begin(&ESP32BootROM, ESP32_BAUDRATE) ) {
|
||||
// retry syncing
|
||||
delay(100);
|
||||
}
|
||||
|
||||
// Writing bin files
|
||||
size_t total_bytes = 0;
|
||||
uint32_t ms = millis();
|
||||
for(size_t i=0; i<BIN_FILES_COUNT; i++) {
|
||||
Serial.printf("Flashing file %u\r\n", i);
|
||||
Serial.printf("File: %s\r\n", bin_files[i].zfile->name);
|
||||
|
||||
char bin_path[128] = BIN_DIR;
|
||||
strcat(bin_path, bin_files[i].zfile->name);
|
||||
|
||||
fbin.open(&SD, bin_path);
|
||||
if (!fbin) {
|
||||
Serial.printf("Failed to open file %s\r\n", bin_files[i].zfile->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t wr_count = TB.esp32_programFlashDefl(bin_files[i].zfile, bin_files[i].addr, &fbin);
|
||||
total_bytes += wr_count;
|
||||
if (!wr_count) {
|
||||
Serial.printf("Failed to flash");
|
||||
}
|
||||
|
||||
fbin.close();
|
||||
}
|
||||
print_speed(total_bytes, millis() - ms);
|
||||
|
||||
TB.esp32_end();
|
||||
|
||||
// reset ESP32 to run new firmware
|
||||
TB.targetReset();
|
||||
}
|
||||
void loop() {
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
name=Adafruit TestBed
|
||||
version=1.1.0
|
||||
version=1.14.2
|
||||
author=Adafruit
|
||||
maintainer=Adafruit <info@adafruit.com>
|
||||
sentence=Adafruit's internal test bed code library
|
||||
|
|
@ -7,4 +7,4 @@ paragraph=Adafruit's internal test bed code library
|
|||
category=Display
|
||||
url=https://github.com/adafruit/Adafruit_TestBed
|
||||
architectures=*
|
||||
depends=Adafruit NeoPixel, Adafruit MCP4725
|
||||
depends=Adafruit NeoPixel, Adafruit MCP4725, Adafruit TinyUSB Library, Adafruit SPIFlash, SdFat - Adafruit Fork, Pico PIO USB, LiquidCrystal, Adafruit DAP library
|
||||
|
|
|
|||
|
|
@ -1,10 +1,25 @@
|
|||
#include "Adafruit_TestBed.h"
|
||||
|
||||
// change to 1 to skip pre-flash md5 check for testing
|
||||
#define SKIP_PRE_FLASH_MD5_CHECK 0
|
||||
|
||||
static inline uint32_t div_ceil(uint32_t v, uint32_t d) {
|
||||
return (v + d - 1) / d;
|
||||
}
|
||||
|
||||
Adafruit_TestBed::Adafruit_TestBed(void) {
|
||||
#if defined(ADAFRUIT_METRO_M0_EXPRESS)
|
||||
neopixelPin = 40;
|
||||
neopixelNum = 1;
|
||||
#elif defined(ADAFRUIT_FEATHER_M0_EXPRESS)
|
||||
neopixelPin = 8;
|
||||
neopixelNum = 1;
|
||||
#endif
|
||||
|
||||
esp32boot = NULL;
|
||||
_esp32_flash_defl = false;
|
||||
_esp32_chip_detect = 0;
|
||||
_esp32s3_in_reset = false;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
|
@ -33,14 +48,20 @@ void Adafruit_TestBed::begin(void) {
|
|||
digitalWrite(ledPin, LOW);
|
||||
}
|
||||
|
||||
if (targetResetPin >= 0) {
|
||||
pinMode(targetResetPin, OUTPUT);
|
||||
digitalWrite(targetResetPin, HIGH);
|
||||
}
|
||||
|
||||
#if defined(__AVR__)
|
||||
analogRef = 5.0;
|
||||
#elif defined(ARDUINO_ARCH_RP2040)
|
||||
analogBits = 4096;
|
||||
analogReadResolution(12);
|
||||
#elif defined(ARDUINO_ARCH_ESP32)
|
||||
analogBits = 4096;
|
||||
analogReadResolution(12);
|
||||
analogRef = 2.4;
|
||||
analogRef = 3.3;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -63,9 +84,9 @@ uint32_t Adafruit_TestBed::timestamp(void) {
|
|||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_TestBed::printTimeTaken(bool restamp) {
|
||||
Serial.print(F("Took: "));
|
||||
Serial.print(millis() - millis_timestamp);
|
||||
Serial.println(F(" ms"));
|
||||
theSerial->print(F("Took: "));
|
||||
theSerial->print(millis() - millis_timestamp);
|
||||
theSerial->println(F(" ms"));
|
||||
if (restamp) {
|
||||
timestamp();
|
||||
}
|
||||
|
|
@ -111,16 +132,16 @@ bool Adafruit_TestBed::scanI2CBus(byte addr, uint8_t post_delay) {
|
|||
/**************************************************************************/
|
||||
void Adafruit_TestBed::printI2CBusScan(void) {
|
||||
theWire->begin();
|
||||
Serial.print("I2C scan: ");
|
||||
theSerial->print("I2C scan: ");
|
||||
for (uint8_t addr = 0x00; addr <= 0x7F; addr++) {
|
||||
theWire->beginTransmission(addr);
|
||||
if (theWire->endTransmission() == 0) {
|
||||
Serial.print("0x");
|
||||
Serial.print(addr, HEX);
|
||||
Serial.print(", ");
|
||||
theSerial->print("0x");
|
||||
theSerial->print(addr, HEX);
|
||||
theSerial->print(", ");
|
||||
}
|
||||
}
|
||||
Serial.println();
|
||||
theSerial->println();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
|
@ -149,6 +170,23 @@ void Adafruit_TestBed::targetPowerCycle(uint16_t off_time) {
|
|||
targetPower(1);
|
||||
}
|
||||
|
||||
void Adafruit_TestBed::targetReset(uint32_t reset_ms) {
|
||||
digitalWrite(targetResetPin, LOW);
|
||||
delay(reset_ms);
|
||||
digitalWrite(targetResetPin, HIGH);
|
||||
|
||||
// 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.
|
||||
// Mark this for application usage
|
||||
if (_esp32_chip_detect == CHIP_DETECT_MAGIC_ESP32S3) {
|
||||
_esp32s3_in_reset = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Read the ADC on a pin and convert it to a voltage
|
||||
|
|
@ -158,12 +196,22 @@ void Adafruit_TestBed::targetPowerCycle(uint16_t off_time) {
|
|||
*/
|
||||
/**************************************************************************/
|
||||
float Adafruit_TestBed::readAnalogVoltage(uint16_t pin, float multiplier) {
|
||||
float x = analogRead(pin);
|
||||
Serial.println(x);
|
||||
x /= analogBits;
|
||||
x *= analogRef;
|
||||
x *= multiplier;
|
||||
return x;
|
||||
float a = analogRead(pin);
|
||||
// theSerial->println(a);
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && !defined(ARDUINO_ADAFRUIT_QTPY_ESP32C3)
|
||||
if (a > 3000) {
|
||||
a = 0.0005 * a + 1.0874;
|
||||
} else {
|
||||
a = 0.0008 * a + 0.1372;
|
||||
}
|
||||
#else
|
||||
a /= analogBits;
|
||||
a *= analogRef;
|
||||
#endif
|
||||
a *= multiplier;
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
|
@ -173,23 +221,27 @@ float Adafruit_TestBed::readAnalogVoltage(uint16_t pin, float multiplier) {
|
|||
@param name Human readable name for the pin
|
||||
@param multiplier If there's a resistor divider, put the inverse here
|
||||
@param value What voltage the pin should be
|
||||
@param error Percent of error permitted (10 is 10%)
|
||||
@return True if the pin voltage is within 10% of target
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_TestBed::testAnalogVoltage(uint16_t pin, const char *name,
|
||||
float multiplier, float value) {
|
||||
float multiplier, float value,
|
||||
uint8_t error) {
|
||||
float voltage = readAnalogVoltage(pin, multiplier);
|
||||
Serial.print(name);
|
||||
Serial.print(F(" output voltage: "));
|
||||
Serial.print(voltage);
|
||||
Serial.print(F(" V (should be "));
|
||||
Serial.print(value);
|
||||
Serial.print(" V)...");
|
||||
if (abs(voltage - value) > (value / 10.0)) {
|
||||
Serial.println("Failed");
|
||||
theSerial->print(name);
|
||||
theSerial->print(F(" output voltage: "));
|
||||
theSerial->print(voltage);
|
||||
theSerial->print(F(" V (should be "));
|
||||
theSerial->print(value);
|
||||
theSerial->print(" V)...");
|
||||
if (abs(voltage - value) > (value * error / 100.0)) {
|
||||
theSerial->println("Failed");
|
||||
return false;
|
||||
}
|
||||
Serial.println(F("OK within 10%"));
|
||||
theSerial->print(F("OK within "));
|
||||
theSerial->print(error);
|
||||
theSerial->println("%");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -208,10 +260,10 @@ bool Adafruit_TestBed::testAnalogVoltage(uint16_t pin, const char *name,
|
|||
bool Adafruit_TestBed::testpins(uint8_t a, uint8_t b, uint8_t *allpins,
|
||||
uint8_t num_allpins) {
|
||||
|
||||
Serial.print(F("\tTesting "));
|
||||
Serial.print(a, DEC);
|
||||
Serial.print(F(" & "));
|
||||
Serial.println(b, DEC);
|
||||
theSerial->print(F("\tTesting "));
|
||||
theSerial->print(a, DEC);
|
||||
theSerial->print(F(" & "));
|
||||
theSerial->println(b, DEC);
|
||||
|
||||
// set both to inputs
|
||||
pinMode(b, INPUT);
|
||||
|
|
@ -221,8 +273,8 @@ bool Adafruit_TestBed::testpins(uint8_t a, uint8_t b, uint8_t *allpins,
|
|||
|
||||
// verify neither are grounded
|
||||
if (!digitalRead(a) || !digitalRead(b)) {
|
||||
Serial.println(F("Ground test 1 fail: both pins should not be grounded"));
|
||||
// while (1) yield();
|
||||
theSerial->println(
|
||||
F("Ground test 1 fail: both pins should not be grounded"));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -240,11 +292,11 @@ bool Adafruit_TestBed::testpins(uint8_t a, uint8_t b, uint8_t *allpins,
|
|||
|
||||
// make sure both are low
|
||||
if (ar || br) {
|
||||
Serial.print(F("Low test fail on "));
|
||||
theSerial->print(F("Low test fail on "));
|
||||
if (br)
|
||||
Serial.println(b, DEC);
|
||||
theSerial->println(b, DEC);
|
||||
if (ar)
|
||||
Serial.println(a, DEC);
|
||||
theSerial->println(a, DEC);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -260,7 +312,8 @@ bool Adafruit_TestBed::testpins(uint8_t a, uint8_t b, uint8_t *allpins,
|
|||
|| !digitalRead(b)
|
||||
#endif
|
||||
) {
|
||||
Serial.println(F("Ground test 2 fail: both pins should not be grounded"));
|
||||
theSerial->println(
|
||||
F("Ground test 2 fail: both pins should not be grounded"));
|
||||
delay(100);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -276,17 +329,17 @@ bool Adafruit_TestBed::testpins(uint8_t a, uint8_t b, uint8_t *allpins,
|
|||
digitalWrite(b, LOW);
|
||||
delay(1);
|
||||
|
||||
for (uint8_t i = 0; i < sizeof(allpins); i++) {
|
||||
for (uint8_t i = 0; i < num_allpins; i++) {
|
||||
if ((allpins[i] == a) || (allpins[i] == b)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Serial.print("Pin #"); Serial.print(allpins[i]);
|
||||
// Serial.print(" -> ");
|
||||
// Serial.println(digitalRead(allpins[i]));
|
||||
// theSerial->print("Pin #"); theSerial->print(allpins[i]);
|
||||
// theSerial->print(" -> ");
|
||||
// theSerial->println(digitalRead(allpins[i]));
|
||||
if (!digitalRead(allpins[i])) {
|
||||
Serial.print(allpins[i]);
|
||||
Serial.println(F(" is shorted?"));
|
||||
theSerial->print(allpins[i]);
|
||||
theSerial->println(F(" is shorted?"));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -349,6 +402,14 @@ void Adafruit_TestBed::disableI2C(void) {
|
|||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Set LED on or off
|
||||
@param state LED State (HIGH, LOW)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_TestBed::setLED(uint8_t state) { digitalWrite(ledPin, state); }
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Perform a beep on the piezoPin if defined
|
||||
|
|
@ -360,8 +421,13 @@ void Adafruit_TestBed::beep(uint32_t freq, uint32_t duration) {
|
|||
if (piezoPin < 0)
|
||||
return;
|
||||
pinMode(piezoPin, OUTPUT);
|
||||
#if !defined(ARDUINO_ARCH_ESP32)
|
||||
#if !defined(ARDUINO_ARCH_ESP32) && !defined(ARDUINO_SAM_DUE) && \
|
||||
!defined(ARDUINO_METRO_ESP32S2)
|
||||
tone(piezoPin, freq, duration);
|
||||
#else
|
||||
// suppress compiler warns
|
||||
(void)freq;
|
||||
(void)duration;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -377,7 +443,28 @@ void Adafruit_TestBed::beepNblink(void) {
|
|||
digitalWrite(ledPin, HIGH);
|
||||
}
|
||||
|
||||
beep(2000, 250);
|
||||
beep(4000, 250);
|
||||
|
||||
delay(500);
|
||||
|
||||
if (ledPin >= 0) {
|
||||
digitalWrite(ledPin, LOW);
|
||||
}
|
||||
#if !defined(ARDUINO_ARCH_ESP32) && !defined(ARDUINO_SAM_DUE)
|
||||
noTone(piezoPin);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief light the LED for 500ms, if defined
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_TestBed::blink(void) {
|
||||
if (ledPin >= 0) {
|
||||
pinMode(ledPin, OUTPUT);
|
||||
digitalWrite(ledPin, HIGH);
|
||||
}
|
||||
|
||||
delay(500);
|
||||
|
||||
|
|
@ -386,4 +473,185 @@ void Adafruit_TestBed::beepNblink(void) {
|
|||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// ESP32 Target
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
bool Adafruit_TestBed::esp32_begin(ESP32BootROMClass *bootrom,
|
||||
uint32_t baudrate) {
|
||||
esp32boot = bootrom;
|
||||
|
||||
Serial.println("Syncing ESP32");
|
||||
_esp32_chip_detect = esp32boot->begin(baudrate);
|
||||
|
||||
if (_esp32_chip_detect) {
|
||||
setColor(0xFFFFFF);
|
||||
Serial.println("Synced OK");
|
||||
return true;
|
||||
} else {
|
||||
Serial.println("Sync failed!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Adafruit_TestBed::esp32_end(bool reset_esp) {
|
||||
if (esp32boot->isRunningStub()) {
|
||||
// skip sending flash_finish to ROM loader here,
|
||||
// as it causes the loader to exit and run user code
|
||||
esp32boot->beginFlash(0, 0, esp32boot->getFlashWriteSize());
|
||||
|
||||
if (_esp32_flash_defl) {
|
||||
esp32boot->endFlashDefl(reset_esp);
|
||||
} else {
|
||||
esp32boot->endFlash(reset_esp);
|
||||
}
|
||||
}
|
||||
|
||||
esp32boot->end();
|
||||
}
|
||||
|
||||
bool Adafruit_TestBed::esp32_s3_inReset(void) { return _esp32s3_in_reset; }
|
||||
|
||||
void Adafruit_TestBed::esp32_s3_clearReset(void) { _esp32s3_in_reset = false; }
|
||||
|
||||
static void print_buf(uint8_t const *buf, size_t len) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
Serial.print(buf[i], HEX);
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
size_t
|
||||
Adafruit_TestBed::_esp32_programFlashDefl_impl(const esp32_zipfile_t *zfile,
|
||||
uint32_t addr, File32 *fsrc) {
|
||||
if (!esp32boot) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check if MD5 matches to skip this file
|
||||
uint8_t esp_md5[16];
|
||||
|
||||
#if !SKIP_PRE_FLASH_MD5_CHECK
|
||||
esp32boot->md5Flash(addr, zfile->uncompressed_len, esp_md5);
|
||||
Serial.print("Flash MD5: ");
|
||||
print_buf(esp_md5, 16);
|
||||
if (0 == memcmp(zfile->md5, esp_md5, 16)) {
|
||||
Serial.println("MD5 matched");
|
||||
return zfile->uncompressed_len;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Write Size is different depending on ROM (1K) or Stub (16KB)
|
||||
uint32_t const block_size = esp32boot->getFlashWriteSize();
|
||||
|
||||
uint8_t *buf = NULL;
|
||||
bool const use_sdcard = (fsrc != NULL);
|
||||
|
||||
if (use_sdcard) {
|
||||
buf = (uint8_t *)malloc(block_size);
|
||||
if (!buf) {
|
||||
Serial.print("No memory ");
|
||||
Serial.println(block_size);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Serial.print("Compressed ");
|
||||
Serial.print(zfile->uncompressed_len);
|
||||
Serial.print(" bytes to ");
|
||||
Serial.println(zfile->compressed_len);
|
||||
|
||||
if (!esp32boot->beginFlashDefl(addr, zfile->uncompressed_len,
|
||||
zfile->compressed_len)) {
|
||||
Serial.println("beginFlash failed!");
|
||||
if (buf) {
|
||||
free(buf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
_esp32_flash_defl = true;
|
||||
|
||||
//------------- Flashing -------------//
|
||||
uint32_t written = 0;
|
||||
|
||||
uint32_t const block_num = div_ceil(zfile->compressed_len, block_size);
|
||||
for (uint32_t i = 0; i < block_num; i++) {
|
||||
setLED(HIGH);
|
||||
// Serial.print("Pckt %lu/%lu", i + 1, block_num);
|
||||
Serial.print("Packet ");
|
||||
Serial.print(i + 1);
|
||||
Serial.print("/");
|
||||
Serial.println(block_num);
|
||||
|
||||
uint32_t const remain = zfile->compressed_len - written;
|
||||
uint32_t const wr_count = (remain < block_size) ? remain : block_size;
|
||||
|
||||
uint8_t const *data;
|
||||
if (!use_sdcard) {
|
||||
// file contents is stored in internal flash (e.g rp2040)
|
||||
data = zfile->data + written;
|
||||
} else {
|
||||
// file contents is stored in sdcard
|
||||
memset(buf, 0xff, block_size); // empty it out
|
||||
if (wr_count != fsrc->read(buf, wr_count)) {
|
||||
Serial.println("File contents does not matched with compressed_len");
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
data = buf;
|
||||
}
|
||||
|
||||
// Note: flash deflat does not need padding
|
||||
if (!esp32boot->dataFlashDefl(data, wr_count)) {
|
||||
Serial.println("Failed to flash");
|
||||
break;
|
||||
}
|
||||
|
||||
written += wr_count;
|
||||
setLED(LOW);
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
// Stub only writes each block to flash after 'ack'ing the receive,
|
||||
// so do a final dummy operation which will not be 'ack'ed
|
||||
// until the last block has actually been written out to flash
|
||||
if (esp32boot->isRunningStub()) {
|
||||
Serial.println("Dummy read chip detect after final block");
|
||||
(void)esp32boot->read_chip_detect();
|
||||
}
|
||||
|
||||
//------------- MD5 verification -------------//
|
||||
Serial.println("Verifying MD5");
|
||||
esp32boot->md5Flash(addr, zfile->uncompressed_len, esp_md5);
|
||||
|
||||
if (0 == memcmp(zfile->md5, esp_md5, 16)) {
|
||||
Serial.println("MD5 matched");
|
||||
} else {
|
||||
Serial.println("MD5 mismatched!!");
|
||||
|
||||
Serial.print("File: ");
|
||||
print_buf(zfile->md5, 16);
|
||||
|
||||
Serial.print("ESP : ");
|
||||
print_buf(esp_md5, 16);
|
||||
}
|
||||
|
||||
if (buf) {
|
||||
free(buf);
|
||||
}
|
||||
|
||||
return zfile->uncompressed_len;
|
||||
}
|
||||
size_t Adafruit_TestBed::esp32_programFlashDefl(const esp32_zipfile_t *zfile,
|
||||
uint32_t addr) {
|
||||
return _esp32_programFlashDefl_impl(zfile, addr, NULL);
|
||||
}
|
||||
|
||||
size_t Adafruit_TestBed::esp32_programFlashDefl(const esp32_zipfile_t *zfile,
|
||||
uint32_t addr, File32 *fsrc) {
|
||||
return _esp32_programFlashDefl_impl(zfile, addr, fsrc);
|
||||
}
|
||||
|
||||
Adafruit_TestBed TB;
|
||||
|
|
@ -5,6 +5,9 @@
|
|||
#include "Arduino.h"
|
||||
#include "Wire.h"
|
||||
|
||||
#include "ESP32BootROM.h"
|
||||
#include "SdFat_Adafruit_Fork.h"
|
||||
|
||||
#define RED 0xFF0000
|
||||
#define YELLOW 0xFFFF00
|
||||
#define GREEN 0x00FF00
|
||||
|
|
@ -13,6 +16,14 @@
|
|||
#define PURPLE 0xFF00FF
|
||||
#define WHITE 0xFFFFFF
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
const uint8_t *data;
|
||||
const uint32_t compressed_len;
|
||||
const uint32_t uncompressed_len;
|
||||
const uint8_t md5[16];
|
||||
} esp32_zipfile_t;
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief A helper class for making test beds and functions. Lots of handy lil
|
||||
|
|
@ -33,23 +44,47 @@ public:
|
|||
void targetPower(bool on);
|
||||
void targetPowerCycle(uint16_t off_time = 10);
|
||||
|
||||
void targetReset(uint32_t reset_ms = 20);
|
||||
|
||||
float readAnalogVoltage(uint16_t pin, float multiplier = 1);
|
||||
bool testAnalogVoltage(uint16_t pin, const char *name, float multiplier,
|
||||
float value);
|
||||
float value, uint8_t error = 10);
|
||||
|
||||
bool testpins(uint8_t a, uint8_t b, uint8_t *allpins, uint8_t num_allpins);
|
||||
|
||||
void setColor(uint32_t color);
|
||||
uint32_t Wheel(byte WheelPos);
|
||||
|
||||
void setLED(uint8_t state);
|
||||
|
||||
void beep(uint32_t freq, uint32_t duration);
|
||||
void beepNblink(void);
|
||||
void blink(void);
|
||||
|
||||
uint32_t timestamp(void);
|
||||
void printTimeTaken(bool restamp = false);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// ESP32 Target
|
||||
//--------------------------------------------------------------------+
|
||||
bool esp32_begin(ESP32BootROMClass *bootrom, uint32_t baudrate);
|
||||
void esp32_end(bool reset_esp = false);
|
||||
|
||||
// program esp32 target with compressed data stored in internal flash
|
||||
size_t esp32_programFlashDefl(const esp32_zipfile_t *zfile, uint32_t addr);
|
||||
|
||||
// program esp32 target with compressed file from SDCard
|
||||
size_t esp32_programFlashDefl(const esp32_zipfile_t *zfile, uint32_t addr,
|
||||
File32 *fsrc);
|
||||
|
||||
bool esp32_s3_inReset(void);
|
||||
void esp32_s3_clearReset(void);
|
||||
|
||||
ESP32BootROMClass *esp32boot; // ESP32 ROM
|
||||
|
||||
//////////////////
|
||||
TwoWire *theWire = &Wire; ///< The I2C port used in scanning
|
||||
TwoWire *theWire = &Wire; ///< The I2C port used in scanning
|
||||
Stream *theSerial = &Serial; ///< The Serial port used for debugging
|
||||
|
||||
float analogRef = 3.3; ///< The default analog reference voltage
|
||||
uint16_t analogBits = 1024; ///< The default ADC resolution bits
|
||||
|
|
@ -57,6 +92,8 @@ public:
|
|||
int16_t targetPowerPin = -1; ///< Set to a target power pin if used
|
||||
bool targetPowerPolarity = HIGH; ///< What to set the power pin to, for ON
|
||||
|
||||
int targetResetPin = -1; ///< Set to target reset pin if used
|
||||
|
||||
int16_t neopixelPin = -1; ///< The neopixel connected pin if any
|
||||
uint8_t neopixelNum = 0; ///< How many neopixels are on board, if any
|
||||
Adafruit_NeoPixel *pixels =
|
||||
|
|
@ -67,6 +104,15 @@ public:
|
|||
|
||||
private:
|
||||
uint32_t millis_timestamp = 0; ///< A general purpose timestamp
|
||||
|
||||
bool _esp32_flash_defl;
|
||||
uint32_t _esp32_chip_detect;
|
||||
bool _esp32s3_in_reset;
|
||||
|
||||
size_t _esp32_programFlashDefl_impl(const esp32_zipfile_t *zfile,
|
||||
uint32_t addr, File32 *fsrc);
|
||||
};
|
||||
|
||||
extern Adafruit_TestBed TB;
|
||||
|
||||
#endif
|
||||
968
src/Adafruit_TestBed_Brains.cpp
Normal file
968
src/Adafruit_TestBed_Brains.cpp
Normal file
|
|
@ -0,0 +1,968 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef ARDUINO_ARCH_RP2040
|
||||
|
||||
#include "SdFat_Adafruit_Fork.h"
|
||||
#include "pio_usb.h"
|
||||
|
||||
#include "Adafruit_DAP.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
#include "Adafruit_TestBed_Brains.h"
|
||||
|
||||
#define USBHOST_RHPORT 1
|
||||
|
||||
// Workaround force F_CPU to 240MHz for programming RP2350 due to handshake
|
||||
// timeout
|
||||
#if F_CPU != 120000000L && F_CPU != 240000000L
|
||||
#error "F_CPU must be set to either 120Mhz or 240Mhz for pio-usb host"
|
||||
#endif
|
||||
|
||||
Adafruit_TestBed_Brains Brain;
|
||||
|
||||
volatile bool LCD_semaphore = false;
|
||||
|
||||
// Simple and low code CRC calculation (copied from PicoOTA)
|
||||
class BrainCRC32 {
|
||||
public:
|
||||
BrainCRC32() { crc = 0xffffffff; }
|
||||
|
||||
~BrainCRC32() {}
|
||||
|
||||
void add(const void *d, uint32_t len) {
|
||||
const uint8_t *data = (const uint8_t *)d;
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
crc ^= data[i];
|
||||
for (int j = 0; j < 8; j++) {
|
||||
if (crc & 1) {
|
||||
crc = (crc >> 1) ^ 0xedb88320;
|
||||
} else {
|
||||
crc >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t get() { return ~crc; }
|
||||
|
||||
private:
|
||||
uint32_t crc;
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Initializer, sets up the timestamp, neopixels, piezo, led,
|
||||
and analog reference. So get all pins assigned before calling
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
Adafruit_TestBed_Brains::Adafruit_TestBed_Brains() {
|
||||
_inited = false;
|
||||
_lcd_line = 0;
|
||||
|
||||
piezoPin = 15; // onboard buzzer
|
||||
ledPin = 25; // green LED on Pico
|
||||
|
||||
targetPowerPin = 6; // VBat switch
|
||||
|
||||
neopixelNum = 1; // LCD backlight
|
||||
neopixelPin = 13; // LCD backlight
|
||||
|
||||
_sd_detect_pin = 14; // SD detect
|
||||
_sd_cs_pin = 17; // SD chip select
|
||||
|
||||
_usbh_dp_pin = 20; // USB Host D+
|
||||
_vbus_en_pin = 22; // USB Host VBus enable
|
||||
|
||||
targetResetPin = 27;
|
||||
_target_swdio = 2;
|
||||
_target_swdclk = 3;
|
||||
|
||||
dap = NULL;
|
||||
}
|
||||
|
||||
void Adafruit_TestBed_Brains::begin(void) {
|
||||
// skip Adafruit_Neopixel by setting neopixelNum = 0 since
|
||||
// we will bit-banging due to the pio conflict with usb host
|
||||
neopixelNum = 0;
|
||||
Adafruit_TestBed::begin();
|
||||
|
||||
neopixelNum = 1;
|
||||
pinMode(neopixelPin, OUTPUT);
|
||||
|
||||
pinMode(targetResetPin, OUTPUT);
|
||||
digitalWrite(targetResetPin, HIGH);
|
||||
|
||||
pinMode(_sd_detect_pin, INPUT_PULLUP);
|
||||
pinMode(_vbus_en_pin, OUTPUT);
|
||||
usbh_setVBus(false); // disabled by default
|
||||
|
||||
analogReadResolution(12);
|
||||
|
||||
// pixels->setBrightness(255); TODO can use variable to take color percentage
|
||||
// in setColor()
|
||||
setColor(0xFFFFFF);
|
||||
|
||||
lcd.begin(16, 2);
|
||||
lcd.clear();
|
||||
lcd.home();
|
||||
lcd.noCursor();
|
||||
|
||||
_inited = true;
|
||||
}
|
||||
|
||||
bool Adafruit_TestBed_Brains::inited(void) { return _inited; }
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// RP2040 Target
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void Adafruit_TestBed_Brains::rp2_targetResetBootRom(int bootsel_pin,
|
||||
uint32_t reset_ms) {
|
||||
pinMode(bootsel_pin, OUTPUT);
|
||||
digitalWrite(bootsel_pin, LOW);
|
||||
|
||||
targetReset(reset_ms);
|
||||
delay(reset_ms);
|
||||
|
||||
// change bootsel to input since it is muxed with Flash ChipSelect
|
||||
digitalWrite(bootsel_pin, HIGH);
|
||||
pinMode(bootsel_pin, INPUT);
|
||||
}
|
||||
|
||||
size_t Adafruit_TestBed_Brains::rp2_programUF2(const uint8_t *buffer,
|
||||
size_t bufsize) {
|
||||
size_t copied_bytes = 0;
|
||||
const char *dst_name = "FIRMWARE.UF2";
|
||||
File32 fdst = USBH_FS.open(dst_name, O_WRONLY | O_CREAT);
|
||||
|
||||
if (!fdst) {
|
||||
Serial.printf("USBH_FS: cannot create file: %s\r\n", dst_name);
|
||||
} else {
|
||||
while (copied_bytes < bufsize) {
|
||||
size_t count = bufsize - copied_bytes;
|
||||
if (count > 4096) {
|
||||
count = 4096; // write 1 sector each
|
||||
}
|
||||
|
||||
setLED(HIGH);
|
||||
size_t wr_count = fdst.write(buffer, count);
|
||||
setLED(LOW);
|
||||
|
||||
buffer += wr_count;
|
||||
copied_bytes += wr_count;
|
||||
|
||||
if (wr_count != count) {
|
||||
Serial.println("USBH_FS: Failed to write file");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fdst.close();
|
||||
|
||||
return copied_bytes;
|
||||
}
|
||||
|
||||
size_t Adafruit_TestBed_Brains::rp2_programUF2(const char *fpath) {
|
||||
File32 fsrc = SD.open(fpath);
|
||||
if (!fsrc) {
|
||||
Serial.printf("SD: cannot open file: %s\r\n", fpath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t copied_bytes = 0;
|
||||
const char *dst_name = "FIRMWARE.UF2";
|
||||
File32 fdst = USBH_FS.open(dst_name, O_WRONLY | O_CREAT);
|
||||
|
||||
if (!fdst) {
|
||||
Serial.printf("USBH_FS: cannot create file: %s\r\n", dst_name);
|
||||
} else {
|
||||
size_t const bufsize = 4096;
|
||||
uint8_t *buf = (uint8_t *)malloc(bufsize);
|
||||
if (!buf) {
|
||||
Serial.println("Not enough memory");
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (fsrc.available()) {
|
||||
memset(buf, 0x00, bufsize); // empty it out
|
||||
|
||||
size_t rd_count = (size_t)fsrc.read(buf, bufsize);
|
||||
size_t wr_count = 0;
|
||||
|
||||
setLED(HIGH);
|
||||
wr_count = fdst.write(buf, rd_count);
|
||||
setLED(LOW);
|
||||
|
||||
copied_bytes += wr_count;
|
||||
|
||||
if (wr_count != rd_count) {
|
||||
Serial.println("USBH_FS: Failed to write file");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
fsrc.close();
|
||||
fdst.close();
|
||||
|
||||
return copied_bytes;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// DAP Target
|
||||
//--------------------------------------------------------------------+
|
||||
static void dap_err_hanlder(const char *msg) { Brain.LCD_error(msg, NULL); }
|
||||
|
||||
bool Adafruit_TestBed_Brains::dap_begin(Adafruit_DAP *dp) {
|
||||
if (!dp) {
|
||||
return dp;
|
||||
}
|
||||
|
||||
pinMode(_target_swdio, OUTPUT);
|
||||
digitalWrite(_target_swdio, LOW);
|
||||
|
||||
pinMode(_target_swdclk, OUTPUT);
|
||||
digitalWrite(_target_swdclk, LOW);
|
||||
|
||||
dap = dp;
|
||||
|
||||
return dap->begin(_target_swdclk, _target_swdio, targetResetPin,
|
||||
dap_err_hanlder);
|
||||
}
|
||||
|
||||
bool Adafruit_TestBed_Brains::dap_connect(uint32_t swj_clock) {
|
||||
if (!dap) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LCD_printf("Connecting...");
|
||||
if (!dap->targetConnect(swj_clock)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t dsu_did;
|
||||
if (!dap->select(&dsu_did)) {
|
||||
setColor(0xFF0000);
|
||||
LCD_printf(0, "Unknown MCU");
|
||||
LCD_printf(1, "ID = %08X", dsu_did);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t const page_size =
|
||||
dap->target_device.n_pages
|
||||
? (dap->target_device.flash_size / dap->target_device.n_pages)
|
||||
: 0;
|
||||
|
||||
Serial.printf("Found Target: %s, ID = %08lX\n", dap->target_device.name,
|
||||
dsu_did);
|
||||
Serial.printf("Flash size: %lu, Page Num: %lu, Page Size: %lu\n",
|
||||
dap->target_device.flash_size, dap->target_device.n_pages,
|
||||
page_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Adafruit_TestBed_Brains::dap_disconnect(void) {
|
||||
if (!dap) {
|
||||
return;
|
||||
}
|
||||
dap->deselect();
|
||||
}
|
||||
|
||||
bool Adafruit_TestBed_Brains::dap_unprotectBoot(void) {
|
||||
if (!dap) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Serial.println("Unlock chip...");
|
||||
bool ret = dap->unprotectBoot();
|
||||
Serial.println(ret ? "OK" : "Failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Adafruit_TestBed_Brains::dap_protectBoot(void) {
|
||||
if (!dap) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Serial.println("Lock chip...");
|
||||
bool ret = dap->protectBoot();
|
||||
Serial.println(ret ? "OK" : "Failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Adafruit_TestBed_Brains::dap_eraseChip(void) {
|
||||
if (!dap) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t const dap_typeid = dap->getTypeID();
|
||||
|
||||
// NOTE: STM32 does erase on-the-fly therefore erasing is not needed
|
||||
if (dap_typeid == DAP_TYPEID_STM32) {
|
||||
LCD_printf("Erasing..skipped");
|
||||
} else {
|
||||
LCD_printf("Erasing..");
|
||||
uint32_t ms = millis();
|
||||
|
||||
dap->erase();
|
||||
|
||||
ms = millis() - ms;
|
||||
LCD_printf("Erased in %.02fs", ms / 1000.0F);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t Adafruit_TestBed_Brains::dap_programFlash(const char *fpath,
|
||||
uint32_t addr, bool do_verify,
|
||||
bool do_crc32) {
|
||||
if (!dap) {
|
||||
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();
|
||||
|
||||
size_t bufsize;
|
||||
uint32_t const dap_typeid = dap->getTypeID();
|
||||
|
||||
switch (dap_typeid) {
|
||||
case DAP_TYPEID_SAM:
|
||||
bufsize = Adafruit_DAP_SAM::PAGESIZE;
|
||||
break;
|
||||
|
||||
case DAP_TYPEID_SAMX5:
|
||||
bufsize = Adafruit_DAP_SAMx5::PAGESIZE;
|
||||
break;
|
||||
|
||||
case DAP_TYPEID_NRF5X:
|
||||
bufsize = 4096;
|
||||
break;
|
||||
|
||||
case DAP_TYPEID_STM32:
|
||||
bufsize = 4096;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t *buf = (uint8_t *)malloc(bufsize);
|
||||
|
||||
if (!buf) {
|
||||
Serial.printf("Not enough memory %u\n", bufsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LCD_printf("Programming...");
|
||||
uint32_t ms = millis();
|
||||
|
||||
BrainCRC32 crc32;
|
||||
dap->program_start(addr, fsize);
|
||||
|
||||
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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
Serial.printf("Programming end, t = %lu ms\r\n", millis(), millis() - ms);
|
||||
|
||||
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!");
|
||||
}
|
||||
|
||||
free(buf);
|
||||
fsrc.close();
|
||||
|
||||
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);
|
||||
LCD_printf("%d remaining", remain);
|
||||
addr += count;
|
||||
remain -= count;
|
||||
}
|
||||
|
||||
fsrc.close();
|
||||
LCD_printf("Done!");
|
||||
|
||||
return size - remain;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// SD Card
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
bool Adafruit_TestBed_Brains::SD_detected(void) {
|
||||
return digitalRead(_sd_detect_pin);
|
||||
}
|
||||
|
||||
bool Adafruit_TestBed_Brains::SD_begin(uint32_t max_clock) {
|
||||
if (!SD_detected()) {
|
||||
LCD_printf(0, "No SD Card");
|
||||
while (!SD_detected()) {
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
|
||||
if (!SD.begin(_sd_cs_pin, max_clock)) {
|
||||
LCD_printf(0, "SD init failed");
|
||||
while (1) {
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
|
||||
LCD_printf(0, "SD mounted");
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// LCD
|
||||
//--------------------------------------------------------------------+
|
||||
#define NOP1 __asm volatile("nop");
|
||||
#define NOP2 NOP1 NOP1
|
||||
#define NOP3 NOP2 NOP1
|
||||
#define NOP4 NOP2 NOP2
|
||||
#define NOP5 NOP4 NOP1
|
||||
#define NOP6 NOP4 NOP2
|
||||
#define NOP7 NOP4 NOP3
|
||||
#define NOP8 NOP4 NOP4
|
||||
#define NOP9 NOP8 NOP1
|
||||
#define NOP10 NOP8 NOP2
|
||||
#define NOP11 NOP8 NOP3
|
||||
#define NOP12 NOP8 NOP4
|
||||
#define NOP13 NOP8 NOP5
|
||||
#define NOP14 NOP8 NOP6
|
||||
#define NOP15 NOP8 NOP7
|
||||
#define NOP16 NOP8 NOP8
|
||||
#define NOP17 NOP16 NOP1
|
||||
#define NOP18 NOP16 NOP2
|
||||
#define NOP19 NOP16 NOP3
|
||||
#define NOP20 NOP16 NOP4
|
||||
#define NOP21 NOP16 NOP5
|
||||
#define NOP22 NOP16 NOP6
|
||||
#define NOP23 NOP16 NOP7
|
||||
#define NOP24 NOP16 NOP8
|
||||
#define NOP25 NOP16 NOP9
|
||||
#define NOP26 NOP16 NOP10
|
||||
#define NOP27 NOP16 NOP11
|
||||
#define NOP28 NOP16 NOP12
|
||||
#define NOP29 NOP16 NOP13
|
||||
#define NOP30 NOP16 NOP14
|
||||
#define NOP31 NOP16 NOP15
|
||||
#define NOP32 NOP16 NOP16
|
||||
#define NOP33 NOP32 NOP1
|
||||
#define NOP34 NOP32 NOP2
|
||||
#define NOP35 NOP32 NOP3
|
||||
#define NOP36 NOP32 NOP4
|
||||
#define NOP37 NOP32 NOP5
|
||||
#define NOP38 NOP32 NOP6
|
||||
#define NOP39 NOP32 NOP7
|
||||
#define NOP40 NOP32 NOP8
|
||||
#define NOP41 NOP32 NOP9
|
||||
#define NOP42 NOP32 NOP10
|
||||
#define NOP43 NOP32 NOP11
|
||||
#define NOP44 NOP32 NOP12
|
||||
#define NOP45 NOP32 NOP13
|
||||
#define NOP46 NOP32 NOP14
|
||||
#define NOP47 NOP32 NOP15
|
||||
#define NOP48 NOP32 NOP16
|
||||
#define NOP49 NOP48 NOP1
|
||||
#define NOP50 NOP48 NOP2
|
||||
#define NOP51 NOP48 NOP3
|
||||
#define NOP52 NOP48 NOP4
|
||||
#define NOP53 NOP48 NOP5
|
||||
#define NOP54 NOP48 NOP6
|
||||
#define NOP55 NOP48 NOP7
|
||||
#define NOP56 NOP48 NOP8
|
||||
#define NOP57 NOP48 NOP9
|
||||
#define NOP58 NOP48 NOP10
|
||||
#define NOP59 NOP48 NOP11
|
||||
#define NOP60 NOP48 NOP12
|
||||
#define NOP61 NOP48 NOP13
|
||||
#define NOP62 NOP48 NOP14
|
||||
#define NOP63 NOP48 NOP15
|
||||
#define NOP64 NOP48 NOP16
|
||||
#define NOP65 NOP64 NOP1
|
||||
#define NOP66 NOP64 NOP2
|
||||
#define NOP67 NOP64 NOP3
|
||||
#define NOP68 NOP64 NOP4
|
||||
#define NOP69 NOP64 NOP5
|
||||
#define NOP70 NOP64 NOP6
|
||||
#define NOP71 NOP64 NOP7
|
||||
#define NOP72 NOP64 NOP8
|
||||
#define NOP73 NOP64 NOP9
|
||||
#define NOP74 NOP64 NOP10
|
||||
#define NOP75 NOP64 NOP11
|
||||
#define NOP76 NOP64 NOP12
|
||||
#define NOP77 NOP64 NOP13
|
||||
#define NOP78 NOP64 NOP14
|
||||
#define NOP79 NOP64 NOP15
|
||||
#define NOP80 NOP64 NOP16
|
||||
#define NOP81 NOP80 NOP1
|
||||
#define NOP82 NOP80 NOP2
|
||||
#define NOP83 NOP80 NOP3
|
||||
#define NOP84 NOP80 NOP4
|
||||
#define NOP85 NOP80 NOP5
|
||||
#define NOP86 NOP80 NOP6
|
||||
#define NOP87 NOP80 NOP7
|
||||
#define NOP88 NOP80 NOP8
|
||||
#define NOP89 NOP80 NOP9
|
||||
#define NOP90 NOP80 NOP10
|
||||
#define NOP91 NOP80 NOP11
|
||||
#define NOP92 NOP80 NOP12
|
||||
#define NOP93 NOP80 NOP13
|
||||
#define NOP94 NOP80 NOP14
|
||||
#define NOP95 NOP80 NOP15
|
||||
#define NOP96 NOP80 NOP16
|
||||
#define NOP97 NOP96 NOP1
|
||||
#define NOP98 NOP96 NOP2
|
||||
#define NOP99 NOP96 NOP3
|
||||
#define NOP100 NOP96 NOP4
|
||||
#define NOP101 NOP100 NOP1
|
||||
#define NOP102 NOP100 NOP2
|
||||
#define NOP103 NOP100 NOP3
|
||||
#define NOP104 NOP100 NOP4
|
||||
#define NOP105 NOP100 NOP5
|
||||
#define NOP106 NOP100 NOP6
|
||||
#define NOP107 NOP100 NOP7
|
||||
#define NOP108 NOP100 NOP8
|
||||
#define NOP109 NOP100 NOP9
|
||||
#define NOP110 NOP100 NOP10
|
||||
#define NOP111 NOP100 NOP11
|
||||
#define NOP112 NOP100 NOP12
|
||||
#define NOP113 NOP100 NOP13
|
||||
#define NOP114 NOP100 NOP14
|
||||
#define NOP115 NOP100 NOP15
|
||||
#define NOP116 NOP100 NOP16
|
||||
#define NOP117 NOP116 NOP1
|
||||
#define NOP118 NOP116 NOP2
|
||||
#define NOP119 NOP116 NOP3
|
||||
#define NOP120 NOP116 NOP4
|
||||
#define NOP121 NOP116 NOP5
|
||||
#define NOP122 NOP116 NOP6
|
||||
#define NOP123 NOP116 NOP7
|
||||
#define NOP124 NOP116 NOP8
|
||||
#define NOP125 NOP116 NOP9
|
||||
#define NOP126 NOP116 NOP10
|
||||
#define NOP127 NOP116 NOP11
|
||||
#define NOP128 NOP116 NOP12
|
||||
#define NOP129 NOP128 NOP1
|
||||
#define NOP130 NOP128 NOP2
|
||||
#define NOP131 NOP128 NOP3
|
||||
#define NOP132 NOP128 NOP4
|
||||
#define NOP133 NOP128 NOP5
|
||||
#define NOP134 NOP128 NOP6
|
||||
#define NOP135 NOP128 NOP7
|
||||
#define NOP136 NOP128 NOP8
|
||||
#define NOP137 NOP128 NOP9
|
||||
#define NOP138 NOP128 NOP10
|
||||
#define NOP139 NOP128 NOP11
|
||||
#define NOP140 NOP128 NOP12
|
||||
#define NOP141 NOP128 NOP13
|
||||
#define NOP142 NOP128 NOP14
|
||||
#define NOP143 NOP128 NOP15
|
||||
#define NOP144 NOP128 NOP16
|
||||
#define NOP145 NOP144 NOP1
|
||||
#define NOP146 NOP144 NOP2
|
||||
#define NOP147 NOP144 NOP3
|
||||
#define NOP148 NOP144 NOP4
|
||||
#define NOP149 NOP144 NOP5
|
||||
#define NOP150 NOP144 NOP6
|
||||
#define NOP151 NOP144 NOP7
|
||||
#define NOP152 NOP144 NOP8
|
||||
#define NOP153 NOP144 NOP9
|
||||
#define NOP154 NOP144 NOP10
|
||||
#define NOP155 NOP144 NOP11
|
||||
#define NOP156 NOP144 NOP12
|
||||
#define NOP157 NOP144 NOP13
|
||||
#define NOP158 NOP144 NOP14
|
||||
#define NOP159 NOP144 NOP15
|
||||
#define NOP160 NOP144 NOP16
|
||||
#define NOP161 NOP160 NOP1
|
||||
#define NOP162 NOP160 NOP2
|
||||
#define NOP163 NOP160 NOP3
|
||||
#define NOP164 NOP160 NOP4
|
||||
#define NOP165 NOP160 NOP5
|
||||
#define NOP166 NOP160 NOP6
|
||||
#define NOP167 NOP160 NOP7
|
||||
#define NOP168 NOP160 NOP8
|
||||
#define NOP169 NOP160 NOP9
|
||||
#define NOP170 NOP160 NOP10
|
||||
#define NOP171 NOP160 NOP11
|
||||
#define NOP172 NOP160 NOP12
|
||||
#define NOP173 NOP160 NOP13
|
||||
#define NOP174 NOP160 NOP14
|
||||
#define NOP175 NOP160 NOP15
|
||||
#define NOP176 NOP160 NOP16
|
||||
#define NOP177 NOP176 NOP1
|
||||
#define NOP178 NOP176 NOP2
|
||||
#define NOP179 NOP176 NOP3
|
||||
#define NOP180 NOP176 NOP4
|
||||
#define NOP181 NOP176 NOP5
|
||||
#define NOP182 NOP176 NOP6
|
||||
#define NOP183 NOP176 NOP7
|
||||
#define NOP184 NOP176 NOP8
|
||||
#define NOP185 NOP176 NOP9
|
||||
#define NOP186 NOP176 NOP10
|
||||
#define NOP187 NOP176 NOP11
|
||||
#define NOP188 NOP176 NOP12
|
||||
#define NOP189 NOP176 NOP13
|
||||
#define NOP190 NOP176 NOP14
|
||||
#define NOP191 NOP176 NOP15
|
||||
#define NOP192 NOP176 NOP16
|
||||
#define NOP193 NOP192 NOP1
|
||||
#define NOP194 NOP192 NOP2
|
||||
#define NOP195 NOP192 NOP3
|
||||
#define NOP196 NOP192 NOP4
|
||||
#define NOP197 NOP192 NOP5
|
||||
#define NOP198 NOP192 NOP6
|
||||
#define NOP199 NOP192 NOP7
|
||||
#define NOP200 NOP192 NOP8
|
||||
|
||||
#define _NOP_COUNT(n) NOP##n
|
||||
#define NOP_COUNT(n) _NOP_COUNT(n)
|
||||
|
||||
void __no_inline_not_in_flash_func(Adafruit_TestBed_Brains::setColor)(
|
||||
uint32_t color) {
|
||||
static uint32_t end_us = 0;
|
||||
static uint32_t last_color = 0x123456;
|
||||
|
||||
if (last_color == color) {
|
||||
// no need to update
|
||||
return;
|
||||
}
|
||||
last_color = color;
|
||||
|
||||
uint8_t r = (uint8_t)(color >> 16); // red
|
||||
uint8_t g = (uint8_t)(color >> 8); // green
|
||||
uint8_t b = (uint8_t)color; // blue
|
||||
|
||||
uint8_t buf[3] = {r, g, b};
|
||||
|
||||
uint8_t *ptr, *end, p, bitMask;
|
||||
uint32_t const pinMask = 1ul << neopixelPin;
|
||||
|
||||
ptr = buf;
|
||||
end = ptr + 3;
|
||||
p = *ptr++;
|
||||
bitMask = 0x80;
|
||||
|
||||
// wait for previous frame to finish
|
||||
enum { FRAME_TIME_US = 300 };
|
||||
|
||||
uint32_t now = end_us;
|
||||
while (now - end_us < FRAME_TIME_US) {
|
||||
now = micros();
|
||||
if (now < end_us) {
|
||||
// micros() overflow
|
||||
end_us = now;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t const isr_context = save_and_disable_interrupts();
|
||||
|
||||
/* Neopixel is 800 KHz, 1T = 1.25 us = 150 nop (120Mhz), 300 nop (240Mhz)
|
||||
- T1H = 0.8 us, T1L = 0.45 us
|
||||
- T0H = 0.4 us, T0L = 0.85 us
|
||||
If F_CPU is 120 MHz: 120 nop = 1us -> 1 nop = 8.33 ns
|
||||
- T1H = 0.8 us = 96 nop, T1L = 0.45 us = 54 nop
|
||||
- T0H = 0.4 us = 48 nop, T0L = 0.85 us = 102 nop
|
||||
If F_CPU is 240 MHz: 240 nop = 1us -> 1 nop = 4.17 ns
|
||||
- T1H = 0.8 us = 192 nop, T1L = 0.45 us = 108 nop
|
||||
- T0H = 0.4 us = 96 nop, T0L = 0.85 us = 204 nop
|
||||
Due to overhead the number of NOP is actually smaller, also M33 run faster
|
||||
(higher IPC) therefore these are hand tuned,
|
||||
*/
|
||||
#if defined(ARDUINO_RASPBERRY_PI_PICO)
|
||||
// value for rp2040 at 120MHz
|
||||
#define T1H_CYCLE 90
|
||||
#define T1L_CYCLE 39
|
||||
#define T0H_CYCLE 42
|
||||
#define T0L_CYCLE 84
|
||||
#define LOOP_OVERHEAD_CYCLE 10 // overhead for if/else and loop
|
||||
#elif defined(ARDUINO_RASPBERRY_PI_PICO_2)
|
||||
// value for rp2350 at 120MHz
|
||||
#define T1H_CYCLE 190
|
||||
#define T1L_CYCLE 90
|
||||
#define T0H_CYCLE 88
|
||||
#define T0L_CYCLE 180
|
||||
#define LOOP_OVERHEAD_CYCLE 5
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
if (p & bitMask) {
|
||||
// T1H 0.8 us = 96 nop (without overhead)
|
||||
sio_hw->gpio_set = pinMask;
|
||||
NOP_COUNT(T1H_CYCLE);
|
||||
#if F_CPU == 240000000L
|
||||
NOP_COUNT(T1H_CYCLE);
|
||||
#endif
|
||||
|
||||
// T1L 0.45 = 54 - 10 (ifelse) - 5 (overhead) = 44 nop
|
||||
sio_hw->gpio_clr = pinMask;
|
||||
NOP_COUNT(T1L_CYCLE);
|
||||
#if F_CPU == 240000000L
|
||||
NOP_COUNT(T1L_CYCLE);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
// T0H 0.4 us = 48 cycles
|
||||
sio_hw->gpio_set = pinMask;
|
||||
NOP_COUNT(T0H_CYCLE);
|
||||
#if F_CPU == 240000000L
|
||||
NOP_COUNT(T0H_CYCLE);
|
||||
#endif
|
||||
|
||||
// T0L 0.85 us = 102 - 10 (ifelse) - 5 (overhead) = 87 nop
|
||||
sio_hw->gpio_clr = pinMask;
|
||||
NOP_COUNT(T0L_CYCLE);
|
||||
#if F_CPU == 240000000L
|
||||
NOP_COUNT(T0L_CYCLE);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (bitMask >>= 1) {
|
||||
// not full byte, shift to next bit
|
||||
NOP_COUNT(LOOP_OVERHEAD_CYCLE);
|
||||
} else {
|
||||
// probably take 10 nops
|
||||
// if a full byte is sent, next to another byte
|
||||
if (ptr >= end) {
|
||||
break;
|
||||
}
|
||||
p = *ptr++;
|
||||
bitMask = 0x80;
|
||||
}
|
||||
#if F_CPU == 240000000L
|
||||
NOP_COUNT(LOOP_OVERHEAD_CYCLE);
|
||||
#endif
|
||||
}
|
||||
|
||||
restore_interrupts(isr_context);
|
||||
|
||||
end_us = micros();
|
||||
}
|
||||
|
||||
void Adafruit_TestBed_Brains::lcd_write(uint8_t linenum, char linebuf[17]) {
|
||||
// wait for semaphore to release
|
||||
while (LCD_semaphore)
|
||||
yield();
|
||||
LCD_semaphore = true;
|
||||
// fill the rest with spaces
|
||||
memset(linebuf + strlen(linebuf), ' ', 16 - strlen(linebuf));
|
||||
linebuf[16] = 0;
|
||||
lcd.setCursor(0, linenum);
|
||||
lcd.write(linebuf);
|
||||
|
||||
Serial.print("LCD: ");
|
||||
Serial.println(linebuf);
|
||||
Serial.flush();
|
||||
|
||||
_lcd_line = 1 - linenum;
|
||||
LCD_semaphore = false;
|
||||
}
|
||||
|
||||
#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[],
|
||||
...) {
|
||||
_LCD_PRINTF(linenum, format);
|
||||
}
|
||||
|
||||
void Adafruit_TestBed_Brains::LCD_printf(const char format[], ...) {
|
||||
_LCD_PRINTF(_lcd_line, format);
|
||||
}
|
||||
|
||||
void Adafruit_TestBed_Brains::LCD_printf_error(const char format[], ...) {
|
||||
setColor(0xFF0000);
|
||||
_LCD_PRINTF(_lcd_line, format);
|
||||
}
|
||||
|
||||
void Adafruit_TestBed_Brains::LCD_info(const char *msg1, const char *msg2) {
|
||||
setColor(0xFFFFFF);
|
||||
LCD_printf(0, msg1);
|
||||
|
||||
if (msg2) {
|
||||
LCD_printf(1, msg2);
|
||||
}
|
||||
}
|
||||
|
||||
void Adafruit_TestBed_Brains::LCD_error(const char *errmsg1,
|
||||
const char *errmsg2) {
|
||||
setColor(0xFF0000);
|
||||
if (errmsg1) {
|
||||
LCD_printf(0, errmsg1);
|
||||
}
|
||||
if (errmsg2) {
|
||||
LCD_printf(1, errmsg2);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USB Host
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void Adafruit_TestBed_Brains::usbh_setVBus(bool en) {
|
||||
digitalWrite(_vbus_en_pin, en ? HIGH : LOW);
|
||||
}
|
||||
|
||||
bool Adafruit_TestBed_Brains::usbh_begin(void) {
|
||||
// Check for CPU frequency, must be multiple of 120Mhz for bit-banging USB
|
||||
uint32_t cpu_hz = clock_get_hz(clk_sys);
|
||||
if (cpu_hz % 12000000UL) {
|
||||
while (!Serial) {
|
||||
delay(10); // wait for native usb
|
||||
}
|
||||
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be "
|
||||
"multiple of 12 Mhz\r\n",
|
||||
cpu_hz);
|
||||
Serial.println("Change your CPU Clock to 12*n Mhz in Menu->CPU Speed");
|
||||
while (1) {
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
// enable vbus
|
||||
pinMode(_vbus_en_pin, OUTPUT);
|
||||
usbh_setVBus(true);
|
||||
|
||||
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
|
||||
pio_cfg.pin_dp = (uint8_t)_usbh_dp_pin;
|
||||
|
||||
USBHost.configure_pio_usb(USBHOST_RHPORT, &pio_cfg);
|
||||
if (!USBHost.begin(USBHOST_RHPORT)) {
|
||||
Serial.println("usb host begin failed");
|
||||
usbh_setVBus(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Adafruit_TestBed_Brains::usbh_inited(void) { return tuh_inited(); }
|
||||
|
||||
bool Adafruit_TestBed_Brains::usbh_mountFS(uint8_t dev_addr) {
|
||||
// Initialize block device with MSC device address (only support LUN 0)
|
||||
USBH_BlockDev.begin(dev_addr);
|
||||
USBH_BlockDev.setActiveLUN(0);
|
||||
|
||||
return USBH_FS.begin(&USBH_BlockDev);
|
||||
}
|
||||
|
||||
bool Adafruit_TestBed_Brains::usbh_umountFS(uint8_t dev_addr) {
|
||||
(void)dev_addr;
|
||||
|
||||
// unmount file system
|
||||
USBH_FS.end();
|
||||
|
||||
// end block device
|
||||
USBH_BlockDev.end();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
129
src/Adafruit_TestBed_Brains.h
Normal file
129
src/Adafruit_TestBed_Brains.h
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
#ifndef ADAFRUIT_TESTBED_BRAINS_H
|
||||
#define ADAFRUIT_TESTBED_BRAINS_H
|
||||
|
||||
#ifdef ARDUINO_ARCH_RP2040
|
||||
|
||||
#include "SdFat_Adafruit_Fork.h"
|
||||
|
||||
#include "Adafruit_TestBed.h"
|
||||
#include <LiquidCrystal.h>
|
||||
|
||||
#include "Adafruit_DAP.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief A helper class for making RP2040 "Tester Brains"
|
||||
*/
|
||||
/**************************************************************************/
|
||||
class Adafruit_TestBed_Brains : public Adafruit_TestBed {
|
||||
public:
|
||||
Adafruit_TestBed_Brains(void);
|
||||
void begin(void);
|
||||
bool inited(void);
|
||||
|
||||
//------------- LCD -------------//
|
||||
|
||||
// printf on specific line
|
||||
void LCD_printf(uint8_t linenum, const char format[], ...);
|
||||
|
||||
// printf on next line
|
||||
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_info(const char *msg1, const char *msg2);
|
||||
|
||||
void setColor(uint32_t color);
|
||||
|
||||
// SD
|
||||
bool SD_detected(void);
|
||||
bool SD_begin(uint32_t max_clock = SD_SCK_MHZ(16));
|
||||
|
||||
// USB Host
|
||||
void usbh_setVBus(bool en);
|
||||
bool usbh_begin(void);
|
||||
bool usbh_inited(void);
|
||||
bool usbh_mountFS(uint8_t dev_addr);
|
||||
bool usbh_umountFS(uint8_t dev_addr);
|
||||
|
||||
//--------------------------------------------------------------------+1
|
||||
// RP2 (rp2040 and rp2350) Target
|
||||
//--------------------------------------------------------------------+
|
||||
// reset rp2 target to Boot ROM
|
||||
void rp2_targetResetBootRom(int bootsel_pin = 28, uint32_t reset_ms = 20);
|
||||
|
||||
// program rp2 target by copying UF2 file stored in flash
|
||||
size_t rp2_programUF2(const uint8_t *buffer, size_t bufsize);
|
||||
|
||||
// program rp2 target by copying UF2 file from SDCard
|
||||
// return number of copied bytes (typically uf2 file size)
|
||||
size_t rp2_programUF2(const char *fpath);
|
||||
|
||||
// backward compatibility
|
||||
void rp2040_targetResetBootRom(int bootsel_pin = 28, uint32_t reset_ms = 20) {
|
||||
rp2_targetResetBootRom(bootsel_pin, reset_ms);
|
||||
}
|
||||
|
||||
size_t rp2040_programUF2(const char *fpath) { return rp2_programUF2(fpath); }
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// DAP (samd21/51, nrf5x, stm32f4 etc..) Target
|
||||
//--------------------------------------------------------------------+
|
||||
bool dap_begin(Adafruit_DAP *dp);
|
||||
bool dap_connect(uint32_t swj_clock = 50);
|
||||
void dap_disconnect(void);
|
||||
|
||||
bool dap_unprotectBoot(void);
|
||||
bool dap_protectBoot(void);
|
||||
|
||||
bool dap_eraseChip(void);
|
||||
|
||||
// program dap target with file from SDCard
|
||||
// return number of programmed bytes
|
||||
// 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
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
LiquidCrystal lcd = LiquidCrystal(7, 8, 9, 10, 11, 12);
|
||||
SdFat SD;
|
||||
SdSpiConfig SD_CONFIG = SdSpiConfig(17, SHARED_SPI, SD_SCK_MHZ(16));
|
||||
|
||||
// USB host
|
||||
Adafruit_USBH_Host USBHost;
|
||||
|
||||
// Host MSC
|
||||
FatVolume USBH_FS;
|
||||
Adafruit_USBH_MSC_BlockDevice USBH_BlockDev;
|
||||
|
||||
// Dap
|
||||
Adafruit_DAP *dap;
|
||||
|
||||
private:
|
||||
bool _inited;
|
||||
uint8_t _lcd_line;
|
||||
|
||||
int _sd_detect_pin;
|
||||
int _sd_cs_pin;
|
||||
int _vbus_en_pin;
|
||||
int _usbh_dp_pin;
|
||||
|
||||
int _target_swdio;
|
||||
int _target_swdclk;
|
||||
|
||||
void lcd_write(uint8_t linenum, char buf[17]);
|
||||
};
|
||||
|
||||
extern Adafruit_TestBed_Brains Brain;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
882
src/ESP32BootROM.cpp
Normal file
882
src/ESP32BootROM.cpp
Normal file
|
|
@ -0,0 +1,882 @@
|
|||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
// https://docs.espressif.com/projects/esptool/en/latest/esp32/advanced-topics/serial-protocol.html
|
||||
|
||||
#if defined(ARDUINO_ARCH_RP2040) || defined(__SAMD51__) || \
|
||||
defined(TARGET_RP2040) || defined(ARDUINO_ARCH_ESP32) || \
|
||||
(defined(ARDUINO_ARCH_SAMD) && defined(ARM_MATH_CM0PLUS))
|
||||
|
||||
#include "ESP32BootROM.h"
|
||||
#include "stub_esp.h"
|
||||
|
||||
#ifdef USE_TINYUSB
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
#endif
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
#if DEBUG
|
||||
#define DBG_PRINTF(...) Serial.printf(__VA_ARGS__)
|
||||
|
||||
#define DBG_PRINT_BUF(_buf, _len) \
|
||||
do { \
|
||||
for (int _i = 0; _i < _len; _i++) \
|
||||
Serial.printf("%02x ", (_buf)[_i]); \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
#define DBG_PRINTF(...)
|
||||
#define DBG_PRINT_BUF(_buf, _len)
|
||||
#endif
|
||||
|
||||
#define VERIFY(_cond) \
|
||||
do { \
|
||||
if (!(_cond)) { \
|
||||
Serial.printf("Failed at line %u", __LINE__); \
|
||||
Serial.flush(); \
|
||||
while (1) { \
|
||||
delay(10); \
|
||||
} \
|
||||
return false; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
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 commands supported by ESP32 and later chips ROM bootloader (or -8266
|
||||
// with 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 without stub
|
||||
FLASH_WRITE_SIZE_NOSTUB = 0x400,
|
||||
|
||||
// flassh write with stub
|
||||
FLASH_WRITE_SIZE_STUB = 0x4000,
|
||||
|
||||
// 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,
|
||||
|
||||
EFUSE_RD_REG_BASE = 0x3FF5A000,
|
||||
|
||||
// Device PIDs
|
||||
USB_JTAG_SERIAL_PID = 0x1001
|
||||
};
|
||||
|
||||
static inline uint32_t div_ceil(uint32_t v, uint32_t d) {
|
||||
return (v + d - 1) / d;
|
||||
}
|
||||
|
||||
void ESP32BootROMClass::init() {
|
||||
_gpio0Pin = -1;
|
||||
_resetnPin = -1;
|
||||
|
||||
_supports_encrypted_flash = true;
|
||||
_stub_running = false;
|
||||
_rom_8266_running = false;
|
||||
_chip_detect = 0;
|
||||
_flashSequenceNumber = 0;
|
||||
}
|
||||
|
||||
ESP32BootROMClass::ESP32BootROMClass(HardwareSerial &serial, int gpio0Pin,
|
||||
int resetnPin)
|
||||
: _serial(&serial) {
|
||||
init();
|
||||
|
||||
_gpio0Pin = gpio0Pin;
|
||||
_resetnPin = resetnPin;
|
||||
}
|
||||
|
||||
void ESP32BootROMClass::resetBootloader(void) {
|
||||
if (_gpio0Pin >= 0 && _resetnPin >= 0) {
|
||||
// IO0 and Resetn pins are available
|
||||
pinMode(_gpio0Pin, OUTPUT);
|
||||
pinMode(_resetnPin, OUTPUT);
|
||||
|
||||
// Reset Low (ESP32 in reset)
|
||||
digitalWrite(_gpio0Pin, LOW);
|
||||
digitalWrite(_resetnPin, LOW);
|
||||
delay(100);
|
||||
|
||||
// IO0 Low, Reset HIGH (ESP32 out of reset)
|
||||
digitalWrite(_resetnPin, HIGH);
|
||||
|
||||
// Wait for serial, needed if using with SerialHost
|
||||
while (!_serial) {
|
||||
delay(10);
|
||||
}
|
||||
delay(100); // additional delay for SerialHost connected
|
||||
|
||||
// IO0 high: done
|
||||
digitalWrite(_gpio0Pin, HIGH);
|
||||
}
|
||||
#if defined(USE_TINYUSB) && defined(ARDUINO_ARCH_RP2040)
|
||||
else {
|
||||
// Serial Host using setDtrRts()
|
||||
// - DTR -> IO0
|
||||
// - RTS -> Reset
|
||||
// DTR & RTS are active low signals, ie True = pin @ 0V, False = pin @ VCC.
|
||||
Adafruit_USBH_CDC *serial_host = (Adafruit_USBH_CDC *)_serial;
|
||||
|
||||
// Wait for serial host
|
||||
while (!serial_host) {
|
||||
delay(10);
|
||||
}
|
||||
|
||||
// IO0 High, Reset Low (ESP32 in reset)
|
||||
serial_host->setDtrRts(false, true);
|
||||
delay(100);
|
||||
|
||||
// IO0 Low, Reset High (ESP32 out of reset)
|
||||
serial_host->setDtrRts(true, false);
|
||||
delay(100);
|
||||
|
||||
// IO0 high, Reset High: done
|
||||
serial_host->setDtrRts(false, false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t ESP32BootROMClass::begin(unsigned long baudrate) {
|
||||
_serial->begin(ESP_ROM_BAUD);
|
||||
|
||||
resetBootloader();
|
||||
|
||||
bool synced = false;
|
||||
for (int retries = 0; !synced && (retries < 5); retries++) {
|
||||
Serial.println("Trying to sync");
|
||||
synced = sync();
|
||||
if (synced) {
|
||||
break;
|
||||
}
|
||||
delay(10);
|
||||
}
|
||||
if (!synced) {
|
||||
return 0;
|
||||
}
|
||||
Serial.println("Synced!");
|
||||
// Serial.printf("After %u ms\r\n", millis());
|
||||
|
||||
//------------- Chip Detect -------------//
|
||||
_chip_detect = read_chip_detect();
|
||||
if (!_chip_detect) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Serial.printf("Chip Detect: 0x%08lX\r\n", _chip_detect);
|
||||
|
||||
const esp32_stub_loader_t *stub = NULL;
|
||||
for (uint32_t i = 0; i < ESP_STUB_COUNT; i++) {
|
||||
if (stub_esp_arr[i]->chip_detect == _chip_detect) {
|
||||
stub = stub_esp_arr[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (stub) {
|
||||
Serial.printf("Found %s\r\n", stub->chip_name);
|
||||
VERIFY(uploadStub(stub));
|
||||
VERIFY(syncStub(3000));
|
||||
} else {
|
||||
Serial.println("Found unknown ESP chip");
|
||||
}
|
||||
|
||||
if (baudrate != ESP_ROM_BAUD) {
|
||||
if (!changeBaudrate(baudrate)) {
|
||||
Serial.println("Failed to change baudrate");
|
||||
return 0;
|
||||
}
|
||||
// _serial->end();
|
||||
delay(100);
|
||||
Serial.printf("Updating local Serial baudrate to %lu\r\n", baudrate);
|
||||
_serial->begin(baudrate);
|
||||
}
|
||||
|
||||
// use default spi connection if no stub
|
||||
if (!stub) {
|
||||
while (!spiAttach()) {
|
||||
Serial.println("Failed to attach SPI");
|
||||
delay(100);
|
||||
}
|
||||
}
|
||||
|
||||
return _chip_detect;
|
||||
}
|
||||
|
||||
void ESP32BootROMClass::end() {
|
||||
if (_gpio0Pin >= 0 && _resetnPin >= 0) {
|
||||
digitalWrite(_gpio0Pin, HIGH);
|
||||
digitalWrite(_resetnPin, HIGH);
|
||||
} else {
|
||||
// #ifdef USE_TINYUSB
|
||||
// Maybe we should reset using RTS
|
||||
// Adafruit_USBH_CDC* serial_host = (Adafruit_USBH_CDC*)_serial;
|
||||
// serial_host->setDtrRts(false, true);
|
||||
// delay(20);
|
||||
// serial_host->setDtrRts(false, false);
|
||||
// #endif
|
||||
}
|
||||
//_serial->end();
|
||||
}
|
||||
|
||||
bool 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(ESP_SYNC, 100);
|
||||
}
|
||||
|
||||
return (results[0] == 0);
|
||||
}
|
||||
|
||||
bool ESP32BootROMClass::changeBaudrate(uint32_t baudrate) {
|
||||
// Two 32-bit words:
|
||||
// - new baud rate, and
|
||||
// - 0 if we are talking to the ROM loader or the current/old baud rate if we
|
||||
// are talking to the stub loader.
|
||||
uint32_t data[2] = {baudrate, 0};
|
||||
|
||||
if (_stub_running) {
|
||||
data[1] = ESP_ROM_BAUD; // we only changed from 115200 to higher baud
|
||||
}
|
||||
|
||||
DBG_PRINTF("Changing baudrate to %u\r\n", baudrate);
|
||||
|
||||
return sendCommandGetResponse(ESP_CHANGE_BAUDRATE, (uint8_t *)data,
|
||||
sizeof(data), NULL, 0, 3000);
|
||||
}
|
||||
|
||||
bool ESP32BootROMClass::spiAttach() {
|
||||
const uint8_t data[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
return sendCommandGetResponse(ESP_SPI_ATTACH, data, sizeof(data), NULL, 0,
|
||||
3000);
|
||||
}
|
||||
|
||||
bool ESP32BootROMClass::isRunningStub(void) { return _stub_running; }
|
||||
|
||||
uint32_t ESP32BootROMClass::getFlashWriteSize(void) {
|
||||
return _stub_running ? FLASH_WRITE_SIZE_STUB : FLASH_WRITE_SIZE_NOSTUB;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Uncompressed Flashing
|
||||
//--------------------------------------------------------------------+
|
||||
bool ESP32BootROMClass::beginFlash(uint32_t offset, uint32_t size,
|
||||
uint32_t chunkSize) {
|
||||
|
||||
const uint32_t data[5] = {size, div_ceil(size, chunkSize), chunkSize, offset,
|
||||
0};
|
||||
uint16_t const len = (_supports_encrypted_flash && !_stub_running) ? 20 : 16;
|
||||
|
||||
_flashSequenceNumber = 0;
|
||||
return sendCommandGetResponse(ESP_FLASH_BEGIN, data, len, NULL, 0, 120000);
|
||||
}
|
||||
|
||||
bool ESP32BootROMClass::dataFlash(const void *data, uint32_t length) {
|
||||
uint32_t header[4];
|
||||
header[0] = length;
|
||||
header[1] = _flashSequenceNumber++;
|
||||
header[2] = 0;
|
||||
header[3] = 0;
|
||||
|
||||
return sendCommandGetResponse(ESP_FLASH_DATA, header, sizeof(header), data,
|
||||
length, 3000);
|
||||
}
|
||||
|
||||
bool ESP32BootROMClass::endFlash(uint32_t reboot) {
|
||||
const uint32_t data[1] = {reboot};
|
||||
return sendCommandGetResponse(ESP_FLASH_END, data, sizeof(data), NULL, 0,
|
||||
3000);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Compressed (Deflated) Flashing
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
bool ESP32BootROMClass::beginFlashDefl(uint32_t offset, uint32_t size,
|
||||
uint32_t zip_size) {
|
||||
const uint32_t block_size = getFlashWriteSize();
|
||||
uint32_t data[5] = {0, div_ceil(zip_size, block_size), block_size, offset, 0};
|
||||
|
||||
if (_stub_running) {
|
||||
// stub expects number of bytes here, manages erasing internally
|
||||
data[0] = size;
|
||||
} else {
|
||||
// ROM expects rounded up to erase block size
|
||||
data[0] = div_ceil(size, block_size) * block_size;
|
||||
}
|
||||
|
||||
uint16_t const len = (_supports_encrypted_flash && !_stub_running) ? 20 : 16;
|
||||
|
||||
_flashSequenceNumber = 0;
|
||||
return sendCommandGetResponse(ESP_FLASH_DEFL_BEGIN, data, len, NULL, 0, 3000);
|
||||
}
|
||||
|
||||
bool ESP32BootROMClass::dataFlashDefl(const void *data, uint32_t len) {
|
||||
uint32_t header[4];
|
||||
header[0] = len;
|
||||
header[1] = _flashSequenceNumber++;
|
||||
header[2] = 0;
|
||||
header[3] = 0;
|
||||
|
||||
return sendCommandGetResponse(ESP_FLASH_DEFL_DATA, header, sizeof(header),
|
||||
data, len, 3000);
|
||||
}
|
||||
|
||||
bool ESP32BootROMClass::endFlashDefl(uint32_t reboot) {
|
||||
const uint32_t data[1] = {reboot};
|
||||
|
||||
return sendCommandGetResponse(ESP_FLASH_DEFL_END, data, sizeof(data), NULL, 0,
|
||||
3000);
|
||||
}
|
||||
|
||||
bool ESP32BootROMClass::md5Flash(uint32_t offset, uint32_t size,
|
||||
uint8_t *result) {
|
||||
const uint32_t data[4] = {offset, size, 0, 0};
|
||||
uint8_t resp[32];
|
||||
|
||||
VERIFY(sendCommandGetResponse(ESP_SPI_FLASH_MD5, data, sizeof(data), NULL, 0,
|
||||
6000, resp));
|
||||
|
||||
// Note that the ESP32 ROM loader returns the md5sum as 32 hex encoded ASCII
|
||||
// bytes, whereas the stub loader returns the md5sum as 16 raw data bytes of
|
||||
// MD5 followed by 2 status bytes.
|
||||
if (_stub_running) {
|
||||
memcpy(result, resp, 16);
|
||||
} else {
|
||||
char temp[3] = {0, 0, 0};
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
temp[0] = resp[i * 2];
|
||||
temp[1] = resp[i * 2 + 1];
|
||||
|
||||
result[i] = strtoul(temp, NULL, 16);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Read REG
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
bool ESP32BootROMClass::read_reg(uint32_t addr, uint32_t *val,
|
||||
uint32_t timeout_ms) {
|
||||
return sendCommandGetResponse(ESP_READ_REG, &addr, 4, NULL, 0, timeout_ms,
|
||||
val);
|
||||
}
|
||||
|
||||
uint32_t ESP32BootROMClass::read_chip_detect(void) {
|
||||
uint32_t chip_detect;
|
||||
if (!read_reg(CHIP_DETECT_MAGIC_REG_ADDR, &chip_detect)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return chip_detect;
|
||||
}
|
||||
|
||||
bool ESP32BootROMClass::read_MAC(uint8_t mac[6]) {
|
||||
union {
|
||||
uint8_t bytes[8];
|
||||
uint32_t words[2];
|
||||
} tmp_mac;
|
||||
|
||||
if (!read_reg(EFUSE_RD_REG_BASE + 4, &tmp_mac.words[1])) {
|
||||
return false;
|
||||
}
|
||||
if (!read_reg(EFUSE_RD_REG_BASE + 8, &tmp_mac.words[0])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// swap endian
|
||||
tmp_mac.words[0] = __builtin_bswap32(tmp_mac.words[0]);
|
||||
tmp_mac.words[1] = __builtin_bswap32(tmp_mac.words[1]);
|
||||
|
||||
// [0] is highest byte
|
||||
memcpy(mac, tmp_mac.bytes + 2, 6);
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Stub
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
bool ESP32BootROMClass::beginMem(uint32_t offset, uint32_t size,
|
||||
uint32_t chunkSize) {
|
||||
const uint32_t data[] = {size, div_ceil(size, chunkSize), chunkSize, offset};
|
||||
uint16_t const len = 16;
|
||||
|
||||
_flashSequenceNumber = 0;
|
||||
return sendCommandGetResponse(ESP_MEM_BEGIN, data, len, NULL, 0, 3000);
|
||||
}
|
||||
|
||||
bool ESP32BootROMClass::dataMem(const void *data, uint32_t length) {
|
||||
uint32_t header[4];
|
||||
header[0] = length;
|
||||
header[1] = _flashSequenceNumber++;
|
||||
header[2] = 0;
|
||||
header[3] = 0;
|
||||
|
||||
return sendCommandGetResponse(ESP_MEM_DATA, header, sizeof(header), data,
|
||||
length, 3000);
|
||||
}
|
||||
|
||||
bool ESP32BootROMClass::endMem(uint32_t entry) {
|
||||
uint32_t data[2];
|
||||
data[0] = (entry == 0);
|
||||
data[1] = entry;
|
||||
|
||||
return sendCommandGetResponse(ESP_MEM_END, data, sizeof(data), NULL, 0, 3000);
|
||||
}
|
||||
|
||||
bool ESP32BootROMClass::syncStub(uint32_t timeout_ms) {
|
||||
// read OHAI packet
|
||||
uint8_t const ohai[4] = {0x4f, 0x48, 0x41, 0x49};
|
||||
uint8_t buf[4];
|
||||
|
||||
Serial.println("Syncing stub...");
|
||||
|
||||
if (!readSLIP(timeout_ms)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (4 != readBytes(buf, 4, timeout_ms)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!readSLIP(timeout_ms)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (0 == memcmp(ohai, buf, 4)) {
|
||||
Serial.println("Stub running...\r\n");
|
||||
return true;
|
||||
} else {
|
||||
Serial.println("Failed to start stub. Unexpected response");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ESP32BootROMClass::uploadStub(const esp32_stub_loader_t *stub) {
|
||||
Serial.println("Uploading stub...");
|
||||
|
||||
uint32_t remain;
|
||||
const uint8_t *buf;
|
||||
|
||||
// upload text
|
||||
Serial.println("Uploading stub text...");
|
||||
VERIFY(beginMem(stub->text_start, stub->text_length, ESP_RAM_BLOCK));
|
||||
|
||||
remain = stub->text_length;
|
||||
buf = stub->text;
|
||||
while (remain) {
|
||||
uint32_t const len =
|
||||
(remain > ESP_RAM_BLOCK) ? (uint32_t)ESP_RAM_BLOCK : remain;
|
||||
dataMem(buf, len);
|
||||
|
||||
buf += len;
|
||||
remain -= len;
|
||||
}
|
||||
|
||||
// upload data
|
||||
Serial.println("Uploading stub data...");
|
||||
VERIFY(beginMem(stub->data_start, stub->data_length, ESP_RAM_BLOCK));
|
||||
|
||||
remain = stub->data_length;
|
||||
buf = stub->data;
|
||||
while (remain) {
|
||||
uint32_t const len =
|
||||
(remain > ESP_RAM_BLOCK) ? (uint32_t)ESP_RAM_BLOCK : remain;
|
||||
dataMem(buf, len);
|
||||
|
||||
buf += len;
|
||||
remain -= len;
|
||||
}
|
||||
|
||||
// run stub
|
||||
Serial.println("Running stub...");
|
||||
VERIFY(endMem(stub->entry));
|
||||
|
||||
_stub_running = true;
|
||||
_rom_8266_running = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Command & Response
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
bool ESP32BootROMClass::sendCommandGetResponse(uint8_t opcode, const void *data,
|
||||
uint16_t length,
|
||||
const void *data2, uint16_t len2,
|
||||
uint32_t timeout_ms,
|
||||
void *body) {
|
||||
for (uint8_t retry = 0; retry < 3; retry++) {
|
||||
command(opcode, data, length, data2, len2);
|
||||
if (response(opcode, timeout_ms, body) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Serial.printf("Command 0x%02x failed, retrying %u/3...\r\n", opcode,
|
||||
retry + 1);
|
||||
delay(5);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ESP32BootROMClass::command(uint8_t opcode, const void *data, uint16_t len,
|
||||
const void *data2, uint16_t len2) {
|
||||
uint32_t checksum = 0;
|
||||
|
||||
// ESP8266 ROM bootloader is slow to ready receiving commands. Need
|
||||
// to wait a bit before sending new command
|
||||
if (_rom_8266_running || (_chip_detect == CHIP_DETECT_MAGIC_ESP8266)) {
|
||||
delay(5);
|
||||
}
|
||||
|
||||
// for FLASH_DATA and MEM_DATA: data is header, data2 is actual payloada
|
||||
if (opcode == ESP_FLASH_DATA || opcode == ESP_MEM_DATA ||
|
||||
opcode == ESP_FLASH_DEFL_DATA) {
|
||||
checksum = ESP_CHECKSUM_MAGIC; // seed
|
||||
|
||||
if (data2) {
|
||||
for (uint16_t i = 0; i < len2; i++) {
|
||||
checksum ^= ((const uint8_t *)data2)[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t const total_len = len + len2;
|
||||
|
||||
DBG_PRINTF("=> c0 00 %02x %04x ", opcode, total_len);
|
||||
|
||||
uint8_t const header[3] = {0xc0, 0x00, opcode};
|
||||
|
||||
_serial->write(header, 3);
|
||||
_serial->write((uint8_t *)&total_len, 2);
|
||||
|
||||
writeEscapedBytes((uint8_t *)&checksum, sizeof(checksum));
|
||||
writeEscapedBytes((uint8_t *)data, len);
|
||||
if (data2 && len2) {
|
||||
writeEscapedBytes((uint8_t const *)data2, len2);
|
||||
}
|
||||
|
||||
_serial->write(0xc0);
|
||||
_serial->flush();
|
||||
|
||||
DBG_PRINTF("c0\r\n");
|
||||
}
|
||||
|
||||
// return response status if success, -1 if failed
|
||||
int ESP32BootROMClass::response(uint8_t opcode, uint32_t timeout_ms,
|
||||
void *body) {
|
||||
// Response Packet is composed of
|
||||
// - 1B: slip start
|
||||
// - 8B: fixed response ( struct below )
|
||||
// - nB: variable response payload ( if any )
|
||||
// - 2B: status, error
|
||||
// - 2B: reserved // ROM only, not stub
|
||||
// - 1B: slip end
|
||||
struct __packed_aligned {
|
||||
uint8_t dir; // 0x01 for response
|
||||
uint8_t opcode;
|
||||
uint16_t length; // at least 2 (or 4) for status bytes
|
||||
uint32_t reg_value; // READ_REG response. zero otherwise
|
||||
} fixed_resp;
|
||||
|
||||
uint8_t status[4] = {0};
|
||||
|
||||
uint32_t end_ms = millis() + timeout_ms;
|
||||
|
||||
if (!readSLIP(timeout_ms)) {
|
||||
Serial.printf("line %d: timeout reading SLIP\r\n", __LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// read fixed response first
|
||||
if (8 != readBytes(&fixed_resp, 8, end_ms - millis())) {
|
||||
Serial.printf("line %d\r\n", __LINE__);
|
||||
return -1; // probably timeout
|
||||
}
|
||||
|
||||
// Status byte are 2 or 4 bytes as follows:
|
||||
// - ESP32 Boot ROM: 2 bytes
|
||||
// - ESP8266 ROM and Stub (all chips): 4 bytes
|
||||
uint8_t status_len = ((_stub_running || _rom_8266_running) ? 2 : 4);
|
||||
|
||||
// ESP8266 ROM only has 2 bytes status which will be larger than length
|
||||
// response in sync() message this is condition is an indicator that ESP8266
|
||||
// ROM is used
|
||||
if ((opcode == ESP_SYNC) && (fixed_resp.length < status_len)) {
|
||||
_rom_8266_running = true;
|
||||
status_len = 2;
|
||||
}
|
||||
|
||||
// read variable payload if any
|
||||
// status len can be miscalculated for ESP8266 ROM (2 bytes instead of 4)
|
||||
uint16_t const payload_len = fixed_resp.length - status_len;
|
||||
uint8_t data[payload_len];
|
||||
|
||||
if (payload_len) {
|
||||
uint16_t rd_len = readBytes(data, payload_len, end_ms - millis());
|
||||
if (payload_len != rd_len) {
|
||||
Serial.printf("Fixed Response: dir = %02x, opcode = %02x, length = %04x, "
|
||||
"reg_value = %08lx\r\n",
|
||||
fixed_resp.dir, fixed_resp.opcode, fixed_resp.length,
|
||||
fixed_resp.reg_value);
|
||||
Serial.printf(
|
||||
"line %d: payload_len = %u, rd_len = %u, status_len = %u\r\n",
|
||||
__LINE__, payload_len, rd_len, status_len);
|
||||
|
||||
if (rd_len) {
|
||||
DBG_PRINT_BUF(data, rd_len);
|
||||
}
|
||||
return -1; // probably timeout
|
||||
}
|
||||
}
|
||||
|
||||
if (body) {
|
||||
if (opcode == ESP_READ_REG) {
|
||||
memcpy(body, &fixed_resp.reg_value, 4);
|
||||
} else {
|
||||
memcpy(body, data, payload_len);
|
||||
}
|
||||
}
|
||||
|
||||
// read status
|
||||
if (status_len != readBytes(status, status_len, end_ms - millis())) {
|
||||
Serial.printf("line %d\r\n", __LINE__);
|
||||
return -1; // probably timeout
|
||||
}
|
||||
|
||||
if (!readSLIP(end_ms - millis())) {
|
||||
Serial.printf("line %d\r\n", __LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
Serial.printf("<= c0 %02x %02x %04x %08x ", fixed_resp.dir, fixed_resp.opcode,
|
||||
fixed_resp.length, fixed_resp.reg_value);
|
||||
if (payload_len) {
|
||||
DBG_PRINT_BUF(data, payload_len);
|
||||
}
|
||||
DBG_PRINT_BUF(status, status_len);
|
||||
Serial.println("c0");
|
||||
#endif
|
||||
|
||||
// check direction, opcode and status
|
||||
if (fixed_resp.dir == 0x01 && fixed_resp.opcode == opcode &&
|
||||
status[0] == 0x00 && status[1] == 0x00) {
|
||||
return 0; // status[0];
|
||||
}
|
||||
|
||||
const char *mess_arr[0x0b + 1] = {
|
||||
NULL, NULL, NULL, NULL, NULL, "Received message is invalid",
|
||||
"Failed to act on received message", "Invalid CRC in message",
|
||||
"Flash write error", // after writing a block of data to flash, the ROM
|
||||
// loader reads the value back and the 8-bit CRC is
|
||||
// compared to the data read from flash. If they
|
||||
// don’t match, this error is returned.
|
||||
"Flash read error", "Flash read length error", "Deflate error"};
|
||||
|
||||
const char *mess =
|
||||
(status[1] <= 0x0b) ? mess_arr[status[1]] : "Unknown Error";
|
||||
Serial.printf("response failed: status = %02x %02x, %s\r\n", status[0],
|
||||
status[1], mess);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// read until we found SLIP (0xC0) byte
|
||||
bool ESP32BootROMClass::readSLIP(uint32_t timeout_ms) {
|
||||
uint32_t const end_ms = millis() + timeout_ms;
|
||||
while (millis() < end_ms) {
|
||||
if (_serial->available()) {
|
||||
uint8_t ch = (uint8_t)_serial->read();
|
||||
if (ch == 0xc0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read response bytes from ESP32, return number of received bytes
|
||||
uint16_t ESP32BootROMClass::readBytes(void *buf, uint16_t length,
|
||||
uint32_t timeout_ms) {
|
||||
uint8_t *buf8 = (uint8_t *)buf;
|
||||
uint16_t count = 0;
|
||||
uint32_t end_ms = millis() + timeout_ms;
|
||||
|
||||
while ((count < length) && (millis() < end_ms)) {
|
||||
if (_serial->available()) {
|
||||
uint8_t ch = (uint8_t)_serial->read();
|
||||
|
||||
// escape
|
||||
if (ch == 0xdb) {
|
||||
while (!_serial->available() && (millis() < end_ms)) {
|
||||
yield();
|
||||
}
|
||||
uint8_t ch2 = (uint8_t)_serial->read();
|
||||
|
||||
if (ch2 == 0xdd) {
|
||||
ch = 0xdb;
|
||||
} else if (ch2 == 0xdc) {
|
||||
ch = 0xc0;
|
||||
} else {
|
||||
// should not reach here, must be an error or uart noise
|
||||
Serial.printf("err %02x ", ch2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
buf8[count++] = ch;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void ESP32BootROMClass::writeEscapedBytes(const uint8_t *data,
|
||||
uint16_t length) {
|
||||
// skip flashing data since it is a lot to print
|
||||
bool const print_payload = (length >= 200) ? false : true;
|
||||
|
||||
uint16_t last_wr = 0;
|
||||
for (uint16_t i = 0; i < length; i++) {
|
||||
uint8_t b = data[i];
|
||||
|
||||
if (b == 0xdb || b == 0xc0) {
|
||||
// write up to i-1
|
||||
if (last_wr < i) {
|
||||
_serial->write(data + last_wr, i - last_wr);
|
||||
|
||||
if (DEBUG && print_payload) {
|
||||
DBG_PRINT_BUF(data + last_wr, i - last_wr);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t esc[2] = {0xdb, 0x00};
|
||||
esc[1] = (b == 0xdb) ? 0xdd : 0xdc;
|
||||
|
||||
_serial->write(esc, 2);
|
||||
|
||||
// +1 since we already write current index with escape
|
||||
last_wr = i + 1;
|
||||
|
||||
if (DEBUG && print_payload) {
|
||||
DBG_PRINT_BUF(esc, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// last chunk without escape
|
||||
if (last_wr < length) {
|
||||
_serial->write(data + last_wr, length - last_wr);
|
||||
if (DEBUG && print_payload) {
|
||||
DBG_PRINT_BUF(data + last_wr, length - last_wr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
120
src/ESP32BootROM.h
Normal file
120
src/ESP32BootROM.h
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
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
|
||||
*/
|
||||
#ifndef ESP32_BOOTROM_H
|
||||
#define ESP32_BOOTROM_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#define ESP32_DEFAULT_TIMEOUT 3000
|
||||
|
||||
enum {
|
||||
CHIP_DETECT_MAGIC_ESP32 = 0x00F01D83,
|
||||
CHIP_DETECT_MAGIC_ESP32S2 = 0x000007C6,
|
||||
CHIP_DETECT_MAGIC_ESP32S3 = 0x9,
|
||||
CHIP_DETECT_MAGIC_ESP8266 = 0xFFF0C101,
|
||||
CHIP_DETECT_MAGIC_ESP32C6 = 0x2CE0806F,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t chip_detect;
|
||||
uint32_t entry;
|
||||
uint32_t text_start;
|
||||
uint32_t text_length;
|
||||
const uint8_t *text;
|
||||
uint32_t data_start;
|
||||
uint32_t data_length;
|
||||
const uint8_t *data;
|
||||
const char *chip_name;
|
||||
} esp32_stub_loader_t;
|
||||
|
||||
class ESP32BootROMClass {
|
||||
public:
|
||||
ESP32BootROMClass(HardwareSerial &hwSerial, int gpio0Pin = -1,
|
||||
int resetnPin = -1);
|
||||
|
||||
// return chip detect magic if success, otherwise 0
|
||||
uint32_t begin(unsigned long baudrate);
|
||||
void end();
|
||||
|
||||
bool isRunningStub(void);
|
||||
uint32_t getFlashWriteSize(void);
|
||||
|
||||
// High Level commands
|
||||
bool read_reg(uint32_t regAddr, uint32_t *regValue,
|
||||
uint32_t timeout_ms = ESP32_DEFAULT_TIMEOUT);
|
||||
bool read_MAC(uint8_t mac[6]);
|
||||
uint32_t read_chip_detect(void);
|
||||
|
||||
// uncompressed
|
||||
bool beginFlash(uint32_t offset, uint32_t size, uint32_t chunkSize);
|
||||
bool dataFlash(const void *data, uint32_t length);
|
||||
bool endFlash(uint32_t reboot);
|
||||
|
||||
// compressed
|
||||
bool beginFlashDefl(uint32_t offset, uint32_t size, uint32_t zip_size);
|
||||
bool dataFlashDefl(const void *data, uint32_t len);
|
||||
bool endFlashDefl(uint32_t reboot);
|
||||
|
||||
bool md5Flash(uint32_t offset, uint32_t size, uint8_t *result);
|
||||
|
||||
private:
|
||||
void init();
|
||||
void resetBootloader(void);
|
||||
bool sync();
|
||||
bool uploadStub(const esp32_stub_loader_t *stub);
|
||||
bool syncStub(uint32_t timeout_ms);
|
||||
|
||||
// Command and Response
|
||||
void command(uint8_t opcode, const void *data, uint16_t length,
|
||||
const void *data2 = NULL, uint16_t len2 = 0);
|
||||
int response(uint8_t opcode, uint32_t timeout_ms, void *body = NULL);
|
||||
|
||||
bool sendCommandGetResponse(uint8_t opcode, const void *data, uint16_t length,
|
||||
const void *data2 = NULL, uint16_t len2 = 0,
|
||||
uint32_t timeout_ms = ESP32_DEFAULT_TIMEOUT,
|
||||
void *body = NULL);
|
||||
|
||||
// High Level commands
|
||||
bool changeBaudrate(uint32_t baudrate);
|
||||
bool spiAttach();
|
||||
|
||||
bool beginMem(uint32_t offset, uint32_t size, uint32_t chunkSize);
|
||||
bool dataMem(const void *data, uint32_t length);
|
||||
bool endMem(uint32_t entry);
|
||||
|
||||
// read and write packets
|
||||
uint16_t readBytes(void *buf, uint16_t length, uint32_t timeout_ms);
|
||||
bool readSLIP(uint32_t timeout_ms);
|
||||
void writeEscapedBytes(const uint8_t *data, uint16_t length);
|
||||
|
||||
HardwareSerial *_serial;
|
||||
int _gpio0Pin;
|
||||
int _resetnPin;
|
||||
|
||||
bool _supports_encrypted_flash;
|
||||
bool _stub_running;
|
||||
bool _rom_8266_running;
|
||||
uint32_t _chip_detect;
|
||||
|
||||
uint32_t _flashSequenceNumber;
|
||||
};
|
||||
|
||||
#endif
|
||||
2234
src/stub_esp.h
Normal file
2234
src/stub_esp.h
Normal file
File diff suppressed because it is too large
Load diff
81
tools/esp_compress.py
Normal file
81
tools/esp_compress.py
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
import zlib
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
import click
|
||||
|
||||
def print_carray(f, payload):
|
||||
while len(payload) > 0:
|
||||
f.write('\n ')
|
||||
f.write(', '.join('0x{:02x}'.format(x) for x in payload[0:16]))
|
||||
f.write(',')
|
||||
payload = payload[16:]
|
||||
f.write('\n')
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.argument('dpath', type=click.Path(exists=True), default='.')
|
||||
@click.option('--sd', is_flag=True, default=False, help='Generate header for using with SDCard')
|
||||
def main(dpath, sd):
|
||||
"""
|
||||
This script takes a directory path (default is current directory) and
|
||||
create compressed .bin.gz file along 'esp_binaries.h' containing metadata in esp32_zipfile_t struct.
|
||||
Which can be used to program ESP32 with TestBed or Brain.
|
||||
If '--sd' option is specified, it will skip generating C array data for gz file.
|
||||
"""
|
||||
output_header = 'esp_binaries.h'
|
||||
with open(output_header, 'w') as fc:
|
||||
# print typedef struct
|
||||
fc.write('// Generated by tools/esp_compress.py\n')
|
||||
file_list = sorted(Path(dpath).glob('*.bin'))
|
||||
fc.write(f'#define ESP_BINARIES_COUNT ({len(file_list)})\n\n')
|
||||
|
||||
# print list of struct first
|
||||
for fname in file_list:
|
||||
var = fname.stem
|
||||
var = var.replace('.', '_')
|
||||
var = var.replace('-', '_')
|
||||
fc.write(f'// const esp32_zipfile_t {var}\n')
|
||||
fc.write('\n')
|
||||
|
||||
for fname in file_list:
|
||||
with open(fname, 'rb') as fi:
|
||||
image = fi.read()
|
||||
zimage = zlib.compress(image, 9)
|
||||
fzname = fname.with_suffix('.bin.gz')
|
||||
md5 = hashlib.md5(image)
|
||||
|
||||
# write .gz file
|
||||
with open(fzname, 'wb') as fz:
|
||||
fz.write(zimage)
|
||||
|
||||
# write to c header file
|
||||
var = fname.stem
|
||||
var = var.replace('.', '_')
|
||||
var = var.replace('-', '_')
|
||||
|
||||
# bin gz contents
|
||||
if not sd:
|
||||
fc.write(f'const uint8_t _{var}_gz[{len(zimage)}] = {{')
|
||||
print_carray(fc, zimage)
|
||||
fc.write('};\n\n')
|
||||
|
||||
fc.write(f'const esp32_zipfile_t {var} = {{\n')
|
||||
fc.write(f' .name = "{fzname}",\n')
|
||||
if sd:
|
||||
fc.write(f' .data = NULL,\n')
|
||||
else:
|
||||
fc.write(f' .data = _{var}_gz,\n')
|
||||
fc.write(f' .compressed_len = {len(zimage)},\n')
|
||||
fc.write(f' .uncompressed_len = {len(image)},\n')
|
||||
fc.write(' .md5 = {')
|
||||
print_carray(fc, md5.digest())
|
||||
fc.write(' },\n')
|
||||
fc.write('};\n')
|
||||
fc.write('\n')
|
||||
|
||||
deflation = 100*(1-len(zimage)/len(image))
|
||||
print(f"Compressed {var}: {len(image)} to {len(zimage)} bytes, deflation: {deflation:.2f}%")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
104
tools/esp_stub.py
Normal file
104
tools/esp_stub.py
Normal file
File diff suppressed because one or more lines are too long
45
tools/file2carray.py
Normal file
45
tools/file2carray.py
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import random
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from multiprocessing import Pool
|
||||
from weakref import finalize
|
||||
|
||||
|
||||
def print_carray(f, payload):
|
||||
while len(payload) > 0:
|
||||
f.write('\n ')
|
||||
f.write(', '.join('0x{:02x}'.format(x) for x in payload[0:16]))
|
||||
f.write(',')
|
||||
payload = payload[16:]
|
||||
f.write('\n')
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Convert binary files to C array format')
|
||||
parser.add_argument('files', nargs='+', help='Binary files to convert')
|
||||
args = parser.parse_args()
|
||||
|
||||
files = args.files
|
||||
for fin_name in files:
|
||||
if not os.path.isfile(fin_name):
|
||||
print(f"File {fin_name} does not exist")
|
||||
continue
|
||||
|
||||
with open(fin_name, 'rb') as fin:
|
||||
contents = fin.read()
|
||||
fout_name = fin_name + '.h'
|
||||
with open(fout_name, 'w') as fout:
|
||||
print(f"Converting {fin_name} to {fout_name}")
|
||||
fout.write(f'const size_t bindata_len = {len(contents)};\n')
|
||||
fout.write(f'const uint8_t bindata[] __attribute__((aligned(16))) = {{')
|
||||
print_carray(fout, contents)
|
||||
fout.write('};\n')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
Loading…
Reference in a new issue