Compare commits

...

236 commits

Author SHA1 Message Date
Tyeth Gundry
c6f2a0cc4c
Update library.properties - bump version to 1.14.2 2025-08-05 13:32:43 +01:00
Ha Thach
b138cd1ba1
Merge pull request #29 from adafruit/brain-240mhz
Support running brain with rp2350 also support both F_CPU 120Mhz or 240Mhz
2025-07-30 21:38:04 +07:00
hathach
5b4034b0f9
add rp2350 to brain ci build 2025-07-30 21:17:17 +07:00
hathach
0332ed1117
support running rp2350 as testbed brain. Correct nop cycle for both rp2040 and rp2350 (higher IPC). Support both running with 120Mhz and 240Mhz 2025-07-30 21:09:27 +07:00
ladyada
6bfd594148 let run on RP2350 2025-07-29 13:44:15 -04:00
hathach
ab3624e73b
error if F_CPU is not 240Mhz due to pio-usb hanndshake timing issue when working with rp2350 bootrom.
support neopixel with 240Mhz
2025-07-29 21:10:15 +07:00
Tyeth Gundry
2b71fa7422
Update library.properties - 1.14.1 2025-06-26 15:03:33 +01:00
ladyada
6d16513e79 add feather m0's built in neopix 2025-06-22 13:40:48 -04:00
Tyeth Gundry
8045dd5c78
Update library.properties - bump to 1.14.0 2025-03-11 21:21:50 +00:00
Ha Thach
0b408468ce
Merge pull request #28 from adafruit/support-program-rp2350
support programming rp2350
2025-03-07 11:15:37 +07:00
hathach
759bdeb282
support programming rp2350, add a new example to program metro rp2350 from firmware.h
rename program_rp2040_uf2.ino to program_rp2_from_sdcard.ino
change include SdFat.h to SdFat_Adafruit_Fork.h
2025-03-05 16:47:56 +07:00
Tyeth Gundry
1130b8c29d
Update library.properties - bump version to 1.13.2 2024-11-27 15:35:24 +00:00
Limor "Ladyada" Fried
45816d8d0a
Merge pull request #27 from mikeysklar/master
qtpy esp32s3 with psram name fix
2024-11-22 19:15:07 -05:00
Mikey Sklar
d75faf6081 qtpy esp32s3 with psram name fix
Incorrect board name being used for Qt Py ESP32-S3 with 2MB PSRAM.

was:
ARDUINO_ADAFRUIT_QTPY_ESP32S3

correct boards.txt name:
ARDUINO_ADAFRUIT_QTPY_ESP32S3_N4R2
2024-11-22 15:18:57 -08:00
Tyeth Gundry
d48670064b
Update library.properties - bump version to 1.13.1 2024-07-23 15:57:58 +01:00
Tyeth Gundry
4125a29235
Merge pull request #26 from adafruit/2024-07-23-formatting
ESP32BootRom.cpp: format ifdefs
2024-07-23 15:57:27 +01:00
Tyeth Gundry
7657c315e3 ESP32BootRom.cpp: format ifdefs 2024-07-23 15:43:57 +01:00
Tyeth Gundry
64fc7e33c9
Update library.properties - bump version to 1.13.0 2024-07-23 15:06:02 +01:00
ladyada
cd2ecc5b76 Merge branch 'master' of github.com:adafruit/Adafruit_TestBed 2024-07-17 17:40:52 -04:00
ladyada
bbc2afadf4 add swj_clock argument, error setting for analog tests, and some ifdefs for ESP32 programming modes 2024-07-17 17:40:04 -04:00
Tyeth Gundry
e0d3b19e47
Update library.properties - bump version to 1.12.2 2024-07-09 11:21:22 +01:00
Ha Thach
4fb2c089bc
Merge pull request #25 from adafruit/support-c6 2024-07-05 16:26:54 +07:00
hathach
1805552376
add test for c6 programmin via cdc but not working yet due to usb host. 2024-07-05 15:21:21 +07:00
hathach
948b602102
add support for c6 programming stub + chip detect. Tested with uart programming 2024-07-05 14:32:14 +07:00
ladyada
00ea80fce2 Merge branch 'master' of github.com:adafruit/Adafruit_TestBed 2024-04-10 11:06:46 -04:00
ladyada
f3f79e1384 reading is slow so give some feedback so they know its working! 2024-04-10 11:06:39 -04:00
Tyeth Gundry
0de33c2804 Clean up old formatting (pre-commit) 2024-04-09 17:47:43 +00:00
ladyada
228169cbe5 add blink 2024-04-06 10:27:00 -04:00
ladyada
d37a36ff29 Merge branch 'master' of github.com:adafruit/Adafruit_TestBed 2024-01-09 15:07:21 -05:00
Tyeth Gundry
d02093a1b1
Update library.properties - bump version to 1.12.0 2024-01-09 15:43:57 +00:00
Ha Thach
f13cdaa159
Merge pull request #24 from adafruit/add-8266-binary
Add 8266 binary
2024-01-09 15:51:13 +07:00
hathach
87f1fa0d9d rename example program_esp32_cdc/uart to simply program_esp_cdc/uart
since esp8266 is also supported
2024-01-09 13:00:23 +07:00
hathach
28fda00cce add 8266 blinky to program_esp32_cdc 2024-01-09 12:57:30 +07:00
ladyada
991d04d7a6 Merge branch 'master' of github.com:adafruit/Adafruit_TestBed 2024-01-08 14:16:23 -05:00
Ha Thach
38c0a286f5
Merge pull request #23 from adafruit/add-verify-arg-dap_programFlash
Add verify arg dap_programFlash(), add new dap_readFlash()
2024-01-03 20:23:09 +07:00
ladyada
293c7f8be2 more correct msg 2023-12-28 14:17:48 -05:00
hathach
dc494b2be1 add do_verify and do_crc32 2023-12-29 02:02:43 +07:00
hathach
4b29b6a223 add Brain::dap_readFlash(), add read_nrf52840_to_sdcard example 2023-12-28 22:04:57 +07:00
hathach
26be867d87 add optional do_verify to Brain.dap_programFlash(), default to true
duplicate program nrf52840 to program rnf52840_from_sdcard
2023-12-28 21:27:13 +07:00
ladyada
0bd60196b2 Merge branch 'master' of github.com:adafruit/Adafruit_TestBed 2023-10-20 23:39:13 -04:00
ladyada
e47a9febec dont halt on bad ID read 2023-10-20 23:39:07 -04:00
Tyeth Gundry
c5216f28cd
Update library.properties - bump version to 1.11.0 2023-10-17 14:52:14 +01:00
Ha Thach
8ffa1d6ff9
Merge pull request #22 from adafruit/refactor-program-esp32
Refactor programming esp32 out of Brain
2023-10-13 09:59:26 +07:00
hathach
fcf8557dd0 replace all printf() to make it compatible with arduino avr and samd core 2023-10-13 00:05:38 +07:00
hathach
0daa066f41 fix ci build with avr core 2023-10-12 23:40:30 +07:00
hathach
9a1477f407 add esp32_programFlashDefl() with File32 from SD card
- upgrade tool/esp_compress.py with --sd option to generate metadata for
use with files on sdcard
- add new program_esp32_uart_from_sdcard that tested on metro m4 (and
pyportal)
2023-10-12 23:24:29 +07:00
hathach
c25bc452fd refactor: move esp32 program function from Brain to TestBed
also move targetResetPin to TestBed
2023-10-11 11:02:19 +07:00
hathach
31c20caf2c
add ESP32_NATIVE_USB setting to make it clear which usb we are dealing with 2023-07-23 13:29:04 +07:00
hathach
d379e56c4f
default program_cdc to S3 2023-07-23 13:23:02 +07:00
Eva Herrada
6e53893034
Bumped to 1.10.0 2023-07-18 15:39:52 -04:00
Ha Thach
4b31541dc4
Merge pull request #21 from adafruit/add-usbh-hub-test
Add usbh hub test
2023-07-10 22:03:05 +07:00
hathach
3930a02dac
use ARM_MATH_CM0PLUS as adafruit samd indicator 2023-07-10 17:19:37 +07:00
hathach
db9ba914b4
fix ci: arduino samd does not have printf, enable esp32bootrom for adafruit samd21 only 2023-07-10 16:56:03 +07:00
hathach
f6aee1c29a
fix clang 2023-07-10 16:18:15 +07:00
hathach
b4249f1614
add usbh hub test example 2023-07-10 16:10:54 +07:00
lady ada
c90c7cd375 qwiic is on second port 2023-06-28 13:11:42 -04:00
lady ada
b65bd1fd88 Merge branch 'master' of github.com:adafruit/Adafruit_TestBed 2023-06-11 13:00:31 -04:00
lady ada
6f3b5e73f6 small tweaks 2023-06-11 13:00:02 -04:00
Eva Herrada
782efbfe5a
Bump to 1.9.0 2023-05-30 12:32:46 -04:00
Ha Thach
c3e647b801
Merge pull request #20 from adafruit/add-featherV2-ch9102f
add support for programming esp via serial host with usb-to-uart chip like ch9102f
2023-05-05 16:52:31 +07:00
hathach
2e5afb8b32 update esp32 to be compatible with M4 and/or board without tinyusb 2023-05-05 16:40:15 +07:00
hathach
ce1d1ec7b0 rebase and fix clang 2023-05-05 16:27:13 +07:00
hathach
5ad6ac8fb6 update doc wiring 2023-05-05 16:26:49 +07:00
hathach
b77e95352f add support for programming esp via serial host with usb-to-uart chip e.g ch9102f
- update program_esp32_cdc.ino to support ch9102f
- add flashing binaries for feather esp32 v2 blinky
2023-05-05 16:26:49 +07:00
lady ada
31792680b3 Merge branch 'master' of github.com:adafruit/Adafruit_TestBed 2023-04-21 13:11:39 -04:00
lady ada
0cf64c14cf retry fewer times 2023-04-21 13:10:49 -04:00
Ha Thach
92764d6ef1
Merge pull request #19 from adafruit/add-esp8266
Add esp8266
2023-04-19 17:15:41 +07:00
hathach
fbe4f207c8 clang, pre-commit skip ino files 2023-04-19 17:03:26 +07:00
hathach
689440a95f change default binaries back to metro s2 2023-04-19 16:49:54 +07:00
hathach
0f8bf4c029 wrap up support for esp8266, testing with speed aroudn 120KB/s 2023-04-19 16:49:23 +07:00
hathach
3417e50633 fix timing delay for esp8266 which is slow to be ready for each new command
also retry 3 times for each command before failed
2023-04-19 16:18:22 +07:00
hathach
bfbcf9b7c6 update all commands to use new sendCommandGetResponse() also slight change signature from int to bool 2023-04-19 13:23:22 +07:00
hathach
03823d562f irmpve esp bootrom to support esp8266
- 8266 rom has status len = 2 (as opposed to esp32 with 4), which is
used to detect 8266 in early (before chip detect)
- small delay each sync attempt to better sync
- small delay before sending command for 8266 rom since it takes longer
to ready receiving (possibly due to flexible baud 74800bps and 115200bps
- able to upload stub, and flashing with baud rate = 115200 with 8266
- add sendCommandGetResponse() to centrally manage failed and retry with
commands
2023-04-19 12:48:15 +07:00
hathach
17575513c3 add esp8266 stub 2023-04-18 11:36:09 +07:00
hathach
0b6ce61c5b clean up 2023-04-18 09:05:16 +07:00
Ha Thach
91f6f7cc72
Merge pull request #18 from adafruit/fix-neopixel-color
fine tune and fix neopixel incorrect color
2023-04-14 10:56:50 +07:00
hathach
984926b7d8 clang 2023-04-14 10:46:41 +07:00
hathach
f7ea00b74b fine tune and fix neopixel incorrect color 2023-04-14 10:42:56 +07:00
Eva Herrada
d19c9f6e4d
Bump to 1.8.2 2023-04-03 15:45:27 -04:00
lady ada
6e013b1c11 Merge branch 'master' of github.com:adafruit/Adafruit_TestBed 2023-03-22 11:22:36 -04:00
lady ada
829d921b35 fix tone() on esp32s2, allow esp32 programming via M4 host 2023-03-22 11:22:30 -04:00
Limor "Ladyada" Fried
30d2ead4cb
Merge pull request #17 from adafruit/fix-s3-reset
Fix s3 reset
2023-03-22 11:19:39 -04:00
hathach
98ca14c68f
use safer walkaround, idleOtherCore() can accidentally idle core0 when executed in core1 2023-03-22 16:38:52 +07:00
hathach
e631a58b30
add pre-commit with clang, trailing spaces, and codespell 2023-03-22 16:21:00 +07:00
hathach
d4a945f967
add walkround for reset S3 2023-03-22 16:20:10 +07:00
hathach
41eae0f21a esp23 bootrom begin() return chip_detect id 2023-03-22 16:04:46 +07:00
Eva Herrada
b5a2854854
Bump to 1.8.1 2023-03-14 15:44:51 -04:00
lady ada
387a95c819 add some debug and semaphore for LCD 2023-03-07 14:28:51 -05:00
lady ada
8c7ba727e5 Merge branch 'master' of github.com:adafruit/Adafruit_TestBed 2023-03-06 18:56:06 -05:00
Eva Herrada
e02f558ca8
Bump to 1.8.0 2023-03-02 16:18:09 -05:00
lady ada
76e28d0e6d Merge branch 'master' of github.com:adafruit/Adafruit_TestBed 2023-02-24 18:02:50 -05:00
Ha Thach
fd4ecd9b87
Merge pull request #16 from adafruit/add-metro-bin
added metro binaries for program cdc
2023-02-24 21:17:50 +07:00
hathach
dfca31499c
clang 2023-02-24 21:05:56 +07:00
hathach
2df3903e52
update binaries for cdc 2023-02-24 21:01:24 +07:00
hathach
68a73923f5
update esp binaries 2023-02-24 20:59:22 +07:00
hathach
94910676de
added metro binaries for program cdc 2023-02-24 18:33:01 +07:00
lady ada
4fa35fbbc7 Merge branch 'master' of github.com:adafruit/Adafruit_TestBed 2023-02-23 22:44:28 -05:00
lady ada
cfd5014475 add debug timing 2023-02-23 22:44:22 -05:00
Ha Thach
62ffc063d3
Merge pull request #15 from adafruit/brain-esp32-s2-s3
Brain esp32 s2 s3
2023-02-23 16:34:31 +07:00
hathach
108db070d7
fix warnings 2023-02-23 12:41:58 +07:00
hathach
05c4ca3e10
more clang 2023-02-23 12:14:52 +07:00
hathach
30e01cd273
clang 2023-02-23 12:13:02 +07:00
hathach
6d727217b7
wrap up 2023-02-23 12:11:22 +07:00
hathach
fd3acf6fe3
stub + compresssion work well with s2 and s3 with decent 56KB/s 2023-02-23 12:04:00 +07:00
hathach
125166afde
fix read escape issue 2023-02-23 10:24:51 +07:00
hathach
5bcbd821b2
use stub for esp32s2, work well
speed is increase from 25 to 38 kB
2023-02-23 09:16:24 +07:00
Ha Thach
6fb3ea8bc7
Merge pull request #14 from adafruit/brain-esp-compression
Brain esp compression
2023-02-22 10:45:55 +07:00
hathach
b7bd917be0
run clang before test 2023-02-22 10:26:06 +07:00
hathach
b183a5b31b
improve serial write(), write in chunk up to escape code instead of 1 by 1 2023-02-22 10:25:06 +07:00
hathach
2e8e572dca
check md5 before flashing 2023-02-21 21:59:32 +07:00
hathach
039fb89810
clang 2023-02-21 21:28:46 +07:00
hathach
33d8bb52d3
rename esp32_stub_loader_t 2023-02-21 21:18:22 +07:00
hathach
1bb697f951
clang 2023-02-21 21:12:11 +07:00
hathach
eabef3a42a
esp32_programFlashDefl() work well with on-board flash 2023-02-21 20:13:35 +07:00
hathach
6e930676c1
implemented flash deflate 2023-02-21 19:43:03 +07:00
hathach
58c6faceb7
adding esp_compress.py, add intial zip program, rename sd based example to program_esp32_uart_uncompressed 2023-02-21 17:30:53 +07:00
hathach
008240300b
improve readSLIP() 2023-02-21 11:38:19 +07:00
hathach
0a3dabfc2f
improve stub hanlding 2023-02-21 10:40:11 +07:00
hathach
6d649f4812
clean up 2023-02-21 10:28:27 +07:00
Ha Thach
cfd77f443e
Merge pull request #13 from adafruit/brain-esp32-stub-loader
Brain esp32 stub loader
2023-02-20 22:45:32 +07:00
hathach
4325321100
fix clang 2023-02-20 22:36:22 +07:00
hathach
566cb691bb
fix typo 2023-02-20 22:22:55 +07:00
hathach
a9e5d3ed88
Merge branch 'master' into brain-esp32-stub-loader 2023-02-20 21:59:02 +07:00
hathach
81b139c124
clang 2023-02-20 21:44:39 +07:00
hathach
4a1cf8ecde
fix ci 2023-02-20 21:31:05 +07:00
hathach
3de56de16b
more enhance 2023-02-20 21:29:03 +07:00
hathach
fcf3f29586
detect SUPPORTS_ENCRYPTED_FLASH by chip detect. fix s2/s3 upload
though s2/s3 upload isn't stable enough.
2023-02-20 20:06:42 +07:00
hathach
442a5d3744
everything works well with stub 2023-02-20 18:18:41 +07:00
hathach
70197ab53b
improve dataMem() 2023-02-20 18:09:12 +07:00
hathach
564de5050d
enhance command() for dataFlash() 2023-02-20 18:05:54 +07:00
hathach
e4623a8095
update syncStub() 2023-02-20 16:38:37 +07:00
hathach
9855be25fe
flashing with stub working 2023-02-20 16:27:57 +07:00
lady ada
09fd788cbb clang 2023-02-18 15:02:06 -05:00
lady ada
69a55bde9e dont compile for AVRs, fix essp to esp 2023-02-18 11:18:09 -05:00
hathach
72c94939c8
fix run stub() 2023-02-17 22:28:55 +07:00
hathach
7145cd3bf4
add debug code 2023-02-17 21:51:36 +07:00
hathach
d25855653a
add beginMem(), dataMem(), endMem(), syncStub()
- beginMen() and dataMem() seems to work  well
- endMem() and syncStub() is still wip
2023-02-17 21:21:38 +07:00
hathach
be5221f5a0
simplify read_reg() 2023-02-17 12:06:20 +07:00
hathach
16c367c107
simplify read_MAC() 2023-02-17 11:55:31 +07:00
hathach
30417d6e10
fix beginFlash() 2023-02-17 09:19:51 +07:00
lady ada
a357d3bfce make opcodes 8-bit and add readreg + readmac (tests readreg) 2023-02-16 21:03:38 -05:00
Ha Thach
84329baa36
Merge pull request #11 from adafruit/brain-esp32
Support Brain to program esp32
2023-02-16 18:26:23 +07:00
Ha Thach
bea8465a25
Merge pull request #10 from adafruit/revtft
updating i2c scan for reverse tft
2023-02-16 18:25:19 +07:00
hathach
1be22d3c2c
correct conflict 2023-02-16 10:19:54 +07:00
hathach
df276b1594
update program esp32 cdc 2023-02-16 09:21:53 +07:00
hathach
14d129d08f
flash factory bins for s2 an s3 2023-02-16 00:34:05 +07:00
hathach
8f4e4f0ddc
enhance bootrom begin to work well with SerialHost 2023-02-15 23:42:18 +07:00
hathach
ee9cc6589f add support for SUPPORTS_ENCRYPTED_FLASH, flashing S2 works well 2023-02-15 23:31:41 +07:00
hathach
02ab42e8be update program esp32 uart with multiple files 2023-02-15 13:34:26 +07:00
hathach
29e185c9a6 add enum for esp32 boot rom 2023-02-15 13:32:43 +07:00
hathach
b3580bd02d add program esp32 cdc 2023-02-14 17:22:16 +07:00
hathach
7ef4d6d655 update esp32_begin() to return bool 2023-02-14 11:54:42 +07:00
hathach
91c795d4d2 program esp32 via uart work well, MD5 checksum matched 2023-02-13 17:01:08 +07:00
hathach
f72c47ffe5 clang 2023-02-09 08:51:13 +07:00
BlitzCityDIY
81766d7f69 updating i2c scan for reverse tft
Updating the I2C_Scan example to support the Feather ESP32-S2 Reverse TFT
2023-02-08 15:57:43 -05:00
hathach
9667f0f50c Adding programming for esp32
move files to src/ folder
add program_esp32_uart example
2023-02-08 23:01:04 +07:00
Eva Herrada
e77271e4cf
Bump to 1.7.0 2023-01-23 16:06:26 -05:00
Ha Thach
a7a2a43908
Merge pull request #9 from adafruit/brain-dap
Brain rp2040 dap support
2023-01-12 09:18:16 +07:00
Eva Herrada
fb2d296679
Bump to 1.6.0 2023-01-11 16:02:01 -05:00
hathach
2901bb7a88
clang 2023-01-11 11:52:30 +07:00
hathach
c28c813666
also add bin file for upload 2023-01-11 09:54:24 +07:00
hathach
2054f9085e
dap work with stm32f405 2023-01-10 22:41:42 +07:00
hathach
5db9ed17d7
brain dap now support samd21 samd51 and nrf52840 2023-01-10 17:37:00 +07:00
hathach
1079cd7524
minor clean up 2023-01-10 00:02:10 +07:00
hathach
93d664335d
work well with samd51 2023-01-09 23:56:58 +07:00
hathach
8f5c84d20a
program samd21 work well 2023-01-09 23:01:58 +07:00
Ha Thach
9a69342718
Merge pull request #8 from adafruit/rp2040brains
Add RP2040 Brain with USB Host MSC and CDC support
2022-12-29 10:11:12 +07:00
hathach
a3857ba7dd
update usbh_test with SerialHost 2022-12-23 22:31:07 +07:00
hathach
681f50a485 temporarily skip dap program for samd21/51 2022-12-19 22:48:42 +07:00
hathach
e2e21f2308 clang 2022-12-19 22:47:14 +07:00
hathach
c24fd98806 bit banging neopixel due to conflict with usbh on pio usage
work well but the color is a bit off, need more timing tuning.
2022-12-13 17:14:11 +07:00
lady ada
16dc03cb18 fix rp2040 analogrez 2022-12-06 18:22:23 -05:00
lady ada
c67e87f382 only on pico in specific! 2022-12-06 17:46:52 -05:00
hathach
856dcea0fa temp comment out dap support 2022-12-05 09:09:08 +07:00
hathach
aad8faa22c
update brain's dap using new abstract API, support both SAMD21 and SAMD51 2022-12-02 23:48:09 +07:00
hathach
22cbaf7473
support samd21 lock/unlock fuse 2022-12-02 19:02:32 +07:00
hathach
13f612a8f0
clang format 2022-12-02 18:18:24 +07:00
hathach
70c3183faf
add Adafruit DAP library to libdep 2022-12-02 17:43:28 +07:00
hathach
6f15521221
wrap up DAP support for sam21 2022-12-02 17:42:19 +07:00
hathach
cf3f297107 fix ci 2022-11-30 00:21:17 +07:00
hathach
576538f417 more refined 2022-11-30 00:13:59 +07:00
hathach
3fa9e557d4 clean up example 2022-11-29 20:50:15 +07:00
hathach
f8b23617d0 fix ci 2022-11-29 09:06:30 +07:00
hathach
c17d145714 clang 2022-11-29 08:35:47 +07:00
hathach
f6e4d40a70 update setLED 2022-11-29 00:47:10 +07:00
hathach
f42817953a clang 2022-11-29 00:34:56 +07:00
hathach
c7de9daf30 clean up 2022-11-29 00:22:26 +07:00
hathach
e29ed40826 wrap up program rp2040 with uf2 example 2022-11-29 00:19:18 +07:00
hathach
7c7d452554 add program rp2040 uf2 sketch example 2022-11-28 16:50:17 +07:00
hathach
262522e74d adding program_rp2040_uf2 example
add more helper for Brain to mount FS on usb msc host
2022-11-25 17:45:10 +07:00
hathach
3d01f48db0 minor clean up 2022-11-25 00:39:35 +07:00
hathach
e52fc9d3ee
should fix ci 2022-11-21 23:29:52 +07:00
hathach
9468e851ec
more ci 2022-11-21 22:45:30 +07:00
hathach
e5e716e0c5
add LiquidCrystal to libdeps 2022-11-21 22:25:41 +07:00
hathach
6fab3c4141
update ci build 2022-11-21 22:20:21 +07:00
hathach
93ae8208b3
add usbh test 2022-11-21 21:50:46 +07:00
hathach
c5f5a3ca97
add brain test sketch 2022-11-21 20:32:28 +07:00
hathach
b339a8f581
update brain with usbh support 2022-11-21 20:31:39 +07:00
lady ada
318098f2f3 only compile rp2040 2022-11-06 16:38:54 -05:00
lady ada
7db6f028a3 fix neopixel color order 2022-11-02 01:24:00 -04:00
lady ada
3c634eed83 add working SD card 2022-10-31 19:19:48 -04:00
lady ada
289bf97e08 brains start 2022-10-31 18:04:28 -04:00
Carter Nelson
df6d5cf4a9
Update library.properties 2022-10-23 14:55:00 -07:00
Carter Nelson
e32eb136b4
Merge pull request #7 from caternuson/rp2040_wire1
Add Wire1 for any RP2040
2022-10-23 14:53:48 -07:00
caternuson
005d0ec682 clang for some reason 2022-10-23 12:46:10 -07:00
caternuson
ef23040a8d add wire1 for any rp2040 2022-10-23 12:33:16 -07:00
Eva Herrada
c3c90b162c
Bump to 1.4.0 2022-10-03 14:59:43 -04:00
lady ada
371afba0a8 add S3 feather, fix typo in testpins 2022-09-06 18:00:59 -04:00
lady ada
17ac30aea6 allow optional serial port 2022-09-02 00:01:13 -04:00
Eva Herrada
e4755effed
Bump to 1.3.0 2022-05-31 14:20:07 -04:00
Limor "Ladyada" Fried
944a44ca30
Merge pull request #6 from caternuson/add_due
Add Arduino DUE to I2C scan
2022-05-21 11:09:20 -04:00
caternuson
ad4dd677c9 print wire instance scanned 2022-05-18 14:57:42 -07:00
caternuson
bc16fe6403 add due 2022-05-18 10:58:09 -07:00
Eva Herrada
baf06e3510
Bump to 1.2.4 2022-03-28 17:21:06 -04:00
lady ada
e27446e680 add qtpy s3 2022-03-28 00:26:38 -04:00
lady ada
0180a5bd2e dont keep testing on fail 2022-03-22 10:08:46 -04:00
lady ada
ef243ed57b clang 2022-03-18 17:39:06 -04:00
lady ada
845304a483 Merge branch 'master' of github.com:adafruit/Adafruit_TestBed 2022-03-18 17:30:08 -04:00
lady ada
91fb1ee2df manually enable i2c until we can get it into the BSP variant 2022-03-18 17:27:44 -04:00
Eva Herrada
7a4055caef
Bump to 1.2.3 2022-03-17 10:52:52 -04:00
Limor "Ladyada" Fried
8118449d7a
Merge pull request #4 from adafruit/add-esp32-v2-i2c-scan
Add support for ESP32 V2.
2022-03-11 16:13:16 -05:00
Kattni Rembor
7aa7a8cbe1 Add support for ESP32 V2. 2022-03-11 15:25:35 -05:00
Eva Herrada
902e2c1b86
Bump to 1.2.2 2022-03-07 16:06:57 -05:00
lady ada
4ae8eee9c3 Merge branch 'master' of github.com:adafruit/Adafruit_TestBed 2022-03-01 16:01:36 -05:00
lady ada
c38b33aaf0 fix for rev C 2022-03-01 16:01:30 -05:00
Eva Herrada
19e8abf9ab
Bump to 1.2.1 2022-03-01 13:24:18 -05:00
lady ada
93ba78434f klang 2022-02-11 22:37:42 -05:00
lady ada
45e59c4146 try to linearize esp32 2022-02-11 21:53:46 -05:00
Eva Herrada
bd55cf66b0
Bump to 1.2.0 2022-01-31 15:44:17 -05:00
lady ada
1236733f7c woops twice 2022-01-29 20:37:29 -05:00
lady ada
5532886d3e Merge branch 'master' of github.com:adafruit/Adafruit_TestBed 2022-01-29 20:37:12 -05:00
lady ada
c8defb341f add rp2040 qt 2022-01-29 20:37:05 -05:00
Kattni
b90e218b85
Merge pull request #3 from adafruit/rp2040-support
Adding support for QT Py and Feather RP2040.
2022-01-26 15:41:42 -05:00
Kattni Rembor
20748d7de0 Adding support for QT Py and Feather RP2040. 2022-01-26 15:34:01 -05:00
Kattni
9ed4a31b7a
Merge pull request #2 from adafruit/itsy-support
Adding ItsyBitsy support.
2022-01-25 17:10:40 -05:00
Kattni Rembor
17906622bc Adding ItsyBitsy support. 2022-01-25 17:05:33 -05:00
89 changed files with 359958 additions and 68 deletions

View file

@ -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
View file

@ -0,0 +1,2 @@
.idea
.pio

25
.pre-commit-config.yaml Normal file
View 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]

View file

@ -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

View file

@ -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 dont 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

View 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);
}

View 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

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View 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);
}
}

View 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

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View 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");
}
}

Binary file not shown.

View 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");
}
}

View 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");
}
}

Binary file not shown.

File diff suppressed because it is too large Load diff

View 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);
}
}

View file

@ -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);
}
}

Binary file not shown.

View 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");
}
}

Binary file not shown.

View 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");
}
}

View 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");
}
}

View file

@ -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");
}
}

View 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) {
}
}

View 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);
}
}

View file

@ -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
}
}

View file

@ -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);

View 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,
},
};

View file

@ -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() {
}

View file

@ -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

View file

@ -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;

View file

@ -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

View 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

View 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
View 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
// dont 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
View 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

File diff suppressed because it is too large Load diff

81
tools/esp_compress.py Normal file
View 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

File diff suppressed because one or more lines are too long

45
tools/file2carray.py Normal file
View 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())