Compare commits
332 commits
sync-tinyu
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
737dfb2115 | ||
|
|
766d8cca00 | ||
|
|
d3cc12070a | ||
|
|
86dfc05234 | ||
|
|
8f13cb8bca | ||
|
|
fb9763423c | ||
|
|
7b30ff9e14 | ||
|
|
0e054b598b | ||
|
|
5ab76b7931 | ||
|
|
028629e93e | ||
|
|
8c615b6519 | ||
|
|
d4071f5abe | ||
|
|
4daede3744 | ||
|
|
44053c45df | ||
|
|
eaa9bfdaa5 | ||
|
|
9806375c60 | ||
|
|
e896107698 | ||
|
|
805aa2d41a | ||
|
|
fee8a5e6bc | ||
|
|
59d4393012 | ||
|
|
60fb663caa | ||
|
|
cdc07c1d96 | ||
|
|
794ac7f34b | ||
|
|
9496740134 | ||
|
|
6fa11c4d5e | ||
|
|
f05bd099c3 | ||
|
|
951dba38f6 | ||
|
|
5618d9c054 | ||
|
|
46d2c6cb49 | ||
|
|
23426ed3f6 | ||
|
|
72cd81005b | ||
|
|
fafc824f6b | ||
|
|
6b772c0ac4 | ||
|
|
560a21bdec | ||
|
|
4b9a629a55 | ||
|
|
55a0283b48 | ||
|
|
332b0c8e31 | ||
|
|
f83e0ce0ff | ||
|
|
d522523fd1 | ||
|
|
76a551be81 | ||
|
|
f4e8959828 | ||
|
|
7b22bd0adf | ||
|
|
36396f4f9e | ||
|
|
cfe6da84d1 | ||
|
|
7f7ac74899 | ||
|
|
8ef30202e5 | ||
|
|
3918606fbe | ||
|
|
1d3576a40a | ||
|
|
605d681c81 | ||
|
|
41bde22a7c | ||
|
|
411821714b | ||
|
|
aba2328b00 | ||
|
|
f12e3f2886 | ||
|
|
a17922159b | ||
|
|
96ac318c19 | ||
|
|
8f2d3edd77 | ||
|
|
c92b7fde16 | ||
|
|
85476dcd8f | ||
|
|
8077b62029 | ||
|
|
c976061caa | ||
|
|
f5211f4226 | ||
|
|
f8ac8130c5 | ||
|
|
1798428b15 | ||
|
|
5920d15f73 | ||
|
|
71e2c4a4bd | ||
|
|
f13b57a01a | ||
|
|
a529a74e4f | ||
|
|
05686e7f97 | ||
|
|
59a651cca0 | ||
|
|
2df6d2905e | ||
|
|
a7c9db3f62 | ||
|
|
0a9c3fe818 | ||
|
|
446e0af7a9 | ||
|
|
f752bc6e05 | ||
|
|
8587060a19 | ||
|
|
0061a40530 | ||
|
|
9aaf9b56bb | ||
|
|
7a32772d52 | ||
|
|
c748ad674a | ||
|
|
4c6e9ce4e0 | ||
|
|
e92d597803 | ||
|
|
889a5d65ed | ||
|
|
51a9de832e | ||
|
|
3bd0180973 | ||
|
|
264556032f | ||
|
|
e034538570 | ||
|
|
c67266b094 | ||
|
|
c1cab3e41c | ||
|
|
1f9da4918f | ||
|
|
a56612b5a9 | ||
|
|
6cc5113f35 | ||
|
|
8cb40327f1 | ||
|
|
468f72001e | ||
|
|
1b9e433c75 | ||
|
|
f5ad52fe7f | ||
|
|
d1708bc87f | ||
|
|
f2168e439f | ||
|
|
69333be53d | ||
|
|
7ca12e3688 | ||
|
|
efa33be67c | ||
|
|
e7941194dc | ||
|
|
6f0f7e6a05 | ||
|
|
1c1a65c834 | ||
|
|
f2286b88a8 | ||
|
|
4d5e4231e2 | ||
|
|
ee005588d0 | ||
|
|
75fd754212 | ||
|
|
6d6cd1788b | ||
|
|
8f7fe509d1 | ||
|
|
2179aeb6d2 | ||
|
|
2e8f1b5c33 | ||
|
|
c0e19ef533 | ||
|
|
c953968c46 | ||
|
|
10b35388a3 | ||
|
|
28dd927214 | ||
|
|
e90e6be60f | ||
|
|
f7e7028fd6 | ||
|
|
2682fe811b | ||
|
|
93f546aa19 | ||
|
|
307e8dc52b | ||
|
|
320903f0d8 | ||
|
|
c0ba78e110 | ||
|
|
8cdf80ab42 | ||
|
|
78f060b048 | ||
|
|
a3abd887a9 | ||
|
|
e6d15a2c3f | ||
|
|
a8aae07ec5 | ||
|
|
b1eb772117 | ||
|
|
f5a27167f6 | ||
|
|
d629476752 | ||
|
|
df1a09fe48 | ||
|
|
681746cc58 | ||
|
|
040eb93e77 | ||
|
|
ebe252cd5a | ||
|
|
631d192b10 | ||
|
|
f755225450 | ||
|
|
1679e75595 | ||
|
|
2c6f60941e | ||
|
|
2ebb6ab2bf | ||
|
|
cc0babfe1b | ||
|
|
c1d2eed330 | ||
|
|
6dab54c855 | ||
|
|
2913c9cb2b | ||
|
|
16168f09dc | ||
|
|
e12a2f80f8 | ||
|
|
dac1eee654 | ||
|
|
8bd4ee67b2 | ||
|
|
e39183c0da | ||
|
|
7be2c9a613 | ||
|
|
1366ac5d50 | ||
|
|
4fb7872555 | ||
|
|
9851a7d7b0 | ||
|
|
7b257c0f86 | ||
|
|
232be2f7ab | ||
|
|
e5ae023803 | ||
|
|
fc0ecddc0d | ||
|
|
8dc1275ede | ||
|
|
99736ac1ac | ||
|
|
8ee7989e42 | ||
|
|
2e5fb959b5 | ||
|
|
756970144f | ||
|
|
56d4b611f2 | ||
|
|
29e0d60db6 | ||
|
|
5cd4063bb8 | ||
|
|
1bae99a760 | ||
|
|
6c7624fcdc | ||
|
|
2ff208bbe0 | ||
|
|
55eebb98c0 | ||
|
|
9eae19b58a | ||
|
|
10e0c41466 | ||
|
|
f0f92403f7 | ||
|
|
15111810b0 | ||
|
|
fe14079068 | ||
|
|
12a186b550 | ||
|
|
6e77d5b4a5 | ||
|
|
7dfc5ab324 | ||
|
|
185692be69 | ||
|
|
bd3fba42d4 | ||
|
|
27ae871a8b | ||
|
|
fb2bfc3e57 | ||
|
|
19814da37b | ||
|
|
5564bbd997 | ||
|
|
a93bb80c6e | ||
|
|
766a14babd | ||
|
|
a9262b4c21 | ||
|
|
cbfff996b3 | ||
|
|
d8e9044069 | ||
|
|
b5fb020216 | ||
|
|
9047e04cae | ||
|
|
0df71c015f | ||
|
|
52fca115ba | ||
|
|
7a926e8fb9 | ||
|
|
fe5a155381 | ||
|
|
208f6c8e4c | ||
|
|
70fd45a713 | ||
|
|
536c8233b5 | ||
|
|
9db1fdf435 | ||
|
|
fb97586573 | ||
|
|
693f7d4bd5 | ||
|
|
f36defbf26 | ||
|
|
8d996db507 | ||
|
|
6481d697a7 | ||
|
|
5bbad8d1eb | ||
|
|
eb09bb48d7 | ||
|
|
6de4a11a3b | ||
|
|
565619630e | ||
|
|
ac087e4bd3 | ||
|
|
541fc93a67 | ||
|
|
e4e854ea2a | ||
|
|
de5353d0ca | ||
|
|
31f1edc668 | ||
|
|
6905192954 | ||
|
|
e291865233 | ||
|
|
e7985fa52e | ||
|
|
89ffd9dca5 | ||
|
|
b276e9ec83 | ||
|
|
c25ae4328c | ||
|
|
58698b05b9 | ||
|
|
865f31b2d1 | ||
|
|
7d72d0b1d8 | ||
|
|
a34e2f29e0 | ||
|
|
221ef2cca1 | ||
|
|
0ff42ce190 | ||
|
|
ebbd30b571 | ||
|
|
2b0b8148db | ||
|
|
2ca4b908bc | ||
|
|
61e908e428 | ||
|
|
f3e0ff74cc | ||
|
|
22f5dacfde | ||
|
|
08856552b0 | ||
|
|
997c1ec86e | ||
|
|
1c7f9c4d5e | ||
|
|
6a87063a3b | ||
|
|
1708cffa55 | ||
|
|
9d5e6a2ff8 | ||
|
|
03bfda3196 | ||
|
|
bf68b766f9 | ||
|
|
2c80ef1f7d | ||
|
|
9a83b0bda8 | ||
|
|
1c5cb1d07c | ||
|
|
9985421c95 | ||
|
|
c91d537c55 | ||
|
|
5deecfb0b7 | ||
|
|
09c47035d9 | ||
|
|
4d397111f1 | ||
|
|
b12da3e01f | ||
|
|
554cb09c6e | ||
|
|
6b2a48199d | ||
|
|
b5ad457895 | ||
|
|
702d953871 | ||
|
|
6f420fa0bc | ||
|
|
ffc744ae87 | ||
|
|
4be0aed13e | ||
|
|
4d04364b68 | ||
|
|
33c2a089e5 | ||
|
|
ea80c18955 | ||
|
|
34c59499d0 | ||
|
|
a07f9fb2df | ||
|
|
788d47d533 | ||
|
|
2c8cb9e541 | ||
|
|
31a23f3686 | ||
|
|
4f811125fd | ||
|
|
5c650e84e3 | ||
|
|
02f1321a48 | ||
|
|
9f3059c200 | ||
|
|
f898ccab35 | ||
|
|
c038be85af | ||
|
|
a465c3c73a | ||
|
|
d4c72bf143 | ||
|
|
2ab530d253 | ||
|
|
3861b59d15 | ||
|
|
fe9ae96122 | ||
|
|
1752f57cd6 | ||
|
|
6829820ac9 | ||
|
|
1429b5cce8 | ||
|
|
edd9c845a5 | ||
|
|
898c62f9c7 | ||
|
|
3df90297f4 | ||
|
|
70605b7ec2 | ||
|
|
336f2378e9 | ||
|
|
b16bbbf5bb | ||
|
|
d6f51faac0 | ||
|
|
102ff12a06 | ||
|
|
2c4b77b9e4 | ||
|
|
b79a383b8b | ||
|
|
2849480b71 | ||
|
|
4a93c7d869 | ||
|
|
138a336892 | ||
|
|
2b4f48d770 | ||
|
|
0a773af488 | ||
|
|
ffaa85e9e7 | ||
|
|
3a2ee4e480 | ||
|
|
feb3f158f3 | ||
|
|
b17ab37a0e | ||
|
|
beff567b60 | ||
|
|
0c067f82d6 | ||
|
|
2e561bec9c | ||
|
|
6257be4f91 | ||
|
|
cd5f6edbc0 | ||
|
|
5aeca208a5 | ||
|
|
2fc1e483da | ||
|
|
9aaa6c9855 | ||
|
|
29a0342258 | ||
|
|
553127a253 | ||
|
|
5678d97fff | ||
|
|
2e0f267f60 | ||
|
|
5924834d75 | ||
|
|
2db0de209a | ||
|
|
f06eb748a4 | ||
|
|
c58ed81a7e | ||
|
|
311f3a3940 | ||
|
|
64256d753d | ||
|
|
ac6d4c51e6 | ||
|
|
d62f7ef7d2 | ||
|
|
47fd7f190e | ||
|
|
3bf82685f5 | ||
|
|
71c70ea1c3 | ||
|
|
761cfd3b49 | ||
|
|
c2ffe2d537 | ||
|
|
6bbc3dbe9c | ||
|
|
a2bcb19f6c | ||
|
|
e7ad4fe2bc | ||
|
|
b576368bec | ||
|
|
d6dffe11a4 | ||
|
|
008de7ff37 | ||
|
|
c4d4a0a4d8 | ||
|
|
6546b4c08c | ||
|
|
647f6b27ae | ||
|
|
b75604f794 | ||
|
|
3c5a5bc727 | ||
|
|
34362e561e | ||
|
|
409f909578 |
251 changed files with 30213 additions and 12018 deletions
|
|
@ -2,3 +2,5 @@ synopsys
|
||||||
sie
|
sie
|
||||||
inout
|
inout
|
||||||
busses
|
busses
|
||||||
|
thre
|
||||||
|
|
||||||
|
|
|
||||||
10
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
10
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
|
|
@ -46,7 +46,7 @@ body:
|
||||||
- type: input
|
- type: input
|
||||||
attributes:
|
attributes:
|
||||||
label: TinyUSB Library version
|
label: TinyUSB Library version
|
||||||
placeholder: "Release version or github latest"
|
placeholder: "Release version or commit SHA"
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
|
|
@ -100,3 +100,11 @@ body:
|
||||||
description: If applicable, add screenshots to help explain your problem.
|
description: If applicable, add screenshots to help explain your problem.
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
|
|
||||||
|
- type: checkboxes
|
||||||
|
attributes:
|
||||||
|
label: I have checked existing issues, pr, discussion and documentation
|
||||||
|
description: You agree to check all the resources above before opening a new issue.
|
||||||
|
options:
|
||||||
|
- label: I confirm I have checked existing issues, pr, discussion and documentation.
|
||||||
|
required: true
|
||||||
|
|
|
||||||
3
.github/ISSUE_TEMPLATE/config.yml
vendored
3
.github/ISSUE_TEMPLATE/config.yml
vendored
|
|
@ -3,3 +3,6 @@ contact_links:
|
||||||
- name: Adafruit Support Forum
|
- name: Adafruit Support Forum
|
||||||
url: https://forums.adafruit.com
|
url: https://forums.adafruit.com
|
||||||
about: If you have other questions or need help, post it here.
|
about: If you have other questions or need help, post it here.
|
||||||
|
- name: TinyUSB Arduino Discussion
|
||||||
|
url: https://github.com/adafruit/Adafruit_TinyUSB_Arduino/discussions
|
||||||
|
about: If you have other questions or need help, post it here.
|
||||||
|
|
|
||||||
46
.github/workflows/githubci.yml
vendored
46
.github/workflows/githubci.yml
vendored
|
|
@ -3,26 +3,24 @@ name: Build
|
||||||
on: [pull_request, push, repository_dispatch]
|
on: [pull_request, push, repository_dispatch]
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
ARDUINO_LIBS: "\"Adafruit SPIFlash\" \"Adafruit seesaw Library\" \"Adafruit NeoPixel\" \"Adafruit Circuit Playground\" \"Adafruit InternalFlash\" \"SdFat - Adafruit Fork\" \"SD\" \"MIDI Library\" \"Pico PIO USB\""
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
pre-commit:
|
pre-commit:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Setup Python
|
|
||||||
uses: actions/setup-python@v4
|
|
||||||
with:
|
|
||||||
python-version: '3.x'
|
|
||||||
|
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Run pre-commit
|
- name: Run pre-commit
|
||||||
uses: pre-commit/action@v3.0.0
|
uses: pre-commit/action@v3.0.1
|
||||||
|
|
||||||
- name: Checkout adafruit/ci-arduino
|
- name: Checkout adafruit/ci-arduino
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
repository: adafruit/ci-arduino
|
repository: adafruit/ci-arduino
|
||||||
path: ci
|
path: ci
|
||||||
|
|
@ -39,6 +37,9 @@ jobs:
|
||||||
PRETTYNAME : "Adafruit TinyUSB Library"
|
PRETTYNAME : "Adafruit TinyUSB Library"
|
||||||
run: bash ci/doxy_gen_and_deploy.sh
|
run: bash ci/doxy_gen_and_deploy.sh
|
||||||
|
|
||||||
|
# ---------------------------------------
|
||||||
|
# build
|
||||||
|
# ---------------------------------------
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: pre-commit
|
needs: pre-commit
|
||||||
|
|
@ -46,31 +47,28 @@ jobs:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
arduino-platform:
|
arduino-platform:
|
||||||
# ESP32S3
|
# ESP32 ci use dev json
|
||||||
- 'feather_esp32s3'
|
- 'feather_esp32_v2'
|
||||||
# ESP32S2
|
|
||||||
- 'feather_esp32s2'
|
- 'feather_esp32s2'
|
||||||
|
- 'feather_esp32s3'
|
||||||
|
- 'esp32p4'
|
||||||
# nRF52
|
# nRF52
|
||||||
- 'cpb'
|
- 'cpb'
|
||||||
- 'nrf52840'
|
- 'nrf52840'
|
||||||
# RP2040
|
# RP2040
|
||||||
- 'feather_rp2040_tinyusb'
|
- 'feather_rp2040_tinyusb'
|
||||||
|
- 'pico_rp2040_tinyusb_host'
|
||||||
# SAMD
|
# SAMD
|
||||||
- 'feather_m4_can_tinyusb'
|
|
||||||
- 'metro_m0_tinyusb'
|
- 'metro_m0_tinyusb'
|
||||||
- 'metro_m4_tinyusb'
|
- 'metro_m4_tinyusb'
|
||||||
|
# Ch32v2
|
||||||
|
- 'CH32V20x_EVT'
|
||||||
steps:
|
steps:
|
||||||
- name: Setup Python
|
|
||||||
uses: actions/setup-python@v4
|
|
||||||
with:
|
|
||||||
python-version: '3.x'
|
|
||||||
|
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Checkout adafruit/ci-arduino
|
- name: Checkout adafruit/ci-arduino
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
repository: adafruit/ci-arduino
|
repository: adafruit/ci-arduino
|
||||||
path: ci
|
path: ci
|
||||||
|
|
@ -78,8 +76,10 @@ jobs:
|
||||||
- name: pre-install
|
- name: pre-install
|
||||||
run: bash ci/actions_install.sh
|
run: bash ci/actions_install.sh
|
||||||
|
|
||||||
- name: Install Libraries for building examples
|
- name: Install Libraries
|
||||||
run: arduino-cli lib install "Adafruit SPIFlash" "MIDI Library" "Adafruit seesaw Library" "Adafruit NeoPixel" "SdFat - Adafruit Fork" "SD" "Adafruit Circuit Playground" "Adafruit InternalFlash" "Pico PIO USB"
|
run: |
|
||||||
|
arduino-cli lib install ${{ env.ARDUINO_LIBS }}
|
||||||
|
arduino-cli lib list
|
||||||
|
|
||||||
- name: test platforms
|
- name: test platforms
|
||||||
run: python3 ci/build_platform.py ${{ matrix.arduino-platform }}
|
run: python3 ci/build_platform.py ${{ matrix.arduino-platform }}
|
||||||
|
|
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1,2 +1,5 @@
|
||||||
/examples/**/build/
|
/examples/**/build/
|
||||||
/.development
|
/.development
|
||||||
|
.idea
|
||||||
|
platformio.ini
|
||||||
|
.pio/
|
||||||
|
|
|
||||||
14
README.md
14
README.md
|
|
@ -15,15 +15,18 @@ Supported device class drivers are:
|
||||||
- Human Interface Device (HID): Generic (In & Out), Keyboard, Mouse, Gamepad etc ...
|
- Human Interface Device (HID): Generic (In & Out), Keyboard, Mouse, Gamepad etc ...
|
||||||
- Mass Storage Class (MSC): with multiple LUNs
|
- Mass Storage Class (MSC): with multiple LUNs
|
||||||
- Musical Instrument Digital Interface (MIDI)
|
- Musical Instrument Digital Interface (MIDI)
|
||||||
|
- Video (UVC): work in progress
|
||||||
- WebUSB with vendor specific class
|
- WebUSB with vendor specific class
|
||||||
|
|
||||||
### Host Stack
|
### Host Stack
|
||||||
|
|
||||||
Host support is still work-in-progress but currently available with rp2040 core thanks to [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB). Supported class driver are:
|
Host stack is available with either addition of MAX3421E hardware (e.g [Host FeatherWing](https://www.adafruit.com/product/5858)) or rp2040 core (thanks to [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB)). Supported class driver are:
|
||||||
|
|
||||||
- Communication (CDC)
|
- Communication (CDC): including vendor usb2uart such as FTDI, CP210x, CH34x
|
||||||
- MassStorage class
|
- MassStorage class
|
||||||
|
|
||||||
|
Note: Host stack is still work-in-progress
|
||||||
|
|
||||||
## Supported Cores
|
## Supported Cores
|
||||||
|
|
||||||
There are 2 type of supported cores: with and without built-in support for TinyUSB. Built-in support provide seamless integration but requires extra code added to core's source code. Unfortunately it is not always easy or possible to make those modification.
|
There are 2 type of supported cores: with and without built-in support for TinyUSB. Built-in support provide seamless integration but requires extra code added to core's source code. Unfortunately it is not always easy or possible to make those modification.
|
||||||
|
|
@ -35,9 +38,12 @@ Following core has TinyUSB as either the primary usb stack or selectable via men
|
||||||
- [adafruit/Adafruit_nRF52_Arduino](https://github.com/adafruit/Adafruit_nRF52_Arduino)
|
- [adafruit/Adafruit_nRF52_Arduino](https://github.com/adafruit/Adafruit_nRF52_Arduino)
|
||||||
- [adafruit/ArduinoCore-samd](https://github.com/adafruit/ArduinoCore-samd)
|
- [adafruit/ArduinoCore-samd](https://github.com/adafruit/ArduinoCore-samd)
|
||||||
- [earlephilhower/arduino-pico](https://github.com/earlephilhower/arduino-pico)
|
- [earlephilhower/arduino-pico](https://github.com/earlephilhower/arduino-pico)
|
||||||
- [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32)
|
- [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) Host mode using MAX3421E controller should work with all chips. Device mode only support S2/S3/P4 and additional Tools menu are needed
|
||||||
|
- `USB Mode=USB-OTG (TinyUSB)` for S3 and P4
|
||||||
|
- `USB CDC On Boot=Enabled`, `USB Firmware MSC On Boot=Disabled`, `USB DFU On Boot=Disabled`
|
||||||
|
- [openwch/arduino_core_ch32](https://github.com/openwch/arduino_core_ch32)
|
||||||
|
|
||||||
ESP32 port relies on Espressif's [esp32-hal-tinyusb.c](https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-tinyusb.c) for building usb descriptors which requires all descriptors must be specified in usb objects declaration i.e constructors. Therefore all descriptor-related fields must be part of object declaration and descriptor-related API have no effect afterwards for this port.
|
Note: For ESP32 port, version before v3.0 requires all descriptors must be specified in usb objects declaration i.e constructors. Therefore all descriptor-related fields must be part of object declaration and descriptor-related API have no effect afterwards. This limitation is not the case for version from v3.0.
|
||||||
|
|
||||||
### Cores without built-in support
|
### Cores without built-in support
|
||||||
|
|
||||||
|
|
|
||||||
8
examples/CDC/cdc_multi/.skip.txt
Normal file
8
examples/CDC/cdc_multi/.skip.txt
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
feather_esp32_v2
|
||||||
|
feather_esp32s2
|
||||||
|
feather_esp32s3
|
||||||
|
funhouse
|
||||||
|
magtag
|
||||||
|
metroesp32s2
|
||||||
|
esp32p4
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
|
@ -25,11 +25,9 @@
|
||||||
|
|
||||||
#include <Adafruit_TinyUSB.h>
|
#include <Adafruit_TinyUSB.h>
|
||||||
|
|
||||||
#define LED LED_BUILTIN
|
|
||||||
|
|
||||||
// Create 2nd instance of CDC Ports.
|
// Create 2nd instance of CDC Ports.
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
#error "Currnetly multiple CDCs on ESP32-Sx is not yet supported. An PR to update core/esp32/USBCDC and/or pre-built libusb are needed."
|
#error "Currently multiple CDCs on ESP32 is not yet supported"
|
||||||
// for ESP32, we need to specify instance number when declaring object
|
// for ESP32, we need to specify instance number when declaring object
|
||||||
Adafruit_USBD_CDC USBSer1(1);
|
Adafruit_USBD_CDC USBSer1(1);
|
||||||
#else
|
#else
|
||||||
|
|
@ -37,13 +35,17 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
pinMode(LED, OUTPUT);
|
#ifdef LED_BUILTIN
|
||||||
|
pinMode(LED_BUILTIN, OUTPUT);
|
||||||
|
#endif
|
||||||
|
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
// check to see if multiple CDCs are enabled
|
// check to see if multiple CDCs are enabled
|
||||||
if ( CFG_TUD_CDC < 2 ) {
|
if ( CFG_TUD_CDC < 2 ) {
|
||||||
digitalWrite(LED, HIGH); // LED on for error indicator
|
#ifdef LED_BUILTIN
|
||||||
|
digitalWrite(LED_BUILTIN, HIGH); // LED on for error indicator
|
||||||
|
#endif
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
Serial.printf("CFG_TUD_CDC must be at least 2, current value is %u\n", CFG_TUD_CDC);
|
Serial.printf("CFG_TUD_CDC must be at least 2, current value is %u\n", CFG_TUD_CDC);
|
||||||
|
|
@ -56,6 +58,13 @@ void setup() {
|
||||||
// initialize 2nd CDC interface
|
// initialize 2nd CDC interface
|
||||||
USBSer1.begin(115200);
|
USBSer1.begin(115200);
|
||||||
|
|
||||||
|
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
|
||||||
|
if (TinyUSBDevice.mounted()) {
|
||||||
|
TinyUSBDevice.detach();
|
||||||
|
delay(10);
|
||||||
|
TinyUSBDevice.attach();
|
||||||
|
}
|
||||||
|
|
||||||
while (!Serial || !USBSer1) {
|
while (!Serial || !USBSer1) {
|
||||||
if (Serial) {
|
if (Serial) {
|
||||||
Serial.println("Waiting for other USB ports");
|
Serial.println("Waiting for other USB ports");
|
||||||
|
|
@ -89,7 +98,9 @@ void loop() {
|
||||||
|
|
||||||
if (delay_without_delaying(500)) {
|
if (delay_without_delaying(500)) {
|
||||||
LEDstate = !LEDstate;
|
LEDstate = !LEDstate;
|
||||||
digitalWrite(LED, LEDstate);
|
#ifdef LED_BUILTIN
|
||||||
|
digitalWrite(LED_BUILTIN, LEDstate);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
2
examples/CDC/no_serial/.skip.txt
Normal file
2
examples/CDC/no_serial/.skip.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
feather_esp32_v2
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
|
@ -18,19 +18,40 @@
|
||||||
* Note: this will cause device to loose the touch1200 and require
|
* Note: this will cause device to loose the touch1200 and require
|
||||||
* user manual interaction to put device into bootloader/DFU mode.
|
* user manual interaction to put device into bootloader/DFU mode.
|
||||||
*/
|
*/
|
||||||
|
void setup() {
|
||||||
|
// Manual begin() is required on core without built-in support e.g. mbed rp2040
|
||||||
|
if (!TinyUSBDevice.isInitialized()) {
|
||||||
|
TinyUSBDevice.begin(0);
|
||||||
|
}
|
||||||
|
|
||||||
int led = LED_BUILTIN;
|
// clear configuration will remove all USB interfaces including CDC (Serial)
|
||||||
|
TinyUSBDevice.clearConfiguration();
|
||||||
|
|
||||||
void setup()
|
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
|
||||||
{
|
if (TinyUSBDevice.mounted()) {
|
||||||
Serial.end();
|
TinyUSBDevice.detach();
|
||||||
pinMode(led, OUTPUT);
|
delay(10);
|
||||||
|
TinyUSBDevice.attach();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LED_BUILTIN
|
||||||
|
pinMode(LED_BUILTIN, OUTPUT);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop() {
|
||||||
{
|
#ifdef TINYUSB_NEED_POLLING_TASK
|
||||||
digitalWrite(led, HIGH);
|
// Manual call tud_task since it isn't called by Core's background
|
||||||
delay(1000);
|
TinyUSBDevice.task();
|
||||||
digitalWrite(led, LOW);
|
#endif
|
||||||
delay(1000);
|
|
||||||
|
// toggle LED
|
||||||
|
static uint32_t ms = 0;
|
||||||
|
static uint8_t led_state = 0;
|
||||||
|
if (millis() - ms > 1000) {
|
||||||
|
ms = millis();
|
||||||
|
#ifdef LED_BUILTIN
|
||||||
|
digitalWrite(LED_BUILTIN, 1-led_state);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
examples/CDC/serial_echo/.skip.txt
Normal file
2
examples/CDC/serial_echo/.skip.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
feather_esp32_v2
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
41
examples/CDC/serial_echo/serial_echo.ino
Normal file
41
examples/CDC/serial_echo/serial_echo.ino
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*********************************************************************
|
||||||
|
Adafruit invests time and resources providing this open source code,
|
||||||
|
please support Adafruit and open-source hardware by purchasing
|
||||||
|
products from Adafruit!
|
||||||
|
|
||||||
|
MIT license, check LICENSE for more information
|
||||||
|
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||||
|
All text above, and the splash screen below must be included in
|
||||||
|
any redistribution
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#include "Adafruit_TinyUSB.h"
|
||||||
|
|
||||||
|
/* This sketch demonstrates USB CDC Serial echo (convert to upper case) using SerialTinyUSB which
|
||||||
|
* is available for both core with built-in USB support and without.
|
||||||
|
* Note: on core with built-in support Serial is alias to SerialTinyUSB
|
||||||
|
*/
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// Manual begin() is required on core without built-in support e.g. mbed rp2040
|
||||||
|
if (!TinyUSBDevice.isInitialized()) {
|
||||||
|
TinyUSBDevice.begin(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
#ifdef TINYUSB_NEED_POLLING_TASK
|
||||||
|
// Manual call tud_task since it isn't called by Core's background
|
||||||
|
TinyUSBDevice.task();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint8_t buf[64];
|
||||||
|
uint32_t count = 0;
|
||||||
|
while (SerialTinyUSB.available()) {
|
||||||
|
buf[count++] = (uint8_t) toupper(SerialTinyUSB.read());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count) {
|
||||||
|
SerialTinyUSB.write(buf, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,192 +0,0 @@
|
||||||
/*********************************************************************
|
|
||||||
Adafruit invests time and resources providing this open source code,
|
|
||||||
please support Adafruit and open-source hardware by purchasing
|
|
||||||
products from Adafruit!
|
|
||||||
|
|
||||||
MIT license, check LICENSE for more information
|
|
||||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
|
||||||
All text above, and the splash screen below must be included in
|
|
||||||
any redistribution
|
|
||||||
*********************************************************************/
|
|
||||||
|
|
||||||
/* This sketch demonstrates USB Mass Storage and HID mouse (and CDC)
|
|
||||||
* - Enumerated as disk using on-board external flash
|
|
||||||
* - Press button pin will move mouse toward bottom right of monitor
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "SPI.h"
|
|
||||||
#include "SdFat.h"
|
|
||||||
#include "Adafruit_SPIFlash.h"
|
|
||||||
#include "Adafruit_TinyUSB.h"
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
// MSC External Flash Config
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
|
|
||||||
// Un-comment to run example with custom SPI SPI and SS e.g with FRAM breakout
|
|
||||||
// #define CUSTOM_CS A5
|
|
||||||
// #define CUSTOM_SPI SPI
|
|
||||||
|
|
||||||
#if defined(CUSTOM_CS) && defined(CUSTOM_SPI)
|
|
||||||
Adafruit_FlashTransport_SPI flashTransport(CUSTOM_CS, CUSTOM_SPI);
|
|
||||||
|
|
||||||
#elif defined(ARDUINO_ARCH_ESP32)
|
|
||||||
// ESP32 use same flash device that store code.
|
|
||||||
// Therefore there is no need to specify the SPI and SS
|
|
||||||
Adafruit_FlashTransport_ESP32 flashTransport;
|
|
||||||
|
|
||||||
#elif defined(ARDUINO_ARCH_RP2040)
|
|
||||||
// RP2040 use same flash device that store code.
|
|
||||||
// Therefore there is no need to specify the SPI and SS
|
|
||||||
// Use default (no-args) constructor to be compatible with CircuitPython partition scheme
|
|
||||||
Adafruit_FlashTransport_RP2040 flashTransport;
|
|
||||||
|
|
||||||
// For generic usage:
|
|
||||||
// Adafruit_FlashTransport_RP2040 flashTransport(start_address, size)
|
|
||||||
// If start_address and size are both 0, value that match filesystem setting in
|
|
||||||
// 'Tools->Flash Size' menu selection will be used
|
|
||||||
|
|
||||||
#else
|
|
||||||
// On-board external flash (QSPI or SPI) macros should already
|
|
||||||
// defined in your board variant if supported
|
|
||||||
// - EXTERNAL_FLASH_USE_QSPI
|
|
||||||
// - EXTERNAL_FLASH_USE_CS/EXTERNAL_FLASH_USE_SPI
|
|
||||||
#if defined(EXTERNAL_FLASH_USE_QSPI)
|
|
||||||
Adafruit_FlashTransport_QSPI flashTransport;
|
|
||||||
|
|
||||||
#elif defined(EXTERNAL_FLASH_USE_SPI)
|
|
||||||
Adafruit_FlashTransport_SPI flashTransport(EXTERNAL_FLASH_USE_CS, EXTERNAL_FLASH_USE_SPI);
|
|
||||||
|
|
||||||
#else
|
|
||||||
#error No QSPI/SPI flash are defined on your board variant.h !
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Adafruit_SPIFlash flash(&flashTransport);
|
|
||||||
|
|
||||||
Adafruit_USBD_MSC usb_msc;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
// HID Config
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
|
|
||||||
// HID report descriptor using TinyUSB's template
|
|
||||||
// Single Report (no ID) descriptor
|
|
||||||
uint8_t const desc_hid_report[] =
|
|
||||||
{
|
|
||||||
TUD_HID_REPORT_DESC_MOUSE()
|
|
||||||
};
|
|
||||||
|
|
||||||
// USB HID object. For ESP32 these values cannot be changed after this declaration
|
|
||||||
// desc report, desc len, protocol, interval, use out endpoint
|
|
||||||
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_NONE, 2, false);
|
|
||||||
|
|
||||||
#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY)
|
|
||||||
const int pin = 4; // Left Button
|
|
||||||
bool activeState = true;
|
|
||||||
|
|
||||||
#elif defined(ARDUINO_FUNHOUSE_ESP32S2)
|
|
||||||
const int pin = BUTTON_DOWN;
|
|
||||||
bool activeState = true;
|
|
||||||
|
|
||||||
#elif defined PIN_BUTTON1
|
|
||||||
const int pin = PIN_BUTTON1;
|
|
||||||
bool activeState = false;
|
|
||||||
|
|
||||||
#else
|
|
||||||
const int pin = 12;
|
|
||||||
bool activeState = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// the setup function runs once when you press reset or power the board
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
flash.begin();
|
|
||||||
|
|
||||||
pinMode(LED_BUILTIN, OUTPUT);
|
|
||||||
|
|
||||||
// Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
|
|
||||||
usb_msc.setID("Adafruit", "External Flash", "1.0");
|
|
||||||
|
|
||||||
// Set callback
|
|
||||||
usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb);
|
|
||||||
|
|
||||||
// Set disk size, block size should be 512 regardless of spi flash page size
|
|
||||||
usb_msc.setCapacity(flash.size()/512, 512);
|
|
||||||
|
|
||||||
// MSC is ready for read/write
|
|
||||||
usb_msc.setUnitReady(true);
|
|
||||||
|
|
||||||
usb_msc.begin();
|
|
||||||
|
|
||||||
// Set up button
|
|
||||||
pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
|
|
||||||
|
|
||||||
// Notes: following commented-out functions has no affect on ESP32
|
|
||||||
// usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
|
||||||
|
|
||||||
usb_hid.begin();
|
|
||||||
|
|
||||||
Serial.begin(115200);
|
|
||||||
//while ( !Serial ) delay(10); // wait for native usb
|
|
||||||
|
|
||||||
Serial.println("Adafruit TinyUSB Mouse + Mass Storage (external flash) example");
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
// poll gpio once each 10 ms
|
|
||||||
delay(10);
|
|
||||||
|
|
||||||
// button is active low
|
|
||||||
uint32_t const btn = (digitalRead(pin) == activeState);
|
|
||||||
|
|
||||||
// Remote wakeup
|
|
||||||
if ( TinyUSBDevice.suspended() && btn )
|
|
||||||
{
|
|
||||||
// Wake up host if we are in suspend mode
|
|
||||||
// and REMOTE_WAKEUP feature is enabled by host
|
|
||||||
tud_remote_wakeup();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*------------- Mouse -------------*/
|
|
||||||
if ( usb_hid.ready() )
|
|
||||||
{
|
|
||||||
if ( btn )
|
|
||||||
{
|
|
||||||
int8_t const delta = 5;
|
|
||||||
usb_hid.mouseMove(0, delta, delta); // no ID: right + down
|
|
||||||
|
|
||||||
// delay a bit before attempt to send keyboard report
|
|
||||||
delay(10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Callback invoked when received READ10 command.
|
|
||||||
// Copy disk's data to buffer (up to bufsize) and
|
|
||||||
// return number of copied bytes (must be multiple of block size)
|
|
||||||
int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
|
||||||
{
|
|
||||||
// Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
|
|
||||||
// already include 4K sector caching internally. We don't need to cache it, yahhhh!!
|
|
||||||
return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Callback invoked when received WRITE10 command.
|
|
||||||
// Process data in buffer to disk's storage and
|
|
||||||
// return number of written bytes (must be multiple of block size)
|
|
||||||
int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
|
||||||
{
|
|
||||||
// Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
|
|
||||||
// already include 4K sector caching internally. We don't need to cache it, yahhhh!!
|
|
||||||
return flash.writeBlocks(lba, buffer, bufsize/512) ? bufsize : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
|
||||||
// used to flush any pending cache.
|
|
||||||
void msc_flush_cb (void)
|
|
||||||
{
|
|
||||||
flash.syncBlocks();
|
|
||||||
}
|
|
||||||
2
examples/Composite/mouse_ramdisk/.skip.txt
Normal file
2
examples/Composite/mouse_ramdisk/.skip.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
feather_esp32_v2
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
// 8KB is the smallest size that windows allow to mount
|
// 8KB is the smallest size that windows allow to mount
|
||||||
#define DISK_BLOCK_NUM 16
|
#define DISK_BLOCK_NUM 16
|
||||||
#define DISK_BLOCK_SIZE 512
|
#define DISK_BLOCK_SIZE 512
|
||||||
|
|
||||||
#include "ramdisk.h"
|
#include "ramdisk.h"
|
||||||
|
|
||||||
Adafruit_USBD_MSC usb_msc;
|
Adafruit_USBD_MSC usb_msc;
|
||||||
|
|
@ -33,39 +34,47 @@ Adafruit_USBD_MSC usb_msc;
|
||||||
|
|
||||||
// HID report descriptor using TinyUSB's template
|
// HID report descriptor using TinyUSB's template
|
||||||
// Single Report (no ID) descriptor
|
// Single Report (no ID) descriptor
|
||||||
uint8_t const desc_hid_report[] =
|
uint8_t const desc_hid_report[] = {
|
||||||
{
|
|
||||||
TUD_HID_REPORT_DESC_MOUSE()
|
TUD_HID_REPORT_DESC_MOUSE()
|
||||||
};
|
};
|
||||||
|
|
||||||
// USB HID object. For ESP32 these values cannot be changed after this declaration
|
// USB HID object
|
||||||
// desc report, desc len, protocol, interval, use out endpoint
|
Adafruit_USBD_HID usb_hid;
|
||||||
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_NONE, 2, false);
|
|
||||||
|
|
||||||
#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY)
|
#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY)
|
||||||
const int pin = 4; // Left Button
|
const int pin = 4; // Left Button
|
||||||
bool activeState = true;
|
bool activeState = true;
|
||||||
|
|
||||||
#elif defined(ARDUINO_FUNHOUSE_ESP32S2)
|
#elif defined(ARDUINO_FUNHOUSE_ESP32S2)
|
||||||
const int pin = BUTTON_DOWN;
|
const int pin = BUTTON_DOWN;
|
||||||
bool activeState = true;
|
bool activeState = true;
|
||||||
|
|
||||||
#elif defined PIN_BUTTON1
|
#elif defined PIN_BUTTON1
|
||||||
const int pin = PIN_BUTTON1;
|
const int pin = PIN_BUTTON1;
|
||||||
bool activeState = false;
|
bool activeState = false;
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_ESP32)
|
||||||
|
const int pin = 0;
|
||||||
|
bool activeState = false;
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_RP2040)
|
||||||
|
const int pin = D0;
|
||||||
|
bool activeState = false;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
const int pin = 12;
|
const int pin = A0;
|
||||||
bool activeState = false;
|
bool activeState = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// the setup function runs once when you press reset or power the board
|
// the setup function runs once when you press reset or power the board
|
||||||
void setup()
|
void setup() {
|
||||||
{
|
// Manual begin() is required on core without built-in support e.g. mbed rp2040
|
||||||
#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
|
if (!TinyUSBDevice.isInitialized()) {
|
||||||
// Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
|
TinyUSBDevice.begin(0);
|
||||||
TinyUSB_Device_Init(0);
|
}
|
||||||
#endif
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
// Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
|
// Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
|
||||||
usb_msc.setID("Adafruit", "Mass Storage", "1.0");
|
usb_msc.setID("Adafruit", "Mass Storage", "1.0");
|
||||||
|
|
@ -84,38 +93,36 @@ void setup()
|
||||||
// Set up button
|
// Set up button
|
||||||
pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
|
pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
|
||||||
|
|
||||||
// Notes: following commented-out functions has no affect on ESP32
|
// Set up HID
|
||||||
// usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
||||||
|
usb_hid.setBootProtocol(HID_ITF_PROTOCOL_NONE);
|
||||||
|
usb_hid.setPollInterval(2);
|
||||||
usb_hid.begin();
|
usb_hid.begin();
|
||||||
|
|
||||||
Serial.begin(115200);
|
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
|
||||||
while( !TinyUSBDevice.mounted() ) delay(1); // wait for native usb
|
if (TinyUSBDevice.mounted()) {
|
||||||
|
TinyUSBDevice.detach();
|
||||||
|
delay(10);
|
||||||
|
TinyUSBDevice.attach();
|
||||||
|
}
|
||||||
|
|
||||||
Serial.println("Adafruit TinyUSB Mouse + Mass Storage (ramdisk) example");
|
Serial.println("Adafruit TinyUSB Mouse + Mass Storage (ramdisk) example");
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void process_hid() {
|
||||||
{
|
|
||||||
// poll gpio once each 10 ms
|
|
||||||
delay(10);
|
|
||||||
|
|
||||||
// button is active low
|
// button is active low
|
||||||
uint32_t const btn = (digitalRead(pin) == activeState);
|
uint32_t const btn = (digitalRead(pin) == activeState);
|
||||||
|
|
||||||
// Remote wakeup
|
// Remote wakeup
|
||||||
if ( TinyUSBDevice.suspended() && btn )
|
if (TinyUSBDevice.suspended() && btn) {
|
||||||
{
|
|
||||||
// Wake up host if we are in suspend mode
|
// Wake up host if we are in suspend mode
|
||||||
// and REMOTE_WAKEUP feature is enabled by host
|
// and REMOTE_WAKEUP feature is enabled by host
|
||||||
tud_remote_wakeup();
|
tud_remote_wakeup();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------- Mouse -------------*/
|
/*------------- Mouse -------------*/
|
||||||
if ( usb_hid.ready() )
|
if (usb_hid.ready()) {
|
||||||
{
|
if (btn) {
|
||||||
if ( btn )
|
|
||||||
{
|
|
||||||
int8_t const delta = 5;
|
int8_t const delta = 5;
|
||||||
usb_hid.mouseMove(0, delta, delta); // no ID: right + down
|
usb_hid.mouseMove(0, delta, delta); // no ID: right + down
|
||||||
|
|
||||||
|
|
@ -125,11 +132,29 @@ void loop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
#ifdef TINYUSB_NEED_POLLING_TASK
|
||||||
|
// Manual call tud_task since it isn't called by Core's background
|
||||||
|
TinyUSBDevice.task();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// not enumerated()/mounted() yet: nothing to do
|
||||||
|
if (!TinyUSBDevice.mounted()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// poll gpio once each 10 ms
|
||||||
|
static uint32_t ms = 0;
|
||||||
|
if (millis() - ms > 10) {
|
||||||
|
ms = millis();
|
||||||
|
process_hid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Callback invoked when received READ10 command.
|
// Callback invoked when received READ10 command.
|
||||||
// Copy disk's data to buffer (up to bufsize) and
|
// Copy disk's data to buffer (up to bufsize) and
|
||||||
// return number of copied bytes (must be multiple of block size)
|
// return number of copied bytes (must be multiple of block size)
|
||||||
int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
int32_t msc_read_cb(uint32_t lba, void* buffer, uint32_t bufsize) {
|
||||||
{
|
|
||||||
uint8_t const* addr = msc_disk[lba];
|
uint8_t const* addr = msc_disk[lba];
|
||||||
memcpy(buffer, addr, bufsize);
|
memcpy(buffer, addr, bufsize);
|
||||||
|
|
||||||
|
|
@ -139,8 +164,7 @@ int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||||
// Callback invoked when received WRITE10 command.
|
// Callback invoked when received WRITE10 command.
|
||||||
// Process data in buffer to disk's storage and
|
// Process data in buffer to disk's storage and
|
||||||
// return number of written bytes (must be multiple of block size)
|
// return number of written bytes (must be multiple of block size)
|
||||||
int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
int32_t msc_write_cb(uint32_t lba, uint8_t* buffer, uint32_t bufsize) {
|
||||||
{
|
|
||||||
uint8_t* addr = msc_disk[lba];
|
uint8_t* addr = msc_disk[lba];
|
||||||
memcpy(addr, buffer, bufsize);
|
memcpy(addr, buffer, bufsize);
|
||||||
|
|
||||||
|
|
@ -149,7 +173,6 @@ int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
||||||
|
|
||||||
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
||||||
// used to flush any pending cache.
|
// used to flush any pending cache.
|
||||||
void msc_flush_cb (void)
|
void msc_flush_cb(void) {
|
||||||
{
|
|
||||||
// nothing to do
|
// nothing to do
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
examples/DualRole/CDC/serial_host_bridge/.skip.txt
Normal file
2
examples/DualRole/CDC/serial_host_bridge/.skip.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
CH32V20x_EVT
|
||||||
|
|
@ -9,154 +9,162 @@
|
||||||
any redistribution
|
any redistribution
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
|
|
||||||
|
/* This example demonstrates use of both device and host, where
|
||||||
|
* - Device run on native usb controller (roothub port0)
|
||||||
|
* - Host depending on MCUs run on either:
|
||||||
|
* - rp2040: bit-banging 2 GPIOs with the help of Pico-PIO-USB library (roothub port1)
|
||||||
|
* - samd21/51, nrf52840, esp32: using MAX3421e controller (host shield)
|
||||||
|
*
|
||||||
|
* Requirements:
|
||||||
|
* - For rp2040:
|
||||||
|
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
|
||||||
|
* - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1
|
||||||
|
* - Provide VBus (5v) and GND for peripheral
|
||||||
|
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
|
||||||
|
* - For samd21/51, nrf52840, esp32:
|
||||||
|
* - Additional MAX2341e USB Host shield or featherwing is required
|
||||||
|
* - SPI instance, CS pin, INT pin are correctly configured in usbh_helper.h
|
||||||
|
*/
|
||||||
|
|
||||||
/* This example demonstrates use of Host Serial (CDC). SerialHost (declared below) is
|
/* This example demonstrates use of Host Serial (CDC). SerialHost (declared below) is
|
||||||
* an object to manage an CDC peripheral connected to our USB Host connector. This example
|
* an object to manage an CDC peripheral connected to our USB Host connector. This example
|
||||||
* will forward all characters from Serial to SerialHost and vice versa.
|
* will forward all characters from Serial to SerialHost and vice versa.
|
||||||
*
|
|
||||||
* Note:
|
|
||||||
* - Device run on native usb controller (controller0)
|
|
||||||
* - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
|
|
||||||
|
|
||||||
* Requirements:
|
|
||||||
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
|
|
||||||
* - 2 consecutive GPIOs: D+ is defined by PIN_PIO_USB_HOST_DP, D- = D+ +1
|
|
||||||
* - Provide VBus (5v) and GND for peripheral
|
|
||||||
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// pio-usb is required for rp2040 host
|
// nRF52 and ESP32 use freeRTOS, we may need to run USBhost.task() in its own rtos's thread.
|
||||||
#include "pio_usb.h"
|
// Since USBHost.task() will put loop() into dormant state and prevent followed code from running
|
||||||
|
// until there is USB host event.
|
||||||
// TinyUSB lib
|
#if defined(ARDUINO_NRF52_ADAFRUIT) || defined(ARDUINO_ARCH_ESP32)
|
||||||
#include "Adafruit_TinyUSB.h"
|
#define USE_FREERTOS
|
||||||
|
|
||||||
// Pin D+ for host, D- = D+ + 1
|
|
||||||
#ifndef PIN_PIO_USB_HOST_DP
|
|
||||||
#define PIN_PIO_USB_HOST_DP 20
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Pin for enabling Host VBUS. comment out if not used
|
// USBHost is defined in usbh_helper.h
|
||||||
#ifndef PIN_PIO_USB_HOST_VBUSEN
|
#include "usbh_helper.h"
|
||||||
#define PIN_PIO_USB_HOST_VBUSEN 22
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef PIN_PIO_USB_HOST_VBUSEN_STATE
|
|
||||||
#define PIN_PIO_USB_HOST_VBUSEN_STATE 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// USB Host object
|
|
||||||
Adafruit_USBH_Host USBHost;
|
|
||||||
|
|
||||||
// CDC Host object
|
// CDC Host object
|
||||||
Adafruit_USBH_CDC SerialHost;
|
Adafruit_USBH_CDC SerialHost;
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
// forward Seral <-> SerialHost
|
||||||
// Setup and Loop on Core0
|
void forward_serial(void) {
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Serial1.begin(115200);
|
|
||||||
|
|
||||||
Serial.begin(115200);
|
|
||||||
while ( !Serial ) delay(10); // wait for native usb
|
|
||||||
|
|
||||||
Serial.println("TinyUSB Host Serial Echo Example");
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
uint8_t buf[64];
|
uint8_t buf[64];
|
||||||
|
|
||||||
// Serial -> SerialHost
|
// Serial -> SerialHost
|
||||||
if (Serial.available()) {
|
if (Serial.available()) {
|
||||||
size_t count = Serial.read(buf, sizeof(buf));
|
size_t count = Serial.read(buf, sizeof(buf));
|
||||||
if ( SerialHost && SerialHost.connected() ) {
|
if (SerialHost && SerialHost.connected()) {
|
||||||
SerialHost.write(buf, count);
|
SerialHost.write(buf, count);
|
||||||
SerialHost.flush();
|
SerialHost.flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SerialHost -> Serial
|
// SerialHost -> Serial
|
||||||
if ( SerialHost.connected() && SerialHost.available() ) {
|
if (SerialHost.connected() && SerialHost.available()) {
|
||||||
size_t count = SerialHost.read(buf, sizeof(buf));
|
size_t count = SerialHost.read(buf, sizeof(buf));
|
||||||
Serial.write(buf, count);
|
Serial.write(buf, count);
|
||||||
|
Serial.flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// Setup and Loop on Core1
|
// Using Host shield MAX3421E controller
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
void setup1() {
|
#ifdef USE_FREERTOS
|
||||||
while ( !Serial ) delay(10); // wait for native usb
|
|
||||||
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
|
|
||||||
|
|
||||||
// Check for CPU frequency, must be multiple of 120Mhz for bit-banging USB
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
uint32_t cpu_hz = clock_get_hz(clk_sys);
|
#define USBH_STACK_SZ 2048
|
||||||
if ( cpu_hz != 120000000UL && cpu_hz != 240000000UL ) {
|
#else
|
||||||
while ( !Serial ) {
|
#define USBH_STACK_SZ 200
|
||||||
delay(10); // wait for native usb
|
|
||||||
}
|
|
||||||
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
|
|
||||||
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n");
|
|
||||||
while(1) {
|
|
||||||
delay(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef PIN_PIO_USB_HOST_VBUSEN
|
|
||||||
pinMode(PIN_PIO_USB_HOST_VBUSEN, OUTPUT);
|
|
||||||
|
|
||||||
// power off first
|
|
||||||
digitalWrite(PIN_PIO_USB_HOST_VBUSEN, 1-PIN_PIO_USB_HOST_VBUSEN_STATE);
|
|
||||||
delay(1);
|
|
||||||
|
|
||||||
// power on
|
|
||||||
digitalWrite(PIN_PIO_USB_HOST_VBUSEN, PIN_PIO_USB_HOST_VBUSEN_STATE);
|
|
||||||
delay(10);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
|
void usbhost_rtos_task(void *param) {
|
||||||
pio_cfg.pin_dp = PIN_PIO_USB_HOST_DP;
|
(void) param;
|
||||||
USBHost.configure_pio_usb(1, &pio_cfg);
|
while (1) {
|
||||||
|
USBHost.task();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
// init host stack on controller (rhport) 1
|
||||||
|
USBHost.begin(1);
|
||||||
|
|
||||||
|
// Initialize SerialHost
|
||||||
|
SerialHost.begin(115200);
|
||||||
|
|
||||||
|
#ifdef USE_FREERTOS
|
||||||
|
// Create a task to run USBHost.task() in background
|
||||||
|
xTaskCreate(usbhost_rtos_task, "usbh", USBH_STACK_SZ, NULL, 3, NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// while ( !Serial ) delay(10); // wait for native usb
|
||||||
|
Serial.println("TinyUSB Host Serial Echo Example");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
#ifndef USE_FREERTOS
|
||||||
|
USBHost.task();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
forward_serial();
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_RP2040)
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// For RP2040 use both core0 for device stack, core1 for host stack
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
//------------- Core0 -------------//
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
// while ( !Serial ) delay(10); // wait for native usb
|
||||||
|
Serial.println("TinyUSB Host Serial Echo Example");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
forward_serial();
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------- Core1 -------------//
|
||||||
|
void setup1() {
|
||||||
|
// configure pio-usb: defined in usbh_helper.h
|
||||||
|
rp2040_configure_pio_usb();
|
||||||
|
|
||||||
// run host stack on controller (rhport) 1
|
// run host stack on controller (rhport) 1
|
||||||
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
|
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
|
||||||
// host bit-banging processing works done in core1 to free up core0 for other works
|
// host bit-banging processing works done in core1 to free up core0 for other works
|
||||||
USBHost.begin(1);
|
USBHost.begin(1);
|
||||||
|
|
||||||
|
// Initialize SerialHost
|
||||||
|
SerialHost.begin(115200);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop1()
|
void loop1() {
|
||||||
{
|
|
||||||
USBHost.task();
|
USBHost.task();
|
||||||
|
|
||||||
// periodically flush SerialHost if connected
|
|
||||||
if ( SerialHost && SerialHost.connected() ) {
|
|
||||||
SerialHost.flush();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// TinyUSB Host callbacks
|
// TinyUSB Host callbacks
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
// Invoked when a device with CDC interface is mounted
|
// Invoked when a device with CDC interface is mounted
|
||||||
// idx is index of cdc interface in the internal pool.
|
// idx is index of cdc interface in the internal pool.
|
||||||
void tuh_cdc_mount_cb(uint8_t idx) {
|
void tuh_cdc_mount_cb(uint8_t idx) {
|
||||||
// bind SerialHost object to this interface index
|
// bind SerialHost object to this interface index
|
||||||
SerialHost.setInterfaceIndex(idx);
|
SerialHost.mount(idx);
|
||||||
SerialHost.begin(115200);
|
|
||||||
|
|
||||||
Serial.println("SerialHost is connected to a new CDC device");
|
Serial.println("SerialHost is connected to a new CDC device");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoked when a device with CDC interface is unmounted
|
// Invoked when a device with CDC interface is unmounted
|
||||||
void tuh_cdc_umount_cb(uint8_t idx) {
|
void tuh_cdc_umount_cb(uint8_t idx) {
|
||||||
if (idx == SerialHost.getInterfaceIndex()) {
|
SerialHost.umount(idx);
|
||||||
// unbind SerialHost if this interface is unmounted
|
|
||||||
SerialHost.end();
|
|
||||||
|
|
||||||
Serial.println("SerialHost is disconnected");
|
Serial.println("SerialHost is disconnected");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
99
examples/DualRole/CDC/serial_host_bridge/usbh_helper.h
Normal file
99
examples/DualRole/CDC/serial_host_bridge/usbh_helper.h
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
/*********************************************************************
|
||||||
|
Adafruit invests time and resources providing this open source code,
|
||||||
|
please support Adafruit and open-source hardware by purchasing
|
||||||
|
products from Adafruit!
|
||||||
|
|
||||||
|
MIT license, check LICENSE for more information
|
||||||
|
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||||
|
All text above, and the splash screen below must be included in
|
||||||
|
any redistribution
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#ifndef USBH_HELPER_H
|
||||||
|
#define USBH_HELPER_H
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_RP2040
|
||||||
|
// pio-usb is required for rp2040 host
|
||||||
|
#include "pio_usb.h"
|
||||||
|
|
||||||
|
// Pin D+ for host, D- = D+ + 1
|
||||||
|
#ifndef PIN_USB_HOST_DP
|
||||||
|
#define PIN_USB_HOST_DP 16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Pin for enabling Host VBUS. comment out if not used
|
||||||
|
#ifndef PIN_5V_EN
|
||||||
|
#define PIN_5V_EN 18
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PIN_5V_EN_STATE
|
||||||
|
#define PIN_5V_EN_STATE 1
|
||||||
|
#endif
|
||||||
|
#endif // ARDUINO_ARCH_RP2040
|
||||||
|
|
||||||
|
#include "Adafruit_TinyUSB.h"
|
||||||
|
|
||||||
|
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
|
// USB Host using MAX3421E: SPI, CS, INT
|
||||||
|
#include "SPI.h"
|
||||||
|
|
||||||
|
#if defined(ARDUINO_METRO_ESP32S2)
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 15, 14);
|
||||||
|
#elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2)
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 33, 15);
|
||||||
|
#else
|
||||||
|
// Default CS and INT are pin 10, 9
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 10, 9);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
// Native USB Host such as rp2040
|
||||||
|
Adafruit_USBH_Host USBHost;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Helper Functions
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_RP2040
|
||||||
|
static void rp2040_configure_pio_usb(void) {
|
||||||
|
//while ( !Serial ) delay(10); // wait for native usb
|
||||||
|
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
|
||||||
|
|
||||||
|
// Check for CPU frequency, must be multiple of 12 Mhz 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.printf("Change your CPU Clock to 12*n Mhz in Menu->CPU Speed \r\n");
|
||||||
|
while (1) {
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PIN_5V_EN
|
||||||
|
pinMode(PIN_5V_EN, OUTPUT);
|
||||||
|
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
|
||||||
|
pio_cfg.pin_dp = PIN_USB_HOST_DP;
|
||||||
|
|
||||||
|
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
|
||||||
|
// For pico-w, PIO is also used to communicate with cyw43
|
||||||
|
// Therefore we need to alternate the pio-usb configuration
|
||||||
|
// details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46
|
||||||
|
pio_cfg.sm_tx = 3;
|
||||||
|
pio_cfg.sm_rx = 2;
|
||||||
|
pio_cfg.sm_eop = 3;
|
||||||
|
pio_cfg.pio_rx_num = 0;
|
||||||
|
pio_cfg.pio_tx_num = 1;
|
||||||
|
pio_cfg.tx_ch = 9;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
USBHost.configure_pio_usb(1, &pio_cfg);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
2
examples/DualRole/HID/hid_device_report/.skip.txt
Normal file
2
examples/DualRole/HID/hid_device_report/.skip.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
CH32V20x_EVT
|
||||||
|
|
@ -11,83 +11,64 @@
|
||||||
|
|
||||||
|
|
||||||
/* This example demonstrates use of both device and host, where
|
/* This example demonstrates use of both device and host, where
|
||||||
* - Device run on native usb controller (controller0)
|
* - Device run on native usb controller (roothub port0)
|
||||||
* - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
|
* - Host depending on MCUs run on either:
|
||||||
|
* - rp2040: bit-banging 2 GPIOs with the help of Pico-PIO-USB library (roothub port1)
|
||||||
|
* - samd21/51, nrf52840, esp32: using MAX3421e controller (host shield)
|
||||||
*
|
*
|
||||||
* Requirements:
|
* Requirements:
|
||||||
|
* - For rp2040:
|
||||||
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
|
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
|
||||||
* - 2 consecutive GPIOs: D+ is defined by PIN_PIO_USB_HOST_DP, D- = D+ +1
|
* - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1
|
||||||
* - Provide VBus (5v) and GND for peripheral
|
* - Provide VBus (5v) and GND for peripheral
|
||||||
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
|
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
|
||||||
|
* - For samd21/51, nrf52840, esp32:
|
||||||
|
* - Additional MAX2341e USB Host shield or featherwing is required
|
||||||
|
* - SPI instance, CS pin, INT pin are correctly configured in usbh_helper.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// pio-usb is required for rp2040 host
|
// USBHost is defined in usbh_helper.h
|
||||||
#include "pio_usb.h"
|
#include "usbh_helper.h"
|
||||||
#include "Adafruit_TinyUSB.h"
|
|
||||||
|
|
||||||
// Pin D+ for host, D- = D+ + 1
|
|
||||||
#ifndef PIN_PIO_USB_HOST_DP
|
|
||||||
#define PIN_PIO_USB_HOST_DP 20
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Pin for enabling Host VBUS. comment out if not used
|
|
||||||
#ifndef PIN_PIO_USB_HOST_VBUSEN
|
|
||||||
#define PIN_PIO_USB_HOST_VBUSEN 22
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef PIN_PIO_USB_HOST_VBUSEN_STATE
|
|
||||||
#define PIN_PIO_USB_HOST_VBUSEN_STATE 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Language ID: English
|
|
||||||
#define LANGUAGE_ID 0x0409
|
|
||||||
|
|
||||||
// USB Host object
|
|
||||||
Adafruit_USBH_Host USBHost;
|
|
||||||
|
|
||||||
|
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// Setup and Loop on Core0
|
// Using Host shield MAX3421E controller
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
// init host stack on controller (rhport) 1
|
||||||
|
USBHost.begin(1);
|
||||||
|
|
||||||
|
// while ( !Serial ) delay(10); // wait for native usb
|
||||||
|
Serial.println("TinyUSB Dual: HID Device Report Example");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
USBHost.task();
|
||||||
|
Serial.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_RP2040)
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// For RP2040 use both core0 for device stack, core1 for host stack
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
void setup()
|
//------------- Core0 -------------//
|
||||||
{
|
void setup() {
|
||||||
Serial1.begin(115200);
|
|
||||||
|
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
//while ( !Serial ) delay(10); // wait for native usb
|
//while ( !Serial ) delay(10); // wait for native usb
|
||||||
|
Serial.println("TinyUSB Dual: HID Device Report Example");
|
||||||
Serial.println("TinyUSB Dual Device Info Example");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop() {
|
||||||
{
|
Serial.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//------------- Core1 -------------//
|
||||||
// Setup and Loop on Core1
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
|
|
||||||
void setup1() {
|
void setup1() {
|
||||||
//while ( !Serial ) delay(10); // wait for native usb
|
// configure pio-usb: defined in usbh_helper.h
|
||||||
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
|
rp2040_configure_pio_usb();
|
||||||
|
|
||||||
// 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 != 120000000UL && cpu_hz != 240000000UL ) {
|
|
||||||
while ( !Serial ) delay(10); // wait for native usb
|
|
||||||
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
|
|
||||||
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n");
|
|
||||||
while(1) delay(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef PIN_PIO_USB_HOST_VBUSEN
|
|
||||||
pinMode(PIN_PIO_USB_HOST_VBUSEN, OUTPUT);
|
|
||||||
digitalWrite(PIN_PIO_USB_HOST_VBUSEN, PIN_PIO_USB_HOST_VBUSEN_STATE);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
|
|
||||||
pio_cfg.pin_dp = PIN_PIO_USB_HOST_DP;
|
|
||||||
USBHost.configure_pio_usb(1, &pio_cfg);
|
|
||||||
|
|
||||||
// run host stack on controller (rhport) 1
|
// run host stack on controller (rhport) 1
|
||||||
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
|
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
|
||||||
|
|
@ -95,19 +76,22 @@ void setup1() {
|
||||||
USBHost.begin(1);
|
USBHost.begin(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop1()
|
void loop1() {
|
||||||
{
|
|
||||||
USBHost.task();
|
USBHost.task();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
// Invoked when device with hid interface is mounted
|
// Invoked when device with hid interface is mounted
|
||||||
// Report descriptor is also available for use.
|
// Report descriptor is also available for use.
|
||||||
// tuh_hid_parse_report_descriptor() can be used to parse common/simple enough
|
// tuh_hid_parse_report_descriptor() can be used to parse common/simple enough
|
||||||
// descriptor. Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE,
|
// descriptor. Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE,
|
||||||
// it will be skipped therefore report_desc = NULL, desc_len = 0
|
// it will be skipped therefore report_desc = NULL, desc_len = 0
|
||||||
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) {
|
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) {
|
||||||
(void)desc_report;
|
(void) desc_report;
|
||||||
(void)desc_len;
|
(void) desc_len;
|
||||||
uint16_t vid, pid;
|
uint16_t vid, pid;
|
||||||
tuh_vid_pid_get(dev_addr, &vid, &pid);
|
tuh_vid_pid_get(dev_addr, &vid, &pid);
|
||||||
|
|
||||||
|
|
@ -135,3 +119,5 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons
|
||||||
Serial.printf("Error: cannot request to receive report\r\n");
|
Serial.printf("Error: cannot request to receive report\r\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // extern C
|
||||||
99
examples/DualRole/HID/hid_device_report/usbh_helper.h
Normal file
99
examples/DualRole/HID/hid_device_report/usbh_helper.h
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
/*********************************************************************
|
||||||
|
Adafruit invests time and resources providing this open source code,
|
||||||
|
please support Adafruit and open-source hardware by purchasing
|
||||||
|
products from Adafruit!
|
||||||
|
|
||||||
|
MIT license, check LICENSE for more information
|
||||||
|
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||||
|
All text above, and the splash screen below must be included in
|
||||||
|
any redistribution
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#ifndef USBH_HELPER_H
|
||||||
|
#define USBH_HELPER_H
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_RP2040
|
||||||
|
// pio-usb is required for rp2040 host
|
||||||
|
#include "pio_usb.h"
|
||||||
|
|
||||||
|
// Pin D+ for host, D- = D+ + 1
|
||||||
|
#ifndef PIN_USB_HOST_DP
|
||||||
|
#define PIN_USB_HOST_DP 16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Pin for enabling Host VBUS. comment out if not used
|
||||||
|
#ifndef PIN_5V_EN
|
||||||
|
#define PIN_5V_EN 18
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PIN_5V_EN_STATE
|
||||||
|
#define PIN_5V_EN_STATE 1
|
||||||
|
#endif
|
||||||
|
#endif // ARDUINO_ARCH_RP2040
|
||||||
|
|
||||||
|
#include "Adafruit_TinyUSB.h"
|
||||||
|
|
||||||
|
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
|
// USB Host using MAX3421E: SPI, CS, INT
|
||||||
|
#include "SPI.h"
|
||||||
|
|
||||||
|
#if defined(ARDUINO_METRO_ESP32S2)
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 15, 14);
|
||||||
|
#elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2)
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 33, 15);
|
||||||
|
#else
|
||||||
|
// Default CS and INT are pin 10, 9
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 10, 9);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
// Native USB Host such as rp2040
|
||||||
|
Adafruit_USBH_Host USBHost;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Helper Functions
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_RP2040
|
||||||
|
static void rp2040_configure_pio_usb(void) {
|
||||||
|
//while ( !Serial ) delay(10); // wait for native usb
|
||||||
|
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
|
||||||
|
|
||||||
|
// Check for CPU frequency, must be multiple of 12 Mhz 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.printf("Change your CPU Clock to 12*n Mhz in Menu->CPU Speed \r\n");
|
||||||
|
while (1) {
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PIN_5V_EN
|
||||||
|
pinMode(PIN_5V_EN, OUTPUT);
|
||||||
|
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
|
||||||
|
pio_cfg.pin_dp = PIN_USB_HOST_DP;
|
||||||
|
|
||||||
|
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
|
||||||
|
// For pico-w, PIO is also used to communicate with cyw43
|
||||||
|
// Therefore we need to alternate the pio-usb configuration
|
||||||
|
// details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46
|
||||||
|
pio_cfg.sm_tx = 3;
|
||||||
|
pio_cfg.sm_rx = 2;
|
||||||
|
pio_cfg.sm_eop = 3;
|
||||||
|
pio_cfg.pio_rx_num = 0;
|
||||||
|
pio_cfg.pio_tx_num = 1;
|
||||||
|
pio_cfg.tx_ch = 9;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
USBHost.configure_pio_usb(1, &pio_cfg);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
3
examples/DualRole/HID/hid_mouse_log_filter/.skip.txt
Normal file
3
examples/DualRole/HID/hid_mouse_log_filter/.skip.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
feather_esp32_v2
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
CH32V20x_EVT
|
||||||
|
|
@ -0,0 +1,184 @@
|
||||||
|
/*********************************************************************
|
||||||
|
Adafruit invests time and resources providing this open source code,
|
||||||
|
please support Adafruit and open-source hardware by purchasing
|
||||||
|
products from Adafruit!
|
||||||
|
|
||||||
|
MIT license, check LICENSE for more information
|
||||||
|
Copyright (c) 2023 Bill Binko for Adafruit Industries
|
||||||
|
Based on tremor_filter example by Thach Ha
|
||||||
|
All text above, and the splash screen below must be included in
|
||||||
|
any redistribution
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
/* This example demonstrates use of both device and host, where
|
||||||
|
* - Device run on native usb controller (roothub port0)
|
||||||
|
* - Host depending on MCUs run on either:
|
||||||
|
* - rp2040: bit-banging 2 GPIOs with the help of Pico-PIO-USB library (roothub port1)
|
||||||
|
* - samd21/51, nrf52840, esp32: using MAX3421e controller (host shield)
|
||||||
|
*
|
||||||
|
* Requirements:
|
||||||
|
* - For rp2040:
|
||||||
|
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
|
||||||
|
* - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1
|
||||||
|
* - Provide VBus (5v) and GND for peripheral
|
||||||
|
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
|
||||||
|
* - For samd21/51, nrf52840, esp32:
|
||||||
|
* - Additional MAX2341e USB Host shield or featherwing is required
|
||||||
|
* - SPI instance, CS pin, INT pin are correctly configured in usbh_helper.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Example sketch receive mouse report from host interface (from e.g consumer mouse)
|
||||||
|
* and reduce large motions due to tremors by applying the natural log function.
|
||||||
|
* It handles negative values and a dead zone where small values will not be adjusted.
|
||||||
|
* Adjusted mouse movement are send via device interface (to PC).
|
||||||
|
*/
|
||||||
|
|
||||||
|
// USBHost is defined in usbh_helper.h
|
||||||
|
#include "usbh_helper.h"
|
||||||
|
|
||||||
|
// HID report descriptor using TinyUSB's template
|
||||||
|
// Single Report (no ID) descriptor
|
||||||
|
uint8_t const desc_hid_report[] = {
|
||||||
|
TUD_HID_REPORT_DESC_MOUSE()
|
||||||
|
};
|
||||||
|
|
||||||
|
// USB HID object: desc report, desc len, protocol, interval, use out endpoint
|
||||||
|
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_MOUSE, 2, false);
|
||||||
|
|
||||||
|
/* Adjustable parameters for the log_filter() method.
|
||||||
|
* Adjust for each user (would be ideal to have this adjustable w/o recompiling) */
|
||||||
|
#define PRESCALE 8.0 // Must be > 0, Higher numbers increase rate of attenuation
|
||||||
|
#define POSTSCALE 1.5 // Must be > 0, Higher numbers compensate for PRESCALE attenuation
|
||||||
|
#define DEADZONE 1.0 // Must be > 1, Movements < this magnitude will not be filtered
|
||||||
|
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
usb_hid.begin();
|
||||||
|
|
||||||
|
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
|
// init host stack on controller (rhport) 1
|
||||||
|
// For rp2040: this is called in core1's setup1()
|
||||||
|
USBHost.begin(1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//while ( !Serial ) delay(10); // wait for native usb
|
||||||
|
Serial.println("ATMakers Logarithm Tremor Filter Example");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Using Host shield MAX3421E controller
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
void loop() {
|
||||||
|
USBHost.task();
|
||||||
|
Serial.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_RP2040)
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// For RP2040 use both core0 for device stack, core1 for host stack
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
Serial.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------- Core1 -------------//
|
||||||
|
void setup1() {
|
||||||
|
// configure pio-usb: defined in usbh_helper.h
|
||||||
|
rp2040_configure_pio_usb();
|
||||||
|
|
||||||
|
// run host stack on controller (rhport) 1
|
||||||
|
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
|
||||||
|
// host bit-banging processing works done in core1 to free up core0 for other works
|
||||||
|
USBHost.begin(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop1() {
|
||||||
|
USBHost.task();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// TinyUSB Host callbacks
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
|
||||||
|
// Invoked when device with hid interface is mounted
|
||||||
|
// Report descriptor is also available for use.
|
||||||
|
// tuh_hid_parse_report_descriptor() can be used to parse common/simple enough
|
||||||
|
// descriptor. Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE,
|
||||||
|
// it will be skipped therefore report_desc = NULL, desc_len = 0
|
||||||
|
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) {
|
||||||
|
(void) desc_report;
|
||||||
|
(void) desc_len;
|
||||||
|
uint16_t vid, pid;
|
||||||
|
tuh_vid_pid_get(dev_addr, &vid, &pid);
|
||||||
|
|
||||||
|
Serial.printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);
|
||||||
|
Serial.printf("VID = %04x, PID = %04x\r\n", vid, pid);
|
||||||
|
|
||||||
|
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
|
||||||
|
if (itf_protocol == HID_ITF_PROTOCOL_MOUSE) {
|
||||||
|
Serial.printf("HID Mouse\r\n");
|
||||||
|
if (!tuh_hid_receive_report(dev_addr, instance)) {
|
||||||
|
Serial.printf("Error: cannot request to receive report\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoked when device with hid interface is un-mounted
|
||||||
|
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) {
|
||||||
|
Serial.printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Invoked when received report from device via interrupt endpoint
|
||||||
|
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) {
|
||||||
|
filter_report((hid_mouse_report_t const *) report);
|
||||||
|
|
||||||
|
// continue to request to receive report
|
||||||
|
if (!tuh_hid_receive_report(dev_addr, instance)) {
|
||||||
|
Serial.printf("Error: cannot request to receive report\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // extern C
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Low pass filter Functions
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
/*
|
||||||
|
* log_filter: Reduce large motions due to tremors by applying the natural log function
|
||||||
|
* Handles negative values and a dead zone where small values will not be adjusted
|
||||||
|
*/
|
||||||
|
int8_t log_filter(int8_t val) {
|
||||||
|
if (val < -1 * DEADZONE) {
|
||||||
|
return (int8_t) (-1.0 * POSTSCALE * logf(-1.0 * PRESCALE * (float) val));
|
||||||
|
} else if (val > DEADZONE) {
|
||||||
|
return (int8_t) (POSTSCALE * logf(PRESCALE * (float) val));
|
||||||
|
} else {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adjust HID report by applying log_filter
|
||||||
|
*/
|
||||||
|
void filter_report(hid_mouse_report_t const *report) {
|
||||||
|
|
||||||
|
int8_t old_x = report->x;
|
||||||
|
int8_t old_y = report->y;
|
||||||
|
|
||||||
|
hid_mouse_report_t filtered_report = *report;
|
||||||
|
filtered_report.x = log_filter(old_x);
|
||||||
|
filtered_report.y = log_filter(old_y);
|
||||||
|
|
||||||
|
//Serial.printf("%d,%d,%d,%d\n", old_x, filtered_report.x, old_y, filtered_report.y);
|
||||||
|
usb_hid.sendReport(0, &filtered_report, sizeof(filtered_report));
|
||||||
|
|
||||||
|
}
|
||||||
99
examples/DualRole/HID/hid_mouse_log_filter/usbh_helper.h
Normal file
99
examples/DualRole/HID/hid_mouse_log_filter/usbh_helper.h
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
/*********************************************************************
|
||||||
|
Adafruit invests time and resources providing this open source code,
|
||||||
|
please support Adafruit and open-source hardware by purchasing
|
||||||
|
products from Adafruit!
|
||||||
|
|
||||||
|
MIT license, check LICENSE for more information
|
||||||
|
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||||
|
All text above, and the splash screen below must be included in
|
||||||
|
any redistribution
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#ifndef USBH_HELPER_H
|
||||||
|
#define USBH_HELPER_H
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_RP2040
|
||||||
|
// pio-usb is required for rp2040 host
|
||||||
|
#include "pio_usb.h"
|
||||||
|
|
||||||
|
// Pin D+ for host, D- = D+ + 1
|
||||||
|
#ifndef PIN_USB_HOST_DP
|
||||||
|
#define PIN_USB_HOST_DP 16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Pin for enabling Host VBUS. comment out if not used
|
||||||
|
#ifndef PIN_5V_EN
|
||||||
|
#define PIN_5V_EN 18
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PIN_5V_EN_STATE
|
||||||
|
#define PIN_5V_EN_STATE 1
|
||||||
|
#endif
|
||||||
|
#endif // ARDUINO_ARCH_RP2040
|
||||||
|
|
||||||
|
#include "Adafruit_TinyUSB.h"
|
||||||
|
|
||||||
|
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
|
// USB Host using MAX3421E: SPI, CS, INT
|
||||||
|
#include "SPI.h"
|
||||||
|
|
||||||
|
#if defined(ARDUINO_METRO_ESP32S2)
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 15, 14);
|
||||||
|
#elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2)
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 33, 15);
|
||||||
|
#else
|
||||||
|
// Default CS and INT are pin 10, 9
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 10, 9);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
// Native USB Host such as rp2040
|
||||||
|
Adafruit_USBH_Host USBHost;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Helper Functions
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_RP2040
|
||||||
|
static void rp2040_configure_pio_usb(void) {
|
||||||
|
//while ( !Serial ) delay(10); // wait for native usb
|
||||||
|
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
|
||||||
|
|
||||||
|
// Check for CPU frequency, must be multiple of 12 Mhz 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.printf("Change your CPU Clock to 12*n Mhz in Menu->CPU Speed \r\n");
|
||||||
|
while (1) {
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PIN_5V_EN
|
||||||
|
pinMode(PIN_5V_EN, OUTPUT);
|
||||||
|
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
|
||||||
|
pio_cfg.pin_dp = PIN_USB_HOST_DP;
|
||||||
|
|
||||||
|
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
|
||||||
|
// For pico-w, PIO is also used to communicate with cyw43
|
||||||
|
// Therefore we need to alternate the pio-usb configuration
|
||||||
|
// details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46
|
||||||
|
pio_cfg.sm_tx = 3;
|
||||||
|
pio_cfg.sm_rx = 2;
|
||||||
|
pio_cfg.sm_eop = 3;
|
||||||
|
pio_cfg.pio_rx_num = 0;
|
||||||
|
pio_cfg.pio_tx_num = 1;
|
||||||
|
pio_cfg.tx_ch = 9;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
USBHost.configure_pio_usb(1, &pio_cfg);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
3
examples/DualRole/HID/hid_mouse_tremor_filter/.skip.txt
Normal file
3
examples/DualRole/HID/hid_mouse_tremor_filter/.skip.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
feather_esp32_v2
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
CH32V20x_EVT
|
||||||
|
|
@ -0,0 +1,205 @@
|
||||||
|
/*********************************************************************
|
||||||
|
Adafruit invests time and resources providing this open source code,
|
||||||
|
please support Adafruit and open-source hardware by purchasing
|
||||||
|
products from Adafruit!
|
||||||
|
|
||||||
|
MIT license, check LICENSE for more information
|
||||||
|
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||||
|
All text above, and the splash screen below must be included in
|
||||||
|
any redistribution
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
/* This example demonstrates use of both device and host, where
|
||||||
|
* - Device run on native usb controller (roothub port0)
|
||||||
|
* - Host depending on MCUs run on either:
|
||||||
|
* - rp2040: bit-banging 2 GPIOs with the help of Pico-PIO-USB library (roothub port1)
|
||||||
|
* - samd21/51, nrf52840, esp32: using MAX3421e controller (host shield)
|
||||||
|
*
|
||||||
|
* Requirements:
|
||||||
|
* - For rp2040:
|
||||||
|
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
|
||||||
|
* - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1
|
||||||
|
* - Provide VBus (5v) and GND for peripheral
|
||||||
|
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
|
||||||
|
* - For samd21/51, nrf52840, esp32:
|
||||||
|
* - Additional MAX2341e USB Host shield or featherwing is required
|
||||||
|
* - SPI instance, CS pin, INT pin are correctly configured in usbh_helper.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Example sketch receive mouse report from host interface (from e.g consumer mouse)
|
||||||
|
* and apply a butterworth low pass filter with a specific CUTOFF_FREQUENCY on hid mouse movement report.
|
||||||
|
* Filtered report are send via device interface (to PC) acting as a "Mouse Tremor Filter".
|
||||||
|
*/
|
||||||
|
|
||||||
|
// USBHost is defined in usbh_helper.h
|
||||||
|
#include "usbh_helper.h"
|
||||||
|
|
||||||
|
// HID report descriptor using TinyUSB's template
|
||||||
|
// Single Report (no ID) descriptor
|
||||||
|
uint8_t const desc_hid_report[] = {
|
||||||
|
TUD_HID_REPORT_DESC_MOUSE()
|
||||||
|
};
|
||||||
|
|
||||||
|
// USB HID object: desc report, desc len, protocol, interval, use out endpoint
|
||||||
|
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_MOUSE, 2, false);
|
||||||
|
|
||||||
|
//------------- Low pass filter with Butterworth -------------//
|
||||||
|
// Butterworth low-pass filter coefficients
|
||||||
|
typedef struct {
|
||||||
|
float b0, b1, b2, a1, a2;
|
||||||
|
} butterworth_coeffs_t;
|
||||||
|
|
||||||
|
#define SAMPLING_FREQUENCY 100.0 // Hz
|
||||||
|
#define CUTOFF_FREQUENCY 10.0 // Hz
|
||||||
|
|
||||||
|
// x, y
|
||||||
|
butterworth_coeffs_t coeffs[2];
|
||||||
|
|
||||||
|
butterworth_coeffs_t butterworth_lowpass(float cutoff_frequency, float sampling_frequency);
|
||||||
|
|
||||||
|
void filter_report(hid_mouse_report_t const *report);
|
||||||
|
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
usb_hid.begin();
|
||||||
|
|
||||||
|
coeffs[0] = butterworth_lowpass(CUTOFF_FREQUENCY, SAMPLING_FREQUENCY);
|
||||||
|
coeffs[1] = butterworth_lowpass(CUTOFF_FREQUENCY, SAMPLING_FREQUENCY);
|
||||||
|
|
||||||
|
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
|
// init host stack on controller (rhport) 1
|
||||||
|
// For rp2040: this is called in core1's setup1()
|
||||||
|
USBHost.begin(1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//while ( !Serial ) delay(10); // wait for native usb
|
||||||
|
Serial.println("TinyUSB Mouse Tremor Filter Example");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Using Host shield MAX3421E controller
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
void loop() {
|
||||||
|
USBHost.task();
|
||||||
|
Serial.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_RP2040)
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// For RP2040 use both core0 for device stack, core1 for host stack
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
void loop() {
|
||||||
|
Serial.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------- Core1 -------------//
|
||||||
|
void setup1() {
|
||||||
|
// configure pio-usb: defined in usbh_helper.h
|
||||||
|
rp2040_configure_pio_usb();
|
||||||
|
|
||||||
|
// run host stack on controller (rhport) 1
|
||||||
|
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
|
||||||
|
// host bit-banging processing works done in core1 to free up core0 for other works
|
||||||
|
USBHost.begin(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop1() {
|
||||||
|
USBHost.task();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// TinyUSB Host callbacks
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
|
||||||
|
// Invoked when device with hid interface is mounted
|
||||||
|
// Report descriptor is also available for use.
|
||||||
|
// tuh_hid_parse_report_descriptor() can be used to parse common/simple enough
|
||||||
|
// descriptor. Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE,
|
||||||
|
// it will be skipped therefore report_desc = NULL, desc_len = 0
|
||||||
|
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) {
|
||||||
|
(void) desc_report;
|
||||||
|
(void) desc_len;
|
||||||
|
uint16_t vid, pid;
|
||||||
|
tuh_vid_pid_get(dev_addr, &vid, &pid);
|
||||||
|
|
||||||
|
Serial.printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);
|
||||||
|
Serial.printf("VID = %04x, PID = %04x\r\n", vid, pid);
|
||||||
|
|
||||||
|
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
|
||||||
|
if (itf_protocol == HID_ITF_PROTOCOL_MOUSE) {
|
||||||
|
Serial.printf("HID Mouse\r\n");
|
||||||
|
if (!tuh_hid_receive_report(dev_addr, instance)) {
|
||||||
|
Serial.printf("Error: cannot request to receive report\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoked when device with hid interface is un-mounted
|
||||||
|
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) {
|
||||||
|
Serial.printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Invoked when received report from device via interrupt endpoint
|
||||||
|
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) {
|
||||||
|
filter_report((hid_mouse_report_t const *) report);
|
||||||
|
|
||||||
|
// continue to request to receive report
|
||||||
|
if (!tuh_hid_receive_report(dev_addr, instance)) {
|
||||||
|
Serial.printf("Error: cannot request to receive report\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // extern C
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Low pass filter Functions
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
butterworth_coeffs_t butterworth_lowpass(float cutoff_frequency, float sampling_frequency) {
|
||||||
|
butterworth_coeffs_t coe;
|
||||||
|
|
||||||
|
float omega = 2.0 * PI * cutoff_frequency / sampling_frequency;
|
||||||
|
float s = sin(omega);
|
||||||
|
float t = tan(omega / 2.0);
|
||||||
|
float alpha = s / (2.0 * t);
|
||||||
|
|
||||||
|
coe.b0 = 1.0 / (1.0 + 2.0 * alpha + 2.0 * alpha * alpha);
|
||||||
|
coe.b1 = 2.0 * coe.b0;
|
||||||
|
coe.b2 = coe.b0;
|
||||||
|
coe.a1 = 2.0 * (alpha * alpha - 1.0) * coe.b0;
|
||||||
|
coe.a2 = (1.0 - 2.0 * alpha + 2.0 * alpha * alpha) * coe.b0;
|
||||||
|
|
||||||
|
return coe;
|
||||||
|
}
|
||||||
|
|
||||||
|
float butterworth_filter(float data, butterworth_coeffs_t *coeffs, float *filtered, float *prev1, float *prev2) {
|
||||||
|
float output = coeffs->b0 * data + coeffs->b1 * (*prev1) + coeffs->b2 * (*prev2) - coeffs->a1 * (*filtered) -
|
||||||
|
coeffs->a2 * (*prev1);
|
||||||
|
*prev2 = *prev1;
|
||||||
|
*prev1 = data;
|
||||||
|
*filtered = output;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
void filter_report(hid_mouse_report_t const *report) {
|
||||||
|
static float filtered[2] = { 0.0, 0.0 };
|
||||||
|
static float prev1[2] = { 0.0, 0.0 };
|
||||||
|
static float prev2[2] = { 0.0, 0.0 };
|
||||||
|
|
||||||
|
butterworth_filter(report->x, &coeffs[0], &filtered[0], &prev1[0], &prev2[0]);
|
||||||
|
butterworth_filter(report->y, &coeffs[1], &filtered[1], &prev1[1], &prev2[1]);
|
||||||
|
|
||||||
|
hid_mouse_report_t filtered_report = *report;
|
||||||
|
filtered_report.x = (int8_t) filtered[0];
|
||||||
|
filtered_report.y = (int8_t) filtered[1];
|
||||||
|
|
||||||
|
usb_hid.sendReport(0, &filtered_report, sizeof(filtered_report));
|
||||||
|
}
|
||||||
99
examples/DualRole/HID/hid_mouse_tremor_filter/usbh_helper.h
Normal file
99
examples/DualRole/HID/hid_mouse_tremor_filter/usbh_helper.h
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
/*********************************************************************
|
||||||
|
Adafruit invests time and resources providing this open source code,
|
||||||
|
please support Adafruit and open-source hardware by purchasing
|
||||||
|
products from Adafruit!
|
||||||
|
|
||||||
|
MIT license, check LICENSE for more information
|
||||||
|
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||||
|
All text above, and the splash screen below must be included in
|
||||||
|
any redistribution
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#ifndef USBH_HELPER_H
|
||||||
|
#define USBH_HELPER_H
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_RP2040
|
||||||
|
// pio-usb is required for rp2040 host
|
||||||
|
#include "pio_usb.h"
|
||||||
|
|
||||||
|
// Pin D+ for host, D- = D+ + 1
|
||||||
|
#ifndef PIN_USB_HOST_DP
|
||||||
|
#define PIN_USB_HOST_DP 16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Pin for enabling Host VBUS. comment out if not used
|
||||||
|
#ifndef PIN_5V_EN
|
||||||
|
#define PIN_5V_EN 18
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PIN_5V_EN_STATE
|
||||||
|
#define PIN_5V_EN_STATE 1
|
||||||
|
#endif
|
||||||
|
#endif // ARDUINO_ARCH_RP2040
|
||||||
|
|
||||||
|
#include "Adafruit_TinyUSB.h"
|
||||||
|
|
||||||
|
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
|
// USB Host using MAX3421E: SPI, CS, INT
|
||||||
|
#include "SPI.h"
|
||||||
|
|
||||||
|
#if defined(ARDUINO_METRO_ESP32S2)
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 15, 14);
|
||||||
|
#elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2)
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 33, 15);
|
||||||
|
#else
|
||||||
|
// Default CS and INT are pin 10, 9
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 10, 9);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
// Native USB Host such as rp2040
|
||||||
|
Adafruit_USBH_Host USBHost;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Helper Functions
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_RP2040
|
||||||
|
static void rp2040_configure_pio_usb(void) {
|
||||||
|
//while ( !Serial ) delay(10); // wait for native usb
|
||||||
|
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
|
||||||
|
|
||||||
|
// Check for CPU frequency, must be multiple of 12 Mhz 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.printf("Change your CPU Clock to 12*n Mhz in Menu->CPU Speed \r\n");
|
||||||
|
while (1) {
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PIN_5V_EN
|
||||||
|
pinMode(PIN_5V_EN, OUTPUT);
|
||||||
|
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
|
||||||
|
pio_cfg.pin_dp = PIN_USB_HOST_DP;
|
||||||
|
|
||||||
|
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
|
||||||
|
// For pico-w, PIO is also used to communicate with cyw43
|
||||||
|
// Therefore we need to alternate the pio-usb configuration
|
||||||
|
// details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46
|
||||||
|
pio_cfg.sm_tx = 3;
|
||||||
|
pio_cfg.sm_rx = 2;
|
||||||
|
pio_cfg.sm_eop = 3;
|
||||||
|
pio_cfg.pio_rx_num = 0;
|
||||||
|
pio_cfg.pio_tx_num = 1;
|
||||||
|
pio_cfg.tx_ch = 9;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
USBHost.configure_pio_usb(1, &pio_cfg);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
3
examples/DualRole/HID/hid_remapper/.skip.txt
Normal file
3
examples/DualRole/HID/hid_remapper/.skip.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
feather_esp32_v2
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
CH32V20x_EVT
|
||||||
|
|
@ -9,103 +9,77 @@
|
||||||
any redistribution
|
any redistribution
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
|
|
||||||
|
|
||||||
/* This example demonstrates use of both device and host, where
|
/* This example demonstrates use of both device and host, where
|
||||||
* - Device run on native usb controller (controller0)
|
* - Device run on native usb controller (roothub port0)
|
||||||
* - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
|
* - Host depending on MCUs run on either:
|
||||||
|
* - rp2040: bit-banging 2 GPIOs with the help of Pico-PIO-USB library (roothub port1)
|
||||||
|
* - samd21/51, nrf52840, esp32: using MAX3421e controller (host shield)
|
||||||
*
|
*
|
||||||
* Example sketch receive keyboard report from host interface (from e.g consumer keyboard)
|
* Requirements:
|
||||||
|
* - For rp2040:
|
||||||
|
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
|
||||||
|
* - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1
|
||||||
|
* - Provide VBus (5v) and GND for peripheral
|
||||||
|
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
|
||||||
|
* - For samd21/51, nrf52840, esp32:
|
||||||
|
* - Additional MAX2341e USB Host shield or featherwing is required
|
||||||
|
* - SPI instance, CS pin, INT pin are correctly configured in usbh_helper.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Example sketch receive keyboard report from host interface (from e.g consumer keyboard)
|
||||||
* and remap it to another key and send it via device interface (to PC). For simplicity,
|
* and remap it to another key and send it via device interface (to PC). For simplicity,
|
||||||
* this example only toggle shift key to the report, effectively remap:
|
* this example only toggle shift key to the report, effectively remap:
|
||||||
* - all character key <-> upper case
|
* - all character key <-> upper case
|
||||||
* - number <-> its symbol (with shift)
|
* - number <-> its symbol (with shift)
|
||||||
*
|
|
||||||
* Requirements:
|
|
||||||
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
|
|
||||||
* - 2 consecutive GPIOs: D+ is defined by PIN_PIO_USB_HOST_DP, D- = D+ +1
|
|
||||||
* - Provide VBus (5v) and GND for peripheral
|
|
||||||
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// pio-usb is required for rp2040 host
|
// USBHost is defined in usbh_helper.h
|
||||||
#include "pio_usb.h"
|
#include "usbh_helper.h"
|
||||||
#include "Adafruit_TinyUSB.h"
|
|
||||||
|
|
||||||
// Pin D+ for host, D- = D+ + 1
|
|
||||||
#ifndef PIN_PIO_USB_HOST_DP
|
|
||||||
#define PIN_PIO_USB_HOST_DP 20
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Pin for enabling Host VBUS. comment out if not used
|
|
||||||
#ifndef PIN_PIO_USB_HOST_VBUSEN
|
|
||||||
#define PIN_PIO_USB_HOST_VBUSEN 22
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef PIN_PIO_USB_HOST_VBUSEN_STATE
|
|
||||||
#define PIN_PIO_USB_HOST_VBUSEN_STATE 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Language ID: English
|
|
||||||
#define LANGUAGE_ID 0x0409
|
|
||||||
|
|
||||||
// USB Host object
|
|
||||||
Adafruit_USBH_Host USBHost;
|
|
||||||
|
|
||||||
// HID report descriptor using TinyUSB's template
|
// HID report descriptor using TinyUSB's template
|
||||||
// Single Report (no ID) descriptor
|
// Single Report (no ID) descriptor
|
||||||
uint8_t const desc_hid_report[] =
|
uint8_t const desc_hid_report[] = {
|
||||||
{
|
|
||||||
TUD_HID_REPORT_DESC_KEYBOARD()
|
TUD_HID_REPORT_DESC_KEYBOARD()
|
||||||
};
|
};
|
||||||
|
|
||||||
// USB HID object. For ESP32 these values cannot be changed after this declaration
|
// USB HID object: desc report, desc len, protocol, interval, use out endpoint
|
||||||
// desc report, desc len, protocol, interval, use out endpoint
|
|
||||||
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_KEYBOARD, 2, false);
|
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_KEYBOARD, 2, false);
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
void setup() {
|
||||||
// Setup and Loop on Core0
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
usb_hid.begin();
|
usb_hid.begin();
|
||||||
|
|
||||||
//while ( !Serial ) delay(10); // wait for native usb
|
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
|
// init host stack on controller (rhport) 1
|
||||||
|
// For rp2040: this is called in core1's setup1()
|
||||||
|
USBHost.begin(1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//while ( !Serial ) delay(10); // wait for native usb
|
||||||
Serial.println("TinyUSB Host HID Remap Example");
|
Serial.println("TinyUSB Host HID Remap Example");
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
{
|
//--------------------------------------------------------------------+
|
||||||
|
// Using Host shield MAX3421E controller
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
void loop() {
|
||||||
|
USBHost.task();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_RP2040)
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// Setup and Loop on Core1
|
// For RP2040 use both core0 for device stack, core1 for host stack
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------- Core1 -------------//
|
||||||
void setup1() {
|
void setup1() {
|
||||||
//while ( !Serial ) delay(10); // wait for native usb
|
// configure pio-usb: defined in usbh_helper.h
|
||||||
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
|
rp2040_configure_pio_usb();
|
||||||
|
|
||||||
// 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 != 120000000UL && cpu_hz != 240000000UL ) {
|
|
||||||
while ( !Serial ) delay(10); // wait for native usb
|
|
||||||
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
|
|
||||||
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n");
|
|
||||||
while(1) delay(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef PIN_PIO_USB_HOST_VBUSEN
|
|
||||||
pinMode(PIN_PIO_USB_HOST_VBUSEN, OUTPUT);
|
|
||||||
digitalWrite(PIN_PIO_USB_HOST_VBUSEN, PIN_PIO_USB_HOST_VBUSEN_STATE);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
|
|
||||||
pio_cfg.pin_dp = PIN_PIO_USB_HOST_DP;
|
|
||||||
USBHost.configure_pio_usb(1, &pio_cfg);
|
|
||||||
|
|
||||||
// run host stack on controller (rhport) 1
|
// run host stack on controller (rhport) 1
|
||||||
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
|
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
|
||||||
|
|
@ -113,10 +87,16 @@ void setup1() {
|
||||||
USBHost.begin(1);
|
USBHost.begin(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop1()
|
void loop1() {
|
||||||
{
|
|
||||||
USBHost.task();
|
USBHost.task();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// TinyUSB Host callbacks
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
|
||||||
// Invoked when device with hid interface is mounted
|
// Invoked when device with hid interface is mounted
|
||||||
// Report descriptor is also available for use.
|
// Report descriptor is also available for use.
|
||||||
|
|
@ -124,8 +104,8 @@ void loop1()
|
||||||
// descriptor. Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE,
|
// descriptor. Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE,
|
||||||
// it will be skipped therefore report_desc = NULL, desc_len = 0
|
// it will be skipped therefore report_desc = NULL, desc_len = 0
|
||||||
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) {
|
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) {
|
||||||
(void)desc_report;
|
(void) desc_report;
|
||||||
(void)desc_len;
|
(void) desc_len;
|
||||||
uint16_t vid, pid;
|
uint16_t vid, pid;
|
||||||
tuh_vid_pid_get(dev_addr, &vid, &pid);
|
tuh_vid_pid_get(dev_addr, &vid, &pid);
|
||||||
|
|
||||||
|
|
@ -134,7 +114,7 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_re
|
||||||
|
|
||||||
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
|
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
|
||||||
if (itf_protocol == HID_ITF_PROTOCOL_KEYBOARD) {
|
if (itf_protocol == HID_ITF_PROTOCOL_KEYBOARD) {
|
||||||
Serial.printf("HID Keyboard\r\n", vid, pid);
|
Serial.printf("HID Keyboard\r\n");
|
||||||
if (!tuh_hid_receive_report(dev_addr, instance)) {
|
if (!tuh_hid_receive_report(dev_addr, instance)) {
|
||||||
Serial.printf("Error: cannot request to receive report\r\n");
|
Serial.printf("Error: cannot request to receive report\r\n");
|
||||||
}
|
}
|
||||||
|
|
@ -146,12 +126,11 @@ void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) {
|
||||||
Serial.printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);
|
Serial.printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
void remap_key(hid_keyboard_report_t const* original_report, hid_keyboard_report_t* remapped_report)
|
void remap_key(hid_keyboard_report_t const *original_report, hid_keyboard_report_t *remapped_report) {
|
||||||
{
|
|
||||||
memcpy(remapped_report, original_report, sizeof(hid_keyboard_report_t));
|
memcpy(remapped_report, original_report, sizeof(hid_keyboard_report_t));
|
||||||
|
|
||||||
// only remap if not empty report i.e key released
|
// only remap if not empty report i.e key released
|
||||||
for(uint8_t i=0; i<6; i++) {
|
for (uint8_t i = 0; i < 6; i++) {
|
||||||
if (remapped_report->keycode[i] != 0) {
|
if (remapped_report->keycode[i] != 0) {
|
||||||
// Note: we ignore right shift here
|
// Note: we ignore right shift here
|
||||||
remapped_report->modifier ^= KEYBOARD_MODIFIER_LEFTSHIFT;
|
remapped_report->modifier ^= KEYBOARD_MODIFIER_LEFTSHIFT;
|
||||||
|
|
@ -162,16 +141,16 @@ void remap_key(hid_keyboard_report_t const* original_report, hid_keyboard_report
|
||||||
|
|
||||||
// Invoked when received report from device via interrupt endpoint
|
// Invoked when received report from device via interrupt endpoint
|
||||||
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) {
|
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) {
|
||||||
if ( len != 8 ) {
|
if (len != 8) {
|
||||||
Serial.printf("report len = %u NOT 8, probably something wrong !!\r\n", len);
|
Serial.printf("report len = %u NOT 8, probably something wrong !!\r\n", len);
|
||||||
}else {
|
} else {
|
||||||
hid_keyboard_report_t remapped_report;
|
hid_keyboard_report_t remapped_report;
|
||||||
remap_key((hid_keyboard_report_t const*) report, &remapped_report);
|
remap_key((hid_keyboard_report_t const *) report, &remapped_report);
|
||||||
|
|
||||||
// send remapped report to PC
|
// send remapped report to PC
|
||||||
// NOTE: for better performance you should save/queue remapped report instead of
|
// NOTE: for better performance you should save/queue remapped report instead of
|
||||||
// blocking wait for usb_hid ready here
|
// blocking wait for usb_hid ready here
|
||||||
while ( !usb_hid.ready() ) {
|
while (!usb_hid.ready()) {
|
||||||
yield();
|
yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -183,3 +162,5 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons
|
||||||
Serial.printf("Error: cannot request to receive report\r\n");
|
Serial.printf("Error: cannot request to receive report\r\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
99
examples/DualRole/HID/hid_remapper/usbh_helper.h
Normal file
99
examples/DualRole/HID/hid_remapper/usbh_helper.h
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
/*********************************************************************
|
||||||
|
Adafruit invests time and resources providing this open source code,
|
||||||
|
please support Adafruit and open-source hardware by purchasing
|
||||||
|
products from Adafruit!
|
||||||
|
|
||||||
|
MIT license, check LICENSE for more information
|
||||||
|
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||||
|
All text above, and the splash screen below must be included in
|
||||||
|
any redistribution
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#ifndef USBH_HELPER_H
|
||||||
|
#define USBH_HELPER_H
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_RP2040
|
||||||
|
// pio-usb is required for rp2040 host
|
||||||
|
#include "pio_usb.h"
|
||||||
|
|
||||||
|
// Pin D+ for host, D- = D+ + 1
|
||||||
|
#ifndef PIN_USB_HOST_DP
|
||||||
|
#define PIN_USB_HOST_DP 16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Pin for enabling Host VBUS. comment out if not used
|
||||||
|
#ifndef PIN_5V_EN
|
||||||
|
#define PIN_5V_EN 18
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PIN_5V_EN_STATE
|
||||||
|
#define PIN_5V_EN_STATE 1
|
||||||
|
#endif
|
||||||
|
#endif // ARDUINO_ARCH_RP2040
|
||||||
|
|
||||||
|
#include "Adafruit_TinyUSB.h"
|
||||||
|
|
||||||
|
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
|
// USB Host using MAX3421E: SPI, CS, INT
|
||||||
|
#include "SPI.h"
|
||||||
|
|
||||||
|
#if defined(ARDUINO_METRO_ESP32S2)
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 15, 14);
|
||||||
|
#elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2)
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 33, 15);
|
||||||
|
#else
|
||||||
|
// Default CS and INT are pin 10, 9
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 10, 9);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
// Native USB Host such as rp2040
|
||||||
|
Adafruit_USBH_Host USBHost;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Helper Functions
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_RP2040
|
||||||
|
static void rp2040_configure_pio_usb(void) {
|
||||||
|
//while ( !Serial ) delay(10); // wait for native usb
|
||||||
|
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
|
||||||
|
|
||||||
|
// Check for CPU frequency, must be multiple of 12 Mhz 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.printf("Change your CPU Clock to 12*n Mhz in Menu->CPU Speed \r\n");
|
||||||
|
while (1) {
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PIN_5V_EN
|
||||||
|
pinMode(PIN_5V_EN, OUTPUT);
|
||||||
|
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
|
||||||
|
pio_cfg.pin_dp = PIN_USB_HOST_DP;
|
||||||
|
|
||||||
|
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
|
||||||
|
// For pico-w, PIO is also used to communicate with cyw43
|
||||||
|
// Therefore we need to alternate the pio-usb configuration
|
||||||
|
// details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46
|
||||||
|
pio_cfg.sm_tx = 3;
|
||||||
|
pio_cfg.sm_rx = 2;
|
||||||
|
pio_cfg.sm_eop = 3;
|
||||||
|
pio_cfg.pio_rx_num = 0;
|
||||||
|
pio_cfg.pio_tx_num = 1;
|
||||||
|
pio_cfg.tx_ch = 9;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
USBHost.configure_pio_usb(1, &pio_cfg);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
2
examples/DualRole/MassStorage/msc_data_logger/.skip.txt
Normal file
2
examples/DualRole/MassStorage/msc_data_logger/.skip.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
CH32V20x_EVT
|
||||||
|
|
@ -11,47 +11,43 @@
|
||||||
|
|
||||||
|
|
||||||
/* This example demonstrates use of both device and host, where
|
/* This example demonstrates use of both device and host, where
|
||||||
* - Device run on native usb controller (controller0)
|
* - Device run on native usb controller (roothub port0)
|
||||||
* - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
|
* - Host depending on MCUs run on either:
|
||||||
*
|
* - rp2040: bit-banging 2 GPIOs with the help of Pico-PIO-USB library (roothub port1)
|
||||||
* Example will log CPU temperature periodically (ms,value) to USB thumbdrive
|
* - samd21/51, nrf52840, esp32: using MAX3421e controller (host shield)
|
||||||
*
|
*
|
||||||
* Requirements:
|
* Requirements:
|
||||||
|
* - For rp2040:
|
||||||
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
|
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
|
||||||
* - 2 consecutive GPIOs: D+ is defined by PIN_PIO_USB_HOST_DP, D- = D+ +1
|
* - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1
|
||||||
* - Provide VBus (5v) and GND for peripheral
|
* - Provide VBus (5v) and GND for peripheral
|
||||||
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
|
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
|
||||||
|
* - For samd21/51, nrf52840, esp32:
|
||||||
|
* - Additional MAX2341e USB Host shield or featherwing is required
|
||||||
|
* - SPI instance, CS pin, INT pin are correctly configured in usbh_helper.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// pio-usb is required for rp2040 host
|
/* Example sketch read analog pin (default A0) and log it to LOG_FILE on the msc device
|
||||||
#include "pio_usb.h"
|
* every LOG_INTERVAL ms. */
|
||||||
|
|
||||||
|
// nRF52 and ESP32 use freeRTOS, we may need to run USBhost.task() in its own rtos's thread.
|
||||||
|
// Since USBHost.task() will put loop() into dormant state and prevent followed code from running
|
||||||
|
// until there is USB host event.
|
||||||
|
#if defined(ARDUINO_NRF52_ADAFRUIT) || defined(ARDUINO_ARCH_ESP32)
|
||||||
|
#define USE_FREERTOS
|
||||||
|
#endif
|
||||||
|
|
||||||
// SdFat is required for using Adafruit_USBH_MSC_SdFatDevice
|
// SdFat is required for using Adafruit_USBH_MSC_SdFatDevice
|
||||||
#include "SdFat.h"
|
#include "SdFat_Adafruit_Fork.h"
|
||||||
|
|
||||||
// TinyUSB lib
|
|
||||||
#include "Adafruit_TinyUSB.h"
|
|
||||||
|
|
||||||
// Pin D+ for host, D- = D+ + 1
|
|
||||||
#ifndef PIN_PIO_USB_HOST_DP
|
|
||||||
#define PIN_PIO_USB_HOST_DP 20
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Pin for enabling Host VBUS. comment out if not used
|
|
||||||
#ifndef PIN_PIO_USB_HOST_VBUSEN
|
|
||||||
#define PIN_PIO_USB_HOST_VBUSEN 22
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef PIN_PIO_USB_HOST_VBUSEN_STATE
|
|
||||||
#define PIN_PIO_USB_HOST_VBUSEN_STATE 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
// USBHost is defined in usbh_helper.h
|
||||||
|
#include "usbh_helper.h"
|
||||||
|
|
||||||
#define LOG_FILE "cpu_temp.csv"
|
#define LOG_FILE "cpu_temp.csv"
|
||||||
#define LOG_INTERVAL 5000
|
#define LOG_INTERVAL 5000
|
||||||
|
|
||||||
// USB Host object
|
// Analog pin for reading
|
||||||
Adafruit_USBH_Host USBHost;
|
const int analogPin = A0;
|
||||||
|
|
||||||
// USB Host MSC Block Device object which implemented API for use with SdFat
|
// USB Host MSC Block Device object which implemented API for use with SdFat
|
||||||
Adafruit_USBH_MSC_BlockDevice msc_block_dev;
|
Adafruit_USBH_MSC_BlockDevice msc_block_dev;
|
||||||
|
|
@ -63,77 +59,103 @@ File32 f_log;
|
||||||
// if file system is successfully mounted on usb block device
|
// if file system is successfully mounted on usb block device
|
||||||
volatile bool is_mounted = false;
|
volatile bool is_mounted = false;
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
void data_log(void) {
|
||||||
// Setup and Loop on Core0
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
pinMode(LED_BUILTIN, OUTPUT);
|
|
||||||
|
|
||||||
Serial.begin(115200);
|
|
||||||
//while ( !Serial ) delay(10); // wait for native usb
|
|
||||||
|
|
||||||
Serial.println("TinyUSB Host MassStorage Data Logger Example");
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
if (!is_mounted) {
|
if (!is_mounted) {
|
||||||
// nothing to do
|
// nothing to do
|
||||||
delay(1000);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned long last_ms = 0;
|
||||||
|
unsigned long ms = millis();
|
||||||
|
|
||||||
|
if ( ms - last_ms < LOG_INTERVAL ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Turn on LED when start writing
|
// Turn on LED when start writing
|
||||||
|
#ifdef LED_BUILTIN
|
||||||
digitalWrite(LED_BUILTIN, HIGH);
|
digitalWrite(LED_BUILTIN, HIGH);
|
||||||
|
#endif
|
||||||
|
|
||||||
f_log = fatfs.open(LOG_FILE, O_WRITE | O_APPEND | O_CREAT);
|
f_log = fatfs.open(LOG_FILE, O_WRITE | O_APPEND | O_CREAT);
|
||||||
|
|
||||||
if (!f_log) {
|
if (!f_log) {
|
||||||
Serial.println("Cannot create file: " LOG_FILE);
|
Serial.println("Cannot create file: " LOG_FILE);
|
||||||
}else {
|
} else {
|
||||||
float cpu_temp = analogReadTemp();
|
int value = analogRead(analogPin);
|
||||||
uint32_t ms = millis();
|
|
||||||
|
|
||||||
Serial.printf("%u,%.02f\r\n", millis(), cpu_temp);
|
Serial.printf("%lu,%d\r\n", ms, value);
|
||||||
f_log.printf("%u,%.02f\r\n", millis(), cpu_temp);
|
f_log.printf("%lu,%d\r\n", ms, value);
|
||||||
|
|
||||||
f_log.close();
|
f_log.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
delay(LOG_INTERVAL);
|
last_ms = ms;
|
||||||
|
Serial.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
#ifdef USE_FREERTOS
|
||||||
// Setup and Loop on Core1
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
|
|
||||||
void setup1() {
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
//while ( !Serial ) delay(10); // wait for native usb
|
#define USBH_STACK_SZ 2048
|
||||||
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
|
#else
|
||||||
|
#define USBH_STACK_SZ 200
|
||||||
// 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 != 120000000UL && cpu_hz != 240000000UL ) {
|
|
||||||
while ( !Serial ) {
|
|
||||||
delay(10); // wait for native usb
|
|
||||||
}
|
|
||||||
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
|
|
||||||
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n");
|
|
||||||
while(1) {
|
|
||||||
delay(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef PIN_PIO_USB_HOST_VBUSEN
|
|
||||||
pinMode(PIN_PIO_USB_HOST_VBUSEN, OUTPUT);
|
|
||||||
digitalWrite(PIN_PIO_USB_HOST_VBUSEN, PIN_PIO_USB_HOST_VBUSEN_STATE);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
|
void usbhost_rtos_task(void *param) {
|
||||||
pio_cfg.pin_dp = PIN_PIO_USB_HOST_DP;
|
(void) param;
|
||||||
USBHost.configure_pio_usb(1, &pio_cfg);
|
while (1) {
|
||||||
|
USBHost.task();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
#ifdef LED_BUILTIN
|
||||||
|
pinMode(LED_BUILTIN, OUTPUT);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
|
// init host stack on controller (rhport) 1
|
||||||
|
// For rp2040: this is called in core1's setup1()
|
||||||
|
USBHost.begin(1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_FREERTOS
|
||||||
|
// Create a task to run USBHost.task() in background
|
||||||
|
xTaskCreate(usbhost_rtos_task, "usbh", USBH_STACK_SZ, NULL, 3, NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// while ( !Serial ) delay(10); // wait for native usb
|
||||||
|
Serial.println("TinyUSB Host MassStorage Data Logger Example");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Using Host shield MAX3421E controller
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
void loop() {
|
||||||
|
#ifndef USE_FREERTOS
|
||||||
|
USBHost.task();
|
||||||
|
#endif
|
||||||
|
data_log();
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_RP2040)
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// For RP2040 use both core0 for device stack, core1 for host stack
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
void loop() {
|
||||||
|
data_log();
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------- Core1 -------------//
|
||||||
|
void setup1() {
|
||||||
|
// configure pio-usb: defined in usbh_helper.h
|
||||||
|
rp2040_configure_pio_usb();
|
||||||
|
|
||||||
// run host stack on controller (rhport) 1
|
// run host stack on controller (rhport) 1
|
||||||
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
|
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
|
||||||
|
|
@ -141,51 +163,61 @@ void setup1() {
|
||||||
USBHost.begin(1);
|
USBHost.begin(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop1()
|
void loop1() {
|
||||||
{
|
|
||||||
USBHost.task();
|
USBHost.task();
|
||||||
Serial.flush();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// TinyUSB Host callbacks
|
// TinyUSB Host callbacks
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
bool write_complete_callback(uint8_t dev_addr, tuh_msc_complete_data_t const *cb_data) {
|
||||||
|
(void) dev_addr;
|
||||||
|
(void) cb_data;
|
||||||
|
|
||||||
|
#ifdef LED_BUILTIN
|
||||||
|
// turn off LED after write is complete
|
||||||
|
// Note this only marks the usb transfer is complete, device can take longer to actual
|
||||||
|
// write data to physical flash
|
||||||
|
digitalWrite(LED_BUILTIN, LOW);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
|
||||||
// Invoked when device is mounted (configured)
|
// Invoked when device is mounted (configured)
|
||||||
void tuh_mount_cb (uint8_t daddr)
|
void tuh_mount_cb(uint8_t daddr) {
|
||||||
{
|
|
||||||
(void) daddr;
|
(void) daddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invoked when device is unmounted (bus reset/unplugged)
|
/// Invoked when device is unmounted (bus reset/unplugged)
|
||||||
void tuh_umount_cb(uint8_t daddr)
|
void tuh_umount_cb(uint8_t daddr) {
|
||||||
{
|
|
||||||
(void) daddr;
|
(void) daddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoked when a device with MassStorage interface is mounted
|
// Invoked when a device with MassStorage interface is mounted
|
||||||
void tuh_msc_mount_cb(uint8_t dev_addr)
|
void tuh_msc_mount_cb(uint8_t dev_addr) {
|
||||||
{
|
|
||||||
// Initialize block device with MSC device address
|
// Initialize block device with MSC device address
|
||||||
msc_block_dev.begin(dev_addr);
|
msc_block_dev.begin(dev_addr);
|
||||||
|
|
||||||
// For simplicity this example only support LUN 0
|
// For simplicity this example only support LUN 0
|
||||||
msc_block_dev.setActiveLUN(0);
|
msc_block_dev.setActiveLUN(0);
|
||||||
|
|
||||||
msc_block_dev.setWriteCompleteCallback(write_complete_callback);
|
msc_block_dev.setWriteCompleteCallback(write_complete_callback);
|
||||||
|
|
||||||
is_mounted = fatfs.begin(&msc_block_dev);
|
is_mounted = fatfs.begin(&msc_block_dev);
|
||||||
|
|
||||||
if (is_mounted) {
|
if (is_mounted) {
|
||||||
fatfs.ls(&Serial, LS_SIZE);
|
fatfs.ls(&Serial, LS_SIZE);
|
||||||
}else {
|
} else {
|
||||||
Serial.println("Failed to mount mass storage device. Make sure it is formatted as FAT");
|
Serial.println("Failed to mount mass storage device. Make sure it is formatted as FAT");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoked when a device with MassStorage interface is unmounted
|
// Invoked when a device with MassStorage interface is unmounted
|
||||||
void tuh_msc_umount_cb(uint8_t dev_addr)
|
void tuh_msc_umount_cb(uint8_t dev_addr) {
|
||||||
{
|
|
||||||
(void) dev_addr;
|
(void) dev_addr;
|
||||||
|
|
||||||
// unmount file system
|
// unmount file system
|
||||||
|
|
@ -196,17 +228,4 @@ void tuh_msc_umount_cb(uint8_t dev_addr)
|
||||||
msc_block_dev.end();
|
msc_block_dev.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool write_complete_callback(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data)
|
|
||||||
{
|
|
||||||
(void) dev_addr;
|
|
||||||
(void) cb_data;
|
|
||||||
|
|
||||||
// turn off LED after write is complete
|
|
||||||
// Note this only marks the usb transfer is complete, device can take longer to actual
|
|
||||||
// write data to physical flash
|
|
||||||
digitalWrite(LED_BUILTIN, LOW);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
99
examples/DualRole/MassStorage/msc_data_logger/usbh_helper.h
Normal file
99
examples/DualRole/MassStorage/msc_data_logger/usbh_helper.h
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
/*********************************************************************
|
||||||
|
Adafruit invests time and resources providing this open source code,
|
||||||
|
please support Adafruit and open-source hardware by purchasing
|
||||||
|
products from Adafruit!
|
||||||
|
|
||||||
|
MIT license, check LICENSE for more information
|
||||||
|
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||||
|
All text above, and the splash screen below must be included in
|
||||||
|
any redistribution
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#ifndef USBH_HELPER_H
|
||||||
|
#define USBH_HELPER_H
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_RP2040
|
||||||
|
// pio-usb is required for rp2040 host
|
||||||
|
#include "pio_usb.h"
|
||||||
|
|
||||||
|
// Pin D+ for host, D- = D+ + 1
|
||||||
|
#ifndef PIN_USB_HOST_DP
|
||||||
|
#define PIN_USB_HOST_DP 16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Pin for enabling Host VBUS. comment out if not used
|
||||||
|
#ifndef PIN_5V_EN
|
||||||
|
#define PIN_5V_EN 18
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PIN_5V_EN_STATE
|
||||||
|
#define PIN_5V_EN_STATE 1
|
||||||
|
#endif
|
||||||
|
#endif // ARDUINO_ARCH_RP2040
|
||||||
|
|
||||||
|
#include "Adafruit_TinyUSB.h"
|
||||||
|
|
||||||
|
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
|
// USB Host using MAX3421E: SPI, CS, INT
|
||||||
|
#include "SPI.h"
|
||||||
|
|
||||||
|
#if defined(ARDUINO_METRO_ESP32S2)
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 15, 14);
|
||||||
|
#elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2)
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 33, 15);
|
||||||
|
#else
|
||||||
|
// Default CS and INT are pin 10, 9
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 10, 9);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
// Native USB Host such as rp2040
|
||||||
|
Adafruit_USBH_Host USBHost;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Helper Functions
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_RP2040
|
||||||
|
static void rp2040_configure_pio_usb(void) {
|
||||||
|
//while ( !Serial ) delay(10); // wait for native usb
|
||||||
|
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
|
||||||
|
|
||||||
|
// Check for CPU frequency, must be multiple of 12 Mhz 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.printf("Change your CPU Clock to 12*n Mhz in Menu->CPU Speed \r\n");
|
||||||
|
while (1) {
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PIN_5V_EN
|
||||||
|
pinMode(PIN_5V_EN, OUTPUT);
|
||||||
|
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
|
||||||
|
pio_cfg.pin_dp = PIN_USB_HOST_DP;
|
||||||
|
|
||||||
|
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
|
||||||
|
// For pico-w, PIO is also used to communicate with cyw43
|
||||||
|
// Therefore we need to alternate the pio-usb configuration
|
||||||
|
// details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46
|
||||||
|
pio_cfg.sm_tx = 3;
|
||||||
|
pio_cfg.sm_rx = 2;
|
||||||
|
pio_cfg.sm_eop = 3;
|
||||||
|
pio_cfg.pio_rx_num = 0;
|
||||||
|
pio_cfg.pio_tx_num = 1;
|
||||||
|
pio_cfg.tx_ch = 9;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
USBHost.configure_pio_usb(1, &pio_cfg);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
CH32V20x_EVT
|
||||||
|
|
@ -9,43 +9,28 @@
|
||||||
any redistribution
|
any redistribution
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
|
|
||||||
|
|
||||||
/* This example demonstrates use of both device and host, where
|
/* This example demonstrates use of both device and host, where
|
||||||
* - Device run on native usb controller (controller0)
|
* - Device run on native usb controller (roothub port0)
|
||||||
* - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
|
* - Host depending on MCUs run on either:
|
||||||
|
* - rp2040: bit-banging 2 GPIOs with the help of Pico-PIO-USB library (roothub port1)
|
||||||
|
* - samd21/51, nrf52840, esp32: using MAX3421e controller (host shield)
|
||||||
*
|
*
|
||||||
* Requirements:
|
* Requirements:
|
||||||
|
* - For rp2040:
|
||||||
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
|
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
|
||||||
* - 2 consecutive GPIOs: D+ is defined by PIN_PIO_USB_HOST_DP, D- = D+ +1
|
* - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1
|
||||||
* - Provide VBus (5v) and GND for peripheral
|
* - Provide VBus (5v) and GND for peripheral
|
||||||
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
|
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
|
||||||
|
* - For samd21/51, nrf52840, esp32:
|
||||||
|
* - Additional MAX2341e USB Host shield or featherwing is required
|
||||||
|
* - SPI instance, CS pin, INT pin are correctly configured in usbh_helper.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// pio-usb is required for rp2040 host
|
|
||||||
#include "pio_usb.h"
|
|
||||||
|
|
||||||
// SdFat is required for using Adafruit_USBH_MSC_SdFatDevice
|
// SdFat is required for using Adafruit_USBH_MSC_SdFatDevice
|
||||||
#include "SdFat.h"
|
#include "SdFat_Adafruit_Fork.h"
|
||||||
|
|
||||||
// TinyUSB lib
|
// USBHost is defined in usbh_helper.h
|
||||||
#include "Adafruit_TinyUSB.h"
|
#include "usbh_helper.h"
|
||||||
|
|
||||||
// Pin D+ for host, D- = D+ + 1
|
|
||||||
#ifndef PIN_PIO_USB_HOST_DP
|
|
||||||
#define PIN_PIO_USB_HOST_DP 20
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Pin for enabling Host VBUS. comment out if not used
|
|
||||||
#ifndef PIN_PIO_USB_HOST_VBUSEN
|
|
||||||
#define PIN_PIO_USB_HOST_VBUSEN 22
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef PIN_PIO_USB_HOST_VBUSEN_STATE
|
|
||||||
#define PIN_PIO_USB_HOST_VBUSEN_STATE 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// USB Host object
|
|
||||||
Adafruit_USBH_Host USBHost;
|
|
||||||
|
|
||||||
// USB Host MSC Block Device object which implemented API for use with SdFat
|
// USB Host MSC Block Device object which implemented API for use with SdFat
|
||||||
Adafruit_USBH_MSC_BlockDevice msc_block_dev;
|
Adafruit_USBH_MSC_BlockDevice msc_block_dev;
|
||||||
|
|
@ -56,51 +41,40 @@ FatVolume fatfs;
|
||||||
// if file system is successfully mounted on usb block device
|
// if file system is successfully mounted on usb block device
|
||||||
bool is_mounted = false;
|
bool is_mounted = false;
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
void setup() {
|
||||||
// Setup and Loop on Core0
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
//while ( !Serial ) delay(10); // wait for native usb
|
|
||||||
|
|
||||||
|
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
|
// init host stack on controller (rhport) 1
|
||||||
|
// For rp2040: this is called in core1's setup1()
|
||||||
|
USBHost.begin(1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// while ( !Serial ) delay(10); // wait for native usb
|
||||||
Serial.println("TinyUSB Host Mass Storage File Explorer Example");
|
Serial.println("TinyUSB Host Mass Storage File Explorer Example");
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Using Host shield MAX3421E controller
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
void loop() {
|
||||||
|
USBHost.task();
|
||||||
|
Serial.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_RP2040)
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// Setup and Loop on Core1
|
// For RP2040 use both core0 for device stack, core1 for host stack
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
void loop() {
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------- Core1 -------------//
|
||||||
void setup1() {
|
void setup1() {
|
||||||
//while ( !Serial ) delay(10); // wait for native usb
|
// configure pio-usb: defined in usbh_helper.h
|
||||||
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
|
rp2040_configure_pio_usb();
|
||||||
|
|
||||||
// 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 != 120000000UL && cpu_hz != 240000000UL ) {
|
|
||||||
while ( !Serial ) {
|
|
||||||
delay(10); // wait for native usb
|
|
||||||
}
|
|
||||||
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
|
|
||||||
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n");
|
|
||||||
while(1) {
|
|
||||||
delay(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef PIN_PIO_USB_HOST_VBUSEN
|
|
||||||
pinMode(PIN_PIO_USB_HOST_VBUSEN, OUTPUT);
|
|
||||||
digitalWrite(PIN_PIO_USB_HOST_VBUSEN, PIN_PIO_USB_HOST_VBUSEN_STATE);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
|
|
||||||
pio_cfg.pin_dp = PIN_PIO_USB_HOST_DP;
|
|
||||||
USBHost.configure_pio_usb(1, &pio_cfg);
|
|
||||||
|
|
||||||
// run host stack on controller (rhport) 1
|
// run host stack on controller (rhport) 1
|
||||||
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
|
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
|
||||||
|
|
@ -108,30 +82,32 @@ void setup1() {
|
||||||
USBHost.begin(1);
|
USBHost.begin(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop1()
|
void loop1() {
|
||||||
{
|
|
||||||
USBHost.task();
|
USBHost.task();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// TinyUSB Host callbacks
|
// TinyUSB Host callbacks
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
|
||||||
// Invoked when device is mounted (configured)
|
// Invoked when device is mounted (configured)
|
||||||
void tuh_mount_cb (uint8_t daddr)
|
void tuh_mount_cb(uint8_t daddr) {
|
||||||
{
|
|
||||||
(void) daddr;
|
(void) daddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invoked when device is unmounted (bus reset/unplugged)
|
/// Invoked when device is unmounted (bus reset/unplugged)
|
||||||
void tuh_umount_cb(uint8_t daddr)
|
void tuh_umount_cb(uint8_t daddr) {
|
||||||
{
|
|
||||||
(void) daddr;
|
(void) daddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoked when a device with MassStorage interface is mounted
|
// Invoked when a device with MassStorage interface is mounted
|
||||||
void tuh_msc_mount_cb(uint8_t dev_addr)
|
void tuh_msc_mount_cb(uint8_t dev_addr) {
|
||||||
{
|
Serial.printf("Device attached, address = %d\r\n", dev_addr);
|
||||||
|
|
||||||
// Initialize block device with MSC device address
|
// Initialize block device with MSC device address
|
||||||
msc_block_dev.begin(dev_addr);
|
msc_block_dev.begin(dev_addr);
|
||||||
|
|
||||||
|
|
@ -146,9 +122,8 @@ void tuh_msc_mount_cb(uint8_t dev_addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoked when a device with MassStorage interface is unmounted
|
// Invoked when a device with MassStorage interface is unmounted
|
||||||
void tuh_msc_umount_cb(uint8_t dev_addr)
|
void tuh_msc_umount_cb(uint8_t dev_addr) {
|
||||||
{
|
Serial.printf("Device removed, address = %d\r\n", dev_addr);
|
||||||
(void) dev_addr;
|
|
||||||
|
|
||||||
// unmount file system
|
// unmount file system
|
||||||
is_mounted = false;
|
is_mounted = false;
|
||||||
|
|
@ -158,3 +133,4 @@ void tuh_msc_umount_cb(uint8_t dev_addr)
|
||||||
msc_block_dev.end();
|
msc_block_dev.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
/*********************************************************************
|
||||||
|
Adafruit invests time and resources providing this open source code,
|
||||||
|
please support Adafruit and open-source hardware by purchasing
|
||||||
|
products from Adafruit!
|
||||||
|
|
||||||
|
MIT license, check LICENSE for more information
|
||||||
|
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||||
|
All text above, and the splash screen below must be included in
|
||||||
|
any redistribution
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#ifndef USBH_HELPER_H
|
||||||
|
#define USBH_HELPER_H
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_RP2040
|
||||||
|
// pio-usb is required for rp2040 host
|
||||||
|
#include "pio_usb.h"
|
||||||
|
|
||||||
|
// Pin D+ for host, D- = D+ + 1
|
||||||
|
#ifndef PIN_USB_HOST_DP
|
||||||
|
#define PIN_USB_HOST_DP 16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Pin for enabling Host VBUS. comment out if not used
|
||||||
|
#ifndef PIN_5V_EN
|
||||||
|
#define PIN_5V_EN 18
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PIN_5V_EN_STATE
|
||||||
|
#define PIN_5V_EN_STATE 1
|
||||||
|
#endif
|
||||||
|
#endif // ARDUINO_ARCH_RP2040
|
||||||
|
|
||||||
|
#include "Adafruit_TinyUSB.h"
|
||||||
|
|
||||||
|
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
|
// USB Host using MAX3421E: SPI, CS, INT
|
||||||
|
#include "SPI.h"
|
||||||
|
|
||||||
|
#if defined(ARDUINO_METRO_ESP32S2)
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 15, 14);
|
||||||
|
#elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2)
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 33, 15);
|
||||||
|
#else
|
||||||
|
// Default CS and INT are pin 10, 9
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 10, 9);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
// Native USB Host such as rp2040
|
||||||
|
Adafruit_USBH_Host USBHost;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Helper Functions
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_RP2040
|
||||||
|
static void rp2040_configure_pio_usb(void) {
|
||||||
|
//while ( !Serial ) delay(10); // wait for native usb
|
||||||
|
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
|
||||||
|
|
||||||
|
// Check for CPU frequency, must be multiple of 12 Mhz 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.printf("Change your CPU Clock to 12*n Mhz in Menu->CPU Speed \r\n");
|
||||||
|
while (1) {
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PIN_5V_EN
|
||||||
|
pinMode(PIN_5V_EN, OUTPUT);
|
||||||
|
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
|
||||||
|
pio_cfg.pin_dp = PIN_USB_HOST_DP;
|
||||||
|
|
||||||
|
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
|
||||||
|
// For pico-w, PIO is also used to communicate with cyw43
|
||||||
|
// Therefore we need to alternate the pio-usb configuration
|
||||||
|
// details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46
|
||||||
|
pio_cfg.sm_tx = 3;
|
||||||
|
pio_cfg.sm_rx = 2;
|
||||||
|
pio_cfg.sm_eop = 3;
|
||||||
|
pio_cfg.pio_rx_num = 0;
|
||||||
|
pio_cfg.pio_tx_num = 1;
|
||||||
|
pio_cfg.tx_ch = 9;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
USBHost.configure_pio_usb(1, &pio_cfg);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
1
examples/DualRole/Simple/device_info/.skip.txt
Normal file
1
examples/DualRole/Simple/device_info/.skip.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
CH32V20x_EVT
|
||||||
268
examples/DualRole/Simple/device_info/device_info.ino
Normal file
268
examples/DualRole/Simple/device_info/device_info.ino
Normal file
|
|
@ -0,0 +1,268 @@
|
||||||
|
/*********************************************************************
|
||||||
|
Adafruit invests time and resources providing this open source code,
|
||||||
|
please support Adafruit and open-source hardware by purchasing
|
||||||
|
products from Adafruit!
|
||||||
|
|
||||||
|
MIT license, check LICENSE for more information
|
||||||
|
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||||
|
All text above, and the splash screen below must be included in
|
||||||
|
any redistribution
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
/* This example demonstrates use of both device and host, where
|
||||||
|
* - Device run on native usb controller (roothub port0)
|
||||||
|
* - Host depending on MCUs run on either:
|
||||||
|
* - rp2040: bit-banging 2 GPIOs with the help of Pico-PIO-USB library (roothub port1)
|
||||||
|
* - samd21/51, nrf52840, esp32: using MAX3421e controller (host shield)
|
||||||
|
*
|
||||||
|
* Requirements:
|
||||||
|
* - For rp2040:
|
||||||
|
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
|
||||||
|
* - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1
|
||||||
|
* - Provide VBus (5v) and GND for peripheral
|
||||||
|
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
|
||||||
|
* - For samd21/51, nrf52840, esp32:
|
||||||
|
* - Additional MAX2341e USB Host shield or featherwing is required
|
||||||
|
* - SPI instance, CS pin, INT pin are correctly configured in usbh_helper.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Host example will get device descriptors of attached devices and print it out via
|
||||||
|
* device cdc (Serial) as follows:
|
||||||
|
* Device 1: ID 046d:c52f
|
||||||
|
Device Descriptor:
|
||||||
|
bLength 18
|
||||||
|
bDescriptorType 1
|
||||||
|
bcdUSB 0200
|
||||||
|
bDeviceClass 0
|
||||||
|
bDeviceSubClass 0
|
||||||
|
bDeviceProtocol 0
|
||||||
|
bMaxPacketSize0 8
|
||||||
|
idVendor 0x046d
|
||||||
|
idProduct 0xc52f
|
||||||
|
bcdDevice 2200
|
||||||
|
iManufacturer 1 Logitech
|
||||||
|
iProduct 2 USB Receiver
|
||||||
|
iSerialNumber 0
|
||||||
|
bNumConfigurations 1
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// USBHost is defined in usbh_helper.h
|
||||||
|
#include "usbh_helper.h"
|
||||||
|
|
||||||
|
// Language ID: English
|
||||||
|
#define LANGUAGE_ID 0x0409
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
tusb_desc_device_t desc_device;
|
||||||
|
uint16_t manufacturer[32];
|
||||||
|
uint16_t product[48];
|
||||||
|
uint16_t serial[16];
|
||||||
|
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 };
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
|
// init host stack on controller (rhport) 1
|
||||||
|
// For rp2040: this is called in core1's setup1()
|
||||||
|
USBHost.begin(1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// while ( !Serial ) delay(10); // wait for native usb
|
||||||
|
Serial.println("TinyUSB Dual Device Info Example");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Using Host shield MAX3421E controller
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
void loop() {
|
||||||
|
USBHost.task();
|
||||||
|
Serial.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_RP2040)
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// For RP2040 use both core0 for device stack, core1 for host stack
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
//------------- Core0 -------------//
|
||||||
|
void loop() {
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------- Core1 -------------//
|
||||||
|
void setup1() {
|
||||||
|
//while ( !Serial ) delay(10); // wait for native usb
|
||||||
|
// configure pio-usb: defined in usbh_helper.h
|
||||||
|
rp2040_configure_pio_usb();
|
||||||
|
|
||||||
|
// run host stack on controller (rhport) 1
|
||||||
|
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
|
||||||
|
// host bit-banging processing works done in core1 to free up core0 for other works
|
||||||
|
USBHost.begin(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop1() {
|
||||||
|
USBHost.task();
|
||||||
|
Serial.flush();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// TinyUSB Host callbacks
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
void print_device_descriptor(tuh_xfer_t *xfer);
|
||||||
|
|
||||||
|
void utf16_to_utf8(uint16_t *temp_buf, size_t buf_len);
|
||||||
|
|
||||||
|
void print_lsusb(void) {
|
||||||
|
bool no_device = true;
|
||||||
|
for (uint8_t daddr = 1; daddr < CFG_TUH_DEVICE_MAX + 1; daddr++) {
|
||||||
|
// TODO can use tuh_mounted(daddr), but tinyusb has an bug
|
||||||
|
// use local connected flag instead
|
||||||
|
dev_info_t *dev = &dev_info[daddr - 1];
|
||||||
|
if (dev->mounted) {
|
||||||
|
Serial.printf("Device %u: ID %04x:%04x %s %s\r\n", daddr,
|
||||||
|
dev->desc_device.idVendor, dev->desc_device.idProduct,
|
||||||
|
(char *) dev->manufacturer, (char *) dev->product);
|
||||||
|
|
||||||
|
no_device = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (no_device) {
|
||||||
|
Serial.println("No device connected (except hub)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoked when device is mounted (configured)
|
||||||
|
void tuh_mount_cb(uint8_t daddr) {
|
||||||
|
Serial.printf("Device attached, address = %d\r\n", daddr);
|
||||||
|
|
||||||
|
dev_info_t *dev = &dev_info[daddr - 1];
|
||||||
|
dev->mounted = true;
|
||||||
|
|
||||||
|
// Get Device Descriptor
|
||||||
|
tuh_descriptor_get_device(daddr, &dev->desc_device, 18, print_device_descriptor, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invoked when device is unmounted (bus reset/unplugged)
|
||||||
|
void tuh_umount_cb(uint8_t daddr) {
|
||||||
|
Serial.printf("Device removed, address = %d\r\n", daddr);
|
||||||
|
dev_info_t *dev = &dev_info[daddr - 1];
|
||||||
|
dev->mounted = false;
|
||||||
|
|
||||||
|
// print device summary
|
||||||
|
print_lsusb();
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_device_descriptor(tuh_xfer_t *xfer) {
|
||||||
|
if (XFER_RESULT_SUCCESS != xfer->result) {
|
||||||
|
Serial.printf("Failed to get device descriptor\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t const daddr = xfer->daddr;
|
||||||
|
dev_info_t *dev = &dev_info[daddr - 1];
|
||||||
|
tusb_desc_device_t *desc = &dev->desc_device;
|
||||||
|
|
||||||
|
Serial.printf("Device %u: ID %04x:%04x\r\n", daddr, desc->idVendor, desc->idProduct);
|
||||||
|
Serial.printf("Device Descriptor:\r\n");
|
||||||
|
Serial.printf(" bLength %u\r\n" , desc->bLength);
|
||||||
|
Serial.printf(" bDescriptorType %u\r\n" , desc->bDescriptorType);
|
||||||
|
Serial.printf(" bcdUSB %04x\r\n" , desc->bcdUSB);
|
||||||
|
Serial.printf(" bDeviceClass %u\r\n" , desc->bDeviceClass);
|
||||||
|
Serial.printf(" bDeviceSubClass %u\r\n" , desc->bDeviceSubClass);
|
||||||
|
Serial.printf(" bDeviceProtocol %u\r\n" , desc->bDeviceProtocol);
|
||||||
|
Serial.printf(" bMaxPacketSize0 %u\r\n" , desc->bMaxPacketSize0);
|
||||||
|
Serial.printf(" idVendor 0x%04x\r\n" , desc->idVendor);
|
||||||
|
Serial.printf(" idProduct 0x%04x\r\n" , desc->idProduct);
|
||||||
|
Serial.printf(" bcdDevice %04x\r\n" , desc->bcdDevice);
|
||||||
|
|
||||||
|
// Get String descriptor using Sync API
|
||||||
|
Serial.printf(" iManufacturer %u ", desc->iManufacturer);
|
||||||
|
if (XFER_RESULT_SUCCESS ==
|
||||||
|
tuh_descriptor_get_manufacturer_string_sync(daddr, LANGUAGE_ID, dev->manufacturer, sizeof(dev->manufacturer))) {
|
||||||
|
utf16_to_utf8(dev->manufacturer, sizeof(dev->manufacturer));
|
||||||
|
Serial.printf((char *) dev->manufacturer);
|
||||||
|
}
|
||||||
|
Serial.printf("\r\n");
|
||||||
|
|
||||||
|
Serial.printf(" iProduct %u ", desc->iProduct);
|
||||||
|
if (XFER_RESULT_SUCCESS ==
|
||||||
|
tuh_descriptor_get_product_string_sync(daddr, LANGUAGE_ID, dev->product, sizeof(dev->product))) {
|
||||||
|
utf16_to_utf8(dev->product, sizeof(dev->product));
|
||||||
|
Serial.printf((char *) dev->product);
|
||||||
|
}
|
||||||
|
Serial.printf("\r\n");
|
||||||
|
|
||||||
|
Serial.printf(" iSerialNumber %u ", desc->iSerialNumber);
|
||||||
|
if (XFER_RESULT_SUCCESS ==
|
||||||
|
tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, dev->serial, sizeof(dev->serial))) {
|
||||||
|
utf16_to_utf8(dev->serial, sizeof(dev->serial));
|
||||||
|
Serial.printf((char *) dev->serial);
|
||||||
|
}
|
||||||
|
Serial.printf("\r\n");
|
||||||
|
|
||||||
|
Serial.printf(" bNumConfigurations %u\r\n", desc->bNumConfigurations);
|
||||||
|
|
||||||
|
// print device summary
|
||||||
|
print_lsusb();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// String Descriptor Helper
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
static void _convert_utf16le_to_utf8(const uint16_t *utf16, size_t utf16_len, uint8_t *utf8, size_t utf8_len) {
|
||||||
|
// TODO: Check for runover.
|
||||||
|
(void) utf8_len;
|
||||||
|
// Get the UTF-16 length out of the data itself.
|
||||||
|
|
||||||
|
for (size_t i = 0; i < utf16_len; i++) {
|
||||||
|
uint16_t chr = utf16[i];
|
||||||
|
if (chr < 0x80) {
|
||||||
|
*utf8++ = chr & 0xff;
|
||||||
|
} else if (chr < 0x800) {
|
||||||
|
*utf8++ = (uint8_t) (0xC0 | (chr >> 6 & 0x1F));
|
||||||
|
*utf8++ = (uint8_t) (0x80 | (chr >> 0 & 0x3F));
|
||||||
|
} else {
|
||||||
|
// TODO: Verify surrogate.
|
||||||
|
*utf8++ = (uint8_t) (0xE0 | (chr >> 12 & 0x0F));
|
||||||
|
*utf8++ = (uint8_t) (0x80 | (chr >> 6 & 0x3F));
|
||||||
|
*utf8++ = (uint8_t) (0x80 | (chr >> 0 & 0x3F));
|
||||||
|
}
|
||||||
|
// TODO: Handle UTF-16 code points that take two entries.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count how many bytes a utf-16-le encoded string will take in utf-8.
|
||||||
|
static int _count_utf8_bytes(const uint16_t *buf, size_t len) {
|
||||||
|
size_t total_bytes = 0;
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
uint16_t chr = buf[i];
|
||||||
|
if (chr < 0x80) {
|
||||||
|
total_bytes += 1;
|
||||||
|
} else if (chr < 0x800) {
|
||||||
|
total_bytes += 2;
|
||||||
|
} else {
|
||||||
|
total_bytes += 3;
|
||||||
|
}
|
||||||
|
// TODO: Handle UTF-16 code points that take two entries.
|
||||||
|
}
|
||||||
|
return total_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void utf16_to_utf8(uint16_t *temp_buf, size_t buf_len) {
|
||||||
|
size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t);
|
||||||
|
size_t utf8_len = _count_utf8_bytes(temp_buf + 1, utf16_len);
|
||||||
|
|
||||||
|
_convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, buf_len);
|
||||||
|
((uint8_t *) temp_buf)[utf8_len] = '\0';
|
||||||
|
}
|
||||||
99
examples/DualRole/Simple/device_info/usbh_helper.h
Normal file
99
examples/DualRole/Simple/device_info/usbh_helper.h
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
/*********************************************************************
|
||||||
|
Adafruit invests time and resources providing this open source code,
|
||||||
|
please support Adafruit and open-source hardware by purchasing
|
||||||
|
products from Adafruit!
|
||||||
|
|
||||||
|
MIT license, check LICENSE for more information
|
||||||
|
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||||
|
All text above, and the splash screen below must be included in
|
||||||
|
any redistribution
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#ifndef USBH_HELPER_H
|
||||||
|
#define USBH_HELPER_H
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_RP2040
|
||||||
|
// pio-usb is required for rp2040 host
|
||||||
|
#include "pio_usb.h"
|
||||||
|
|
||||||
|
// Pin D+ for host, D- = D+ + 1
|
||||||
|
#ifndef PIN_USB_HOST_DP
|
||||||
|
#define PIN_USB_HOST_DP 16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Pin for enabling Host VBUS. comment out if not used
|
||||||
|
#ifndef PIN_5V_EN
|
||||||
|
#define PIN_5V_EN 18
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PIN_5V_EN_STATE
|
||||||
|
#define PIN_5V_EN_STATE 1
|
||||||
|
#endif
|
||||||
|
#endif // ARDUINO_ARCH_RP2040
|
||||||
|
|
||||||
|
#include "Adafruit_TinyUSB.h"
|
||||||
|
|
||||||
|
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
|
// USB Host using MAX3421E: SPI, CS, INT
|
||||||
|
#include "SPI.h"
|
||||||
|
|
||||||
|
#if defined(ARDUINO_METRO_ESP32S2)
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 15, 14);
|
||||||
|
#elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2)
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 33, 15);
|
||||||
|
#else
|
||||||
|
// Default CS and INT are pin 10, 9
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 10, 9);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
// Native USB Host such as rp2040
|
||||||
|
Adafruit_USBH_Host USBHost;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Helper Functions
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_RP2040
|
||||||
|
static void rp2040_configure_pio_usb(void) {
|
||||||
|
//while ( !Serial ) delay(10); // wait for native usb
|
||||||
|
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
|
||||||
|
|
||||||
|
// Check for CPU frequency, must be multiple of 12 Mhz 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.printf("Change your CPU Clock to 12*n Mhz in Menu->CPU Speed \r\n");
|
||||||
|
while (1) {
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PIN_5V_EN
|
||||||
|
pinMode(PIN_5V_EN, OUTPUT);
|
||||||
|
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
|
||||||
|
pio_cfg.pin_dp = PIN_USB_HOST_DP;
|
||||||
|
|
||||||
|
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
|
||||||
|
// For pico-w, PIO is also used to communicate with cyw43
|
||||||
|
// Therefore we need to alternate the pio-usb configuration
|
||||||
|
// details https://github.com/sekigon-gonnoc/Pico-PIO-USB/issues/46
|
||||||
|
pio_cfg.sm_tx = 3;
|
||||||
|
pio_cfg.sm_rx = 2;
|
||||||
|
pio_cfg.sm_eop = 3;
|
||||||
|
pio_cfg.pio_rx_num = 0;
|
||||||
|
pio_cfg.pio_tx_num = 1;
|
||||||
|
pio_cfg.tx_ch = 9;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
USBHost.configure_pio_usb(1, &pio_cfg);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
2
examples/DualRole/Simple/device_info_max3421e/.skip.txt
Normal file
2
examples/DualRole/Simple/device_info_max3421e/.skip.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
CH32V20x_EVT
|
||||||
|
|
@ -0,0 +1,241 @@
|
||||||
|
/*********************************************************************
|
||||||
|
Adafruit invests time and resources providing this open source code,
|
||||||
|
please support Adafruit and open-source hardware by purchasing
|
||||||
|
products from Adafruit!
|
||||||
|
|
||||||
|
MIT license, check LICENSE for more information
|
||||||
|
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||||
|
All text above, and the splash screen below must be included in
|
||||||
|
any redistribution
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
/* This example demonstrates use of both device and host, where
|
||||||
|
* - Device run on native usb controller (roothub port0)
|
||||||
|
* - Host run on MAX3421E controller (roothub port1) tested with:
|
||||||
|
* - SAMD21, SAMD51, nRF52840, ESP32S2, ESP32S3, ESP32
|
||||||
|
* - RP2040: "pio_usb.h" must not be included, otherwise pio-usb will be used as host controller
|
||||||
|
*
|
||||||
|
* Requirements:
|
||||||
|
* - SPI instance, CS pin, INT pin are correctly configured
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Host example will get device descriptors of attached devices and print it out:
|
||||||
|
* Device 1: ID 046d:c52f
|
||||||
|
Device Descriptor:
|
||||||
|
bLength 18
|
||||||
|
bDescriptorType 1
|
||||||
|
bcdUSB 0200
|
||||||
|
bDeviceClass 0
|
||||||
|
bDeviceSubClass 0
|
||||||
|
bDeviceProtocol 0
|
||||||
|
bMaxPacketSize0 8
|
||||||
|
idVendor 0x046d
|
||||||
|
idProduct 0xc52f
|
||||||
|
bcdDevice 2200
|
||||||
|
iManufacturer 1 Logitech
|
||||||
|
iProduct 2 USB Receiver
|
||||||
|
iSerialNumber 0
|
||||||
|
bNumConfigurations 1
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include "Adafruit_TinyUSB.h"
|
||||||
|
#include "SPI.h"
|
||||||
|
|
||||||
|
// USB Host using MAX3421E: SPI, CS, INT
|
||||||
|
#if defined(ARDUINO_METRO_ESP32S2)
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 15, 14);
|
||||||
|
#elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32_V2)
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 33, 15);
|
||||||
|
#elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32C6)
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 8, 7);
|
||||||
|
#elif defined(ARDUINO_ESP32C3_DEV)
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 10, 7);
|
||||||
|
#else
|
||||||
|
// Default CS and INT are pin 10, 9
|
||||||
|
Adafruit_USBH_Host USBHost(&SPI, 10, 9);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Language ID: English
|
||||||
|
#define LANGUAGE_ID 0x0409
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
tusb_desc_device_t desc_device;
|
||||||
|
uint16_t manufacturer[32];
|
||||||
|
uint16_t product[48];
|
||||||
|
uint16_t serial[16];
|
||||||
|
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() & loop()
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
// init host stack on controller (rhport) 1
|
||||||
|
USBHost.begin(1);
|
||||||
|
|
||||||
|
// while ( !Serial ) delay(10); // wait for native usb
|
||||||
|
Serial.println("TinyUSB Dual: Device Info Example with MAX3421E");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
USBHost.task();
|
||||||
|
Serial.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// TinyUSB Host callbacks
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
void print_device_descriptor(tuh_xfer_t *xfer);
|
||||||
|
|
||||||
|
void utf16_to_utf8(uint16_t *temp_buf, size_t buf_len);
|
||||||
|
|
||||||
|
void print_lsusb(void) {
|
||||||
|
bool no_device = true;
|
||||||
|
for (uint8_t daddr = 1; daddr < CFG_TUH_DEVICE_MAX + 1; daddr++) {
|
||||||
|
// TODO can use tuh_mounted(daddr), but tinyusb has an bug
|
||||||
|
// use local connected flag instead
|
||||||
|
dev_info_t *dev = &dev_info[daddr - 1];
|
||||||
|
if (dev->mounted) {
|
||||||
|
Serial.printf("Device %u: ID %04x:%04x %s %s\r\n", daddr,
|
||||||
|
dev->desc_device.idVendor, dev->desc_device.idProduct,
|
||||||
|
(char *) dev->manufacturer, (char *) dev->product);
|
||||||
|
|
||||||
|
no_device = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (no_device) {
|
||||||
|
Serial.println("No device connected (except hub)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoked when device is mounted (configured)
|
||||||
|
void tuh_mount_cb(uint8_t daddr) {
|
||||||
|
Serial.printf("Device attached, address = %d\r\n", daddr);
|
||||||
|
|
||||||
|
dev_info_t *dev = &dev_info[daddr - 1];
|
||||||
|
dev->mounted = true;
|
||||||
|
|
||||||
|
// Get Device Descriptor
|
||||||
|
tuh_descriptor_get_device(daddr, &dev->desc_device, 18, print_device_descriptor, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invoked when device is unmounted (bus reset/unplugged)
|
||||||
|
void tuh_umount_cb(uint8_t daddr) {
|
||||||
|
Serial.printf("Device removed, address = %d\r\n", daddr);
|
||||||
|
dev_info_t *dev = &dev_info[daddr - 1];
|
||||||
|
dev->mounted = false;
|
||||||
|
|
||||||
|
// print device summary
|
||||||
|
print_lsusb();
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_device_descriptor(tuh_xfer_t *xfer) {
|
||||||
|
if (XFER_RESULT_SUCCESS != xfer->result) {
|
||||||
|
Serial.printf("Failed to get device descriptor\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t const daddr = xfer->daddr;
|
||||||
|
dev_info_t *dev = &dev_info[daddr - 1];
|
||||||
|
tusb_desc_device_t *desc = &dev->desc_device;
|
||||||
|
|
||||||
|
Serial.printf("Device %u: ID %04x:%04x\r\n", daddr, desc->idVendor, desc->idProduct);
|
||||||
|
Serial.printf("Device Descriptor:\r\n");
|
||||||
|
Serial.printf(" bLength %u\r\n" , desc->bLength);
|
||||||
|
Serial.printf(" bDescriptorType %u\r\n" , desc->bDescriptorType);
|
||||||
|
Serial.printf(" bcdUSB %04x\r\n" , desc->bcdUSB);
|
||||||
|
Serial.printf(" bDeviceClass %u\r\n" , desc->bDeviceClass);
|
||||||
|
Serial.printf(" bDeviceSubClass %u\r\n" , desc->bDeviceSubClass);
|
||||||
|
Serial.printf(" bDeviceProtocol %u\r\n" , desc->bDeviceProtocol);
|
||||||
|
Serial.printf(" bMaxPacketSize0 %u\r\n" , desc->bMaxPacketSize0);
|
||||||
|
Serial.printf(" idVendor 0x%04x\r\n" , desc->idVendor);
|
||||||
|
Serial.printf(" idProduct 0x%04x\r\n" , desc->idProduct);
|
||||||
|
Serial.printf(" bcdDevice %04x\r\n" , desc->bcdDevice);
|
||||||
|
|
||||||
|
// Get String descriptor using Sync API
|
||||||
|
Serial.printf(" iManufacturer %u ", desc->iManufacturer);
|
||||||
|
if (XFER_RESULT_SUCCESS ==
|
||||||
|
tuh_descriptor_get_manufacturer_string_sync(daddr, LANGUAGE_ID, dev->manufacturer, sizeof(dev->manufacturer))) {
|
||||||
|
utf16_to_utf8(dev->manufacturer, sizeof(dev->manufacturer));
|
||||||
|
Serial.printf((char *) dev->manufacturer);
|
||||||
|
}
|
||||||
|
Serial.printf("\r\n");
|
||||||
|
|
||||||
|
Serial.printf(" iProduct %u ", desc->iProduct);
|
||||||
|
if (XFER_RESULT_SUCCESS ==
|
||||||
|
tuh_descriptor_get_product_string_sync(daddr, LANGUAGE_ID, dev->product, sizeof(dev->product))) {
|
||||||
|
utf16_to_utf8(dev->product, sizeof(dev->product));
|
||||||
|
Serial.printf((char *) dev->product);
|
||||||
|
}
|
||||||
|
Serial.printf("\r\n");
|
||||||
|
|
||||||
|
Serial.printf(" iSerialNumber %u ", desc->iSerialNumber);
|
||||||
|
if (XFER_RESULT_SUCCESS ==
|
||||||
|
tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, dev->serial, sizeof(dev->serial))) {
|
||||||
|
utf16_to_utf8(dev->serial, sizeof(dev->serial));
|
||||||
|
Serial.printf((char *) dev->serial);
|
||||||
|
}
|
||||||
|
Serial.printf("\r\n");
|
||||||
|
|
||||||
|
Serial.printf(" bNumConfigurations %u\r\n", desc->bNumConfigurations);
|
||||||
|
|
||||||
|
// print device summary
|
||||||
|
print_lsusb();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// String Descriptor Helper
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
static void _convert_utf16le_to_utf8(const uint16_t *utf16, size_t utf16_len, uint8_t *utf8, size_t utf8_len) {
|
||||||
|
// TODO: Check for runover.
|
||||||
|
(void) utf8_len;
|
||||||
|
// Get the UTF-16 length out of the data itself.
|
||||||
|
|
||||||
|
for (size_t i = 0; i < utf16_len; i++) {
|
||||||
|
uint16_t chr = utf16[i];
|
||||||
|
if (chr < 0x80) {
|
||||||
|
*utf8++ = chr & 0xff;
|
||||||
|
} else if (chr < 0x800) {
|
||||||
|
*utf8++ = (uint8_t) (0xC0 | (chr >> 6 & 0x1F));
|
||||||
|
*utf8++ = (uint8_t) (0x80 | (chr >> 0 & 0x3F));
|
||||||
|
} else {
|
||||||
|
// TODO: Verify surrogate.
|
||||||
|
*utf8++ = (uint8_t) (0xE0 | (chr >> 12 & 0x0F));
|
||||||
|
*utf8++ = (uint8_t) (0x80 | (chr >> 6 & 0x3F));
|
||||||
|
*utf8++ = (uint8_t) (0x80 | (chr >> 0 & 0x3F));
|
||||||
|
}
|
||||||
|
// TODO: Handle UTF-16 code points that take two entries.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count how many bytes a utf-16-le encoded string will take in utf-8.
|
||||||
|
static int _count_utf8_bytes(const uint16_t *buf, size_t len) {
|
||||||
|
size_t total_bytes = 0;
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
uint16_t chr = buf[i];
|
||||||
|
if (chr < 0x80) {
|
||||||
|
total_bytes += 1;
|
||||||
|
} else if (chr < 0x800) {
|
||||||
|
total_bytes += 2;
|
||||||
|
} else {
|
||||||
|
total_bytes += 3;
|
||||||
|
}
|
||||||
|
// TODO: Handle UTF-16 code points that take two entries.
|
||||||
|
}
|
||||||
|
return total_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void utf16_to_utf8(uint16_t *temp_buf, size_t buf_len) {
|
||||||
|
size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t);
|
||||||
|
size_t utf8_len = _count_utf8_bytes(temp_buf + 1, utf16_len);
|
||||||
|
|
||||||
|
_convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, buf_len);
|
||||||
|
((uint8_t *) temp_buf)[utf8_len] = '\0';
|
||||||
|
}
|
||||||
|
|
@ -1,252 +0,0 @@
|
||||||
/*********************************************************************
|
|
||||||
Adafruit invests time and resources providing this open source code,
|
|
||||||
please support Adafruit and open-source hardware by purchasing
|
|
||||||
products from Adafruit!
|
|
||||||
|
|
||||||
MIT license, check LICENSE for more information
|
|
||||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
|
||||||
All text above, and the splash screen below must be included in
|
|
||||||
any redistribution
|
|
||||||
*********************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
/* This example demonstrates use of both device and host, where
|
|
||||||
* - Device run on native usb controller (controller0)
|
|
||||||
* - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
|
|
||||||
*
|
|
||||||
* Requirements:
|
|
||||||
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
|
|
||||||
* - 2 consecutive GPIOs: D+ is defined by PIN_PIO_USB_HOST_DP, D- = D+ +1
|
|
||||||
* - Provide VBus (5v) and GND for peripheral
|
|
||||||
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
|
|
||||||
*
|
|
||||||
* RP2040 host stack will get device descriptors of attached devices and print it out via
|
|
||||||
* device cdc (Serial) as follows:
|
|
||||||
* Device 1: ID 046d:c52f
|
|
||||||
Device Descriptor:
|
|
||||||
bLength 18
|
|
||||||
bDescriptorType 1
|
|
||||||
bcdUSB 0200
|
|
||||||
bDeviceClass 0
|
|
||||||
bDeviceSubClass 0
|
|
||||||
bDeviceProtocol 0
|
|
||||||
bMaxPacketSize0 8
|
|
||||||
idVendor 0x046d
|
|
||||||
idProduct 0xc52f
|
|
||||||
bcdDevice 2200
|
|
||||||
iManufacturer 1 Logitech
|
|
||||||
iProduct 2 USB Receiver
|
|
||||||
iSerialNumber 0
|
|
||||||
bNumConfigurations 1
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
// pio-usb is required for rp2040 host
|
|
||||||
#include "pio_usb.h"
|
|
||||||
#include "Adafruit_TinyUSB.h"
|
|
||||||
|
|
||||||
// Pin D+ for host, D- = D+ + 1
|
|
||||||
#ifndef PIN_PIO_USB_HOST_DP
|
|
||||||
#define PIN_PIO_USB_HOST_DP 20
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Pin for enabling Host VBUS. comment out if not used
|
|
||||||
#ifndef PIN_PIO_USB_HOST_VBUSEN
|
|
||||||
#define PIN_PIO_USB_HOST_VBUSEN 22
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef PIN_PIO_USB_HOST_VBUSEN_STATE
|
|
||||||
#define PIN_PIO_USB_HOST_VBUSEN_STATE 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Language ID: English
|
|
||||||
#define LANGUAGE_ID 0x0409
|
|
||||||
|
|
||||||
// USB Host object
|
|
||||||
Adafruit_USBH_Host USBHost;
|
|
||||||
|
|
||||||
// holding device descriptor
|
|
||||||
tusb_desc_device_t desc_device;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
// Setup and Loop on Core0
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
|
|
||||||
// the setup function runs once when you press reset or power the board
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
Serial1.begin(115200);
|
|
||||||
|
|
||||||
Serial.begin(115200);
|
|
||||||
//while ( !Serial ) delay(10); // wait for native usb
|
|
||||||
|
|
||||||
Serial.println("TinyUSB Dual Device Info Example");
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
// Setup and Loop on Core1
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
|
|
||||||
void setup1() {
|
|
||||||
//while ( !Serial ) delay(10); // wait for native usb
|
|
||||||
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
|
|
||||||
|
|
||||||
// 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 != 120000000UL && cpu_hz != 240000000UL ) {
|
|
||||||
while ( !Serial ) {
|
|
||||||
delay(10); // wait for native usb
|
|
||||||
}
|
|
||||||
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
|
|
||||||
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n");
|
|
||||||
while(1) {
|
|
||||||
delay(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef PIN_PIO_USB_HOST_VBUSEN
|
|
||||||
pinMode(PIN_PIO_USB_HOST_VBUSEN, OUTPUT);
|
|
||||||
digitalWrite(PIN_PIO_USB_HOST_VBUSEN, PIN_PIO_USB_HOST_VBUSEN_STATE);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
|
|
||||||
pio_cfg.pin_dp = PIN_PIO_USB_HOST_DP;
|
|
||||||
USBHost.configure_pio_usb(1, &pio_cfg);
|
|
||||||
|
|
||||||
// run host stack on controller (rhport) 1
|
|
||||||
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
|
|
||||||
// host bit-banging processing works done in core1 to free up core0 for other works
|
|
||||||
USBHost.begin(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop1()
|
|
||||||
{
|
|
||||||
USBHost.task();
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
// TinyUSB Host callbacks
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
|
|
||||||
// Invoked when device is mounted (configured)
|
|
||||||
void tuh_mount_cb (uint8_t daddr)
|
|
||||||
{
|
|
||||||
Serial.printf("Device attached, address = %d\r\n", daddr);
|
|
||||||
|
|
||||||
// Get Device Descriptor
|
|
||||||
tuh_descriptor_get_device(daddr, &desc_device, 18, print_device_descriptor, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Invoked when device is unmounted (bus reset/unplugged)
|
|
||||||
void tuh_umount_cb(uint8_t daddr)
|
|
||||||
{
|
|
||||||
Serial.printf("Device removed, address = %d\r\n", daddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void print_device_descriptor(tuh_xfer_t* xfer)
|
|
||||||
{
|
|
||||||
if ( XFER_RESULT_SUCCESS != xfer->result )
|
|
||||||
{
|
|
||||||
Serial.printf("Failed to get device descriptor\r\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t const daddr = xfer->daddr;
|
|
||||||
|
|
||||||
Serial.printf("Device %u: ID %04x:%04x\r\n", daddr, desc_device.idVendor, desc_device.idProduct);
|
|
||||||
Serial.printf("Device Descriptor:\r\n");
|
|
||||||
Serial.printf(" bLength %u\r\n" , desc_device.bLength);
|
|
||||||
Serial.printf(" bDescriptorType %u\r\n" , desc_device.bDescriptorType);
|
|
||||||
Serial.printf(" bcdUSB %04x\r\n" , desc_device.bcdUSB);
|
|
||||||
Serial.printf(" bDeviceClass %u\r\n" , desc_device.bDeviceClass);
|
|
||||||
Serial.printf(" bDeviceSubClass %u\r\n" , desc_device.bDeviceSubClass);
|
|
||||||
Serial.printf(" bDeviceProtocol %u\r\n" , desc_device.bDeviceProtocol);
|
|
||||||
Serial.printf(" bMaxPacketSize0 %u\r\n" , desc_device.bMaxPacketSize0);
|
|
||||||
Serial.printf(" idVendor 0x%04x\r\n" , desc_device.idVendor);
|
|
||||||
Serial.printf(" idProduct 0x%04x\r\n" , desc_device.idProduct);
|
|
||||||
Serial.printf(" bcdDevice %04x\r\n" , desc_device.bcdDevice);
|
|
||||||
|
|
||||||
// Get String descriptor using Sync API
|
|
||||||
uint16_t temp_buf[128];
|
|
||||||
|
|
||||||
Serial.printf(" iManufacturer %u " , desc_device.iManufacturer);
|
|
||||||
if (XFER_RESULT_SUCCESS == tuh_descriptor_get_manufacturer_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf)) )
|
|
||||||
{
|
|
||||||
print_utf16(temp_buf, TU_ARRAY_SIZE(temp_buf));
|
|
||||||
}
|
|
||||||
Serial.printf("\r\n");
|
|
||||||
|
|
||||||
Serial.printf(" iProduct %u " , desc_device.iProduct);
|
|
||||||
if (XFER_RESULT_SUCCESS == tuh_descriptor_get_product_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf)))
|
|
||||||
{
|
|
||||||
print_utf16(temp_buf, TU_ARRAY_SIZE(temp_buf));
|
|
||||||
}
|
|
||||||
Serial.printf("\r\n");
|
|
||||||
|
|
||||||
Serial.printf(" iSerialNumber %u " , desc_device.iSerialNumber);
|
|
||||||
if (XFER_RESULT_SUCCESS == tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf)))
|
|
||||||
{
|
|
||||||
print_utf16(temp_buf, TU_ARRAY_SIZE(temp_buf));
|
|
||||||
}
|
|
||||||
Serial.printf("\r\n");
|
|
||||||
|
|
||||||
Serial.printf(" bNumConfigurations %u\r\n" , desc_device.bNumConfigurations);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
// String Descriptor Helper
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
|
|
||||||
static void _convert_utf16le_to_utf8(const uint16_t *utf16, size_t utf16_len, uint8_t *utf8, size_t utf8_len) {
|
|
||||||
// TODO: Check for runover.
|
|
||||||
(void)utf8_len;
|
|
||||||
// Get the UTF-16 length out of the data itself.
|
|
||||||
|
|
||||||
for (size_t i = 0; i < utf16_len; i++) {
|
|
||||||
uint16_t chr = utf16[i];
|
|
||||||
if (chr < 0x80) {
|
|
||||||
*utf8++ = chr & 0xff;
|
|
||||||
} else if (chr < 0x800) {
|
|
||||||
*utf8++ = (uint8_t)(0xC0 | (chr >> 6 & 0x1F));
|
|
||||||
*utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
|
|
||||||
} else {
|
|
||||||
// TODO: Verify surrogate.
|
|
||||||
*utf8++ = (uint8_t)(0xE0 | (chr >> 12 & 0x0F));
|
|
||||||
*utf8++ = (uint8_t)(0x80 | (chr >> 6 & 0x3F));
|
|
||||||
*utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
|
|
||||||
}
|
|
||||||
// TODO: Handle UTF-16 code points that take two entries.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count how many bytes a utf-16-le encoded string will take in utf-8.
|
|
||||||
static int _count_utf8_bytes(const uint16_t *buf, size_t len) {
|
|
||||||
size_t total_bytes = 0;
|
|
||||||
for (size_t i = 0; i < len; i++) {
|
|
||||||
uint16_t chr = buf[i];
|
|
||||||
if (chr < 0x80) {
|
|
||||||
total_bytes += 1;
|
|
||||||
} else if (chr < 0x800) {
|
|
||||||
total_bytes += 2;
|
|
||||||
} else {
|
|
||||||
total_bytes += 3;
|
|
||||||
}
|
|
||||||
// TODO: Handle UTF-16 code points that take two entries.
|
|
||||||
}
|
|
||||||
return total_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_utf16(uint16_t *temp_buf, size_t buf_len) {
|
|
||||||
size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t);
|
|
||||||
size_t utf8_len = _count_utf8_bytes(temp_buf + 1, utf16_len);
|
|
||||||
|
|
||||||
_convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, sizeof(uint16_t) * buf_len);
|
|
||||||
((uint8_t*) temp_buf)[utf8_len] = '\0';
|
|
||||||
|
|
||||||
Serial.printf((char*)temp_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
2
examples/HID/hid_boot_keyboard/.skip.txt
Normal file
2
examples/HID/hid_boot_keyboard/.skip.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
feather_esp32_v2
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
|
@ -10,93 +10,73 @@
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
|
|
||||||
#include "Adafruit_TinyUSB.h"
|
#include "Adafruit_TinyUSB.h"
|
||||||
#include <Adafruit_NeoPixel.h>
|
|
||||||
|
|
||||||
/* This sketch demonstrates USB HID keyboard.
|
/* This sketch demonstrates USB HID keyboard.
|
||||||
* - PIN A0-A5 is used to send digit '0' to '5' respectively
|
* - PIN A0-A3 is used to send digit '0' to '3' respectively
|
||||||
* (On the RP2040, pins D0-D5 used)
|
* (On the RP2040, pins D0-D5 used)
|
||||||
* - LED and/or Neopixels will be used as Capslock indicator
|
* - LED and/or Neopixels will be used as Capslock indicator
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// HID report descriptor using TinyUSB's template
|
// HID report descriptor using TinyUSB's template
|
||||||
// Single Report (no ID) descriptor
|
// Single Report (no ID) descriptor
|
||||||
uint8_t const desc_hid_report[] =
|
uint8_t const desc_hid_report[] = {
|
||||||
{
|
|
||||||
TUD_HID_REPORT_DESC_KEYBOARD()
|
TUD_HID_REPORT_DESC_KEYBOARD()
|
||||||
};
|
};
|
||||||
|
|
||||||
// USB HID object. For ESP32 these values cannot be changed after this declaration
|
// USB HID object. For ESP32 these values cannot be changed after this declaration
|
||||||
// desc report, desc len, protocol, interval, use out endpoint
|
// desc report, desc len, protocol, interval, use out endpoint
|
||||||
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_KEYBOARD, 2, false);
|
Adafruit_USBD_HID usb_hid;
|
||||||
|
|
||||||
//------------- Input Pins -------------//
|
//------------- Input Pins -------------//
|
||||||
// Array of pins and its keycode.
|
// Array of pins and its keycode.
|
||||||
// Notes: these pins can be replaced by PIN_BUTTONn if defined in setup()
|
// Notes: these pins can be replaced by PIN_BUTTONn if defined in setup()
|
||||||
#ifdef ARDUINO_ARCH_RP2040
|
#ifdef ARDUINO_ARCH_RP2040
|
||||||
uint8_t pins[] = { D0, D1, D2, D3 };
|
uint8_t pins[] = { D0, D1, D2, D3 };
|
||||||
#else
|
#else
|
||||||
uint8_t pins[] = { A0, A1, A2, A3 };
|
uint8_t pins[] = {A0, A1, A2, A3};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// number of pins
|
// number of pins
|
||||||
uint8_t pincount = sizeof(pins)/sizeof(pins[0]);
|
uint8_t pincount = sizeof(pins) / sizeof(pins[0]);
|
||||||
|
|
||||||
// For keycode definition check out https://github.com/hathach/tinyusb/blob/master/src/class/hid/hid.h
|
// For keycode definition check out https://github.com/hathach/tinyusb/blob/master/src/class/hid/hid.h
|
||||||
uint8_t hidcode[] = { HID_KEY_ARROW_RIGHT, HID_KEY_ARROW_LEFT, HID_KEY_ARROW_DOWN, HID_KEY_ARROW_UP };
|
uint8_t hidcode[] = {HID_KEY_0, HID_KEY_1, HID_KEY_2, HID_KEY_3};
|
||||||
|
|
||||||
#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY) || defined(ARDUINO_FUNHOUSE_ESP32S2)
|
#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY) || defined(ARDUINO_FUNHOUSE_ESP32S2)
|
||||||
bool activeState = true;
|
bool activeState = true;
|
||||||
#else
|
#else
|
||||||
bool activeState = false;
|
bool activeState = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//------------- Neopixel -------------//
|
|
||||||
// #define PIN_NEOPIXEL 8
|
|
||||||
#ifdef PIN_NEOPIXEL
|
|
||||||
|
|
||||||
// How many NeoPixels are attached to the Arduino?
|
|
||||||
// use on-board defined NEOPIXEL_NUM if existed
|
|
||||||
#ifndef NEOPIXEL_NUM
|
|
||||||
#define NEOPIXEL_NUM 10
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NEOPIXEL_NUM, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// the setup function runs once when you press reset or power the board
|
// the setup function runs once when you press reset or power the board
|
||||||
void setup()
|
void setup() {
|
||||||
{
|
// Manual begin() is required on core without built-in support e.g. mbed rp2040
|
||||||
#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
|
if (!TinyUSBDevice.isInitialized()) {
|
||||||
// Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
|
TinyUSBDevice.begin(0);
|
||||||
TinyUSB_Device_Init(0);
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// Notes: following commented-out functions has no affect on ESP32
|
// Setup HID
|
||||||
// usb_hid.setBootProtocol(HID_ITF_PROTOCOL_KEYBOARD);
|
usb_hid.setBootProtocol(HID_ITF_PROTOCOL_KEYBOARD);
|
||||||
// usb_hid.setPollInterval(2);
|
usb_hid.setPollInterval(2);
|
||||||
// usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
||||||
// usb_hid.setStringDescriptor("TinyUSB Keyboard");
|
usb_hid.setStringDescriptor("TinyUSB Keyboard");
|
||||||
|
|
||||||
// Set up output report (on control endpoint) for Capslock indicator
|
// Set up output report (on control endpoint) for Capslock indicator
|
||||||
usb_hid.setReportCallback(NULL, hid_report_callback);
|
usb_hid.setReportCallback(NULL, hid_report_callback);
|
||||||
|
|
||||||
usb_hid.begin();
|
usb_hid.begin();
|
||||||
|
|
||||||
|
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
|
||||||
|
if (TinyUSBDevice.mounted()) {
|
||||||
|
TinyUSBDevice.detach();
|
||||||
|
delay(10);
|
||||||
|
TinyUSBDevice.attach();
|
||||||
|
}
|
||||||
|
|
||||||
// led pin
|
// led pin
|
||||||
|
#ifdef LED_BUILTIN
|
||||||
pinMode(LED_BUILTIN, OUTPUT);
|
pinMode(LED_BUILTIN, OUTPUT);
|
||||||
digitalWrite(LED_BUILTIN, LOW);
|
digitalWrite(LED_BUILTIN, LOW);
|
||||||
|
|
||||||
// neopixel if existed
|
|
||||||
#ifdef PIN_NEOPIXEL
|
|
||||||
pixels.begin();
|
|
||||||
pixels.setBrightness(50);
|
|
||||||
|
|
||||||
#ifdef NEOPIXEL_POWER
|
|
||||||
pinMode(NEOPIXEL_POWER, OUTPUT);
|
|
||||||
digitalWrite(NEOPIXEL_POWER, NEOPIXEL_POWER_ON);
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// overwrite input pin with PIN_BUTTONx
|
// overwrite input pin with PIN_BUTTONx
|
||||||
|
|
@ -117,32 +97,21 @@ void setup()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Set up pin as input
|
// Set up pin as input
|
||||||
for (uint8_t i=0; i<pincount; i++)
|
for (uint8_t i = 0; i < pincount; i++) {
|
||||||
{
|
|
||||||
pinMode(pins[i], activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
|
pinMode(pins[i], activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait until device mounted
|
|
||||||
while( !TinyUSBDevice.mounted() ) delay(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void process_hid() {
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
// poll gpio once each 2 ms
|
|
||||||
delay(2);
|
|
||||||
|
|
||||||
// used to avoid send multiple consecutive zero report for keyboard
|
// used to avoid send multiple consecutive zero report for keyboard
|
||||||
static bool keyPressedPreviously = false;
|
static bool keyPressedPreviously = false;
|
||||||
|
|
||||||
uint8_t count=0;
|
uint8_t count = 0;
|
||||||
uint8_t keycode[6] = { 0 };
|
uint8_t keycode[6] = {0};
|
||||||
|
|
||||||
// scan normal key and send report
|
// scan normal key and send report
|
||||||
for(uint8_t i=0; i < pincount; i++)
|
for (uint8_t i = 0; i < pincount; i++) {
|
||||||
{
|
if (activeState == digitalRead(pins[i])) {
|
||||||
if ( activeState == digitalRead(pins[i]) )
|
|
||||||
{
|
|
||||||
// if pin is active (low), add its hid code to key report
|
// if pin is active (low), add its hid code to key report
|
||||||
keycode[count++] = hidcode[i];
|
keycode[count++] = hidcode[i];
|
||||||
|
|
||||||
|
|
@ -151,55 +120,66 @@ void loop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( TinyUSBDevice.suspended() && count )
|
if (TinyUSBDevice.suspended() && count) {
|
||||||
{
|
|
||||||
// Wake up host if we are in suspend mode
|
// Wake up host if we are in suspend mode
|
||||||
// and REMOTE_WAKEUP feature is enabled by host
|
// and REMOTE_WAKEUP feature is enabled by host
|
||||||
TinyUSBDevice.remoteWakeup();
|
TinyUSBDevice.remoteWakeup();
|
||||||
}
|
}
|
||||||
|
|
||||||
// skip if hid is not ready e.g still transferring previous report
|
// skip if hid is not ready e.g still transferring previous report
|
||||||
if ( !usb_hid.ready() ) return;
|
if (!usb_hid.ready()) return;
|
||||||
|
|
||||||
if ( count )
|
if (count) {
|
||||||
{
|
|
||||||
// Send report if there is key pressed
|
// Send report if there is key pressed
|
||||||
uint8_t const report_id = 0;
|
uint8_t const report_id = 0;
|
||||||
uint8_t const modifier = 0;
|
uint8_t const modifier = 0;
|
||||||
|
|
||||||
keyPressedPreviously = true;
|
keyPressedPreviously = true;
|
||||||
usb_hid.keyboardReport(report_id, modifier, keycode);
|
usb_hid.keyboardReport(report_id, modifier, keycode);
|
||||||
}else
|
} else {
|
||||||
{
|
|
||||||
// Send All-zero report to indicate there is no keys pressed
|
// Send All-zero report to indicate there is no keys pressed
|
||||||
// Most of the time, it is, though we don't need to send zero report
|
// Most of the time, it is, though we don't need to send zero report
|
||||||
// every loop(), only a key is pressed in previous loop()
|
// every loop(), only a key is pressed in previous loop()
|
||||||
if ( keyPressedPreviously )
|
if (keyPressedPreviously) {
|
||||||
{
|
|
||||||
keyPressedPreviously = false;
|
keyPressedPreviously = false;
|
||||||
usb_hid.keyboardRelease(0);
|
usb_hid.keyboardRelease(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
#ifdef TINYUSB_NEED_POLLING_TASK
|
||||||
|
// Manual call tud_task since it isn't called by Core's background
|
||||||
|
TinyUSBDevice.task();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// not enumerated()/mounted() yet: nothing to do
|
||||||
|
if (!TinyUSBDevice.mounted()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// poll gpio once each 2 ms
|
||||||
|
static uint32_t ms = 0;
|
||||||
|
if (millis() - ms > 2) {
|
||||||
|
ms = millis();
|
||||||
|
process_hid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Output report callback for LED indicator such as Caplocks
|
// Output report callback for LED indicator such as Caplocks
|
||||||
void hid_report_callback(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
|
void hid_report_callback(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) {
|
||||||
{
|
|
||||||
(void) report_id;
|
(void) report_id;
|
||||||
(void) bufsize;
|
(void) bufsize;
|
||||||
|
|
||||||
// LED indicator is output report with only 1 byte length
|
// LED indicator is output report with only 1 byte length
|
||||||
if ( report_type != HID_REPORT_TYPE_OUTPUT ) return;
|
if (report_type != HID_REPORT_TYPE_OUTPUT) return;
|
||||||
|
|
||||||
// The LED bit map is as follows: (also defined by KEYBOARD_LED_* )
|
// The LED bit map is as follows: (also defined by KEYBOARD_LED_* )
|
||||||
// Kana (4) | Compose (3) | ScrollLock (2) | CapsLock (1) | Numlock (0)
|
// Kana (4) | Compose (3) | ScrollLock (2) | CapsLock (1) | Numlock (0)
|
||||||
uint8_t ledIndicator = buffer[0];
|
uint8_t ledIndicator = buffer[0];
|
||||||
|
|
||||||
|
#ifdef LED_BUILTIN
|
||||||
// turn on LED if capslock is set
|
// turn on LED if capslock is set
|
||||||
digitalWrite(LED_BUILTIN, ledIndicator & KEYBOARD_LED_CAPSLOCK);
|
digitalWrite(LED_BUILTIN, ledIndicator & KEYBOARD_LED_CAPSLOCK);
|
||||||
|
|
||||||
#ifdef PIN_NEOPIXEL
|
|
||||||
pixels.fill(ledIndicator & KEYBOARD_LED_CAPSLOCK ? 0xff0000 : 0x000000);
|
|
||||||
pixels.show();
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
examples/HID/hid_boot_mouse/.skip.txt
Normal file
2
examples/HID/hid_boot_mouse/.skip.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
feather_esp32_v2
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
|
@ -19,66 +19,69 @@
|
||||||
* and its active state (when pressed) are different
|
* and its active state (when pressed) are different
|
||||||
*/
|
*/
|
||||||
#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY)
|
#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY)
|
||||||
const int pin = 4; // Left Button
|
const int pin = 4; // Left Button
|
||||||
bool activeState = true;
|
bool activeState = true;
|
||||||
|
|
||||||
#elif defined(ARDUINO_FUNHOUSE_ESP32S2)
|
#elif defined(ARDUINO_FUNHOUSE_ESP32S2)
|
||||||
const int pin = BUTTON_DOWN;
|
const int pin = BUTTON_DOWN;
|
||||||
bool activeState = true;
|
bool activeState = true;
|
||||||
|
|
||||||
#elif defined PIN_BUTTON1
|
#elif defined PIN_BUTTON1
|
||||||
const int pin = PIN_BUTTON1;
|
const int pin = PIN_BUTTON1;
|
||||||
bool activeState = false;
|
bool activeState = false;
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_ESP32)
|
||||||
|
const int pin = 0;
|
||||||
|
bool activeState = false;
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_RP2040)
|
||||||
|
const int pin = D0;
|
||||||
|
bool activeState = false;
|
||||||
#else
|
#else
|
||||||
const int pin = 12;
|
const int pin = A0;
|
||||||
bool activeState = false;
|
bool activeState = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// HID report descriptor using TinyUSB's template
|
// HID report descriptor using TinyUSB's template
|
||||||
// Single Report (no ID) descriptor
|
// Single Report (no ID) descriptor
|
||||||
uint8_t const desc_hid_report[] =
|
uint8_t const desc_hid_report[] = {
|
||||||
{
|
|
||||||
TUD_HID_REPORT_DESC_MOUSE()
|
TUD_HID_REPORT_DESC_MOUSE()
|
||||||
};
|
};
|
||||||
|
|
||||||
// USB HID object. For ESP32 these values cannot be changed after this declaration
|
// USB HID object
|
||||||
// desc report, desc len, protocol, interval, use out endpoint
|
Adafruit_USBD_HID usb_hid;
|
||||||
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_MOUSE, 2, false);
|
|
||||||
|
|
||||||
// the setup function runs once when you press reset or power the board
|
// the setup function runs once when you press reset or power the board
|
||||||
void setup()
|
void setup() {
|
||||||
{
|
// Manual begin() is required on core without built-in support e.g. mbed rp2040
|
||||||
#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
|
if (!TinyUSBDevice.isInitialized()) {
|
||||||
// Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
|
TinyUSBDevice.begin(0);
|
||||||
TinyUSB_Device_Init(0);
|
}
|
||||||
#endif
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
// Set up button, pullup opposite to active state
|
// Set up button, pullup opposite to active state
|
||||||
pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
|
pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
|
||||||
|
|
||||||
// Notes: following commented-out functions has no affect on ESP32
|
// Set up HID
|
||||||
// usb_hid.setBootProtocol(HID_ITF_PROTOCOL_MOUSE);
|
usb_hid.setBootProtocol(HID_ITF_PROTOCOL_MOUSE);
|
||||||
// usb_hid.setPollInterval(2);
|
usb_hid.setPollInterval(2);
|
||||||
// usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
||||||
// usb_hid.setStringDescriptor("TinyUSB Mouse");
|
usb_hid.setStringDescriptor("TinyUSB Mouse");
|
||||||
|
|
||||||
usb_hid.begin();
|
usb_hid.begin();
|
||||||
|
|
||||||
Serial.begin(115200);
|
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
|
||||||
|
if (TinyUSBDevice.mounted()) {
|
||||||
// wait until device mounted
|
TinyUSBDevice.detach();
|
||||||
while( !TinyUSBDevice.mounted() ) delay(1);
|
delay(10);
|
||||||
|
TinyUSBDevice.attach();
|
||||||
|
}
|
||||||
|
|
||||||
Serial.println("Adafruit TinyUSB HID Mouse example");
|
Serial.println("Adafruit TinyUSB HID Mouse example");
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void process_hid() {
|
||||||
{
|
|
||||||
// poll gpio once each 10 ms
|
|
||||||
delay(10);
|
|
||||||
|
|
||||||
// Whether button is pressed
|
// Whether button is pressed
|
||||||
bool btn_pressed = (digitalRead(pin) == activeState);
|
bool btn_pressed = (digitalRead(pin) == activeState);
|
||||||
|
|
||||||
|
|
@ -86,17 +89,34 @@ void loop()
|
||||||
if (!btn_pressed) return;
|
if (!btn_pressed) return;
|
||||||
|
|
||||||
// Remote wakeup
|
// Remote wakeup
|
||||||
if ( TinyUSBDevice.suspended() )
|
if (TinyUSBDevice.suspended()) {
|
||||||
{
|
|
||||||
// Wake up host if we are in suspend mode
|
// Wake up host if we are in suspend mode
|
||||||
// and REMOTE_WAKEUP feature is enabled by host
|
// and REMOTE_WAKEUP feature is enabled by host
|
||||||
TinyUSBDevice.remoteWakeup();
|
TinyUSBDevice.remoteWakeup();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( usb_hid.ready() )
|
if (usb_hid.ready()) {
|
||||||
{
|
|
||||||
uint8_t const report_id = 0; // no ID
|
uint8_t const report_id = 0; // no ID
|
||||||
int8_t const delta = 5;
|
int8_t const delta = 5;
|
||||||
usb_hid.mouseMove(report_id, delta, delta); // right + down
|
usb_hid.mouseMove(report_id, delta, delta); // right + down
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
#ifdef TINYUSB_NEED_POLLING_TASK
|
||||||
|
// Manual call tud_task since it isn't called by Core's background
|
||||||
|
TinyUSBDevice.task();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// not enumerated()/mounted() yet: nothing to do
|
||||||
|
if (!TinyUSBDevice.mounted()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// poll gpio once each 10 ms
|
||||||
|
static uint32_t ms = 0;
|
||||||
|
if (millis() - ms > 10) {
|
||||||
|
ms = millis();
|
||||||
|
process_hid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
2
examples/HID/hid_composite/.skip.txt
Normal file
2
examples/HID/hid_composite/.skip.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
feather_esp32_v2
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
|
@ -20,83 +20,90 @@
|
||||||
* and its active state (when pressed) are different
|
* and its active state (when pressed) are different
|
||||||
*/
|
*/
|
||||||
#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY)
|
#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY)
|
||||||
const int pin = 4; // Left Button
|
const int pin = 4; // Left Button
|
||||||
bool activeState = true;
|
bool activeState = true;
|
||||||
|
|
||||||
#elif defined(ARDUINO_FUNHOUSE_ESP32S2)
|
#elif defined(ARDUINO_FUNHOUSE_ESP32S2)
|
||||||
const int pin = BUTTON_DOWN;
|
const int pin = BUTTON_DOWN;
|
||||||
bool activeState = true;
|
bool activeState = true;
|
||||||
|
|
||||||
#elif defined PIN_BUTTON1
|
#elif defined PIN_BUTTON1
|
||||||
const int pin = PIN_BUTTON1;
|
const int pin = PIN_BUTTON1;
|
||||||
bool activeState = false;
|
bool activeState = false;
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_ESP32)
|
||||||
|
const int pin = 0;
|
||||||
|
bool activeState = false;
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_RP2040)
|
||||||
|
const int pin = D0;
|
||||||
|
bool activeState = false;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
const int pin = 12;
|
const int pin = A0;
|
||||||
bool activeState = false;
|
bool activeState = false;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// Report ID
|
// Report ID
|
||||||
enum
|
enum {
|
||||||
{
|
|
||||||
RID_KEYBOARD = 1,
|
RID_KEYBOARD = 1,
|
||||||
RID_MOUSE,
|
RID_MOUSE,
|
||||||
RID_CONSUMER_CONTROL, // Media, volume etc ..
|
RID_CONSUMER_CONTROL, // Media, volume etc ..
|
||||||
};
|
};
|
||||||
|
|
||||||
// HID report descriptor using TinyUSB's template
|
// HID report descriptor using TinyUSB's template
|
||||||
uint8_t const desc_hid_report[] =
|
uint8_t const desc_hid_report[] = {
|
||||||
{
|
TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(RID_KEYBOARD)),
|
||||||
TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(RID_KEYBOARD) ),
|
TUD_HID_REPORT_DESC_MOUSE (HID_REPORT_ID(RID_MOUSE)),
|
||||||
TUD_HID_REPORT_DESC_MOUSE ( HID_REPORT_ID(RID_MOUSE) ),
|
TUD_HID_REPORT_DESC_CONSUMER(HID_REPORT_ID(RID_CONSUMER_CONTROL))
|
||||||
TUD_HID_REPORT_DESC_CONSUMER( HID_REPORT_ID(RID_CONSUMER_CONTROL) )
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// USB HID object. For ESP32 these values cannot be changed after this declaration
|
// USB HID object.
|
||||||
// desc report, desc len, protocol, interval, use out endpoint
|
Adafruit_USBD_HID usb_hid;
|
||||||
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_NONE, 2, false);
|
|
||||||
|
|
||||||
// the setup function runs once when you press reset or power the board
|
// the setup function runs once when you press reset or power the board
|
||||||
void setup()
|
void setup() {
|
||||||
{
|
// Manual begin() is required on core without built-in support e.g. mbed rp2040
|
||||||
// Notes: following commented-out functions has no affect on ESP32
|
if (!TinyUSBDevice.isInitialized()) {
|
||||||
// usb_hid.setPollInterval(2);
|
TinyUSBDevice.begin(0);
|
||||||
// usb_hid.setReportDescriptor();
|
}
|
||||||
// usb_hid.setStringDescriptor("TinyUSB HID Composite");
|
|
||||||
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
// Set up HID
|
||||||
|
usb_hid.setPollInterval(2);
|
||||||
|
usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
||||||
|
usb_hid.setStringDescriptor("TinyUSB HID Composite");
|
||||||
usb_hid.begin();
|
usb_hid.begin();
|
||||||
|
|
||||||
|
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
|
||||||
|
if (TinyUSBDevice.mounted()) {
|
||||||
|
TinyUSBDevice.detach();
|
||||||
|
delay(10);
|
||||||
|
TinyUSBDevice.attach();
|
||||||
|
}
|
||||||
|
|
||||||
// Set up button, pullup opposite to active state
|
// Set up button, pullup opposite to active state
|
||||||
pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
|
pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
|
||||||
|
|
||||||
Serial.begin(115200);
|
|
||||||
|
|
||||||
// wait until device mounted
|
|
||||||
while( !TinyUSBDevice.mounted() ) delay(1);
|
|
||||||
|
|
||||||
Serial.println("Adafruit TinyUSB HID Composite example");
|
Serial.println("Adafruit TinyUSB HID Composite example");
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void process_hid() {
|
||||||
{
|
|
||||||
// poll gpio once each 10 ms
|
|
||||||
delay(10);
|
|
||||||
|
|
||||||
// Whether button is pressed
|
// Whether button is pressed
|
||||||
bool btn_pressed = (digitalRead(pin) == activeState);
|
bool btn_pressed = (digitalRead(pin) == activeState);
|
||||||
|
|
||||||
// Remote wakeup
|
// Remote wakeup
|
||||||
if ( TinyUSBDevice.suspended() && btn_pressed )
|
if (TinyUSBDevice.suspended() && btn_pressed) {
|
||||||
{
|
|
||||||
// Wake up host if we are in suspend mode
|
// Wake up host if we are in suspend mode
|
||||||
// and REMOTE_WAKEUP feature is enabled by host
|
// and REMOTE_WAKEUP feature is enabled by host
|
||||||
TinyUSBDevice.remoteWakeup();
|
TinyUSBDevice.remoteWakeup();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------- Mouse -------------*/
|
/*------------- Mouse -------------*/
|
||||||
if ( usb_hid.ready() && btn_pressed )
|
if (usb_hid.ready() && btn_pressed) {
|
||||||
{
|
|
||||||
int8_t const delta = 5;
|
int8_t const delta = 5;
|
||||||
usb_hid.mouseMove(RID_MOUSE, delta, delta); // right + down
|
usb_hid.mouseMove(RID_MOUSE, delta, delta); // right + down
|
||||||
|
|
||||||
|
|
@ -105,21 +112,18 @@ void loop()
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------- Keyboard -------------*/
|
/*------------- Keyboard -------------*/
|
||||||
if ( usb_hid.ready() )
|
if (usb_hid.ready()) {
|
||||||
{
|
|
||||||
// use to send key release report
|
// use to send key release report
|
||||||
static bool has_key = false;
|
static bool has_key = false;
|
||||||
|
|
||||||
if ( btn_pressed )
|
if (btn_pressed) {
|
||||||
{
|
uint8_t keycode[6] = {0};
|
||||||
uint8_t keycode[6] = { 0 };
|
|
||||||
keycode[0] = HID_KEY_A;
|
keycode[0] = HID_KEY_A;
|
||||||
|
|
||||||
usb_hid.keyboardReport(RID_KEYBOARD, 0, keycode);
|
usb_hid.keyboardReport(RID_KEYBOARD, 0, keycode);
|
||||||
|
|
||||||
has_key = true;
|
has_key = true;
|
||||||
}else
|
} else {
|
||||||
{
|
|
||||||
// send empty key report if previously has key pressed
|
// send empty key report if previously has key pressed
|
||||||
if (has_key) usb_hid.keyboardRelease(RID_KEYBOARD);
|
if (has_key) usb_hid.keyboardRelease(RID_KEYBOARD);
|
||||||
has_key = false;
|
has_key = false;
|
||||||
|
|
@ -130,8 +134,7 @@ void loop()
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------- Consumer Control -------------*/
|
/*------------- Consumer Control -------------*/
|
||||||
if ( usb_hid.ready() )
|
if (usb_hid.ready()) {
|
||||||
{
|
|
||||||
// Consumer Control is used to control Media playback, Volume, Brightness etc ...
|
// Consumer Control is used to control Media playback, Volume, Brightness etc ...
|
||||||
// Consumer report is 2-byte containing the control code of the key
|
// Consumer report is 2-byte containing the control code of the key
|
||||||
// For list of control check out https://github.com/hathach/tinyusb/blob/master/src/class/hid/hid.h
|
// For list of control check out https://github.com/hathach/tinyusb/blob/master/src/class/hid/hid.h
|
||||||
|
|
@ -139,16 +142,33 @@ void loop()
|
||||||
// use to send consumer release report
|
// use to send consumer release report
|
||||||
static bool has_consumer_key = false;
|
static bool has_consumer_key = false;
|
||||||
|
|
||||||
if ( btn_pressed )
|
if (btn_pressed) {
|
||||||
{
|
|
||||||
// send volume down (0x00EA)
|
// send volume down (0x00EA)
|
||||||
usb_hid.sendReport16(RID_CONSUMER_CONTROL, HID_USAGE_CONSUMER_VOLUME_DECREMENT);
|
usb_hid.sendReport16(RID_CONSUMER_CONTROL, HID_USAGE_CONSUMER_VOLUME_DECREMENT);
|
||||||
has_consumer_key = true;
|
has_consumer_key = true;
|
||||||
}else
|
} else {
|
||||||
{
|
|
||||||
// release the consume key by sending zero (0x0000)
|
// release the consume key by sending zero (0x0000)
|
||||||
if (has_consumer_key) usb_hid.sendReport16(RID_CONSUMER_CONTROL, 0);
|
if (has_consumer_key) usb_hid.sendReport16(RID_CONSUMER_CONTROL, 0);
|
||||||
has_consumer_key = false;
|
has_consumer_key = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
#ifdef TINYUSB_NEED_POLLING_TASK
|
||||||
|
// Manual call tud_task since it isn't called by Core's background
|
||||||
|
TinyUSBDevice.task();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// not enumerated()/mounted() yet: nothing to do
|
||||||
|
if (!TinyUSBDevice.mounted()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// poll gpio once each 10 ms
|
||||||
|
static uint32_t ms = 0;
|
||||||
|
if (millis() - ms > 10) {
|
||||||
|
ms = millis();
|
||||||
|
process_hid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
3
examples/HID/hid_composite_joy_featherwing/.skip.txt
Normal file
3
examples/HID/hid_composite_joy_featherwing/.skip.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
feather_esp32_v2
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
CH32V20x_EVT
|
||||||
|
|
@ -33,17 +33,15 @@ uint32_t button_mask = (1 << BUTTON_A) | (1 << BUTTON_B) |
|
||||||
Adafruit_seesaw ss;
|
Adafruit_seesaw ss;
|
||||||
|
|
||||||
// Report ID
|
// Report ID
|
||||||
enum
|
enum {
|
||||||
{
|
|
||||||
RID_KEYBOARD = 1,
|
RID_KEYBOARD = 1,
|
||||||
RID_MOUSE
|
RID_MOUSE
|
||||||
};
|
};
|
||||||
|
|
||||||
// HID report descriptor using TinyUSB's template
|
// HID report descriptor using TinyUSB's template
|
||||||
uint8_t const desc_hid_report[] =
|
uint8_t const desc_hid_report[] = {
|
||||||
{
|
TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(RID_KEYBOARD)),
|
||||||
TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(RID_KEYBOARD) ),
|
TUD_HID_REPORT_DESC_MOUSE (HID_REPORT_ID(RID_MOUSE))
|
||||||
TUD_HID_REPORT_DESC_MOUSE ( HID_REPORT_ID(RID_MOUSE) )
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// USB HID object. For ESP32 these values cannot be changed after this declaration
|
// USB HID object. For ESP32 these values cannot be changed after this declaration
|
||||||
|
|
@ -53,20 +51,30 @@ Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROT
|
||||||
int last_x, last_y;
|
int last_x, last_y;
|
||||||
|
|
||||||
// the setup function runs once when you press reset or power the board
|
// the setup function runs once when you press reset or power the board
|
||||||
void setup()
|
void setup() {
|
||||||
{
|
// Manual begin() is required on core without built-in support e.g. mbed rp2040
|
||||||
|
if (!TinyUSBDevice.isInitialized()) {
|
||||||
|
TinyUSBDevice.begin(0);
|
||||||
|
}
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
// Notes: following commented-out functions has no affect on ESP32
|
// Notes: following commented-out functions has no affect on ESP32
|
||||||
// usb_hid.setPollInterval(2);
|
// usb_hid.setPollInterval(2);
|
||||||
// usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
// usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
||||||
|
|
||||||
usb_hid.begin();
|
usb_hid.begin();
|
||||||
|
|
||||||
Serial.begin(115200);
|
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
|
||||||
|
if (TinyUSBDevice.mounted()) {
|
||||||
|
TinyUSBDevice.detach();
|
||||||
|
delay(10);
|
||||||
|
TinyUSBDevice.attach();
|
||||||
|
}
|
||||||
|
|
||||||
Serial.println("Adafruit TinyUSB HID Mouse with Joy FeatherWing example");
|
Serial.println("Adafruit TinyUSB HID Mouse with Joy FeatherWing example");
|
||||||
|
|
||||||
if(!ss.begin(0x49)){
|
if (!ss.begin(0x49)) {
|
||||||
Serial.println("ERROR! seesaw not found");
|
Serial.println("ERROR! seesaw not found");
|
||||||
while(1);
|
while (1) {}
|
||||||
} else {
|
} else {
|
||||||
Serial.println("seesaw started");
|
Serial.println("seesaw started");
|
||||||
Serial.print("version: ");
|
Serial.print("version: ");
|
||||||
|
|
@ -77,16 +85,9 @@ void setup()
|
||||||
|
|
||||||
last_y = ss.analogRead(2);
|
last_y = ss.analogRead(2);
|
||||||
last_x = ss.analogRead(3);
|
last_x = ss.analogRead(3);
|
||||||
|
|
||||||
// wait until device mounted
|
|
||||||
while( !TinyUSBDevice.mounted() ) delay(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void process_hid() {
|
||||||
{
|
|
||||||
// poll gpio once each 10 ms
|
|
||||||
delay(10);
|
|
||||||
|
|
||||||
// If either analog stick or any buttons is pressed
|
// If either analog stick or any buttons is pressed
|
||||||
bool has_action = false;
|
bool has_action = false;
|
||||||
|
|
||||||
|
|
@ -98,12 +99,10 @@ void loop()
|
||||||
int dx = (x - last_x) / 2;
|
int dx = (x - last_x) / 2;
|
||||||
int dy = (y - last_y) / 2;
|
int dy = (y - last_y) / 2;
|
||||||
|
|
||||||
if ( (abs(dx) > 3) || (abs(dy) > 3) )
|
if ((abs(dx) > 3) || (abs(dy) > 3)) {
|
||||||
{
|
|
||||||
has_action = true;
|
has_action = true;
|
||||||
|
|
||||||
if ( usb_hid.ready() )
|
if (usb_hid.ready()) {
|
||||||
{
|
|
||||||
usb_hid.mouseMove(RID_MOUSE, dx, dy); // no ID: right + down
|
usb_hid.mouseMove(RID_MOUSE, dx, dy); // no ID: right + down
|
||||||
|
|
||||||
last_x = x;
|
last_x = x;
|
||||||
|
|
@ -114,31 +113,27 @@ void loop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*------------- Keyboard -------------*/
|
/*------------- Keyboard -------------*/
|
||||||
// button is active low, invert read value for convenience
|
// button is active low, invert read value for convenience
|
||||||
uint32_t buttons = ~ss.digitalReadBulk(button_mask);
|
uint32_t buttons = ~ss.digitalReadBulk(button_mask);
|
||||||
|
|
||||||
if ( usb_hid.ready() )
|
if (usb_hid.ready()) {
|
||||||
{
|
|
||||||
// use to prevent sending multiple consecutive zero report
|
// use to prevent sending multiple consecutive zero report
|
||||||
static bool has_key = false;
|
static bool has_key = false;
|
||||||
|
|
||||||
if ( buttons & button_mask )
|
if (buttons & button_mask) {
|
||||||
{
|
|
||||||
has_action = true;
|
has_action = true;
|
||||||
has_key = true;
|
has_key = true;
|
||||||
|
|
||||||
uint8_t keycode[6] = { 0 };
|
uint8_t keycode[6] = {0};
|
||||||
|
|
||||||
if ( buttons & (1 << BUTTON_A) ) keycode[0] = HID_KEY_A;
|
if (buttons & (1 << BUTTON_A)) keycode[0] = HID_KEY_A;
|
||||||
if ( buttons & (1 << BUTTON_B) ) keycode[0] = HID_KEY_B;
|
if (buttons & (1 << BUTTON_B)) keycode[0] = HID_KEY_B;
|
||||||
if ( buttons & (1 << BUTTON_X) ) keycode[0] = HID_KEY_X;
|
if (buttons & (1 << BUTTON_X)) keycode[0] = HID_KEY_X;
|
||||||
if ( buttons & (1 << BUTTON_Y) ) keycode[0] = HID_KEY_Y;
|
if (buttons & (1 << BUTTON_Y)) keycode[0] = HID_KEY_Y;
|
||||||
|
|
||||||
usb_hid.keyboardReport(RID_KEYBOARD, 0, keycode);
|
usb_hid.keyboardReport(RID_KEYBOARD, 0, keycode);
|
||||||
}else
|
} else {
|
||||||
{
|
|
||||||
// send empty key report if previously has key pressed
|
// send empty key report if previously has key pressed
|
||||||
if (has_key) usb_hid.keyboardRelease(RID_KEYBOARD);
|
if (has_key) usb_hid.keyboardRelease(RID_KEYBOARD);
|
||||||
has_key = false;
|
has_key = false;
|
||||||
|
|
@ -147,10 +142,28 @@ void loop()
|
||||||
|
|
||||||
/*------------- Remote Wakeup -------------*/
|
/*------------- Remote Wakeup -------------*/
|
||||||
// Remote wakeup if PC is suspended and we has user interaction with joy feather wing
|
// Remote wakeup if PC is suspended and we has user interaction with joy feather wing
|
||||||
if ( has_action && TinyUSBDevice.suspended() )
|
if (has_action && TinyUSBDevice.suspended()) {
|
||||||
{
|
|
||||||
// Wake up only works if REMOTE_WAKEUP feature is enable by host
|
// Wake up only works if REMOTE_WAKEUP feature is enable by host
|
||||||
// Usually this is the case with Mouse/Keyboard device
|
// Usually this is the case with Mouse/Keyboard device
|
||||||
TinyUSBDevice.remoteWakeup();
|
TinyUSBDevice.remoteWakeup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
#ifdef TINYUSB_NEED_POLLING_TASK
|
||||||
|
// Manual call tud_task since it isn't called by Core's background
|
||||||
|
TinyUSBDevice.task();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// not enumerated()/mounted() yet: nothing to do
|
||||||
|
if (!TinyUSBDevice.mounted()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// poll gpio once each 10 ms
|
||||||
|
static uint32_t ms = 0;
|
||||||
|
if (millis() - ms > 10) {
|
||||||
|
ms = millis();
|
||||||
|
process_hid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
2
examples/HID/hid_dual_interfaces/.skip.txt
Normal file
2
examples/HID/hid_dual_interfaces/.skip.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
feather_esp32_v2
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
153
examples/HID/hid_dual_interfaces/hid_dual_interfaces.ino
Normal file
153
examples/HID/hid_dual_interfaces/hid_dual_interfaces.ino
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
/*********************************************************************
|
||||||
|
Adafruit invests time and resources providing this open source code,
|
||||||
|
please support Adafruit and open-source hardware by purchasing
|
||||||
|
products from Adafruit!
|
||||||
|
|
||||||
|
MIT license, check LICENSE for more information
|
||||||
|
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||||
|
All text above, and the splash screen below must be included in
|
||||||
|
any redistribution
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#include "Adafruit_TinyUSB.h"
|
||||||
|
|
||||||
|
/* This sketch demonstrates multiple USB HID interfaces. Pressing the button will
|
||||||
|
* - mouse toward bottom right of monitor
|
||||||
|
* - send 'a' key
|
||||||
|
*
|
||||||
|
* Depending on the board, the button pin
|
||||||
|
* and its active state (when pressed) are different
|
||||||
|
*/
|
||||||
|
#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY)
|
||||||
|
const int pin = 4; // Left Button
|
||||||
|
bool activeState = true;
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_FUNHOUSE_ESP32S2)
|
||||||
|
const int pin = BUTTON_DOWN;
|
||||||
|
bool activeState = true;
|
||||||
|
|
||||||
|
#elif defined PIN_BUTTON1
|
||||||
|
const int pin = PIN_BUTTON1;
|
||||||
|
bool activeState = false;
|
||||||
|
|
||||||
|
#elif defined PIN_BUTTON
|
||||||
|
const int pin = PIN_BUTTON;
|
||||||
|
bool activeState = false;
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_ESP32)
|
||||||
|
const int pin = 0;
|
||||||
|
bool activeState = false;
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_RP2040)
|
||||||
|
const int pin = D0;
|
||||||
|
bool activeState = false;
|
||||||
|
#else
|
||||||
|
|
||||||
|
const int pin = A0;
|
||||||
|
bool activeState = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// HID report descriptor using TinyUSB's template
|
||||||
|
uint8_t const desc_keyboard_report[] = {
|
||||||
|
TUD_HID_REPORT_DESC_KEYBOARD()
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t const desc_mouse_report[] = {
|
||||||
|
TUD_HID_REPORT_DESC_MOUSE()
|
||||||
|
};
|
||||||
|
|
||||||
|
// USB HID objects
|
||||||
|
Adafruit_USBD_HID usb_keyboard;
|
||||||
|
Adafruit_USBD_HID usb_mouse;
|
||||||
|
|
||||||
|
// the setup function runs once when you press reset or power the board
|
||||||
|
void setup() {
|
||||||
|
// Manual begin() is required on core without built-in support e.g. mbed rp2040
|
||||||
|
if (!TinyUSBDevice.isInitialized()) {
|
||||||
|
TinyUSBDevice.begin(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
// HID Keyboard
|
||||||
|
usb_keyboard.setPollInterval(2);
|
||||||
|
usb_keyboard.setBootProtocol(HID_ITF_PROTOCOL_KEYBOARD);
|
||||||
|
usb_keyboard.setReportDescriptor(desc_keyboard_report, sizeof(desc_keyboard_report));
|
||||||
|
usb_keyboard.setStringDescriptor("TinyUSB HID Keyboard");
|
||||||
|
usb_keyboard.begin();
|
||||||
|
|
||||||
|
// HID Mouse
|
||||||
|
usb_mouse.setPollInterval(2);
|
||||||
|
usb_mouse.setBootProtocol(HID_ITF_PROTOCOL_MOUSE);
|
||||||
|
usb_mouse.setReportDescriptor(desc_mouse_report, sizeof(desc_mouse_report));
|
||||||
|
usb_mouse.setStringDescriptor("TinyUSB HID Keyboard");
|
||||||
|
usb_mouse.begin();
|
||||||
|
|
||||||
|
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
|
||||||
|
if (TinyUSBDevice.mounted()) {
|
||||||
|
TinyUSBDevice.detach();
|
||||||
|
delay(10);
|
||||||
|
TinyUSBDevice.attach();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up button, pullup opposite to active state
|
||||||
|
pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
|
||||||
|
|
||||||
|
Serial.println("Adafruit TinyUSB HID Composite example");
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_hid() {
|
||||||
|
// Whether button is pressed
|
||||||
|
bool btn_pressed = (digitalRead(pin) == activeState);
|
||||||
|
|
||||||
|
// Remote wakeup
|
||||||
|
if (TinyUSBDevice.suspended() && btn_pressed) {
|
||||||
|
// Wake up host if we are in suspend mode
|
||||||
|
// and REMOTE_WAKEUP feature is enabled by host
|
||||||
|
TinyUSBDevice.remoteWakeup();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------- Mouse -------------*/
|
||||||
|
if (usb_mouse.ready() && btn_pressed) {
|
||||||
|
int8_t const delta = 5;
|
||||||
|
usb_mouse.mouseMove(0, delta, delta); // right + down
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------- Keyboard -------------*/
|
||||||
|
if (usb_keyboard.ready()) {
|
||||||
|
// use to send key release report
|
||||||
|
static bool has_key = false;
|
||||||
|
|
||||||
|
if (btn_pressed) {
|
||||||
|
uint8_t keycode[6] = {0};
|
||||||
|
keycode[0] = HID_KEY_A;
|
||||||
|
|
||||||
|
usb_keyboard.keyboardReport(0, 0, keycode);
|
||||||
|
|
||||||
|
has_key = true;
|
||||||
|
} else {
|
||||||
|
// send empty key report if previously has key pressed
|
||||||
|
if (has_key) usb_keyboard.keyboardRelease(0);
|
||||||
|
has_key = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
#ifdef TINYUSB_NEED_POLLING_TASK
|
||||||
|
// Manual call tud_task since it isn't called by Core's background
|
||||||
|
TinyUSBDevice.task();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// not enumerated()/mounted() yet: nothing to do
|
||||||
|
if (!TinyUSBDevice.mounted()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// poll gpio once each 10 ms
|
||||||
|
static uint32_t ms = 0;
|
||||||
|
if (millis() - ms > 10) {
|
||||||
|
ms = millis();
|
||||||
|
process_hid();
|
||||||
|
}
|
||||||
|
}
|
||||||
2
examples/HID/hid_gamepad/.skip.txt
Normal file
2
examples/HID/hid_gamepad/.skip.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
feather_esp32_v2
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
|
@ -22,43 +22,52 @@
|
||||||
|
|
||||||
// HID report descriptor using TinyUSB's template
|
// HID report descriptor using TinyUSB's template
|
||||||
// Single Report (no ID) descriptor
|
// Single Report (no ID) descriptor
|
||||||
uint8_t const desc_hid_report[] =
|
uint8_t const desc_hid_report[] = {
|
||||||
{
|
|
||||||
TUD_HID_REPORT_DESC_GAMEPAD()
|
TUD_HID_REPORT_DESC_GAMEPAD()
|
||||||
};
|
};
|
||||||
|
|
||||||
// USB HID object. For ESP32 these values cannot be changed after this declaration
|
// USB HID object
|
||||||
// desc report, desc len, protocol, interval, use out endpoint
|
Adafruit_USBD_HID usb_hid;
|
||||||
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_NONE, 2, false);
|
|
||||||
|
|
||||||
// Report payload defined in src/class/hid/hid.h
|
// Report payload defined in src/class/hid/hid.h
|
||||||
// - For Gamepad Button Bit Mask see hid_gamepad_button_bm_t
|
// - For Gamepad Button Bit Mask see hid_gamepad_button_bm_t
|
||||||
// - For Gamepad Hat Bit Mask see hid_gamepad_hat_t
|
// - For Gamepad Hat Bit Mask see hid_gamepad_hat_t
|
||||||
hid_gamepad_report_t gp;
|
hid_gamepad_report_t gp;
|
||||||
|
|
||||||
void setup()
|
void setup() {
|
||||||
{
|
// Manual begin() is required on core without built-in support e.g. mbed rp2040
|
||||||
#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
|
if (!TinyUSBDevice.isInitialized()) {
|
||||||
// Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
|
TinyUSBDevice.begin(0);
|
||||||
TinyUSB_Device_Init(0);
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
// Notes: following commented-out functions has no affect on ESP32
|
// Setup HID
|
||||||
// usb_hid.setPollInterval(2);
|
usb_hid.setPollInterval(2);
|
||||||
// usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
||||||
|
|
||||||
usb_hid.begin();
|
usb_hid.begin();
|
||||||
|
|
||||||
// wait until device mounted
|
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
|
||||||
while( !TinyUSBDevice.mounted() ) delay(1);
|
if (TinyUSBDevice.mounted()) {
|
||||||
|
TinyUSBDevice.detach();
|
||||||
|
delay(10);
|
||||||
|
TinyUSBDevice.attach();
|
||||||
|
}
|
||||||
|
|
||||||
Serial.println("Adafruit TinyUSB HID Gamepad example");
|
Serial.println("Adafruit TinyUSB HID Gamepad example");
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop() {
|
||||||
{
|
#ifdef TINYUSB_NEED_POLLING_TASK
|
||||||
|
// Manual call tud_task since it isn't called by Core's background
|
||||||
|
TinyUSBDevice.task();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// not enumerated()/mounted() yet: nothing to do
|
||||||
|
if (!TinyUSBDevice.mounted()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// // Remote wakeup
|
// // Remote wakeup
|
||||||
// if ( TinyUSBDevice.suspended() && btn )
|
// if ( TinyUSBDevice.suspended() && btn )
|
||||||
// {
|
// {
|
||||||
|
|
@ -67,7 +76,7 @@ void loop()
|
||||||
// TinyUSBDevice.remoteWakeup();
|
// TinyUSBDevice.remoteWakeup();
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if ( !usb_hid.ready() ) return;
|
if (!usb_hid.ready()) return;
|
||||||
|
|
||||||
// Reset buttons
|
// Reset buttons
|
||||||
Serial.println("No pressing buttons");
|
Serial.println("No pressing buttons");
|
||||||
|
|
@ -249,9 +258,9 @@ void loop()
|
||||||
|
|
||||||
|
|
||||||
// Test buttons (up to 32 buttons)
|
// Test buttons (up to 32 buttons)
|
||||||
for (int i=0; i<32; ++i)
|
for (int i = 0; i < 32; ++i) {
|
||||||
{
|
Serial.print("Pressing button ");
|
||||||
Serial.print("Pressing button "); Serial.println(i);
|
Serial.println(i);
|
||||||
gp.buttons = (1U << i);
|
gp.buttons = (1U << i);
|
||||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||||
delay(1000);
|
delay(1000);
|
||||||
|
|
|
||||||
2
examples/HID/hid_generic_inout/.skip.txt
Normal file
2
examples/HID/hid_generic_inout/.skip.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
feather_esp32_v2
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
|
@ -39,50 +39,51 @@
|
||||||
|
|
||||||
// HID report descriptor using TinyUSB's template
|
// HID report descriptor using TinyUSB's template
|
||||||
// Generic In Out with 64 bytes report (max)
|
// Generic In Out with 64 bytes report (max)
|
||||||
uint8_t const desc_hid_report[] =
|
uint8_t const desc_hid_report[] = {
|
||||||
{
|
|
||||||
TUD_HID_REPORT_DESC_GENERIC_INOUT(64)
|
TUD_HID_REPORT_DESC_GENERIC_INOUT(64)
|
||||||
};
|
};
|
||||||
|
|
||||||
// USB HID object. For ESP32 these values cannot be changed after this declaration
|
// USB HID object
|
||||||
// desc report, desc len, protocol, interval, use out endpoint
|
Adafruit_USBD_HID usb_hid;
|
||||||
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_NONE, 2, true);
|
|
||||||
|
|
||||||
// the setup function runs once when you press reset or power the board
|
// the setup function runs once when you press reset or power the board
|
||||||
void setup()
|
void setup() {
|
||||||
{
|
// Manual begin() is required on core without built-in support e.g. mbed rp2040
|
||||||
#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
|
if (!TinyUSBDevice.isInitialized()) {
|
||||||
// Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
|
TinyUSBDevice.begin(0);
|
||||||
TinyUSB_Device_Init(0);
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// Notes: following commented-out functions has no affect on ESP32
|
|
||||||
// usb_hid.enableOutEndpoint(true);
|
|
||||||
// usb_hid.setPollInterval(2);
|
|
||||||
// usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
|
||||||
// usb_hid.setStringDescriptor("TinyUSB HID Generic");
|
|
||||||
|
|
||||||
usb_hid.setReportCallback(get_report_callback, set_report_callback);
|
|
||||||
usb_hid.begin();
|
|
||||||
|
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
// wait until device mounted
|
// Notes: following commented-out functions has no affect on ESP32
|
||||||
while( !TinyUSBDevice.mounted() ) delay(1);
|
usb_hid.enableOutEndpoint(true);
|
||||||
|
usb_hid.setPollInterval(2);
|
||||||
|
usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
||||||
|
usb_hid.setStringDescriptor("TinyUSB HID Generic");
|
||||||
|
usb_hid.setReportCallback(get_report_callback, set_report_callback);
|
||||||
|
usb_hid.begin();
|
||||||
|
|
||||||
|
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
|
||||||
|
if (TinyUSBDevice.mounted()) {
|
||||||
|
TinyUSBDevice.detach();
|
||||||
|
delay(10);
|
||||||
|
TinyUSBDevice.attach();
|
||||||
|
}
|
||||||
|
|
||||||
Serial.println("Adafruit TinyUSB HID Generic In Out example");
|
Serial.println("Adafruit TinyUSB HID Generic In Out example");
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop() {
|
||||||
{
|
#ifdef TINYUSB_NEED_POLLING_TASK
|
||||||
// nothing to do
|
// Manual call tud_task since it isn't called by Core's background
|
||||||
|
TinyUSBDevice.task();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoked when received GET_REPORT control request
|
// Invoked when received GET_REPORT control request
|
||||||
// Application must fill buffer report's content and return its length.
|
// Application must fill buffer report's content and return its length.
|
||||||
// Return zero will cause the stack to STALL request
|
// Return zero will cause the stack to STALL request
|
||||||
uint16_t get_report_callback (uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
|
uint16_t get_report_callback(uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) {
|
||||||
{
|
|
||||||
// not used in this example
|
// not used in this example
|
||||||
(void) report_id;
|
(void) report_id;
|
||||||
(void) report_type;
|
(void) report_type;
|
||||||
|
|
@ -93,8 +94,7 @@ uint16_t get_report_callback (uint8_t report_id, hid_report_type_t report_type,
|
||||||
|
|
||||||
// Invoked when received SET_REPORT control request or
|
// Invoked when received SET_REPORT control request or
|
||||||
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
|
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
|
||||||
void set_report_callback(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
|
void set_report_callback(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) {
|
||||||
{
|
|
||||||
// This example doesn't use multiple report and report ID
|
// This example doesn't use multiple report and report ID
|
||||||
(void) report_id;
|
(void) report_id;
|
||||||
(void) report_type;
|
(void) report_type;
|
||||||
|
|
|
||||||
225
examples/Host/Simple/host_device_info/host_device_info.ino
Normal file
225
examples/Host/Simple/host_device_info/host_device_info.ino
Normal file
|
|
@ -0,0 +1,225 @@
|
||||||
|
/*********************************************************************
|
||||||
|
Adafruit invests time and resources providing this open source code,
|
||||||
|
please support Adafruit and open-source hardware by purchasing
|
||||||
|
products from Adafruit!
|
||||||
|
|
||||||
|
MIT license, check LICENSE for more information
|
||||||
|
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||||
|
All text above, and the splash screen below must be included in
|
||||||
|
any redistribution
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
/* This example demonstrates use of native controller as host (TinyUSB Host)
|
||||||
|
* Note:
|
||||||
|
* - For most mcu with only 1 native usb, Serial is not available. We will use Serial1 instead
|
||||||
|
*
|
||||||
|
* Host example will get device descriptors of attached devices and print it out as follows:
|
||||||
|
Device 1: ID 046d:c52f
|
||||||
|
Device Descriptor:
|
||||||
|
bLength 18
|
||||||
|
bDescriptorType 1
|
||||||
|
bcdUSB 0200
|
||||||
|
bDeviceClass 0
|
||||||
|
bDeviceSubClass 0
|
||||||
|
bDeviceProtocol 0
|
||||||
|
bMaxPacketSize0 8
|
||||||
|
idVendor 0x046d
|
||||||
|
idProduct 0xc52f
|
||||||
|
bcdDevice 2200
|
||||||
|
iManufacturer 1 Logitech
|
||||||
|
iProduct 2 USB Receiver
|
||||||
|
iSerialNumber 0
|
||||||
|
bNumConfigurations 1
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Adafruit_TinyUSB.h"
|
||||||
|
|
||||||
|
#ifndef USE_TINYUSB_HOST
|
||||||
|
#error This example requires usb stack configured as host in "Tools -> USB Stack -> Adafruit TinyUSB Host"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Language ID: English
|
||||||
|
#define LANGUAGE_ID 0x0409
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
tusb_desc_device_t desc_device;
|
||||||
|
uint16_t manufacturer[32];
|
||||||
|
uint16_t product[48];
|
||||||
|
uint16_t serial[16];
|
||||||
|
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 };
|
||||||
|
|
||||||
|
Adafruit_USBH_Host USBHost;
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// setup() & loop()
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
void setup() {
|
||||||
|
Serial1.begin(115200);
|
||||||
|
Serial1.println("TinyUSB Host: Device Info Example");
|
||||||
|
|
||||||
|
// Init USB Host on native controller roothub port0
|
||||||
|
USBHost.begin(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
USBHost.task();
|
||||||
|
Serial1.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// TinyUSB Host callbacks
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
void print_device_descriptor(tuh_xfer_t *xfer);
|
||||||
|
|
||||||
|
void utf16_to_utf8(uint16_t *temp_buf, size_t buf_len);
|
||||||
|
|
||||||
|
void print_lsusb(void) {
|
||||||
|
bool no_device = true;
|
||||||
|
for (uint8_t daddr = 1; daddr < CFG_TUH_DEVICE_MAX + 1; daddr++) {
|
||||||
|
// TODO can use tuh_mounted(daddr), but tinyusb has an bug
|
||||||
|
// use local connected flag instead
|
||||||
|
dev_info_t *dev = &dev_info[daddr - 1];
|
||||||
|
if (dev->mounted) {
|
||||||
|
Serial1.printf("Device %u: ID %04x:%04x %s %s\r\n", daddr,
|
||||||
|
dev->desc_device.idVendor, dev->desc_device.idProduct,
|
||||||
|
(char *) dev->manufacturer, (char *) dev->product);
|
||||||
|
|
||||||
|
no_device = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (no_device) {
|
||||||
|
Serial1.println("No device connected (except hub)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoked when device is mounted (configured)
|
||||||
|
void tuh_mount_cb(uint8_t daddr) {
|
||||||
|
Serial1.printf("Device attached, address = %d\r\n", daddr);
|
||||||
|
|
||||||
|
dev_info_t *dev = &dev_info[daddr - 1];
|
||||||
|
dev->mounted = true;
|
||||||
|
|
||||||
|
// Get Device Descriptor
|
||||||
|
tuh_descriptor_get_device(daddr, &dev->desc_device, 18, print_device_descriptor, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invoked when device is unmounted (bus reset/unplugged)
|
||||||
|
void tuh_umount_cb(uint8_t daddr) {
|
||||||
|
Serial1.printf("Device removed, address = %d\r\n", daddr);
|
||||||
|
dev_info_t *dev = &dev_info[daddr - 1];
|
||||||
|
dev->mounted = false;
|
||||||
|
|
||||||
|
// print device summary
|
||||||
|
print_lsusb();
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_device_descriptor(tuh_xfer_t *xfer) {
|
||||||
|
if (XFER_RESULT_SUCCESS != xfer->result) {
|
||||||
|
Serial1.printf("Failed to get device descriptor\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t const daddr = xfer->daddr;
|
||||||
|
dev_info_t *dev = &dev_info[daddr - 1];
|
||||||
|
tusb_desc_device_t *desc = &dev->desc_device;
|
||||||
|
|
||||||
|
Serial1.printf("Device %u: ID %04x:%04x\r\n", daddr, desc->idVendor, desc->idProduct);
|
||||||
|
Serial1.printf("Device Descriptor:\r\n");
|
||||||
|
Serial1.printf(" bLength %u\r\n" , desc->bLength);
|
||||||
|
Serial1.printf(" bDescriptorType %u\r\n" , desc->bDescriptorType);
|
||||||
|
Serial1.printf(" bcdUSB %04x\r\n" , desc->bcdUSB);
|
||||||
|
Serial1.printf(" bDeviceClass %u\r\n" , desc->bDeviceClass);
|
||||||
|
Serial1.printf(" bDeviceSubClass %u\r\n" , desc->bDeviceSubClass);
|
||||||
|
Serial1.printf(" bDeviceProtocol %u\r\n" , desc->bDeviceProtocol);
|
||||||
|
Serial1.printf(" bMaxPacketSize0 %u\r\n" , desc->bMaxPacketSize0);
|
||||||
|
Serial1.printf(" idVendor 0x%04x\r\n" , desc->idVendor);
|
||||||
|
Serial1.printf(" idProduct 0x%04x\r\n" , desc->idProduct);
|
||||||
|
Serial1.printf(" bcdDevice %04x\r\n" , desc->bcdDevice);
|
||||||
|
|
||||||
|
// Get String descriptor using Sync API
|
||||||
|
Serial1.printf(" iManufacturer %u ", desc->iManufacturer);
|
||||||
|
if (XFER_RESULT_SUCCESS ==
|
||||||
|
tuh_descriptor_get_manufacturer_string_sync(daddr, LANGUAGE_ID, dev->manufacturer, sizeof(dev->manufacturer))) {
|
||||||
|
utf16_to_utf8(dev->manufacturer, sizeof(dev->manufacturer));
|
||||||
|
Serial1.printf((char *) dev->manufacturer);
|
||||||
|
}
|
||||||
|
Serial1.printf("\r\n");
|
||||||
|
|
||||||
|
Serial1.printf(" iProduct %u ", desc->iProduct);
|
||||||
|
if (XFER_RESULT_SUCCESS ==
|
||||||
|
tuh_descriptor_get_product_string_sync(daddr, LANGUAGE_ID, dev->product, sizeof(dev->product))) {
|
||||||
|
utf16_to_utf8(dev->product, sizeof(dev->product));
|
||||||
|
Serial1.printf((char *) dev->product);
|
||||||
|
}
|
||||||
|
Serial1.printf("\r\n");
|
||||||
|
|
||||||
|
Serial1.printf(" iSerialNumber %u ", desc->iSerialNumber);
|
||||||
|
if (XFER_RESULT_SUCCESS ==
|
||||||
|
tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, dev->serial, sizeof(dev->serial))) {
|
||||||
|
utf16_to_utf8(dev->serial, sizeof(dev->serial));
|
||||||
|
Serial1.printf((char *) dev->serial);
|
||||||
|
}
|
||||||
|
Serial1.printf("\r\n");
|
||||||
|
|
||||||
|
Serial1.printf(" bNumConfigurations %u\r\n", desc->bNumConfigurations);
|
||||||
|
|
||||||
|
// print device summary
|
||||||
|
print_lsusb();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// String Descriptor Helper
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
static void _convert_utf16le_to_utf8(const uint16_t *utf16, size_t utf16_len, uint8_t *utf8, size_t utf8_len) {
|
||||||
|
// TODO: Check for runover.
|
||||||
|
(void) utf8_len;
|
||||||
|
// Get the UTF-16 length out of the data itself.
|
||||||
|
|
||||||
|
for (size_t i = 0; i < utf16_len; i++) {
|
||||||
|
uint16_t chr = utf16[i];
|
||||||
|
if (chr < 0x80) {
|
||||||
|
*utf8++ = chr & 0xff;
|
||||||
|
} else if (chr < 0x800) {
|
||||||
|
*utf8++ = (uint8_t) (0xC0 | (chr >> 6 & 0x1F));
|
||||||
|
*utf8++ = (uint8_t) (0x80 | (chr >> 0 & 0x3F));
|
||||||
|
} else {
|
||||||
|
// TODO: Verify surrogate.
|
||||||
|
*utf8++ = (uint8_t) (0xE0 | (chr >> 12 & 0x0F));
|
||||||
|
*utf8++ = (uint8_t) (0x80 | (chr >> 6 & 0x3F));
|
||||||
|
*utf8++ = (uint8_t) (0x80 | (chr >> 0 & 0x3F));
|
||||||
|
}
|
||||||
|
// TODO: Handle UTF-16 code points that take two entries.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count how many bytes a utf-16-le encoded string will take in utf-8.
|
||||||
|
static int _count_utf8_bytes(const uint16_t *buf, size_t len) {
|
||||||
|
size_t total_bytes = 0;
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
uint16_t chr = buf[i];
|
||||||
|
if (chr < 0x80) {
|
||||||
|
total_bytes += 1;
|
||||||
|
} else if (chr < 0x800) {
|
||||||
|
total_bytes += 2;
|
||||||
|
} else {
|
||||||
|
total_bytes += 3;
|
||||||
|
}
|
||||||
|
// TODO: Handle UTF-16 code points that take two entries.
|
||||||
|
}
|
||||||
|
return total_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void utf16_to_utf8(uint16_t *temp_buf, size_t buf_len) {
|
||||||
|
size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t);
|
||||||
|
size_t utf8_len = _count_utf8_bytes(temp_buf + 1, utf16_len);
|
||||||
|
|
||||||
|
_convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, buf_len);
|
||||||
|
((uint8_t *) temp_buf)[utf8_len] = '\0';
|
||||||
|
}
|
||||||
2
examples/MIDI/midi_multi_ports/.skip.txt
Normal file
2
examples/MIDI/midi_multi_ports/.skip.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
feather_esp32_v2
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
|
@ -19,28 +19,43 @@
|
||||||
// USB MIDI object with 3 ports
|
// USB MIDI object with 3 ports
|
||||||
Adafruit_USBD_MIDI usb_midi(3);
|
Adafruit_USBD_MIDI usb_midi(3);
|
||||||
|
|
||||||
void setup()
|
void setup() {
|
||||||
{
|
#ifdef LED_BUILTIN
|
||||||
pinMode(LED_BUILTIN, OUTPUT);
|
pinMode(LED_BUILTIN, OUTPUT);
|
||||||
|
|
||||||
#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
|
|
||||||
// Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
|
|
||||||
TinyUSB_Device_Init(0);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Manual begin() is required on core without built-in support e.g. mbed rp2040
|
||||||
|
if (!TinyUSBDevice.isInitialized()) {
|
||||||
|
TinyUSBDevice.begin(0);
|
||||||
|
}
|
||||||
|
|
||||||
// Set name for each cable, must be done before usb_midi.begin()
|
// Set name for each cable, must be done before usb_midi.begin()
|
||||||
usb_midi.setCableName(1, "Keyboard");
|
usb_midi.setCableName(1, "Keyboard");
|
||||||
usb_midi.setCableName(2, "Drum Pads");
|
usb_midi.setCableName(2, "Drum Pads");
|
||||||
usb_midi.setCableName(3, "Lights");
|
usb_midi.setCableName(3, "Lights");
|
||||||
|
|
||||||
usb_midi.begin();
|
usb_midi.begin();
|
||||||
|
|
||||||
|
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
|
||||||
|
if (TinyUSBDevice.mounted()) {
|
||||||
|
TinyUSBDevice.detach();
|
||||||
|
delay(10);
|
||||||
|
TinyUSBDevice.attach();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop() {
|
||||||
{
|
#ifdef TINYUSB_NEED_POLLING_TASK
|
||||||
digitalWrite(LED_BUILTIN, HIGH);
|
// Manual call tud_task since it isn't called by Core's background
|
||||||
delay(1000);
|
TinyUSBDevice.task();
|
||||||
|
#endif
|
||||||
|
|
||||||
digitalWrite(LED_BUILTIN, LOW);
|
// toggle LED
|
||||||
delay(1000);
|
static uint32_t ms = 0;
|
||||||
|
static uint8_t led_state = 0;
|
||||||
|
if (millis() - ms > 1000) {
|
||||||
|
ms = millis();
|
||||||
|
#ifdef LED_BUILTIN
|
||||||
|
digitalWrite(LED_BUILTIN, 1-led_state);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
examples/MIDI/midi_test/.skip.txt
Normal file
2
examples/MIDI/midi_test/.skip.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
feather_esp32_v2
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
|
@ -31,44 +31,53 @@ uint32_t position = 0;
|
||||||
|
|
||||||
// Store example melody as an array of note values
|
// Store example melody as an array of note values
|
||||||
byte note_sequence[] = {
|
byte note_sequence[] = {
|
||||||
74,78,81,86,90,93,98,102,57,61,66,69,73,78,81,85,88,92,97,100,97,92,88,85,81,78,
|
74, 78, 81, 86, 90, 93, 98, 102, 57, 61, 66, 69, 73, 78, 81, 85, 88, 92, 97, 100, 97, 92, 88, 85, 81, 78,
|
||||||
74,69,66,62,57,62,66,69,74,78,81,86,90,93,97,102,97,93,90,85,81,78,73,68,64,61,
|
74, 69, 66, 62, 57, 62, 66, 69, 74, 78, 81, 86, 90, 93, 97, 102, 97, 93, 90, 85, 81, 78, 73, 68, 64, 61,
|
||||||
56,61,64,68,74,78,81,86,90,93,98,102
|
56, 61, 64, 68, 74, 78, 81, 86, 90, 93, 98, 102
|
||||||
};
|
};
|
||||||
|
|
||||||
void setup()
|
void setup() {
|
||||||
{
|
// Manual begin() is required on core without built-in support e.g. mbed rp2040
|
||||||
#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
|
if (!TinyUSBDevice.isInitialized()) {
|
||||||
// Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
|
TinyUSBDevice.begin(0);
|
||||||
TinyUSB_Device_Init(0);
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
pinMode(LED_BUILTIN, OUTPUT);
|
Serial.begin(115200);
|
||||||
|
|
||||||
//usb_midi.setStringDescriptor("TinyUSB MIDI");
|
usb_midi.setStringDescriptor("TinyUSB MIDI");
|
||||||
|
|
||||||
// Initialize MIDI, and listen to all MIDI channels
|
// Initialize MIDI, and listen to all MIDI channels
|
||||||
// This will also call usb_midi's begin()
|
// This will also call usb_midi's begin()
|
||||||
MIDI.begin(MIDI_CHANNEL_OMNI);
|
MIDI.begin(MIDI_CHANNEL_OMNI);
|
||||||
|
|
||||||
|
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
|
||||||
|
if (TinyUSBDevice.mounted()) {
|
||||||
|
TinyUSBDevice.detach();
|
||||||
|
delay(10);
|
||||||
|
TinyUSBDevice.attach();
|
||||||
|
}
|
||||||
|
|
||||||
// Attach the handleNoteOn function to the MIDI Library. It will
|
// Attach the handleNoteOn function to the MIDI Library. It will
|
||||||
// be called whenever the Bluefruit receives MIDI Note On messages.
|
// be called whenever the Bluefruit receives MIDI Note On messages.
|
||||||
MIDI.setHandleNoteOn(handleNoteOn);
|
MIDI.setHandleNoteOn(handleNoteOn);
|
||||||
|
|
||||||
// Do the same for MIDI Note Off messages.
|
// Do the same for MIDI Note Off messages.
|
||||||
MIDI.setHandleNoteOff(handleNoteOff);
|
MIDI.setHandleNoteOff(handleNoteOff);
|
||||||
|
|
||||||
Serial.begin(115200);
|
|
||||||
|
|
||||||
// wait until device mounted
|
|
||||||
while( !TinyUSBDevice.mounted() ) delay(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop() {
|
||||||
{
|
#ifdef TINYUSB_NEED_POLLING_TASK
|
||||||
|
// Manual call tud_task since it isn't called by Core's background
|
||||||
|
TinyUSBDevice.task();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// not enumerated()/mounted() yet: nothing to do
|
||||||
|
if (!TinyUSBDevice.mounted()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t start_ms = 0;
|
static uint32_t start_ms = 0;
|
||||||
if ( millis() - start_ms > 266 )
|
if (millis() - start_ms > 266) {
|
||||||
{
|
|
||||||
start_ms += 266;
|
start_ms += 266;
|
||||||
|
|
||||||
// Setup variables for the current and previous
|
// Setup variables for the current and previous
|
||||||
|
|
@ -100,8 +109,7 @@ void loop()
|
||||||
MIDI.read();
|
MIDI.read();
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleNoteOn(byte channel, byte pitch, byte velocity)
|
void handleNoteOn(byte channel, byte pitch, byte velocity) {
|
||||||
{
|
|
||||||
// Log when a note is pressed.
|
// Log when a note is pressed.
|
||||||
Serial.print("Note on: channel = ");
|
Serial.print("Note on: channel = ");
|
||||||
Serial.print(channel);
|
Serial.print(channel);
|
||||||
|
|
@ -113,8 +121,7 @@ void handleNoteOn(byte channel, byte pitch, byte velocity)
|
||||||
Serial.println(velocity);
|
Serial.println(velocity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleNoteOff(byte channel, byte pitch, byte velocity)
|
void handleNoteOff(byte channel, byte pitch, byte velocity) {
|
||||||
{
|
|
||||||
// Log when a note is released.
|
// Log when a note is released.
|
||||||
Serial.print("Note off: channel = ");
|
Serial.print("Note off: channel = ");
|
||||||
Serial.print(channel);
|
Serial.print(channel);
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "SPI.h"
|
#include "SPI.h"
|
||||||
#include "SdFat.h"
|
#include "SdFat_Adafruit_Fork.h"
|
||||||
#include "Adafruit_SPIFlash.h"
|
#include "Adafruit_SPIFlash.h"
|
||||||
#include "Adafruit_TinyUSB.h"
|
#include "Adafruit_TinyUSB.h"
|
||||||
|
|
||||||
|
|
@ -93,14 +93,19 @@ void setupMassStorage(void)
|
||||||
// MSC is ready for read/write
|
// MSC is ready for read/write
|
||||||
fs_changed = false;
|
fs_changed = false;
|
||||||
usb_msc.setReadyCallback(0, msc_ready_callback);
|
usb_msc.setReadyCallback(0, msc_ready_callback);
|
||||||
|
|
||||||
usb_msc.begin();
|
usb_msc.begin();
|
||||||
|
|
||||||
|
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
|
||||||
|
if (TinyUSBDevice.mounted()) {
|
||||||
|
TinyUSBDevice.detach();
|
||||||
|
delay(10);
|
||||||
|
TinyUSBDevice.attach();
|
||||||
|
}
|
||||||
|
|
||||||
// Init file system on the flash
|
// Init file system on the flash
|
||||||
fs_formatted = fatfs.begin(&flash);
|
fs_formatted = fatfs.begin(&flash);
|
||||||
|
|
||||||
if ( !fs_formatted )
|
if ( !fs_formatted ) {
|
||||||
{
|
|
||||||
DBG_SERIAL.println("Failed to init files system, flash may not be formatted");
|
DBG_SERIAL.println("Failed to init files system, flash may not be formatted");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
3
examples/MassStorage/msc_external_flash/.skip.txt
Normal file
3
examples/MassStorage/msc_external_flash/.skip.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
feather_esp32_v2
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
CH32V20x_EVT
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "SPI.h"
|
#include "SPI.h"
|
||||||
#include "SdFat.h"
|
#include "SdFat_Adafruit_Fork.h"
|
||||||
#include "Adafruit_SPIFlash.h"
|
#include "Adafruit_SPIFlash.h"
|
||||||
#include "Adafruit_TinyUSB.h"
|
#include "Adafruit_TinyUSB.h"
|
||||||
|
|
||||||
|
|
@ -48,9 +48,12 @@ bool fs_formatted = false;
|
||||||
bool fs_changed = true;;
|
bool fs_changed = true;;
|
||||||
|
|
||||||
// the setup function runs once when you press reset or power the board
|
// the setup function runs once when you press reset or power the board
|
||||||
void setup()
|
void setup() {
|
||||||
{
|
#ifdef LED_BUILTIN
|
||||||
pinMode(LED_BUILTIN, OUTPUT);
|
pinMode(LED_BUILTIN, OUTPUT);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
flash.begin();
|
flash.begin();
|
||||||
|
|
||||||
|
|
@ -68,10 +71,16 @@ void setup()
|
||||||
|
|
||||||
usb_msc.begin();
|
usb_msc.begin();
|
||||||
|
|
||||||
|
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
|
||||||
|
if (TinyUSBDevice.mounted()) {
|
||||||
|
TinyUSBDevice.detach();
|
||||||
|
delay(10);
|
||||||
|
TinyUSBDevice.attach();
|
||||||
|
}
|
||||||
|
|
||||||
// Init file system on the flash
|
// Init file system on the flash
|
||||||
fs_formatted = fatfs.begin(&flash);
|
fs_formatted = fatfs.begin(&flash);
|
||||||
|
|
||||||
Serial.begin(115200);
|
|
||||||
//while ( !Serial ) delay(10); // wait for native usb
|
//while ( !Serial ) delay(10); // wait for native usb
|
||||||
|
|
||||||
Serial.println("Adafruit TinyUSB Mass Storage External Flash example");
|
Serial.println("Adafruit TinyUSB Mass Storage External Flash example");
|
||||||
|
|
@ -79,15 +88,12 @@ void setup()
|
||||||
Serial.print("Flash size: "); Serial.print(flash.size() / 1024); Serial.println(" KB");
|
Serial.print("Flash size: "); Serial.print(flash.size() / 1024); Serial.println(" KB");
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop() {
|
||||||
{
|
|
||||||
// check if formatted
|
// check if formatted
|
||||||
if ( !fs_formatted )
|
if ( !fs_formatted ) {
|
||||||
{
|
|
||||||
fs_formatted = fatfs.begin(&flash);
|
fs_formatted = fatfs.begin(&flash);
|
||||||
|
|
||||||
if (!fs_formatted)
|
if (!fs_formatted) {
|
||||||
{
|
|
||||||
Serial.println("Failed to init files system, flash may not be formatted");
|
Serial.println("Failed to init files system, flash may not be formatted");
|
||||||
Serial.println("Please format it as FAT12 with your PC or using Adafruit_SPIFlash's SdFat_format example:");
|
Serial.println("Please format it as FAT12 with your PC or using Adafruit_SPIFlash's SdFat_format example:");
|
||||||
Serial.println("- https://github.com/adafruit/Adafruit_SPIFlash/tree/master/examples/SdFat_format");
|
Serial.println("- https://github.com/adafruit/Adafruit_SPIFlash/tree/master/examples/SdFat_format");
|
||||||
|
|
@ -98,14 +104,12 @@ void loop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( fs_changed )
|
if ( fs_changed ) {
|
||||||
{
|
|
||||||
fs_changed = false;
|
fs_changed = false;
|
||||||
|
|
||||||
Serial.println("Opening root");
|
Serial.println("Opening root");
|
||||||
|
|
||||||
if ( !root.open("/") )
|
if ( !root.open("/") ) {
|
||||||
{
|
|
||||||
Serial.println("open root failed");
|
Serial.println("open root failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -115,13 +119,11 @@ void loop()
|
||||||
// Open next file in root.
|
// Open next file in root.
|
||||||
// Warning, openNext starts at the current directory position
|
// Warning, openNext starts at the current directory position
|
||||||
// so a rewind of the directory may be required.
|
// so a rewind of the directory may be required.
|
||||||
while ( file.openNext(&root, O_RDONLY) )
|
while ( file.openNext(&root, O_RDONLY) ) {
|
||||||
{
|
|
||||||
file.printFileSize(&Serial);
|
file.printFileSize(&Serial);
|
||||||
Serial.write(' ');
|
Serial.write(' ');
|
||||||
file.printName(&Serial);
|
file.printName(&Serial);
|
||||||
if ( file.isDir() )
|
if ( file.isDir() ) {
|
||||||
{
|
|
||||||
// Indicate a directory.
|
// Indicate a directory.
|
||||||
Serial.write('/');
|
Serial.write('/');
|
||||||
}
|
}
|
||||||
|
|
@ -139,8 +141,7 @@ void loop()
|
||||||
// Callback invoked when received READ10 command.
|
// Callback invoked when received READ10 command.
|
||||||
// Copy disk's data to buffer (up to bufsize) and
|
// Copy disk's data to buffer (up to bufsize) and
|
||||||
// return number of copied bytes (must be multiple of block size)
|
// return number of copied bytes (must be multiple of block size)
|
||||||
int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) {
|
||||||
{
|
|
||||||
// Note: SPIFLash Block API: readBlocks/writeBlocks/syncBlocks
|
// Note: SPIFLash Block API: readBlocks/writeBlocks/syncBlocks
|
||||||
// already include 4K sector caching internally. We don't need to cache it, yahhhh!!
|
// already include 4K sector caching internally. We don't need to cache it, yahhhh!!
|
||||||
return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1;
|
return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1;
|
||||||
|
|
@ -149,9 +150,10 @@ int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||||
// Callback invoked when received WRITE10 command.
|
// Callback invoked when received WRITE10 command.
|
||||||
// Process data in buffer to disk's storage and
|
// Process data in buffer to disk's storage and
|
||||||
// return number of written bytes (must be multiple of block size)
|
// return number of written bytes (must be multiple of block size)
|
||||||
int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize) {
|
||||||
{
|
#ifdef LED_BUILTIN
|
||||||
digitalWrite(LED_BUILTIN, HIGH);
|
digitalWrite(LED_BUILTIN, HIGH);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Note: SPIFLash Block API: readBlocks/writeBlocks/syncBlocks
|
// Note: SPIFLash Block API: readBlocks/writeBlocks/syncBlocks
|
||||||
// already include 4K sector caching internally. We don't need to cache it, yahhhh!!
|
// already include 4K sector caching internally. We don't need to cache it, yahhhh!!
|
||||||
|
|
@ -160,8 +162,7 @@ int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
||||||
|
|
||||||
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
||||||
// used to flush any pending cache.
|
// used to flush any pending cache.
|
||||||
void msc_flush_cb (void)
|
void msc_flush_cb (void) {
|
||||||
{
|
|
||||||
// sync with flash
|
// sync with flash
|
||||||
flash.syncBlocks();
|
flash.syncBlocks();
|
||||||
|
|
||||||
|
|
@ -170,5 +171,7 @@ void msc_flush_cb (void)
|
||||||
|
|
||||||
fs_changed = true;
|
fs_changed = true;
|
||||||
|
|
||||||
|
#ifdef LED_BUILTIN
|
||||||
digitalWrite(LED_BUILTIN, LOW);
|
digitalWrite(LED_BUILTIN, LOW);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
||||||
3
examples/MassStorage/msc_external_flash_sdcard/.skip.txt
Normal file
3
examples/MassStorage/msc_external_flash_sdcard/.skip.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
feather_esp32_v2
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
CH32V20x_EVT
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "SPI.h"
|
#include "SPI.h"
|
||||||
#include "SdFat.h"
|
#include "SdFat_Adafruit_Fork.h"
|
||||||
#include "Adafruit_SPIFlash.h"
|
#include "Adafruit_SPIFlash.h"
|
||||||
#include "Adafruit_TinyUSB.h"
|
#include "Adafruit_TinyUSB.h"
|
||||||
|
|
||||||
|
|
@ -33,42 +33,67 @@
|
||||||
|
|
||||||
// for flashTransport definition
|
// for flashTransport definition
|
||||||
#include "flash_config.h"
|
#include "flash_config.h"
|
||||||
|
|
||||||
Adafruit_SPIFlash flash(&flashTransport);
|
Adafruit_SPIFlash flash(&flashTransport);
|
||||||
|
|
||||||
// External Flash File system
|
|
||||||
FatVolume fatfs;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// SDCard Config
|
// SDCard Config
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
#if defined(ARDUINO_PYPORTAL_M4) || defined(ARDUINO_PYPORTAL_M4_TITANO)
|
#if defined(ARDUINO_PYPORTAL_M4) || defined(ARDUINO_PYPORTAL_M4_TITANO)
|
||||||
// PyPortal has on-board card reader
|
// PyPortal has on-board card reader
|
||||||
#define SDCARD_CS 32
|
#define SDCARD_CS 32
|
||||||
#define SDCARD_DETECT 33
|
#define SDCARD_DETECT 33
|
||||||
|
#define SDCARD_DETECT_ACTIVE HIGH
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ADAFRUIT_METRO_RP2040)
|
||||||
|
#define SDIO_CLK_PIN 18
|
||||||
|
#define SDIO_CMD_PIN 19 // MOSI
|
||||||
|
#define SDIO_DAT0_PIN 20 // DAT1: 21, DAT2: 22, DAT3: 23
|
||||||
|
|
||||||
|
#define SDCARD_DETECT 15
|
||||||
|
#define SDCARD_DETECT_ACTIVE LOW
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ADAFRUIT_METRO_RP2350)
|
||||||
|
// Note: not working yet (need troubleshoot later)
|
||||||
|
#define SDIO_CLK_PIN 34
|
||||||
|
#define SDIO_CMD_PIN 35 // MOSI
|
||||||
|
#define SDIO_DAT0_PIN 36 // DAT1: 37, DAT2: 38, DAT3: 39
|
||||||
|
|
||||||
|
#define SDCARD_DETECT 40
|
||||||
|
#define SDCARD_DETECT_ACTIVE LOW
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ADAFRUIT_FRUITJAM_RP2350)
|
||||||
|
#define SDIO_CLK_PIN 34
|
||||||
|
#define SDIO_CMD_PIN 35 // MOSI
|
||||||
|
#define SDIO_DAT0_PIN 36 // DAT1: 37, DAT2: 38, DAT3: 39
|
||||||
|
|
||||||
|
#define SDCARD_DETECT 33
|
||||||
|
#define SDCARD_DETECT_ACTIVE LOW
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
// Use SPI, no detect
|
||||||
#define SDCARD_CS 10
|
#define SDCARD_CS 10
|
||||||
// no detect
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// SDCard File system
|
#if defined(SDIO_CLK_PIN) && defined(SDIO_CMD_PIN) && defined(SDIO_DAT0_PIN)
|
||||||
|
#define SD_CONFIG SdioConfig(SDIO_CLK_PIN, SDIO_CMD_PIN, SDIO_DAT0_PIN)
|
||||||
|
#else
|
||||||
|
#define SD_CONFIG SdSpiConfig(SDCARD_CS, SHARED_SPI, SD_SCK_MHZ(50))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// File system on SD Card
|
||||||
SdFat sd;
|
SdFat sd;
|
||||||
|
|
||||||
// USB Mass Storage object
|
// USB Mass Storage object
|
||||||
Adafruit_USBD_MSC usb_msc;
|
Adafruit_USBD_MSC usb_msc;
|
||||||
|
|
||||||
// Set to true when PC write to flash
|
// Set to true when PC write to flash
|
||||||
bool sd_changed = false;
|
|
||||||
bool sd_inited = false;
|
bool sd_inited = false;
|
||||||
|
|
||||||
bool flash_formatted = false;
|
|
||||||
bool flash_changed = false;
|
|
||||||
|
|
||||||
// the setup function runs once when you press reset or power the board
|
// the setup function runs once when you press reset or power the board
|
||||||
void setup()
|
void setup() {
|
||||||
{
|
#ifdef LED_BUILTIN
|
||||||
pinMode(LED_BUILTIN, OUTPUT);
|
pinMode(LED_BUILTIN, OUTPUT);
|
||||||
|
#endif
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
// MSC with 2 Logical Units: LUN0: External Flash, LUN1: SDCard
|
// MSC with 2 Logical Units: LUN0: External Flash, LUN1: SDCard
|
||||||
|
|
@ -83,16 +108,20 @@ void setup()
|
||||||
// LUN readiness will always be set later on
|
// LUN readiness will always be set later on
|
||||||
usb_msc.begin();
|
usb_msc.begin();
|
||||||
|
|
||||||
|
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
|
||||||
|
if (TinyUSBDevice.mounted()) {
|
||||||
|
TinyUSBDevice.detach();
|
||||||
|
delay(10);
|
||||||
|
TinyUSBDevice.attach();
|
||||||
|
}
|
||||||
|
|
||||||
//------------- Lun 0 for external flash -------------//
|
//------------- Lun 0 for external flash -------------//
|
||||||
flash.begin();
|
flash.begin();
|
||||||
flash_formatted = fatfs.begin(&flash);
|
|
||||||
|
|
||||||
usb_msc.setCapacity(0, flash.size()/512, 512);
|
usb_msc.setCapacity(0, flash.size()/512, 512);
|
||||||
usb_msc.setReadWriteCallback(0, external_flash_read_cb, external_flash_write_cb, external_flash_flush_cb);
|
usb_msc.setReadWriteCallback(0, external_flash_read_cb, external_flash_write_cb, external_flash_flush_cb);
|
||||||
usb_msc.setUnitReady(0, true);
|
usb_msc.setUnitReady(0, true);
|
||||||
|
|
||||||
flash_changed = true; // to print contents initially
|
|
||||||
|
|
||||||
//------------- Lun 1 for SD card -------------//
|
//------------- Lun 1 for SD card -------------//
|
||||||
#ifdef SDCARD_DETECT
|
#ifdef SDCARD_DETECT
|
||||||
// DETECT pin is available, detect card present on the fly with test unit ready
|
// DETECT pin is available, detect card present on the fly with test unit ready
|
||||||
|
|
@ -105,58 +134,44 @@ void setup()
|
||||||
usb_msc.setUnitReady(1, true);
|
usb_msc.setUnitReady(1, true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// while ( !Serial ) delay(10); // wait for native usb
|
// while ( !Serial ) delay(10); // wait for native usb
|
||||||
Serial.println("Adafruit TinyUSB Mass Storage External Flash + SD Card example");
|
Serial.println("Adafruit TinyUSB Mass Storage External Flash + SD Card example");
|
||||||
delay(1000);
|
delay(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool init_sdcard(void)
|
bool init_sdcard(void) {
|
||||||
{
|
|
||||||
Serial.print("Init SDCard ... ");
|
Serial.print("Init SDCard ... ");
|
||||||
|
|
||||||
if ( !sd.begin(SDCARD_CS, SD_SCK_MHZ(50)) )
|
if (!sd.begin(SD_CONFIG)) {
|
||||||
{
|
Serial.println("initialization failed. Things to check:");
|
||||||
Serial.print("Failed ");
|
Serial.println("- is a card inserted?");
|
||||||
sd.errorPrint("sd.begin() failed");
|
Serial.println("- is your wiring correct?");
|
||||||
|
Serial.println("- did you change the SDCARD_CS or SDIO pin to match your shield or module?");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t block_count;
|
uint32_t block_count = sd.card()->sectorCount();
|
||||||
|
|
||||||
#if SD_FAT_VERSION >= 20000
|
|
||||||
block_count = sd.card()->sectorCount();
|
|
||||||
#else
|
|
||||||
block_count = sd.card()->cardSize();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
usb_msc.setCapacity(1, block_count, 512);
|
usb_msc.setCapacity(1, block_count, 512);
|
||||||
usb_msc.setReadWriteCallback(1, sdcard_read_cb, sdcard_write_cb, sdcard_flush_cb);
|
usb_msc.setReadWriteCallback(1, sdcard_read_cb, sdcard_write_cb, sdcard_flush_cb);
|
||||||
|
|
||||||
sd_changed = true; // to print contents initially
|
|
||||||
|
|
||||||
Serial.print("OK, Card size = ");
|
Serial.print("OK, Card size = ");
|
||||||
Serial.print((block_count / (1024*1024)) * 512);
|
Serial.print((block_count / (1024 * 1024)) * 512);
|
||||||
Serial.println(" MB");
|
Serial.println(" MB");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_rootdir(File32* rdir)
|
void print_rootdir(File32* rdir) {
|
||||||
{
|
|
||||||
File32 file;
|
File32 file;
|
||||||
|
|
||||||
// Open next file in root.
|
// Open next file in root.
|
||||||
// Warning, openNext starts at the current directory position
|
// Warning, openNext starts at the current directory position
|
||||||
// so a rewind of the directory may be required.
|
// so a rewind of the directory may be required.
|
||||||
while ( file.openNext(rdir, O_RDONLY) )
|
while (file.openNext(rdir, O_RDONLY)) {
|
||||||
{
|
|
||||||
file.printFileSize(&Serial);
|
file.printFileSize(&Serial);
|
||||||
Serial.write(' ');
|
Serial.write(' ');
|
||||||
file.printName(&Serial);
|
file.printName(&Serial);
|
||||||
if ( file.isDir() )
|
if (file.isDir()) {
|
||||||
{
|
|
||||||
// Indicate a directory.
|
// Indicate a directory.
|
||||||
Serial.write('/');
|
Serial.write('/');
|
||||||
}
|
}
|
||||||
|
|
@ -165,46 +180,8 @@ void print_rootdir(File32* rdir)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop() {
|
||||||
{
|
// nothing to do
|
||||||
if ( flash_changed )
|
|
||||||
{
|
|
||||||
if (!flash_formatted)
|
|
||||||
{
|
|
||||||
flash_formatted = fatfs.begin(&flash);
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip if still not formatted
|
|
||||||
if (flash_formatted)
|
|
||||||
{
|
|
||||||
File32 root;
|
|
||||||
root = fatfs.open("/");
|
|
||||||
|
|
||||||
Serial.println("Flash contents:");
|
|
||||||
print_rootdir(&root);
|
|
||||||
Serial.println();
|
|
||||||
|
|
||||||
root.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
flash_changed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( sd_changed )
|
|
||||||
{
|
|
||||||
File32 root;
|
|
||||||
root = sd.open("/");
|
|
||||||
|
|
||||||
Serial.println("SD contents:");
|
|
||||||
print_rootdir(&root);
|
|
||||||
Serial.println();
|
|
||||||
|
|
||||||
root.close();
|
|
||||||
|
|
||||||
sd_changed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
delay(1000); // refresh every 1 second
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -212,76 +189,48 @@ void loop()
|
||||||
// SD Card callbacks
|
// SD Card callbacks
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
int32_t sdcard_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
int32_t sdcard_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) {
|
||||||
{
|
bool rc = sd.card()->readSectors(lba, (uint8_t*) buffer, bufsize/512);
|
||||||
bool rc;
|
|
||||||
|
|
||||||
#if SD_FAT_VERSION >= 20000
|
|
||||||
rc = sd.card()->readSectors(lba, (uint8_t*) buffer, bufsize/512);
|
|
||||||
#else
|
|
||||||
rc = sd.card()->readBlocks(lba, (uint8_t*) buffer, bufsize/512);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return rc ? bufsize : -1;
|
return rc ? bufsize : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback invoked when received WRITE10 command.
|
// Callback invoked when received WRITE10 command.
|
||||||
// Process data in buffer to disk's storage and
|
// Process data in buffer to disk's storage and
|
||||||
// return number of written bytes (must be multiple of block size)
|
// return number of written bytes (must be multiple of block size)
|
||||||
int32_t sdcard_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
int32_t sdcard_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize) {
|
||||||
{
|
#ifdef LED_BUILTIN
|
||||||
bool rc;
|
|
||||||
|
|
||||||
digitalWrite(LED_BUILTIN, HIGH);
|
digitalWrite(LED_BUILTIN, HIGH);
|
||||||
|
|
||||||
#if SD_FAT_VERSION >= 20000
|
|
||||||
rc = sd.card()->writeSectors(lba, buffer, bufsize/512);
|
|
||||||
#else
|
|
||||||
rc = sd.card()->writeBlocks(lba, buffer, bufsize/512);
|
|
||||||
#endif
|
#endif
|
||||||
|
bool rc = sd.card()->writeSectors(lba, buffer, bufsize/512);
|
||||||
return rc ? bufsize : -1;
|
return rc ? bufsize : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
||||||
// used to flush any pending cache.
|
// used to flush any pending cache.
|
||||||
void sdcard_flush_cb (void)
|
void sdcard_flush_cb (void) {
|
||||||
{
|
|
||||||
#if SD_FAT_VERSION >= 20000
|
|
||||||
sd.card()->syncDevice();
|
sd.card()->syncDevice();
|
||||||
#else
|
sd.cacheClear(); // clear file system's cache to force refresh
|
||||||
sd.card()->syncBlocks();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// clear file system's cache to force refresh
|
|
||||||
sd.cacheClear();
|
|
||||||
|
|
||||||
sd_changed = true;
|
|
||||||
|
|
||||||
|
#ifdef LED_BUILTIN
|
||||||
digitalWrite(LED_BUILTIN, LOW);
|
digitalWrite(LED_BUILTIN, LOW);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SDCARD_DETECT
|
#ifdef SDCARD_DETECT
|
||||||
// Invoked when received Test Unit Ready command.
|
// Invoked when received Test Unit Ready command.
|
||||||
// return true allowing host to read/write this LUN e.g SD card inserted
|
// return true allowing host to read/write this LUN e.g SD card inserted
|
||||||
bool sdcard_ready_callback(void)
|
bool sdcard_ready_callback(void) {
|
||||||
{
|
|
||||||
// Card is inserted
|
// Card is inserted
|
||||||
if ( digitalRead(SDCARD_DETECT) == HIGH )
|
if (digitalRead(SDCARD_DETECT) == SDCARD_DETECT_ACTIVE) {
|
||||||
{
|
|
||||||
// init SD card if not already
|
// init SD card if not already
|
||||||
if ( !sd_inited )
|
if (!sd_inited) {
|
||||||
{
|
|
||||||
sd_inited = init_sdcard();
|
sd_inited = init_sdcard();
|
||||||
}
|
}
|
||||||
}else
|
} else {
|
||||||
{
|
|
||||||
sd_inited = false;
|
sd_inited = false;
|
||||||
usb_msc.setReadWriteCallback(1, NULL, NULL, NULL);
|
usb_msc.setReadWriteCallback(1, NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial.println(sd_inited);
|
|
||||||
|
|
||||||
return sd_inited;
|
return sd_inited;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -293,8 +242,7 @@ bool sdcard_ready_callback(void)
|
||||||
// Callback invoked when received READ10 command.
|
// Callback invoked when received READ10 command.
|
||||||
// Copy disk's data to buffer (up to bufsize) and
|
// Copy disk's data to buffer (up to bufsize) and
|
||||||
// return number of copied bytes (must be multiple of block size)
|
// return number of copied bytes (must be multiple of block size)
|
||||||
int32_t external_flash_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
int32_t external_flash_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) {
|
||||||
{
|
|
||||||
// Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
|
// Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
|
||||||
// already include 4K sector caching internally. We don't need to cache it, yahhhh!!
|
// already include 4K sector caching internally. We don't need to cache it, yahhhh!!
|
||||||
return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1;
|
return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1;
|
||||||
|
|
@ -303,9 +251,10 @@ int32_t external_flash_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||||
// Callback invoked when received WRITE10 command.
|
// Callback invoked when received WRITE10 command.
|
||||||
// Process data in buffer to disk's storage and
|
// Process data in buffer to disk's storage and
|
||||||
// return number of written bytes (must be multiple of block size)
|
// return number of written bytes (must be multiple of block size)
|
||||||
int32_t external_flash_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
int32_t external_flash_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize) {
|
||||||
{
|
#ifdef LED_BUILTIN
|
||||||
digitalWrite(LED_BUILTIN, HIGH);
|
digitalWrite(LED_BUILTIN, HIGH);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
|
// Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
|
||||||
// already include 4K sector caching internally. We don't need to cache it, yahhhh!!
|
// already include 4K sector caching internally. We don't need to cache it, yahhhh!!
|
||||||
|
|
@ -314,14 +263,9 @@ int32_t external_flash_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize
|
||||||
|
|
||||||
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
||||||
// used to flush any pending cache.
|
// used to flush any pending cache.
|
||||||
void external_flash_flush_cb (void)
|
void external_flash_flush_cb (void) {
|
||||||
{
|
|
||||||
flash.syncBlocks();
|
flash.syncBlocks();
|
||||||
|
#ifdef LED_BUILTIN
|
||||||
// clear file system's cache to force refresh
|
|
||||||
fatfs.cacheClear();
|
|
||||||
|
|
||||||
flash_changed = true;
|
|
||||||
|
|
||||||
digitalWrite(LED_BUILTIN, LOW);
|
digitalWrite(LED_BUILTIN, LOW);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
|
|
||||||
#include "SPI.h"
|
#include "SPI.h"
|
||||||
#include "SdFat.h"
|
#include "SdFat_Adafruit_Fork.h"
|
||||||
#include "Adafruit_InternalFlash.h"
|
#include "Adafruit_InternalFlash.h"
|
||||||
#include "Adafruit_TinyUSB.h"
|
#include "Adafruit_TinyUSB.h"
|
||||||
|
|
||||||
|
|
@ -35,8 +35,9 @@ Adafruit_USBD_MSC usb_msc;
|
||||||
bool fs_changed;
|
bool fs_changed;
|
||||||
|
|
||||||
// the setup function runs once when you press reset or power the board
|
// the setup function runs once when you press reset or power the board
|
||||||
void setup()
|
void setup() {
|
||||||
{
|
Serial.begin(115200);
|
||||||
|
|
||||||
// Initialize internal flash
|
// Initialize internal flash
|
||||||
flash.begin();
|
flash.begin();
|
||||||
|
|
||||||
|
|
@ -46,32 +47,30 @@ void setup()
|
||||||
// Set callback
|
// Set callback
|
||||||
usb_msc.setReadWriteCallback(msc_read_callback, msc_write_callback, msc_flush_callback);
|
usb_msc.setReadWriteCallback(msc_read_callback, msc_write_callback, msc_flush_callback);
|
||||||
usb_msc.setWritableCallback(msc_writable_callback);
|
usb_msc.setWritableCallback(msc_writable_callback);
|
||||||
|
usb_msc.setCapacity(flash.size()/512, 512); // Set disk size, block size should be 512 regardless of flash page size
|
||||||
// Set disk size, block size should be 512 regardless of flash page size
|
usb_msc.setUnitReady(true); // Set Lun ready
|
||||||
usb_msc.setCapacity(flash.size()/512, 512);
|
|
||||||
|
|
||||||
// Set Lun ready
|
|
||||||
usb_msc.setUnitReady(true);
|
|
||||||
|
|
||||||
usb_msc.begin();
|
usb_msc.begin();
|
||||||
|
|
||||||
|
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
|
||||||
|
if (TinyUSBDevice.mounted()) {
|
||||||
|
TinyUSBDevice.detach();
|
||||||
|
delay(10);
|
||||||
|
TinyUSBDevice.attach();
|
||||||
|
}
|
||||||
|
|
||||||
// Init file system on the flash
|
// Init file system on the flash
|
||||||
fatfs.begin(&flash);
|
fatfs.begin(&flash);
|
||||||
|
|
||||||
Serial.begin(115200);
|
|
||||||
//while ( !Serial ) delay(10); // wait for native usb
|
//while ( !Serial ) delay(10); // wait for native usb
|
||||||
|
|
||||||
fs_changed = true; // to print contents initially
|
fs_changed = true; // to print contents initially
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop() {
|
||||||
{
|
if ( fs_changed ) {
|
||||||
if ( fs_changed )
|
|
||||||
{
|
|
||||||
fs_changed = false;
|
fs_changed = false;
|
||||||
|
|
||||||
if ( !root.open("/") )
|
if ( !root.open("/") ) {
|
||||||
{
|
|
||||||
Serial.println("open root failed");
|
Serial.println("open root failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -81,13 +80,11 @@ void loop()
|
||||||
// Open next file in root.
|
// Open next file in root.
|
||||||
// Warning, openNext starts at the current directory position
|
// Warning, openNext starts at the current directory position
|
||||||
// so a rewind of the directory may be required.
|
// so a rewind of the directory may be required.
|
||||||
while ( file.openNext(&root, O_RDONLY) )
|
while ( file.openNext(&root, O_RDONLY) ) {
|
||||||
{
|
|
||||||
file.printFileSize(&Serial);
|
file.printFileSize(&Serial);
|
||||||
Serial.write(' ');
|
Serial.write(' ');
|
||||||
file.printName(&Serial);
|
file.printName(&Serial);
|
||||||
if ( file.isDir() )
|
if ( file.isDir() ) {
|
||||||
{
|
|
||||||
// Indicate a directory.
|
// Indicate a directory.
|
||||||
Serial.write('/');
|
Serial.write('/');
|
||||||
}
|
}
|
||||||
|
|
@ -105,8 +102,7 @@ void loop()
|
||||||
// Callback invoked when received READ10 command.
|
// Callback invoked when received READ10 command.
|
||||||
// Copy disk's data to buffer (up to bufsize) and
|
// Copy disk's data to buffer (up to bufsize) and
|
||||||
// return number of copied bytes (must be multiple of block size)
|
// return number of copied bytes (must be multiple of block size)
|
||||||
int32_t msc_read_callback (uint32_t lba, void* buffer, uint32_t bufsize)
|
int32_t msc_read_callback (uint32_t lba, void* buffer, uint32_t bufsize) {
|
||||||
{
|
|
||||||
// Note: InternalFlash Block API: readBlocks/writeBlocks/syncBlocks
|
// Note: InternalFlash Block API: readBlocks/writeBlocks/syncBlocks
|
||||||
// already include sector caching (if needed). We don't need to cache it, yahhhh!!
|
// already include sector caching (if needed). We don't need to cache it, yahhhh!!
|
||||||
return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1;
|
return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1;
|
||||||
|
|
@ -115,8 +111,7 @@ int32_t msc_read_callback (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||||
// Callback invoked when received WRITE10 command.
|
// Callback invoked when received WRITE10 command.
|
||||||
// Process data in buffer to disk's storage and
|
// Process data in buffer to disk's storage and
|
||||||
// return number of written bytes (must be multiple of block size)
|
// return number of written bytes (must be multiple of block size)
|
||||||
int32_t msc_write_callback (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
int32_t msc_write_callback (uint32_t lba, uint8_t* buffer, uint32_t bufsize) {
|
||||||
{
|
|
||||||
// Note: InternalFlash Block API: readBlocks/writeBlocks/syncBlocks
|
// Note: InternalFlash Block API: readBlocks/writeBlocks/syncBlocks
|
||||||
// already include sector caching (if needed). We don't need to cache it, yahhhh!!
|
// already include sector caching (if needed). We don't need to cache it, yahhhh!!
|
||||||
return flash.writeBlocks(lba, buffer, bufsize/512) ? bufsize : -1;
|
return flash.writeBlocks(lba, buffer, bufsize/512) ? bufsize : -1;
|
||||||
|
|
@ -124,8 +119,7 @@ int32_t msc_write_callback (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
||||||
|
|
||||||
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
||||||
// used to flush any pending cache.
|
// used to flush any pending cache.
|
||||||
void msc_flush_callback (void)
|
void msc_flush_callback (void) {
|
||||||
{
|
|
||||||
// sync with flash
|
// sync with flash
|
||||||
flash.syncBlocks();
|
flash.syncBlocks();
|
||||||
|
|
||||||
|
|
@ -137,8 +131,7 @@ void msc_flush_callback (void)
|
||||||
|
|
||||||
// Invoked to check if device is writable as part of SCSI WRITE10
|
// Invoked to check if device is writable as part of SCSI WRITE10
|
||||||
// Default mode is writable
|
// Default mode is writable
|
||||||
bool msc_writable_callback(void)
|
bool msc_writable_callback(void) {
|
||||||
{
|
|
||||||
// true for writable, false for read-only
|
// true for writable, false for read-only
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
examples/MassStorage/msc_ramdisk/.skip.txt
Normal file
2
examples/MassStorage/msc_ramdisk/.skip.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
feather_esp32_v2
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
// 8KB is the smallest size that windows allow to mount
|
// 8KB is the smallest size that windows allow to mount
|
||||||
#define DISK_BLOCK_NUM 16
|
#define DISK_BLOCK_NUM 16
|
||||||
#define DISK_BLOCK_SIZE 512
|
#define DISK_BLOCK_SIZE 512
|
||||||
|
|
||||||
#include "ramdisk.h"
|
#include "ramdisk.h"
|
||||||
|
|
||||||
Adafruit_USBD_MSC usb_msc;
|
Adafruit_USBD_MSC usb_msc;
|
||||||
|
|
@ -35,12 +36,16 @@ Adafruit_USBD_MSC usb_msc;
|
||||||
|
|
||||||
|
|
||||||
// the setup function runs once when you press reset or power the board
|
// the setup function runs once when you press reset or power the board
|
||||||
void setup()
|
void setup() {
|
||||||
{
|
// Manual begin() is required on core without built-in support e.g. mbed rp2040
|
||||||
#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
|
if (!TinyUSBDevice.isInitialized()) {
|
||||||
// Manual begin() is required on core without built-in support for TinyUSB such as
|
TinyUSBDevice.begin(0);
|
||||||
// - mbed rp2040
|
}
|
||||||
TinyUSB_Device_Init(0);
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
#ifdef BTN_EJECT
|
||||||
|
pinMode(BTN_EJECT, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
|
// Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
|
||||||
|
|
@ -51,33 +56,35 @@ void setup()
|
||||||
|
|
||||||
// Set callback
|
// Set callback
|
||||||
usb_msc.setReadWriteCallback(msc_read_callback, msc_write_callback, msc_flush_callback);
|
usb_msc.setReadWriteCallback(msc_read_callback, msc_write_callback, msc_flush_callback);
|
||||||
|
usb_msc.setStartStopCallback(msc_start_stop_callback);
|
||||||
|
usb_msc.setReadyCallback(msc_ready_callback);
|
||||||
|
|
||||||
// Set Lun ready (RAM disk is always ready)
|
// Set Lun ready (RAM disk is always ready)
|
||||||
usb_msc.setUnitReady(true);
|
usb_msc.setUnitReady(true);
|
||||||
|
|
||||||
#ifdef BTN_EJECT
|
|
||||||
pinMode(BTN_EJECT, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
|
|
||||||
usb_msc.setReadyCallback(msc_ready_callback);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
usb_msc.begin();
|
usb_msc.begin();
|
||||||
|
|
||||||
Serial.begin(115200);
|
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
|
||||||
//while ( !Serial ) delay(10); // wait for native usb
|
if (TinyUSBDevice.mounted()) {
|
||||||
|
TinyUSBDevice.detach();
|
||||||
|
delay(10);
|
||||||
|
TinyUSBDevice.attach();
|
||||||
|
}
|
||||||
|
|
||||||
|
// while ( !Serial ) delay(10); // wait for native usb
|
||||||
Serial.println("Adafruit TinyUSB Mass Storage RAM Disk example");
|
Serial.println("Adafruit TinyUSB Mass Storage RAM Disk example");
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop() {
|
||||||
{
|
#ifdef TINYUSB_NEED_POLLING_TASK
|
||||||
// nothing to do
|
// Manual call tud_task since it isn't called by Core's background
|
||||||
|
TinyUSBDevice.task();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback invoked when received READ10 command.
|
// Callback invoked when received READ10 command.
|
||||||
// Copy disk's data to buffer (up to bufsize) and
|
// Copy disk's data to buffer (up to bufsize) and
|
||||||
// return number of copied bytes (must be multiple of block size)
|
// return number of copied bytes (must be multiple of block size)
|
||||||
int32_t msc_read_callback (uint32_t lba, void* buffer, uint32_t bufsize)
|
int32_t msc_read_callback(uint32_t lba, void* buffer, uint32_t bufsize) {
|
||||||
{
|
|
||||||
uint8_t const* addr = msc_disk[lba];
|
uint8_t const* addr = msc_disk[lba];
|
||||||
memcpy(buffer, addr, bufsize);
|
memcpy(buffer, addr, bufsize);
|
||||||
|
|
||||||
|
|
@ -87,8 +94,7 @@ int32_t msc_read_callback (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||||
// Callback invoked when received WRITE10 command.
|
// Callback invoked when received WRITE10 command.
|
||||||
// Process data in buffer to disk's storage and
|
// Process data in buffer to disk's storage and
|
||||||
// return number of written bytes (must be multiple of block size)
|
// return number of written bytes (must be multiple of block size)
|
||||||
int32_t msc_write_callback (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
int32_t msc_write_callback(uint32_t lba, uint8_t* buffer, uint32_t bufsize) {
|
||||||
{
|
|
||||||
uint8_t* addr = msc_disk[lba];
|
uint8_t* addr = msc_disk[lba];
|
||||||
memcpy(addr, buffer, bufsize);
|
memcpy(addr, buffer, bufsize);
|
||||||
|
|
||||||
|
|
@ -97,18 +103,22 @@ int32_t msc_write_callback (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
||||||
|
|
||||||
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
||||||
// used to flush any pending cache.
|
// used to flush any pending cache.
|
||||||
void msc_flush_callback (void)
|
void msc_flush_callback(void) {
|
||||||
{
|
|
||||||
// nothing to do
|
// nothing to do
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool msc_start_stop_callback(uint8_t power_condition, bool start, bool load_eject) {
|
||||||
|
Serial.printf("Start/Stop callback: power condition %u, start %u, load_eject %u\n", power_condition, start, load_eject);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef BTN_EJECT
|
|
||||||
// Invoked when received Test Unit Ready command.
|
// Invoked when received Test Unit Ready command.
|
||||||
// return true allowing host to read/write this LUN e.g SD card inserted
|
// return true allowing host to read/write this LUN e.g SD card inserted
|
||||||
bool msc_ready_callback(void)
|
bool msc_ready_callback(void) {
|
||||||
{
|
#ifdef BTN_EJECT
|
||||||
// button not active --> medium ready
|
// button not active --> medium ready
|
||||||
return digitalRead(BTN_EJECT) != activeState;
|
return digitalRead(BTN_EJECT) != activeState;
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
|
||||||
3
examples/MassStorage/msc_ramdisk_dual/.skip.txt
Normal file
3
examples/MassStorage/msc_ramdisk_dual/.skip.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
feather_esp32_v2
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
CH32V20x_EVT
|
||||||
|
|
@ -14,17 +14,19 @@
|
||||||
// 8KB is the smallest size that windows allow to mount
|
// 8KB is the smallest size that windows allow to mount
|
||||||
#define DISK_BLOCK_NUM 16
|
#define DISK_BLOCK_NUM 16
|
||||||
#define DISK_BLOCK_SIZE 512
|
#define DISK_BLOCK_SIZE 512
|
||||||
|
|
||||||
#include "ramdisk.h"
|
#include "ramdisk.h"
|
||||||
|
|
||||||
Adafruit_USBD_MSC usb_msc;
|
Adafruit_USBD_MSC usb_msc;
|
||||||
|
|
||||||
// the setup function runs once when you press reset or power the board
|
// the setup function runs once when you press reset or power the board
|
||||||
void setup()
|
void setup() {
|
||||||
{
|
// Manual begin() is required on core without built-in support e.g. mbed rp2040
|
||||||
#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
|
if (!TinyUSBDevice.isInitialized()) {
|
||||||
// Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
|
TinyUSBDevice.begin(0);
|
||||||
TinyUSB_Device_Init(0);
|
}
|
||||||
#endif
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
usb_msc.setMaxLun(2);
|
usb_msc.setMaxLun(2);
|
||||||
|
|
||||||
|
|
@ -42,15 +44,22 @@ void setup()
|
||||||
|
|
||||||
usb_msc.begin();
|
usb_msc.begin();
|
||||||
|
|
||||||
Serial.begin(115200);
|
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
|
||||||
//while ( !Serial ) delay(10); // wait for native usb
|
if (TinyUSBDevice.mounted()) {
|
||||||
|
TinyUSBDevice.detach();
|
||||||
|
delay(10);
|
||||||
|
TinyUSBDevice.attach();
|
||||||
|
}
|
||||||
|
|
||||||
|
//while ( !Serial ) delay(10); // wait for native usb
|
||||||
Serial.println("Adafruit TinyUSB Mass Storage Dual RAM Disks example");
|
Serial.println("Adafruit TinyUSB Mass Storage Dual RAM Disks example");
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop() {
|
||||||
{
|
#ifdef TINYUSB_NEED_POLLING_TASK
|
||||||
// nothing to do
|
// Manual call tud_task since it isn't called by Core's background
|
||||||
|
TinyUSBDevice.task();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -61,8 +70,7 @@ void loop()
|
||||||
// Callback invoked when received READ10 command.
|
// Callback invoked when received READ10 command.
|
||||||
// Copy disk's data to buffer (up to bufsize) and
|
// Copy disk's data to buffer (up to bufsize) and
|
||||||
// return number of copied bytes (must be multiple of block size)
|
// return number of copied bytes (must be multiple of block size)
|
||||||
int32_t ram0_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
int32_t ram0_read_cb(uint32_t lba, void* buffer, uint32_t bufsize) {
|
||||||
{
|
|
||||||
uint8_t const* addr = msc_disk0[lba];
|
uint8_t const* addr = msc_disk0[lba];
|
||||||
memcpy(buffer, addr, bufsize);
|
memcpy(buffer, addr, bufsize);
|
||||||
|
|
||||||
|
|
@ -72,8 +80,7 @@ int32_t ram0_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||||
// Callback invoked when received WRITE10 command.
|
// Callback invoked when received WRITE10 command.
|
||||||
// Process data in buffer to disk's storage and
|
// Process data in buffer to disk's storage and
|
||||||
// return number of written bytes (must be multiple of block size)
|
// return number of written bytes (must be multiple of block size)
|
||||||
int32_t ram0_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
int32_t ram0_write_cb(uint32_t lba, uint8_t* buffer, uint32_t bufsize) {
|
||||||
{
|
|
||||||
uint8_t* addr = msc_disk0[lba];
|
uint8_t* addr = msc_disk0[lba];
|
||||||
memcpy(addr, buffer, bufsize);
|
memcpy(addr, buffer, bufsize);
|
||||||
|
|
||||||
|
|
@ -82,8 +89,7 @@ int32_t ram0_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
||||||
|
|
||||||
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
||||||
// used to flush any pending cache.
|
// used to flush any pending cache.
|
||||||
void ram0_flush_cb (void)
|
void ram0_flush_cb(void) {
|
||||||
{
|
|
||||||
// nothing to do
|
// nothing to do
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,8 +101,7 @@ void ram0_flush_cb (void)
|
||||||
// Callback invoked when received READ10 command.
|
// Callback invoked when received READ10 command.
|
||||||
// Copy disk's data to buffer (up to bufsize) and
|
// Copy disk's data to buffer (up to bufsize) and
|
||||||
// return number of copied bytes (must be multiple of block size)
|
// return number of copied bytes (must be multiple of block size)
|
||||||
int32_t ram1_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
int32_t ram1_read_cb(uint32_t lba, void* buffer, uint32_t bufsize) {
|
||||||
{
|
|
||||||
uint8_t const* addr = msc_disk1[lba];
|
uint8_t const* addr = msc_disk1[lba];
|
||||||
memcpy(buffer, addr, bufsize);
|
memcpy(buffer, addr, bufsize);
|
||||||
|
|
||||||
|
|
@ -106,8 +111,7 @@ int32_t ram1_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||||
// Callback invoked when received WRITE10 command.
|
// Callback invoked when received WRITE10 command.
|
||||||
// Process data in buffer to disk's storage and
|
// Process data in buffer to disk's storage and
|
||||||
// return number of written bytes (must be multiple of block size)
|
// return number of written bytes (must be multiple of block size)
|
||||||
int32_t ram1_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
int32_t ram1_write_cb(uint32_t lba, uint8_t* buffer, uint32_t bufsize) {
|
||||||
{
|
|
||||||
uint8_t* addr = msc_disk1[lba];
|
uint8_t* addr = msc_disk1[lba];
|
||||||
memcpy(addr, buffer, bufsize);
|
memcpy(addr, buffer, bufsize);
|
||||||
|
|
||||||
|
|
@ -116,7 +120,6 @@ int32_t ram1_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
||||||
|
|
||||||
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
||||||
// used to flush any pending cache.
|
// used to flush any pending cache.
|
||||||
void ram1_flush_cb (void)
|
void ram1_flush_cb(void) {
|
||||||
{
|
|
||||||
// nothing to do
|
// nothing to do
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
examples/MassStorage/msc_sd/.skip.txt
Normal file
10
examples/MassStorage/msc_sd/.skip.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
feather_esp32_v2
|
||||||
|
feather_esp32s2
|
||||||
|
feather_esp32s3
|
||||||
|
funhouse
|
||||||
|
magtag
|
||||||
|
metroesp32s2
|
||||||
|
esp32p4
|
||||||
|
feather_rp2040_tinyusb
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
CH32V20x_EVT
|
||||||
|
|
@ -26,6 +26,8 @@ SdVolume volume;
|
||||||
// the setup function runs once when you press reset or power the board
|
// the setup function runs once when you press reset or power the board
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
// Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
|
// Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
|
||||||
usb_msc.setID("Adafruit", "SD Card", "1.0");
|
usb_msc.setID("Adafruit", "SD Card", "1.0");
|
||||||
|
|
||||||
|
|
@ -37,15 +39,18 @@ void setup()
|
||||||
usb_msc.setUnitReady(false);
|
usb_msc.setUnitReady(false);
|
||||||
usb_msc.begin();
|
usb_msc.begin();
|
||||||
|
|
||||||
Serial.begin(115200);
|
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
|
||||||
|
if (TinyUSBDevice.mounted()) {
|
||||||
|
TinyUSBDevice.detach();
|
||||||
|
delay(10);
|
||||||
|
TinyUSBDevice.attach();
|
||||||
|
}
|
||||||
|
|
||||||
//while ( !Serial ) delay(10); // wait for native usb
|
//while ( !Serial ) delay(10); // wait for native usb
|
||||||
|
|
||||||
Serial.println("Adafruit TinyUSB Mass Storage SD Card example");
|
Serial.println("Adafruit TinyUSB Mass Storage SD Card example");
|
||||||
|
|
||||||
Serial.println("\nInitializing SD card...");
|
Serial.println("\nInitializing SD card...");
|
||||||
|
|
||||||
if ( !card.init(SPI_HALF_SPEED, chipSelect) )
|
if ( !card.init(SPI_HALF_SPEED, chipSelect) ) {
|
||||||
{
|
|
||||||
Serial.println("initialization failed. Things to check:");
|
Serial.println("initialization failed. Things to check:");
|
||||||
Serial.println("* is a card inserted?");
|
Serial.println("* is a card inserted?");
|
||||||
Serial.println("* is your wiring correct?");
|
Serial.println("* is your wiring correct?");
|
||||||
|
|
@ -71,16 +76,14 @@ void setup()
|
||||||
usb_msc.setUnitReady(true);
|
usb_msc.setUnitReady(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop() {
|
||||||
{
|
|
||||||
// nothing to do
|
// nothing to do
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback invoked when received READ10 command.
|
// Callback invoked when received READ10 command.
|
||||||
// Copy disk's data to buffer (up to bufsize) and
|
// Copy disk's data to buffer (up to bufsize) and
|
||||||
// return number of copied bytes (must be multiple of block size)
|
// return number of copied bytes (must be multiple of block size)
|
||||||
int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) {
|
||||||
{
|
|
||||||
(void) bufsize;
|
(void) bufsize;
|
||||||
return card.readBlock(lba, (uint8_t*) buffer) ? 512 : -1;
|
return card.readBlock(lba, (uint8_t*) buffer) ? 512 : -1;
|
||||||
}
|
}
|
||||||
|
|
@ -88,15 +91,13 @@ int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||||
// Callback invoked when received WRITE10 command.
|
// Callback invoked when received WRITE10 command.
|
||||||
// Process data in buffer to disk's storage and
|
// Process data in buffer to disk's storage and
|
||||||
// return number of written bytes (must be multiple of block size)
|
// return number of written bytes (must be multiple of block size)
|
||||||
int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize) {
|
||||||
{
|
|
||||||
(void) bufsize;
|
(void) bufsize;
|
||||||
return card.writeBlock(lba, buffer) ? 512 : -1;
|
return card.writeBlock(lba, buffer) ? 512 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
||||||
// used to flush any pending cache.
|
// used to flush any pending cache.
|
||||||
void msc_flush_cb (void)
|
void msc_flush_cb (void) {
|
||||||
{
|
|
||||||
// nothing to do
|
// nothing to do
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
examples/MassStorage/msc_sdfat/.skip.txt
Normal file
2
examples/MassStorage/msc_sdfat/.skip.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
feather_esp32_v2
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
|
@ -10,31 +10,69 @@
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
|
|
||||||
/* This example expose SD card as mass storage using
|
/* This example expose SD card as mass storage using
|
||||||
* SdFat Library
|
* - SdFat https://github.com/adafruit/SdFat
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "SPI.h"
|
#include "SPI.h"
|
||||||
#include "SdFat.h"
|
#include "SdFat_Adafruit_Fork.h"
|
||||||
#include "Adafruit_TinyUSB.h"
|
#include "Adafruit_TinyUSB.h"
|
||||||
|
|
||||||
const int chipSelect = 10;
|
//--------------------------------------------------------------------+
|
||||||
|
// SDCard Config
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
#if defined(ARDUINO_PYPORTAL_M4) || defined(ARDUINO_PYPORTAL_M4_TITANO)
|
||||||
|
// PyPortal has on-board card reader
|
||||||
|
#define SDCARD_CS 32
|
||||||
|
#define SDCARD_DETECT 33
|
||||||
|
#define SDCARD_DETECT_ACTIVE HIGH
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ADAFRUIT_METRO_RP2040)
|
||||||
|
#define SDIO_CLK_PIN 18
|
||||||
|
#define SDIO_CMD_PIN 19 // MOSI
|
||||||
|
#define SDIO_DAT0_PIN 20 // DAT1: 21, DAT2: 22, DAT3: 23
|
||||||
|
|
||||||
|
#define SDCARD_DETECT 15
|
||||||
|
#define SDCARD_DETECT_ACTIVE LOW
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ADAFRUIT_METRO_RP2350)
|
||||||
|
#define SDIO_CLK_PIN 34
|
||||||
|
#define SDIO_CMD_PIN 35 // MOSI
|
||||||
|
#define SDIO_DAT0_PIN 36 // DAT1: 37, DAT2: 38, DAT3: 39
|
||||||
|
|
||||||
|
#define SDCARD_DETECT 40
|
||||||
|
#define SDCARD_DETECT_ACTIVE LOW
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ADAFRUIT_FRUITJAM_RP2350)
|
||||||
|
#define SDIO_CLK_PIN 34
|
||||||
|
#define SDIO_CMD_PIN 35 // MOSI
|
||||||
|
#define SDIO_DAT0_PIN 36 // DAT1: 37, DAT2: 38, DAT3: 39
|
||||||
|
|
||||||
|
#define SDCARD_DETECT 33
|
||||||
|
#define SDCARD_DETECT_ACTIVE LOW
|
||||||
|
|
||||||
|
#else
|
||||||
|
// Use SPI, no detect
|
||||||
|
#define SDCARD_CS 10
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(SDIO_CLK_PIN) && defined(SDIO_CMD_PIN) && defined(SDIO_DAT0_PIN)
|
||||||
|
#define SD_CONFIG SdioConfig(SDIO_CLK_PIN, SDIO_CMD_PIN, SDIO_DAT0_PIN)
|
||||||
|
#else
|
||||||
|
#define SD_CONFIG SdSpiConfig(SDCARD_CS, SHARED_SPI, SD_SCK_MHZ(50))
|
||||||
|
#endif
|
||||||
|
|
||||||
// File system on SD Card
|
// File system on SD Card
|
||||||
SdFat sd;
|
SdFat sd;
|
||||||
|
|
||||||
SdFile root;
|
|
||||||
SdFile file;
|
|
||||||
|
|
||||||
// USB Mass Storage object
|
// USB Mass Storage object
|
||||||
Adafruit_USBD_MSC usb_msc;
|
Adafruit_USBD_MSC usb_msc;
|
||||||
|
|
||||||
// Set to true when PC write to flash
|
|
||||||
bool fs_changed;
|
|
||||||
|
|
||||||
// the setup function runs once when you press reset or power the board
|
// the setup function runs once when you press reset or power the board
|
||||||
void setup()
|
void setup() {
|
||||||
{
|
#ifdef LED_BUILTIN
|
||||||
pinMode(LED_BUILTIN, OUTPUT);
|
pinMode(LED_BUILTIN, OUTPUT);
|
||||||
|
#endif
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
// Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
|
// Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
|
||||||
usb_msc.setID("Adafruit", "SD Card", "1.0");
|
usb_msc.setID("Adafruit", "SD Card", "1.0");
|
||||||
|
|
@ -47,30 +85,27 @@ void setup()
|
||||||
usb_msc.setUnitReady(false);
|
usb_msc.setUnitReady(false);
|
||||||
usb_msc.begin();
|
usb_msc.begin();
|
||||||
|
|
||||||
Serial.begin(115200);
|
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
|
||||||
|
if (TinyUSBDevice.mounted()) {
|
||||||
|
TinyUSBDevice.detach();
|
||||||
|
delay(10);
|
||||||
|
TinyUSBDevice.attach();
|
||||||
|
}
|
||||||
|
|
||||||
//while ( !Serial ) delay(10); // wait for native usb
|
//while ( !Serial ) delay(10); // wait for native usb
|
||||||
|
|
||||||
Serial.println("Adafruit TinyUSB Mass Storage SD Card example");
|
Serial.println("Adafruit TinyUSB Mass Storage SD Card example");
|
||||||
|
|
||||||
Serial.print("\nInitializing SD card ... ");
|
Serial.print("\nInitializing SD card ... ");
|
||||||
Serial.print("CS = "); Serial.println(chipSelect);
|
|
||||||
|
|
||||||
if ( !sd.begin(chipSelect, SD_SCK_MHZ(50)) )
|
if (!sd.begin(SD_CONFIG)) {
|
||||||
{
|
|
||||||
Serial.println("initialization failed. Things to check:");
|
Serial.println("initialization failed. Things to check:");
|
||||||
Serial.println("* is a card inserted?");
|
Serial.println("- is a card inserted?");
|
||||||
Serial.println("* is your wiring correct?");
|
Serial.println("- is your wiring correct?");
|
||||||
Serial.println("* did you change the chipSelect pin to match your shield or module?");
|
Serial.println("- did you change the SDCARD_CS or SDIO pin to match your shield or module?");
|
||||||
while (1) delay(1);
|
while (1) delay(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size in blocks (512 bytes)
|
// Size in blocks (512 bytes)
|
||||||
#if SD_FAT_VERSION >= 20000
|
|
||||||
uint32_t block_count = sd.card()->sectorCount();
|
uint32_t block_count = sd.card()->sectorCount();
|
||||||
#else
|
|
||||||
uint32_t block_count = sd.card()->cardSize();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Serial.print("Volume size (MB): ");
|
Serial.print("Volume size (MB): ");
|
||||||
Serial.println((block_count/2) / 1024);
|
Serial.println((block_count/2) / 1024);
|
||||||
|
|
||||||
|
|
@ -79,91 +114,38 @@ void setup()
|
||||||
|
|
||||||
// MSC is ready for read/write
|
// MSC is ready for read/write
|
||||||
usb_msc.setUnitReady(true);
|
usb_msc.setUnitReady(true);
|
||||||
|
|
||||||
fs_changed = true; // to print contents initially
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop() {
|
||||||
{
|
// noting to do
|
||||||
if ( fs_changed )
|
|
||||||
{
|
|
||||||
root.open("/");
|
|
||||||
Serial.println("SD contents:");
|
|
||||||
|
|
||||||
// Open next file in root.
|
|
||||||
// Warning, openNext starts at the current directory position
|
|
||||||
// so a rewind of the directory may be required.
|
|
||||||
while ( file.openNext(&root, O_RDONLY) )
|
|
||||||
{
|
|
||||||
file.printFileSize(&Serial);
|
|
||||||
Serial.write(' ');
|
|
||||||
file.printName(&Serial);
|
|
||||||
if ( file.isDir() )
|
|
||||||
{
|
|
||||||
// Indicate a directory.
|
|
||||||
Serial.write('/');
|
|
||||||
}
|
|
||||||
Serial.println();
|
|
||||||
file.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
root.close();
|
|
||||||
|
|
||||||
Serial.println();
|
|
||||||
|
|
||||||
fs_changed = false;
|
|
||||||
delay(1000); // refresh every 0.5 second
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback invoked when received READ10 command.
|
// Callback invoked when received READ10 command.
|
||||||
// Copy disk's data to buffer (up to bufsize) and
|
// Copy disk's data to buffer (up to bufsize) and
|
||||||
// return number of copied bytes (must be multiple of block size)
|
// return number of copied bytes (must be multiple of block size)
|
||||||
int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) {
|
||||||
{
|
bool rc = sd.card()->readSectors(lba, (uint8_t*) buffer, bufsize/512);
|
||||||
bool rc;
|
|
||||||
|
|
||||||
#if SD_FAT_VERSION >= 20000
|
|
||||||
rc = sd.card()->readSectors(lba, (uint8_t*) buffer, bufsize/512);
|
|
||||||
#else
|
|
||||||
rc = sd.card()->readBlocks(lba, (uint8_t*) buffer, bufsize/512);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return rc ? bufsize : -1;
|
return rc ? bufsize : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback invoked when received WRITE10 command.
|
// Callback invoked when received WRITE10 command.
|
||||||
// Process data in buffer to disk's storage and
|
// Process data in buffer to disk's storage and
|
||||||
// return number of written bytes (must be multiple of block size)
|
// return number of written bytes (must be multiple of block size)
|
||||||
int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize) {
|
||||||
{
|
#ifdef LED_BUILTIN
|
||||||
bool rc;
|
|
||||||
|
|
||||||
digitalWrite(LED_BUILTIN, HIGH);
|
digitalWrite(LED_BUILTIN, HIGH);
|
||||||
|
|
||||||
#if SD_FAT_VERSION >= 20000
|
|
||||||
rc = sd.card()->writeSectors(lba, buffer, bufsize/512);
|
|
||||||
#else
|
|
||||||
rc = sd.card()->writeBlocks(lba, buffer, bufsize/512);
|
|
||||||
#endif
|
#endif
|
||||||
|
bool rc = sd.card()->writeSectors(lba, buffer, bufsize/512);
|
||||||
return rc ? bufsize : -1;
|
return rc ? bufsize : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
||||||
// used to flush any pending cache.
|
// used to flush any pending cache.
|
||||||
void msc_flush_cb (void)
|
void msc_flush_cb (void) {
|
||||||
{
|
|
||||||
#if SD_FAT_VERSION >= 20000
|
|
||||||
sd.card()->syncDevice();
|
sd.card()->syncDevice();
|
||||||
#else
|
sd.cacheClear(); // clear file system's cache to force refresh
|
||||||
sd.card()->syncBlocks();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// clear file system's cache to force refresh
|
|
||||||
sd.cacheClear();
|
|
||||||
|
|
||||||
fs_changed = true;
|
|
||||||
|
|
||||||
|
#ifdef LED_BUILTIN
|
||||||
digitalWrite(LED_BUILTIN, LOW);
|
digitalWrite(LED_BUILTIN, LOW);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
||||||
3
examples/Vendor/i2c_tiny_usb_adapter/.skip.txt
vendored
Normal file
3
examples/Vendor/i2c_tiny_usb_adapter/.skip.txt
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
feather_esp32_v2
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
CH32V20x_EVT
|
||||||
|
|
@ -64,15 +64,29 @@ Adafruit_USBD_I2C::Adafruit_USBD_I2C(TwoWire* wire) {
|
||||||
setStringDescriptor("I2C Interface");
|
setStringDescriptor("I2C Interface");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t Adafruit_USBD_I2C::getInterfaceDescriptor(uint8_t itfnum, uint8_t* buf, uint16_t bufsize) {
|
uint16_t Adafruit_USBD_I2C::getInterfaceDescriptor(uint8_t itfnum_deprecated, uint8_t* buf, uint16_t bufsize) {
|
||||||
uint8_t desc[] = { TUD_VENDOR_DESCRIPTOR(itfnum, 0, 0x00, 0x80, 64) };
|
uint8_t itfnum = 0;
|
||||||
|
uint8_t ep_in = 0;
|
||||||
|
uint8_t ep_out = 0;
|
||||||
|
(void) itfnum_deprecated;
|
||||||
|
|
||||||
|
// null buffer is used to get the length of descriptor only
|
||||||
|
if (buf) {
|
||||||
|
itfnum = TinyUSBDevice.allocInterface(1);
|
||||||
|
ep_in = TinyUSBDevice.allocEndpoint(TUSB_DIR_IN);
|
||||||
|
ep_out = TinyUSBDevice.allocEndpoint(TUSB_DIR_OUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t const desc[] = { TUD_VENDOR_DESCRIPTOR(itfnum, _strid, ep_out, ep_in, 64) };
|
||||||
uint16_t const len = sizeof(desc);
|
uint16_t const len = sizeof(desc);
|
||||||
|
|
||||||
if (buf) {
|
if (buf) {
|
||||||
if (bufsize < len) {
|
if (bufsize < len) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
memcpy(buf, desc, len);
|
memcpy(buf, desc, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,11 +88,13 @@
|
||||||
class Adafruit_USBD_I2C : public Adafruit_USBD_Interface {
|
class Adafruit_USBD_I2C : public Adafruit_USBD_Interface {
|
||||||
public:
|
public:
|
||||||
Adafruit_USBD_I2C(TwoWire* wire);
|
Adafruit_USBD_I2C(TwoWire* wire);
|
||||||
uint16_t getInterfaceDescriptor(uint8_t itfnum, uint8_t* buf, uint16_t bufsize);
|
|
||||||
bool begin(uint8_t* buffer, size_t bufsize);
|
bool begin(uint8_t* buffer, size_t bufsize);
|
||||||
|
|
||||||
bool handleControlTransfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request);
|
bool handleControlTransfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request);
|
||||||
|
|
||||||
|
// from Adafruit_USBD_Interface
|
||||||
|
virtual uint16_t getInterfaceDescriptor(uint8_t itfnum, uint8_t* buf, uint16_t bufsize);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TwoWire* _wire;
|
TwoWire* _wire;
|
||||||
uint8_t _state;
|
uint8_t _state;
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,13 @@ void setup() {
|
||||||
|
|
||||||
// init i2c usb with buffer and size
|
// init i2c usb with buffer and size
|
||||||
i2c_usb.begin(i2c_buf, sizeof(i2c_buf));
|
i2c_usb.begin(i2c_buf, sizeof(i2c_buf));
|
||||||
|
|
||||||
|
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
|
||||||
|
if (TinyUSBDevice.mounted()) {
|
||||||
|
TinyUSBDevice.detach();
|
||||||
|
delay(10);
|
||||||
|
TinyUSBDevice.attach();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
|
|
|
||||||
3
examples/Video/video_capture/.skip.txt
Normal file
3
examples/Video/video_capture/.skip.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
feather_esp32_v2
|
||||||
|
pico_rp2040_tinyusb_host
|
||||||
|
CH32V20x_EVT
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue