Compare commits

..

170 Commits

Author SHA1 Message Date
7d3f49940f Update esptool for Big Sur 2020-12-07 10:17:52 +02:00
9bc8420e2f Update boards.txt 2020-12-01 18:00:24 +02:00
c1b06cc120 Fix possible race condition in uart attach (#4569) 2020-12-01 16:36:44 +02:00
93c6226177 Separate Provisioning library from WiFi library to avoid unnecessary compilation while using WiFi library (#4550) 2020-11-19 00:13:14 +02:00
b5651491e5 Ignore mklittlefs 2020-11-18 19:11:42 +02:00
a25ccb2ef7 Fix Wire.begin causing divide by zero
Fixes: https://github.com/espressif/arduino-esp32/issues/4530
2020-11-17 02:30:12 +02:00
5b5b61c018 rework persist reboot 2020-11-17 02:04:56 +02:00
cbafe67ee1 Fix PSRAM on S2 2020-11-17 01:13:23 +02:00
e0f8b845fb Merge branch 'master' into idf-release/v4.2 2020-11-15 21:47:59 +02:00
1eb2c6d3dc Merge pull request #4542 from lbernstone/adc_vref
Fix deprecated vref function
2020-11-15 21:31:36 +02:00
564733137a Merge pull request #4541 from lbernstone/SD_MMC_v4.2
Updated SD_MMC init to match changes upstream
2020-11-15 21:31:12 +02:00
e5555c72e5 Fix deprecated vref function 2020-11-15 12:16:02 -07:00
104d28bd9c Merge pull request #4540 from loick111/feature/custom_variants_dir_idf4.2
Allow custom variants directory
2020-11-15 21:10:52 +02:00
934553d290 Updated SD_MMC init to match changes upstream 2020-11-15 12:00:55 -07:00
f7fe024744 Allow custom variants directory 2020-11-15 19:56:05 +01:00
29e3b640a8 Update IDF to 494a124d9 2020-11-15 12:25:38 +02:00
91025f8515 Merge branch 'master' into idf-release/v4.2 2020-11-15 12:04:09 +02:00
a2e0e865dd Provisioning Fixes (#4522) 2020-11-12 14:31:59 +02:00
9debb9fc76 Merge branch 'master' into idf-release/v4.2 2020-11-10 20:52:25 +02:00
5d62ba56f6 Idf release/v4.2 - corrections of LITTLEFS and tools (#4515)
* Update package_esp32_index.template.json

Fix of wrong file type

* Update LITTLEFS.cpp

Suppress warnings fix.
2020-11-10 10:19:34 +02:00
2d0e772674 add 2 variants (#4514)
* add variants

* add boards
2020-11-10 10:18:42 +02:00
2063a606e9 Merge branch 'master' into idf-release/v4.2 2020-11-09 17:08:38 +02:00
ca6405658a Merge branch 'master' into idf-release/v4.2 2020-11-06 22:28:28 +02:00
70bd58b00b Update Arduino.h 2020-11-06 22:07:24 +02:00
f1cbd3b74b Create esp_arduino_version.h 2020-11-06 22:02:40 +02:00
e55d657e9f Try to free some memory 2020-11-06 15:45:10 +02:00
ef5c73f1ed Merge branch 'master' into idf-release/v4.2 2020-11-06 14:17:30 +02:00
591c43880a RE: Change check for BT_ENABLE to really be a check for BLUEDROID_ENABLED (#4497)
* Change check for CONFIG_BT_ENABLE to really be a check for CONFIG_BLUEDROID_ENABLED

Which is really what should have been tested.  This allows use of
the Arduino layer with the newer Nimble stack for those that don't want
to use Bluedroid.

In support of https://github.com/meshtastic/Meshtastic-device/issues/266

* Change check for CONFIG_BT_ENABLE to really be a check for CONFIG_BLUEDROID_ENABLED

Which is really what should have been tested.  This allows use of
the Arduino layer with the newer Nimble stack for those that don't want
to use Bluedroid.

In support of https://github.com/meshtastic/Meshtastic-device/issues/266

* wifi prov changes

* merge fixes

Co-authored-by: geeksville <kevinh@geeksville.com>
2020-11-06 14:00:06 +02:00
8767419289 Merge branch 'master' into idf-release/v4.2 2020-11-06 13:27:35 +02:00
78783c5183 fix psram init 2020-11-06 12:20:20 +02:00
1bb7abe271 Make setHostname return true 2020-11-05 20:37:07 +02:00
ec5ec746d9 skip bt tests for esp32s2 2020-11-04 04:08:22 +02:00
a4aaec6a23 Merge branch 'master' into idf-release/v4.2 2020-11-04 02:31:29 +02:00
976aca4781 more fixes 2020-11-04 02:31:08 +02:00
72c25f2fdb Update WiFiProv.ino 2020-11-04 02:21:38 +02:00
a07f3c16a5 Add missing config 2020-11-04 02:16:30 +02:00
37af4c9d2f more fixes 2020-11-04 01:53:38 +02:00
5e3189f2f1 fix some merge errors 2020-11-04 01:33:52 +02:00
b76c95206c Adding LITTLEFS after esp_littlefs (IDF) is built-in (#4483)
Tools idea: https://github.com/lorol/arduino-esp32fs-plugin
2020-11-04 01:20:58 +02:00
8ae5be5659 Add esp-rainmaker support for ESP32 2020-11-04 01:19:31 +02:00
6ffe081fd2 Update IDF master to 357a27760 2020-11-04 01:19:29 +02:00
2d0b8c7e81 Update IDF and Camera 2020-11-04 01:19:07 +02:00
9a37a020d2 Fix Arduino PIN counts 2020-11-04 01:19:05 +02:00
cf93d473fb Make esp32-hal-tinyusb.h conditional on tinyusb (#4155) 2020-11-04 01:19:05 +02:00
659e9a51dd Update IDF and Tools 2020-11-04 01:19:01 +02:00
8900e8fca9 Update .gitignore 2020-11-04 01:18:31 +02:00
064aa692f9 Update platform.txt 2020-11-04 01:18:31 +02:00
57c96aa4e3 Add camera support
first automated cmake build
2020-11-04 01:18:31 +02:00
f8b72db3c6 Try with speed optimization as opposed to debug. Coremark 240 -> 430 2020-11-04 01:18:28 +02:00
100001389b Added ESP32-Wrover-Kit with distinct build.board (#4118)
* Added ESP32-Wrover-Kit with distinct build.board

* Fixed broken values

* Update boards.txt

Co-authored-by: Me No Dev <me-no-dev@users.noreply.github.com>
2020-11-04 01:18:27 +02:00
8c85642b04 Add board microS2 (#4314) 2020-11-04 01:16:22 +02:00
bae722f1c1 Makes ethernet get an IP when connected (#4234) 2020-11-04 01:16:22 +02:00
fa852c955f Update WiFiMulti.cpp (#4099)
Fix for https://github.com/espressif/arduino-esp32/issues/3914 by syncing with https://github.com/espressif/arduino-esp32/blob/esp32s2/libraries/WiFi/src/WiFiSTA.cpp#L161
2020-11-04 01:16:22 +02:00
1ded874ce1 Update USB.cpp 2020-11-04 01:16:22 +02:00
470cbedd8a Update boards.txt 2020-11-04 01:16:22 +02:00
7f2bf4e401 Update platform.txt 2020-11-04 01:16:22 +02:00
ad07421931 Update install-platformio-esp32.sh 2020-11-04 01:16:22 +02:00
537384da7d Update platform.txt
Provided by @ESP32DE
2020-11-04 01:16:22 +02:00
394c32ddfc Update IDF, tools and toolchains 2020-11-04 01:16:17 +02:00
86c87aaeee Some fixes 2020-11-04 01:15:33 +02:00
0ac788f666 Add option to select the core used for Arduino and it's events 2020-11-04 01:15:32 +02:00
e25ef9e6d0 Update CMakeLists.txt 2020-11-04 01:15:32 +02:00
9e2b2bff70 Update HardwareSerial.h 2020-11-04 01:14:42 +02:00
17581ec74d Added UM FeatherS2 and UM ProS2 boards to boards.txt (#4188)
* Added UM FeatherS2 and UM ProS2 boards to boards.txt
Updated the name of TinyPICO to UM TinyPICO in boards.txt

* Added VID/PID/Product names for TinyPICO, ProS2 & FeatherS2
Setup variant folders for each board

* Removed unneeded stuff from FeatherS2 & ProS2 menu options

* Added Serial CDC output default for FeatherS2 and ProS2

* Removed unneeded stuff from FeatherS2 & ProS2 menu options

* Rebase from upstream and fixed Serial Output settings for FeatherS2 and ProS2

Co-authored-by: Seon Rozenblum <seonr@3sprockets.com>
2020-11-04 01:14:41 +02:00
31ab456a3a Update CMakeLists.txt 2020-11-04 01:11:29 +02:00
681b1214cf Improve CDC Logging support 2020-11-04 01:11:29 +02:00
d777949bf5 Create USB_NOT.h 2020-11-04 01:11:28 +02:00
1a7a928b64 Add option USB CDC to be used for Serial (starting USB early) 2020-11-04 01:11:28 +02:00
4967f19513 Add support for custom VID/PID and Board name to show in ArduinoIDE ports list 2020-11-04 01:11:28 +02:00
2a94977f60 Update tinyusb 2020-11-04 01:11:28 +02:00
e325872f4e Update USB.cpp 2020-11-04 01:11:28 +02:00
e687951c0f Some CDC and BTSerial compatibility fixes 2020-11-04 01:11:28 +02:00
8cc9e955dc Add debug output to CDC 2020-11-04 01:11:28 +02:00
29e3d0e75f Handle persistent reboot better in CDC 2020-11-04 01:11:28 +02:00
7f54a357a4 Change driver attach api and remove DFU from CDC 2020-11-04 01:11:28 +02:00
c9ae74f012 Update TinyUSB 2020-11-04 01:11:27 +02:00
c6c3be12b9 Update USBCDC.cpp 2020-11-04 01:11:27 +02:00
e9f1b5e838 Update libtinyusb.a 2020-11-04 01:11:27 +02:00
ec7a51b263 Fix compilation issues 2020-11-04 01:11:27 +02:00
6cd0d7c3db Fix DTR/RTS state for ESP32S2 native USB 2020-11-04 01:11:27 +02:00
1879a5c93d Update CMakeLists.txt 2020-11-04 01:11:27 +02:00
1b67e41c82 Add files to cmakelists and disconnect CDC if unplugged 2020-11-04 01:11:27 +02:00
f43352b752 Add TinyUSB HAL and CDC 2020-11-04 01:10:37 +02:00
47b34df897 Update IDF Libs 2020-11-04 01:10:37 +02:00
7611f483ae Update TinyUSB Lib 2020-11-04 01:10:35 +02:00
1e48761177 Fix GPIO Interrupts 2020-11-04 01:10:35 +02:00
06125d22e1 Fixing static IP configuration so it doesn't get overwritten by DHCP as part of WiFi.begin(). (#4103)
Fixing DHCP client stop if WiFi.config() is called before WiFi.begin() (as done in WiFiClientStaticIP.ino)
2020-11-04 01:10:35 +02:00
cf713a88c8 Update libtinyusb.a 2020-11-04 01:10:35 +02:00
e094e19f17 Add missing DFU driver 2020-11-04 01:10:35 +02:00
0df54ea169 Try custom device descriptors 2020-11-04 01:10:34 +02:00
93c97aac1c again 2020-11-04 01:10:34 +02:00
232ab09694 change endpoints 2020-11-04 01:10:33 +02:00
146878768c TinyUSB adjust 2020-11-04 01:10:32 +02:00
1f53f28481 Update pins_arduino.h 2020-11-04 01:10:32 +02:00
5a2580db7e Fix swapped USB pins issue 2020-11-04 01:10:32 +02:00
298a6f8910 Update CMakeLists.txt 2020-11-04 01:10:31 +02:00
eda687069a what happened to no-stub? 2020-11-04 01:09:00 +02:00
9612ac89b7 how about now? 2020-11-04 01:09:00 +02:00
c32a9be28b what if functions are in the core? 2020-11-04 01:08:59 +02:00
832edd2c63 try to fix linking errors 2020-11-04 01:08:58 +02:00
908ee03db4 hopefully all is here now 2020-11-04 01:08:57 +02:00
76637cbd5b Once again 2020-11-04 01:08:56 +02:00
f2e1016ea5 Update TinyUSB 2020-11-04 01:08:55 +02:00
8ac2a69553 Add support for no-stub usb s2 flashing 2020-11-04 01:08:54 +02:00
5dbcf201b8 Pull latest IDF and enable TinyUSB 2020-11-04 01:07:49 +02:00
604abf0a96 Disable modem sleep by default on S2 for now. 2020-11-04 01:07:47 +02:00
dc707a3121 add psram to malloc only if interrupts are not in IRAM 2020-11-04 01:07:21 +02:00
b499befa9b fix psram always init 2020-11-04 01:07:21 +02:00
895fba0ded fix issue with rtc wdt 2020-11-04 01:07:20 +02:00
67e7706728 update idf libs, disable WDT on S2, use malloc for PSRAM 2020-11-04 01:07:19 +02:00
99b5be0037 Disable IRAM ISRs and functions by default 2020-11-04 01:07:18 +02:00
3397208d12 Update esp32-hal-gpio.c 2020-11-04 01:06:45 +02:00
131c87b127 Update main.cpp 2020-11-04 01:06:45 +02:00
87c9a8a8fa some i2c fixes 2020-11-04 01:06:44 +02:00
90e77cdaaf Update WPS.ino 2020-11-04 01:06:44 +02:00
59264b0254 Update WiFiProv.ino 2020-11-04 01:06:44 +02:00
d1e7aefed7 Update WiFiBlueToothSwitch.ino 2020-11-04 01:06:08 +02:00
ae27682601 Update WiFiClientEvents.ino 2020-11-04 01:06:08 +02:00
dd64404823 more example fixes 2020-11-04 01:06:08 +02:00
146c493b30 fix wrong bootloader path in pio scripts 2020-11-04 01:06:08 +02:00
1f204676e6 fix some examples 2020-11-04 01:06:08 +02:00
ecc96060da fix WiFi 2020-11-04 01:04:59 +02:00
a761281d8c Fix PSRAM support 2020-11-04 00:57:18 +02:00
5abe013f78 Update esp32-hal-uart.c 2020-11-04 00:57:18 +02:00
92aa3b5e14 Update esp32-hal-uart.c 2020-11-04 00:57:18 +02:00
61132a7172 Fix Serial 2020-11-04 00:57:18 +02:00
4b9f70236f Update HardwareSerial.cpp 2020-11-04 00:56:45 +02:00
ce64a26ce3 Add I2C IDF Wrapper 2020-11-04 00:56:45 +02:00
77015e05be fix compile errors for esp32 2020-11-04 00:56:45 +02:00
0c5f0f8bf8 fix peripherals 2020-11-04 00:56:45 +02:00
3f89e22174 Update on-push.sh 2020-11-04 00:56:45 +02:00
986b2a2699 Update install-platformio-esp32.sh 2020-11-04 00:56:45 +02:00
55eca6830d fix py script 2020-11-04 00:56:45 +02:00
39c1de2e6d new try at pio 2020-11-04 00:56:45 +02:00
703ce7ed14 does not work 2020-11-04 00:56:44 +02:00
df0c8aedda how about now? 2020-11-04 00:56:44 +02:00
40665eaf3a try outputing the map 2020-11-04 00:56:44 +02:00
bac6aece9e Update on-push.sh 2020-11-04 00:56:44 +02:00
f6d705f577 Update platformio-build-esp32.py 2020-11-04 00:56:44 +02:00
d2bf40c0b3 Update platformio-build-esp32.py 2020-11-04 00:56:44 +02:00
4aefc0ea3b try pio again 2020-11-04 00:56:44 +02:00
bcadf08fa6 Update on-push.sh 2020-11-04 00:55:56 +02:00
92772e2aba Update on-push.sh 2020-11-04 00:55:56 +02:00
edee32ac07 Update WiFiTelnetToSerial.ino 2020-11-04 00:55:56 +02:00
cd9f890400 skip more examples 2020-11-04 00:55:56 +02:00
66b3e68bc4 Update esp32-hal-i2c.c 2020-11-04 00:55:56 +02:00
d64a825b0a Update SD_Update.ino 2020-11-04 00:55:56 +02:00
2fcb386dcf Create .skip.esp32s2 2020-11-04 00:55:56 +02:00
fbac930d7c skip some examples 2020-11-04 00:55:56 +02:00
d349cdc08f Update SPI_Multiple_Buses.ino 2020-11-04 00:55:55 +02:00
a0b8025ad8 Update TouchRead.ino 2020-11-04 00:55:55 +02:00
5784081147 disable BT Serial examples for S2 2020-11-04 00:55:55 +02:00
d3c5f26fa4 Update ResetReason.ino 2020-11-04 00:55:55 +02:00
bcae3a4def Update on-push.sh 2020-11-04 00:55:55 +02:00
7e06b32ce3 try s2 ci 2020-11-04 00:55:55 +02:00
2326f91bc9 fix provision compilation 2020-11-04 00:55:55 +02:00
c070e7152b fix cmake check 2020-11-04 00:54:09 +02:00
3735cfe548 Update app_httpd.cpp 2020-11-04 00:54:09 +02:00
d9c7b589a0 some compile fixes 2020-11-04 00:54:09 +02:00
5570003949 Update CameraWebServer.ino 2020-11-04 00:52:50 +02:00
96b9e89015 Update esp32-hal-gpio.c 2020-11-04 00:52:50 +02:00
c6b03a3f94 Add S2 variant 2020-11-04 00:52:50 +02:00
0a262244e6 Initial Commit 2020-11-04 00:52:28 +02:00
ebe0d9a6cb Add fixes 2020-11-04 00:29:15 +02:00
970fef63c0 Pass ethernet events to the main handler 2020-11-04 00:28:42 +02:00
f14a85311f get smart config to work as well 2020-11-04 00:28:41 +02:00
92db9730e0 make ETH work 2020-11-04 00:28:41 +02:00
ee535efb5c Update package_esp32_index.template.json 2020-11-04 00:28:41 +02:00
96679576d0 Update CMakeLists.txt 2020-11-04 00:28:41 +02:00
1bf59ac227 Initial IDF-4.0 port
SmartConfig and ETH need some work to adapt to the new API
2020-11-04 00:28:05 +02:00
8136 changed files with 111654 additions and 1348674 deletions

View File

@ -1,62 +0,0 @@
name: Feature request
description: Suggest an idea for this project
labels: ["Type: Feature request"]
body:
- type: markdown
attributes:
value: |
* We welcome any ideas or feature requests! It is helpful if you can explain exactly why the feature would be useful.
* There are usually some outstanding feature requests in the [existing issues list](https://github.com/espressif/arduino-esp32/issues?q=is%3Aopen+is%3Aissue+label%3A%22Type%3A+Feature+request%22), feel free to add comments to them.
* If you would like to contribute, please read the [contributions guide](https://docs.espressif.com/projects/arduino-esp32/en/latest/contributing.html).
- type: input
id: Area
attributes:
label: Related area
description: Please briefly explain the area of your Feature Request.
placeholder: eg. Board support, specific Peripheral, BT, Wifi...
validations:
required: true
- type: input
id: HW
attributes:
label: Hardware specification
description: Please provide if your proposal depends on specific Hardware.
placeholder: eg. Support for ESP32 DevKitC, ESP32-C3 DevKitM...
validations:
required: true
- type: textarea
id: problem-related
attributes:
label: Is your feature request related to a problem?
description: Please provide a clear and concise description of what the problem is. Add relevant issue link.
placeholder: ex. I'm facing the issue/missing function...
validations:
required: true
- type: textarea
id: solution
attributes:
label: Describe the solution you'd like
description: Please provide a clear and concise description of what you want to happen.
placeholder: ex. When using this function...
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Describe alternatives you've considered
description: Please provide a clear and concise description of any alternative solutions or features you've considered.
placeholder: ex. Choosing other approach wouldn't work, because...
- type: textarea
id: context
attributes:
label: Additional context
description: Please add any other context or screenshots about the feature request here.
placeholder: ex. This would work only when ...
- type: checkboxes
id: confirmation
attributes:
label: I have checked existing list of Feature requests and the Contribution Guide
description: You agree to check all the resources above before opening a new Feature request.
options:
- label: I confirm I have checked existing list of Feature requests and Contribution Guide.
required: true

View File

@ -1,133 +0,0 @@
name: Issue report
description: Report any problem here
labels: ["Status: Awaiting triage"]
body:
- type: markdown
attributes:
value: |
* Before reporting a new issue please check and search in [List of existing issues](https://github.com/espressif/arduino-esp32/issues?q=is%3Aissue)
* Please check [Online Documentation](https://docs.espressif.com/projects/arduino-esp32/en/latest/index.html)
* Take a look on [Troubleshooting guide](https://docs.espressif.com/projects/arduino-esp32/en/latest/troubleshooting.html)
* If still experiencing the issue, please provide as many details as possible below about your hardware, computer setup and code.
- type: input
id: Board
attributes:
label: Board
description: On which Board does this issue occur?
placeholder: eg. ESP32 Dev Module, ESP32-S2, LilyGo TTGO LoRa32...
validations:
required: true
- type: textarea
id: devboard
attributes:
label: Device Description
description: What development board or other hardware is the chip attached to?
placeholder: ex. DevKitC, plain module on breadboard, etc. If your hardware is custom or unusual, please attach a photo.
validations:
required: true
- type: textarea
id: other-hw
attributes:
label: Hardware Configuration
description: Is anything else attached to the development board?
placeholder: ex. GPIO 18 & 19 are connected to I2C devices.
validations:
required: true
- type: dropdown
id: version
attributes:
label: Version
description: What version of Arduino ESP32 are you running? If possible, consider updating to the latest version.
options:
- latest master (checkout manually)
- latest development Release Candidate (RC-X)
- v2.0.3
- v2.0.2
- v2.0.1
- v2.0.0
- v1.0.6
- other
validations:
required: true
- type: input
id: IDE
attributes:
label: IDE Name
description: What IDE are you using?
placeholder: eg. Arduino IDE, PlatformIO, Sloeber...
validations:
required: true
- type: input
id: os
attributes:
label: Operating System
description: On which OS does this issue occur?
placeholder: ex. macOS 12.1, Windows 10...
validations:
required: true
- type: input
id: Flash
attributes:
label: Flash frequency
description: What flash frequency is used?
placeholder: eg. 40Mhz
validations:
required: true
- type: dropdown
id: PSRAM
attributes:
label: PSRAM enabled
description: Is PSRAM enabled?
options:
- 'yes'
- 'no'
validations:
required: true
- type: input
id: Upload
attributes:
label: Upload speed
description: What upload speed is used?
placeholder: eg. 115200
validations:
required: true
- type: textarea
id: Description
attributes:
label: Description
description: Please describe your problem here and expected behaviour
placeholder: ex. Can't connect/weird behaviour/wrong function/missing parameter..
validations:
required: true
- type: textarea
id: sketch
attributes:
label: Sketch
description: Please provide full minimal sketch/code which can be run to reproduce your issue
placeholder: ex. Related part of the code to replicate the issue
render: cpp
validations:
required: true
- type: textarea
id: Debug
attributes:
label: Debug Message
description: Please provide a debug message or error message. If you have a Guru Meditation Error or Backtrace, please decode it with [ExceptionDecoder](https://github.com/me-no-dev/EspExceptionDecoder)
placeholder: Enable Core debug level - Debug on tools menu of Arduino IDE, then put the serial output here.
render: plain
validations:
required: true
- type: textarea
id: other-remarks
attributes:
label: Other Steps to Reproduce
description: Is there any other information you can think of which will help us reproduce this problem? Any additional info can be added as well.
placeholder: ex. I also tried on other OS, HW...it works correctly on that setup.
- type: checkboxes
id: confirmation
attributes:
label: I have checked existing issues, online documentation and the Troubleshooting Guide
description: You agree to check all the resources above before opening a new issue.
options:
- label: I confirm I have checked existing issues, online documentation and Troubleshooting guide.
required: true

54
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,54 @@
---
name: Bug report
about: Please fill in the bug report carefully
title: ''
labels: ''
assignees: ''
---
Make your question, not a Statement, inclusive. Include all pertinent information:
What you are trying to do?
Describe your system( Hardware, computer, O/S, core version, environment).
Describe what is failing.
Show the shortest possible code that will duplicate the error.
Show the EXACT error message(it doesn't work is not enough).
All of this work on your part shows us that you have worked to solve YOUR problem. The more complete your issue posting is, the more likely someone will volunteer their time to help you.
If you have a Guru Meditation Error or Backtrace, ***please decode it***:
https://github.com/me-no-dev/EspExceptionDecoder
----------------------------- Remove above -----------------------------
### Hardware:
Board: ?ESP32 Dev Module? ?node32? ?ttgo_lora?
Core Installation version: ?1.0.0? ?1.0.1-rc4? ?1.0.1? ?1.0.1-git? ?1.0.2? ?1.0.3?
IDE name: ?Arduino IDE? ?Platform.io? ?IDF component?
Flash Frequency: ?40Mhz?
PSRAM enabled: ?no? ?yes?
Upload Speed: ?115200?
Computer OS: ?Windows 10? ?Mac OSX? ?Ubuntu?
### Description:
Describe your problem here
### Sketch: (leave the backquotes for [code formatting](https://help.github.com/articles/creating-and-highlighting-code-blocks/))
```cpp
//Change the code below by your sketch
#include <Arduino.h>
void setup() {
}
void loop() {
}
```
### Debug Messages:
```
Enable Core debug level: Debug on tools menu of Arduino IDE, then put the serial output here
```

View File

@ -1,8 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Arduino ESP32 Gitter Channel
url: https://gitter.im/espressif/arduino-esp32
about: Community channel for questions and help
- name: ESP32 Forum - Arduino
url: https://esp32.com/viewforum.php?f=19
about: Official Forum for questions

View File

@ -1,23 +0,0 @@
*By completing this PR sufficiently, you help us to review this Pull Request quicker and also help improve the quality of Release Notes*
### Checklist
1. [ ] Please provide specific title of the PR describing the change, including the component name (*eg. „Update of Documentation link on Readme.md“*)
2. [ ] Please provide related links (*eg. Issue which will be closed by this Pull Request*)
3. [ ] Please **update relevant Documentation** if applicable
4. [ ] Please check [Contributing guide](https://docs.espressif.com/projects/arduino-esp32/en/latest/contributing.html)
*This entire section above can be deleted if all items are checked.*
-----------
## Description of Change
Please describe your proposed Pull Request and it's impact.
## Tests scenarios
Please describe on what Hardware and Software combinations you have tested this Pull Request and how.
(*eg. I have tested my Pull Request on Arduino-esp32 core v2.0.2 with ESP32 and ESP32-S2 Board with this scenario*)
## Related links
Please provide links to related issue, PRs etc.
(*eg. Closes #number of issue*)

View File

@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# #
# This script is used in the CI workflow. It checks all non-examples source files in libraries/ and cores/ are listed in # This script is for Travis. It checks all non-examples source files in libraries/ and cores/ are listed in
# CMakeLists.txt for the cmake-based IDF component # CMakeLists.txt for the cmake-based IDF component
# #
# If you see an error running this script, edit CMakeLists.txt and add any new source files into your PR # If you see an error running this script, edit CMakeLists.txt and add any new source files into your PR
@ -15,7 +15,7 @@ git submodule update --init --recursive
REPO_SRCS=`find cores/esp32/ libraries/ -name 'examples' -prune -o -name '*.c' -print -o -name '*.cpp' -print | sort` REPO_SRCS=`find cores/esp32/ libraries/ -name 'examples' -prune -o -name '*.c' -print -o -name '*.cpp' -print | sort`
# find all source files named in CMakeLists.txt COMPONENT_SRCS # find all source files named in CMakeLists.txt COMPONENT_SRCS
CMAKE_SRCS=`cmake --trace-expand -P CMakeLists.txt 2>&1 | grep set\(srcs | cut -d'(' -f3 | sed 's/ )//' | sed 's/srcs //' | tr ' ;' '\n' | sort` CMAKE_SRCS=`cmake --trace-expand -C CMakeLists.txt 2>&1 | grep set\(srcs | cut -d'(' -f3 | sed 's/ )//' | sed 's/srcs //' | tr ' ;' '\n' | sort`
if ! diff -u0 --label "Repo Files" --label "srcs" <(echo "$REPO_SRCS") <(echo "$CMAKE_SRCS"); then if ! diff -u0 --label "Repo Files" --label "srcs" <(echo "$REPO_SRCS") <(echo "$CMAKE_SRCS"); then
echo "Source files in repo (-) and source files in CMakeLists.txt (+) don't match" echo "Source files in repo (-) and source files in CMakeLists.txt (+) don't match"

View File

@ -15,7 +15,7 @@ if [ ! -d "$ARDUINO_ESP32_PATH" ]; then
pip install requests > /dev/null pip install requests > /dev/null
fi fi
if [ ! -z "$GITHUB_REPOSITORY" ]; then if [ "$GITHUB_REPOSITORY" == "espressif/arduino-esp32" ]; then
echo "Linking Core..." echo "Linking Core..."
ln -s $GITHUB_WORKSPACE esp32 ln -s $GITHUB_WORKSPACE esp32
else else

View File

@ -34,6 +34,9 @@ else
fi fi
export OS_NAME export OS_NAME
ARDUINO_BUILD_DIR="$HOME/.arduino/build.tmp"
ARDUINO_CACHE_DIR="$HOME/.arduino/cache.tmp"
if [ "$OS_IS_MACOS" == "1" ]; then if [ "$OS_IS_MACOS" == "1" ]; then
export ARDUINO_IDE_PATH="/Applications/Arduino.app/Contents/Java" export ARDUINO_IDE_PATH="/Applications/Arduino.app/Contents/Java"
export ARDUINO_USR_PATH="$HOME/Documents/Arduino" export ARDUINO_USR_PATH="$HOME/Documents/Arduino"
@ -78,3 +81,148 @@ if [ ! -d "$ARDUINO_IDE_PATH" ]; then
echo "" echo ""
fi fi
function build_sketch(){ # build_sketch <fqbn> <path-to-ino> [extra-options]
if [ "$#" -lt 2 ]; then
echo "ERROR: Illegal number of parameters"
echo "USAGE: build_sketch <fqbn> <path-to-ino> [extra-options]"
return 1
fi
local fqbn="$1"
local sketch="$2"
local xtra_opts="$3"
local win_opts=""
if [ "$OS_IS_WINDOWS" == "1" ]; then
local ctags_version=`ls "$ARDUINO_IDE_PATH/tools-builder/ctags/"`
local preprocessor_version=`ls "$ARDUINO_IDE_PATH/tools-builder/arduino-preprocessor/"`
win_opts="-prefs=runtime.tools.ctags.path=$ARDUINO_IDE_PATH/tools-builder/ctags/$ctags_version -prefs=runtime.tools.arduino-preprocessor.path=$ARDUINO_IDE_PATH/tools-builder/arduino-preprocessor/$preprocessor_version"
fi
echo ""
echo "Compiling '"$(basename "$sketch")"' ..."
mkdir -p "$ARDUINO_BUILD_DIR"
mkdir -p "$ARDUINO_CACHE_DIR"
$ARDUINO_IDE_PATH/arduino-builder -compile -logger=human -core-api-version=10810 \
-fqbn=$fqbn \
-warnings="all" \
-tools "$ARDUINO_IDE_PATH/tools-builder" \
-tools "$ARDUINO_IDE_PATH/tools" \
-built-in-libraries "$ARDUINO_IDE_PATH/libraries" \
-hardware "$ARDUINO_IDE_PATH/hardware" \
-hardware "$ARDUINO_USR_PATH/hardware" \
-libraries "$ARDUINO_USR_PATH/libraries" \
-build-cache "$ARDUINO_CACHE_DIR" \
-build-path "$ARDUINO_BUILD_DIR" \
$win_opts $xtra_opts "$sketch"
}
function count_sketches() # count_sketches <examples-path> <target-mcu>
{
local examples="$1"
local target="$2"
rm -rf sketches.txt
if [ ! -d "$examples" ]; then
touch sketches.txt
return 0
fi
local sketches=$(find $examples -name *.ino)
local sketchnum=0
for sketch in $sketches; do
local sketchdir=$(dirname $sketch)
local sketchdirname=$(basename $sketchdir)
local sketchname=$(basename $sketch)
if [[ "${sketchdirname}.ino" != "$sketchname" ]]; then
continue
fi;
if [[ -f "$sketchdir/.skip.$target" ]]; then
continue
fi
echo $sketch >> sketches.txt
sketchnum=$(($sketchnum + 1))
done
return $sketchnum
}
function build_sketches() # build_sketches <fqbn> <target-mcu> <examples-path> <chunk> <total-chunks> [extra-options]
{
local fqbn=$1
local target="$2"
local examples=$3
local chunk_idex=$4
local chunks_num=$5
local xtra_opts=$6
if [ "$#" -lt 3 ]; then
echo "ERROR: Illegal number of parameters"
echo "USAGE: build_sketches <fqbn> <target-mcu <examples-path> [<chunk> <total-chunks>] [extra-options]"
return 1
fi
if [ "$#" -lt 5 ]; then
chunk_idex="0"
chunks_num="1"
xtra_opts=$4
fi
if [ "$chunks_num" -le 0 ]; then
echo "ERROR: Chunks count must be positive number"
return 1
fi
if [ "$chunk_idex" -ge "$chunks_num" ]; then
echo "ERROR: Chunk index must be less than chunks count"
return 1
fi
set +e
count_sketches "$examples"
local sketchcount=$?
set -e
local sketches=$(cat sketches.txt)
rm -rf sketches.txt
local chunk_size=$(( $sketchcount / $chunks_num ))
local all_chunks=$(( $chunks_num * $chunk_size ))
if [ "$all_chunks" -lt "$sketchcount" ]; then
chunk_size=$(( $chunk_size + 1 ))
fi
local start_index=$(( $chunk_idex * $chunk_size ))
if [ "$sketchcount" -le "$start_index" ]; then
echo "Skipping job"
return 0
fi
local end_index=$(( $(( $chunk_idex + 1 )) * $chunk_size ))
if [ "$end_index" -gt "$sketchcount" ]; then
end_index=$sketchcount
fi
local start_num=$(( $start_index + 1 ))
echo "Found $sketchcount Sketches";
echo "Chunk Count : $chunks_num"
echo "Chunk Size : $chunk_size"
echo "Start Sketch: $start_num"
echo "End Sketch : $end_index"
local sketchnum=0
for sketch in $sketches; do
local sketchdir=$(dirname $sketch)
local sketchdirname=$(basename $sketchdir)
local sketchname=$(basename $sketch)
if [ "${sketchdirname}.ino" != "$sketchname" ] \
|| [ -f "$sketchdir/.skip.$target" ]; then
continue
fi
sketchnum=$(($sketchnum + 1))
if [ "$sketchnum" -le "$start_index" ] \
|| [ "$sketchnum" -gt "$end_index" ]; then
continue
fi
build_sketch "$fqbn" "$sketch" "$xtra_opts"
local result=$?
if [ $result -ne 0 ]; then
return $result
fi
done
return 0
}

View File

@ -1,44 +1,19 @@
#!/bin/bash #!/bin/bash
export PLATFORMIO_ESP32_PATH="$HOME/.platformio/packages/framework-arduinoespressif32" export PLATFORMIO_ESP32_PATH="$HOME/.platformio/packages/framework-arduinoespressif32"
PLATFORMIO_ESP32_URL="https://github.com/platformio/platform-espressif32.git" PLATFORMIO_ESP32_URL="https://github.com/platformio/platform-espressif32.git#feature/idf-v4.0"
TOOLCHAIN_VERSION="8.4.0+2021r2-patch3"
ESPTOOLPY_VERSION="~1.30100.0"
ESPRESSIF_ORGANIZATION_NAME="espressif"
echo "Installing Python Wheel ..." echo "Installing Python Wheel ..."
pip install wheel > /dev/null 2>&1 pip install wheel > /dev/null 2>&1
echo "Installing PlatformIO ..." echo "Installing PlatformIO ..."
pip install -U https://github.com/platformio/platformio/archive/master.zip > /dev/null 2>&1 pip install -U https://github.com/platformio/platformio/archive/develop.zip > /dev/null 2>&1
echo "Installing Platform ESP32 ..." echo "Installing Platform ESP32 ..."
python -m platformio platform install $PLATFORMIO_ESP32_URL > /dev/null 2>&1 python -m platformio platform install $PLATFORMIO_ESP32_URL > /dev/null 2>&1
echo "Replacing the package versions ..." echo "Replacing the framework version ..."
replace_script="import json; import os;" python -c "import json; import os; fp=open(os.path.expanduser('~/.platformio/platforms/espressif32/platform.json'), 'r+'); data=json.load(fp); data['packages']['framework-arduinoespressif32']['version'] = '*'; fp.seek(0); fp.truncate(); json.dump(data, fp); fp.close()"
replace_script+="fp=open(os.path.expanduser('~/.platformio/platforms/espressif32/platform.json'), 'r+');"
replace_script+="data=json.load(fp);"
# Use framework sources from the repository
replace_script+="data['packages']['framework-arduinoespressif32']['version'] = '*';"
replace_script+="del data['packages']['framework-arduinoespressif32']['owner'];"
# Use toolchain packages from the "espressif" organization
replace_script+="data['packages']['toolchain-xtensa-esp32']['owner']='$ESPRESSIF_ORGANIZATION_NAME';"
replace_script+="data['packages']['toolchain-xtensa-esp32s2']['owner']='$ESPRESSIF_ORGANIZATION_NAME';"
replace_script+="data['packages']['toolchain-riscv32-esp']['owner']='$ESPRESSIF_ORGANIZATION_NAME';"
# Update versions to use the upstream
replace_script+="data['packages']['toolchain-xtensa-esp32']['version']='$TOOLCHAIN_VERSION';"
replace_script+="data['packages']['toolchain-xtensa-esp32s2']['version']='$TOOLCHAIN_VERSION';"
replace_script+="data['packages']['toolchain-riscv32-esp']['version']='$TOOLCHAIN_VERSION';"
# Add ESP32-S3 Toolchain
replace_script+="data['packages'].update({'toolchain-xtensa-esp32s3':{'type':'toolchain','optional':True,'owner':'$ESPRESSIF_ORGANIZATION_NAME','version':'$TOOLCHAIN_VERSION'}});"
replace_script+="data['packages']['toolchain-xtensa-esp32'].update({'optional':False});"
# esptool.py may require an upstream version (for now platformio is the owner)
replace_script+="data['packages']['tool-esptoolpy']['version']='$ESPTOOLPY_VERSION';"
# Save results
replace_script+="fp.seek(0);fp.truncate();json.dump(data, fp, indent=2);fp.close()"
python -c "$replace_script"
if [ "$GITHUB_REPOSITORY" == "espressif/arduino-esp32" ]; then if [ "$GITHUB_REPOSITORY" == "espressif/arduino-esp32" ]; then
echo "Linking Core..." echo "Linking Core..."
@ -67,7 +42,8 @@ function build_pio_sketch(){ # build_pio_sketch <board> <options> <path-to-ino>
python -m platformio ci --board "$board" "$sketch_dir" --project-option="$options" python -m platformio ci --board "$board" "$sketch_dir" --project-option="$options"
} }
function count_sketches(){ # count_sketches <examples-path> function count_sketches() # count_sketches <examples-path>
{
local examples="$1" local examples="$1"
rm -rf sketches.txt rm -rf sketches.txt
if [ ! -d "$examples" ]; then if [ ! -d "$examples" ]; then
@ -82,7 +58,7 @@ function count_sketches(){ # count_sketches <examples-path>
local sketchname=$(basename $sketch) local sketchname=$(basename $sketch)
if [[ "${sketchdirname}.ino" != "$sketchname" ]]; then if [[ "${sketchdirname}.ino" != "$sketchname" ]]; then
continue continue
fi fi;
if [[ -f "$sketchdir/.test.skip" ]]; then if [[ -f "$sketchdir/.test.skip" ]]; then
continue continue
fi fi
@ -92,7 +68,8 @@ function count_sketches(){ # count_sketches <examples-path>
return $sketchnum return $sketchnum
} }
function build_pio_sketches(){ # build_pio_sketches <board> <options> <examples-path> <chunk> <total-chunks> function build_pio_sketches() # build_pio_sketches <board> <options> <examples-path> <chunk> <total-chunks>
{
if [ "$#" -lt 3 ]; then if [ "$#" -lt 3 ]; then
echo "ERROR: Illegal number of parameters" echo "ERROR: Illegal number of parameters"
echo "USAGE: build_pio_sketches <board> <options> <examples-path> [<chunk> <total-chunks>]" echo "USAGE: build_pio_sketches <board> <options> <examples-path> [<chunk> <total-chunks>]"

86
.github/scripts/on-pages.sh vendored Executable file → Normal file
View File

@ -85,59 +85,47 @@ function git_safe_upload_to_pages(){
return $? return $?
} }
git_safe_upload_to_pages "index.md" "README.md" EVENT_JSON=`cat $GITHUB_EVENT_PATH`
# At some point github stopped providing a list of edited file pages_added=`echo "$EVENT_JSON" | jq -r '.commits[].added[]'`
# but we also stopped havong documentation in md format, pages_modified=`echo "$EVENT_JSON" | jq -r '.commits[].modified[]'`
# so we can skip this portion safely and update just the index pages_removed=`echo "$EVENT_JSON" | jq -r '.commits[].removed[]'`
# EVENT_JSON=`cat $GITHUB_EVENT_PATH` for page in $pages_added; do
if [[ $page != "README.md" && $page != "docs/"* ]]; then
continue
fi
echo "Adding '$page' to pages ..."
if [[ $page == "README.md" ]]; then
git_safe_upload_to_pages "index.md" "README.md"
else
git_safe_upload_to_pages "$page" "$page"
fi
done
# echo "GITHUB_EVENT_PATH: $GITHUB_EVENT_PATH" for page in $pages_modified; do
# echo "EVENT_JSON: $EVENT_JSON" if [[ $page != "README.md" && $page != "docs/"* ]]; then
continue
fi
echo "Modifying '$page' ..."
if [[ $page == "README.md" ]]; then
git_safe_upload_to_pages "index.md" "README.md"
else
git_safe_upload_to_pages "$page" "$page"
fi
done
# pages_added=`echo "$EVENT_JSON" | jq -r '.commits[].added[]'` for page in $pages_removed; do
# echo "added: $pages_added" if [[ $page != "README.md" && $page != "docs/"* ]]; then
# pages_modified=`echo "$EVENT_JSON" | jq -r '.commits[].modified[]'` continue
# echo "modified: $pages_modified" fi
# pages_removed=`echo "$EVENT_JSON" | jq -r '.commits[].removed[]'` echo "Removing '$page' from pages ..."
# echo "removed: $pages_removed" if [[ $page == "README.md" ]]; then
git_remove_from_pages "README.md" > /dev/null
# for page in $pages_added; do else
# if [[ $page != "README.md" && $page != "docs/"* ]]; then git_remove_from_pages "$page" > /dev/null
# continue fi
# fi done
# echo "Adding '$page' to pages ..."
# if [[ $page == "README.md" ]]; then
# git_safe_upload_to_pages "index.md" "README.md"
# else
# git_safe_upload_to_pages "$page" "$page"
# fi
# done
# for page in $pages_modified; do
# if [[ $page != "README.md" && $page != "docs/"* ]]; then
# continue
# fi
# echo "Modifying '$page' ..."
# if [[ $page == "README.md" ]]; then
# git_safe_upload_to_pages "index.md" "README.md"
# else
# git_safe_upload_to_pages "$page" "$page"
# fi
# done
# for page in $pages_removed; do
# if [[ $page != "README.md" && $page != "docs/"* ]]; then
# continue
# fi
# echo "Removing '$page' from pages ..."
# if [[ $page == "README.md" ]]; then
# git_remove_from_pages "README.md" > /dev/null
# else
# git_remove_from_pages "$page" > /dev/null
# fi
# done
echo echo
echo "DONE!" echo "DONE!"

View File

@ -2,43 +2,18 @@
set -e set -e
export ARDUINO_BUILD_DIR="$HOME/.arduino/build.tmp" if [ ! -z "$TRAVIS_TAG" ]; then
echo "Skipping Test: Tagged build"
exit 0
fi
function build(){ if [ ! -z "$GITHUB_WORKSPACE" ]; then
local target=$1 export TRAVIS_BUILD_DIR="$GITHUB_WORKSPACE"
local fqbn=$2 export TRAVIS_REPO_SLUG="$GITHUB_REPOSITORY"
local chunk_index=$3 elif [ ! -z "$TRAVIS_BUILD_DIR" ]; then
local chunks_cnt=$4 export GITHUB_WORKSPACE="$TRAVIS_BUILD_DIR"
local sketches=$5 export GITHUB_REPOSITORY="$TRAVIS_REPO_SLUG"
else
local BUILD_SKETCH="${SCRIPTS_DIR}/sketch_utils.sh build"
local BUILD_SKETCHES="${SCRIPTS_DIR}/sketch_utils.sh chunk_build"
local args="$ARDUINO_IDE_PATH $ARDUINO_USR_PATH"
args+=" \"$fqbn\""
if [ "$OS_IS_LINUX" == "1" ]; then
args+=" $target"
args+=" $ARDUINO_ESP32_PATH/libraries"
args+=" $chunk_index $chunks_cnt"
${BUILD_SKETCHES} ${args}
else
if [ "$OS_IS_WINDOWS" == "1" ]; then
local ctags_version=`ls "$ARDUINO_IDE_PATH/tools-builder/ctags/"`
local preprocessor_version=`ls "$ARDUINO_IDE_PATH/tools-builder/arduino-preprocessor/"`
win_opts="-prefs=runtime.tools.ctags.path=$ARDUINO_IDE_PATH/tools-builder/ctags/$ctags_version
-prefs=runtime.tools.arduino-preprocessor.path=$ARDUINO_IDE_PATH/tools-builder/arduino-preprocessor/$preprocessor_version"
args+=" ${win_opts}"
fi
for sketch in ${sketches}; do
${BUILD_SKETCH} ${args} ${sketch}
done
fi
}
if [ -z "$GITHUB_WORKSPACE" ]; then
export GITHUB_WORKSPACE="$PWD" export GITHUB_WORKSPACE="$PWD"
export GITHUB_REPOSITORY="espressif/arduino-esp32" export GITHUB_REPOSITORY="espressif/arduino-esp32"
fi fi
@ -49,7 +24,7 @@ BUILD_PIO=0
if [ "$#" -lt 2 ] || [ "$CHUNKS_CNT" -le 0 ]; then if [ "$#" -lt 2 ] || [ "$CHUNKS_CNT" -le 0 ]; then
CHUNK_INDEX=0 CHUNK_INDEX=0
CHUNKS_CNT=1 CHUNKS_CNT=1
elif [ "$CHUNK_INDEX" -gt "$CHUNKS_CNT" ] && [ "$CHUNKS_CNT" -ge 2 ]; then elif [ "$CHUNK_INDEX" -gt "$CHUNKS_CNT" ]; then
CHUNK_INDEX=$CHUNKS_CNT CHUNK_INDEX=$CHUNKS_CNT
elif [ "$CHUNK_INDEX" -eq "$CHUNKS_CNT" ]; then elif [ "$CHUNK_INDEX" -eq "$CHUNKS_CNT" ]; then
BUILD_PIO=1 BUILD_PIO=1
@ -58,33 +33,44 @@ fi
#echo "Updating submodules ..." #echo "Updating submodules ..."
#git -C "$GITHUB_WORKSPACE" submodule update --init --recursive > /dev/null 2>&1 #git -C "$GITHUB_WORKSPACE" submodule update --init --recursive > /dev/null 2>&1
SCRIPTS_DIR="./.github/scripts"
if [ "$BUILD_PIO" -eq 0 ]; then if [ "$BUILD_PIO" -eq 0 ]; then
source ${SCRIPTS_DIR}/install-arduino-ide.sh # ArduinoIDE ESP32 Test
source ${SCRIPTS_DIR}/install-arduino-core-esp32.sh TARGET="esp32"
FQBN="espressif:esp32:esp32:PSRAM=enabled,PartitionScheme=huge_app"
source ./.github/scripts/install-arduino-ide.sh
source ./.github/scripts/install-arduino-core-esp32.sh
if [ "$OS_IS_WINDOWS" == "1" ]; then
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/WiFiClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino" && \
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/BLE/examples/BLE_server/BLE_server.ino" && \
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/ESP32/examples/Camera/CameraWebServer/CameraWebServer.ino"
elif [ "$OS_IS_MACOS" == "1" ]; then
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/WiFi/examples/WiFiClient/WiFiClient.ino" && \
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/WiFiClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino" && \
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/BluetoothSerial/examples/SerialToSerialBT/SerialToSerialBT.ino" && \
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/BLE/examples/BLE_server/BLE_server.ino" && \
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/ESP32/examples/Camera/CameraWebServer/CameraWebServer.ino"
else
# CMake Test
if [ "$CHUNK_INDEX" -eq 0 ]; then
bash "$ARDUINO_ESP32_PATH/.github/scripts/check-cmakelists.sh"
fi
build_sketches "$FQBN" "$TARGET" "$ARDUINO_ESP32_PATH/libraries" "$CHUNK_INDEX" "$CHUNKS_CNT"
fi
FQBN_ESP32="espressif:esp32:esp32:PSRAM=enabled,PartitionScheme=huge_app" # ArduinoIDE ESP32S2 Test
FQBN_ESP32S2="espressif:esp32:esp32s2:PSRAM=enabled,PartitionScheme=huge_app" TARGET="esp32s2"
FQBN_ESP32S3="espressif:esp32:esp32s3:PSRAM=opi,USBMode=default,PartitionScheme=huge_app" FQBN="espressif:esp32:esp32s2:PSRAM=enabled,PartitionScheme=huge_app"
FQBN_ESP32C3="espressif:esp32:esp32c3:PartitionScheme=huge_app" if [ "$OS_IS_WINDOWS" == "1" ]; then
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/WiFi/examples/WiFiClient/WiFiClient.ino" && \
SKETCHES_ESP32="\ build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/WiFiClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino"
$ARDUINO_ESP32_PATH/libraries/WiFiClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino\ elif [ "$OS_IS_MACOS" == "1" ]; then
$ARDUINO_ESP32_PATH/libraries/BLE/examples/BLE_server/BLE_server.ino\ build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/WiFi/examples/WiFiClient/WiFiClient.ino" && \
$ARDUINO_ESP32_PATH/libraries/ESP32/examples/Camera/CameraWebServer/CameraWebServer.ino\ build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/WiFiClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino"
" else
build_sketches "$FQBN" "$TARGET" "$ARDUINO_ESP32_PATH/libraries" "$CHUNK_INDEX" "$CHUNKS_CNT"
SKETCHES_ESP32XX="\ fi
$ARDUINO_ESP32_PATH/libraries/WiFiClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino\
$ARDUINO_ESP32_PATH/libraries/WiFi/examples/WiFiClient/WiFiClient.ino\
"
build "esp32s3" $FQBN_ESP32S3 $CHUNK_INDEX $CHUNKS_CNT $SKETCHES_ESP32
build "esp32s2" $FQBN_ESP32S2 $CHUNK_INDEX $CHUNKS_CNT $SKETCHES_ESP32XX
build "esp32c3" $FQBN_ESP32C3 $CHUNK_INDEX $CHUNKS_CNT $SKETCHES_ESP32XX
build "esp32" $FQBN_ESP32 $CHUNK_INDEX $CHUNKS_CNT $SKETCHES_ESP32
else else
source ${SCRIPTS_DIR}/install-platformio-esp32.sh source ./.github/scripts/install-platformio-esp32.sh
# PlatformIO ESP32 Test # PlatformIO ESP32 Test
BOARD="esp32dev" BOARD="esp32dev"
OPTIONS="board_build.partitions = huge_app.csv" OPTIONS="board_build.partitions = huge_app.csv"
@ -100,20 +86,6 @@ else
# build_pio_sketch "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries/WiFiClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino" # build_pio_sketch "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries/WiFiClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino"
python -m platformio ci --board "$BOARD" "$PLATFORMIO_ESP32_PATH/libraries/WiFi/examples/WiFiClient" --project-option="board_build.mcu = esp32s2" --project-option="board_build.partitions = huge_app.csv" python -m platformio ci --board "$BOARD" "$PLATFORMIO_ESP32_PATH/libraries/WiFi/examples/WiFiClient" --project-option="board_build.mcu = esp32s2" --project-option="board_build.partitions = huge_app.csv"
python -m platformio ci --board "$BOARD" "$PLATFORMIO_ESP32_PATH/libraries/WiFi/examples/WiFiClient" --project-option="board_build.mcu = esp32c3" --project-option="board_build.partitions = huge_app.csv"
echo "Hacking in S3 support ..."
replace_script="import json; import os;"
replace_script+="fp=open(os.path.expanduser('~/.platformio/platforms/espressif32/platform.json'), 'r+');"
replace_script+="data=json.load(fp);"
replace_script+="data['packages']['toolchain-xtensa-esp32']['optional']=True;"
replace_script+="data['packages']['toolchain-xtensa-esp32s3']['optional']=False;"
replace_script+="data['packages']['tool-esptoolpy']['owner']='tasmota';"
replace_script+="data['packages']['tool-esptoolpy']['version']='https://github.com/tasmota/esptool/releases/download/v3.3/esptool-3.3.zip';"
replace_script+="fp.seek(0);fp.truncate();json.dump(data, fp, indent=2);fp.close()"
python -c "$replace_script"
python -m platformio ci --board "$BOARD" "$PLATFORMIO_ESP32_PATH/libraries/WiFi/examples/WiFiClient" --project-option="board_build.mcu = esp32s3" --project-option="board_build.partitions = huge_app.csv"
#build_pio_sketches "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries" #build_pio_sketches "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries"
fi fi

View File

@ -172,7 +172,6 @@ mkdir -p "$PKG_DIR/tools"
# Copy all core files to the package folder # Copy all core files to the package folder
echo "Copying files for packaging ..." echo "Copying files for packaging ..."
cp -f "$GITHUB_WORKSPACE/boards.txt" "$PKG_DIR/" cp -f "$GITHUB_WORKSPACE/boards.txt" "$PKG_DIR/"
cp -f "$GITHUB_WORKSPACE/package.json" "$PKG_DIR/"
cp -f "$GITHUB_WORKSPACE/programmers.txt" "$PKG_DIR/" cp -f "$GITHUB_WORKSPACE/programmers.txt" "$PKG_DIR/"
cp -Rf "$GITHUB_WORKSPACE/cores" "$PKG_DIR/" cp -Rf "$GITHUB_WORKSPACE/cores" "$PKG_DIR/"
cp -Rf "$GITHUB_WORKSPACE/libraries" "$PKG_DIR/" cp -Rf "$GITHUB_WORKSPACE/libraries" "$PKG_DIR/"
@ -184,7 +183,6 @@ cp -f "$GITHUB_WORKSPACE/tools/gen_esp32part.py" "$PKG_DIR/tools/"
cp -f "$GITHUB_WORKSPACE/tools/gen_esp32part.exe" "$PKG_DIR/tools/" cp -f "$GITHUB_WORKSPACE/tools/gen_esp32part.exe" "$PKG_DIR/tools/"
cp -Rf "$GITHUB_WORKSPACE/tools/partitions" "$PKG_DIR/tools/" cp -Rf "$GITHUB_WORKSPACE/tools/partitions" "$PKG_DIR/tools/"
cp -Rf "$GITHUB_WORKSPACE/tools/sdk" "$PKG_DIR/tools/" cp -Rf "$GITHUB_WORKSPACE/tools/sdk" "$PKG_DIR/tools/"
cp -f $GITHUB_WORKSPACE/tools/platformio-build*.py "$PKG_DIR/tools/"
# Remove unnecessary files in the package folder # Remove unnecessary files in the package folder
echo "Cleaning up folders ..." echo "Cleaning up folders ..."
@ -196,7 +194,6 @@ echo "Generating platform.txt..."
cat "$GITHUB_WORKSPACE/platform.txt" | \ cat "$GITHUB_WORKSPACE/platform.txt" | \
sed "s/version=.*/version=$ver$extent/g" | \ sed "s/version=.*/version=$ver$extent/g" | \
sed 's/runtime.tools.xtensa-esp32-elf-gcc.path={runtime.platform.path}\/tools\/xtensa-esp32-elf//g' | \ sed 's/runtime.tools.xtensa-esp32-elf-gcc.path={runtime.platform.path}\/tools\/xtensa-esp32-elf//g' | \
sed 's/runtime.tools.xtensa-esp32s2-elf-gcc.path={runtime.platform.path}\/tools\/xtensa-esp32s2-elf//g' | \
sed 's/tools.esptool_py.path={runtime.platform.path}\/tools\/esptool/tools.esptool_py.path=\{runtime.tools.esptool_py.path\}/g' \ sed 's/tools.esptool_py.path={runtime.platform.path}\/tools\/esptool/tools.esptool_py.path=\{runtime.tools.esptool_py.path\}/g' \
> "$PKG_DIR/platform.txt" > "$PKG_DIR/platform.txt"
@ -257,30 +254,17 @@ releasesJson=`curl -sH "Authorization: token $GITHUB_TOKEN" "https://api.github.
if [ $? -ne 0 ]; then echo "ERROR: Get Releases Failed! ($?)"; exit 1; fi if [ $? -ne 0 ]; then echo "ERROR: Get Releases Failed! ($?)"; exit 1; fi
set +e set +e
prev_release=$(echo "$releasesJson" | jq -e -r ". | map(select(.draft == false and .prerelease == false)) | sort_by(.published_at | - fromdateiso8601) | .[0].tag_name") prev_release=$(echo "$releasesJson" | jq -e -r '. | map(select(.draft == false and .prerelease == false)) | sort_by(.created_at | - fromdateiso8601) | .[0].tag_name')
prev_any_release=$(echo "$releasesJson" | jq -e -r ". | map(select(.draft == false)) | sort_by(.published_at | - fromdateiso8601) | .[0].tag_name") prev_any_release=$(echo "$releasesJson" | jq -e -r '. | map(select(.draft == false)) | sort_by(.created_at | - fromdateiso8601) | .[0].tag_name')
prev_branch_release=$(echo "$releasesJson" | jq -e -r ". | map(select(.draft == false and .prerelease == false and .target_commitish == \"$RELEASE_BRANCH\")) | sort_by(.published_at | - fromdateiso8601) | .[0].tag_name")
prev_branch_any_release=$(echo "$releasesJson" | jq -e -r ". | map(select(.draft == false and .target_commitish == \"$RELEASE_BRANCH\")) | sort_by(.published_at | - fromdateiso8601) | .[0].tag_name")
shopt -s nocasematch shopt -s nocasematch
if [ "$prev_release" == "$RELEASE_TAG" ]; then
prev_release=$(echo "$releasesJson" | jq -e -r ". | map(select(.draft == false and .prerelease == false)) | sort_by(.published_at | - fromdateiso8601) | .[1].tag_name")
fi
if [ "$prev_any_release" == "$RELEASE_TAG" ]; then if [ "$prev_any_release" == "$RELEASE_TAG" ]; then
prev_any_release=$(echo "$releasesJson" | jq -e -r ". | map(select(.draft == false)) | sort_by(.published_at | - fromdateiso8601) | .[1].tag_name") prev_release=$(echo "$releasesJson" | jq -e -r '. | map(select(.draft == false and .prerelease == false)) | sort_by(.created_at | - fromdateiso8601) | .[1].tag_name')
fi prev_any_release=$(echo "$releasesJson" | jq -e -r '. | map(select(.draft == false)) | sort_by(.created_at | - fromdateiso8601) | .[1].tag_name')
if [ "$prev_branch_release" == "$RELEASE_TAG" ]; then
prev_branch_release=$(echo "$releasesJson" | jq -e -r ". | map(select(.draft == false and .prerelease == false and .target_commitish == \"$RELEASE_BRANCH\")) | sort_by(.published_at | - fromdateiso8601) | .[1].tag_name")
fi
if [ "$prev_branch_any_release" == "$RELEASE_TAG" ]; then
prev_branch_any_release=$(echo "$releasesJson" | jq -e -r ". | map(select(.draft == false and .target_commitish == \"$RELEASE_BRANCH\")) | sort_by(.published_at | - fromdateiso8601) | .[1].tag_name")
fi fi
COMMITS_SINCE_RELEASE="$prev_any_release"
shopt -u nocasematch shopt -u nocasematch
set -e set -e
echo "Previous Release: $prev_release"
echo "Previous (any)release: $prev_any_release"
echo
# Merge package JSONs with previous releases # Merge package JSONs with previous releases
if [ ! -z "$prev_any_release" ] && [ "$prev_any_release" != "null" ]; then if [ ! -z "$prev_any_release" ] && [ "$prev_any_release" != "null" ]; then
echo "Merging with JSON from $prev_any_release ..." echo "Merging with JSON from $prev_any_release ..."
@ -288,12 +272,17 @@ if [ ! -z "$prev_any_release" ] && [ "$prev_any_release" != "null" ]; then
fi fi
if [ "$RELEASE_PRE" == "false" ]; then if [ "$RELEASE_PRE" == "false" ]; then
COMMITS_SINCE_RELEASE="$prev_release"
if [ ! -z "$prev_release" ] && [ "$prev_release" != "null" ]; then if [ ! -z "$prev_release" ] && [ "$prev_release" != "null" ]; then
echo "Merging with JSON from $prev_release ..." echo "Merging with JSON from $prev_release ..."
merge_package_json "$prev_release/$PACKAGE_JSON_REL" "$OUTPUT_DIR/$PACKAGE_JSON_REL" merge_package_json "$prev_release/$PACKAGE_JSON_REL" "$OUTPUT_DIR/$PACKAGE_JSON_REL"
fi fi
fi fi
echo "Previous Release: $prev_release"
echo "Previous (any)release: $prev_any_release"
echo
# Upload package JSONs # Upload package JSONs
echo "Uploading $PACKAGE_JSON_DEV ..." echo "Uploading $PACKAGE_JSON_DEV ..."
echo "Download URL: "`git_safe_upload_asset "$OUTPUT_DIR/$PACKAGE_JSON_DEV"` echo "Download URL: "`git_safe_upload_asset "$OUTPUT_DIR/$PACKAGE_JSON_DEV"`
@ -338,35 +327,21 @@ if [ $arrLen > 3 ] && [ "${msgArray[0]:0:3}" == "tag" ]; then
fi fi
# Append Commit Messages # Append Commit Messages
echo
echo "Previous Branch Release: $prev_branch_release"
echo "Previous Branch (any)release: $prev_branch_any_release"
echo
commitFile="$OUTPUT_DIR/commits.txt"
COMMITS_SINCE_RELEASE="$prev_branch_any_release"
if [ "$RELEASE_PRE" == "false" ]; then
COMMITS_SINCE_RELEASE="$prev_branch_release"
fi
if [ ! -z "$COMMITS_SINCE_RELEASE" ] && [ "$COMMITS_SINCE_RELEASE" != "null" ]; then if [ ! -z "$COMMITS_SINCE_RELEASE" ] && [ "$COMMITS_SINCE_RELEASE" != "null" ]; then
echo "Getting commits since $COMMITS_SINCE_RELEASE ..." echo "Getting commits since $COMMITS_SINCE_RELEASE ..."
git -C "$GITHUB_WORKSPACE" log --oneline -n 500 "$COMMITS_SINCE_RELEASE..HEAD" > "$commitFile" commitFile=$OUTPUT_DIR/commits.txt
elif [ "$RELEASE_BRANCH" != "master" ]; then git -C "$GITHUB_WORKSPACE" log --oneline "$COMMITS_SINCE_RELEASE..HEAD" > "$OUTPUT_DIR/commits.txt"
echo "Getting all commits on branch '$RELEASE_BRANCH' ..." releaseNotes+=$'\r\n##### Commits\r\n'
git -C "$GITHUB_WORKSPACE" log --oneline -n 500 --cherry-pick --left-only --no-merges HEAD...origin/master > "$commitFile" IFS=$'\n'
else for next in `cat $commitFile`
echo "Getting all commits on master ..." do
git -C "$GITHUB_WORKSPACE" log --oneline -n 500 --no-merges > "$commitFile"
fi
releaseNotes+=$'\r\n##### Commits\r\n'
IFS=$'\n'
for next in `cat $commitFile`
do
IFS=' ' read -r commitId commitMsg <<< "$next" IFS=' ' read -r commitId commitMsg <<< "$next"
commitLine="- [$commitId](https://github.com/$GITHUB_REPOSITORY/commit/$commitId) $commitMsg" commitLine="- [$commitId](https://github.com/$GITHUB_REPOSITORY/commit/$commitId) $commitMsg"
releaseNotes+="$commitLine" releaseNotes+="$commitLine"
releaseNotes+=$'\r\n' releaseNotes+=$'\r\n'
done done
rm -f $commitFile rm -f $commitFile
fi
# Prepend the original release body # Prepend the original release body
if [ "${RELEASE_BODY: -1}" == $'\r' ]; then if [ "${RELEASE_BODY: -1}" == $'\r' ]; then

View File

@ -1,192 +0,0 @@
#!/bin/bash
function build_sketch(){ # build_sketch <ide_path> <user_path> <fqbn> <path-to-ino> [extra-options]
if [ "$#" -lt 4 ]; then
echo "ERROR: Illegal number of parameters"
echo "USAGE: ${0} build <ide_path> <user_path> <fqbn> <path-to-ino> [extra-options]"
return 1
fi
local ide_path=$1
local usr_path=$2
local fqbn=$3
local sketch=$4
local xtra_opts=$5
local win_opts=$6
ARDUINO_CACHE_DIR="$HOME/.arduino/cache.tmp"
if [ -z "$ARDUINO_BUILD_DIR" ]; then
build_dir="$(dirname $sketch)/build"
else
build_dir="$ARDUINO_BUILD_DIR"
fi
echo $sketch
rm -rf "$build_dir"
mkdir -p "$build_dir"
mkdir -p "$ARDUINO_CACHE_DIR"
$ide_path/arduino-builder -compile -logger=human -core-api-version=10810 \
-fqbn=$fqbn \
-warnings="all" \
-tools "$ide_path/tools-builder" \
-tools "$ide_path/tools" \
-built-in-libraries "$ide_path/libraries" \
-hardware "$ide_path/hardware" \
-hardware "$usr_path/hardware" \
-libraries "$usr_path/libraries" \
-build-cache "$ARDUINO_CACHE_DIR" \
-build-path "$build_dir" \
$win_opts $xtra_opts "$sketch"
}
function count_sketches(){ # count_sketches <path> [target]
local path=$1
local target=$2
if [ $# -lt 1 ]; then
echo "ERROR: Illegal number of parameters"
echo "USAGE: ${0} count <path> [target]"
fi
rm -rf sketches.txt
if [ ! -d "$path" ]; then
touch sketches.txt
return 0
fi
local sketches=$(find $path -name *.ino | sort)
local sketchnum=0
for sketch in $sketches; do
local sketchdir=$(dirname $sketch)
local sketchdirname=$(basename $sketchdir)
local sketchname=$(basename $sketch)
if [[ "$sketchdirname.ino" != "$sketchname" ]]; then
continue
elif [[ -n $target ]] && [[ -f "$sketchdir/.skip.$target" ]]; then
continue
else
echo $sketch >> sketches.txt
sketchnum=$(($sketchnum + 1))
fi
done
return $sketchnum
}
function build_sketches(){ # build_sketches <ide_path> <user_path> <fqbn> <target> <path> <chunk> <total-chunks> [extra-options]
local ide_path=$1
local usr_path=$2
local fqbn=$3
local target=$4
local path=$5
local chunk_idex=$6
local chunks_num=$7
local xtra_opts=$8
if [ "$#" -lt 7 ]; then
echo "ERROR: Illegal number of parameters"
echo "USAGE: ${0} chunk_build <ide_path> <user_path> <fqbn> <target> <path> [<chunk> <total-chunks>] [extra-options]"
return 1
fi
if [ "$chunks_num" -le 0 ]; then
echo "ERROR: Chunks count must be positive number"
return 1
fi
if [ "$chunk_idex" -ge "$chunks_num" ] && [ "$chunks_num" -ge 2 ]; then
echo "ERROR: Chunk index must be less than chunks count"
return 1
fi
set +e
count_sketches "$path" "$target"
local sketchcount=$?
set -e
local sketches=$(cat sketches.txt)
rm -rf sketches.txt
local chunk_size=$(( $sketchcount / $chunks_num ))
local all_chunks=$(( $chunks_num * $chunk_size ))
if [ "$all_chunks" -lt "$sketchcount" ]; then
chunk_size=$(( $chunk_size + 1 ))
fi
local start_index=0
local end_index=0
if [ "$chunk_idex" -ge "$chunks_num" ]; then
start_index=$chunk_idex
end_index=$sketchcount
else
start_index=$(( $chunk_idex * $chunk_size ))
if [ "$sketchcount" -le "$start_index" ]; then
echo "Skipping job"
return 0
fi
end_index=$(( $(( $chunk_idex + 1 )) * $chunk_size ))
if [ "$end_index" -gt "$sketchcount" ]; then
end_index=$sketchcount
fi
fi
local start_num=$(( $start_index + 1 ))
echo "Found $sketchcount Sketches for target '$target'";
echo "Chunk Index : $chunk_idex"
echo "Chunk Count : $chunks_num"
echo "Chunk Size : $chunk_size"
echo "Start Sketch: $start_num"
echo "End Sketch : $end_index"
local sketchnum=0
for sketch in $sketches; do
local sketchdir=$(dirname $sketch)
local sketchdirname=$(basename $sketchdir)
local sketchname=$(basename $sketch)
sketchnum=$(($sketchnum + 1))
if [ "$sketchnum" -le "$start_index" ] \
|| [ "$sketchnum" -gt "$end_index" ]; then
continue
fi
echo ""
echo "Building Sketch Index $(($sketchnum - 1)) - $sketchdirname"
build_sketch "$ide_path" "$usr_path" "$fqbn" "$sketch" "$xtra_opts"
local result=$?
if [ $result -ne 0 ]; then
return $result
fi
done
return 0
}
USAGE="
USAGE: ${0} [command] [options]
Available commands:
count: Count sketches.
build: Build a sketch.
chunk_build: Build a chunk of sketches.
"
cmd=$1
shift
if [ -z $cmd ]; then
echo "ERROR: No command supplied"
echo "$USAGE"
exit 2
fi
case "$cmd" in
"count")
count_sketches $*
;;
"build")
build_sketch $*
;;
"chunk_build")
build_sketches $*
;;
*)
echo "ERROR: Unrecognized command"
echo "$USAGE"
exit 2
esac

View File

@ -1,58 +0,0 @@
#!/bin/bash
SCRIPTS_DIR="./.github/scripts"
BUILD_CMD=""
if [ $# -eq 3 ]; then
chunk_build=1
elif [ $# -eq 2 ]; then
chunk_build=0
else
echo "ERROR: Illegal number of parameters"
echo "USAGE:
${0} <target> <sketch_dir>
${0} <target> <chunk> <total_chunks>
"
exit 0
fi
target=$1
case "$target" in
"esp32") fqbn="espressif:esp32:esp32:PSRAM=enabled,PartitionScheme=huge_app"
;;
"esp32s2") fqbn="espressif:esp32:esp32s2:PSRAM=enabled,PartitionScheme=huge_app"
;;
"esp32c3") fqbn="espressif:esp32:esp32c3:PartitionScheme=huge_app"
;;
"esp32s3") fqbn="espressif:esp32:esp32s3:PSRAM=opi,USBMode=default,PartitionScheme=huge_app"
;;
esac
if [ -z $fqbn ]; then
echo "Unvalid chip $1"
exit 0
fi
source ${SCRIPTS_DIR}/install-arduino-ide.sh
source ${SCRIPTS_DIR}/install-arduino-core-esp32.sh
args="$ARDUINO_IDE_PATH $ARDUINO_USR_PATH \"$fqbn\""
if [ $chunk_build -eq 1 ]; then
chunk_index=$2
chunk_max=$3
if [ "$chunk_index" -gt "$chunk_max" ] && [ "$chunk_max" -ge 2 ]; then
chunk_index=$chunk_max
fi
BUILD_CMD="${SCRIPTS_DIR}/sketch_utils.sh chunk_build"
args+=" $target $PWD/tests $chunk_index $chunk_max"
else
sketchdir=$2
BUILD_CMD="${SCRIPTS_DIR}/sketch_utils.sh build"
args+=" $PWD/tests/$sketchdir/$sketchdir.ino"
fi
${BUILD_CMD} ${args}

View File

@ -1,71 +0,0 @@
#!/bin/bash
target=$1
chunk_idex=$2
chunks_num=$3
SCRIPTS_DIR="./.github/scripts"
COUNT_SKETCHES="${SCRIPTS_DIR}/sketch_utils.sh count"
source ${SCRIPTS_DIR}/install-arduino-ide.sh
if [ "$chunks_num" -le 0 ]; then
echo "ERROR: Chunks count must be positive number"
return 1
fi
if [ "$chunk_idex" -ge "$chunks_num" ] && [ "$chunks_num" -ge 2 ]; then
echo "ERROR: Chunk index must be less than chunks count"
return 1
fi
set +e
${COUNT_SKETCHES} $PWD/tests $target
sketchcount=$?
set -e
sketches=$(cat sketches.txt)
rm -rf sketches.txt
chunk_size=$(( $sketchcount / $chunks_num ))
all_chunks=$(( $chunks_num * $chunk_size ))
if [ "$all_chunks" -lt "$sketchcount" ]; then
chunk_size=$(( $chunk_size + 1 ))
fi
start_index=0
end_index=0
if [ "$chunk_idex" -ge "$chunks_num" ]; then
start_index=$chunk_idex
end_index=$sketchcount
else
start_index=$(( $chunk_idex * $chunk_size ))
if [ "$sketchcount" -le "$start_index" ]; then
echo "Skipping job"
return 0
fi
end_index=$(( $(( $chunk_idex + 1 )) * $chunk_size ))
if [ "$end_index" -gt "$sketchcount" ]; then
end_index=$sketchcount
fi
fi
start_num=$(( $start_index + 1 ))
sketchnum=0
for sketch in $sketches; do
sketchdir=$(dirname $sketch)
sketchdirname=$(basename $sketchdir)
sketchname=$(basename $sketch)
sketchnum=$(($sketchnum + 1))
if [ "$sketchnum" -le "$start_index" ] \
|| [ "$sketchnum" -gt "$end_index" ]; then
continue
fi
echo ""
echo "Test for Sketch Index $(($sketchnum - 1)) - $sketchdirname"
pytest tests -k test_$sketchdirname --junit-xml=tests/$sketchdirname/$sketchdirname.xml
result=$?
if [ $result -ne 0 ]; then
return $result
fi
done

View File

@ -1,39 +0,0 @@
#!/bin/bash
# For reference: add tools for all boards by replacing one line in each board
# "[board].upload.tool=esptool_py" to "[board].upload.tool=esptool_py\n[board].upload.tool.default=esptool_py\n[board].upload.tool.network=esp_ota"
#cat boards.txt | sed "s/\([a-zA-Z0-9_\-]*\)\.upload\.tool\=esptool_py/\1\.upload\.tool\=esptool_py\\n\1\.upload\.tool\.default\=esptool_py\\n\1\.upload\.tool\.network\=esp_ota/"
if [ ! $# -eq 3 ]; then
echo "Bad number of arguments: $#" >&2
echo "usage: $0 <major> <minor> <patch>" >&2
exit 1
fi
re='^[0-9]+$'
if [[ ! $1 =~ $re ]] || [[ ! $2 =~ $re ]] || [[ ! $3 =~ $re ]] ; then
echo "error: Not a valid version: $1.$2.$3" >&2
echo "usage: $0 <major> <minor> <patch>" >&2
exit 1
fi
ESP_ARDUINO_VERSION_MAJOR="$1"
ESP_ARDUINO_VERSION_MINOR="$2"
ESP_ARDUINO_VERSION_PATCH="$3"
ESP_ARDUINO_VERSION="$ESP_ARDUINO_VERSION_MAJOR.$ESP_ARDUINO_VERSION_MINOR.$ESP_ARDUINO_VERSION_PATCH"
echo "New Arduino Version: $ESP_ARDUINO_VERSION"
echo "Updating platform.txt..."
cat platform.txt | sed "s/version=.*/version=$ESP_ARDUINO_VERSION/g" > __platform.txt && mv __platform.txt platform.txt
echo "Updating package.json..."
cat package.json | sed "s/.*\"version\":.*/ \"version\": \"$ESP_ARDUINO_VERSION\",/g" > __package.json && mv __package.json package.json
echo "Updating cores/esp32/esp_arduino_version.h..."
cat cores/esp32/esp_arduino_version.h | \
sed "s/#define ESP_ARDUINO_VERSION_MAJOR.*/#define ESP_ARDUINO_VERSION_MAJOR $ESP_ARDUINO_VERSION_MAJOR/g" | \
sed "s/#define ESP_ARDUINO_VERSION_MINOR.*/#define ESP_ARDUINO_VERSION_MINOR $ESP_ARDUINO_VERSION_MINOR/g" | \
sed "s/#define ESP_ARDUINO_VERSION_PATCH.*/#define ESP_ARDUINO_VERSION_PATCH $ESP_ARDUINO_VERSION_PATCH/g" > __esp_arduino_version.h && mv __esp_arduino_version.h cores/esp32/esp_arduino_version.h
exit 0

64
.github/stale.yml vendored Normal file
View File

@ -0,0 +1,64 @@
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 60
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
daysUntilClose: 14
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
onlyLabels: []
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
exemptLabels:
- pinned
- security
- "to be implemented"
- "for reference"
- "move to PR"
- "enhancement"
# Set to true to ignore issues in a project (defaults to false)
exemptProjects: false
# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: false
# Set to true to ignore issues with an assignee (defaults to false)
exemptAssignees: false
# Label to use when marking as stale
staleLabel: stale
# Comment to post when marking as stale. Set to `false` to disable
markComment: >
[STALE_SET] This issue has been automatically marked as stale because it has not had
recent activity. It will be closed in 14 days if no further activity occurs. Thank you
for your contributions.
# Comment to post when removing the stale label.
unmarkComment: >
[STALE_CLR] This issue has been removed from the stale queue. Please ensure activity to keep it openin the future.
# Comment to post when closing a stale Issue or Pull Request.
closeComment: >
[STALE_DEL] This stale issue has been automatically closed. Thank you for your contributions.
# Limit the number of actions per hour, from 1-30. Default is 30
limitPerRun: 30
# Limit to only `issues` or `pulls`
only: issues
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
# pulls:
# daysUntilStale: 30
# markComment: >
# This pull request has been automatically marked as stale because it has not had
# recent activity. It will be closed if no further activity occurs. Thank you
# for your contributions.
# issues:
# exemptLabels:
# - confirmed

View File

@ -1,38 +0,0 @@
name: ReadTheDocs CI
on:
push:
branches:
- master
- release/*
paths:
- 'docs/**'
- '.github/workflows/docs.yml'
pull_request:
paths:
- 'docs/**'
- '.github/workflows/docs.yml'
jobs:
build-docs:
name: Build ReadTheDocs
runs-on: ubuntu-latest
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v2
with:
submodules: true
- uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Build
run: |
sudo apt update
sudo apt install python3-pip python3-setuptools
# GitHub CI installs pip3 and setuptools outside the path.
# Update the path to include them and run.
PATH=/home/runner/.local/bin:$PATH pip3 install --user -r ./docs/requirements.txt
cd ./docs && PATH=/home/runner/.local/bin:$PATH SPHINXOPTS="-W" make html

View File

@ -4,11 +4,9 @@ on:
push: push:
branches: branches:
- master - master
- pages
paths: paths:
- 'README.md' - 'README.md'
- '.github/scripts/on-pages.sh' - 'docs/**'
- '.github/workflows/gh-pages.yml'
jobs: jobs:
@ -16,7 +14,7 @@ jobs:
name: Build GitHub Pages name: Build GitHub Pages
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v1
- name: Copy Files - name: Copy Files
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1,123 +0,0 @@
name: Run tests in hardware
on:
pull_request:
types: [opened, reopened, synchronize, labeled]
schedule:
- cron: '0 2 * * *'
env:
MAX_CHUNKS: 15
concurrency:
group: hil-${{github.event.pull_request.number || github.ref}}
cancel-in-progress: true
jobs:
gen_chunks:
if: |
contains(github.event.pull_request.labels.*.name, 'hil_test') ||
(github.event_name == 'schedule' && github.repository == 'espressif/arduino-esp32')
name: Generate Chunks matrix
runs-on: ubuntu-latest
outputs:
chunks: ${{ steps.gen-chunks.outputs.chunks }}
steps:
- name: Checkout Repository
uses: actions/checkout@v2
- name: Generate Chunks matrix
id: gen-chunks
run: |
set +e
bash .github/scripts/sketch_utils.sh count tests
sketches=$((? - 1))
if [[ $sketches -gt ${{env.MAX_CHUNKS}} ]]; then
$sketches=${{env.MAX_CHUNKS}}
fi
set -e
rm sketches.txt
CHUNKS=$(jq -c -n '$ARGS.positional' --args `seq 0 1 $sketches`)
echo "::set-output name=chunks::${CHUNKS}"
Build:
needs: gen_chunks
name: ${{matrix.chip}}-Build#${{matrix.chunks}}
runs-on: ubuntu-latest
strategy:
matrix:
chip: ['esp32', 'esp32s2', 'esp32s3', 'esp32c3']
chunks: ${{fromJson(needs.gen_chunks.outputs.chunks)}}
steps:
- name: Checkout Repository
uses: actions/checkout@v2
- name: Build sketches
run: |
bash .github/scripts/tests_build.sh ${{matrix.chip}} ${{matrix.chunks}} ${{env.MAX_CHUNKS}}
- name: Upload ${{matrix.chip}}-${{matrix.chunks}} artifacts
uses: actions/upload-artifact@v2
with:
name: ${{matrix.chip}}-${{matrix.chunks}}.artifacts
path: |
tests/*/build/*.bin
tests/*/build/*.json
Test:
needs: [gen_chunks, Build]
name: ${{matrix.chip}}-Test#${{matrix.chunks}}
runs-on:
- ESP32
- ESP32-S2
- ESP32-S3
- ESP32-C3
strategy:
fail-fast: false
matrix:
chip: ['esp32', 'esp32s2', 'esp32s3', 'esp32c3']
chunks: ${{fromJson(needs.gen_chunks.outputs.chunks)}}
container:
image: python:3.10.1-bullseye
options: --privileged
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Download ${{matrix.chip}}-${{matrix.chunks}} artifacts
uses: actions/download-artifact@v2
with:
name: ${{matrix.chip}}-${{matrix.chunks}}.artifacts
path: tests/
- name: Install dependencies
run: |
pip install -U pip
pip install -r tests/requirements.txt
- name: Run Tests
run: |
bash .github/scripts/tests_run.sh ${{matrix.chip}} ${{matrix.chunks}} ${{env.MAX_CHUNKS}}
- name: Upload test result artifacts
uses: actions/upload-artifact@v2
if: always()
with:
name: test_results-${{matrix.chip}}-${{matrix.chunks}}
path: tests/*/*.xml
event_file:
name: "Event File"
if: |
contains(github.event.pull_request.labels.*.name, 'hil_test') ||
github.event_name == 'schedule'
needs: Test
runs-on: ubuntu-latest
steps:
- name: Upload
uses: actions/upload-artifact@v2
with:
name: Event File
path: ${{github.event_path}}

View File

@ -1,38 +0,0 @@
name: Unit Test Results
on:
workflow_run:
workflows: [Run tests in hardware]
branches-ignore: [master]
types:
- completed
jobs:
unit-test-results:
name: Unit Test Results
runs-on: ubuntu-latest
if: |
github.event.workflow_run.event == 'pull_request' &&
(github.event.workflow_run.conclusion == 'success' ||
github.event.workflow_run.conclusion == 'failure')
steps:
- name: Download and Extract Artifacts
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
run: |
mkdir -p artifacts && cd artifacts
artifacts_url=${{ github.event.workflow_run.artifacts_url }}
gh api "$artifacts_url" -q '.artifacts[] | [.name, .archive_download_url] | @tsv' | while read artifact
do
IFS=$'\t' read name url <<< "$artifact"
gh api $url > "$name.zip"
unzip -d "$name" "$name.zip"
done
- name: Publish Unit Test Results
uses: EnricoMi/publish-unit-test-result-action@v1
with:
commit: ${{ github.event.workflow_run.head_sha }}
event_file: artifacts/Event File/event.json
event_name: ${{ github.event.workflow_run.event }}
files: "artifacts/**/*.xml"

View File

@ -1,26 +1,14 @@
name: ESP32 Arduino CI name: ESP32 Arduino CI
on: on:
workflow_dispatch:
push: push:
branches: branches:
- master - master
- release/* - release/*
pull_request: pull_request:
concurrency:
group: build-${{github.event.pull_request.number || github.ref}}
cancel-in-progress: true
jobs: jobs:
cmake-check:
name: Check cmake file
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: bash ./.github/scripts/check-cmakelists.sh
# Ubuntu # Ubuntu
build-arduino-linux: build-arduino-linux:
name: Arduino ${{ matrix.chunk }} on ubuntu-latest name: Arduino ${{ matrix.chunk }} on ubuntu-latest
@ -30,20 +18,10 @@ jobs:
chunk: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] chunk: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v1
- uses: actions/setup-python@v2 - uses: actions/setup-python@v1
with: with:
python-version: '3.x' python-version: '3.x'
- name: Cache tools
id: cache-linux
uses: actions/cache@v2
with:
path: |
./tools/dist
~/arduino_ide
key: ${{ runner.os }}-${{ hashFiles('package/package_esp32_index.template.json',
'tools/get.py',
'.github/scripts/install-arduino-ide.sh') }}
- name: Build Sketches - name: Build Sketches
run: bash ./.github/scripts/on-push.sh ${{ matrix.chunk }} 15 run: bash ./.github/scripts/on-push.sh ${{ matrix.chunk }} 15
@ -56,8 +34,8 @@ jobs:
os: [windows-latest, macOS-latest] os: [windows-latest, macOS-latest]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v1
- uses: actions/setup-python@v2 - uses: actions/setup-python@v1
with: with:
python-version: '3.x' python-version: '3.x'
- name: Build Sketches - name: Build Sketches
@ -72,36 +50,9 @@ jobs:
os: [ubuntu-latest, windows-latest, macOS-latest] os: [ubuntu-latest, windows-latest, macOS-latest]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v1
- uses: actions/setup-python@v2 - uses: actions/setup-python@v1
with: with:
python-version: '3.x' python-version: '3.x'
- name: Build Sketches - name: Build Sketches
run: bash ./.github/scripts/on-push.sh 1 1 #equal and non-zero to trigger PIO run: bash ./.github/scripts/on-push.sh 1 1 #equal and non-zero to trigger PIO
build-esp-idf-component:
name: Build with ESP-IDF ${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
runs-on: ubuntu-20.04
strategy:
matrix:
# The version names here correspond to the versions of espressif/idf Docker image.
# See https://hub.docker.com/r/espressif/idf/tags and
# https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-docker-image.html
# for details.
idf_ver: ["release-v4.4"]
idf_target: ["esp32", "esp32s2", "esp32s3", "esp32c3"]
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Check out arduino-esp32 as a component
uses: actions/checkout@v2
with:
submodules: recursive
path: components/arduino-esp32
- name: Build
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
idf.py create-project test
idf.py -C test -DEXTRA_COMPONENT_DIRS=$PWD/components build

View File

@ -10,10 +10,8 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@master
with: - uses: actions/setup-python@v1
fetch-depth: 0
- uses: actions/setup-python@v2
with: with:
python-version: '3.x' python-version: '3.x'
- name: Build Release - name: Build Release

View File

@ -1,19 +0,0 @@
name: Push components to https://components.espressif.com
on:
push:
tags:
- '*'
jobs:
upload_components:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: "recursive"
- name: Upload components to the component registry
uses: espressif/github-actions/upload_components@master
with:
name: arduino-esp32
namespace: espressif
api_token: ${{ secrets.IDF_COMPONENT_API_TOKEN }}

15
.gitignore vendored
View File

@ -1,13 +1,10 @@
tools/xtensa-esp32-elf tools/xtensa-esp32-elf
tools/xtensa-esp32s2-elf tools/xtensa-esp32s2-elf
tools/xtensa-esp32s3-elf
tools/riscv32-esp-elf
tools/dist tools/dist
tools/esptool tools/esptool
tools/esptool.exe tools/esptool.exe
tools/mkspiffs tools/mkspiffs/mkspiffs
tools/mklittlefs tools/mkspiffs/mkspiffs.exe
tools/mkfatfs.exe
.DS_Store .DS_Store
#Ignore files built by Visual Studio/Visual Micro #Ignore files built by Visual Studio/Visual Micro
@ -19,10 +16,4 @@ __vm/
.vscode/ .vscode/
platform.sloeber.txt platform.sloeber.txt
boards.sloeber.txt boards.sloeber.txt
tools/mklittlefs
# Ignore docs build (Sphinx)
docs/build
docs/source/_build
# Test log files
*.log

55
.travis.yml Normal file
View File

@ -0,0 +1,55 @@
sudo: false
language: python
os:
- linux
git:
depth: false
before_install:
- git submodule update --init --recursive
stages:
- build
- deploy
jobs:
include:
- name: "Build Arduino 0"
if: tag IS blank AND (type = pull_request OR (type = push AND branch = master))
stage: build
script: $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh 0 10
- name: "Build Arduino 1"
if: tag IS blank AND (type = pull_request OR (type = push AND branch = master))
stage: build
script: $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh 1 10
- name: "Build Arduino 2"
if: tag IS blank AND (type = pull_request OR (type = push AND branch = master))
stage: build
script: $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh 2 10
- name: "Build Arduino 3"
if: tag IS blank AND (type = pull_request OR (type = push AND branch = master))
stage: build
script: $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh 3 10
- name: "Build PlatformIO"
if: tag IS blank AND (type = pull_request OR (type = push AND branch = master))
stage: build
script: $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh 1 1
notifications:
email:
on_success: change
on_failure: change
webhooks:
urls:
- https://webhooks.gitter.im/e/cb057279c430d91a47a8
on_success: change # options: [always|never|change] default: always
on_failure: always # options: [always|never|change] default: always
on_start: never # options: [always|never|change] default: always

View File

@ -1,27 +1,3 @@
# Check ESP-IDF version and error out if it is not in the supported range.
#
# Note for arduino-esp32 developers: to bypass the version check locally,
# set ARDUINO_SKIP_IDF_VERSION_CHECK environment variable to 1. For example:
# export ARDUINO_SKIP_IDF_VERSION_CHECK=1
# idf.py build
set(min_supported_idf_version "4.4.0")
set(max_supported_idf_version "4.4.99")
set(idf_version "${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}.${IDF_VERSION_PATCH}")
if ("${idf_version}" AND NOT "$ENV{ARDUINO_SKIP_IDF_VERSION_CHECK}")
if (idf_version VERSION_LESS min_supported_idf_version)
message(FATAL_ERROR "Arduino-esp32 can be used with ESP-IDF versions "
"between ${min_supported_idf_version} and ${max_supported_idf_version}, "
"but an older version is detected: ${idf_version}.")
endif()
if (idf_version VERSION_GREATER max_supported_idf_version)
message(FATAL_ERROR "Arduino-esp32 can be used with ESP-IDF versions "
"between ${min_supported_idf_version} and ${max_supported_idf_version}, "
"but a newer version is detected: ${idf_version}.")
endif()
endif()
set(CORE_SRCS set(CORE_SRCS
cores/esp32/base64.cpp cores/esp32/base64.cpp
cores/esp32/cbuf.cpp cores/esp32/cbuf.cpp
@ -31,7 +7,6 @@ set(CORE_SRCS
cores/esp32/esp32-hal-dac.c cores/esp32/esp32-hal-dac.c
cores/esp32/esp32-hal-gpio.c cores/esp32/esp32-hal-gpio.c
cores/esp32/esp32-hal-i2c.c cores/esp32/esp32-hal-i2c.c
cores/esp32/esp32-hal-i2c-slave.c
cores/esp32/esp32-hal-ledc.c cores/esp32/esp32-hal-ledc.c
cores/esp32/esp32-hal-matrix.c cores/esp32/esp32-hal-matrix.c
cores/esp32/esp32-hal-misc.c cores/esp32/esp32-hal-misc.c
@ -57,13 +32,8 @@ set(CORE_SRCS
cores/esp32/stdlib_noniso.c cores/esp32/stdlib_noniso.c
cores/esp32/Stream.cpp cores/esp32/Stream.cpp
cores/esp32/StreamString.cpp cores/esp32/StreamString.cpp
cores/esp32/Tone.cpp
cores/esp32/HWCDC.cpp
cores/esp32/USB.cpp cores/esp32/USB.cpp
cores/esp32/USBCDC.cpp cores/esp32/USBCDC.cpp
cores/esp32/USBMSC.cpp
cores/esp32/FirmwareMSC.cpp
cores/esp32/firmware_msc_fat.c
cores/esp32/wiring_pulse.c cores/esp32/wiring_pulse.c
cores/esp32/wiring_shift.c cores/esp32/wiring_shift.c
cores/esp32/WMath.cpp cores/esp32/WMath.cpp
@ -74,29 +44,17 @@ set(LIBRARY_SRCS
libraries/ArduinoOTA/src/ArduinoOTA.cpp libraries/ArduinoOTA/src/ArduinoOTA.cpp
libraries/AsyncUDP/src/AsyncUDP.cpp libraries/AsyncUDP/src/AsyncUDP.cpp
libraries/BluetoothSerial/src/BluetoothSerial.cpp libraries/BluetoothSerial/src/BluetoothSerial.cpp
libraries/BluetoothSerial/src/BTAddress.cpp
libraries/BluetoothSerial/src/BTAdvertisedDeviceSet.cpp
libraries/BluetoothSerial/src/BTScanResultsSet.cpp
libraries/DNSServer/src/DNSServer.cpp libraries/DNSServer/src/DNSServer.cpp
libraries/EEPROM/src/EEPROM.cpp libraries/EEPROM/src/EEPROM.cpp
libraries/ESPmDNS/src/ESPmDNS.cpp libraries/ESPmDNS/src/ESPmDNS.cpp
libraries/Ethernet/src/ETH.cpp
libraries/FFat/src/FFat.cpp libraries/FFat/src/FFat.cpp
libraries/FS/src/FS.cpp libraries/FS/src/FS.cpp
libraries/FS/src/vfs_api.cpp libraries/FS/src/vfs_api.cpp
libraries/HTTPClient/src/HTTPClient.cpp libraries/HTTPClient/src/HTTPClient.cpp
libraries/HTTPUpdate/src/HTTPUpdate.cpp libraries/HTTPUpdate/src/HTTPUpdate.cpp
libraries/LittleFS/src/LittleFS.cpp libraries/LITTLEFS/src/LITTLEFS.cpp
libraries/I2S/src/I2S.cpp
libraries/NetBIOS/src/NetBIOS.cpp libraries/NetBIOS/src/NetBIOS.cpp
libraries/Preferences/src/Preferences.cpp libraries/Preferences/src/Preferences.cpp
libraries/RainMaker/src/RMaker.cpp
libraries/RainMaker/src/RMakerNode.cpp
libraries/RainMaker/src/RMakerParam.cpp
libraries/RainMaker/src/RMakerDevice.cpp
libraries/RainMaker/src/RMakerType.cpp
libraries/RainMaker/src/RMakerQR.cpp
libraries/RainMaker/src/RMakerUtils.cpp
libraries/SD_MMC/src/SD_MMC.cpp libraries/SD_MMC/src/SD_MMC.cpp
libraries/SD/src/SD.cpp libraries/SD/src/SD.cpp
libraries/SD/src/sd_diskio.cpp libraries/SD/src/sd_diskio.cpp
@ -107,20 +65,12 @@ set(LIBRARY_SRCS
libraries/Ticker/src/Ticker.cpp libraries/Ticker/src/Ticker.cpp
libraries/Update/src/Updater.cpp libraries/Update/src/Updater.cpp
libraries/Update/src/HttpsOTAUpdate.cpp libraries/Update/src/HttpsOTAUpdate.cpp
libraries/USB/src/USBHID.cpp
libraries/USB/src/USBHIDMouse.cpp
libraries/USB/src/USBHIDKeyboard.cpp
libraries/USB/src/USBHIDGamepad.cpp
libraries/USB/src/USBHIDConsumerControl.cpp
libraries/USB/src/USBHIDSystemControl.cpp
libraries/USB/src/USBHIDVendor.cpp
libraries/USB/src/USBVendor.cpp
libraries/WebServer/src/WebServer.cpp libraries/WebServer/src/WebServer.cpp
libraries/WebServer/src/Parsing.cpp libraries/WebServer/src/Parsing.cpp
libraries/WebServer/src/detail/mimetable.cpp libraries/WebServer/src/detail/mimetable.cpp
libraries/WiFiClientSecure/src/ssl_client.cpp libraries/WiFiClientSecure/src/ssl_client.cpp
libraries/WiFiClientSecure/src/esp_crt_bundle.c
libraries/WiFiClientSecure/src/WiFiClientSecure.cpp libraries/WiFiClientSecure/src/WiFiClientSecure.cpp
libraries/WiFi/src/ETH.cpp
libraries/WiFi/src/WiFiAP.cpp libraries/WiFi/src/WiFiAP.cpp
libraries/WiFi/src/WiFiClient.cpp libraries/WiFi/src/WiFiClient.cpp
libraries/WiFi/src/WiFi.cpp libraries/WiFi/src/WiFi.cpp
@ -166,8 +116,9 @@ set(BLE_SRCS
libraries/BLE/src/GeneralUtils.cpp libraries/BLE/src/GeneralUtils.cpp
) )
set(includedirs set(includedirs
variants/${IDF_TARGET}/ variants/esp32/
cores/esp32/ cores/esp32/
libraries/ArduinoOTA/src libraries/ArduinoOTA/src
libraries/AsyncUDP/src libraries/AsyncUDP/src
@ -177,16 +128,13 @@ set(includedirs
libraries/EEPROM/src libraries/EEPROM/src
libraries/ESP32/src libraries/ESP32/src
libraries/ESPmDNS/src libraries/ESPmDNS/src
libraries/Ethernet/src
libraries/FFat/src libraries/FFat/src
libraries/FS/src libraries/FS/src
libraries/HTTPClient/src libraries/HTTPClient/src
libraries/HTTPUpdate/src libraries/HTTPUpdate/src
libraries/LittleFS/src libraries/LITTLEFS/src
libraries/I2S/src
libraries/NetBIOS/src libraries/NetBIOS/src
libraries/Preferences/src libraries/Preferences/src
libraries/RainMaker/src
libraries/SD_MMC/src libraries/SD_MMC/src
libraries/SD/src libraries/SD/src
libraries/SimpleBLE/src libraries/SimpleBLE/src
@ -194,7 +142,6 @@ set(includedirs
libraries/SPI/src libraries/SPI/src
libraries/Ticker/src libraries/Ticker/src
libraries/Update/src libraries/Update/src
libraries/USB/src
libraries/WebServer/src libraries/WebServer/src
libraries/WiFiClientSecure/src libraries/WiFiClientSecure/src
libraries/WiFi/src libraries/WiFi/src
@ -204,53 +151,14 @@ set(includedirs
set(srcs ${CORE_SRCS} ${LIBRARY_SRCS} ${BLE_SRCS}) set(srcs ${CORE_SRCS} ${LIBRARY_SRCS} ${BLE_SRCS})
set(priv_includes cores/esp32/libb64) set(priv_includes cores/esp32/libb64)
set(requires spi_flash mbedtls mdns esp_adc_cal wifi_provisioning nghttp wpa_supplicant) set(requires spi_flash mbedtls mdns esp_adc_cal)
set(priv_requires fatfs nvs_flash app_update spiffs bootloader_support openssl bt esp_ipc esp_hid) set(priv_requires fatfs nvs_flash app_update spiffs bootloader_support openssl bt tinyusb main)
idf_component_register(INCLUDE_DIRS ${includedirs} PRIV_INCLUDE_DIRS ${priv_includes} SRCS ${srcs} REQUIRES ${requires} PRIV_REQUIRES ${priv_requires}) idf_component_register(INCLUDE_DIRS ${includedirs} PRIV_INCLUDE_DIRS ${priv_includes} SRCS ${srcs} REQUIRES ${requires} PRIV_REQUIRES ${priv_requires})
string(TOUPPER ${CONFIG_IDF_TARGET} idf_target_caps) if(IDF_TARGET STREQUAL "esp32")
target_compile_options(${COMPONENT_TARGET} PUBLIC target_compile_options(${COMPONENT_TARGET} PUBLIC -DARDUINO=10812 -DARDUINO_ESP32_DEV -DARDUINO_ARCH_ESP32 -DARDUINO_BOARD="ESP32_DEV" -DARDUINO_VARIANT="esp32" -DESP32)
-DARDUINO=10812
-DARDUINO_${idf_target_caps}_DEV
-DARDUINO_ARCH_ESP32
-DARDUINO_BOARD="${idf_target_caps}_DEV"
-DARDUINO_VARIANT="${CONFIG_IDF_TARGET}"
-DESP32)
if(CONFIG_AUTOSTART_ARDUINO)
# in autostart mode, arduino-esp32 contains app_main() function and needs to
# reference setup() and loop() in the main component. If we add main
# component to priv_requires then we create a large circular dependency
# (arduino-esp32 -> main -> arduino-esp32) and can get linker errors, so
# instead we add setup() and loop() to the undefined symbols list so the
# linker will always include them.
#
# (As they are C++ symbol, we need to add the C++ mangled names.)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u _Z5setupv -u _Z4loopv")
endif() endif()
if(IDF_TARGET STREQUAL "esp32s2")
# This function adds a dependency on the given component if the component is included into the build. target_compile_options(${COMPONENT_TARGET} PUBLIC -DARDUINO=10812 -DARDUINO_ESP32S2_DEV -DARDUINO_ARCH_ESP32 -DARDUINO_BOARD="ESP32S2_DEV" -DARDUINO_VARIANT="esp32s2" -DESP32)
function(maybe_add_component component_name)
idf_build_get_property(components BUILD_COMPONENTS)
if (${component_name} IN_LIST components)
idf_component_get_property(lib_name ${component_name} COMPONENT_LIB)
target_link_libraries(${COMPONENT_LIB} PUBLIC ${lib_name})
endif()
endfunction()
maybe_add_component(esp-dsp)
if(CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK)
maybe_add_component(esp_rainmaker)
maybe_add_component(qrcode)
endif()
if(IDF_TARGET MATCHES "esp32s2|esp32s3" AND CONFIG_TINYUSB_ENABLED)
maybe_add_component(arduino_tinyusb)
endif()
if(NOT CONFIG_ARDUINO_SELECTIVE_COMPILATION OR CONFIG_ARDUINO_SELECTIVE_ArduinoOTA)
maybe_add_component(esp_https_ota)
endif()
if(NOT CONFIG_ARDUINO_SELECTIVE_COMPILATION OR CONFIG_ARDUINO_SELECTIVE_LITTLEFS)
maybe_add_component(esp_littlefs)
endif() endif()

View File

@ -1,50 +0,0 @@
Contributions Guide
===================
We welcome contributions to the Arduino ESP32 project!
How to Contribute
-----------------
Contributions to Arduino ESP32 - fixing bugs, adding features, adding documentation - are welcome. We accept contributions via `Github Pull Requests <https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests>`_.
Before Contributing
-------------------
Before sending us a Pull Request, please consider this list of points:
* Is the contribution entirely your own work, or already licensed under an LGPL 2.1 compatible Open Source License? If not then we unfortunately cannot accept it.
* Is the code adequately commented for people to understand how it is structured?
* Is there documentation or examples that go with code contributions?
* Are comments and documentation written in clear English, with no spelling or grammar errors?
* Example contributions are also welcome.
* If the contribution contains multiple commits, are they grouped together into logical changes (one major change per pull request)? Are any commits with names like "fixed typo" `squashed into previous commits <https://eli.thegreenplace.net/2014/02/19/squashing-github-pull-requests-into-a-single-commit/>`_?
* If you're unsure about any of these points, please open the Pull Request anyhow and then ask us for feedback.
Pull Request Process
--------------------
After you open the Pull Request, there will probably be some discussion in the comments field of the request itself.
Once the Pull Request is ready to merge, it will first be merged into our internal git system for in-house automated testing.
If this process passes, it will be merged onto the public github repository.
Legal Part
----------
Before a contribution can be accepted, you will need to sign our :doc:`contributor-agreement`. You will be prompted for this automatically as part of the Pull Request process.
Related Documents
-----------------
.. toctree::
:maxdepth: 1
contributor-agreement

View File

@ -21,8 +21,7 @@ config AUTOSTART_ARDUINO
choice ARDUINO_RUNNING_CORE choice ARDUINO_RUNNING_CORE
bool "Core on which Arduino's setup() and loop() are running" bool "Core on which Arduino's setup() and loop() are running"
default ARDUINO_RUN_CORE0 if FREERTOS_UNICORE default ARDUINO_RUN_CORE1
default ARDUINO_RUN_CORE1 if !FREERTOS_UNICORE
help help
Select on which core Arduino's setup() and loop() functions run Select on which core Arduino's setup() and loop() functions run
@ -30,10 +29,8 @@ choice ARDUINO_RUNNING_CORE
bool "CORE 0" bool "CORE 0"
config ARDUINO_RUN_CORE1 config ARDUINO_RUN_CORE1
bool "CORE 1" bool "CORE 1"
depends on !FREERTOS_UNICORE
config ARDUINO_RUN_NO_AFFINITY config ARDUINO_RUN_NO_AFFINITY
bool "BOTH" bool "BOTH"
depends on !FREERTOS_UNICORE
endchoice endchoice
@ -43,16 +40,9 @@ config ARDUINO_RUNNING_CORE
default 1 if ARDUINO_RUN_CORE1 default 1 if ARDUINO_RUN_CORE1
default -1 if ARDUINO_RUN_NO_AFFINITY default -1 if ARDUINO_RUN_NO_AFFINITY
config ARDUINO_LOOP_STACK_SIZE
int "Loop thread stack size"
default 8192
help
Amount of stack available for the Arduino task.
choice ARDUINO_EVENT_RUNNING_CORE choice ARDUINO_EVENT_RUNNING_CORE
bool "Core on which Arduino's event handler is running" bool "Core on which Arduino's event handler is running"
default ARDUINO_EVENT_RUN_CORE0 if FREERTOS_UNICORE default ARDUINO_EVENT_RUN_CORE1
default ARDUINO_EVENT_RUN_CORE1 if !FREERTOS_UNICORE
help help
Select on which core Arduino's WiFi.onEvent() run Select on which core Arduino's WiFi.onEvent() run
@ -60,10 +50,8 @@ choice ARDUINO_EVENT_RUNNING_CORE
bool "CORE 0" bool "CORE 0"
config ARDUINO_EVENT_RUN_CORE1 config ARDUINO_EVENT_RUN_CORE1
bool "CORE 1" bool "CORE 1"
depends on !FREERTOS_UNICORE
config ARDUINO_EVENT_RUN_NO_AFFINITY config ARDUINO_EVENT_RUN_NO_AFFINITY
bool "BOTH" bool "BOTH"
depends on !FREERTOS_UNICORE
endchoice endchoice
@ -73,45 +61,9 @@ config ARDUINO_EVENT_RUNNING_CORE
default 1 if ARDUINO_EVENT_RUN_CORE1 default 1 if ARDUINO_EVENT_RUN_CORE1
default -1 if ARDUINO_EVENT_RUN_NO_AFFINITY default -1 if ARDUINO_EVENT_RUN_NO_AFFINITY
choice ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE
bool "Core on which Arduino's Serial Event task is running"
default ARDUINO_SERIAL_EVENT_RUN_CORE0 if FREERTOS_UNICORE
default ARDUINO_SERIAL_EVENT_RUN_NO_AFFINITY if !FREERTOS_UNICORE
help
Select on which core Arduino's Serial Event task run
config ARDUINO_SERIAL_EVENT_RUN_CORE0
bool "CORE 0"
config ARDUINO_SERIAL_EVENT_RUN_CORE1
bool "CORE 1"
depends on !FREERTOS_UNICORE
config ARDUINO_SERIAL_EVENT_RUN_NO_AFFINITY
bool "BOTH"
depends on !FREERTOS_UNICORE
endchoice
config ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE
int
default 0 if ARDUINO_SERIAL_EVENT_RUN_CORE0
default 1 if ARDUINO_SERIAL_EVENT_RUN_CORE1
default -1 if ARDUINO_SERIAL_EVENT_RUN_NO_AFFINITY
config ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE
int "Serial Event task stack size"
default 2048
help
Amount of stack available for the Serial Event task.
config ARDUINO_SERIAL_EVENT_TASK_PRIORITY
int "Priority of the Serial Event task"
default 24
help
Select at what priority you want the Serial Event task to run.
choice ARDUINO_UDP_RUNNING_CORE choice ARDUINO_UDP_RUNNING_CORE
bool "Core on which Arduino's UDP is running" bool "Core on which Arduino's UDP is running"
default ARDUINO_UDP_RUN_CORE0 default ARDUINO_UDP_RUN_CORE1
help help
Select on which core Arduino's UDP run Select on which core Arduino's UDP run
@ -119,25 +71,23 @@ choice ARDUINO_UDP_RUNNING_CORE
bool "CORE 0" bool "CORE 0"
config ARDUINO_UDP_RUN_CORE1 config ARDUINO_UDP_RUN_CORE1
bool "CORE 1" bool "CORE 1"
depends on !FREERTOS_UNICORE
config ARDUINO_UDP_RUN_NO_AFFINITY config ARDUINO_UDP_RUN_NO_AFFINITY
bool "BOTH" bool "BOTH"
depends on !FREERTOS_UNICORE
endchoice endchoice
config ARDUINO_UDP_RUNNING_CORE
int
default 0 if ARDUINO_UDP_RUN_CORE0
default 1 if ARDUINO_UDP_RUN_CORE1
default -1 if ARDUINO_UDP_RUN_NO_AFFINITY
config ARDUINO_UDP_TASK_PRIORITY config ARDUINO_UDP_TASK_PRIORITY
int "Priority of the UDP task" int "Priority of the UDP task"
default 3 default 3
help help
Select at what priority you want the UDP task to run. Select at what priority you want the UDP task to run.
config ARDUINO_UDP_RUNNING_CORE
int
default 0 if ARDUINO_UDP_RUN_CORE0
default 1 if ARDUINO_UDP_RUN_CORE1
default -1 if ARDUINO_UDP_RUN_NO_AFFINITY
config ARDUINO_ISR_IRAM config ARDUINO_ISR_IRAM
bool "Run interrupts in IRAM" bool "Run interrupts in IRAM"
default "n" default "n"
@ -315,12 +265,6 @@ config ARDUINO_SELECTIVE_HTTPClient
select ARDUINO_SELECTIVE_WiFiClientSecure select ARDUINO_SELECTIVE_WiFiClientSecure
default y default y
config ARDUINO_SELECTIVE_LITTLEFS
bool "Enable LITTLEFS"
depends on ARDUINO_SELECTIVE_COMPILATION
select ARDUINO_SELECTIVE_FS
default y
config ARDUINO_SELECTIVE_NetBIOS config ARDUINO_SELECTIVE_NetBIOS
bool "Enable NetBIOS" bool "Enable NetBIOS"
depends on ARDUINO_SELECTIVE_COMPILATION depends on ARDUINO_SELECTIVE_COMPILATION
@ -387,12 +331,6 @@ config ARDUINO_SELECTIVE_WiFiClientSecure
select ARDUINO_SELECTIVE_WiFi select ARDUINO_SELECTIVE_WiFi
default y default y
config ARDUINO_SELECTIVE_WiFiProv
bool "Enable WiFiProv"
depends on ARDUINO_SELECTIVE_COMPILATION
select ARDUINO_SELECTIVE_WiFi
default y
config ARDUINO_SELECTIVE_Wire config ARDUINO_SELECTIVE_Wire
bool "Enable Wire" bool "Enable Wire"
depends on ARDUINO_SELECTIVE_COMPILATION depends on ARDUINO_SELECTIVE_COMPILATION
@ -400,4 +338,3 @@ config ARDUINO_SELECTIVE_Wire
endmenu endmenu

7
Makefile.projbuild Normal file
View File

@ -0,0 +1,7 @@
BOOT_APP_BIN_ROOT := $(call dequote,$(COMPONENT_PATH))
ifndef CONFIG_PARTITION_TABLE_CUSTOM
PARTITION_TABLE_CSV_PATH = $(call dequote,$(abspath $(BOOT_APP_BIN_ROOT)/$(subst $(quote),,tools/partitions/$(CONFIG_ARDUHAL_PARTITION_SCHEME).csv)))
endif
CPPFLAGS += -DARDUINO=10800 -DESP32=1 -DARDUINO_ARCH_ESP32=1 -DBOARD_HAS_PSRAM

View File

@ -1,58 +1,49 @@
# Arduino core for the ESP32, ESP32-S2, ESP32-S3 and ESP32-C3 # Arduino core for the ESP32
[![Build Status](https://travis-ci.org/espressif/arduino-esp32.svg?branch=master)](https://travis-ci.org/espressif/arduino-esp32) ![](https://github.com/espressif/arduino-esp32/workflows/ESP32%20Arduino%20CI/badge.svg)
![Build Status](https://github.com/espressif/arduino-esp32/workflows/ESP32%20Arduino%20CI/badge.svg) [![Documentation Status](https://readthedocs.com/projects/espressif-arduino-esp32/badge/?version=latest)](https://docs.espressif.com/projects/arduino-esp32/en/latest/?badge=latest) ### Need help or have a question? Join the chat at [![https://gitter.im/espressif/arduino-esp32](https://badges.gitter.im/espressif/arduino-esp32.svg)](https://gitter.im/espressif/arduino-esp32?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
### Need help or have a question? Join the chat at [![https://gitter.im/espressif/arduino-esp32](https://badges.gitter.im/espressif/arduino-esp32.svg)](https://gitter.im/espressif/arduino-esp32?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) or [open a new Discussion](https://github.com/espressif/arduino-esp32/discussions)
## Contents ## Contents
- [Development Status](#development-status)
- [Development Status](#development-status) - [Installation Instructions](#installation-instructions)
- [Development Planning](#development-planning) - [Decoding Exceptions](#decoding-exceptions)
- [Documentation](#documentation) - [Issue/Bug report template](#issuebug-report-template)
- [Supported Chips](#supported-chips) - [ESP32Dev Board PINMAP](#esp32dev-board-pinmap)
- [Decoding exceptions](#decoding-exceptions)
- [Issue/Bug report template](#issuebug-report-template)
- [Contributing](#contributing)
### Development Status ### Development Status
Latest Stable Release [![Release Version](https://img.shields.io/github/release/espressif/arduino-esp32.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/latest/) [![Release Date](https://img.shields.io/github/release-date/espressif/arduino-esp32.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/latest/) [![Downloads](https://img.shields.io/github/downloads/espressif/arduino-esp32/latest/total.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/latest/) Latest Stable Release [![Release Version](https://img.shields.io/github/release/espressif/arduino-esp32.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/latest/) [![Release Date](https://img.shields.io/github/release-date/espressif/arduino-esp32.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/latest/) [![Downloads](https://img.shields.io/github/downloads/espressif/arduino-esp32/latest/total.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/latest/)
Latest Development Release [![Release Version](https://img.shields.io/github/release/espressif/arduino-esp32/all.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/) [![Release Date](https://img.shields.io/github/release-date-pre/espressif/arduino-esp32.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/) [![Downloads](https://img.shields.io/github/downloads-pre/espressif/arduino-esp32/latest/total.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/) Latest Development Release [![Release Version](https://img.shields.io/github/release/espressif/arduino-esp32/all.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/latest/) [![Release Date](https://img.shields.io/github/release-date-pre/espressif/arduino-esp32.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/latest/) [![Downloads](https://img.shields.io/github/downloads-pre/espressif/arduino-esp32/latest/total.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/latest/)
### Development Planning
Our Development is fully tracked on this public **[Roadmap 🎉](https://github.com/orgs/espressif/projects/3)** ### Installation Instructions
- Using Arduino IDE Boards Manager (preferred)
For even more information you can take a look at [Sprint Meeting notes](https://github.com/espressif/arduino-esp32/discussions/categories/sprints-meeting-notes) or join [Monthly Community Meetings 🔔](https://github.com/espressif/arduino-esp32/discussions/categories/monthly-community-meetings) + [Instructions for Boards Manager](docs/arduino-ide/boards_manager.md)
- Using Arduino IDE with the development repository
### Documentation + [Instructions for Windows](docs/arduino-ide/windows.md)
+ [Instructions for Mac](docs/arduino-ide/mac.md)
You can use the [Arduino-ESP32 Online Documentation](https://docs.espressif.com/projects/arduino-esp32/en/latest/) to get all information about this project. + [Instructions for Debian/Ubuntu Linux](docs/arduino-ide/debian_ubuntu.md)
+ [Instructions for Fedora](docs/arduino-ide/fedora.md)
* [Getting Started](https://docs.espressif.com/projects/arduino-esp32/en/latest/getting_started.html) + [Instructions for openSUSE](docs/arduino-ide/opensuse.md)
* [Installing (Windows, Linux and macOS)](https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html) - [Using PlatformIO](docs/platformio.md)
* [Libraries](https://docs.espressif.com/projects/arduino-esp32/en/latest/libraries.html) - [Building with make](docs/make.md)
* [ESP-IDF as Component](https://docs.espressif.com/projects/arduino-esp32/en/latest/esp-idf_component.html) - [Using as ESP-IDF component](docs/esp-idf_component.md)
* [FAQ](https://docs.espressif.com/projects/arduino-esp32/en/latest/faq.html) - [Using OTAWebUpdater](docs/OTAWebUpdate/OTAWebUpdate.md)
* [Troubleshooting](https://docs.espressif.com/projects/arduino-esp32/en/latest/troubleshooting.html)
### Supported Chips
Visit the [supported chips](https://docs.espressif.com/projects/arduino-esp32/en/latest/getting_started.html#supported-soc-s) documentation to see the list of current supported ESP32 SoCs.
### Decoding exceptions ### Decoding exceptions
You can use [EspExceptionDecoder](https://github.com/me-no-dev/EspExceptionDecoder) to get meaningful call trace. You can use [EspExceptionDecoder](https://github.com/me-no-dev/EspExceptionDecoder) to get meaningful call trace.
### Issue/Bug report template ### Issue/Bug report template
Before reporting an issue, make sure you've searched for similar one that was already created. Also make sure to go through all the issues labelled as [for reference](https://github.com/espressif/arduino-esp32/issues?utf8=%E2%9C%93&q=is%3Aissue%20label%3A%22for%20reference%22%20).
Before reporting an issue, make sure you've searched for similar one that was already created. Also make sure to go through all the issues labelled as [Type: For reference](https://github.com/espressif/arduino-esp32/issues?q=is%3Aissue+label%3A%22Type%3A+For+reference%22+). Finally, if you are sure no one else had the issue, follow the [ISSUE_TEMPLATE](docs/ISSUE_TEMPLATE.md) while reporting any issue.
Finally, if you are sure no one else had the issue, follow the **Issue template** or **Feature request template** while reporting any [new Issue](https://github.com/espressif/arduino-esp32/issues/new/choose). ### ESP32Dev Board PINMAP
### Contributing ![Pin Functions](docs/esp32_pinmap.png)
We welcome contributions to the Arduino ESP32 project! ### Tip
See [contributing](https://docs.espressif.com/projects/arduino-esp32/en/latest/contributing.html) in the documentation for more information on how to contribute to the project. Sometimes to program ESP32 via serial you must keep GPIO0 LOW during the programming process

9176
boards.txt

File diff suppressed because it is too large Load Diff

36
component.mk Normal file
View File

@ -0,0 +1,36 @@
ARDUINO_ALL_LIBRARIES := $(patsubst $(COMPONENT_PATH)/libraries/%,%,$(wildcard $(COMPONENT_PATH)/libraries/*))
# Macro returns non-empty if Arduino library $(1) should be included in the build
# (either because selective compilation is of, or this library is enabled
define ARDUINO_LIBRARY_ENABLED
$(if $(CONFIG_ARDUINO_SELECTIVE_COMPILATION),$(CONFIG_ARDUINO_SELECTIVE_$(1)),y)
endef
ARDUINO_ENABLED_LIBRARIES := $(foreach LIBRARY,$(sort $(ARDUINO_ALL_LIBRARIES)),$(if $(call ARDUINO_LIBRARY_ENABLED,$(LIBRARY)),$(LIBRARY)))
$(info Arduino libraries in build: $(ARDUINO_ENABLED_LIBRARIES))
# Expand all subdirs under $(1)
define EXPAND_SUBDIRS
$(sort $(dir $(wildcard $(1)/* $(1)/*/* $(1)/*/*/* $(1)/*/*/*/* $(1)/*/*/*/*/*)))
endef
# Macro returns SRCDIRS for library
define ARDUINO_LIBRARY_GET_SRCDIRS
$(if $(wildcard $(COMPONENT_PATH)/libraries/$(1)/src/.), \
$(call EXPAND_SUBDIRS,$(COMPONENT_PATH)/libraries/$(1)/src), \
$(filter-out $(call EXPAND_SUBDIRS,$(COMPONENT_PATH)/libraries/$(1)/examples), \
$(call EXPAND_SUBDIRS,$(COMPONENT_PATH)/libraries/$(1)) \
) \
)
endef
# Make a list of all srcdirs in enabled libraries
ARDUINO_LIBRARY_SRCDIRS := $(patsubst $(COMPONENT_PATH)/%,%,$(foreach LIBRARY,$(ARDUINO_ENABLED_LIBRARIES),$(call ARDUINO_LIBRARY_GET_SRCDIRS,$(LIBRARY))))
#$(info Arduino libraries src dirs: $(ARDUINO_LIBRARY_SRCDIRS))
COMPONENT_ADD_INCLUDEDIRS := cores/esp32 variants/esp32 $(ARDUINO_LIBRARY_SRCDIRS)
COMPONENT_PRIV_INCLUDEDIRS := cores/esp32/libb64
COMPONENT_SRCDIRS := cores/esp32/libb64 cores/esp32 variants/esp32 $(ARDUINO_LIBRARY_SRCDIRS)
CXXFLAGS += -fno-rtti

View File

@ -69,12 +69,7 @@
#define __STRINGIFY(a) #a #define __STRINGIFY(a) #a
#endif #endif
// can't define max() / min() because of conflicts with C++
#define _min(a,b) ((a)<(b)?(a):(b))
#define _max(a,b) ((a)>(b)?(a):(b))
#define _abs(x) ((x)>0?(x):-(x)) // abs() comes from STL
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt))) #define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
#define _round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) // round() comes from STL
#define radians(deg) ((deg)*DEG_TO_RAD) #define radians(deg) ((deg)*DEG_TO_RAD)
#define degrees(rad) ((rad)*RAD_TO_DEG) #define degrees(rad) ((rad)*RAD_TO_DEG)
#define sq(x) ((x)*(x)) #define sq(x) ((x)*(x))
@ -94,7 +89,6 @@
#define bitRead(value, bit) (((value) >> (bit)) & 0x01) #define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit))) #define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define bitClear(value, bit) ((value) &= ~(1UL << (bit))) #define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
#define bitToggle(value, bit) ((value) ^= (1UL << (bit)))
#define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet(value, bit) : bitClear(value, bit)) #define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet(value, bit) : bitClear(value, bit))
// avr-libc defines _NOP() since 1.6.2 // avr-libc defines _NOP() since 1.6.2
@ -105,23 +99,13 @@
#define bit(b) (1UL << (b)) #define bit(b) (1UL << (b))
#define _BV(b) (1UL << (b)) #define _BV(b) (1UL << (b))
#define digitalPinToTimer(pin) (0)
#define analogInPinToBit(P) (P)
#if SOC_GPIO_PIN_COUNT <= 32
#define digitalPinToPort(pin) (0)
#define digitalPinToBitMask(pin) (1UL << (pin))
#define portOutputRegister(port) ((volatile uint32_t*)GPIO_OUT_REG)
#define portInputRegister(port) ((volatile uint32_t*)GPIO_IN_REG)
#define portModeRegister(port) ((volatile uint32_t*)GPIO_ENABLE_REG)
#elif SOC_GPIO_PIN_COUNT <= 64
#define digitalPinToPort(pin) (((pin)>31)?1:0) #define digitalPinToPort(pin) (((pin)>31)?1:0)
#define digitalPinToBitMask(pin) (1UL << (((pin)>31)?((pin)-32):(pin))) #define digitalPinToBitMask(pin) (1UL << (((pin)>31)?((pin)-32):(pin)))
#define digitalPinToTimer(pin) (0)
#define analogInPinToBit(P) (P)
#define portOutputRegister(port) ((volatile uint32_t*)((port)?GPIO_OUT1_REG:GPIO_OUT_REG)) #define portOutputRegister(port) ((volatile uint32_t*)((port)?GPIO_OUT1_REG:GPIO_OUT_REG))
#define portInputRegister(port) ((volatile uint32_t*)((port)?GPIO_IN1_REG:GPIO_IN_REG)) #define portInputRegister(port) ((volatile uint32_t*)((port)?GPIO_IN1_REG:GPIO_IN_REG))
#define portModeRegister(port) ((volatile uint32_t*)((port)?GPIO_ENABLE1_REG:GPIO_ENABLE_REG)) #define portModeRegister(port) ((volatile uint32_t*)((port)?GPIO_ENABLE1_REG:GPIO_ENABLE_REG))
#else
#error SOC_GPIO_PIN_COUNT > 64 not implemented
#endif
#define NOT_A_PIN -1 #define NOT_A_PIN -1
#define NOT_A_PORT -1 #define NOT_A_PORT -1
@ -172,27 +156,19 @@ void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
#include "Udp.h" #include "Udp.h"
#include "HardwareSerial.h" #include "HardwareSerial.h"
#include "Esp.h" #include "Esp.h"
#include "esp32/spiram.h"
// Use float-compatible stl abs() and round(), we don't use Arduino macros to avoid issues with the C++ libraries
using std::abs; using std::abs;
using std::isinf; using std::isinf;
using std::isnan; using std::isnan;
using std::max; using std::max;
using std::min; using std::min;
using std::round; using ::round;
uint16_t makeWord(uint16_t w); uint16_t makeWord(uint16_t w);
uint16_t makeWord(uint8_t h, uint8_t l); uint16_t makeWord(byte h, byte l);
#define word(...) makeWord(__VA_ARGS__) #define word(...) makeWord(__VA_ARGS__)
size_t getArduinoLoopTaskStackSize(void);
#define SET_LOOP_TASK_STACK_SIZE(sz) size_t getArduinoLoopTaskStackSize() { return sz;}
// allows user to bypass esp_spiram_test()
#define BYPASS_SPIRAM_TEST(bypass) bool testSPIRAM(void) { if (bypass) return true; else return esp_spiram_test(); }
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L); unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L);
unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L); unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L);
@ -202,14 +178,13 @@ extern "C" void configTime(long gmtOffset_sec, int daylightOffset_sec,
extern "C" void configTzTime(const char* tz, extern "C" void configTzTime(const char* tz,
const char* server1, const char* server2 = nullptr, const char* server3 = nullptr); const char* server1, const char* server2 = nullptr, const char* server3 = nullptr);
void setToneChannel(uint8_t channel = 0);
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0);
void noTone(uint8_t _pin);
// WMath prototypes // WMath prototypes
long random(long); long random(long);
#endif /* __cplusplus */ #endif /* __cplusplus */
#define _min(a,b) ((a)<(b)?(a):(b))
#define _max(a,b) ((a)>(b)?(a):(b))
#include "pins_arduino.h" #include "pins_arduino.h"
#endif /* _ESP32_CORE_ARDUINO_H_ */ #endif /* _ESP32_CORE_ARDUINO_H_ */

View File

@ -35,24 +35,13 @@ extern "C" {
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 #if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
#include "esp32/rom/spi_flash.h" #include "esp32/rom/spi_flash.h"
#include "soc/efuse_reg.h" #include "soc/efuse_reg.h"
#define ESP_FLASH_IMAGE_BASE 0x1000 // Flash offset containing flash size and spi mode
#elif CONFIG_IDF_TARGET_ESP32S2 #elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/spi_flash.h" #include "esp32s2/rom/spi_flash.h"
#include "soc/efuse_reg.h"
#define ESP_FLASH_IMAGE_BASE 0x1000
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/spi_flash.h"
#include "soc/efuse_reg.h"
#define ESP_FLASH_IMAGE_BASE 0x0000 // Esp32s3 is located at 0x0000
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/spi_flash.h"
#define ESP_FLASH_IMAGE_BASE 0x0000 // Esp32c3 is located at 0x0000
#else #else
#error Target CONFIG_IDF_TARGET is not supported #error Target CONFIG_IDF_TARGET is not supported
#endif #endif
#else // ESP32 Before IDF 4.0 #else // ESP32 Before IDF 4.0
#include "rom/spi_flash.h" #include "rom/spi_flash.h"
#define ESP_FLASH_IMAGE_BASE 0x1000
#endif #endif
/** /**
@ -275,21 +264,7 @@ const char * EspClass::getChipModel(void)
return "Unknown"; return "Unknown";
} }
#elif CONFIG_IDF_TARGET_ESP32S2 #elif CONFIG_IDF_TARGET_ESP32S2
uint32_t pkg_ver = REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_3_REG, EFUSE_PKG_VERSION);
switch (pkg_ver) {
case 0:
return "ESP32-S2"; return "ESP32-S2";
case 1:
return "ESP32-S2FH16";
case 2:
return "ESP32-S2FH32";
default:
return "ESP32-S2 (Unknown)";
}
#elif CONFIG_IDF_TARGET_ESP32S3
return "ESP32-S3";
#elif CONFIG_IDF_TARGET_ESP32C3
return "ESP32-C3";
#endif #endif
} }
@ -308,7 +283,7 @@ const char * EspClass::getSdkVersion(void)
uint32_t EspClass::getFlashChipSize(void) uint32_t EspClass::getFlashChipSize(void)
{ {
esp_image_header_t fhdr; esp_image_header_t fhdr;
if(flashRead(ESP_FLASH_IMAGE_BASE, (uint32_t*)&fhdr, sizeof(esp_image_header_t)) && fhdr.magic != ESP_IMAGE_HEADER_MAGIC) { if(flashRead(0x1000, (uint32_t*)&fhdr, sizeof(esp_image_header_t)) && fhdr.magic != ESP_IMAGE_HEADER_MAGIC) {
return 0; return 0;
} }
return magicFlashChipSize(fhdr.spi_size); return magicFlashChipSize(fhdr.spi_size);
@ -317,7 +292,7 @@ uint32_t EspClass::getFlashChipSize(void)
uint32_t EspClass::getFlashChipSpeed(void) uint32_t EspClass::getFlashChipSpeed(void)
{ {
esp_image_header_t fhdr; esp_image_header_t fhdr;
if(flashRead(ESP_FLASH_IMAGE_BASE, (uint32_t*)&fhdr, sizeof(esp_image_header_t)) && fhdr.magic != ESP_IMAGE_HEADER_MAGIC) { if(flashRead(0x1000, (uint32_t*)&fhdr, sizeof(esp_image_header_t)) && fhdr.magic != ESP_IMAGE_HEADER_MAGIC) {
return 0; return 0;
} }
return magicFlashChipSpeed(fhdr.spi_speed); return magicFlashChipSpeed(fhdr.spi_speed);
@ -326,7 +301,7 @@ uint32_t EspClass::getFlashChipSpeed(void)
FlashMode_t EspClass::getFlashChipMode(void) FlashMode_t EspClass::getFlashChipMode(void)
{ {
esp_image_header_t fhdr; esp_image_header_t fhdr;
if(flashRead(ESP_FLASH_IMAGE_BASE, (uint32_t*)&fhdr, sizeof(esp_image_header_t)) && fhdr.magic != ESP_IMAGE_HEADER_MAGIC) { if(flashRead(0x1000, (uint32_t*)&fhdr, sizeof(esp_image_header_t)) && fhdr.magic != ESP_IMAGE_HEADER_MAGIC) {
return FM_UNKNOWN; return FM_UNKNOWN;
} }
return magicFlashChipMode(fhdr.spi_mode); return magicFlashChipMode(fhdr.spi_mode);

View File

@ -22,7 +22,6 @@
#include <Arduino.h> #include <Arduino.h>
#include <esp_partition.h> #include <esp_partition.h>
#include <hal/cpu_hal.h>
/** /**
* AVR macros for WDT managment * AVR macros for WDT managment
@ -111,7 +110,9 @@ public:
uint32_t ARDUINO_ISR_ATTR EspClass::getCycleCount() uint32_t ARDUINO_ISR_ATTR EspClass::getCycleCount()
{ {
return cpu_hal_get_cycle_count(); uint32_t ccount;
__asm__ __volatile__("esync; rsr %0,ccount":"=a" (ccount));
return ccount;
} }
extern EspClass ESP; extern EspClass ESP;

View File

@ -1,424 +0,0 @@
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "FirmwareMSC.h"
#if CONFIG_TINYUSB_MSC_ENABLED
#include <cstring>
#include "esp_partition.h"
#include "esp_ota_ops.h"
#include "esp32-hal.h"
#include "pins_arduino.h"
#include "firmware_msc_fat.h"
#ifndef USB_FW_MSC_VENDOR_ID
#define USB_FW_MSC_VENDOR_ID "ESP32" //max 8 chars
#endif
#ifndef USB_FW_MSC_PRODUCT_ID
#define USB_FW_MSC_PRODUCT_ID "Firmware MSC"//max 16 chars
#endif
#ifndef USB_FW_MSC_PRODUCT_REVISION
#define USB_FW_MSC_PRODUCT_REVISION "1.0" //max 4 chars
#endif
#ifndef USB_FW_MSC_VOLUME_NAME
#define USB_FW_MSC_VOLUME_NAME "ESP32-FWMSC" //max 11 chars
#endif
#ifndef USB_FW_MSC_SERIAL_NUMBER
#define USB_FW_MSC_SERIAL_NUMBER 0x00000000
#endif
ESP_EVENT_DEFINE_BASE(ARDUINO_FIRMWARE_MSC_EVENTS);
esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait);
esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg);
//General Variables
static uint8_t * msc_ram_disk = NULL;
static fat_boot_sector_t * msc_boot = NULL;
static uint8_t * msc_table = NULL;
static uint16_t msc_table_sectors = 0;
static uint16_t msc_total_sectors = 0;
static bool mcs_is_fat16 = false;
//Firmware Read
static const esp_partition_t* msc_run_partition = NULL;
static uint16_t fw_start_sector = 0;
static uint16_t fw_end_sector = 0;
static size_t fw_size = 0;
static fat_dir_entry_t * fw_entry = NULL;
//Firmware Write
typedef enum {
MSC_UPDATE_IDLE,
MSC_UPDATE_STARTING,
MSC_UPDATE_RUNNING,
MSC_UPDATE_END
} msc_update_state_t;
static const esp_partition_t* msc_ota_partition = NULL;
static msc_update_state_t msc_update_state = MSC_UPDATE_IDLE;
static uint16_t msc_update_start_sector = 0;
static uint32_t msc_update_bytes_written = 0;
static fat_dir_entry_t * msc_update_entry = NULL;
static uint32_t get_firmware_size(const esp_partition_t* partition){
esp_image_metadata_t data;
const esp_partition_pos_t running_pos = {
.offset = partition->address,
.size = partition->size,
};
data.start_addr = running_pos.offset;
esp_image_verify(ESP_IMAGE_VERIFY, &running_pos, &data);
return data.image_len;
}
//Get number of sectors required based on the size of the firmware and OTA partition
static size_t msc_update_get_required_disk_sectors(){
size_t data_sectors = 16;
size_t total_sectors = 0;
msc_run_partition = esp_ota_get_running_partition();
msc_ota_partition = esp_ota_get_next_update_partition(NULL);
if(msc_run_partition){
fw_size = get_firmware_size(msc_run_partition);
data_sectors += FAT_SIZE_TO_SECTORS(fw_size);
log_d("APP size: %u (%u sectors)", fw_size, FAT_SIZE_TO_SECTORS(fw_size));
} else {
log_w("APP partition not found. Reading disabled");
}
if(msc_ota_partition){
data_sectors += FAT_SIZE_TO_SECTORS(msc_ota_partition->size);
log_d("OTA size: %u (%u sectors)", msc_ota_partition->size, FAT_SIZE_TO_SECTORS(msc_ota_partition->size));
} else {
log_w("OTA partition not found. Writing disabled");
}
msc_table_sectors = fat_sectors_per_alloc_table(data_sectors, false);
total_sectors = data_sectors + msc_table_sectors + 2;
if(total_sectors > 0xFF4){
log_d("USING FAT16");
mcs_is_fat16 = true;
total_sectors -= msc_table_sectors;
msc_table_sectors = fat_sectors_per_alloc_table(data_sectors, true);
total_sectors += msc_table_sectors;
} else {
log_d("USING FAT12");
mcs_is_fat16 = false;
}
log_d("FAT sector size: %u", DISK_SECTOR_SIZE);
log_d("FAT data sectors: %u", data_sectors);
log_d("FAT table sectors: %u", msc_table_sectors);
log_d("FAT total sectors: %u (%uKB)", total_sectors, (total_sectors * DISK_SECTOR_SIZE) / 1024);
return total_sectors;
}
//setup the ramdisk and add the firmware download file
static bool msc_update_setup_disk(const char * volume_label, uint32_t serial_number){
msc_total_sectors = msc_update_get_required_disk_sectors();
uint8_t ram_sectors = msc_table_sectors + 2;
msc_ram_disk = (uint8_t*)calloc(ram_sectors, DISK_SECTOR_SIZE);
if(!msc_ram_disk){
log_e("Failed to allocate RAM Disk: %u bytes", ram_sectors * DISK_SECTOR_SIZE);
return false;
}
fw_start_sector = ram_sectors;
fw_end_sector = fw_start_sector;
msc_boot = fat_add_boot_sector(msc_ram_disk, msc_total_sectors, msc_table_sectors, fat_file_system_type(mcs_is_fat16), volume_label, serial_number);
msc_table = fat_add_table(msc_ram_disk, msc_boot, mcs_is_fat16);
//fat_dir_entry_t * label = fat_add_label(msc_ram_disk, volume_label);
if(msc_run_partition){
fw_entry = fat_add_root_file(msc_ram_disk, 0, "FIRMWARE", "BIN", fw_size, 2, mcs_is_fat16);
fw_end_sector = FAT_SIZE_TO_SECTORS(fw_size) + fw_start_sector;
}
return true;
}
static void msc_update_delete_disk(){
fw_entry = NULL;
fw_size = 0;
fw_end_sector = 0;
fw_start_sector = 0;
msc_table = NULL;
msc_boot = NULL;
msc_table_sectors = 0;
msc_total_sectors = 0;
msc_run_partition = NULL;
msc_ota_partition = NULL;
msc_update_state = MSC_UPDATE_IDLE;
msc_update_start_sector = 0;
msc_update_bytes_written = 0;
msc_update_entry = NULL;
free(msc_ram_disk);
msc_ram_disk = NULL;
}
//filter out entries to only include BINs in the root folder
static fat_dir_entry_t * msc_update_get_root_bin_entry(uint8_t index){
fat_dir_entry_t * entry = (fat_dir_entry_t *)(msc_ram_disk + ((msc_boot->sectors_per_alloc_table+1) * DISK_SECTOR_SIZE) + (index * sizeof(fat_dir_entry_t)));
fat_lfn_entry_t * lfn = (fat_lfn_entry_t*)entry;
//empty entry
if(entry->file_magic == 0){
return NULL;
}
//long file name
if(lfn->attr == 0x0F && lfn->type == 0x00 && lfn->first_cluster == 0x0000){
return NULL;
}
//only files marked as archives
if(entry->file_attr != FAT_FILE_ATTR_ARCHIVE){
return NULL;
}
//deleted
if(entry->file_magic == 0xE5 || entry->file_magic == 0x05){
return NULL;
}
//not bins
if(memcmp("BIN", entry->file_extension, 3)){
return NULL;
}
return entry;
}
//get an empty bin (the host will add an entry for file about to be written with size of zero)
static fat_dir_entry_t * msc_update_find_new_bin(){
for(uint8_t i=16; i;){
i--;
fat_dir_entry_t * entry = msc_update_get_root_bin_entry(i);
if(entry && entry->file_size == 0){
return entry;
}
}
return NULL;
}
//get a bin starting from particular sector
static fat_dir_entry_t * msc_update_find_bin(uint16_t sector){
for(uint8_t i=16; i; ){
i--;
fat_dir_entry_t * entry = msc_update_get_root_bin_entry(i);
if(entry && entry->data_start_sector == (sector - msc_boot->sectors_per_alloc_table)){
return entry;
}
}
return NULL;
}
//write the new data and erase the flash blocks when necessary
static esp_err_t msc_update_write(const esp_partition_t *partition, uint32_t offset, void *data, size_t size){
esp_err_t err = ESP_OK;
if((offset & (SPI_FLASH_SEC_SIZE-1)) == 0){
err = esp_partition_erase_range(partition, offset, SPI_FLASH_SEC_SIZE);
log_v("ERASE[0x%08X]: %s", offset, (err != ESP_OK)?"FAIL":"OK");
if(err != ESP_OK){
return err;
}
}
return esp_partition_write(partition, offset, data, size);
}
//called when error was encountered while updating
static void msc_update_error(){
log_e("UPDATE_ERROR: %u", msc_update_bytes_written);
arduino_firmware_msc_event_data_t p;
p.error.size = msc_update_bytes_written;
arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_ERROR_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY);
msc_update_state = MSC_UPDATE_IDLE;
msc_update_entry = NULL;
msc_update_bytes_written = 0;
msc_update_start_sector = 0;
}
//called when all firmware bytes have been received
static void msc_update_end(){
log_d("UPDATE_END: %u", msc_update_entry->file_size);
msc_update_state = MSC_UPDATE_END;
size_t ota_size = get_firmware_size(msc_ota_partition);
if(ota_size != msc_update_entry->file_size){
log_e("OTA SIZE MISMATCH %u != %u", ota_size, msc_update_entry->file_size);
msc_update_error();
return;
}
if(!ota_size || esp_ota_set_boot_partition(msc_ota_partition) != ESP_OK){
log_e("ENABLING OTA PARTITION FAILED");
msc_update_error();
return;
}
arduino_firmware_msc_event_data_t p;
p.end.size = msc_update_entry->file_size;
arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_END_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY);
}
static int32_t msc_write(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize){
//log_d("lba: %u, offset: %u, bufsize: %u", lba, offset, bufsize);
if(lba < fw_start_sector){
//write to sectors that are in RAM
memcpy(msc_ram_disk + (lba * DISK_SECTOR_SIZE) + offset, buffer, bufsize);
if(msc_ota_partition && lba == (fw_start_sector - 1)){
//monitor the root folder table
if(msc_update_state <= MSC_UPDATE_RUNNING){
fat_dir_entry_t * update_entry = msc_update_find_new_bin();
if(update_entry) {
if(msc_update_entry) {
log_v("REPLACING ENTRY");
} else {
log_v("ASSIGNING ENTRY");
}
if(msc_update_state <= MSC_UPDATE_STARTING){
msc_update_state = MSC_UPDATE_STARTING;
msc_update_bytes_written = 0;
msc_update_start_sector = 0;
}
msc_update_entry = update_entry;
} else if(msc_update_state == MSC_UPDATE_RUNNING){
if(!msc_update_entry && msc_update_start_sector){
msc_update_entry = msc_update_find_bin(msc_update_start_sector);
}
if(msc_update_entry && msc_update_bytes_written >= msc_update_entry->file_size){
msc_update_end();
}
}
}
}
} else if(msc_ota_partition && lba >= msc_update_start_sector){
//handle writes to the region where the new firmware will be uploaded
arduino_firmware_msc_event_data_t p;
if(msc_update_state <= MSC_UPDATE_STARTING && buffer[0] == 0xE9){
msc_update_state = MSC_UPDATE_RUNNING;
msc_update_start_sector = lba;
msc_update_bytes_written = 0;
log_d("UPDATE_START: %u (0x%02X)", lba, lba - msc_boot->sectors_per_alloc_table);
arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_START_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY);
if(msc_update_write(msc_ota_partition, ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset, buffer, bufsize) == ESP_OK){
log_v("UPDATE_WRITE: %u %u", ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset, bufsize);
msc_update_bytes_written = ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset + bufsize;
p.write.offset = ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset;
p.write.size = bufsize;
arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_WRITE_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY);
} else {
msc_update_error();
return 0;
}
} else if(msc_update_state == MSC_UPDATE_RUNNING){
if(msc_update_entry && msc_update_entry->file_size && msc_update_bytes_written < msc_update_entry->file_size && (msc_update_bytes_written + bufsize) >= msc_update_entry->file_size){
bufsize = msc_update_entry->file_size - msc_update_bytes_written;
}
if(msc_update_write(msc_ota_partition, ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset, buffer, bufsize) == ESP_OK){
log_v("UPDATE_WRITE: %u %u", ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset, bufsize);
msc_update_bytes_written = ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset + bufsize;
p.write.offset = ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset;
p.write.size = bufsize;
arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_WRITE_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY);
if(msc_update_entry && msc_update_entry->file_size && msc_update_bytes_written >= msc_update_entry->file_size){
msc_update_end();
}
} else {
msc_update_error();
return 0;
}
}
}
return bufsize;
}
static int32_t msc_read(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize){
//log_d("lba: %u, offset: %u, bufsize: %u", lba, offset, bufsize);
if(lba < fw_start_sector){
memcpy(buffer, msc_ram_disk + (lba * DISK_SECTOR_SIZE) + offset, bufsize);
} else if(msc_run_partition && lba < fw_end_sector){
//read the currently running firmware
if(esp_partition_read(msc_run_partition, ((lba - fw_start_sector) * DISK_SECTOR_SIZE) + offset, buffer, bufsize) != ESP_OK){
return 0;
}
} else {
memset(buffer, 0, bufsize);
}
return bufsize;
}
static bool msc_start_stop(uint8_t power_condition, bool start, bool load_eject){
//log_d("power: %u, start: %u, eject: %u", power_condition, start, load_eject);
arduino_firmware_msc_event_data_t p;
p.power.power_condition = power_condition;
p.power.start = start;
p.power.load_eject = load_eject;
arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_POWER_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY);
return true;
}
static volatile TaskHandle_t msc_task_handle = NULL;
static void msc_task(void *pvParameters){
for (;;) {
if(msc_update_state == MSC_UPDATE_END){
delay(100);
esp_restart();
}
delay(100);
}
msc_task_handle = NULL;
vTaskDelete(NULL);
}
FirmwareMSC::FirmwareMSC():msc(){}
FirmwareMSC::~FirmwareMSC(){
end();
}
bool FirmwareMSC::begin(){
if(msc_ram_disk){
return true;
}
if(!msc_update_setup_disk(USB_FW_MSC_VOLUME_NAME, USB_FW_MSC_SERIAL_NUMBER)){
return false;
}
if(!msc_task_handle){
xTaskCreateUniversal(msc_task, "msc_disk", 1024, NULL, 2, (TaskHandle_t*)&msc_task_handle, 0);
if(!msc_task_handle){
msc_update_delete_disk();
return false;
}
}
msc.vendorID(USB_FW_MSC_VENDOR_ID);
msc.productID(USB_FW_MSC_PRODUCT_ID);
msc.productRevision(USB_FW_MSC_PRODUCT_REVISION);
msc.onStartStop(msc_start_stop);
msc.onRead(msc_read);
msc.onWrite(msc_write);
msc.mediaPresent(true);
msc.begin(msc_boot->fat12_sector_num, DISK_SECTOR_SIZE);
return true;
}
void FirmwareMSC::end(){
msc.end();
if(msc_task_handle){
vTaskDelete(msc_task_handle);
msc_task_handle = NULL;
}
msc_update_delete_disk();
}
void FirmwareMSC::onEvent(esp_event_handler_t callback){
onEvent(ARDUINO_FIRMWARE_MSC_ANY_EVENT, callback);
}
void FirmwareMSC::onEvent(arduino_firmware_msc_event_t event, esp_event_handler_t callback){
arduino_usb_event_handler_register_with(ARDUINO_FIRMWARE_MSC_EVENTS, event, callback, this);
}
#if ARDUINO_USB_MSC_ON_BOOT
FirmwareMSC MSC_Update;
#endif
#endif /* CONFIG_USB_MSC_ENABLED */

View File

@ -1,70 +0,0 @@
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stdbool.h>
#include "USBMSC.h"
#if CONFIG_TINYUSB_MSC_ENABLED
#include "esp_event.h"
ESP_EVENT_DECLARE_BASE(ARDUINO_FIRMWARE_MSC_EVENTS);
typedef enum {
ARDUINO_FIRMWARE_MSC_ANY_EVENT = ESP_EVENT_ANY_ID,
ARDUINO_FIRMWARE_MSC_START_EVENT = 0,
ARDUINO_FIRMWARE_MSC_WRITE_EVENT,
ARDUINO_FIRMWARE_MSC_END_EVENT,
ARDUINO_FIRMWARE_MSC_ERROR_EVENT,
ARDUINO_FIRMWARE_MSC_POWER_EVENT,
ARDUINO_FIRMWARE_MSC_MAX_EVENT,
} arduino_firmware_msc_event_t;
typedef union {
struct {
size_t offset;
size_t size;
} write;
struct {
uint8_t power_condition;
bool start;
bool load_eject;
} power;
struct {
size_t size;
} end;
struct {
size_t size;
} error;
} arduino_firmware_msc_event_data_t;
class FirmwareMSC {
private:
USBMSC msc;
public:
FirmwareMSC();
~FirmwareMSC();
bool begin();
void end();
void onEvent(esp_event_handler_t callback);
void onEvent(arduino_firmware_msc_event_t event, esp_event_handler_t callback);
};
#if ARDUINO_USB_MSC_ON_BOOT
extern FirmwareMSC MSC_Update;
#endif
#endif /* CONFIG_TINYUSB_MSC_ENABLED */

View File

@ -1,392 +0,0 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "USB.h"
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
#include "esp32-hal.h"
#include "HWCDC.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "freertos/ringbuf.h"
#include "esp_intr_alloc.h"
#include "soc/periph_defs.h"
#include "hal/usb_serial_jtag_ll.h"
ESP_EVENT_DEFINE_BASE(ARDUINO_HW_CDC_EVENTS);
static RingbufHandle_t tx_ring_buf = NULL;
static xQueueHandle rx_queue = NULL;
static uint8_t rx_data_buf[64];
static intr_handle_t intr_handle = NULL;
static volatile bool initial_empty = false;
static xSemaphoreHandle tx_lock = NULL;
static uint32_t tx_timeout_ms = 200;
static esp_event_loop_handle_t arduino_hw_cdc_event_loop_handle = NULL;
static esp_err_t arduino_hw_cdc_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, BaseType_t *task_unblocked){
if(arduino_hw_cdc_event_loop_handle == NULL){
return ESP_FAIL;
}
return esp_event_isr_post_to(arduino_hw_cdc_event_loop_handle, event_base, event_id, event_data, event_data_size, task_unblocked);
}
static esp_err_t arduino_hw_cdc_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg){
if (!arduino_hw_cdc_event_loop_handle) {
esp_event_loop_args_t event_task_args = {
.queue_size = 5,
.task_name = "arduino_hw_cdc_events",
.task_priority = 5,
.task_stack_size = 2048,
.task_core_id = tskNO_AFFINITY
};
if (esp_event_loop_create(&event_task_args, &arduino_hw_cdc_event_loop_handle) != ESP_OK) {
log_e("esp_event_loop_create failed");
}
}
if(arduino_hw_cdc_event_loop_handle == NULL){
return ESP_FAIL;
}
return esp_event_handler_register_with(arduino_hw_cdc_event_loop_handle, event_base, event_id, event_handler, event_handler_arg);
}
static void hw_cdc_isr_handler(void *arg) {
portBASE_TYPE xTaskWoken = 0;
uint32_t usbjtag_intr_status = 0;
arduino_hw_cdc_event_data_t event = {0};
usbjtag_intr_status = usb_serial_jtag_ll_get_intsts_mask();
if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY) {
// Interrupt tells us the host picked up the data we sent.
if (usb_serial_jtag_ll_txfifo_writable() == 1) {
// We disable the interrupt here so that the interrupt won't be triggered if there is no data to send.
usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
if(!initial_empty){
initial_empty = true;
//send event?
//ets_printf("CONNECTED\n");
arduino_hw_cdc_event_post(ARDUINO_HW_CDC_EVENTS, ARDUINO_HW_CDC_CONNECTED_EVENT, &event, sizeof(arduino_hw_cdc_event_data_t), &xTaskWoken);
}
size_t queued_size;
uint8_t *queued_buff = (uint8_t *)xRingbufferReceiveUpToFromISR(tx_ring_buf, &queued_size, 64);
// If the hardware fifo is avaliable, write in it. Otherwise, do nothing.
if (queued_buff != NULL) { //Although tx_queued_bytes may be larger than 0. We may have interrupt before xRingbufferSend() was called.
//Copy the queued buffer into the TX FIFO
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
usb_serial_jtag_ll_write_txfifo(queued_buff, queued_size);
usb_serial_jtag_ll_txfifo_flush();
vRingbufferReturnItemFromISR(tx_ring_buf, queued_buff, &xTaskWoken);
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
//send event?
//ets_printf("TX:%u\n", queued_size);
event.tx.len = queued_size;
arduino_hw_cdc_event_post(ARDUINO_HW_CDC_EVENTS, ARDUINO_HW_CDC_TX_EVENT, &event, sizeof(arduino_hw_cdc_event_data_t), &xTaskWoken);
}
} else {
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
}
}
if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT) {
// read rx buffer(max length is 64), and send avaliable data to ringbuffer.
// Ensure the rx buffer size is larger than RX_MAX_SIZE.
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT);
uint32_t rx_fifo_len = usb_serial_jtag_ll_read_rxfifo(rx_data_buf, 64);
uint32_t i=0;
for(i=0; i<rx_fifo_len; i++){
if(rx_queue == NULL || !xQueueSendFromISR(rx_queue, rx_data_buf+i, &xTaskWoken)){
break;
}
}
//send event?
//ets_printf("RX:%u/%u\n", i, rx_fifo_len);
event.rx.len = i;
arduino_hw_cdc_event_post(ARDUINO_HW_CDC_EVENTS, ARDUINO_HW_CDC_RX_EVENT, &event, sizeof(arduino_hw_cdc_event_data_t), &xTaskWoken);
}
if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_BUS_RESET) {
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_BUS_RESET);
initial_empty = false;
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
//ets_printf("BUS_RESET\n");
arduino_hw_cdc_event_post(ARDUINO_HW_CDC_EVENTS, ARDUINO_HW_CDC_BUS_RESET_EVENT, &event, sizeof(arduino_hw_cdc_event_data_t), &xTaskWoken);
}
if (xTaskWoken == pdTRUE) {
portYIELD_FROM_ISR();
}
}
static void ARDUINO_ISR_ATTR cdc0_write_char(char c) {
if(xPortInIsrContext()){
xRingbufferSendFromISR(tx_ring_buf, (void*) (&c), 1, NULL);
} else {
xRingbufferSend(tx_ring_buf, (void*) (&c), 1, tx_timeout_ms / portTICK_PERIOD_MS);
}
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
}
HWCDC::HWCDC() {
}
HWCDC::~HWCDC(){
end();
}
HWCDC::operator bool() const
{
return initial_empty;
}
void HWCDC::onEvent(esp_event_handler_t callback){
onEvent(ARDUINO_HW_CDC_ANY_EVENT, callback);
}
void HWCDC::onEvent(arduino_hw_cdc_event_t event, esp_event_handler_t callback){
arduino_hw_cdc_event_handler_register_with(ARDUINO_HW_CDC_EVENTS, event, callback, this);
}
void HWCDC::begin(unsigned long baud)
{
if(tx_lock == NULL) {
tx_lock = xSemaphoreCreateMutex();
}
setRxBufferSize(256);//default if not preset
setTxBufferSize(256);//default if not preset
usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_LL_INTR_MASK);
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_LL_INTR_MASK);
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY | USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT | USB_SERIAL_JTAG_INTR_BUS_RESET);
if(!intr_handle && esp_intr_alloc(ETS_USB_SERIAL_JTAG_INTR_SOURCE, 0, hw_cdc_isr_handler, NULL, &intr_handle) != ESP_OK){
isr_log_e("HW USB CDC failed to init interrupts");
end();
return;
}
usb_serial_jtag_ll_txfifo_flush();
}
void HWCDC::end()
{
//Disable tx/rx interrupt.
usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_LL_INTR_MASK);
esp_intr_free(intr_handle);
intr_handle = NULL;
if(tx_lock != NULL) {
vSemaphoreDelete(tx_lock);
}
setRxBufferSize(0);
setTxBufferSize(0);
if (arduino_hw_cdc_event_loop_handle) {
esp_event_loop_delete(arduino_hw_cdc_event_loop_handle);
arduino_hw_cdc_event_loop_handle = NULL;
}
}
void HWCDC::setTxTimeoutMs(uint32_t timeout){
tx_timeout_ms = timeout;
}
/*
* WRITING
*/
size_t HWCDC::setTxBufferSize(size_t tx_queue_len){
if(tx_ring_buf){
if(!tx_queue_len){
vRingbufferDelete(tx_ring_buf);
tx_ring_buf = NULL;
}
return 0;
}
tx_ring_buf = xRingbufferCreate(tx_queue_len, RINGBUF_TYPE_BYTEBUF);
if(!tx_ring_buf){
return 0;
}
return tx_queue_len;
}
int HWCDC::availableForWrite(void)
{
if(tx_ring_buf == NULL || tx_lock == NULL){
return 0;
}
if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){
return 0;
}
size_t a = xRingbufferGetCurFreeSize(tx_ring_buf);
xSemaphoreGive(tx_lock);
return a;
}
size_t HWCDC::write(const uint8_t *buffer, size_t size)
{
if(buffer == NULL || size == 0 || tx_ring_buf == NULL || tx_lock == NULL){
return 0;
}
if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){
return 0;
}
size_t max_size = xRingbufferGetMaxItemSize(tx_ring_buf);
size_t space = xRingbufferGetCurFreeSize(tx_ring_buf);
size_t to_send = size, so_far = 0;
if(space > size){
space = size;
}
// Non-Blocking method, Sending data to ringbuffer, and handle the data in ISR.
if(xRingbufferSend(tx_ring_buf, (void*) (buffer), space, 0) != pdTRUE){
size = 0;
} else {
to_send -= space;
so_far += space;
// Now trigger the ISR to read data from the ring buffer.
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
while(to_send){
if(max_size > to_send){
max_size = to_send;
}
// Blocking method, Sending data to ringbuffer, and handle the data in ISR.
if(xRingbufferSend(tx_ring_buf, (void*) (buffer+so_far), max_size, tx_timeout_ms / portTICK_PERIOD_MS) != pdTRUE){
size = so_far;
break;
}
so_far += max_size;
to_send -= max_size;
// Now trigger the ISR to read data from the ring buffer.
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
}
}
xSemaphoreGive(tx_lock);
return size;
}
size_t HWCDC::write(uint8_t c)
{
return write(&c, 1);
}
void HWCDC::flush(void)
{
if(tx_ring_buf == NULL || tx_lock == NULL){
return;
}
if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){
return;
}
UBaseType_t uxItemsWaiting = 0;
vRingbufferGetInfo(tx_ring_buf, NULL, NULL, NULL, NULL, &uxItemsWaiting);
if(uxItemsWaiting){
// Now trigger the ISR to read data from the ring buffer.
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
}
while(uxItemsWaiting){
delay(5);
vRingbufferGetInfo(tx_ring_buf, NULL, NULL, NULL, NULL, &uxItemsWaiting);
}
xSemaphoreGive(tx_lock);
}
/*
* READING
*/
size_t HWCDC::setRxBufferSize(size_t rx_queue_len){
if(rx_queue){
if(!rx_queue_len){
vQueueDelete(rx_queue);
rx_queue = NULL;
}
return 0;
}
rx_queue = xQueueCreate(rx_queue_len, sizeof(uint8_t));
if(!rx_queue){
return 0;
}
if(!tx_ring_buf){
tx_ring_buf = xRingbufferCreate(rx_queue_len, RINGBUF_TYPE_BYTEBUF);
}
return rx_queue_len;
}
int HWCDC::available(void)
{
if(rx_queue == NULL){
return -1;
}
return uxQueueMessagesWaiting(rx_queue);
}
int HWCDC::peek(void)
{
if(rx_queue == NULL){
return -1;
}
uint8_t c;
if(xQueuePeek(rx_queue, &c, 0)) {
return c;
}
return -1;
}
int HWCDC::read(void)
{
if(rx_queue == NULL){
return -1;
}
uint8_t c = 0;
if(xQueueReceive(rx_queue, &c, 0)) {
return c;
}
return -1;
}
size_t HWCDC::read(uint8_t *buffer, size_t size)
{
if(rx_queue == NULL){
return -1;
}
uint8_t c = 0;
size_t count = 0;
while(count < size && xQueueReceive(rx_queue, &c, 0)){
buffer[count++] = c;
}
return count;
}
/*
* DEBUG
*/
void HWCDC::setDebugOutput(bool en)
{
if(en) {
uartSetDebug(NULL);
ets_install_putc1((void (*)(char)) &cdc0_write_char);
} else {
ets_install_putc1(NULL);
}
}
#if ARDUINO_USB_MODE
#if ARDUINO_USB_CDC_ON_BOOT//Serial used for USB CDC
HWCDC Serial;
#else
HWCDC USBSerial;
#endif
#endif
#endif /* CONFIG_TINYUSB_CDC_ENABLED */

View File

@ -1,109 +0,0 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "sdkconfig.h"
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
#include <inttypes.h>
#include "esp_event.h"
#include "Stream.h"
ESP_EVENT_DECLARE_BASE(ARDUINO_HW_CDC_EVENTS);
typedef enum {
ARDUINO_HW_CDC_ANY_EVENT = ESP_EVENT_ANY_ID,
ARDUINO_HW_CDC_CONNECTED_EVENT = 0,
ARDUINO_HW_CDC_BUS_RESET_EVENT,
ARDUINO_HW_CDC_RX_EVENT,
ARDUINO_HW_CDC_TX_EVENT,
ARDUINO_HW_CDC_MAX_EVENT,
} arduino_hw_cdc_event_t;
typedef union {
struct {
size_t len;
} rx;
struct {
size_t len;
} tx;
} arduino_hw_cdc_event_data_t;
class HWCDC: public Stream
{
public:
HWCDC();
~HWCDC();
void onEvent(esp_event_handler_t callback);
void onEvent(arduino_hw_cdc_event_t event, esp_event_handler_t callback);
size_t setRxBufferSize(size_t);
size_t setTxBufferSize(size_t);
void setTxTimeoutMs(uint32_t timeout);
void begin(unsigned long baud=0);
void end();
int available(void);
int availableForWrite(void);
int peek(void);
int read(void);
size_t read(uint8_t *buffer, size_t size);
size_t write(uint8_t);
size_t write(const uint8_t *buffer, size_t size);
void flush(void);
inline size_t read(char * buffer, size_t size)
{
return read((uint8_t*) buffer, size);
}
inline size_t write(const char * buffer, size_t size)
{
return write((uint8_t*) buffer, size);
}
inline size_t write(const char * s)
{
return write((uint8_t*) s, strlen(s));
}
inline size_t write(unsigned long n)
{
return write((uint8_t) n);
}
inline size_t write(long n)
{
return write((uint8_t) n);
}
inline size_t write(unsigned int n)
{
return write((uint8_t) n);
}
inline size_t write(int n)
{
return write((uint8_t) n);
}
operator bool() const;
void setDebugOutput(bool);
uint32_t baudRate(){return 115200;}
};
#if ARDUINO_USB_MODE
#if ARDUINO_USB_CDC_ON_BOOT//Serial used for USB CDC
extern HWCDC Serial;
#else
extern HWCDC USBSerial;
#endif
#endif
#endif /* CONFIG_IDF_TARGET_ESP32C3 */

View File

@ -5,343 +5,84 @@
#include "pins_arduino.h" #include "pins_arduino.h"
#include "HardwareSerial.h" #include "HardwareSerial.h"
#include "soc/soc_caps.h"
#include "driver/uart.h"
#include "freertos/queue.h"
#ifndef ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE
#define ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE 2048
#endif
#ifndef ARDUINO_SERIAL_EVENT_TASK_PRIORITY
#define ARDUINO_SERIAL_EVENT_TASK_PRIORITY (configMAX_PRIORITIES-1)
#endif
#ifndef ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE
#define ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE -1
#endif
#ifndef SOC_RX0
#if CONFIG_IDF_TARGET_ESP32 #if CONFIG_IDF_TARGET_ESP32
#define SOC_RX0 3
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
#define SOC_RX0 44
#elif CONFIG_IDF_TARGET_ESP32C3
#define SOC_RX0 20
#endif
#endif
#ifndef SOC_TX0
#if CONFIG_IDF_TARGET_ESP32
#define SOC_TX0 1
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
#define SOC_TX0 43
#elif CONFIG_IDF_TARGET_ESP32C3
#define SOC_TX0 21
#endif
#endif
void serialEvent(void) __attribute__((weak));
void serialEvent(void) {}
#if SOC_UART_NUM > 1
#ifndef RX1 #ifndef RX1
#if CONFIG_IDF_TARGET_ESP32
#define RX1 9 #define RX1 9
#elif CONFIG_IDF_TARGET_ESP32S2
#define RX1 18
#elif CONFIG_IDF_TARGET_ESP32C3
#define RX1 18
#elif CONFIG_IDF_TARGET_ESP32S3
#define RX1 15
#endif
#endif #endif
#ifndef TX1 #ifndef TX1
#if CONFIG_IDF_TARGET_ESP32
#define TX1 10 #define TX1 10
#elif CONFIG_IDF_TARGET_ESP32S2
#define TX1 17
#elif CONFIG_IDF_TARGET_ESP32C3
#define TX1 19
#elif CONFIG_IDF_TARGET_ESP32S3
#define TX1 16
#endif
#endif #endif
void serialEvent1(void) __attribute__((weak));
void serialEvent1(void) {}
#endif /* SOC_UART_NUM > 1 */
#if SOC_UART_NUM > 2
#ifndef RX2 #ifndef RX2
#if CONFIG_IDF_TARGET_ESP32
#define RX2 16 #define RX2 16
#elif CONFIG_IDF_TARGET_ESP32S3
#define RX2 19
#endif
#endif #endif
#ifndef TX2 #ifndef TX2
#if CONFIG_IDF_TARGET_ESP32
#define TX2 17 #define TX2 17
#elif CONFIG_IDF_TARGET_ESP32S3
#define TX2 20
#endif
#endif #endif
void serialEvent2(void) __attribute__((weak)); #else
void serialEvent2(void) {}
#endif /* SOC_UART_NUM > 2 */ #ifndef RX1
#define RX1 18
#endif
#ifndef TX1
#define TX1 17
#endif
#endif
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL) #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC #if ARDUINO_SERIAL_PORT //Serial used for USB CDC
HardwareSerial Serial0(0); HardwareSerial Serial0(0);
#else #else
HardwareSerial Serial(0); HardwareSerial Serial(0);
#endif #endif
#if SOC_UART_NUM > 1
HardwareSerial Serial1(1); HardwareSerial Serial1(1);
#endif #if CONFIG_IDF_TARGET_ESP32
#if SOC_UART_NUM > 2
HardwareSerial Serial2(2); HardwareSerial Serial2(2);
#endif #endif
#endif
void serialEventRun(void) HardwareSerial::HardwareSerial(int uart_nr) : _uart_nr(uart_nr), _uart(NULL) {}
void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert, unsigned long timeout_ms)
{ {
#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC if(0 > _uart_nr || _uart_nr > 2) {
if(Serial0.available()) serialEvent(); log_e("Serial number is invalid, please use 0, 1 or 2");
#else
if(Serial.available()) serialEvent();
#endif
#if SOC_UART_NUM > 1
if(Serial1.available()) serialEvent1();
#endif
#if SOC_UART_NUM > 2
if(Serial2.available()) serialEvent2();
#endif
}
#endif
#if !CONFIG_DISABLE_HAL_LOCKS
#define HSERIAL_MUTEX_LOCK() do {} while (xSemaphoreTake(_lock, portMAX_DELAY) != pdPASS)
#define HSERIAL_MUTEX_UNLOCK() xSemaphoreGive(_lock)
#else
#define HSERIAL_MUTEX_LOCK()
#define HSERIAL_MUTEX_UNLOCK()
#endif
HardwareSerial::HardwareSerial(int uart_nr) :
_uart_nr(uart_nr),
_uart(NULL),
_rxBufferSize(256),
_txBufferSize(0),
_onReceiveCB(NULL),
_onReceiveErrorCB(NULL),
_onReceiveTimeout(true),
_rxTimeout(10),
_eventTask(NULL)
#if !CONFIG_DISABLE_HAL_LOCKS
,_lock(NULL)
#endif
{
#if !CONFIG_DISABLE_HAL_LOCKS
if(_lock == NULL){
_lock = xSemaphoreCreateMutex();
if(_lock == NULL){
log_e("xSemaphoreCreateMutex failed");
return; return;
} }
} if(_uart) {
#endif
}
HardwareSerial::~HardwareSerial()
{
end(); end();
#if !CONFIG_DISABLE_HAL_LOCKS
if(_lock != NULL){
vSemaphoreDelete(_lock);
} }
if(_uart_nr == 0 && rxPin < 0 && txPin < 0) {
#if CONFIG_IDF_TARGET_ESP32
rxPin = 3;
txPin = 1;
#elif CONFIG_IDF_TARGET_ESP32S2
rxPin = 44;
txPin = 43;
#endif #endif
}
void HardwareSerial::_createEventTask(void *args)
{
// Creating UART event Task
xTaskCreateUniversal(_uartEventTask, "uart_event_task", ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE, this, ARDUINO_SERIAL_EVENT_TASK_PRIORITY, &_eventTask, ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE);
if (_eventTask == NULL) {
log_e(" -- UART%d Event Task not Created!", _uart_nr);
} }
} if(_uart_nr == 1 && rxPin < 0 && txPin < 0) {
void HardwareSerial::_destroyEventTask(void)
{
if (_eventTask != NULL) {
vTaskDelete(_eventTask);
_eventTask = NULL;
}
}
void HardwareSerial::onReceiveError(OnReceiveErrorCb function)
{
HSERIAL_MUTEX_LOCK();
// function may be NULL to cancel onReceive() from its respective task
_onReceiveErrorCB = function;
// this can be called after Serial.begin(), therefore it shall create the event task
if (function != NULL && _uart != NULL && _eventTask == NULL) {
_createEventTask(this);
}
HSERIAL_MUTEX_UNLOCK();
}
void HardwareSerial::onReceive(OnReceiveCb function, bool onlyOnTimeout)
{
HSERIAL_MUTEX_LOCK();
// function may be NULL to cancel onReceive() from its respective task
_onReceiveCB = function;
// When Rx timeout is Zero (disabled), there is only one possible option that is callback when FIFO reaches 120 bytes
_onReceiveTimeout = _rxTimeout > 0 ? onlyOnTimeout : false;
// this can be called after Serial.begin(), therefore it shall create the event task
if (function != NULL && _uart != NULL && _eventTask == NULL) {
_createEventTask(this); // Create event task
}
HSERIAL_MUTEX_UNLOCK();
}
// timout is calculates in time to receive UART symbols at the UART baudrate.
// the estimation is about 11 bits per symbol (SERIAL_8N1)
void HardwareSerial::setRxTimeout(uint8_t symbols_timeout)
{
HSERIAL_MUTEX_LOCK();
// Zero disables timeout, thus, onReceive callback will only be called when RX FIFO reaches 120 bytes
// Any non-zero value will activate onReceive callback based on UART baudrate with about 11 bits per symbol
_rxTimeout = symbols_timeout;
if (!symbols_timeout) _onReceiveTimeout = false; // only when RX timeout is disabled, we also must disable this flag
if(_uart != NULL) uart_set_rx_timeout(_uart_nr, _rxTimeout); // Set new timeout
HSERIAL_MUTEX_UNLOCK();
}
void HardwareSerial::eventQueueReset()
{
QueueHandle_t uartEventQueue = NULL;
if (_uart == NULL) {
return;
}
uartGetEventQueue(_uart, &uartEventQueue);
if (uartEventQueue != NULL) {
xQueueReset(uartEventQueue);
}
}
void HardwareSerial::_uartEventTask(void *args)
{
HardwareSerial *uart = (HardwareSerial *)args;
uart_event_t event;
QueueHandle_t uartEventQueue = NULL;
uartGetEventQueue(uart->_uart, &uartEventQueue);
if (uartEventQueue != NULL) {
for(;;) {
//Waiting for UART event.
if(xQueueReceive(uartEventQueue, (void * )&event, (portTickType)portMAX_DELAY)) {
switch(event.type) {
case UART_DATA:
if(uart->_onReceiveCB && uart->available() > 0 &&
((uart->_onReceiveTimeout && event.timeout_flag) || !uart->_onReceiveTimeout) )
uart->_onReceiveCB();
break;
case UART_FIFO_OVF:
log_w("UART%d FIFO Overflow. Consider adding Hardware Flow Control to your Application.", uart->_uart_nr);
if(uart->_onReceiveErrorCB) uart->_onReceiveErrorCB(UART_FIFO_OVF_ERROR);
break;
case UART_BUFFER_FULL:
log_w("UART%d Buffer Full. Consider increasing your buffer size of your Application.", uart->_uart_nr);
if(uart->_onReceiveErrorCB) uart->_onReceiveErrorCB(UART_BUFFER_FULL_ERROR);
break;
case UART_BREAK:
log_w("UART%d RX break.", uart->_uart_nr);
if(uart->_onReceiveErrorCB) uart->_onReceiveErrorCB(UART_BREAK_ERROR);
break;
case UART_PARITY_ERR:
log_w("UART%d parity error.", uart->_uart_nr);
if(uart->_onReceiveErrorCB) uart->_onReceiveErrorCB(UART_PARITY_ERROR);
break;
case UART_FRAME_ERR:
log_w("UART%d frame error.", uart->_uart_nr);
if(uart->_onReceiveErrorCB) uart->_onReceiveErrorCB(UART_FRAME_ERROR);
break;
default:
log_w("UART%d unknown event type %d.", uart->_uart_nr, event.type);
break;
}
}
}
}
vTaskDelete(NULL);
}
void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert, unsigned long timeout_ms, uint8_t rxfifo_full_thrhd)
{
if(0 > _uart_nr || _uart_nr >= SOC_UART_NUM) {
log_e("Serial number is invalid, please use numers from 0 to %u", SOC_UART_NUM - 1);
return;
}
#if !CONFIG_DISABLE_HAL_LOCKS
if(_lock == NULL){
log_e("MUTEX Lock failed. Can't begin.");
return;
}
#endif
HSERIAL_MUTEX_LOCK();
// First Time or after end() --> set default Pins
if (!uartIsDriverInstalled(_uart)) {
switch (_uart_nr) {
case UART_NUM_0:
if (rxPin < 0 && txPin < 0) {
rxPin = SOC_RX0;
txPin = SOC_TX0;
}
break;
#if SOC_UART_NUM > 1 // may save some flash bytes...
case UART_NUM_1:
if (rxPin < 0 && txPin < 0) {
rxPin = RX1; rxPin = RX1;
txPin = TX1; txPin = TX1;
} }
break; #if CONFIG_IDF_TARGET_ESP32
#endif if(_uart_nr == 2 && rxPin < 0 && txPin < 0) {
#if SOC_UART_NUM > 2 // may save some flash bytes...
case UART_NUM_2:
if (rxPin < 0 && txPin < 0) {
rxPin = RX2; rxPin = RX2;
txPin = TX2; txPin = TX2;
} }
break;
#endif #endif
default: _uart = uartBegin(_uart_nr, baud ? baud : 9600, config, rxPin, txPin, 256, invert);
log_e("Bad UART Number"); _tx_pin = txPin;
return; _rx_pin = rxPin;
}
}
if(_uart) { if(!baud) {
// in this case it is a begin() over a previous begin() - maybe to change baud rate
// thus do not disable debug output
end(false);
}
// IDF UART driver keeps Pin setting on restarting. Negative Pin number will keep it unmodified.
_uart = uartBegin(_uart_nr, baud ? baud : 9600, config, rxPin, txPin, _rxBufferSize, _txBufferSize, invert, rxfifo_full_thrhd);
if (!baud) {
// using baud rate as zero, forces it to try to detect the current baud rate in place
uartStartDetectBaudrate(_uart); uartStartDetectBaudrate(_uart);
time_t startMillis = millis(); time_t startMillis = millis();
unsigned long detectedBaudRate = 0; unsigned long detectedBaudRate = 0;
@ -349,28 +90,18 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
yield(); yield();
} }
end(false); end();
if(detectedBaudRate) { if(detectedBaudRate) {
delay(100); // Give some time... delay(100); // Give some time...
_uart = uartBegin(_uart_nr, detectedBaudRate, config, rxPin, txPin, _rxBufferSize, _txBufferSize, invert, rxfifo_full_thrhd); _uart = uartBegin(_uart_nr, detectedBaudRate, config, rxPin, txPin, 256, invert);
} else { } else {
log_e("Could not detect baudrate. Serial data at the port must be present within the timeout for detection to be possible"); log_e("Could not detect baudrate. Serial data at the port must be present within the timeout for detection to be possible");
_uart = NULL; _uart = NULL;
_tx_pin = 255;
_rx_pin = 255;
} }
} }
// create a task to deal with Serial Events when, for example, calling begin() twice to change the baudrate,
// or when setting the callback before calling begin()
if (_uart != NULL && (_onReceiveCB != NULL || _onReceiveErrorCB != NULL) && _eventTask == NULL) {
_createEventTask(this);
}
// Set UART RX timeout
if (_uart != NULL) {
uart_set_rx_timeout(_uart_nr, _rxTimeout);
}
HSERIAL_MUTEX_UNLOCK();
} }
void HardwareSerial::updateBaudRate(unsigned long baud) void HardwareSerial::updateBaudRate(unsigned long baud)
@ -378,21 +109,18 @@ void HardwareSerial::updateBaudRate(unsigned long baud)
uartSetBaudRate(_uart, baud); uartSetBaudRate(_uart, baud);
} }
void HardwareSerial::end(bool fullyTerminate) void HardwareSerial::end()
{ {
// default Serial.end() will completely disable HardwareSerial, if(uartGetDebug() == _uart_nr) {
// including any tasks or debug message channel (log_x()) - but not for IDF log messages!
if(fullyTerminate) {
_onReceiveCB = NULL;
_onReceiveErrorCB = NULL;
if (uartGetDebug() == _uart_nr) {
uartSetDebug(0); uartSetDebug(0);
} }
} log_v("pins %d %d",_tx_pin, _rx_pin);
delay(10); uartEnd(_uart, _tx_pin, _rx_pin);
uartEnd(_uart);
_uart = 0; _uart = 0;
_destroyEventTask(); }
size_t HardwareSerial::setRxBufferSize(size_t new_size) {
return uartResizeRxBuffer(_uart, new_size);
} }
void HardwareSerial::setDebugOutput(bool en) void HardwareSerial::setDebugOutput(bool en)
@ -480,54 +208,10 @@ uint32_t HardwareSerial::baudRate()
} }
HardwareSerial::operator bool() const HardwareSerial::operator bool() const
{ {
return uartIsDriverInstalled(_uart); return true;
} }
void HardwareSerial::setRxInvert(bool invert) void HardwareSerial::setRxInvert(bool invert)
{ {
uartSetRxInvert(_uart, invert); uartSetRxInvert(_uart, invert);
} }
// negative Pin value will keep it unmodified
void HardwareSerial::setPins(int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin)
{
uartSetPins(_uart, rxPin, txPin, ctsPin, rtsPin);
}
// Enables or disables Hardware Flow Control using RTS and/or CTS pins (must use setAllPins() before)
void HardwareSerial::setHwFlowCtrlMode(uint8_t mode, uint8_t threshold)
{
uartSetHwFlowCtrlMode(_uart, mode, threshold);
}
size_t HardwareSerial::setRxBufferSize(size_t new_size) {
if (_uart) {
log_e("RX Buffer can't be resized when Serial is already running.\n");
return 0;
}
if (new_size <= SOC_UART_FIFO_LEN) {
log_e("RX Buffer must be higher than %d.\n", SOC_UART_FIFO_LEN); // ESP32, S2, S3 and C3 means higher than 128
return 0;
}
_rxBufferSize = new_size;
return _rxBufferSize;
}
size_t HardwareSerial::setTxBufferSize(size_t new_size) {
if (_uart) {
log_e("TX Buffer can't be resized when Serial is already running.\n");
return 0;
}
if (new_size <= SOC_UART_FIFO_LEN) {
log_e("TX Buffer must be higher than %d.\n", SOC_UART_FIFO_LEN); // ESP32, S2, S3 and C3 means higher than 128
return 0;
}
_txBufferSize = new_size;
return _txBufferSize;
}

View File

@ -46,61 +46,17 @@
#define HardwareSerial_h #define HardwareSerial_h
#include <inttypes.h> #include <inttypes.h>
#include <functional>
#include "Stream.h" #include "Stream.h"
#include "esp32-hal.h" #include "esp32-hal.h"
#include "soc/soc_caps.h"
#include "HWCDC.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
typedef enum {
UART_BREAK_ERROR,
UART_BUFFER_FULL_ERROR,
UART_FIFO_OVF_ERROR,
UART_FRAME_ERROR,
UART_PARITY_ERROR
} hardwareSerial_error_t;
typedef std::function<void(void)> OnReceiveCb;
typedef std::function<void(hardwareSerial_error_t)> OnReceiveErrorCb;
class HardwareSerial: public Stream class HardwareSerial: public Stream
{ {
public: public:
HardwareSerial(int uart_nr); HardwareSerial(int uart_nr);
~HardwareSerial();
// setRxTimeout sets the timeout after which onReceive callback will be called (after receiving data, it waits for this time of UART rx inactivity to call the callback fnc) void begin(unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1, bool invert=false, unsigned long timeout_ms = 20000UL);
// param symbols_timeout defines a timeout threshold in uart symbol periods. Setting 0 symbol timeout disables the callback call by timeout. void end();
// Maximum timeout setting is calculacted automatically by IDF. If set above the maximum, it is ignored and an error is printed on Serial0 (check console).
// Examples: Maximum for 11 bits symbol is 92 (SERIAL_8N2, SERIAL_8E1, SERIAL_8O1, etc), Maximum for 10 bits symbol is 101 (SERIAL_8N1).
// For example symbols_timeout=1 defines a timeout equal to transmission time of one symbol (~11 bit) on current baudrate.
// For a baudrate of 9600, SERIAL_8N1 (10 bit symbol) and symbols_timeout = 3, the timeout would be 3 / (9600 / 10) = 3.125 ms
void setRxTimeout(uint8_t symbols_timeout);
// onReceive will setup a callback that will be called whenever an UART interruption occurs (UART_INTR_RXFIFO_FULL or UART_INTR_RXFIFO_TOUT)
// UART_INTR_RXFIFO_FULL interrupt triggers at UART_FULL_THRESH_DEFAULT bytes received (defined as 120 bytes by default in IDF)
// UART_INTR_RXFIFO_TOUT interrupt triggers at UART_TOUT_THRESH_DEFAULT symbols passed without any reception (defined as 10 symbos by default in IDF)
// onlyOnTimeout parameter will define how onReceive will behave:
// Default: true -- The callback will only be called when RX Timeout happens.
// Whole stream of bytes will be ready for being read on the callback function at once.
// This option may lead to Rx Overflow depending on the Rx Buffer Size and number of bytes received in the streaming
// false -- The callback will be called when FIFO reaches 120 bytes and also on RX Timeout.
// The stream of incommig bytes will be "split" into blocks of 120 bytes on each callback.
// This option avoid any sort of Rx Overflow, but leaves the UART packet reassembling work to the Application.
void onReceive(OnReceiveCb function, bool onlyOnTimeout = true);
// onReceive will be called on error events (see hardwareSerial_error_t)
void onReceiveError(OnReceiveErrorCb function);
// eventQueueReset clears all events in the queue (the events that trigger onReceive and onReceiveError) - maybe usefull in some use cases
void eventQueueReset();
void begin(unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1, bool invert=false, unsigned long timeout_ms = 20000UL, uint8_t rxfifo_full_thrhd = 112);
void end(bool fullyTerminate = true);
void updateBaudRate(unsigned long baud); void updateBaudRate(unsigned long baud);
int available(void); int available(void);
int availableForWrite(void); int availableForWrite(void);
@ -142,58 +98,33 @@ public:
uint32_t baudRate(); uint32_t baudRate();
operator bool() const; operator bool() const;
size_t setRxBufferSize(size_t);
void setDebugOutput(bool); void setDebugOutput(bool);
void setRxInvert(bool); void setRxInvert(bool);
// Negative Pin Number will keep it unmodified, thus this function can set individual pins
// SetPins shall be called after Serial begin()
void setPins(int8_t rxPin, int8_t txPin, int8_t ctsPin = -1, int8_t rtsPin = -1);
// Enables or disables Hardware Flow Control using RTS and/or CTS pins (must use setAllPins() before)
void setHwFlowCtrlMode(uint8_t mode = HW_FLOWCTRL_CTS_RTS, uint8_t threshold = 64); // 64 is half FIFO Length
size_t setRxBufferSize(size_t new_size);
size_t setTxBufferSize(size_t new_size);
protected: protected:
int _uart_nr; int _uart_nr;
uart_t* _uart; uart_t* _uart;
size_t _rxBufferSize; uint8_t _tx_pin;
size_t _txBufferSize; uint8_t _rx_pin;
OnReceiveCb _onReceiveCB;
OnReceiveErrorCb _onReceiveErrorCB;
// _onReceive and _rxTimeout have be consistent when timeout is disabled
bool _onReceiveTimeout;
uint8_t _rxTimeout;
TaskHandle_t _eventTask;
#if !CONFIG_DISABLE_HAL_LOCKS
SemaphoreHandle_t _lock;
#endif
void _createEventTask(void *args);
void _destroyEventTask(void);
static void _uartEventTask(void *args);
}; };
extern void serialEventRun(void) __attribute__((weak)); extern void serialEventRun(void) __attribute__((weak));
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL) #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
#ifndef ARDUINO_USB_CDC_ON_BOOT #ifndef ARDUINO_SERIAL_PORT
#define ARDUINO_USB_CDC_ON_BOOT 0 #define ARDUINO_SERIAL_PORT 0
#endif #endif
#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC #if ARDUINO_SERIAL_PORT //Serial used for USB CDC
#if !ARDUINO_USB_MODE
#include "USB.h" #include "USB.h"
#include "USBCDC.h" #include "USBCDC.h"
#endif
extern HardwareSerial Serial0; extern HardwareSerial Serial0;
#else #else
extern HardwareSerial Serial; extern HardwareSerial Serial;
#endif #endif
#if SOC_UART_NUM > 1
extern HardwareSerial Serial1; extern HardwareSerial Serial1;
#endif #if CONFIG_IDF_TARGET_ESP32
#if SOC_UART_NUM > 2
extern HardwareSerial Serial2; extern HardwareSerial Serial2;
#endif #endif
#endif #endif

View File

@ -120,6 +120,3 @@ bool IPAddress::fromString(const char *address)
_address.bytes[3] = acc; _address.bytes[3] = acc;
return true; return true;
} }
// declared one time - as external in IPAddress.h
IPAddress INADDR_NONE(0, 0, 0, 0);

View File

@ -91,6 +91,6 @@ public:
friend class DNSClient; friend class DNSClient;
}; };
// changed to extern because const declaration creates copies in BSS of INADDR_NONE for each CPP unit that includes it const IPAddress INADDR_NONE(0, 0, 0, 0);
extern IPAddress INADDR_NONE;
#endif #endif

View File

@ -19,7 +19,7 @@
#include <Arduino.h> #include <Arduino.h>
#include <MD5Builder.h> #include <MD5Builder.h>
static uint8_t hex_char_to_byte(uint8_t c) uint8_t hex_char_to_byte(uint8_t c)
{ {
return (c >= 'a' && c <= 'f') ? (c - ((uint8_t)'a' - 0xa)) : return (c >= 'a' && c <= 'f') ? (c - ((uint8_t)'a' - 0xa)) :
(c >= 'A' && c <= 'F') ? (c - ((uint8_t)'A' - 0xA)) : (c >= 'A' && c <= 'F') ? (c - ((uint8_t)'A' - 0xA)) :
@ -28,13 +28,13 @@ static uint8_t hex_char_to_byte(uint8_t c)
void MD5Builder::begin(void) void MD5Builder::begin(void)
{ {
memset(_buf, 0x00, ESP_ROM_MD5_DIGEST_LEN); memset(_buf, 0x00, 16);
esp_rom_md5_init(&_ctx); MD5Init(&_ctx);
} }
void MD5Builder::add(uint8_t * data, uint16_t len) void MD5Builder::add(uint8_t * data, uint16_t len)
{ {
esp_rom_md5_update(&_ctx, data, len); MD5Update(&_ctx, data, len);
} }
void MD5Builder::addHexString(const char * data) void MD5Builder::addHexString(const char * data)
@ -82,7 +82,7 @@ bool MD5Builder::addStream(Stream & stream, const size_t maxLen)
} }
// Update MD5 with buffer payload // Update MD5 with buffer payload
esp_rom_md5_update(&_ctx, buf, numBytesRead); MD5Update(&_ctx, buf, numBytesRead);
// update available number of bytes // update available number of bytes
maxLengthLeft -= numBytesRead; maxLengthLeft -= numBytesRead;
@ -94,24 +94,24 @@ bool MD5Builder::addStream(Stream & stream, const size_t maxLen)
void MD5Builder::calculate(void) void MD5Builder::calculate(void)
{ {
esp_rom_md5_final(_buf, &_ctx); MD5Final(_buf, &_ctx);
} }
void MD5Builder::getBytes(uint8_t * output) void MD5Builder::getBytes(uint8_t * output)
{ {
memcpy(output, _buf, ESP_ROM_MD5_DIGEST_LEN); memcpy(output, _buf, 16);
} }
void MD5Builder::getChars(char * output) void MD5Builder::getChars(char * output)
{ {
for(uint8_t i = 0; i < ESP_ROM_MD5_DIGEST_LEN; i++) { for(uint8_t i = 0; i < 16; i++) {
sprintf(output + (i * 2), "%02x", _buf[i]); sprintf(output + (i * 2), "%02x", _buf[i]);
} }
} }
String MD5Builder::toString(void) String MD5Builder::toString(void)
{ {
char out[(ESP_ROM_MD5_DIGEST_LEN * 2) + 1]; char out[33];
getChars(out); getChars(out);
return String(out); return String(out);
} }

View File

@ -23,13 +23,23 @@
#include <Stream.h> #include <Stream.h>
#include "esp_system.h" #include "esp_system.h"
#include "esp_rom_md5.h" #ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
#include "esp32/rom/md5_hash.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/md5_hash.h"
#else
#error Target CONFIG_IDF_TARGET is not supported
#endif
#else // ESP32 Before IDF 4.0
#include "rom/md5_hash.h"
#endif
class MD5Builder class MD5Builder
{ {
private: private:
md5_context_t _ctx; struct MD5Context _ctx;
uint8_t _buf[ESP_ROM_MD5_DIGEST_LEN]; uint8_t _buf[16];
public: public:
void begin(void); void begin(void);
void add(uint8_t * data, uint16_t len); void add(uint8_t * data, uint16_t len);

View File

@ -73,11 +73,6 @@ public:
} }
size_t printf(const char * format, ...) __attribute__ ((format (printf, 2, 3))); size_t printf(const char * format, ...) __attribute__ ((format (printf, 2, 3)));
// add availableForWrite to make compatible with Arduino Print.h
// default to zero, meaning "a single write may block"
// should be overriden by subclasses with buffering
virtual int availableForWrite() { return 0; }
size_t print(const __FlashStringHelper *); size_t print(const __FlashStringHelper *);
size_t print(const String &); size_t print(const String &);
size_t print(const char[]); size_t print(const char[]);
@ -108,9 +103,6 @@ public:
size_t println(const Printable&); size_t println(const Printable&);
size_t println(struct tm * timeinfo, const char * format = NULL); size_t println(struct tm * timeinfo, const char * format = NULL);
size_t println(void); size_t println(void);
virtual void flush() { /* Empty implementation for backward compatibility */ }
}; };
#endif #endif

View File

@ -256,7 +256,7 @@ float Stream::parseFloat(char skipChar)
} else if(c >= '0' && c <= '9') { // is c a digit? } else if(c >= '0' && c <= '9') { // is c a digit?
value = value * 10 + c - '0'; value = value * 10 + c - '0';
if(isFraction) { if(isFraction) {
fraction *= 0.1f; fraction *= 0.1;
} }
} }
read(); // consume the character we got with peek read(); // consume the character we got with peek

View File

@ -48,6 +48,7 @@ public:
virtual int available() = 0; virtual int available() = 0;
virtual int read() = 0; virtual int read() = 0;
virtual int peek() = 0; virtual int peek() = 0;
virtual void flush() = 0;
Stream():_startMillis(0) Stream():_startMillis(0)
{ {

View File

@ -1,138 +0,0 @@
#include <Arduino.h>
#include "esp32-hal-ledc.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
static TaskHandle_t _tone_task = NULL;
static QueueHandle_t _tone_queue = NULL;
static uint8_t _channel = 0;
typedef enum{
TONE_START,
TONE_END,
TONE_SET_CHANNEL
} tone_cmd_t;
typedef struct{
tone_cmd_t tone_cmd;
uint8_t pin;
unsigned int frequency;
unsigned long duration;
uint8_t channel;
} tone_msg_t;
static void tone_task(void*){
tone_msg_t tone_msg;
while(1){
xQueueReceive(_tone_queue, &tone_msg, portMAX_DELAY);
switch(tone_msg.tone_cmd){
case TONE_START:
log_d("Task received from queue TONE_START: _pin=%d, frequency=%u Hz, duration=%lu ms", tone_msg.pin, tone_msg.frequency, tone_msg.duration);
log_d("Setup LED controll on channel %d", _channel);
// ledcSetup(_channel, tone_msg.frequency, 11);
// ledcAttachPin(tone_msg.pin, _channel);
// ledcWrite(_channel, 1024);
ledcWriteTone(_channel, tone_msg.frequency);
ledcAttachPin(tone_msg.pin, _channel);
if(tone_msg.duration){
delay(tone_msg.duration);
ledcDetachPin(tone_msg.pin);
ledcWriteTone(_channel, 0);
}
break;
case TONE_END:
log_d("Task received from queue TONE_END: pin=%d", tone_msg.pin);
ledcDetachPin(tone_msg.pin);
ledcWriteTone(_channel, 0);
break;
case TONE_SET_CHANNEL:
log_d("Task received from queue TONE_SET_CHANNEL: channel=%d", tone_msg.channel);
_channel = tone_msg.channel;
break;
default: ; // do nothing
} // switch
} // infinite loop
}
static int tone_init(){
if(_tone_queue == NULL){
log_v("Creating tone queue");
_tone_queue = xQueueCreate(128, sizeof(tone_msg_t));
if(_tone_queue == NULL){
log_e("Could not create tone queue");
return 0; // ERR
}
log_v("Tone queue created");
}
if(_tone_task == NULL){
log_v("Creating tone task");
xTaskCreate(
tone_task, // Function to implement the task
"toneTask", // Name of the task
3500, // Stack size in words
NULL, // Task input parameter
1, // Priority of the task
&_tone_task // Task handle.
);
if(_tone_task == NULL){
log_e("Could not create tone task");
return 0; // ERR
}
log_v("Tone task created");
}
return 1; // OK
}
void setToneChannel(uint8_t channel){
log_d("channel=%d", channel);
if(tone_init()){
tone_msg_t tone_msg = {
.tone_cmd = TONE_SET_CHANNEL,
.pin = 0, // Ignored
.frequency = 0, // Ignored
.duration = 0, // Ignored
.channel = channel
};
xQueueSend(_tone_queue, &tone_msg, portMAX_DELAY);
}
}
void noTone(uint8_t _pin){
log_d("noTone was called");
if(tone_init()){
tone_msg_t tone_msg = {
.tone_cmd = TONE_END,
.pin = _pin,
.frequency = 0, // Ignored
.duration = 0, // Ignored
.channel = 0 // Ignored
};
xQueueSend(_tone_queue, &tone_msg, portMAX_DELAY);
}
}
// parameters:
// _pin - pin number which will output the signal
// frequency - PWM frequency in Hz
// duration - time in ms - how long will the signal be outputted.
// If not provided, or 0 you must manually call noTone to end output
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration){
log_d("_pin=%d, frequency=%u Hz, duration=%lu ms", _pin, frequency, duration);
if(tone_init()){
tone_msg_t tone_msg = {
.tone_cmd = TONE_START,
.pin = _pin,
.frequency = frequency,
.duration = duration,
.channel = 0 // Ignored
};
xQueueSend(_tone_queue, &tone_msg, portMAX_DELAY);
}
}

View File

@ -11,15 +11,10 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "USB.h"
#if CONFIG_TINYUSB_ENABLED
#include "pins_arduino.h"
#include "esp32-hal.h" #include "esp32-hal.h"
#include "esp32-hal-tinyusb.h" #include "esp32-hal-tinyusb.h"
#include "common/tusb_common.h" #include "USB.h"
#include "StreamString.h" #if CONFIG_USB_ENABLED
#ifndef USB_VID #ifndef USB_VID
#define USB_VID USB_ESPRESSIF_VID #define USB_VID USB_ESPRESSIF_VID
@ -34,22 +29,20 @@
#define USB_PRODUCT ARDUINO_BOARD #define USB_PRODUCT ARDUINO_BOARD
#endif #endif
#ifndef USB_SERIAL #ifndef USB_SERIAL
#if CONFIG_IDF_TARGET_ESP32S3
#define USB_SERIAL "__MAC__"
#else
#define USB_SERIAL "0" #define USB_SERIAL "0"
#endif #endif
#endif
#ifndef USB_WEBUSB_ENABLED
#define USB_WEBUSB_ENABLED false
#endif
#ifndef USB_WEBUSB_URL
#define USB_WEBUSB_URL "https://espressif.github.io/arduino-esp32/webusb.html"
#endif
#if CFG_TUD_DFU_RUNTIME extern "C" {
#include "tinyusb.h"
}
#if CFG_TUD_DFU_RT
static uint16_t load_dfu_descriptor(uint8_t * dst, uint8_t * itf) static uint16_t load_dfu_descriptor(uint8_t * dst, uint8_t * itf)
{ {
#define DFU_ATTR_CAN_DOWNLOAD 1
#define DFU_ATTR_CAN_UPLOAD 2
#define DFU_ATTR_MANIFESTATION_TOLERANT 4
#define DFU_ATTR_WILL_DETACH 8
#define DFU_ATTRS (DFU_ATTR_CAN_DOWNLOAD | DFU_ATTR_CAN_UPLOAD | DFU_ATTR_MANIFESTATION_TOLERANT) #define DFU_ATTRS (DFU_ATTR_CAN_DOWNLOAD | DFU_ATTR_CAN_UPLOAD | DFU_ATTR_MANIFESTATION_TOLERANT)
uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB DFU_RT"); uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB DFU_RT");
@ -62,11 +55,11 @@ static uint16_t load_dfu_descriptor(uint8_t * dst, uint8_t * itf)
return TUD_DFU_RT_DESC_LEN; return TUD_DFU_RT_DESC_LEN;
} }
// Invoked on DFU_DETACH request to reboot to the bootloader // Invoked on DFU_DETACH request to reboot to the bootloader
void tud_dfu_runtime_reboot_to_dfu_cb(void) void tud_dfu_rt_reboot_to_dfu(void)
{ {
usb_persist_restart(RESTART_BOOTLOADER_DFU); usb_persist_restart(RESTART_BOOTLOADER_DFU);
} }
#endif /* CFG_TUD_DFU_RUNTIME */ #endif /* CFG_TUD_DFU_RT */
ESP_EVENT_DEFINE_BASE(ARDUINO_USB_EVENTS); ESP_EVENT_DEFINE_BASE(ARDUINO_USB_EVENTS);
@ -91,14 +84,14 @@ static bool tinyusb_device_suspended = false;
// Invoked when device is mounted (configured) // Invoked when device is mounted (configured)
void tud_mount_cb(void){ void tud_mount_cb(void){
tinyusb_device_mounted = true; tinyusb_device_mounted = true;
arduino_usb_event_data_t p; arduino_usb_event_data_t p = {0};
arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_STARTED_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY); arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_STARTED_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY);
} }
// Invoked when device is unmounted // Invoked when device is unmounted
void tud_umount_cb(void){ void tud_umount_cb(void){
tinyusb_device_mounted = false; tinyusb_device_mounted = false;
arduino_usb_event_data_t p; arduino_usb_event_data_t p = {0};
arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY); arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY);
} }
@ -106,7 +99,7 @@ void tud_umount_cb(void){
// Within 7ms, device must draw an average of current less than 2.5 mA from bus // Within 7ms, device must draw an average of current less than 2.5 mA from bus
void tud_suspend_cb(bool remote_wakeup_en){ void tud_suspend_cb(bool remote_wakeup_en){
tinyusb_device_suspended = true; tinyusb_device_suspended = true;
arduino_usb_event_data_t p; arduino_usb_event_data_t p = {0};
p.suspend.remote_wakeup_en = remote_wakeup_en; p.suspend.remote_wakeup_en = remote_wakeup_en;
arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_SUSPEND_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY); arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_SUSPEND_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY);
} }
@ -114,7 +107,7 @@ void tud_suspend_cb(bool remote_wakeup_en){
// Invoked when usb bus is resumed // Invoked when usb bus is resumed
void tud_resume_cb(void){ void tud_resume_cb(void){
tinyusb_device_suspended = false; tinyusb_device_suspended = false;
arduino_usb_event_data_t p; arduino_usb_event_data_t p = {0};
arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_RESUME_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY); arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_RESUME_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY);
} }
@ -131,8 +124,8 @@ ESPUSB::ESPUSB(size_t task_stack_size, uint8_t event_task_priority)
,usb_protocol(MISC_PROTOCOL_IAD) ,usb_protocol(MISC_PROTOCOL_IAD)
,usb_attributes(TUSB_DESC_CONFIG_ATT_SELF_POWERED) ,usb_attributes(TUSB_DESC_CONFIG_ATT_SELF_POWERED)
,usb_power_ma(500) ,usb_power_ma(500)
,webusb_enabled(USB_WEBUSB_ENABLED) ,webusb_enabled(false)
,webusb_url(USB_WEBUSB_URL) ,webusb_url("espressif.github.io/arduino-esp32/webusb.html")
,_started(false) ,_started(false)
,_task_stack_size(task_stack_size) ,_task_stack_size(task_stack_size)
,_event_task_priority(event_task_priority) ,_event_task_priority(event_task_priority)
@ -160,15 +153,6 @@ ESPUSB::~ESPUSB(){
bool ESPUSB::begin(){ bool ESPUSB::begin(){
if(!_started){ if(!_started){
#if CONFIG_IDF_TARGET_ESP32S3
if(serial_number == "__MAC__"){
StreamString s;
uint8_t m[6];
esp_efuse_mac_get_default(m);
s.printf("%02X:%02X:%02X:%02X:%02X:%02X", m[0], m[1], m[2], m[3], m[4], m[5]);
serial_number = s;
}
#endif
tinyusb_device_config_t tinyusb_device_config = { tinyusb_device_config_t tinyusb_device_config = {
.vid = vid, .vid = vid,
.pid = pid, .pid = pid,
@ -203,9 +187,9 @@ ESPUSB::operator bool() const
} }
bool ESPUSB::enableDFU(){ bool ESPUSB::enableDFU(){
#if CFG_TUD_DFU_RUNTIME #if CFG_TUD_DFU_RT
return tinyusb_enable_interface(USB_INTERFACE_DFU, TUD_DFU_RT_DESC_LEN, load_dfu_descriptor) == ESP_OK; return tinyusb_enable_interface(USB_INTERFACE_DFU, TUD_DFU_RT_DESC_LEN, load_dfu_descriptor) == ESP_OK;
#endif /* CFG_TUD_DFU_RUNTIME */ #endif /* CFG_TUD_DFU_RT */
return false; return false;
} }
@ -302,9 +286,6 @@ uint8_t ESPUSB::usbAttributes(void){
bool ESPUSB::webUSB(bool enabled){ bool ESPUSB::webUSB(bool enabled){
if(!_started){ if(!_started){
webusb_enabled = enabled; webusb_enabled = enabled;
if(enabled && usb_version < 0x0210){
usb_version = 0x0210;
}
} }
return !_started; return !_started;
} }
@ -354,4 +335,4 @@ const char * ESPUSB::webUSBURL(void){
ESPUSB USB; ESPUSB USB;
#endif /* CONFIG_TINYUSB_ENABLED */ #endif /* CONFIG_USB_ENABLED */

View File

@ -14,13 +14,12 @@
#pragma once #pragma once
#include "sdkconfig.h" #include "sdkconfig.h"
#if CONFIG_USB_ENABLED
#if CONFIG_TINYUSB_ENABLED #include "Arduino.h"
#include "esp_event.h"
#include "USBCDC.h" #include "USBCDC.h"
#define ARDUINO_USB_ON_BOOT (ARDUINO_USB_CDC_ON_BOOT|ARDUINO_USB_MSC_ON_BOOT|ARDUINO_USB_DFU_ON_BOOT) #include "esp_event.h"
ESP_EVENT_DECLARE_BASE(ARDUINO_USB_EVENTS); ESP_EVENT_DECLARE_BASE(ARDUINO_USB_EVENTS);
@ -116,4 +115,4 @@ class ESPUSB {
extern ESPUSB USB; extern ESPUSB USB;
#endif /* CONFIG_TINYUSB_ENABLED */ #endif /* CONFIG_USB_ENABLED */

View File

@ -11,22 +11,28 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "USB.h" #include "esp32-hal.h"
#if CONFIG_TINYUSB_CDC_ENABLED
#include "USBCDC.h"
#include "esp32-hal-tinyusb.h" #include "esp32-hal-tinyusb.h"
#include "USB.h"
#include "USBCDC.h"
#if CONFIG_USB_ENABLED
ESP_EVENT_DEFINE_BASE(ARDUINO_USB_CDC_EVENTS); ESP_EVENT_DEFINE_BASE(ARDUINO_USB_CDC_EVENTS);
esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait); esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait);
esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg); esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg);
extern "C" {
#include "tinyusb.h"
}
#if CFG_TUD_CDC
#define MAX_USB_CDC_DEVICES 2 #define MAX_USB_CDC_DEVICES 2
USBCDC * devices[MAX_USB_CDC_DEVICES] = {NULL, NULL}; USBCDC * devices[MAX_USB_CDC_DEVICES] = {NULL, NULL};
static uint16_t load_cdc_descriptor(uint8_t * dst, uint8_t * itf) static uint16_t load_cdc_descriptor(uint8_t * dst, uint8_t * itf)
{ {
uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB CDC"); uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB CDC");
// Interface number, string index, attributes, detach timeout, transfer size */
uint8_t descriptor[TUD_CDC_DESC_LEN] = { uint8_t descriptor[TUD_CDC_DESC_LEN] = {
// Interface number, string index, EP notification address and size, EP data address (out, in) and size. // Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(*itf, str_index, 0x85, 64, 0x03, 0x84, 64) TUD_CDC_DESCRIPTOR(*itf, str_index, 0x85, 64, 0x03, 0x84, 64)
@ -36,7 +42,6 @@ static uint16_t load_cdc_descriptor(uint8_t * dst, uint8_t * itf)
return TUD_CDC_DESC_LEN; return TUD_CDC_DESC_LEN;
} }
// Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE
void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
{ {
if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){ if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){
@ -44,7 +49,6 @@ void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
} }
} }
// Invoked when line coding is change via SET_LINE_CODING
void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding) void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding)
{ {
if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){ if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){
@ -52,7 +56,6 @@ void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding)
} }
} }
// Invoked when received new data
void tud_cdc_rx_cb(uint8_t itf) void tud_cdc_rx_cb(uint8_t itf)
{ {
if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){ if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){
@ -60,52 +63,54 @@ void tud_cdc_rx_cb(uint8_t itf)
} }
} }
// Invoked when received send break
void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms){ static size_t tinyusb_cdc_write(uint8_t itf, const uint8_t *buffer, size_t size){
//log_v("itf: %u, duration_ms: %u", itf, duration_ms); if(itf >= MAX_USB_CDC_DEVICES){
return 0;
}
if(!tud_cdc_n_connected(itf)){
return 0;
}
size_t tosend = size, sofar = 0;
while(tosend){
uint32_t space = tud_cdc_n_write_available(itf);
if(!space){
delay(1);
continue;
}
if(tosend < space){
space = tosend;
}
uint32_t sent = tud_cdc_n_write(itf, buffer + sofar, space);
if(!sent){
return sofar;
}
sofar += sent;
tosend -= sent;
tud_cdc_n_write_flush(itf);
}
return sofar;
} }
// Invoked when space becomes available in TX buffer static void ARDUINO_ISR_ATTR cdc0_write_char(char c)
void tud_cdc_tx_complete_cb(uint8_t itf){ {
if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){ tinyusb_cdc_write(0, (const uint8_t *)&c, 1);
devices[itf]->_onTX();
}
} }
static void ARDUINO_ISR_ATTR cdc0_write_char(char c){ //void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char);
if(devices[0] != NULL){
devices[0]->write(c);
}
}
static void usb_unplugged_cb(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data){ static void usb_unplugged_cb(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data){
((USBCDC*)arg)->_onUnplugged(); ((USBCDC*)arg)->_onUnplugged();
} }
USBCDC::USBCDC(uint8_t itfn) USBCDC::USBCDC(uint8_t itfn) : itf(itfn), bit_rate(0), stop_bits(0), parity(0), data_bits(0), dtr(false), rts(false), connected(false), reboot_enable(true), rx_queue(NULL) {
: itf(itfn)
, bit_rate(0)
, stop_bits(0)
, parity(0)
, data_bits(0)
, dtr(false)
, rts(false)
, connected(false)
, reboot_enable(true)
, rx_queue(NULL)
, tx_lock(NULL)
, tx_timeout_ms(250)
{
tinyusb_enable_interface(USB_INTERFACE_CDC, TUD_CDC_DESC_LEN, load_cdc_descriptor); tinyusb_enable_interface(USB_INTERFACE_CDC, TUD_CDC_DESC_LEN, load_cdc_descriptor);
if(itf < MAX_USB_CDC_DEVICES){ if(itf < MAX_USB_CDC_DEVICES){
devices[itf] = this;
arduino_usb_event_handler_register_with(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, usb_unplugged_cb, this); arduino_usb_event_handler_register_with(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, usb_unplugged_cb, this);
} }
} }
USBCDC::~USBCDC(){
end();
}
void USBCDC::onEvent(esp_event_handler_t callback){ void USBCDC::onEvent(esp_event_handler_t callback){
onEvent(ARDUINO_USB_CDC_ANY_EVENT, callback); onEvent(ARDUINO_USB_CDC_ANY_EVENT, callback);
} }
@ -114,69 +119,23 @@ void USBCDC::onEvent(arduino_usb_cdc_event_t event, esp_event_handler_t callback
} }
size_t USBCDC::setRxBufferSize(size_t rx_queue_len){ size_t USBCDC::setRxBufferSize(size_t rx_queue_len){
size_t currentQueueSize = rx_queue ? if(rx_queue){
uxQueueSpacesAvailable(rx_queue) + uxQueueMessagesWaiting(rx_queue) : 0;
if (rx_queue_len != currentQueueSize) {
xQueueHandle new_rx_queue = NULL;
if (rx_queue_len) {
new_rx_queue = xQueueCreate(rx_queue_len, sizeof(uint8_t));
if(!new_rx_queue){
log_e("CDC Queue creation failed.");
return 0; return 0;
} }
if (rx_queue) { rx_queue = xQueueCreate(rx_queue_len, sizeof(uint8_t));
size_t copySize = uxQueueMessagesWaiting(rx_queue); if(!rx_queue){
if (copySize > 0) { return 0;
for(size_t i = 0; i < copySize; i++) {
uint8_t ch = 0;
xQueueReceive(rx_queue, &ch, 0);
if (!xQueueSend(new_rx_queue, &ch, 0)) {
arduino_usb_cdc_event_data_t p;
p.rx_overflow.dropped_bytes = copySize - i;
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_RX_OVERFLOW_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
log_e("CDC RX Overflow.");
break;
}
}
}
vQueueDelete(rx_queue);
}
rx_queue = new_rx_queue;
return rx_queue_len;
} else {
if (rx_queue) {
vQueueDelete(rx_queue);
rx_queue = NULL;
}
}
} }
return rx_queue_len; return rx_queue_len;
} }
void USBCDC::begin(unsigned long baud) void USBCDC::begin(unsigned long baud)
{ {
if(tx_lock == NULL) { setRxBufferSize(256);//default if not preset
tx_lock = xSemaphoreCreateMutex();
}
// if rx_queue was set before begin(), keep it
if (!rx_queue) setRxBufferSize(256); //default if not preset
devices[itf] = this;
} }
void USBCDC::end() void USBCDC::end()
{ {
connected = false;
devices[itf] = NULL;
setRxBufferSize(0);
if(tx_lock != NULL) {
vSemaphoreDelete(tx_lock);
tx_lock = NULL;
}
}
void USBCDC::setTxTimeoutMs(uint32_t timeout){
tx_timeout_ms = timeout;
} }
void USBCDC::_onUnplugged(void){ void USBCDC::_onUnplugged(void){
@ -184,7 +143,7 @@ void USBCDC::_onUnplugged(void){
connected = false; connected = false;
dtr = false; dtr = false;
rts = false; rts = false;
arduino_usb_cdc_event_data_t p; arduino_usb_cdc_event_data_t p = {0};
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_DISCONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY); arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_DISCONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
} }
} }
@ -192,11 +151,6 @@ void USBCDC::_onUnplugged(void){
enum { CDC_LINE_IDLE, CDC_LINE_1, CDC_LINE_2, CDC_LINE_3 }; enum { CDC_LINE_IDLE, CDC_LINE_1, CDC_LINE_2, CDC_LINE_3 };
void USBCDC::_onLineState(bool _dtr, bool _rts){ void USBCDC::_onLineState(bool _dtr, bool _rts){
static uint8_t lineState = CDC_LINE_IDLE; static uint8_t lineState = CDC_LINE_IDLE;
if(dtr == _dtr && rts == _rts){
return; // Skip duplicate events
}
dtr = _dtr; dtr = _dtr;
rts = _rts; rts = _rts;
@ -204,11 +158,6 @@ void USBCDC::_onLineState(bool _dtr, bool _rts){
if(!dtr && rts){ if(!dtr && rts){
if(lineState == CDC_LINE_IDLE){ if(lineState == CDC_LINE_IDLE){
lineState++; lineState++;
if(connected){
connected = false;
arduino_usb_cdc_event_data_t p;
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_DISCONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
}
} else { } else {
lineState = CDC_LINE_IDLE; lineState = CDC_LINE_IDLE;
} }
@ -236,14 +185,14 @@ void USBCDC::_onLineState(bool _dtr, bool _rts){
if(lineState == CDC_LINE_IDLE){ if(lineState == CDC_LINE_IDLE){
if(dtr && rts && !connected){ if(dtr && rts && !connected){
connected = true; connected = true;
arduino_usb_cdc_event_data_t p; arduino_usb_cdc_event_data_t p = {0};
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_CONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY); arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_CONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
} else if(!dtr && connected){ } else if(!dtr && !rts && connected){
connected = false; connected = false;
arduino_usb_cdc_event_data_t p; arduino_usb_cdc_event_data_t p = {0};
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_DISCONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY); arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_DISCONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
} }
arduino_usb_cdc_event_data_t l; arduino_usb_cdc_event_data_t l = {0};
l.line_state.dtr = dtr; l.line_state.dtr = dtr;
l.line_state.rts = rts; l.line_state.rts = rts;
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_LINE_STATE_EVENT, &l, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY); arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_LINE_STATE_EVENT, &l, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
@ -253,46 +202,30 @@ void USBCDC::_onLineState(bool _dtr, bool _rts){
void USBCDC::_onLineCoding(uint32_t _bit_rate, uint8_t _stop_bits, uint8_t _parity, uint8_t _data_bits){ void USBCDC::_onLineCoding(uint32_t _bit_rate, uint8_t _stop_bits, uint8_t _parity, uint8_t _data_bits){
if(bit_rate != _bit_rate || data_bits != _data_bits || stop_bits != _stop_bits || parity != _parity){ if(bit_rate != _bit_rate || data_bits != _data_bits || stop_bits != _stop_bits || parity != _parity){
// ArduinoIDE sends LineCoding with 1200bps baud to reset the device
if(reboot_enable && _bit_rate == 1200){
usb_persist_restart(RESTART_BOOTLOADER);
} else {
bit_rate = _bit_rate; bit_rate = _bit_rate;
data_bits = _data_bits; data_bits = _data_bits;
stop_bits = _stop_bits; stop_bits = _stop_bits;
parity = _parity; parity = _parity;
arduino_usb_cdc_event_data_t p; arduino_usb_cdc_event_data_t p = {0};
p.line_coding.bit_rate = bit_rate; p.line_coding.bit_rate = bit_rate;
p.line_coding.data_bits = data_bits; p.line_coding.data_bits = data_bits;
p.line_coding.stop_bits = stop_bits; p.line_coding.stop_bits = stop_bits;
p.line_coding.parity = parity; p.line_coding.parity = parity;
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_LINE_CODING_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY); arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_LINE_CODING_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
} }
}
} }
void USBCDC::_onRX(){ void USBCDC::_onRX(){
arduino_usb_cdc_event_data_t p; uint8_t buf[CONFIG_USB_CDC_RX_BUFSIZE+1];
uint8_t buf[CONFIG_TINYUSB_CDC_RX_BUFSIZE+1]; uint32_t count = tud_cdc_n_read(itf, buf, CONFIG_USB_CDC_RX_BUFSIZE);
uint32_t count = tud_cdc_n_read(itf, buf, CONFIG_TINYUSB_CDC_RX_BUFSIZE);
for(uint32_t i=0; i<count; i++){ for(uint32_t i=0; i<count; i++){
if(rx_queue == NULL || !xQueueSend(rx_queue, buf+i, 10)) { if(rx_queue == NULL || !xQueueSend(rx_queue, buf+i, 0)){
p.rx_overflow.dropped_bytes = count - i; return;
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_RX_OVERFLOW_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
log_e("CDC RX Overflow.");
count = i;
break;
} }
} }
if (count) { arduino_usb_cdc_event_data_t p = {0};
p.rx.len = count; p.rx.len = count;
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_RX_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY); arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_RX_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
}
}
void USBCDC::_onTX(){
arduino_usb_cdc_event_data_t p;
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_TX_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
} }
void USBCDC::enableReboot(bool enable){ void USBCDC::enableReboot(bool enable){
@ -349,73 +282,23 @@ size_t USBCDC::read(uint8_t *buffer, size_t size)
void USBCDC::flush(void) void USBCDC::flush(void)
{ {
if(itf >= MAX_USB_CDC_DEVICES || tx_lock == NULL || !tud_cdc_n_connected(itf)){ if(itf >= MAX_USB_CDC_DEVICES){
return;
}
if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){
return; return;
} }
tud_cdc_n_write_flush(itf); tud_cdc_n_write_flush(itf);
xSemaphoreGive(tx_lock);
} }
int USBCDC::availableForWrite(void) int USBCDC::availableForWrite(void)
{ {
if(itf >= MAX_USB_CDC_DEVICES || tx_lock == NULL || !tud_cdc_n_connected(itf)){ if(itf >= MAX_USB_CDC_DEVICES){
return 0; return -1;
} }
if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){ return tud_cdc_n_write_available(itf);
return 0;
}
size_t a = tud_cdc_n_write_available(itf);
xSemaphoreGive(tx_lock);
return a;
} }
size_t USBCDC::write(const uint8_t *buffer, size_t size) size_t USBCDC::write(const uint8_t *buffer, size_t size)
{ {
if(itf >= MAX_USB_CDC_DEVICES || tx_lock == NULL || buffer == NULL || size == 0 || !tud_cdc_n_connected(itf)){ return tinyusb_cdc_write(itf, buffer, size);
return 0;
}
if(xPortInIsrContext()){
BaseType_t taskWoken = false;
if(xSemaphoreTakeFromISR(tx_lock, &taskWoken) != pdPASS){
return 0;
}
} else if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){
return 0;
}
size_t to_send = size, so_far = 0;
while(to_send){
if(!tud_cdc_n_connected(itf)){
size = so_far;
break;
}
size_t space = tud_cdc_n_write_available(itf);
if(!space){
tud_cdc_n_write_flush(itf);
continue;
}
if(space > to_send){
space = to_send;
}
size_t sent = tud_cdc_n_write(itf, buffer+so_far, space);
if(sent){
so_far += sent;
to_send -= sent;
tud_cdc_n_write_flush(itf);
} else {
size = so_far;
break;
}
}
if(xPortInIsrContext()){
BaseType_t taskWoken = false;
xSemaphoreGiveFromISR(tx_lock, &taskWoken);
} else {
xSemaphoreGive(tx_lock);
}
return size;
} }
size_t USBCDC::write(uint8_t c) size_t USBCDC::write(uint8_t c)
@ -446,8 +329,10 @@ USBCDC::operator bool() const
return connected; return connected;
} }
#if ARDUINO_USB_CDC_ON_BOOT && !ARDUINO_USB_MODE //Serial used for USB CDC #if ARDUINO_SERIAL_PORT //Serial used for USB CDC
USBCDC Serial(0); USBCDC Serial(0);
#endif #endif
#endif /* CONFIG_TINYUSB_CDC_ENABLED */ #endif /* CONFIG_USB_CDC_ENABLED */
#endif /* CONFIG_USB_ENABLED */

View File

@ -13,15 +13,13 @@
// limitations under the License. // limitations under the License.
#pragma once #pragma once
#include "sdkconfig.h"
#if CONFIG_TINYUSB_CDC_ENABLED
#include <inttypes.h> #include <inttypes.h>
#include "esp_event.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "Stream.h" #include "Stream.h"
#include "esp32-hal.h"
#if CONFIG_USB_CDC_ENABLED
#include "esp_event.h"
ESP_EVENT_DECLARE_BASE(ARDUINO_USB_CDC_EVENTS); ESP_EVENT_DECLARE_BASE(ARDUINO_USB_CDC_EVENTS);
@ -32,8 +30,6 @@ typedef enum {
ARDUINO_USB_CDC_LINE_STATE_EVENT, ARDUINO_USB_CDC_LINE_STATE_EVENT,
ARDUINO_USB_CDC_LINE_CODING_EVENT, ARDUINO_USB_CDC_LINE_CODING_EVENT,
ARDUINO_USB_CDC_RX_EVENT, ARDUINO_USB_CDC_RX_EVENT,
ARDUINO_USB_CDC_TX_EVENT,
ARDUINO_USB_CDC_RX_OVERFLOW_EVENT,
ARDUINO_USB_CDC_MAX_EVENT, ARDUINO_USB_CDC_MAX_EVENT,
} arduino_usb_cdc_event_t; } arduino_usb_cdc_event_t;
@ -51,22 +47,17 @@ typedef union {
struct { struct {
size_t len; size_t len;
} rx; } rx;
struct {
size_t dropped_bytes;
} rx_overflow;
} arduino_usb_cdc_event_data_t; } arduino_usb_cdc_event_data_t;
class USBCDC: public Stream class USBCDC: public Stream
{ {
public: public:
USBCDC(uint8_t itf=0); USBCDC(uint8_t itf=0);
~USBCDC();
void onEvent(esp_event_handler_t callback); void onEvent(esp_event_handler_t callback);
void onEvent(arduino_usb_cdc_event_t event, esp_event_handler_t callback); void onEvent(arduino_usb_cdc_event_t event, esp_event_handler_t callback);
size_t setRxBufferSize(size_t size); size_t setRxBufferSize(size_t);
void setTxTimeoutMs(uint32_t timeout);
void begin(unsigned long baud=0); void begin(unsigned long baud=0);
void end(); void end();
@ -119,7 +110,6 @@ public:
void _onLineState(bool _dtr, bool _rts); void _onLineState(bool _dtr, bool _rts);
void _onLineCoding(uint32_t _bit_rate, uint8_t _stop_bits, uint8_t _parity, uint8_t _data_bits); void _onLineCoding(uint32_t _bit_rate, uint8_t _stop_bits, uint8_t _parity, uint8_t _data_bits);
void _onRX(void); void _onRX(void);
void _onTX(void);
void _onUnplugged(void); void _onUnplugged(void);
protected: protected:
@ -133,13 +123,11 @@ protected:
bool connected; bool connected;
bool reboot_enable; bool reboot_enable;
xQueueHandle rx_queue; xQueueHandle rx_queue;
xSemaphoreHandle tx_lock;
uint32_t tx_timeout_ms;
}; };
#if ARDUINO_USB_CDC_ON_BOOT && !ARDUINO_USB_MODE //Serial used for USB CDC #if ARDUINO_SERIAL_PORT //Serial used for USB CDC
extern USBCDC Serial; extern USBCDC Serial;
#endif #endif
#endif /* CONFIG_TINYUSB_CDC_ENABLED */ #endif /* CONFIG_USB_CDC_ENABLED */

View File

@ -1,260 +0,0 @@
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "USBMSC.h"
#if CONFIG_TINYUSB_MSC_ENABLED
#include "esp32-hal-tinyusb.h"
extern "C" uint16_t tusb_msc_load_descriptor(uint8_t * dst, uint8_t * itf)
{
uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB MSC");
uint8_t ep_num = tinyusb_get_free_duplex_endpoint();
TU_VERIFY (ep_num != 0);
uint8_t descriptor[TUD_MSC_DESC_LEN] = {
// Interface number, string index, EP Out & EP In address, EP size
TUD_MSC_DESCRIPTOR(*itf, str_index, ep_num, (uint8_t)(0x80 | ep_num), 64)
};
*itf+=1;
memcpy(dst, descriptor, TUD_MSC_DESC_LEN);
return TUD_MSC_DESC_LEN;
}
typedef struct {
bool media_present;
uint8_t vendor_id[8];
uint8_t product_id[16];
uint8_t product_rev[4];
uint16_t block_size;
uint32_t block_count;
bool (*start_stop)(uint8_t power_condition, bool start, bool load_eject);
int32_t (*read)(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize);
int32_t (*write)(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize);
} msc_lun_t;
static const uint8_t MSC_MAX_LUN = 3;
static uint8_t MSC_ACTIVE_LUN = 0;
static msc_lun_t msc_luns[MSC_MAX_LUN];
static void cplstr(void *dst, const void * src, size_t max_len){
if(!src || !dst || !max_len){
return;
}
size_t l = strlen((const char *)src);
if(l > max_len){
l = max_len;
}
memcpy(dst, src, l);
}
// Invoked when received GET_MAX_LUN request, required for multiple LUNs implementation
uint8_t tud_msc_get_maxlun_cb(void)
{
log_v("%u", MSC_ACTIVE_LUN);
return MSC_ACTIVE_LUN;
}
// Invoked when received SCSI_CMD_INQUIRY
// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4])
{
log_v("[%u]", lun);
cplstr(vendor_id , msc_luns[lun].vendor_id, 8);
cplstr(product_id , msc_luns[lun].product_id, 16);
cplstr(product_rev, msc_luns[lun].product_rev, 4);
}
// Invoked when received Test Unit Ready command.
// return true allowing host to read/write this LUN e.g SD card inserted
bool tud_msc_test_unit_ready_cb(uint8_t lun)
{
log_v("[%u]: %u", lun, msc_luns[lun].media_present);
return msc_luns[lun].media_present; // RAM disk is always ready
}
// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
// Application update block count and block size
void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size)
{
log_v("[%u]", lun);
if(!msc_luns[lun].media_present){
*block_count = 0;
*block_size = 0;
return;
}
*block_count = msc_luns[lun].block_count;
*block_size = msc_luns[lun].block_size;
}
// Invoked when received Start Stop Unit command
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject)
{
log_v("[%u] power: %u, start: %u, eject: %u", lun, power_condition, start, load_eject);
if(msc_luns[lun].start_stop){
return msc_luns[lun].start_stop(power_condition, start, load_eject);
}
return true;
}
// Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
{
log_v("[%u], lba: %u, offset: %u, bufsize: %u", lun, lba, offset, bufsize);
if(!msc_luns[lun].media_present){
return 0;
}
if(msc_luns[lun].read){
return msc_luns[lun].read(lba, offset, buffer, bufsize);
}
return 0;
}
// Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and return number of written bytes
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize)
{
log_v("[%u], lba: %u, offset: %u, bufsize: %u", lun, lba, offset, bufsize);
if(!msc_luns[lun].media_present){
return 0;
}
if(msc_luns[lun].write){
return msc_luns[lun].write(lba, offset, buffer, bufsize);
}
return 0;
}
// Callback invoked when received an SCSI command not in built-in list below
// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
// - READ10 and WRITE10 has their own callbacks
int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize)
{
// read10 & write10 has their own callback and MUST not be handled here
log_v("[%u] cmd: %u, bufsize: %u", lun, scsi_cmd[0], bufsize);
void const* response = NULL;
uint16_t resplen = 0;
// most scsi handled is input
bool in_xfer = true;
if(!msc_luns[lun].media_present){
return -1;
}
switch (scsi_cmd[0]) {
case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
// Host is about to read/write etc ... better not to disconnect disk
resplen = 0;
break;
default:
// Set Sense = Invalid Command Operation
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
// negative means error -> tinyusb could stall and/or response with failed status
resplen = -1;
break;
}
// return resplen must not larger than bufsize
if (resplen > bufsize) resplen = bufsize;
if (response && (resplen > 0)) {
if (in_xfer) {
memcpy(buffer, response, resplen);
} else {
// SCSI output
}
}
return resplen;
}
USBMSC::USBMSC(){
if(MSC_ACTIVE_LUN < MSC_MAX_LUN){
_lun = MSC_ACTIVE_LUN;
MSC_ACTIVE_LUN++;
msc_luns[_lun].media_present = false;
msc_luns[_lun].vendor_id[0] = 0;
msc_luns[_lun].product_id[0] = 0;
msc_luns[_lun].product_rev[0] = 0;
msc_luns[_lun].block_size = 0;
msc_luns[_lun].block_count = 0;
msc_luns[_lun].start_stop = NULL;
msc_luns[_lun].read = NULL;
msc_luns[_lun].write = NULL;
}
if(_lun == 0){
tinyusb_enable_interface(USB_INTERFACE_MSC, TUD_MSC_DESC_LEN, tusb_msc_load_descriptor);
}
}
USBMSC::~USBMSC(){
end();
}
bool USBMSC::begin(uint32_t block_count, uint16_t block_size){
msc_luns[_lun].block_size = block_size;
msc_luns[_lun].block_count = block_count;
if(!msc_luns[_lun].block_size || !msc_luns[_lun].block_count || !msc_luns[_lun].read || !msc_luns[_lun].write){
return false;
}
return true;
}
void USBMSC::end(){
msc_luns[_lun].media_present = false;
msc_luns[_lun].vendor_id[0] = 0;
msc_luns[_lun].product_id[0] = 0;
msc_luns[_lun].product_rev[0] = 0;
msc_luns[_lun].block_size = 0;
msc_luns[_lun].block_count = 0;
msc_luns[_lun].start_stop = NULL;
msc_luns[_lun].read = NULL;
msc_luns[_lun].write = NULL;
}
void USBMSC::vendorID(const char * vid){
cplstr(msc_luns[_lun].vendor_id, vid, 8);
}
void USBMSC::productID(const char * pid){
cplstr(msc_luns[_lun].product_id, pid, 16);
}
void USBMSC::productRevision(const char * rev){
cplstr(msc_luns[_lun].product_rev, rev, 4);
}
void USBMSC::onStartStop(msc_start_stop_cb cb){
msc_luns[_lun].start_stop = cb;
}
void USBMSC::onRead(msc_read_cb cb){
msc_luns[_lun].read = cb;
}
void USBMSC::onWrite(msc_write_cb cb){
msc_luns[_lun].write = cb;
}
void USBMSC::mediaPresent(bool media_present){
msc_luns[_lun].media_present = media_present;
}
#endif /* CONFIG_TINYUSB_MSC_ENABLED */

View File

@ -1,51 +0,0 @@
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "sdkconfig.h"
#if CONFIG_TINYUSB_MSC_ENABLED
// Invoked when received Start Stop Unit command
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
typedef bool (*msc_start_stop_cb)(uint8_t power_condition, bool start, bool load_eject);
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
typedef int32_t (*msc_read_cb)(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize);
// Process data in buffer to disk's storage and return number of written bytes
typedef int32_t (*msc_write_cb)(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize);
class USBMSC
{
public:
USBMSC();
~USBMSC();
bool begin(uint32_t block_count, uint16_t block_size);
void end();
void vendorID(const char * vid);//max 8 chars
void productID(const char * pid);//max 16 chars
void productRevision(const char * ver);//max 4 chars
void mediaPresent(bool media_present);
void onStartStop(msc_start_stop_cb cb);
void onRead(msc_read_cb cb);
void onWrite(msc_write_cb cb);
private:
uint8_t _lun;
};
#endif /* CONFIG_TINYUSB_MSC_ENABLED */

View File

@ -27,7 +27,6 @@ extern "C" {
#include <stdlib.h> #include <stdlib.h>
#include "esp_system.h" #include "esp_system.h"
} }
#include "esp32-hal-log.h"
void randomSeed(unsigned long seed) void randomSeed(unsigned long seed)
{ {
@ -67,22 +66,19 @@ long random(long howsmall, long howbig)
} }
long map(long x, long in_min, long in_max, long out_min, long out_max) { long map(long x, long in_min, long in_max, long out_min, long out_max) {
const long run = in_max - in_min; const long dividend = out_max - out_min;
if(run == 0){ const long divisor = in_max - in_min;
log_e("map(): Invalid input range, min == max");
return -1; // AVR returns -1, SAM returns 0
}
const long rise = out_max - out_min;
const long delta = x - in_min; const long delta = x - in_min;
return (delta * rise) / run + out_min;
return (delta * dividend + (divisor / 2)) / divisor + out_min;
} }
uint16_t makeWord(uint16_t w) unsigned int makeWord(unsigned int w)
{ {
return w; return w;
} }
uint16_t makeWord(uint8_t h, uint8_t l) unsigned int makeWord(unsigned char h, unsigned char l)
{ {
return (h << 8) | l; return (h << 8) | l;
} }

View File

@ -24,7 +24,6 @@
#include <Arduino.h> #include <Arduino.h>
#include "WString.h" #include "WString.h"
#include "stdlib_noniso.h" #include "stdlib_noniso.h"
#include "esp32-hal-log.h"
/*********************************************/ /*********************************************/
/* Constructors */ /* Constructors */
@ -36,12 +35,6 @@ String::String(const char *cstr) {
copy(cstr, strlen(cstr)); copy(cstr, strlen(cstr));
} }
String::String(const char *cstr, unsigned int length) {
init();
if (cstr)
copy(cstr, length);
}
String::String(const String &value) { String::String(const String &value) {
init(); init();
*this = value; *this = value;
@ -66,7 +59,9 @@ String::String(StringSumHelper &&rval) {
String::String(char c) { String::String(char c) {
init(); init();
char buf[] = { c, '\0' }; char buf[2];
buf[0] = c;
buf[1] = 0;
*this = buf; *this = buf;
} }
@ -113,46 +108,16 @@ String::String(unsigned long value, unsigned char base) {
*this = buf; *this = buf;
} }
String::String(float value, unsigned int decimalPlaces) { String::String(float value, unsigned char decimalPlaces) {
init(); init();
char *buf = (char*)malloc(decimalPlaces + 42); char buf[33];
if (buf) {
*this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf); *this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf);
free(buf);
} else {
*this = "nan";
log_e("No enought memory for the operation.");
}
} }
String::String(double value, unsigned int decimalPlaces) { String::String(double value, unsigned char decimalPlaces) {
init(); init();
char *buf = (char*)malloc(decimalPlaces + 312); char buf[33];
if (buf) {
*this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf); *this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf);
free(buf);
} else {
*this = "nan";
log_e("No enought memory for the operation.");
}
}
String::String(long long value, unsigned char base) {
init();
char buf[2 + 8 * sizeof(long long)];
if (base==10) {
sprintf(buf, "%lld", value); // NOT SURE - NewLib Nano ... does it support %lld?
} else {
lltoa(value, buf, base);
}
*this = buf;
}
String::String(unsigned long long value, unsigned char base) {
init();
char buf[1 + 8 * sizeof(unsigned long long)];
ulltoa(value, buf, base);
*this = buf;
} }
String::~String() { String::~String() {
@ -165,9 +130,9 @@ String::~String() {
inline void String::init(void) { inline void String::init(void) {
setSSO(false); setSSO(false);
setBuffer(nullptr);
setCapacity(0); setCapacity(0);
setLen(0); setLen(0);
setBuffer(nullptr);
} }
void String::invalidate(void) { void String::invalidate(void) {
@ -203,8 +168,8 @@ unsigned char String::changeBuffer(unsigned int maxStrLen) {
free(wbuffer()); free(wbuffer());
uint16_t oldLen = len(); uint16_t oldLen = len();
setSSO(true); setSSO(true);
memcpy(wbuffer(), temp, maxStrLen);
setLen(oldLen); setLen(oldLen);
memcpy(wbuffer(), temp, maxStrLen);
return 1; return 1;
} }
} }
@ -228,8 +193,8 @@ unsigned char String::changeBuffer(unsigned int maxStrLen) {
} }
setSSO(false); setSSO(false);
setCapacity(newSize - 1); setCapacity(newSize - 1);
setBuffer(newbuffer);
setLen(oldLen); // Needed in case of SSO where len() never existed setLen(oldLen); // Needed in case of SSO where len() never existed
setBuffer(newbuffer);
return 1; return 1;
} }
return 0; return 0;
@ -244,8 +209,8 @@ String & String::copy(const char *cstr, unsigned int length) {
invalidate(); invalidate();
return *this; return *this;
} }
memmove(wbuffer(), cstr, length + 1);
setLen(length); setLen(length);
memmove(wbuffer(), cstr, length + 1);
return *this; return *this;
} }
@ -254,8 +219,8 @@ String & String::copy(const __FlashStringHelper *pstr, unsigned int length) {
invalidate(); invalidate();
return *this; return *this;
} }
memcpy_P(wbuffer(), (PGM_P)pstr, length + 1); // We know wbuffer() cannot ever be in PROGMEM, so memcpy safe here
setLen(length); setLen(length);
memcpy_P(wbuffer(), (PGM_P)pstr, length + 1); // We know wbuffer() cannot ever be in PROGMEM, so memcpy safe here
return *this; return *this;
} }
@ -285,8 +250,8 @@ void String::move(String &rhs) {
setLen(rhs.len()); setLen(rhs.len());
rhs.setSSO(false); rhs.setSSO(false);
rhs.setCapacity(0); rhs.setCapacity(0);
rhs.setBuffer(nullptr);
rhs.setLen(0); rhs.setLen(0);
rhs.setBuffer(nullptr);
} }
#endif #endif
@ -325,11 +290,10 @@ String & String::operator =(const char *cstr) {
return *this; return *this;
} }
String & String::operator =(const __FlashStringHelper *pstr) { String & String::operator = (const __FlashStringHelper *pstr)
if(pstr) {
copy(pstr, strlen_P((PGM_P)pstr)); if (pstr) copy(pstr, strlen_P((PGM_P)pstr));
else else invalidate();
invalidate();
return *this; return *this;
} }
@ -383,18 +347,22 @@ unsigned char String::concat(const char *cstr) {
} }
unsigned char String::concat(char c) { unsigned char String::concat(char c) {
char buf[] = { c, '\0' }; char buf[2];
buf[0] = c;
buf[1] = 0;
return concat(buf, 1); return concat(buf, 1);
} }
unsigned char String::concat(unsigned char num) { unsigned char String::concat(unsigned char num) {
char buf[1 + 3 * sizeof(unsigned char)]; char buf[1 + 3 * sizeof(unsigned char)];
return concat(buf, sprintf(buf, "%d", num)); sprintf(buf, "%d", num);
return concat(buf, strlen(buf));
} }
unsigned char String::concat(int num) { unsigned char String::concat(int num) {
char buf[2 + 3 * sizeof(int)]; char buf[2 + 3 * sizeof(int)];
return concat(buf, sprintf(buf, "%d", num)); sprintf(buf, "%d", num);
return concat(buf, strlen(buf));
} }
unsigned char String::concat(unsigned int num) { unsigned char String::concat(unsigned int num) {
@ -405,7 +373,8 @@ unsigned char String::concat(unsigned int num) {
unsigned char String::concat(long num) { unsigned char String::concat(long num) {
char buf[2 + 3 * sizeof(long)]; char buf[2 + 3 * sizeof(long)];
return concat(buf, sprintf(buf, "%ld", num)); sprintf(buf, "%ld", num);
return concat(buf, strlen(buf));
} }
unsigned char String::concat(unsigned long num) { unsigned char String::concat(unsigned long num) {
@ -426,17 +395,6 @@ unsigned char String::concat(double num) {
return concat(string, strlen(string)); return concat(string, strlen(string));
} }
unsigned char String::concat(long long num) {
char buf[2 + 3 * sizeof(long long)];
return concat(buf, sprintf(buf, "%lld", num)); // NOT SURE - NewLib Nano ... does it support %lld?
}
unsigned char String::concat(unsigned long long num) {
char buf[1 + 3 * sizeof(unsigned long long)];
ulltoa(num, buf, 10);
return concat(buf, strlen(buf));
}
unsigned char String::concat(const __FlashStringHelper * str) { unsigned char String::concat(const __FlashStringHelper * str) {
if (!str) return 0; if (!str) return 0;
int length = strlen_P((PGM_P)str); int length = strlen_P((PGM_P)str);
@ -522,20 +480,6 @@ StringSumHelper & operator +(const StringSumHelper &lhs, double num) {
return a; return a;
} }
StringSumHelper & operator +(const StringSumHelper &lhs, long long num) {
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
if(!a.concat(num))
a.invalidate();
return a;
}
StringSumHelper & operator +(const StringSumHelper &lhs, unsigned long long num) {
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
if(!a.concat(num))
a.invalidate();
return a;
}
StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs) StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs)
{ {
StringSumHelper &a = const_cast<StringSumHelper&>(lhs); StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
@ -611,7 +555,7 @@ unsigned char String::equalsConstantTime(const String &s2) const {
//at this point lengths are the same //at this point lengths are the same
if(len() == 0) if(len() == 0)
return 1; return 1;
//at this point lengths are the same and non-zero //at this point lenghts are the same and non-zero
const char *p1 = buffer(); const char *p1 = buffer();
const char *p2 = s2.buffer(); const char *p2 = s2.buffer();
unsigned int equalchars = 0; unsigned int equalchars = 0;
@ -767,7 +711,10 @@ String String::substring(unsigned int left, unsigned int right) const {
return out; return out;
if(right > len()) if(right > len())
right = len(); right = len();
out.copy(buffer() + left, right - left); char temp = buffer()[right]; // save the replaced character
wbuffer()[right] = '\0';
out = wbuffer() + left; // pointer arithmetic
wbuffer()[right] = temp; //restore character
return out; return out;
} }
@ -797,7 +744,6 @@ void String::replace(const String& find, const String& replace) {
} }
} else if(diff < 0) { } else if(diff < 0) {
char *writeTo = wbuffer(); char *writeTo = wbuffer();
unsigned int l = len();
while((foundAt = strstr(readFrom, find.buffer())) != NULL) { while((foundAt = strstr(readFrom, find.buffer())) != NULL) {
unsigned int n = foundAt - readFrom; unsigned int n = foundAt - readFrom;
memmove(writeTo, readFrom, n); memmove(writeTo, readFrom, n);
@ -805,10 +751,9 @@ void String::replace(const String& find, const String& replace) {
memmove(writeTo, replace.buffer(), replace.len()); memmove(writeTo, replace.buffer(), replace.len());
writeTo += replace.len(); writeTo += replace.len();
readFrom = foundAt + find.len(); readFrom = foundAt + find.len();
l += diff; setLen(len() + diff);
} }
memmove(writeTo, readFrom, strlen(readFrom)+1); memmove(writeTo, readFrom, strlen(readFrom)+1);
setLen(l);
} else { } else {
unsigned int size = len(); // compute size needed for result unsigned int size = len(); // compute size needed for result
while((foundAt = strstr(readFrom, find.buffer())) != NULL) { while((foundAt = strstr(readFrom, find.buffer())) != NULL) {
@ -817,10 +762,8 @@ void String::replace(const String& find, const String& replace) {
} }
if(size == len()) if(size == len())
return; return;
if(size > capacity() && !changeBuffer(size)) { if(size > capacity() && !changeBuffer(size))
log_w("String.Replace() Insufficient space to replace string"); return; // XXX: tell user!
return;
}
int index = len() - 1; int index = len() - 1;
while(index >= 0 && (index = lastIndexOf(find, index)) >= 0) { while(index >= 0 && (index = lastIndexOf(find, index)) >= 0) {
readFrom = wbuffer() + index + find.len(); readFrom = wbuffer() + index + find.len();
@ -853,8 +796,8 @@ void String::remove(unsigned int index, unsigned int count) {
} }
char *writeTo = wbuffer() + index; char *writeTo = wbuffer() + index;
unsigned int newlen = len() - count; unsigned int newlen = len() - count;
memmove(writeTo, wbuffer() + index + count, newlen - index);
setLen(newlen); setLen(newlen);
memmove(writeTo, wbuffer() + index + count, newlen - index);
wbuffer()[newlen] = 0; wbuffer()[newlen] = 0;
} }
@ -884,9 +827,9 @@ void String::trim(void) {
while(isspace(*end) && end >= begin) while(isspace(*end) && end >= begin)
end--; end--;
unsigned int newlen = end + 1 - begin; unsigned int newlen = end + 1 - begin;
setLen(newlen);
if(begin > buffer()) if(begin > buffer())
memmove(wbuffer(), begin, newlen); memmove(wbuffer(), begin, newlen);
setLen(newlen);
wbuffer()[newlen] = 0; wbuffer()[newlen] = 0;
} }

View File

@ -55,10 +55,6 @@ class String {
// fails, the string will be marked as invalid (i.e. "if (s)" will // fails, the string will be marked as invalid (i.e. "if (s)" will
// be false). // be false).
String(const char *cstr = ""); String(const char *cstr = "");
String(const char *cstr, unsigned int length);
#ifdef __GXX_EXPERIMENTAL_CXX0X__
String(const uint8_t *cstr, unsigned int length) : String((const char*)cstr, length) {}
#endif
String(const String &str); String(const String &str);
String(const __FlashStringHelper *str); String(const __FlashStringHelper *str);
#ifdef __GXX_EXPERIMENTAL_CXX0X__ #ifdef __GXX_EXPERIMENTAL_CXX0X__
@ -71,10 +67,8 @@ class String {
explicit String(unsigned int, unsigned char base = 10); explicit String(unsigned int, unsigned char base = 10);
explicit String(long, unsigned char base = 10); explicit String(long, unsigned char base = 10);
explicit String(unsigned long, unsigned char base = 10); explicit String(unsigned long, unsigned char base = 10);
explicit String(float, unsigned int decimalPlaces = 2); explicit String(float, unsigned char decimalPlaces = 2);
explicit String(double, unsigned int decimalPlaces = 2); explicit String(double, unsigned char decimalPlaces = 2);
explicit String(long long, unsigned char base = 10);
explicit String(unsigned long long, unsigned char base = 10);
~String(void); ~String(void);
// memory management // memory management
@ -114,8 +108,6 @@ class String {
// concatenation is considered unsuccessful. // concatenation is considered unsuccessful.
unsigned char concat(const String &str); unsigned char concat(const String &str);
unsigned char concat(const char *cstr); unsigned char concat(const char *cstr);
unsigned char concat(const char *cstr, unsigned int length);
unsigned char concat(const uint8_t *cstr, unsigned int length) {return concat((const char*)cstr, length);}
unsigned char concat(char c); unsigned char concat(char c);
unsigned char concat(unsigned char c); unsigned char concat(unsigned char c);
unsigned char concat(int num); unsigned char concat(int num);
@ -124,8 +116,6 @@ class String {
unsigned char concat(unsigned long num); unsigned char concat(unsigned long num);
unsigned char concat(float num); unsigned char concat(float num);
unsigned char concat(double num); unsigned char concat(double num);
unsigned char concat(long long num);
unsigned char concat(unsigned long long num);
unsigned char concat(const __FlashStringHelper * str); unsigned char concat(const __FlashStringHelper * str);
// if there's not enough memory for the concatenated value, the string // if there's not enough memory for the concatenated value, the string
@ -170,14 +160,6 @@ class String {
concat(num); concat(num);
return (*this); return (*this);
} }
String & operator +=(long long num) {
concat(num);
return (*this);
}
String & operator +=(unsigned long long num) {
concat(num);
return (*this);
}
String & operator += (const __FlashStringHelper *str){ String & operator += (const __FlashStringHelper *str){
concat(str); concat(str);
return (*this); return (*this);
@ -194,8 +176,6 @@ class String {
friend StringSumHelper & operator +(const StringSumHelper &lhs, float num); friend StringSumHelper & operator +(const StringSumHelper &lhs, float num);
friend StringSumHelper & operator +(const StringSumHelper &lhs, double num); friend StringSumHelper & operator +(const StringSumHelper &lhs, double num);
friend StringSumHelper & operator +(const StringSumHelper &lhs, const __FlashStringHelper *rhs); friend StringSumHelper & operator +(const StringSumHelper &lhs, const __FlashStringHelper *rhs);
friend StringSumHelper & operator +(const StringSumHelper &lhs, long long num);
friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned long long num);
// comparison (only works w/ Strings and "strings") // comparison (only works w/ Strings and "strings")
operator StringIfHelperType() const { operator StringIfHelperType() const {
@ -301,8 +281,8 @@ class String {
// Contains the string info when we're not in SSO mode // Contains the string info when we're not in SSO mode
struct _ptr { struct _ptr {
char * buff; char * buff;
uint32_t cap; uint16_t cap;
uint32_t len; uint16_t len;
}; };
// This allows strings up up to 11 (10 + \0 termination) without any extra space. // This allows strings up up to 11 (10 + \0 termination) without any extra space.
enum { SSOSIZE = sizeof(struct _ptr) + 4 - 1 }; // Characters to allocate space for SSO, must be 12 or more enum { SSOSIZE = sizeof(struct _ptr) + 4 - 1 }; // Characters to allocate space for SSO, must be 12 or more
@ -311,11 +291,7 @@ class String {
unsigned char len : 7; // Ensure only one byte is allocated by GCC for the bitfields unsigned char len : 7; // Ensure only one byte is allocated by GCC for the bitfields
unsigned char isSSO : 1; unsigned char isSSO : 1;
} __attribute__((packed)); // Ensure that GCC doesn't expand the flag byte to a 32-bit word for alignment issues } __attribute__((packed)); // Ensure that GCC doesn't expand the flag byte to a 32-bit word for alignment issues
#ifdef BOARD_HAS_PSRAM enum { CAPACITY_MAX = 65535 }; // If typeof(cap) changed from uint16_t, be sure to update this enum to the max value storable in the type
enum { CAPACITY_MAX = 3145728 };
#else
enum { CAPACITY_MAX = 65535 };
#endif
union { union {
struct _ptr ptr; struct _ptr ptr;
struct _sso sso; struct _sso sso;
@ -325,17 +301,7 @@ class String {
inline unsigned int len() const { return isSSO() ? sso.len : ptr.len; } inline unsigned int len() const { return isSSO() ? sso.len : ptr.len; }
inline unsigned int capacity() const { return isSSO() ? (unsigned int)SSOSIZE - 1 : ptr.cap; } // Size of max string not including terminal NUL inline unsigned int capacity() const { return isSSO() ? (unsigned int)SSOSIZE - 1 : ptr.cap; } // Size of max string not including terminal NUL
inline void setSSO(bool set) { sso.isSSO = set; } inline void setSSO(bool set) { sso.isSSO = set; }
inline void setLen(int len) { inline void setLen(int len) { if (isSSO()) sso.len = len; else ptr.len = len; }
if (isSSO()) {
sso.len = len;
sso.buff[len] = 0;
} else {
ptr.len = len;
if (ptr.buff) {
ptr.buff[len] = 0;
}
}
}
inline void setCapacity(int cap) { if (!isSSO()) ptr.cap = cap; } inline void setCapacity(int cap) { if (!isSSO()) ptr.cap = cap; }
inline void setBuffer(char *buff) { if (!isSSO()) ptr.buff = buff; } inline void setBuffer(char *buff) { if (!isSSO()) ptr.buff = buff; }
// Buffer accessor functions // Buffer accessor functions
@ -346,6 +312,7 @@ class String {
void init(void); void init(void);
void invalidate(void); void invalidate(void);
unsigned char changeBuffer(unsigned int maxStrLen); unsigned char changeBuffer(unsigned int maxStrLen);
unsigned char concat(const char *cstr, unsigned int length);
// copy and move // copy and move
String & copy(const char *cstr, unsigned int length); String & copy(const char *cstr, unsigned int length);
@ -387,12 +354,6 @@ class StringSumHelper: public String {
StringSumHelper(double num) : StringSumHelper(double num) :
String(num) { String(num) {
} }
StringSumHelper(long long num) :
String(num) {
}
StringSumHelper(unsigned long long num) :
String(num) {
}
}; };
extern const String emptyString; extern const String emptyString;

View File

@ -62,7 +62,7 @@ public:
cbuf *next; cbuf *next;
protected: private:
inline char* wrap_if_bufend(char* ptr) const inline char* wrap_if_bufend(char* ptr) const
{ {
return (ptr == _bufend) ? _buf : ptr; return (ptr == _bufend) ? _buf : ptr;

View File

@ -13,48 +13,45 @@
// limitations under the License. // limitations under the License.
#include "esp32-hal-adc.h" #include "esp32-hal-adc.h"
#include "driver/adc.h" #include "freertos/FreeRTOS.h"
#include "esp_adc_cal.h" #include "freertos/task.h"
#include "esp_attr.h"
#if SOC_DAC_SUPPORTED //ESP32, ESP32S2
#include "soc/dac_channel.h"
#include "soc/sens_reg.h"
#include "soc/rtc_io_reg.h" #include "soc/rtc_io_reg.h"
#endif #include "soc/rtc_cntl_reg.h"
#include "soc/sens_reg.h"
#include "driver/adc.h"
#include "esp_system.h"
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
#include "esp_adc_cal.h"
#include "esp32/rom/ets_sys.h"
#include "esp_intr_alloc.h"
#define DEFAULT_VREF 1100 #define DEFAULT_VREF 1100
static esp_adc_cal_characteristics_t *__analogCharacteristics[2] = {NULL, NULL};
static uint16_t __analogVRef = 0;
static uint8_t __analogVRefPin = 0;
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/ets_sys.h"
#else
#error Target CONFIG_IDF_TARGET is not supported
#endif
#else // ESP32 Before IDF 4.0
#include "rom/ets_sys.h"
#include "esp_intr.h"
#endif
static uint8_t __analogAttenuation = 3;//11db static uint8_t __analogAttenuation = 3;//11db
static uint8_t __analogWidth = ADC_WIDTH_MAX - 1; //3 for ESP32/ESP32C3; 4 for ESP32S2 static uint8_t __analogWidth = 3;//12 bits
static uint8_t __analogReturnedWidth = SOC_ADC_MAX_BITWIDTH; //12 for ESP32/ESP32C3; 13 for ESP32S2
static uint8_t __analogClockDiv = 1; static uint8_t __analogClockDiv = 1;
static adc_attenuation_t __pin_attenuation[SOC_GPIO_PIN_COUNT];
static uint16_t __analogVRef = 0;
#if CONFIG_IDF_TARGET_ESP32
static uint8_t __analogVRefPin = 0;
#endif
static inline uint16_t mapResolution(uint16_t value)
{
uint8_t from = __analogWidth + 9;
if (from == __analogReturnedWidth) {
return value;
}
if (from > __analogReturnedWidth) {
return value >> (from - __analogReturnedWidth);
}
return value << (__analogReturnedWidth - from);
}
void __analogSetClockDiv(uint8_t clockDiv){ void __analogSetClockDiv(uint8_t clockDiv){
if(!clockDiv){ if(!clockDiv){
clockDiv = 1; clockDiv = 1;
} }
__analogClockDiv = clockDiv; __analogClockDiv = clockDiv;
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
adc_set_clk_div(__analogClockDiv); adc_set_clk_div(__analogClockDiv);
#endif
} }
void __analogSetAttenuation(adc_attenuation_t attenuation) void __analogSetAttenuation(adc_attenuation_t attenuation)
@ -84,9 +81,6 @@ void __analogInit(){
#if CONFIG_IDF_TARGET_ESP32 #if CONFIG_IDF_TARGET_ESP32
__analogSetWidth(__analogWidth + 9);//in bits __analogSetWidth(__analogWidth + 9);//in bits
#endif #endif
for(int i=0; i<SOC_GPIO_PIN_COUNT; i++){
__pin_attenuation[i] = ADC_ATTENDB_MAX;
}
} }
void __analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation) void __analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation)
@ -95,15 +89,12 @@ void __analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation)
if(channel < 0 || attenuation > 3){ if(channel < 0 || attenuation > 3){
return ; return ;
} }
if(channel > (SOC_ADC_MAX_CHANNEL_NUM - 1)){ if(channel > 9){
adc2_config_channel_atten(channel - SOC_ADC_MAX_CHANNEL_NUM, attenuation); adc2_config_channel_atten(channel - 10, attenuation);
} else { } else {
adc1_config_channel_atten(channel, attenuation); adc1_config_channel_atten(channel, attenuation);
} }
__analogInit(); __analogInit();
if((__pin_attenuation[pin] != ADC_ATTENDB_MAX) || (attenuation != __analogAttenuation)){
__pin_attenuation[pin] = attenuation;
}
} }
bool __adcAttachPin(uint8_t pin){ bool __adcAttachPin(uint8_t pin){
@ -112,7 +103,6 @@ bool __adcAttachPin(uint8_t pin){
log_e("Pin %u is not ADC pin!", pin); log_e("Pin %u is not ADC pin!", pin);
return false; return false;
} }
__analogInit();
int8_t pad = digitalPinToTouchChannel(pin); int8_t pad = digitalPinToTouchChannel(pin);
if(pad >= 0){ if(pad >= 0){
#if CONFIG_IDF_TARGET_ESP32 #if CONFIG_IDF_TARGET_ESP32
@ -124,17 +114,14 @@ bool __adcAttachPin(uint8_t pin){
WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG, touch); WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG, touch);
} }
#endif #endif
} } else if(pin == 25){
#if SOC_DAC_SUPPORTED
else if(pin == DAC_CHANNEL_1_GPIO_NUM){
CLEAR_PERI_REG_MASK(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_XPD_DAC | RTC_IO_PDAC1_DAC_XPD_FORCE);//stop dac1 CLEAR_PERI_REG_MASK(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_XPD_DAC | RTC_IO_PDAC1_DAC_XPD_FORCE);//stop dac1
} else if(pin == DAC_CHANNEL_2_GPIO_NUM){ } else if(pin == 26){
CLEAR_PERI_REG_MASK(RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_XPD_DAC | RTC_IO_PDAC2_DAC_XPD_FORCE);//stop dac2 CLEAR_PERI_REG_MASK(RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_XPD_DAC | RTC_IO_PDAC2_DAC_XPD_FORCE);//stop dac2
} }
#endif
pinMode(pin, ANALOG); pinMode(pin, ANALOG);
__analogSetPinAttenuation(pin, (__pin_attenuation[pin] != ADC_ATTENDB_MAX)?__pin_attenuation[pin]:__analogAttenuation); __analogSetPinAttenuation(pin, __analogAttenuation);
return true; return true;
} }
@ -143,7 +130,6 @@ void __analogReadResolution(uint8_t bits)
if(!bits || bits > 16){ if(!bits || bits > 16){
return; return;
} }
__analogReturnedWidth = bits;
#if CONFIG_IDF_TARGET_ESP32 #if CONFIG_IDF_TARGET_ESP32
__analogSetWidth(bits); // hadware from 9 to 12 __analogSetWidth(bits); // hadware from 9 to 12
#endif #endif
@ -159,23 +145,22 @@ uint16_t __analogRead(uint8_t pin)
return value; return value;
} }
__adcAttachPin(pin); __adcAttachPin(pin);
if(channel > (SOC_ADC_MAX_CHANNEL_NUM - 1)){ if(channel > 9){
channel -= SOC_ADC_MAX_CHANNEL_NUM; channel -= 10;
r = adc2_get_raw( channel, __analogWidth, &value); r = adc2_get_raw( channel, __analogWidth, &value);
if ( r == ESP_OK ) { if ( r == ESP_OK ) {
return mapResolution(value); return value;
} else if ( r == ESP_ERR_INVALID_STATE ) { } else if ( r == ESP_ERR_INVALID_STATE ) {
log_e("GPIO%u: %s: ADC2 not initialized yet.", pin, esp_err_to_name(r)); log_e("GPIO%u: %s: ADC2 not initialized yet.", pin, esp_err_to_name(r));
} else if ( r == ESP_ERR_TIMEOUT ) { } else if ( r == ESP_ERR_TIMEOUT ) {
log_e("GPIO%u: %s: ADC2 is in use by Wi-Fi. Please see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/adc.html#adc-limitations for more info", pin, esp_err_to_name(r)); log_e("GPIO%u: %s: ADC2 is in use by Wi-Fi.", pin, esp_err_to_name(r));
} else { } else {
log_e("GPIO%u: %s", pin, esp_err_to_name(r)); log_e("GPIO%u: %s", pin, esp_err_to_name(r));
} }
} else { } else {
value = adc1_get_raw(channel); return adc1_get_raw(channel);
return mapResolution(value);
} }
return mapResolution(value); return value;
} }
uint32_t __analogReadMilliVolts(uint8_t pin){ uint32_t __analogReadMilliVolts(uint8_t pin){
@ -184,7 +169,7 @@ uint32_t __analogReadMilliVolts(uint8_t pin){
log_e("Pin %u is not ADC pin!", pin); log_e("Pin %u is not ADC pin!", pin);
return 0; return 0;
} }
#if CONFIG_IDF_TARGET_ESP32
if(!__analogVRef){ if(!__analogVRef){
if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) { if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) {
log_d("eFuse Two Point: Supported"); log_d("eFuse Two Point: Supported");
@ -196,8 +181,6 @@ uint32_t __analogReadMilliVolts(uint8_t pin){
} }
if(!__analogVRef){ if(!__analogVRef){
__analogVRef = DEFAULT_VREF; __analogVRef = DEFAULT_VREF;
#if CONFIG_IDF_TARGET_ESP32
if(__analogVRefPin){ if(__analogVRefPin){
esp_adc_cal_characteristics_t chars; esp_adc_cal_characteristics_t chars;
if(adc_vref_to_gpio(ADC_UNIT_2, __analogVRefPin) == ESP_OK){ if(adc_vref_to_gpio(ADC_UNIT_2, __analogVRefPin) == ESP_OK){
@ -207,44 +190,42 @@ uint32_t __analogReadMilliVolts(uint8_t pin){
log_d("Vref to GPIO%u: %u", __analogVRefPin, __analogVRef); log_d("Vref to GPIO%u: %u", __analogVRefPin, __analogVRef);
} }
} }
#endif
} }
} }
uint8_t unit = 1; uint8_t unit = 1;
if(channel > (SOC_ADC_MAX_CHANNEL_NUM - 1)){ if(channel > 9){
unit = 2; unit = 2;
} }
uint16_t adc_reading = __analogRead(pin); uint16_t adc_reading = __analogRead(pin);
if(__analogCharacteristics[unit - 1] == NULL){
uint8_t atten = __analogAttenuation; __analogCharacteristics[unit - 1] = calloc(1, sizeof(esp_adc_cal_characteristics_t));
if (__pin_attenuation[pin] != ADC_ATTENDB_MAX){ if(__analogCharacteristics[unit - 1] == NULL){
atten = __pin_attenuation[pin]; return 0;
} }
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, __analogAttenuation, __analogWidth, __analogVRef, __analogCharacteristics[unit - 1]);
esp_adc_cal_characteristics_t chars = {};
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, atten, __analogWidth, __analogVRef, &chars);
static bool print_chars_info = true;
if(print_chars_info)
{
if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) { if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
log_i("ADC%u: Characterized using Two Point Value: %u\n", unit, chars.vref); log_i("ADC%u: Characterized using Two Point Value: %u\n", unit, __analogCharacteristics[unit - 1]->vref);
} else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
log_i("ADC%u: Characterized using eFuse Vref: %u\n", unit, __analogCharacteristics[unit - 1]->vref);
} else if(__analogVRef != DEFAULT_VREF){
log_i("ADC%u: Characterized using Vref to GPIO%u: %u\n", unit, __analogVRefPin, __analogCharacteristics[unit - 1]->vref);
} else {
log_i("ADC%u: Characterized using Default Vref: %u\n", unit, __analogCharacteristics[unit - 1]->vref);
} }
else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
log_i("ADC%u: Characterized using eFuse Vref: %u\n", unit, chars.vref);
} }
#if CONFIG_IDF_TARGET_ESP32 return esp_adc_cal_raw_to_voltage(adc_reading, __analogCharacteristics[unit - 1]);
else if(__analogVRef != DEFAULT_VREF){ #else
log_i("ADC%u: Characterized using Vref to GPIO%u: %u\n", unit, __analogVRefPin, chars.vref); uint16_t adc_reading = __analogRead(pin);
uint16_t max_reading = 8191;
uint16_t max_mv = 1100;
switch(__analogAttenuation){
case 3: max_mv = 3900; break;
case 2: max_mv = 2200; break;
case 1: max_mv = 1500; break;
default: break;
} }
#endif return (adc_reading * max_mv) / max_reading;
else { #endif
log_i("ADC%u: Characterized using Default Vref: %u\n", unit, chars.vref);
}
print_chars_info = false;
}
return esp_adc_cal_raw_to_voltage((uint32_t)adc_reading, &chars);
} }
#if CONFIG_IDF_TARGET_ESP32 #if CONFIG_IDF_TARGET_ESP32
@ -256,12 +237,28 @@ void __analogSetVRefPin(uint8_t pin){
__analogVRefPin = pin; __analogVRefPin = pin;
} }
int __hallRead() //hall sensor using idf read int __hallRead() //hall sensor without LNA
{ {
int Sens_Vp0;
int Sens_Vn0;
int Sens_Vp1;
int Sens_Vn1;
pinMode(36, ANALOG); pinMode(36, ANALOG);
pinMode(39, ANALOG); pinMode(39, ANALOG);
__analogSetWidth(12); SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_XPD_HALL_FORCE_M); // hall sens force enable
return hall_sensor_read(); SET_PERI_REG_MASK(RTC_IO_HALL_SENS_REG, RTC_IO_XPD_HALL); // xpd hall
SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_HALL_PHASE_FORCE_M); // phase force
CLEAR_PERI_REG_MASK(RTC_IO_HALL_SENS_REG, RTC_IO_HALL_PHASE); // hall phase
Sens_Vp0 = __analogRead(36);
Sens_Vn0 = __analogRead(39);
SET_PERI_REG_MASK(RTC_IO_HALL_SENS_REG, RTC_IO_HALL_PHASE);
Sens_Vp1 = __analogRead(36);
Sens_Vn1 = __analogRead(39);
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR, 0, SENS_FORCE_XPD_SAR_S);
CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_XPD_HALL_FORCE);
CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_HALL_PHASE_FORCE);
return (Sens_Vp1 - Sens_Vp0) - (Sens_Vn1 - Sens_Vn0);
} }
#endif #endif
@ -279,3 +276,4 @@ extern void analogSetVRefPin(uint8_t pin) __attribute__ ((weak, alias("__analogS
extern void analogSetWidth(uint8_t bits) __attribute__ ((weak, alias("__analogSetWidth"))); extern void analogSetWidth(uint8_t bits) __attribute__ ((weak, alias("__analogSetWidth")));
extern int hallRead() __attribute__ ((weak, alias("__hallRead"))); extern int hallRead() __attribute__ ((weak, alias("__hallRead")));
#endif #endif

View File

@ -30,8 +30,7 @@ typedef enum {
ADC_0db, ADC_0db,
ADC_2_5db, ADC_2_5db,
ADC_6db, ADC_6db,
ADC_11db, ADC_11db
ADC_ATTENDB_MAX
} adc_attenuation_t; } adc_attenuation_t;
/* /*

View File

@ -18,12 +18,11 @@
bool btInUse(){ return true; } bool btInUse(){ return true; }
#ifdef CONFIG_BLUEDROID_ENABLED
#include "esp_bt.h" #include "esp_bt.h"
#ifdef CONFIG_BTDM_CONTROLLER_MODE_BTDM #ifdef CONFIG_CLASSIC_BT_ENABLED
#define BT_MODE ESP_BT_MODE_BTDM #define BT_MODE ESP_BT_MODE_BTDM
#elif defined(CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY)
#define BT_MODE ESP_BT_MODE_CLASSIC_BT
#else #else
#define BT_MODE ESP_BT_MODE_BLE #define BT_MODE ESP_BT_MODE_BLE
#endif #endif
@ -80,7 +79,7 @@ bool btStop(){
return false; return false;
} }
#else // CONFIG_BT_ENABLED #else
bool btStarted() bool btStarted()
{ {
return false; return false;
@ -95,6 +94,6 @@ bool btStop()
{ {
return false; return false;
} }
#endif
#endif // CONFIG_BT_ENABLED #endif

View File

@ -16,6 +16,7 @@
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/semphr.h" #include "freertos/semphr.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "freertos/xtensa_timer.h"
#include "esp_attr.h" #include "esp_attr.h"
#include "esp_log.h" #include "esp_log.h"
#include "soc/rtc.h" #include "soc/rtc.h"
@ -28,16 +29,9 @@
#include "esp_system.h" #include "esp_system.h"
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+ #ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 #if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
#include "freertos/xtensa_timer.h"
#include "esp32/rom/rtc.h" #include "esp32/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32S2 #elif CONFIG_IDF_TARGET_ESP32S2
#include "freertos/xtensa_timer.h"
#include "esp32s2/rom/rtc.h" #include "esp32s2/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "freertos/xtensa_timer.h"
#include "esp32s3/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/rtc.h"
#else #else
#error Target CONFIG_IDF_TARGET is not supported #error Target CONFIG_IDF_TARGET is not supported
#endif #endif
@ -107,7 +101,7 @@ bool addApbChangeCallback(void * arg, apb_change_cb_t cb){
// look for duplicate callbacks // look for duplicate callbacks
while( (r != NULL ) && !((r->cb == cb) && ( r->arg == arg))) r = r->next; while( (r != NULL ) && !((r->cb == cb) && ( r->arg == arg))) r = r->next;
if (r) { if (r) {
log_e("duplicate func=%8p arg=%8p",c->cb,c->arg); log_e("duplicate func=%08X arg=%08X",c->cb,c->arg);
free(c); free(c);
xSemaphoreGive(apb_change_lock); xSemaphoreGive(apb_change_lock);
return false; return false;
@ -129,7 +123,7 @@ bool removeApbChangeCallback(void * arg, apb_change_cb_t cb){
// look for matching callback // look for matching callback
while( (r != NULL ) && !((r->cb == cb) && ( r->arg == arg))) r = r->next; while( (r != NULL ) && !((r->cb == cb) && ( r->arg == arg))) r = r->next;
if ( r == NULL ) { if ( r == NULL ) {
log_e("not found func=%8p arg=%8p",cb,arg); log_e("not found func=%08X arg=%08X",cb,arg);
xSemaphoreGive(apb_change_lock); xSemaphoreGive(apb_change_lock);
return false; return false;
} }
@ -147,14 +141,10 @@ bool removeApbChangeCallback(void * arg, apb_change_cb_t cb){
} }
static uint32_t calculateApb(rtc_cpu_freq_config_t * conf){ static uint32_t calculateApb(rtc_cpu_freq_config_t * conf){
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
return APB_CLK_FREQ;
#else
if(conf->freq_mhz >= 80){ if(conf->freq_mhz >= 80){
return 80 * MHZ; return 80 * MHZ;
} }
return (conf->source_freq_mhz * MHZ) / conf->div; return (conf->source_freq_mhz * MHZ) / conf->div;
#endif
} }
void esp_timer_impl_update_apb_freq(uint32_t apb_ticks_per_us); //private in IDF void esp_timer_impl_update_apb_freq(uint32_t apb_ticks_per_us); //private in IDF
@ -229,14 +219,8 @@ bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz){
esp_timer_impl_update_apb_freq(apb / MHZ); esp_timer_impl_update_apb_freq(apb / MHZ);
} }
//Update FreeRTOS Tick Divisor //Update FreeRTOS Tick Divisor
#if CONFIG_IDF_TARGET_ESP32C3
#elif CONFIG_IDF_TARGET_ESP32S3
#else
uint32_t fcpu = (conf.freq_mhz >= 80)?(conf.freq_mhz * MHZ):(apb); uint32_t fcpu = (conf.freq_mhz >= 80)?(conf.freq_mhz * MHZ):(apb);
_xt_tick_divisor = fcpu / XT_TICK_PER_SEC; _xt_tick_divisor = fcpu / XT_TICK_PER_SEC;
#endif
//Call peripheral functions after the APB change //Call peripheral functions after the APB change
if(apb_change_callbacks){ if(apb_change_callbacks){
triggerApbChangeCallback(APB_AFTER_CHANGE, capb, apb); triggerApbChangeCallback(APB_AFTER_CHANGE, capb, apb);

View File

@ -13,37 +13,44 @@
// limitations under the License. // limitations under the License.
#include "esp32-hal.h" #include "esp32-hal.h"
#include "soc/soc_caps.h" #include "esp_attr.h"
#include "soc/rtc_io_reg.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_io_periph.h"
#include "soc/sens_reg.h"
#include "soc/sens_struct.h"
#include "driver/dac.h"
#ifndef SOC_DAC_SUPPORTED #if CONFIG_IDF_TARGET_ESP32
#define NODAC #define DAC1 25
#define DAC2 26
#elif CONFIG_IDF_TARGET_ESP32S2
#define DAC1 17
#define DAC2 18
#else #else
#include "soc/dac_channel.h" #error Target CONFIG_IDF_TARGET is not supported
#include "driver/dac_common.h" #endif
void ARDUINO_ISR_ATTR __dacWrite(uint8_t pin, uint8_t value) void ARDUINO_ISR_ATTR __dacWrite(uint8_t pin, uint8_t value)
{ {
if(pin < DAC_CHANNEL_1_GPIO_NUM || pin > DAC_CHANNEL_2_GPIO_NUM){ if(pin < DAC1 || pin > DAC2){
return;//not dac pin return;//not dac pin
} }
pinMode(pin, ANALOG);
uint8_t channel = pin - DAC_CHANNEL_1_GPIO_NUM; uint8_t channel = pin - DAC1;
dac_output_enable(channel); #if CONFIG_IDF_TARGET_ESP32
dac_output_voltage(channel, value); CLEAR_PERI_REG_MASK(SENS_SAR_DAC_CTRL1_REG, SENS_SW_TONE_EN);
#elif CONFIG_IDF_TARGET_ESP32S2
} SENS.sar_dac_ctrl1.dac_clkgate_en = 1;
#endif
void ARDUINO_ISR_ATTR __dacDisable(uint8_t pin) RTCIO.pad_dac[channel].dac_xpd_force = 1;
{ RTCIO.pad_dac[channel].xpd_dac = 1;
if(pin < DAC_CHANNEL_1_GPIO_NUM || pin > DAC_CHANNEL_2_GPIO_NUM){ if (channel == 0) {
return;//not dac pin SENS.sar_dac_ctrl2.dac_cw_en1 = 0;
} else if (channel == 1) {
SENS.sar_dac_ctrl2.dac_cw_en2 = 0;
} }
RTCIO.pad_dac[channel].dac = value;
uint8_t channel = pin - DAC_CHANNEL_1_GPIO_NUM;
dac_output_disable(channel);
} }
extern void dacWrite(uint8_t pin, uint8_t value) __attribute__ ((weak, alias("__dacWrite"))); extern void dacWrite(uint8_t pin, uint8_t value) __attribute__ ((weak, alias("__dacWrite")));
extern void dacDisable(uint8_t pin) __attribute__ ((weak, alias("__dacDisable")));
#endif

View File

@ -28,7 +28,6 @@ extern "C" {
#include "driver/gpio.h" #include "driver/gpio.h"
void dacWrite(uint8_t pin, uint8_t value); void dacWrite(uint8_t pin, uint8_t value);
void dacDisable(uint8_t pin);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -13,71 +13,137 @@
// limitations under the License. // limitations under the License.
#include "esp32-hal-gpio.h" #include "esp32-hal-gpio.h"
#include "hal/gpio_hal.h" #include "pins_arduino.h"
#include "soc/soc_caps.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_attr.h"
#include "soc/gpio_reg.h"
#include "soc/io_mux_reg.h"
#include "soc/gpio_struct.h"
#include "soc/rtc_io_reg.h"
// It fixes lack of pin definition for S3 and for any future SoC #include "esp_system.h"
// this function works for ESP32, ESP32-S2 and ESP32-S3 - including the C3, it will return -1 for any pin #ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
#if SOC_TOUCH_SENSOR_NUM > 0 #if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
#include "soc/touch_sensor_periph.h" #include "esp32/rom/ets_sys.h"
#include "esp32/rom/gpio.h"
int8_t digitalPinToTouchChannel(uint8_t pin) #include "esp_intr_alloc.h"
{ #define GPIO_FUNC 2
int8_t ret = -1; #elif CONFIG_IDF_TARGET_ESP32S2
if (pin < SOC_GPIO_PIN_COUNT) { #include "esp32s2/rom/ets_sys.h"
for (uint8_t i = 0; i < SOC_TOUCH_SENSOR_NUM; i++) { #include "esp32s2/rom/gpio.h"
if (touch_sensor_channel_io_map[i] == pin) { #include "esp_intr_alloc.h"
ret = i; #include "soc/periph_defs.h"
break; #define GPIO_FUNC 1
}
}
}
return ret;
}
#else #else
// No Touch Sensor available #error Target CONFIG_IDF_TARGET is not supported
int8_t digitalPinToTouchChannel(uint8_t pin) #endif
{ #else // ESP32 Before IDF 4.0
return -1; #include "rom/ets_sys.h"
} #include "rom/gpio.h"
#include "esp_intr.h"
#endif #endif
#ifdef SOC_ADC_SUPPORTED #if CONFIG_IDF_TARGET_ESP32
#include "soc/adc_periph.h" const int8_t esp32_adc2gpio[20] = {36, 37, 38, 39, 32, 33, 34, 35, -1, -1, 4, 0, 2, 15, 13, 12, 14, 27, 25, 26};
#elif CONFIG_IDF_TARGET_ESP32S2
int8_t digitalPinToAnalogChannel(uint8_t pin) const int8_t esp32_adc2gpio[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
{
uint8_t channel = 0;
if (pin < SOC_GPIO_PIN_COUNT) {
for (uint8_t i = 0; i < SOC_ADC_PERIPH_NUM; i++) {
for (uint8_t j = 0; j < SOC_ADC_MAX_CHANNEL_NUM; j++) {
if (adc_channel_io_map[i][j] == pin) {
return channel;
}
channel++;
}
}
}
return -1;
}
int8_t analogChannelToDigitalPin(uint8_t channel)
{
if (channel >= (SOC_ADC_PERIPH_NUM * SOC_ADC_MAX_CHANNEL_NUM)) {
return -1;
}
uint8_t adc_unit = (channel / SOC_ADC_MAX_CHANNEL_NUM);
uint8_t adc_chan = (channel % SOC_ADC_MAX_CHANNEL_NUM);
return adc_channel_io_map[adc_unit][adc_chan];
}
#else
// No Analog channels availible
int8_t analogChannelToDigitalPin(uint8_t channel)
{
return -1;
}
#endif #endif
const DRAM_ATTR esp32_gpioMux_t esp32_gpioMux[SOC_GPIO_PIN_COUNT]={
#if CONFIG_IDF_TARGET_ESP32
{0x44, 11, 11, 1},
{0x88, -1, -1, -1},
{0x40, 12, 12, 2},
{0x84, -1, -1, -1},
{0x48, 10, 10, 0},
{0x6c, -1, -1, -1},
{0x60, -1, -1, -1},
{0x64, -1, -1, -1},
{0x68, -1, -1, -1},
{0x54, -1, -1, -1},
{0x58, -1, -1, -1},
{0x5c, -1, -1, -1},
{0x34, 15, 15, 5},
{0x38, 14, 14, 4},
{0x30, 16, 16, 6},
{0x3c, 13, 13, 3},
{0x4c, -1, -1, -1},
{0x50, -1, -1, -1},
{0x70, -1, -1, -1},
{0x74, -1, -1, -1},
{0x78, -1, -1, -1},
{0x7c, -1, -1, -1},
{0x80, -1, -1, -1},
{0x8c, -1, -1, -1},
{0, -1, -1, -1},
{0x24, 6, 18, -1}, //DAC1
{0x28, 7, 19, -1}, //DAC2
{0x2c, 17, 17, 7},
{0, -1, -1, -1},
{0, -1, -1, -1},
{0, -1, -1, -1},
{0, -1, -1, -1},
{0x1c, 9, 4, 8},
{0x20, 8, 5, 9},
{0x14, 4, 6, -1},
{0x18, 5, 7, -1},
{0x04, 0, 0, -1},
{0x08, 1, 1, -1},
{0x0c, 2, 2, -1},
{0x10, 3, 3, -1}
#elif CONFIG_IDF_TARGET_ESP32S2
{0x04, 0, -1, -1},
{0x08, 1, 0, 1},
{0x0c, 2, 1, 2},
{0x10, 3, 2, 3},
{0x14, 4, 3, 4},
{0x18, 5, 4, 5},
{0x1c, 6, 5, 6},
{0x20, 7, 6, 7},
{0x24, 8, 7, 8},
{0x28, 9, 8, 9},//FSPI_HD
{0x2c, 10, 9, 10},//FSPI_CS0 / FSPI_D4
{0x30, 11, 10, 11},//FSPI_D / FSPI_D5
{0x34, 12, 11, 12},//FSPI_CLK / FSPI_D6
{0x38, 13, 12, 13},//FSPI_Q / FSPI_D7
{0x3c, 14, 13, 14},//FSPI_WP / FSPI_DQS
{0x40, 15, 14, -1},//32K+ / RTS0
{0x44, 16, 15, -1},//32K- / CTS0
{0x48, 17, 16, -1},//DAC1 / TXD1
{0x4c, 18, 17, -1},//DAC2 / RXD1
{0x50, 19, 18, -1},//USB D- / RTS1
{0x54, 20, 19, -1},//USB D+ / CTS1
{0x58, 21, -1, -1},//SDA?
{ 0, -1, -1, -1},//UNAVAILABLE
{ 0, -1, -1, -1},//UNAVAILABLE
{ 0, -1, -1, -1},//UNAVAILABLE
{ 0, -1, -1, -1},//UNAVAILABLE
{0x6c, -1, -1, -1},//RESERVED SPI_CS1
{0x70, -1, -1, -1},//RESERVED SPI_HD
{0x74, -1, -1, -1},//RESERVED SPI_WP
{0x78, -1, -1, -1},//RESERVED SPI_CS0
{0x7c, -1, -1, -1},//RESERVED SPI_CLK
{0x80, -1, -1, -1},//RESERVED SPI_Q
{0x84, -1, -1, -1},//RESERVED SPI_D
{0x88, -1, -1, -1},//FSPI_HD
{0x8c, -1, -1, -1},//FSPI_CS0
{0x90, -1, -1, -1},//FSPI_D
{0x94, -1, -1, -1},//FSPI_CLK
{0x98, -1, -1, -1},//FSPI_Q
{0x9c, -1, -1, -1},//FSPI_WP
{0xa0, -1, -1, -1},//MTCK
{0xa4, -1, -1, -1},//MTDO
{0xa8, -1, -1, -1},//MTDI
{0xac, -1, -1, -1},//MTMS
{0xb0, -1, -1, -1},//TXD0
{0xb4, -1, -1, -1},//RXD0
{0xb8, -1, -1, -1},//SCL?
{0xbc, -1, -1, -1},//INPUT ONLY
{0, -1, -1, -1}
#endif
};
typedef void (*voidFuncPtr)(void); typedef void (*voidFuncPtr)(void);
typedef void (*voidFuncPtrArg)(void*); typedef void (*voidFuncPtrArg)(void*);
typedef struct { typedef struct {
@ -91,59 +157,168 @@ static InterruptHandle_t __pinInterruptHandlers[SOC_GPIO_PIN_COUNT] = {0,};
extern void ARDUINO_ISR_ATTR __pinMode(uint8_t pin, uint8_t mode) extern void ARDUINO_ISR_ATTR __pinMode(uint8_t pin, uint8_t mode)
{ {
if (!GPIO_IS_VALID_GPIO(pin)) {
log_e("Invalid pin selected"); if(!digitalPinIsValid(pin)) {
return; return;
} }
gpio_hal_context_t gpiohal; int8_t rtc_io = esp32_gpioMux[pin].rtc;
gpiohal.dev = GPIO_LL_GET_HW(GPIO_PORT_0); uint32_t rtc_reg = (rtc_io != -1)?rtc_io_desc[rtc_io].reg:0;
if(mode == ANALOG) {
if(!rtc_reg) {
return;//not rtc pin
}
#if CONFIG_IDF_TARGET_ESP32S2
SENS.sar_io_mux_conf.iomux_clk_gate_en = 1;
#endif
SET_PERI_REG_MASK(rtc_io_desc[rtc_io].reg, (rtc_io_desc[rtc_io].mux));
SET_PERI_REG_BITS(rtc_io_desc[rtc_io].reg, RTC_IO_TOUCH_PAD1_FUN_SEL_V, 0, rtc_io_desc[rtc_io].func);
gpio_config_t conf = { RTCIO.pin[rtc_io].pad_driver = 0;//OD = 1
.pin_bit_mask = (1ULL<<pin), /*!< GPIO pin: set with bit mask, each bit maps to a GPIO */ RTCIO.enable_w1tc.w1tc = (1U << rtc_io);
.mode = GPIO_MODE_DISABLE, /*!< GPIO mode: set input/output mode */ CLEAR_PERI_REG_MASK(rtc_io_desc[rtc_io].reg, rtc_io_desc[rtc_io].ie);
.pull_up_en = GPIO_PULLUP_DISABLE, /*!< GPIO pull-up */
.pull_down_en = GPIO_PULLDOWN_DISABLE, /*!< GPIO pull-down */ if (rtc_io_desc[rtc_io].pullup) {
.intr_type = gpiohal.dev->pin[pin].int_type /*!< GPIO interrupt type - previously set */ CLEAR_PERI_REG_MASK(rtc_io_desc[rtc_io].reg, rtc_io_desc[rtc_io].pullup);
};
if (mode < 0x20) {//io
conf.mode = mode & (INPUT | OUTPUT);
if (mode & OPEN_DRAIN) {
conf.mode |= GPIO_MODE_DEF_OD;
} }
if (mode & PULLUP) { if (rtc_io_desc[rtc_io].pulldown) {
conf.pull_up_en = GPIO_PULLUP_ENABLE; CLEAR_PERI_REG_MASK(rtc_io_desc[rtc_io].reg, rtc_io_desc[rtc_io].pulldown);
} }
if (mode & PULLDOWN) { ESP_REG(DR_REG_IO_MUX_BASE + esp32_gpioMux[pin].reg) = ((uint32_t)GPIO_FUNC << MCU_SEL_S) | ((uint32_t)2 << FUN_DRV_S) | FUN_IE;
conf.pull_down_en = GPIO_PULLDOWN_ENABLE;
}
}
if(gpio_config(&conf) != ESP_OK)
{
log_e("GPIO config failed");
return; return;
} }
//RTC pins PULL settings
if(rtc_reg) {
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[rtc_io].mux);
if(mode & PULLUP) {
ESP_REG(rtc_reg) = (ESP_REG(rtc_reg) | rtc_io_desc[rtc_io].pullup) & ~(rtc_io_desc[rtc_io].pulldown);
} else if(mode & PULLDOWN) {
ESP_REG(rtc_reg) = (ESP_REG(rtc_reg) | rtc_io_desc[rtc_io].pulldown) & ~(rtc_io_desc[rtc_io].pullup);
} else {
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[rtc_io].pullup | rtc_io_desc[rtc_io].pulldown);
}
}
uint32_t pinFunction = 0, pinControl = 0;
if(mode & INPUT) {
if(pin < 32) {
GPIO.enable_w1tc = ((uint32_t)1 << pin);
} else {
GPIO.enable1_w1tc.val = ((uint32_t)1 << (pin - 32));
}
} else if(mode & OUTPUT) {
if(pin >= NUM_OUPUT_PINS){
return;
} else if(pin < 32) {
GPIO.enable_w1ts = ((uint32_t)1 << pin);
} else {
GPIO.enable1_w1ts.val = ((uint32_t)1 << (pin - 32));
}
}
if(mode & PULLUP) {
pinFunction |= FUN_PU;
} else if(mode & PULLDOWN) {
pinFunction |= FUN_PD;
}
pinFunction |= ((uint32_t)2 << FUN_DRV_S);//what are the drivers?
pinFunction |= FUN_IE;//input enable but required for output as well?
if(mode & (INPUT | OUTPUT)) {
#if CONFIG_IDF_TARGET_ESP32
pinFunction |= ((uint32_t)2 << MCU_SEL_S);
#elif CONFIG_IDF_TARGET_ESP32S2
pinFunction |= ((uint32_t)1 << MCU_SEL_S);
#endif
} else if(mode == SPECIAL) {
#if CONFIG_IDF_TARGET_ESP32
pinFunction |= ((uint32_t)(((pin)==RX||(pin)==TX)?0:1) << MCU_SEL_S);
#elif CONFIG_IDF_TARGET_ESP32S2
pinFunction |= ((uint32_t)(((pin)==RX||(pin)==TX)?0:2) << MCU_SEL_S);
#endif
} else {
pinFunction |= ((uint32_t)(mode >> 5) << MCU_SEL_S);
}
ESP_REG(DR_REG_IO_MUX_BASE + esp32_gpioMux[pin].reg) = pinFunction;
if(mode & OPEN_DRAIN) {
pinControl = (1 << GPIO_PIN0_PAD_DRIVER_S);
}
GPIO.pin[pin].val = pinControl;
} }
extern void ARDUINO_ISR_ATTR __digitalWrite(uint8_t pin, uint8_t val) extern void ARDUINO_ISR_ATTR __digitalWrite(uint8_t pin, uint8_t val)
{ {
gpio_set_level((gpio_num_t)pin, val); if(val) {
if(pin < 32) {
GPIO.out_w1ts = ((uint32_t)1 << pin);
} else if(pin < NUM_OUPUT_PINS) {
GPIO.out1_w1ts.val = ((uint32_t)1 << (pin - 32));
}
} else {
if(pin < 32) {
GPIO.out_w1tc = ((uint32_t)1 << pin);
} else if(pin < NUM_OUPUT_PINS) {
GPIO.out1_w1tc.val = ((uint32_t)1 << (pin - 32));
}
}
} }
extern int ARDUINO_ISR_ATTR __digitalRead(uint8_t pin) extern int ARDUINO_ISR_ATTR __digitalRead(uint8_t pin)
{ {
return gpio_get_level((gpio_num_t)pin); if(pin < 32) {
return (GPIO.in >> pin) & 0x1;
} else if(pin < GPIO_PIN_COUNT) {
return (GPIO.in1.val >> (pin - 32)) & 0x1;
}
return 0;
} }
static void ARDUINO_ISR_ATTR __onPinInterrupt(void * arg) { static intr_handle_t gpio_intr_handle = NULL;
InterruptHandle_t * isr = (InterruptHandle_t*)arg;
if(isr->fn) { static void ARDUINO_ISR_ATTR __onPinInterrupt()
if(isr->arg){ {
((voidFuncPtrArg)isr->fn)(isr->arg); uint32_t gpio_intr_status_l=0;
uint32_t gpio_intr_status_h=0;
gpio_intr_status_l = GPIO.status;
gpio_intr_status_h = GPIO.status1.val;
GPIO.status_w1tc = gpio_intr_status_l;//Clear intr for gpio0-gpio31
GPIO.status1_w1tc.val = gpio_intr_status_h;//Clear intr for gpio32-39
uint8_t pin=0;
if(gpio_intr_status_l) {
do {
if(gpio_intr_status_l & ((uint32_t)1 << pin)) {
if(__pinInterruptHandlers[pin].fn) {
if(__pinInterruptHandlers[pin].arg){
((voidFuncPtrArg)__pinInterruptHandlers[pin].fn)(__pinInterruptHandlers[pin].arg);
} else { } else {
isr->fn(); __pinInterruptHandlers[pin].fn();
} }
} }
}
} while(++pin<32);
}
if(gpio_intr_status_h) {
pin=32;
do {
if(gpio_intr_status_h & ((uint32_t)1 << (pin - 32))) {
if(__pinInterruptHandlers[pin].fn) {
if(__pinInterruptHandlers[pin].arg){
((voidFuncPtrArg)__pinInterruptHandlers[pin].fn)(__pinInterruptHandlers[pin].arg);
} else {
__pinInterruptHandlers[pin].fn();
}
}
}
} while(++pin<GPIO_PIN_COUNT);
}
} }
extern void cleanupFunctional(void* arg); extern void cleanupFunctional(void* arg);
@ -153,12 +328,8 @@ extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc,
static bool interrupt_initialized = false; static bool interrupt_initialized = false;
if(!interrupt_initialized) { if(!interrupt_initialized) {
esp_err_t err = gpio_install_isr_service((int)ARDUINO_ISR_FLAG); interrupt_initialized = true;
interrupt_initialized = (err == ESP_OK) || (err == ESP_ERR_INVALID_STATE); esp_intr_alloc(ETS_GPIO_INTR_SOURCE, (int)ARDUINO_ISR_FLAG, __onPinInterrupt, NULL, &gpio_intr_handle);
}
if(!interrupt_initialized) {
log_e("GPIO ISR Service Failed To Start");
return;
} }
// if new attach without detach remove old info // if new attach without detach remove old info
@ -170,18 +341,18 @@ extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc,
__pinInterruptHandlers[pin].arg = arg; __pinInterruptHandlers[pin].arg = arg;
__pinInterruptHandlers[pin].functional = functional; __pinInterruptHandlers[pin].functional = functional;
gpio_set_intr_type((gpio_num_t)pin, (gpio_int_type_t)(intr_type & 0x7)); esp_intr_disable(gpio_intr_handle);
if(intr_type & 0x8){ #if CONFIG_IDF_TARGET_ESP32
gpio_wakeup_enable((gpio_num_t)pin, (gpio_int_type_t)(intr_type & 0x7)); if(esp_intr_get_cpu(gpio_intr_handle)) { //APP_CPU
#endif
GPIO.pin[pin].int_ena = 1;
#if CONFIG_IDF_TARGET_ESP32
} else { //PRO_CPU
GPIO.pin[pin].int_ena = 4;
} }
gpio_isr_handler_add((gpio_num_t)pin, __onPinInterrupt, &__pinInterruptHandlers[pin]); #endif
GPIO.pin[pin].int_type = intr_type;
esp_intr_enable(gpio_intr_handle);
//FIX interrupts on peripherals outputs (eg. LEDC,...)
//Enable input in GPIO register
gpio_hal_context_t gpiohal;
gpiohal.dev = GPIO_LL_GET_HW(GPIO_PORT_0);
gpio_hal_input_enable(&gpiohal, pin);
} }
extern void __attachInterruptArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type) extern void __attachInterruptArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type)
@ -195,9 +366,7 @@ extern void __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int intr_type)
extern void __detachInterrupt(uint8_t pin) extern void __detachInterrupt(uint8_t pin)
{ {
gpio_isr_handler_remove((gpio_num_t)pin); //remove handle and disable isr for pin esp_intr_disable(gpio_intr_handle);
gpio_wakeup_disable((gpio_num_t)pin);
if (__pinInterruptHandlers[pin].functional && __pinInterruptHandlers[pin].arg) if (__pinInterruptHandlers[pin].functional && __pinInterruptHandlers[pin].arg)
{ {
cleanupFunctional(__pinInterruptHandlers[pin].arg); cleanupFunctional(__pinInterruptHandlers[pin].arg);
@ -206,7 +375,9 @@ extern void __detachInterrupt(uint8_t pin)
__pinInterruptHandlers[pin].arg = NULL; __pinInterruptHandlers[pin].arg = NULL;
__pinInterruptHandlers[pin].functional = false; __pinInterruptHandlers[pin].functional = false;
gpio_set_intr_type((gpio_num_t)pin, GPIO_INTR_DISABLE); GPIO.pin[pin].int_ena = 0;
GPIO.pin[pin].int_type = 0;
esp_intr_enable(gpio_intr_handle);
} }
@ -216,3 +387,4 @@ extern int digitalRead(uint8_t pin) __attribute__ ((weak, alias("__digitalRead")
extern void attachInterrupt(uint8_t pin, voidFuncPtr handler, int mode) __attribute__ ((weak, alias("__attachInterrupt"))); extern void attachInterrupt(uint8_t pin, voidFuncPtr handler, int mode) __attribute__ ((weak, alias("__attachInterrupt")));
extern void attachInterruptArg(uint8_t pin, voidFuncPtrArg handler, void * arg, int mode) __attribute__ ((weak, alias("__attachInterruptArg"))); extern void attachInterruptArg(uint8_t pin, voidFuncPtrArg handler, void * arg, int mode) __attribute__ ((weak, alias("__attachInterruptArg")));
extern void detachInterrupt(uint8_t pin) __attribute__ ((weak, alias("__detachInterrupt"))); extern void detachInterrupt(uint8_t pin) __attribute__ ((weak, alias("__detachInterrupt")));

View File

@ -28,7 +28,7 @@ extern "C" {
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
#if (CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3) #if (CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3)
#define NUM_OUPUT_PINS 46 #define NUM_OUPUT_PINS 45
#define PIN_DAC1 17 #define PIN_DAC1 17
#define PIN_DAC2 18 #define PIN_DAC2 18
#else #else
@ -42,15 +42,20 @@ extern "C" {
//GPIO FUNCTIONS //GPIO FUNCTIONS
#define INPUT 0x01 #define INPUT 0x01
// Changed OUTPUT from 0x02 to behave the same as Arduino pinMode(pin,OUTPUT) #define OUTPUT 0x02
// where you can read the state of pin even when it is set as OUTPUT
#define OUTPUT 0x03
#define PULLUP 0x04 #define PULLUP 0x04
#define INPUT_PULLUP 0x05 #define INPUT_PULLUP 0x05
#define PULLDOWN 0x08 #define PULLDOWN 0x08
#define INPUT_PULLDOWN 0x09 #define INPUT_PULLDOWN 0x09
#define OPEN_DRAIN 0x10 #define OPEN_DRAIN 0x10
#define OUTPUT_OPEN_DRAIN 0x12 #define OUTPUT_OPEN_DRAIN 0x12
#define SPECIAL 0xF0
#define FUNCTION_1 0x00
#define FUNCTION_2 0x20
#define FUNCTION_3 0x40
#define FUNCTION_4 0x60
#define FUNCTION_5 0x80
#define FUNCTION_6 0xA0
#define ANALOG 0xC0 #define ANALOG 0xC0
//Interrupt Modes //Interrupt Modes
@ -63,11 +68,22 @@ extern "C" {
#define ONLOW_WE 0x0C #define ONLOW_WE 0x0C
#define ONHIGH_WE 0x0D #define ONHIGH_WE 0x0D
#define digitalPinIsValid(pin) GPIO_IS_VALID_GPIO(pin) typedef struct {
#define digitalPinCanOutput(pin) GPIO_IS_VALID_OUTPUT_GPIO(pin) uint8_t reg; /*!< GPIO register offset from DR_REG_IO_MUX_BASE */
int8_t rtc; /*!< RTC GPIO number (-1 if not RTC GPIO pin) */
int8_t adc; /*!< ADC Channel number (-1 if not ADC pin) */
int8_t touch; /*!< Touch Channel number (-1 if not Touch pin) */
} esp32_gpioMux_t;
#define digitalPinToRtcPin(pin) ((RTC_GPIO_IS_VALID_GPIO(pin))?rtc_io_number_get(pin):-1) extern const esp32_gpioMux_t esp32_gpioMux[SOC_GPIO_PIN_COUNT];
#define digitalPinToDacChannel(pin) (((pin) == DAC_CHANNEL_1_GPIO_NUM)?0:((pin) == DAC_CHANNEL_2_GPIO_NUM)?1:-1) extern const int8_t esp32_adc2gpio[20];
#define digitalPinIsValid(pin) ((pin) < SOC_GPIO_PIN_COUNT && esp32_gpioMux[(pin)].reg)
#define digitalPinCanOutput(pin) ((pin) < NUM_OUPUT_PINS && esp32_gpioMux[(pin)].reg)
#define digitalPinToRtcPin(pin) (((pin) < SOC_GPIO_PIN_COUNT)?esp32_gpioMux[(pin)].rtc:-1)
#define digitalPinToAnalogChannel(pin) (((pin) < SOC_GPIO_PIN_COUNT)?esp32_gpioMux[(pin)].adc:-1)
#define digitalPinToTouchChannel(pin) (((pin) < SOC_GPIO_PIN_COUNT)?esp32_gpioMux[(pin)].touch:-1)
#define digitalPinToDacChannel(pin) (((pin) == PIN_DAC1)?0:((pin) == PIN_DAC2)?1:-1)
void pinMode(uint8_t pin, uint8_t mode); void pinMode(uint8_t pin, uint8_t mode);
void digitalWrite(uint8_t pin, uint8_t val); void digitalWrite(uint8_t pin, uint8_t val);
@ -77,10 +93,6 @@ void attachInterrupt(uint8_t pin, void (*)(void), int mode);
void attachInterruptArg(uint8_t pin, void (*)(void*), void * arg, int mode); void attachInterruptArg(uint8_t pin, void (*)(void*), void * arg, int mode);
void detachInterrupt(uint8_t pin); void detachInterrupt(uint8_t pin);
int8_t digitalPinToTouchChannel(uint8_t pin);
int8_t digitalPinToAnalogChannel(uint8_t pin);
int8_t analogChannelToDigitalPin(uint8_t channel);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -1,853 +0,0 @@
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <inttypes.h>
#include <string.h>
#include <math.h>
#include "sdkconfig.h"
#include "esp_attr.h"
#include "rom/gpio.h"
#include "soc/gpio_sig_map.h"
#include "hal/gpio_types.h"
#include "driver/gpio.h"
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "freertos/ringbuf.h"
#include "esp_intr_alloc.h"
#include "driver/periph_ctrl.h"
#include "soc/i2c_reg.h"
#include "soc/i2c_struct.h"
#include "hal/i2c_ll.h"
#include "esp32-hal-log.h"
#include "esp32-hal-i2c-slave.h"
#define I2C_SLAVE_USE_RX_QUEUE 0 // 1: Queue, 0: RingBuffer
#if SOC_I2C_NUM > 1
#define I2C_SCL_IDX(p) ((p==0)?I2CEXT0_SCL_OUT_IDX:((p==1)?I2CEXT1_SCL_OUT_IDX:0))
#define I2C_SDA_IDX(p) ((p==0)?I2CEXT0_SDA_OUT_IDX:((p==1)?I2CEXT1_SDA_OUT_IDX:0))
#else
#define I2C_SCL_IDX(p) I2CEXT0_SCL_OUT_IDX
#define I2C_SDA_IDX(p) I2CEXT0_SDA_OUT_IDX
#endif
#if CONFIG_IDF_TARGET_ESP32
#define I2C_TXFIFO_WM_INT_ENA I2C_TXFIFO_EMPTY_INT_ENA
#define I2C_RXFIFO_WM_INT_ENA I2C_RXFIFO_FULL_INT_ENA
#endif
enum {
I2C_SLAVE_EVT_RX, I2C_SLAVE_EVT_TX
};
typedef struct i2c_slave_struct_t {
i2c_dev_t * dev;
uint8_t num;
int8_t sda;
int8_t scl;
i2c_slave_request_cb_t request_callback;
i2c_slave_receive_cb_t receive_callback;
void * arg;
intr_handle_t intr_handle;
TaskHandle_t task_handle;
xQueueHandle event_queue;
#if I2C_SLAVE_USE_RX_QUEUE
xQueueHandle rx_queue;
#else
RingbufHandle_t rx_ring_buf;
#endif
xQueueHandle tx_queue;
uint32_t rx_data_count;
#if !CONFIG_DISABLE_HAL_LOCKS
xSemaphoreHandle lock;
#endif
} i2c_slave_struct_t;
typedef union {
struct {
uint32_t event : 2;
uint32_t stop : 1;
uint32_t param : 29;
};
uint32_t val;
} i2c_slave_queue_event_t;
static i2c_slave_struct_t _i2c_bus_array[SOC_I2C_NUM] = {
{ &I2C0, 0, -1, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0
#if !CONFIG_DISABLE_HAL_LOCKS
, NULL
#endif
},
#if SOC_I2C_NUM > 1
{ &I2C1, 1, -1, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0
#if !CONFIG_DISABLE_HAL_LOCKS
, NULL
#endif
}
#endif
};
#if CONFIG_DISABLE_HAL_LOCKS
#define I2C_SLAVE_MUTEX_LOCK()
#define I2C_SLAVE_MUTEX_UNLOCK()
#else
#define I2C_SLAVE_MUTEX_LOCK() if(i2c->lock){xSemaphoreTake(i2c->lock, portMAX_DELAY);}
#define I2C_SLAVE_MUTEX_UNLOCK() if(i2c->lock){xSemaphoreGive(i2c->lock);}
#endif
//-------------------------------------- HAL_LL (Missing Functions) ------------------------------------------------
typedef enum {
I2C_STRETCH_CAUSE_MASTER_READ,
I2C_STRETCH_CAUSE_TX_FIFO_EMPTY,
I2C_STRETCH_CAUSE_RX_FIFO_FULL,
I2C_STRETCH_CAUSE_MAX
} i2c_stretch_cause_t;
static inline i2c_stretch_cause_t i2c_ll_stretch_cause(i2c_dev_t *hw)
{
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
return hw->sr.stretch_cause;
#elif CONFIG_IDF_TARGET_ESP32S2
return hw->status_reg.stretch_cause;
#else
return I2C_STRETCH_CAUSE_MAX;
#endif
}
static inline void i2c_ll_set_stretch(i2c_dev_t *hw, uint16_t time)
{
#ifndef CONFIG_IDF_TARGET_ESP32
typeof(hw->scl_stretch_conf) scl_stretch_conf;
scl_stretch_conf.val = 0;
scl_stretch_conf.slave_scl_stretch_en = (time > 0);
scl_stretch_conf.stretch_protect_num = time;
scl_stretch_conf.slave_scl_stretch_clr = 1;
hw->scl_stretch_conf.val = scl_stretch_conf.val;
if(time > 0){
//enable interrupt
hw->int_ena.val |= I2C_SLAVE_STRETCH_INT_ENA;
} else {
//disable interrupt
hw->int_ena.val &= (~I2C_SLAVE_STRETCH_INT_ENA);
}
#endif
}
static inline void i2c_ll_stretch_clr(i2c_dev_t *hw)
{
#ifndef CONFIG_IDF_TARGET_ESP32
hw->scl_stretch_conf.slave_scl_stretch_clr = 1;
#endif
}
static inline bool i2c_ll_slave_addressed(i2c_dev_t *hw)
{
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
return hw->sr.slave_addressed;
#else
return hw->status_reg.slave_addressed;
#endif
}
static inline bool i2c_ll_slave_rw(i2c_dev_t *hw)//not exposed by hal_ll
{
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
return hw->sr.slave_rw;
#else
return hw->status_reg.slave_rw;
#endif
}
//-------------------------------------- PRIVATE (Function Prototypes) ------------------------------------------------
static void i2c_slave_free_resources(i2c_slave_struct_t * i2c);
static void i2c_slave_delay_us(uint64_t us);
static void i2c_slave_gpio_mode(int8_t pin, gpio_mode_t mode);
static bool i2c_slave_check_line_state(int8_t sda, int8_t scl);
static bool i2c_slave_attach_gpio(i2c_slave_struct_t * i2c, int8_t sda, int8_t scl);
static bool i2c_slave_detach_gpio(i2c_slave_struct_t * i2c);
static bool i2c_slave_set_frequency(i2c_slave_struct_t * i2c, uint32_t clk_speed);
static bool i2c_slave_send_event(i2c_slave_struct_t * i2c, i2c_slave_queue_event_t* event);
static bool i2c_slave_handle_tx_fifo_empty(i2c_slave_struct_t * i2c);
static bool i2c_slave_handle_rx_fifo_full(i2c_slave_struct_t * i2c, uint32_t len);
static size_t i2c_slave_read_rx(i2c_slave_struct_t * i2c, uint8_t * data, size_t len);
static void i2c_slave_isr_handler(void* arg);
static void i2c_slave_task(void *pv_args);
//=====================================================================================================================
//-------------------------------------- Public Functions -------------------------------------------------------------
//=====================================================================================================================
esp_err_t i2cSlaveAttachCallbacks(uint8_t num, i2c_slave_request_cb_t request_callback, i2c_slave_receive_cb_t receive_callback, void * arg){
if(num >= SOC_I2C_NUM){
log_e("Invalid port num: %u", num);
return ESP_ERR_INVALID_ARG;
}
i2c_slave_struct_t * i2c = &_i2c_bus_array[num];
I2C_SLAVE_MUTEX_LOCK();
i2c->request_callback = request_callback;
i2c->receive_callback = receive_callback;
i2c->arg = arg;
I2C_SLAVE_MUTEX_UNLOCK();
return ESP_OK;
}
esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t frequency, size_t rx_len, size_t tx_len) {
if(num >= SOC_I2C_NUM){
log_e("Invalid port num: %u", num);
return ESP_ERR_INVALID_ARG;
}
if (sda < 0 || scl < 0) {
log_e("invalid pins sda=%d, scl=%d", sda, scl);
return ESP_ERR_INVALID_ARG;
}
if(!frequency){
frequency = 100000;
} else if(frequency > 1000000){
frequency = 1000000;
}
log_i("Initialising I2C Slave: sda=%d scl=%d freq=%d, addr=0x%x", sda, scl, frequency, slaveID);
i2c_slave_struct_t * i2c = &_i2c_bus_array[num];
esp_err_t ret = ESP_OK;
#if !CONFIG_DISABLE_HAL_LOCKS
if(!i2c->lock){
i2c->lock = xSemaphoreCreateMutex();
if (i2c->lock == NULL) {
log_e("RX queue create failed");
return ESP_ERR_NO_MEM;
}
}
#endif
I2C_SLAVE_MUTEX_LOCK();
i2c_slave_free_resources(i2c);
#if I2C_SLAVE_USE_RX_QUEUE
i2c->rx_queue = xQueueCreate(rx_len, sizeof(uint8_t));
if (i2c->rx_queue == NULL) {
log_e("RX queue create failed");
ret = ESP_ERR_NO_MEM;
goto fail;
}
#else
i2c->rx_ring_buf = xRingbufferCreate(rx_len, RINGBUF_TYPE_BYTEBUF);
if (i2c->rx_ring_buf == NULL) {
log_e("RX RingBuf create failed");
ret = ESP_ERR_NO_MEM;
goto fail;
}
#endif
i2c->tx_queue = xQueueCreate(tx_len, sizeof(uint8_t));
if (i2c->tx_queue == NULL) {
log_e("TX queue create failed");
ret = ESP_ERR_NO_MEM;
goto fail;
}
i2c->event_queue = xQueueCreate(16, sizeof(i2c_slave_queue_event_t));
if (i2c->event_queue == NULL) {
log_e("Event queue create failed");
ret = ESP_ERR_NO_MEM;
goto fail;
}
xTaskCreate(i2c_slave_task, "i2c_slave_task", 4096, i2c, 20, &i2c->task_handle);
if(i2c->task_handle == NULL){
log_e("Event thread create failed");
ret = ESP_ERR_NO_MEM;
goto fail;
}
if (frequency == 0) {
frequency = 100000L;
}
frequency = (frequency * 5) / 4;
if (i2c->num == 0) {
periph_module_enable(PERIPH_I2C0_MODULE);
#if SOC_I2C_NUM > 1
} else {
periph_module_enable(PERIPH_I2C1_MODULE);
#endif
}
i2c_ll_slave_init(i2c->dev);
i2c_ll_set_fifo_mode(i2c->dev, true);
i2c_ll_set_slave_addr(i2c->dev, slaveID, false);
i2c_ll_set_tout(i2c->dev, I2C_LL_MAX_TIMEOUT);
i2c_slave_set_frequency(i2c, frequency);
if (!i2c_slave_check_line_state(sda, scl)) {
log_e("bad pin state");
ret = ESP_FAIL;
goto fail;
}
i2c_slave_attach_gpio(i2c, sda, scl);
if (i2c_ll_is_bus_busy(i2c->dev)) {
log_w("Bus busy, reinit");
ret = ESP_FAIL;
goto fail;
}
i2c_ll_disable_intr_mask(i2c->dev, I2C_LL_INTR_MASK);
i2c_ll_clr_intsts_mask(i2c->dev, I2C_LL_INTR_MASK);
i2c_ll_set_fifo_mode(i2c->dev, true);
if (!i2c->intr_handle) {
uint32_t flags = ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED;
if(i2c->num == 0) {
ret = esp_intr_alloc(ETS_I2C_EXT0_INTR_SOURCE, flags, &i2c_slave_isr_handler, i2c, &i2c->intr_handle);
#if SOC_I2C_NUM > 1
} else {
ret = esp_intr_alloc(ETS_I2C_EXT1_INTR_SOURCE, flags, &i2c_slave_isr_handler, i2c, &i2c->intr_handle);
#endif
}
if (ret != ESP_OK) {
log_e("install interrupt handler Failed=%d", ret);
goto fail;
}
}
i2c_ll_txfifo_rst(i2c->dev);
i2c_ll_rxfifo_rst(i2c->dev);
i2c_ll_slave_enable_rx_it(i2c->dev);
i2c_ll_set_stretch(i2c->dev, 0x3FF);
i2c_ll_update(i2c->dev);
I2C_SLAVE_MUTEX_UNLOCK();
return ret;
fail:
i2c_slave_free_resources(i2c);
I2C_SLAVE_MUTEX_UNLOCK();
return ret;
}
esp_err_t i2cSlaveDeinit(uint8_t num){
if(num >= SOC_I2C_NUM){
log_e("Invalid port num: %u", num);
return ESP_ERR_INVALID_ARG;
}
i2c_slave_struct_t * i2c = &_i2c_bus_array[num];
#if !CONFIG_DISABLE_HAL_LOCKS
if(!i2c->lock){
log_e("Lock is not initialized! Did you call i2c_slave_init()?");
return ESP_ERR_NO_MEM;
}
#endif
I2C_SLAVE_MUTEX_LOCK();
i2c_slave_free_resources(i2c);
I2C_SLAVE_MUTEX_UNLOCK();
return ESP_OK;
}
size_t i2cSlaveWrite(uint8_t num, const uint8_t *buf, uint32_t len, uint32_t timeout_ms) {
if(num >= SOC_I2C_NUM){
log_e("Invalid port num: %u", num);
return 0;
}
size_t to_queue = 0, to_fifo = 0;
i2c_slave_struct_t * i2c = &_i2c_bus_array[num];
#if !CONFIG_DISABLE_HAL_LOCKS
if(!i2c->lock){
log_e("Lock is not initialized! Did you call i2c_slave_init()?");
return ESP_ERR_NO_MEM;
}
#endif
if(!i2c->tx_queue){
return 0;
}
I2C_SLAVE_MUTEX_LOCK();
#if CONFIG_IDF_TARGET_ESP32
//make sure that tx is idle
uint64_t tout_at = esp_timer_get_time() + (timeout_ms * 1000);
while(i2c_ll_slave_addressed(i2c->dev) && i2c_ll_slave_rw(i2c->dev)) {
// ongoing MASTER READ
//wait up to timeout_ms for current transaction to finish
vTaskDelay(2);
if((uint64_t)esp_timer_get_time() >= tout_at){
log_e("TX IDLE WAIT TIMEOUT!");
I2C_SLAVE_MUTEX_UNLOCK();
return 0;
}
}
i2c_ll_slave_disable_tx_it(i2c->dev);
if (i2c_ll_get_txfifo_len(i2c->dev) < SOC_I2C_FIFO_LEN) {
i2c_ll_txfifo_rst(i2c->dev);
}
#endif
to_fifo = i2c_ll_get_txfifo_len(i2c->dev);
if(len < to_fifo){
to_fifo = len;
}
i2c_ll_write_txfifo(i2c->dev, (uint8_t*)buf, to_fifo);
buf += to_fifo;
len -= to_fifo;
//reset tx_queue
xQueueReset(i2c->tx_queue);
//write the rest of the bytes to the queue
if(len){
to_queue = uxQueueSpacesAvailable(i2c->tx_queue);
if(len < to_queue){
to_queue = len;
}
for (size_t i = 0; i < to_queue; i++) {
if (xQueueSend(i2c->tx_queue, &buf[i], timeout_ms / portTICK_RATE_MS) != pdTRUE) {
xQueueReset(i2c->tx_queue);
to_queue = 0;
break;
}
}
//no need to enable TX_EMPTY if tx_queue is empty
if(to_queue){
i2c_ll_slave_enable_tx_it(i2c->dev);
}
}
I2C_SLAVE_MUTEX_UNLOCK();
return to_queue + to_fifo;
}
//=====================================================================================================================
//-------------------------------------- Private Functions ------------------------------------------------------------
//=====================================================================================================================
static void i2c_slave_free_resources(i2c_slave_struct_t * i2c){
i2c_slave_detach_gpio(i2c);
i2c_ll_set_slave_addr(i2c->dev, 0, false);
i2c_ll_disable_intr_mask(i2c->dev, I2C_LL_INTR_MASK);
i2c_ll_clr_intsts_mask(i2c->dev, I2C_LL_INTR_MASK);
if (i2c->intr_handle) {
esp_intr_free(i2c->intr_handle);
i2c->intr_handle = NULL;
}
if(i2c->task_handle){
vTaskDelete(i2c->task_handle);
i2c->task_handle = NULL;
}
#if I2C_SLAVE_USE_RX_QUEUE
if (i2c->rx_queue) {
vQueueDelete(i2c->rx_queue);
i2c->rx_queue = NULL;
}
#else
if (i2c->rx_ring_buf) {
vRingbufferDelete(i2c->rx_ring_buf);
i2c->rx_ring_buf = NULL;
}
#endif
if (i2c->tx_queue) {
vQueueDelete(i2c->tx_queue);
i2c->tx_queue = NULL;
}
if (i2c->event_queue) {
vQueueDelete(i2c->event_queue);
i2c->event_queue = NULL;
}
i2c->rx_data_count = 0;
}
static bool i2c_slave_set_frequency(i2c_slave_struct_t * i2c, uint32_t clk_speed)
{
if (i2c == NULL) {
log_e("no control buffer");
return false;
}
if(clk_speed > 1100000UL){
clk_speed = 1100000UL;
}
// Adjust Fifo thresholds based on frequency
uint32_t a = (clk_speed / 50000L) + 2;
log_d("Fifo thresholds: rx_fifo_full = %d, tx_fifo_empty = %d", SOC_I2C_FIFO_LEN - a, a);
i2c_clk_cal_t clk_cal;
#if SOC_I2C_SUPPORT_APB
i2c_ll_cal_bus_clk(APB_CLK_FREQ, clk_speed, &clk_cal);
i2c_ll_set_source_clk(i2c->dev, I2C_SCLK_APB); /*!< I2C source clock from APB, 80M*/
#elif SOC_I2C_SUPPORT_XTAL
i2c_ll_cal_bus_clk(XTAL_CLK_FREQ, clk_speed, &clk_cal);
i2c_ll_set_source_clk(i2c->dev, I2C_SCLK_XTAL); /*!< I2C source clock from XTAL, 40M */
#endif
i2c_ll_set_txfifo_empty_thr(i2c->dev, a);
i2c_ll_set_rxfifo_full_thr(i2c->dev, SOC_I2C_FIFO_LEN - a);
i2c_ll_set_bus_timing(i2c->dev, &clk_cal);
i2c_ll_set_filter(i2c->dev, 3);
return true;
}
static void i2c_slave_delay_us(uint64_t us)
{
uint64_t m = esp_timer_get_time();
if (us) {
uint64_t e = (m + us);
if (m > e) { //overflow
while ((uint64_t)esp_timer_get_time() > e);
}
while ((uint64_t)esp_timer_get_time() < e);
}
}
static void i2c_slave_gpio_mode(int8_t pin, gpio_mode_t mode)
{
gpio_config_t conf = {
.pin_bit_mask = 1LL << pin,
.mode = mode,
.pull_up_en = GPIO_PULLUP_ENABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE
};
gpio_config(&conf);
}
static bool i2c_slave_check_line_state(int8_t sda, int8_t scl)
{
if (sda < 0 || scl < 0) {
return false;//return false since there is nothing to do
}
// if the bus is not 'clear' try the cycling SCL until SDA goes High or 9 cycles
gpio_set_level(sda, 1);
gpio_set_level(scl, 1);
i2c_slave_gpio_mode(sda, GPIO_MODE_INPUT | GPIO_MODE_DEF_OD);
i2c_slave_gpio_mode(scl, GPIO_MODE_INPUT | GPIO_MODE_DEF_OD);
gpio_set_level(scl, 1);
if (!gpio_get_level(sda) || !gpio_get_level(scl)) { // bus in busy state
log_w("invalid state sda(%d)=%d, scl(%d)=%d", sda, gpio_get_level(sda), scl, gpio_get_level(scl));
for (uint8_t a=0; a<9; a++) {
i2c_slave_delay_us(5);
if (gpio_get_level(sda) && gpio_get_level(scl)) { // bus recovered
log_w("Recovered after %d Cycles",a);
gpio_set_level(sda,0); // start
i2c_slave_delay_us(5);
for (uint8_t a=0;a<9; a++) {
gpio_set_level(scl,1);
i2c_slave_delay_us(5);
gpio_set_level(scl,0);
i2c_slave_delay_us(5);
}
gpio_set_level(scl,1);
i2c_slave_delay_us(5);
gpio_set_level(sda,1); // stop
break;
}
gpio_set_level(scl, 0);
i2c_slave_delay_us(5);
gpio_set_level(scl, 1);
}
}
if (!gpio_get_level(sda) || !gpio_get_level(scl)) { // bus in busy state
log_e("Bus Invalid State, Can't init sda=%d, scl=%d",gpio_get_level(sda),gpio_get_level(scl));
return false; // bus is busy
}
return true;
}
static bool i2c_slave_attach_gpio(i2c_slave_struct_t * i2c, int8_t sda, int8_t scl)
{
if (i2c == NULL) {
log_e("no control block");
return false;
}
if ((sda < 0)||( scl < 0)) {
log_e("bad pins sda=%d, scl=%d",sda,scl);
return false;
}
i2c->scl = scl;
gpio_set_level(scl, 1);
i2c_slave_gpio_mode(scl, GPIO_MODE_INPUT_OUTPUT_OD);
gpio_matrix_out(scl, I2C_SCL_IDX(i2c->num), false, false);
gpio_matrix_in(scl, I2C_SCL_IDX(i2c->num), false);
i2c->sda = sda;
gpio_set_level(sda, 1);
i2c_slave_gpio_mode(sda, GPIO_MODE_INPUT_OUTPUT_OD);
gpio_matrix_out(sda, I2C_SDA_IDX(i2c->num), false, false);
gpio_matrix_in(sda, I2C_SDA_IDX(i2c->num), false);
return true;
}
static bool i2c_slave_detach_gpio(i2c_slave_struct_t * i2c)
{
if (i2c == NULL) {
log_e("no control Block");
return false;
}
if (i2c->scl >= 0) {
gpio_matrix_out(i2c->scl, 0x100, false, false);
gpio_matrix_in(0x30, I2C_SCL_IDX(i2c->num), false);
i2c_slave_gpio_mode(i2c->scl, GPIO_MODE_INPUT);
i2c->scl = -1; // un attached
}
if (i2c->sda >= 0) {
gpio_matrix_out(i2c->sda, 0x100, false, false);
gpio_matrix_in(0x30, I2C_SDA_IDX(i2c->num), false);
i2c_slave_gpio_mode(i2c->sda, GPIO_MODE_INPUT);
i2c->sda = -1; // un attached
}
return true;
}
static bool i2c_slave_send_event(i2c_slave_struct_t * i2c, i2c_slave_queue_event_t* event)
{
bool pxHigherPriorityTaskWoken = false;
if(i2c->event_queue) {
if(xQueueSendFromISR(i2c->event_queue, event, (BaseType_t * const)&pxHigherPriorityTaskWoken) != pdTRUE){
//log_e("event_queue_full");
}
}
return pxHigherPriorityTaskWoken;
}
static bool i2c_slave_handle_tx_fifo_empty(i2c_slave_struct_t * i2c)
{
bool pxHigherPriorityTaskWoken = false;
uint32_t d = 0, moveCnt = i2c_ll_get_txfifo_len(i2c->dev);
while (moveCnt > 0) { // read tx queue until Fifo is full or queue is empty
if(xQueueReceiveFromISR(i2c->tx_queue, &d, (BaseType_t * const)&pxHigherPriorityTaskWoken) == pdTRUE){
i2c_ll_write_txfifo(i2c->dev, (uint8_t*)&d, 1);
moveCnt--;
} else {
i2c_ll_slave_disable_tx_it(i2c->dev);
break;
}
}
return pxHigherPriorityTaskWoken;
}
static bool i2c_slave_handle_rx_fifo_full(i2c_slave_struct_t * i2c, uint32_t len)
{
#if I2C_SLAVE_USE_RX_QUEUE
uint32_t d = 0;
#else
uint8_t data[SOC_I2C_FIFO_LEN];
#endif
bool pxHigherPriorityTaskWoken = false;
#if I2C_SLAVE_USE_RX_QUEUE
while (len > 0) {
i2c_ll_read_rxfifo(i2c->dev, (uint8_t*)&d, 1);
if(xQueueSendFromISR(i2c->rx_queue, &d, (BaseType_t * const)&pxHigherPriorityTaskWoken) != pdTRUE){
log_e("rx_queue_full");
} else {
i2c->rx_data_count++;
}
if (--len == 0) {
len = i2c_ll_get_rxfifo_cnt(i2c->dev);
}
#else
if(len){
i2c_ll_read_rxfifo(i2c->dev, data, len);
if(xRingbufferSendFromISR(i2c->rx_ring_buf, (void*) data, len, (BaseType_t * const)&pxHigherPriorityTaskWoken) != pdTRUE){
log_e("rx_ring_buf_full");
} else {
i2c->rx_data_count += len;
}
#endif
}
return pxHigherPriorityTaskWoken;
}
static void i2c_slave_isr_handler(void* arg)
{
bool pxHigherPriorityTaskWoken = false;
i2c_slave_struct_t * i2c = (i2c_slave_struct_t *) arg; // recover data
uint32_t activeInt = i2c_ll_get_intsts_mask(i2c->dev);
i2c_ll_clr_intsts_mask(i2c->dev, activeInt);
uint8_t rx_fifo_len = i2c_ll_get_rxfifo_cnt(i2c->dev);
bool slave_rw = i2c_ll_slave_rw(i2c->dev);
if(activeInt & I2C_RXFIFO_WM_INT_ENA){ // RX FiFo Full
pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len);
i2c_ll_slave_enable_rx_it(i2c->dev);//is this necessary?
}
if(activeInt & I2C_TRANS_COMPLETE_INT_ENA){ // STOP
if(rx_fifo_len){ //READ RX FIFO
pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len);
}
if(i2c->rx_data_count){ //WRITE or RepeatedStart
//SEND RX Event
i2c_slave_queue_event_t event;
event.event = I2C_SLAVE_EVT_RX;
event.stop = !slave_rw;
event.param = i2c->rx_data_count;
pxHigherPriorityTaskWoken |= i2c_slave_send_event(i2c, &event);
//Zero RX count
i2c->rx_data_count = 0;
}
if(slave_rw){ // READ
#if CONFIG_IDF_TARGET_ESP32
if(i2c->dev->status_reg.scl_main_state_last == 6){
//SEND TX Event
i2c_slave_queue_event_t event;
event.event = I2C_SLAVE_EVT_TX;
pxHigherPriorityTaskWoken |= i2c_slave_send_event(i2c, &event);
}
#else
//reset TX data
i2c_ll_txfifo_rst(i2c->dev);
uint8_t d;
while (xQueueReceiveFromISR(i2c->tx_queue, &d, (BaseType_t * const)&pxHigherPriorityTaskWoken) == pdTRUE) ;//flush partial write
#endif
}
}
#ifndef CONFIG_IDF_TARGET_ESP32
if(activeInt & I2C_SLAVE_STRETCH_INT_ENA){ // STRETCH
i2c_stretch_cause_t cause = i2c_ll_stretch_cause(i2c->dev);
if(cause == I2C_STRETCH_CAUSE_MASTER_READ){
//on C3 RX data dissapears with repeated start, so we need to get it here
if(rx_fifo_len){
pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len);
}
//SEND TX Event
i2c_slave_queue_event_t event;
event.event = I2C_SLAVE_EVT_TX;
pxHigherPriorityTaskWoken |= i2c_slave_send_event(i2c, &event);
//will clear after execution
} else if(cause == I2C_STRETCH_CAUSE_TX_FIFO_EMPTY){
pxHigherPriorityTaskWoken |= i2c_slave_handle_tx_fifo_empty(i2c);
i2c_ll_stretch_clr(i2c->dev);
} else if(cause == I2C_STRETCH_CAUSE_RX_FIFO_FULL){
pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len);
i2c_ll_stretch_clr(i2c->dev);
}
}
#endif
if(activeInt & I2C_TXFIFO_WM_INT_ENA){ // TX FiFo Empty
pxHigherPriorityTaskWoken |= i2c_slave_handle_tx_fifo_empty(i2c);
}
if(pxHigherPriorityTaskWoken){
portYIELD_FROM_ISR();
}
}
static size_t i2c_slave_read_rx(i2c_slave_struct_t * i2c, uint8_t * data, size_t len){
if(!len){
return 0;
}
#if I2C_SLAVE_USE_RX_QUEUE
uint8_t d = 0;
BaseType_t res = pdTRUE;
for(size_t i=0; i<len; i++) {
if(data){
res = xQueueReceive(i2c->rx_queue, &data[i], 0);
} else {
res = xQueueReceive(i2c->rx_queue, &d, 0);
}
if (res != pdTRUE) {
log_e("Read Queue(%u) Failed", i);
len = i;
break;
}
}
return (data)?len:0;
#else
size_t dlen = 0,
to_read = len,
so_far = 0,
available = 0;
uint8_t * rx_data = NULL;
vRingbufferGetInfo(i2c->rx_ring_buf, NULL, NULL, NULL, NULL, &available);
if(available < to_read){
log_e("Less available than requested. %u < %u", available, len);
to_read = available;
}
while(to_read){
dlen = 0;
rx_data = (uint8_t *)xRingbufferReceiveUpTo(i2c->rx_ring_buf, &dlen, 0, to_read);
if(!rx_data){
log_e("Receive %u Failed", to_read);
return so_far;
}
if(data){
memcpy(data+so_far, rx_data, dlen);
}
vRingbufferReturnItem(i2c->rx_ring_buf, rx_data);
so_far+=dlen;
to_read-=dlen;
}
return (data)?so_far:0;
#endif
}
static void i2c_slave_task(void *pv_args)
{
i2c_slave_struct_t * i2c = (i2c_slave_struct_t *)pv_args;
i2c_slave_queue_event_t event;
size_t len = 0;
bool stop = false;
uint8_t * data = NULL;
for(;;){
if(xQueueReceive(i2c->event_queue, &event, portMAX_DELAY) == pdTRUE){
// Write
if(event.event == I2C_SLAVE_EVT_RX){
len = event.param;
stop = event.stop;
data = (len > 0)?(uint8_t*)malloc(len):NULL;
if(len && data == NULL){
log_e("Malloc (%u) Failed", len);
}
len = i2c_slave_read_rx(i2c, data, len);
if(i2c->receive_callback){
i2c->receive_callback(i2c->num, data, len, stop, i2c->arg);
}
free(data);
// Read
} else if(event.event == I2C_SLAVE_EVT_TX){
if(i2c->request_callback){
i2c->request_callback(i2c->num, i2c->arg);
}
i2c_ll_stretch_clr(i2c->dev);
}
}
}
vTaskDelete(NULL);
}

View File

@ -1,35 +0,0 @@
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "stdint.h"
#include "stddef.h"
#include "esp_err.h"
typedef void (*i2c_slave_request_cb_t) (uint8_t num, void * arg);
typedef void (*i2c_slave_receive_cb_t) (uint8_t num, uint8_t * data, size_t len, bool stop, void * arg);
esp_err_t i2cSlaveAttachCallbacks(uint8_t num, i2c_slave_request_cb_t request_callback, i2c_slave_receive_cb_t receive_callback, void * arg);
esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t frequency, size_t rx_len, size_t tx_len);
esp_err_t i2cSlaveDeinit(uint8_t num);
size_t i2cSlaveWrite(uint8_t num, const uint8_t *buf, uint32_t len, uint32_t timeout_ms);
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// modified Nov 2017 by Chuck Todd <StickBreaker> to support Interrupt Driven I/O // modified Nov 2017 by Chuck Todd <StickBreaker> to support Interrupt Driven I/O
// modified Nov 2021 by Hristo Gochkov <Me-No-Dev> to support ESP-IDF API
#ifndef _ESP32_HAL_I2C_H_ #ifndef _ESP32_HAL_I2C_H_
#define _ESP32_HAL_I2C_H_ #define _ESP32_HAL_I2C_H_
@ -23,16 +22,58 @@ extern "C" {
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <esp_err.h> #include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
esp_err_t i2cInit(uint8_t i2c_num, int8_t sda, int8_t scl, uint32_t clk_speed); // External Wire.h equivalent error Codes
esp_err_t i2cDeinit(uint8_t i2c_num); typedef enum {
esp_err_t i2cSetClock(uint8_t i2c_num, uint32_t frequency); I2C_ERROR_OK=0,
esp_err_t i2cGetClock(uint8_t i2c_num, uint32_t * frequency); I2C_ERROR_DEV,
esp_err_t i2cWrite(uint8_t i2c_num, uint16_t address, const uint8_t* buff, size_t size, uint32_t timeOutMillis); I2C_ERROR_ACK,
esp_err_t i2cRead(uint8_t i2c_num, uint16_t address, uint8_t* buff, size_t size, uint32_t timeOutMillis, size_t *readCount); I2C_ERROR_TIMEOUT,
esp_err_t i2cWriteReadNonStop(uint8_t i2c_num, uint16_t address, const uint8_t* wbuff, size_t wsize, uint8_t* rbuff, size_t rsize, uint32_t timeOutMillis, size_t *readCount); I2C_ERROR_BUS,
bool i2cIsInit(uint8_t i2c_num); I2C_ERROR_BUSY,
I2C_ERROR_MEMORY,
I2C_ERROR_CONTINUE,
I2C_ERROR_NO_BEGIN
} i2c_err_t;
struct i2c_struct_t;
typedef struct i2c_struct_t i2c_t;
i2c_t * i2cInit(uint8_t i2c_num, int8_t sda, int8_t scl, uint32_t clk_speed);
void i2cRelease(i2c_t *i2c); // free ISR, Free DQ, Power off peripheral clock. Must call i2cInit() to recover
i2c_err_t i2cWrite(i2c_t * i2c, uint16_t address, uint8_t* buff, uint16_t size, bool sendStop, uint16_t timeOutMillis);
i2c_err_t i2cRead(i2c_t * i2c, uint16_t address, uint8_t* buff, uint16_t size, bool sendStop, uint16_t timeOutMillis, uint32_t *readCount);
i2c_err_t i2cFlush(i2c_t *i2c);
i2c_err_t i2cSetFrequency(i2c_t * i2c, uint32_t clk_speed);
uint32_t i2cGetFrequency(i2c_t * i2c);
uint32_t i2cGetStatus(i2c_t * i2c); // Status register of peripheral
//Functions below should be used only if well understood
//Might be deprecated and removed in future
i2c_err_t i2cAttachSCL(i2c_t * i2c, int8_t scl);
i2c_err_t i2cDetachSCL(i2c_t * i2c, int8_t scl);
i2c_err_t i2cAttachSDA(i2c_t * i2c, int8_t sda);
i2c_err_t i2cDetachSDA(i2c_t * i2c, int8_t sda);
//Stickbreakers ISR Support
i2c_err_t i2cProcQueue(i2c_t *i2c, uint32_t *readCount, uint16_t timeOutMillis);
i2c_err_t i2cAddQueueWrite(i2c_t *i2c, uint16_t i2cDeviceAddr, uint8_t *dataPtr, uint16_t dataLen, bool SendStop, EventGroupHandle_t event);
i2c_err_t i2cAddQueueRead(i2c_t *i2c, uint16_t i2cDeviceAddr, uint8_t *dataPtr, uint16_t dataLen, bool SendStop, EventGroupHandle_t event);
//stickbreaker debug support
uint32_t i2cDebug(i2c_t *, uint32_t setBits, uint32_t resetBits);
// Debug actions have 3 currently defined locus
// 0xXX------ : at entry of ProcQueue
// 0x--XX---- : at exit of ProcQueue
// 0x------XX : at entry of Flush
//
// bit 0 causes DumpI2c to execute
// bit 1 causes DumpInts to execute
// bit 2 causes DumpCmdqueue to execute
// bit 3 causes DumpStatus to execute
// bit 4 causes DumpFifo to execute
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -13,25 +13,39 @@
// limitations under the License. // limitations under the License.
#include "esp32-hal.h" #include "esp32-hal.h"
#include "soc/soc_caps.h" #include "freertos/FreeRTOS.h"
#include "driver/ledc.h" #include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp32-hal-matrix.h"
#include "soc/dport_reg.h"
#include "soc/ledc_reg.h"
#include "soc/ledc_struct.h"
#ifdef SOC_LEDC_SUPPORT_HS_MODE #include "esp_system.h"
#define LEDC_CHANNELS (SOC_LEDC_CHANNEL_NUM<<1) #ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
#include "esp32/rom/ets_sys.h"
#define LAST_CHAN (15)
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/ets_sys.h"
#define LAST_CHAN (7)
#define LEDC_DIV_NUM_HSTIMER0_V LEDC_CLK_DIV_LSTIMER0_V
#else #else
#define LEDC_CHANNELS (SOC_LEDC_CHANNEL_NUM) #error Target CONFIG_IDF_TARGET is not supported
#endif
#else // ESP32 Before IDF 4.0
#include "rom/ets_sys.h"
#endif #endif
//Use XTAL clock if possible to avoid timer frequency error when setting APB clock < 80 Mhz #if CONFIG_DISABLE_HAL_LOCKS
//Need to be fixed in ESP-IDF #define LEDC_MUTEX_LOCK()
#ifdef SOC_LEDC_SUPPORT_XTAL_CLOCK #define LEDC_MUTEX_UNLOCK()
#define LEDC_DEFAULT_CLK LEDC_USE_XTAL_CLK
#else #else
#define LEDC_DEFAULT_CLK LEDC_AUTO_CLK #define LEDC_MUTEX_LOCK() do {} while (xSemaphoreTake(_ledc_sys_lock, portMAX_DELAY) != pdPASS)
#define LEDC_MUTEX_UNLOCK() xSemaphoreGive(_ledc_sys_lock)
xSemaphoreHandle _ledc_sys_lock = NULL;
#endif #endif
#define LEDC_MAX_BIT_WIDTH SOC_LEDC_TIMER_BIT_WIDE_NUM
/* /*
* LEDC Chan to Group/Channel/Timer Mapping * LEDC Chan to Group/Channel/Timer Mapping
** ledc: 0 => Group: 0, Channel: 0, Timer: 0 ** ledc: 0 => Group: 0, Channel: 0, Timer: 0
@ -51,103 +65,225 @@
** ledc: 14 => Group: 1, Channel: 6, Timer: 3 ** ledc: 14 => Group: 1, Channel: 6, Timer: 3
** ledc: 15 => Group: 1, Channel: 7, Timer: 3 ** ledc: 15 => Group: 1, Channel: 7, Timer: 3
*/ */
#define LEDC_CHAN(g,c) LEDC.channel_group[(g)].channel[(c)]
#define LEDC_TIMER(g,t) LEDC.timer_group[(g)].timer[(t)]
uint8_t channels_resolution[LEDC_CHANNELS] = {0}; static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){
if(ev_type == APB_AFTER_CHANGE && old_apb != new_apb){
uint32_t ledcSetup(uint8_t chan, uint32_t freq, uint8_t bit_num) uint16_t iarg = *(uint16_t*)arg;
{ uint8_t chan = 0;
if(chan >= LEDC_CHANNELS || bit_num > LEDC_MAX_BIT_WIDTH){ old_apb /= 1000000;
log_e("No more LEDC channels available! (maximum %u) or bit width too big (maximum %u)", LEDC_CHANNELS, LEDC_MAX_BIT_WIDTH); new_apb /= 1000000;
return 0; while(iarg){ // run though all active channels, adjusting timing configurations
} if(iarg & 1) {// this channel is active
uint8_t group=(chan/8), timer=((chan/2)%4); uint8_t group=(chan/8), timer=((chan/2)%4);
if(LEDC_TIMER(group, timer).conf.tick_sel){
LEDC_MUTEX_LOCK();
uint32_t old_div = LEDC_TIMER(group, timer).conf.clock_divider;
uint32_t div_num = (new_apb * old_div) / old_apb;
if(div_num > LEDC_DIV_NUM_HSTIMER0_V){
div_num = ((REF_CLK_FREQ /1000000) * old_div) / old_apb;
if(div_num > LEDC_DIV_NUM_HSTIMER0_V) {
div_num = LEDC_DIV_NUM_HSTIMER0_V;//lowest clock possible
}
LEDC_TIMER(group, timer).conf.tick_sel = 0;
} else if(div_num < 256) {
div_num = 256;//highest clock possible
}
LEDC_TIMER(group, timer).conf.clock_divider = div_num;
LEDC_MUTEX_UNLOCK();
}
else {
log_d("using REF_CLK chan=%d",chan);
}
}
iarg = iarg >> 1;
chan++;
}
}
}
ledc_timer_config_t ledc_timer = { //uint32_t frequency = (80MHz or 1MHz)/((div_num / 256.0)*(1 << bit_num));
.speed_mode = group, static void _ledcSetupTimer(uint8_t chan, uint32_t div_num, uint8_t bit_num, bool apb_clk)
.timer_num = timer, {
.duty_resolution = bit_num, uint8_t group=(chan/8), timer=((chan/2)%4);
.freq_hz = freq, static bool tHasStarted = false;
.clk_cfg = LEDC_DEFAULT_CLK static uint16_t _activeChannels = 0;
}; if(!tHasStarted) {
if(ledc_timer_config(&ledc_timer) != ESP_OK) tHasStarted = true;
{ DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_LEDC_CLK_EN);
log_e("ledc setup failed!"); DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_LEDC_RST);
LEDC.conf.apb_clk_sel = 1;//LS use apb clock
addApbChangeCallback((void*)&_activeChannels, _on_apb_change);
#if !CONFIG_DISABLE_HAL_LOCKS
_ledc_sys_lock = xSemaphoreCreateMutex();
#endif
}
LEDC_MUTEX_LOCK();
LEDC_TIMER(group, timer).conf.clock_divider = div_num;//18 bit (10.8) This register is used to configure parameter for divider in timer the least significant eight bits represent the decimal part.
LEDC_TIMER(group, timer).conf.duty_resolution = bit_num;//5 bit This register controls the range of the counter in timer. the counter range is [0 2**bit_num] the max bit width for counter is 20.
LEDC_TIMER(group, timer).conf.tick_sel = apb_clk;//apb clock
#if CONFIG_IDF_TARGET_ESP32
if(group) {
#endif
LEDC_TIMER(group, timer).conf.low_speed_update = 1;//This bit is only useful for low speed timer channels, reserved for high speed timers
#if CONFIG_IDF_TARGET_ESP32
}
#endif
LEDC_TIMER(group, timer).conf.pause = 0;
LEDC_TIMER(group, timer).conf.rst = 1;//This bit is used to reset timer the counter will be 0 after reset.
LEDC_TIMER(group, timer).conf.rst = 0;
LEDC_MUTEX_UNLOCK();
_activeChannels |= (1 << chan); // mark as active for APB callback
}
//max div_num 0x3FFFF (262143)
//max bit_num 0x1F (31)
static double _ledcSetupTimerFreq(uint8_t chan, double freq, uint8_t bit_num)
{
uint64_t clk_freq = getApbFrequency();
clk_freq <<= 8;//div_num is 8 bit decimal
uint32_t div_num = (clk_freq >> bit_num) / freq;
bool apb_clk = true;
if(div_num > LEDC_DIV_NUM_HSTIMER0_V) {
clk_freq /= 80;
div_num = (clk_freq >> bit_num) / freq;
if(div_num > LEDC_DIV_NUM_HSTIMER0_V) {
div_num = LEDC_DIV_NUM_HSTIMER0_V;//lowest clock possible
}
apb_clk = false;
} else if(div_num < 256) {
div_num = 256;//highest clock possible
}
_ledcSetupTimer(chan, div_num, bit_num, apb_clk);
//log_i("Fin: %f, Fclk: %uMhz, bits: %u, DIV: %u, Fout: %f",
// freq, apb_clk?80:1, bit_num, div_num, (clk_freq >> bit_num) / (double)div_num);
return (clk_freq >> bit_num) / (double)div_num;
}
static double _ledcTimerRead(uint8_t chan)
{
uint32_t div_num;
uint8_t bit_num;
bool apb_clk;
uint8_t group=(chan/8), timer=((chan/2)%4);
LEDC_MUTEX_LOCK();
div_num = LEDC_TIMER(group, timer).conf.clock_divider;//18 bit (10.8) This register is used to configure parameter for divider in timer the least significant eight bits represent the decimal part.
bit_num = LEDC_TIMER(group, timer).conf.duty_resolution;//5 bit This register controls the range of the counter in timer. the counter range is [0 2**bit_num] the max bit width for counter is 20.
apb_clk = LEDC_TIMER(group, timer).conf.tick_sel;//apb clock
LEDC_MUTEX_UNLOCK();
uint64_t clk_freq = 1000000;
if(apb_clk) {
clk_freq = getApbFrequency();
}
clk_freq <<= 8;//div_num is 8 bit decimal
return (clk_freq >> bit_num) / (double)div_num;
}
static void _ledcSetupChannel(uint8_t chan, uint8_t idle_level)
{
uint8_t group=(chan/8), channel=(chan%8), timer=((chan/2)%4);
LEDC_MUTEX_LOCK();
LEDC_CHAN(group, channel).conf0.timer_sel = timer;//2 bit Selects the timer to attach 0-3
LEDC_CHAN(group, channel).conf0.idle_lv = idle_level;//1 bit This bit is used to control the output value when channel is off.
LEDC_CHAN(group, channel).hpoint.hpoint = 0;//20 bit The output value changes to high when timer selected by channel has reached hpoint
LEDC_CHAN(group, channel).conf1.duty_inc = 1;//1 bit This register is used to increase the duty of output signal or decrease the duty of output signal for high speed channel
LEDC_CHAN(group, channel).conf1.duty_num = 1;//10 bit This register is used to control the number of increased or decreased times for channel
LEDC_CHAN(group, channel).conf1.duty_cycle = 1;//10 bit This register is used to increase or decrease the duty every duty_cycle cycles for channel
LEDC_CHAN(group, channel).conf1.duty_scale = 0;//10 bit This register controls the increase or decrease step scale for channel.
LEDC_CHAN(group, channel).duty.duty = 0;
LEDC_CHAN(group, channel).conf0.sig_out_en = 0;//This is the output enable control bit for channel
LEDC_CHAN(group, channel).conf1.duty_start = 0;//When duty_num duty_cycle and duty_scale has been configured. these register won't take effect until set duty_start. this bit is automatically cleared by hardware.
#if CONFIG_IDF_TARGET_ESP32
if(group) {
#endif
LEDC_CHAN(group, channel).conf0.low_speed_update = 1;
#if CONFIG_IDF_TARGET_ESP32
} else {
LEDC_CHAN(group, channel).conf0.clk_en = 0;
}
#endif
LEDC_MUTEX_UNLOCK();
}
double ledcSetup(uint8_t chan, double freq, uint8_t bit_num)
{
if(chan > LAST_CHAN) {
return 0; return 0;
} }
channels_resolution[chan] = bit_num; double res_freq = _ledcSetupTimerFreq(chan, freq, bit_num);
return ledc_get_freq(group,timer); _ledcSetupChannel(chan, LOW);
return res_freq;
} }
void ledcWrite(uint8_t chan, uint32_t duty) void ledcWrite(uint8_t chan, uint32_t duty)
{ {
if(chan >= LEDC_CHANNELS){ if(chan > LAST_CHAN) {
return; return;
} }
uint8_t group=(chan/8), channel=(chan%8); uint8_t group=(chan/8), channel=(chan%8);
LEDC_MUTEX_LOCK();
//Fixing if all bits in resolution is set = LEDC FULL ON LEDC_CHAN(group, channel).duty.duty = duty << 4;//25 bit (21.4)
uint32_t max_duty = (1 << channels_resolution[chan]) - 1; if(duty) {
LEDC_CHAN(group, channel).conf0.sig_out_en = 1;//This is the output enable control bit for channel
if(duty == max_duty){ LEDC_CHAN(group, channel).conf1.duty_start = 1;//When duty_num duty_cycle and duty_scale has been configured. these register won't take effect until set duty_start. this bit is automatically cleared by hardware.
duty = max_duty + 1; #if CONFIG_IDF_TARGET_ESP32
if(group) {
#endif
LEDC_CHAN(group, channel).conf0.low_speed_update = 1;
#if CONFIG_IDF_TARGET_ESP32
} else {
LEDC_CHAN(group, channel).conf0.clk_en = 1;
} }
#endif
ledc_set_duty(group, channel, duty); } else {
ledc_update_duty(group, channel); LEDC_CHAN(group, channel).conf0.sig_out_en = 0;//This is the output enable control bit for channel
LEDC_CHAN(group, channel).conf1.duty_start = 0;//When duty_num duty_cycle and duty_scale has been configured. these register won't take effect until set duty_start. this bit is automatically cleared by hardware.
#if CONFIG_IDF_TARGET_ESP32
if(group) {
#endif
LEDC_CHAN(group, channel).conf0.low_speed_update = 1;
#if CONFIG_IDF_TARGET_ESP32
} else {
LEDC_CHAN(group, channel).conf0.clk_en = 0;
}
#endif
}
LEDC_MUTEX_UNLOCK();
} }
uint32_t ledcRead(uint8_t chan) uint32_t ledcRead(uint8_t chan)
{ {
if(chan >= LEDC_CHANNELS){ if(chan > LAST_CHAN) {
return 0; return 0;
} }
uint8_t group=(chan/8), channel=(chan%8); return LEDC.channel_group[chan/8].channel[chan%8].duty.duty >> 4;
return ledc_get_duty(group,channel);
} }
uint32_t ledcReadFreq(uint8_t chan) double ledcReadFreq(uint8_t chan)
{ {
if(!ledcRead(chan)){ if(!ledcRead(chan)){
return 0; return 0;
} }
uint8_t group=(chan/8), timer=((chan/2)%4); return _ledcTimerRead(chan);
return ledc_get_freq(group,timer);
} }
uint32_t ledcWriteTone(uint8_t chan, uint32_t freq) double ledcWriteTone(uint8_t chan, double freq)
{ {
if(chan >= LEDC_CHANNELS){ if(chan > LAST_CHAN) {
return 0; return 0;
} }
if(!freq){ if(!freq) {
ledcWrite(chan, 0); ledcWrite(chan, 0);
return 0; return 0;
} }
double res_freq = _ledcSetupTimerFreq(chan, freq, 10);
uint8_t group=(chan/8), timer=((chan/2)%4);
ledc_timer_config_t ledc_timer = {
.speed_mode = group,
.timer_num = timer,
.duty_resolution = 10,
.freq_hz = freq,
.clk_cfg = LEDC_DEFAULT_CLK
};
if(ledc_timer_config(&ledc_timer) != ESP_OK)
{
log_e("ledcSetup failed!");
return 0;
}
channels_resolution[chan] = 10;
uint32_t res_freq = ledc_get_freq(group,timer);
ledcWrite(chan, 0x1FF); ledcWrite(chan, 0x1FF);
return res_freq; return res_freq;
} }
uint32_t ledcWriteNote(uint8_t chan, note_t note, uint8_t octave){ double ledcWriteNote(uint8_t chan, note_t note, uint8_t octave){
const uint16_t noteFrequencyBase[12] = { const uint16_t noteFrequencyBase[12] = {
// C C# D Eb E F F# G G# A Bb B // C C# D Eb E F F# G G# A Bb B
4186, 4435, 4699, 4978, 5274, 5588, 5920, 6272, 6645, 7040, 7459, 7902 4186, 4435, 4699, 4978, 5274, 5588, 5920, 6272, 6645, 7040, 7459, 7902
@ -156,73 +292,24 @@ uint32_t ledcWriteNote(uint8_t chan, note_t note, uint8_t octave){
if(octave > 8 || note >= NOTE_MAX){ if(octave > 8 || note >= NOTE_MAX){
return 0; return 0;
} }
uint32_t noteFreq = (uint32_t)noteFrequencyBase[note] / (uint32_t)(1 << (8-octave)); double noteFreq = (double)noteFrequencyBase[note] / (double)(1 << (8-octave));
return ledcWriteTone(chan, noteFreq); return ledcWriteTone(chan, noteFreq);
} }
void ledcAttachPin(uint8_t pin, uint8_t chan) void ledcAttachPin(uint8_t pin, uint8_t chan)
{ {
if(chan >= LEDC_CHANNELS){ if(chan > LAST_CHAN) {
return; return;
} }
uint8_t group=(chan/8), channel=(chan%8), timer=((chan/2)%4); pinMode(pin, OUTPUT);
#if CONFIG_IDF_TARGET_ESP32S2
ledc_channel_config_t ledc_channel = { pinMatrixOutAttach(pin, LEDC_LS_SIG_OUT0_IDX + chan, false, false);
.speed_mode = group, #else
.channel = channel, pinMatrixOutAttach(pin, ((chan/8)?LEDC_LS_SIG_OUT0_IDX:LEDC_HS_SIG_OUT0_IDX) + (chan%8), false, false);
.timer_sel = timer, #endif
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = pin,
.duty = 0,
.hpoint = 0
};
ledc_channel_config(&ledc_channel);
} }
void ledcDetachPin(uint8_t pin) void ledcDetachPin(uint8_t pin)
{ {
pinMatrixOutDetach(pin, false, false); pinMatrixOutDetach(pin, false, false);
} }
uint32_t ledcChangeFrequency(uint8_t chan, uint32_t freq, uint8_t bit_num)
{
if(chan >= LEDC_CHANNELS || bit_num > LEDC_MAX_BIT_WIDTH){
log_e("LEDC channel not available! (maximum %u) or bit width too big (maximum %u)", LEDC_CHANNELS, LEDC_MAX_BIT_WIDTH);
return 0;
}
uint8_t group=(chan/8), timer=((chan/2)%4);
ledc_timer_config_t ledc_timer = {
.speed_mode = group,
.timer_num = timer,
.duty_resolution = bit_num,
.freq_hz = freq,
.clk_cfg = LEDC_DEFAULT_CLK
};
if(ledc_timer_config(&ledc_timer) != ESP_OK)
{
log_e("ledcChangeFrequency failed!");
return 0;
}
channels_resolution[chan] = bit_num;
return ledc_get_freq(group,timer);
}
static int8_t pin_to_channel[SOC_GPIO_PIN_COUNT] = { 0 };
static int cnt_channel = LEDC_CHANNELS;
void analogWrite(uint8_t pin, int value) {
// Use ledc hardware for internal pins
if (pin < SOC_GPIO_PIN_COUNT) {
if (pin_to_channel[pin] == 0) {
if (!cnt_channel) {
log_e("No more analogWrite channels available! You can have maximum %u", LEDC_CHANNELS);
return;
}
pin_to_channel[pin] = cnt_channel--;
ledcAttachPin(pin, cnt_channel);
ledcSetup(cnt_channel, 1000, 8);
}
ledcWrite(pin_to_channel[pin] - 1, value);
}
}

View File

@ -27,15 +27,14 @@ typedef enum {
} note_t; } note_t;
//channel 0-15 resolution 1-16bits freq limits depend on resolution //channel 0-15 resolution 1-16bits freq limits depend on resolution
uint32_t ledcSetup(uint8_t channel, uint32_t freq, uint8_t resolution_bits); double ledcSetup(uint8_t channel, double freq, uint8_t resolution_bits);
void ledcWrite(uint8_t channel, uint32_t duty); void ledcWrite(uint8_t channel, uint32_t duty);
uint32_t ledcWriteTone(uint8_t channel, uint32_t freq); double ledcWriteTone(uint8_t channel, double freq);
uint32_t ledcWriteNote(uint8_t channel, note_t note, uint8_t octave); double ledcWriteNote(uint8_t channel, note_t note, uint8_t octave);
uint32_t ledcRead(uint8_t channel); uint32_t ledcRead(uint8_t channel);
uint32_t ledcReadFreq(uint8_t channel); double ledcReadFreq(uint8_t channel);
void ledcAttachPin(uint8_t pin, uint8_t channel); void ledcAttachPin(uint8_t pin, uint8_t channel);
void ledcDetachPin(uint8_t pin); void ledcDetachPin(uint8_t pin);
uint32_t ledcChangeFrequency(uint8_t channel, uint32_t freq, uint8_t resolution_bits);
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -37,11 +37,6 @@ extern "C"
#define ARDUHAL_LOG_LEVEL CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL #define ARDUHAL_LOG_LEVEL CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL
#else #else
#define ARDUHAL_LOG_LEVEL CORE_DEBUG_LEVEL #define ARDUHAL_LOG_LEVEL CORE_DEBUG_LEVEL
#ifdef USE_ESP_IDF_LOG
#ifndef LOG_LOCAL_LEVEL
#define LOG_LOCAL_LEVEL CORE_DEBUG_LEVEL
#endif
#endif
#endif #endif
#ifndef CONFIG_ARDUHAL_LOG_COLORS #ifndef CONFIG_ARDUHAL_LOG_COLORS
@ -68,8 +63,6 @@ extern "C"
#define ARDUHAL_LOG_COLOR_I ARDUHAL_LOG_COLOR(ARDUHAL_LOG_COLOR_GREEN) #define ARDUHAL_LOG_COLOR_I ARDUHAL_LOG_COLOR(ARDUHAL_LOG_COLOR_GREEN)
#define ARDUHAL_LOG_COLOR_D ARDUHAL_LOG_COLOR(ARDUHAL_LOG_COLOR_CYAN) #define ARDUHAL_LOG_COLOR_D ARDUHAL_LOG_COLOR(ARDUHAL_LOG_COLOR_CYAN)
#define ARDUHAL_LOG_COLOR_V ARDUHAL_LOG_COLOR(ARDUHAL_LOG_COLOR_GRAY) #define ARDUHAL_LOG_COLOR_V ARDUHAL_LOG_COLOR(ARDUHAL_LOG_COLOR_GRAY)
#define ARDUHAL_LOG_COLOR_PRINT(letter) log_printf(ARDUHAL_LOG_COLOR_ ## letter)
#define ARDUHAL_LOG_COLOR_PRINT_END log_printf(ARDUHAL_LOG_RESET_COLOR)
#else #else
#define ARDUHAL_LOG_COLOR_E #define ARDUHAL_LOG_COLOR_E
#define ARDUHAL_LOG_COLOR_W #define ARDUHAL_LOG_COLOR_W
@ -77,123 +70,64 @@ extern "C"
#define ARDUHAL_LOG_COLOR_D #define ARDUHAL_LOG_COLOR_D
#define ARDUHAL_LOG_COLOR_V #define ARDUHAL_LOG_COLOR_V
#define ARDUHAL_LOG_RESET_COLOR #define ARDUHAL_LOG_RESET_COLOR
#define ARDUHAL_LOG_COLOR_PRINT(letter)
#define ARDUHAL_LOG_COLOR_PRINT_END
#endif #endif
const char * pathToFileName(const char * path); const char * pathToFileName(const char * path);
int log_printf(const char *fmt, ...); int log_printf(const char *fmt, ...);
void log_print_buf(const uint8_t *b, size_t len);
#define ARDUHAL_SHORT_LOG_FORMAT(letter, format) ARDUHAL_LOG_COLOR_ ## letter format ARDUHAL_LOG_RESET_COLOR "\r\n" #define ARDUHAL_SHORT_LOG_FORMAT(letter, format) ARDUHAL_LOG_COLOR_ ## letter format ARDUHAL_LOG_RESET_COLOR "\r\n"
#define ARDUHAL_LOG_FORMAT(letter, format) ARDUHAL_LOG_COLOR_ ## letter "[%6u][" #letter "][%s:%u] %s(): " format ARDUHAL_LOG_RESET_COLOR "\r\n", (unsigned long) (esp_timer_get_time() / 1000ULL), pathToFileName(__FILE__), __LINE__, __FUNCTION__ #define ARDUHAL_LOG_FORMAT(letter, format) ARDUHAL_LOG_COLOR_ ## letter "[%6u][" #letter "][%s:%u] %s(): " format ARDUHAL_LOG_RESET_COLOR "\r\n", (unsigned long) (esp_timer_get_time() / 1000ULL), pathToFileName(__FILE__), __LINE__, __FUNCTION__
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
#ifndef USE_ESP_IDF_LOG
#define log_v(format, ...) log_printf(ARDUHAL_LOG_FORMAT(V, format), ##__VA_ARGS__) #define log_v(format, ...) log_printf(ARDUHAL_LOG_FORMAT(V, format), ##__VA_ARGS__)
#define isr_log_v(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(V, format), ##__VA_ARGS__) #define isr_log_v(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(V, format), ##__VA_ARGS__)
#define log_buf_v(b,l) do{ARDUHAL_LOG_COLOR_PRINT(V);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0)
#else #else
#define log_v(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_VERBOSE, TAG, format, ##__VA_ARGS__);}while(0) #define log_v(format, ...)
#define isr_log_v(format, ...) do {ets_printf(LOG_FORMAT(V, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0) #define isr_log_v(format, ...)
#define log_buf_v(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_VERBOSE);}while(0)
#endif
#else
#define log_v(format, ...) do {} while(0)
#define isr_log_v(format, ...) do {} while(0)
#define log_buf_v(b,l) do {} while(0)
#endif #endif
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
#ifndef USE_ESP_IDF_LOG
#define log_d(format, ...) log_printf(ARDUHAL_LOG_FORMAT(D, format), ##__VA_ARGS__) #define log_d(format, ...) log_printf(ARDUHAL_LOG_FORMAT(D, format), ##__VA_ARGS__)
#define isr_log_d(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(D, format), ##__VA_ARGS__) #define isr_log_d(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(D, format), ##__VA_ARGS__)
#define log_buf_d(b,l) do{ARDUHAL_LOG_COLOR_PRINT(D);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0)
#else #else
#define log_d(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_DEBUG, TAG, format, ##__VA_ARGS__);}while(0) #define log_d(format, ...)
#define isr_log_d(format, ...) do {ets_printf(LOG_FORMAT(D, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0) #define isr_log_d(format, ...)
#define log_buf_d(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_DEBUG);}while(0)
#endif
#else
#define log_d(format, ...) do {} while(0)
#define isr_log_d(format, ...) do {} while(0)
#define log_buf_d(b,l) do {} while(0)
#endif #endif
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
#ifndef USE_ESP_IDF_LOG
#define log_i(format, ...) log_printf(ARDUHAL_LOG_FORMAT(I, format), ##__VA_ARGS__) #define log_i(format, ...) log_printf(ARDUHAL_LOG_FORMAT(I, format), ##__VA_ARGS__)
#define isr_log_i(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(I, format), ##__VA_ARGS__) #define isr_log_i(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(I, format), ##__VA_ARGS__)
#define log_buf_i(b,l) do{ARDUHAL_LOG_COLOR_PRINT(I);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0)
#else #else
#define log_i(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_INFO, TAG, format, ##__VA_ARGS__);}while(0) #define log_i(format, ...)
#define isr_log_i(format, ...) do {ets_printf(LOG_FORMAT(I, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0) #define isr_log_i(format, ...)
#define log_buf_i(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_INFO);}while(0)
#endif
#else
#define log_i(format, ...) do {} while(0)
#define isr_log_i(format, ...) do {} while(0)
#define log_buf_i(b,l) do {} while(0)
#endif #endif
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_WARN #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_WARN
#ifndef USE_ESP_IDF_LOG
#define log_w(format, ...) log_printf(ARDUHAL_LOG_FORMAT(W, format), ##__VA_ARGS__) #define log_w(format, ...) log_printf(ARDUHAL_LOG_FORMAT(W, format), ##__VA_ARGS__)
#define isr_log_w(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(W, format), ##__VA_ARGS__) #define isr_log_w(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(W, format), ##__VA_ARGS__)
#define log_buf_w(b,l) do{ARDUHAL_LOG_COLOR_PRINT(W);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0)
#else #else
#define log_w(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_WARN, TAG, format, ##__VA_ARGS__);}while(0) #define log_w(format, ...)
#define isr_log_w(format, ...) do {ets_printf(LOG_FORMAT(W, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0) #define isr_log_w(format, ...)
#define log_buf_w(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_WARN);}while(0)
#endif
#else
#define log_w(format, ...) do {} while(0)
#define isr_log_w(format, ...) do {} while(0)
#define log_buf_w(b,l) do {} while(0)
#endif #endif
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
#ifndef USE_ESP_IDF_LOG
#define log_e(format, ...) log_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__) #define log_e(format, ...) log_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__)
#define isr_log_e(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__) #define isr_log_e(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__)
#define log_buf_e(b,l) do{ARDUHAL_LOG_COLOR_PRINT(E);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0)
#else #else
#define log_e(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_ERROR, TAG, format, ##__VA_ARGS__);}while(0) #define log_e(format, ...)
#define isr_log_e(format, ...) do {ets_printf(LOG_FORMAT(E, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0) #define isr_log_e(format, ...)
#define log_buf_e(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_ERROR);}while(0)
#endif
#else
#define log_e(format, ...) do {} while(0)
#define isr_log_e(format, ...) do {} while(0)
#define log_buf_e(b,l) do {} while(0)
#endif #endif
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_NONE #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_NONE
#ifndef USE_ESP_IDF_LOG
#define log_n(format, ...) log_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__) #define log_n(format, ...) log_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__)
#define isr_log_n(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__) #define isr_log_n(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__)
#define log_buf_n(b,l) do{ARDUHAL_LOG_COLOR_PRINT(E);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0)
#else #else
#define log_n(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_ERROR, TAG, format, ##__VA_ARGS__);}while(0) #define log_n(format, ...)
#define isr_log_n(format, ...) do {ets_printf(LOG_FORMAT(E, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0) #define isr_log_n(format, ...)
#define log_buf_n(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_ERROR);}while(0)
#endif
#else
#define log_n(format, ...) do {} while(0)
#define isr_log_n(format, ...) do {} while(0)
#define log_buf_n(b,l) do {} while(0)
#endif #endif
#include "esp_log.h" #include "esp_log.h"
#ifdef USE_ESP_IDF_LOG
//#ifndef TAG
//#define TAG "ARDUINO"
//#endif
//#define log_n(format, ...) myLog(ESP_LOG_NONE, format, ##__VA_ARGS__)
#else
#ifdef CONFIG_ARDUHAL_ESP_LOG #ifdef CONFIG_ARDUHAL_ESP_LOG
#undef ESP_LOGE #undef ESP_LOGE
#undef ESP_LOGW #undef ESP_LOGW
@ -206,17 +140,16 @@ void log_print_buf(const uint8_t *b, size_t len);
#undef ESP_EARLY_LOGD #undef ESP_EARLY_LOGD
#undef ESP_EARLY_LOGV #undef ESP_EARLY_LOGV
#define ESP_LOGE(tag, format, ...) log_e("[%s] " format, tag, ##__VA_ARGS__) #define ESP_LOGE(tag, ...) log_e(__VA_ARGS__)
#define ESP_LOGW(tag, format, ...) log_w("[%s] " format, tag, ##__VA_ARGS__) #define ESP_LOGW(tag, ...) log_w(__VA_ARGS__)
#define ESP_LOGI(tag, format, ...) log_i("[%s] " format, tag, ##__VA_ARGS__) #define ESP_LOGI(tag, ...) log_i(__VA_ARGS__)
#define ESP_LOGD(tag, format, ...) log_d("[%s] " format, tag, ##__VA_ARGS__) #define ESP_LOGD(tag, ...) log_d(__VA_ARGS__)
#define ESP_LOGV(tag, format, ...) log_v("[%s] " format, tag, ##__VA_ARGS__) #define ESP_LOGV(tag, ...) log_v(__VA_ARGS__)
#define ESP_EARLY_LOGE(tag, format, ...) isr_log_e("[%s] " format, tag, ##__VA_ARGS__) #define ESP_EARLY_LOGE(tag, ...) isr_log_e(__VA_ARGS__)
#define ESP_EARLY_LOGW(tag, format, ...) isr_log_w("[%s] " format, tag, ##__VA_ARGS__) #define ESP_EARLY_LOGW(tag, ...) isr_log_w(__VA_ARGS__)
#define ESP_EARLY_LOGI(tag, format, ...) isr_log_i("[%s] " format, tag, ##__VA_ARGS__) #define ESP_EARLY_LOGI(tag, ...) isr_log_i(__VA_ARGS__)
#define ESP_EARLY_LOGD(tag, format, ...) isr_log_d("[%s] " format, tag, ##__VA_ARGS__) #define ESP_EARLY_LOGD(tag, ...) isr_log_d(__VA_ARGS__)
#define ESP_EARLY_LOGV(tag, format, ...) isr_log_v("[%s] " format, tag, ##__VA_ARGS__) #define ESP_EARLY_LOGV(tag, ...) isr_log_v(__VA_ARGS__)
#endif
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -21,10 +21,6 @@
#include "esp32/rom/gpio.h" #include "esp32/rom/gpio.h"
#elif CONFIG_IDF_TARGET_ESP32S2 #elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/gpio.h" #include "esp32s2/rom/gpio.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/gpio.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/gpio.h"
#else #else
#error Target CONFIG_IDF_TARGET is not supported #error Target CONFIG_IDF_TARGET is not supported
#endif #endif

View File

@ -40,13 +40,6 @@
#include "esp32/rom/rtc.h" #include "esp32/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32S2 #elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/rtc.h" #include "esp32s2/rom/rtc.h"
#include "driver/temp_sensor.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/rtc.h"
#include "driver/temp_sensor.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/rtc.h"
#include "driver/temp_sensor.h"
#else #else
#error Target CONFIG_IDF_TARGET is not supported #error Target CONFIG_IDF_TARGET is not supported
#endif #endif
@ -56,25 +49,12 @@
//Undocumented!!! Get chip temperature in Farenheit //Undocumented!!! Get chip temperature in Farenheit
//Source: https://github.com/pcbreflux/espressif/blob/master/esp32/arduino/sketchbook/ESP32_int_temp_sensor/ESP32_int_temp_sensor.ino //Source: https://github.com/pcbreflux/espressif/blob/master/esp32/arduino/sketchbook/ESP32_int_temp_sensor/ESP32_int_temp_sensor.ino
#ifdef CONFIG_IDF_TARGET_ESP32
uint8_t temprature_sens_read(); uint8_t temprature_sens_read();
float temperatureRead() float temperatureRead()
{ {
return (temprature_sens_read() - 32) / 1.8; return (temprature_sens_read() - 32) / 1.8;
} }
#else
float temperatureRead()
{
float result = NAN;
temp_sensor_config_t tsens = TSENS_CONFIG_DEFAULT();
temp_sensor_set_config(tsens);
temp_sensor_start();
temp_sensor_read_celsius(&result);
temp_sensor_stop();
return result;
}
#endif
void __yield() void __yield()
{ {
@ -180,15 +160,15 @@ void delay(uint32_t ms)
void ARDUINO_ISR_ATTR delayMicroseconds(uint32_t us) void ARDUINO_ISR_ATTR delayMicroseconds(uint32_t us)
{ {
uint64_t m = (uint64_t)esp_timer_get_time(); uint32_t m = micros();
if(us){ if(us){
uint64_t e = (m + us); uint32_t e = (m + us);
if(m > e){ //overflow if(m > e){ //overflow
while((uint64_t)esp_timer_get_time() > e){ while(micros() > e){
NOP(); NOP();
} }
} }
while((uint64_t)esp_timer_get_time() < e){ while(micros() < e){
NOP(); NOP();
} }
} }
@ -200,14 +180,9 @@ void initVariant() {}
void init() __attribute__((weak)); void init() __attribute__((weak));
void init() {} void init() {}
#ifdef CONFIG_APP_ROLLBACK_ENABLE
bool verifyOta() __attribute__((weak)); bool verifyOta() __attribute__((weak));
bool verifyOta() { return true; } bool verifyOta() { return true; }
bool verifyRollbackLater() __attribute__((weak));
bool verifyRollbackLater() { return false; }
#endif
#ifdef CONFIG_BT_ENABLED #ifdef CONFIG_BT_ENABLED
//overwritten in esp32-hal-bt.c //overwritten in esp32-hal-bt.c
bool btInUse() __attribute__((weak)); bool btInUse() __attribute__((weak));
@ -217,7 +192,6 @@ bool btInUse(){ return false; }
void initArduino() void initArduino()
{ {
#ifdef CONFIG_APP_ROLLBACK_ENABLE #ifdef CONFIG_APP_ROLLBACK_ENABLE
if(!verifyRollbackLater()){
const esp_partition_t *running = esp_ota_get_running_partition(); const esp_partition_t *running = esp_ota_get_running_partition();
esp_ota_img_states_t ota_state; esp_ota_img_states_t ota_state;
if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) { if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) {
@ -230,7 +204,6 @@ void initArduino()
} }
} }
} }
}
#endif #endif
//init proper ref tick value for PLL (uncomment if REF_TICK is different than 1MHz) //init proper ref tick value for PLL (uncomment if REF_TICK is different than 1MHz)
//ESP_REG(APB_CTRL_PLL_TICK_CONF_REG) = APB_CLK_FREQ / REF_CLK_FREQ - 1; //ESP_REG(APB_CTRL_PLL_TICK_CONF_REG) = APB_CLK_FREQ / REF_CLK_FREQ - 1;
@ -242,7 +215,7 @@ void initArduino()
#endif #endif
esp_log_level_set("*", CONFIG_LOG_DEFAULT_LEVEL); esp_log_level_set("*", CONFIG_LOG_DEFAULT_LEVEL);
esp_err_t err = nvs_flash_init(); esp_err_t err = nvs_flash_init();
if(err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND){ if(err == ESP_ERR_NVS_NO_FREE_PAGES){
const esp_partition_t* partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL); const esp_partition_t* partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL);
if (partition != NULL) { if (partition != NULL) {
err = esp_partition_erase_range(partition, 0, partition->size); err = esp_partition_erase_range(partition, 0, partition->size);
@ -251,8 +224,6 @@ void initArduino()
} else { } else {
log_e("Failed to format the broken NVS partition!"); log_e("Failed to format the broken NVS partition!");
} }
} else {
log_e("Could not find NVS partition");
} }
} }
if(err) { if(err) {

View File

@ -25,9 +25,6 @@
#elif CONFIG_IDF_TARGET_ESP32S2 #elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/spiram.h" #include "esp32s2/spiram.h"
#include "esp32s2/rom/cache.h" #include "esp32s2/rom/cache.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/spiram.h"
#include "esp32s3/rom/cache.h"
#else #else
#error Target CONFIG_IDF_TARGET is not supported #error Target CONFIG_IDF_TARGET is not supported
#endif #endif
@ -38,13 +35,6 @@
static volatile bool spiramDetected = false; static volatile bool spiramDetected = false;
static volatile bool spiramFailed = false; static volatile bool spiramFailed = false;
//allows user to bypass SPI RAM test routine
__attribute__((weak)) bool testSPIRAM(void)
{
return esp_spiram_test();
}
bool psramInit(){ bool psramInit(){
if (spiramDetected) { if (spiramDetected) {
return true; return true;
@ -70,16 +60,13 @@ bool psramInit(){
spiramFailed = true; spiramFailed = true;
log_w("PSRAM init failed!"); log_w("PSRAM init failed!");
#if CONFIG_IDF_TARGET_ESP32 #if CONFIG_IDF_TARGET_ESP32
if (pkg_ver != EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4) {
pinMatrixOutDetach(16, false, false); pinMatrixOutDetach(16, false, false);
pinMatrixOutDetach(17, false, false); pinMatrixOutDetach(17, false, false);
}
#endif #endif
return false; return false;
} }
esp_spiram_init_cache(); esp_spiram_init_cache();
//testSPIRAM() allows user to bypass SPI RAM test routine if (!esp_spiram_test()) {
if (!testSPIRAM()) {
spiramFailed = true; spiramFailed = true;
log_e("PSRAM test failed!"); log_e("PSRAM test failed!");
return false; return false;
@ -89,12 +76,12 @@ bool psramInit(){
log_e("PSRAM could not be added to the heap!"); log_e("PSRAM could not be added to the heap!");
return false; return false;
} }
#if CONFIG_SPIRAM_USE_MALLOC && !CONFIG_ARDUINO_ISR_IRAM #if CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL && !CONFIG_ARDUINO_ISR_IRAM
heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL); heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL);
#endif #endif
#endif /* CONFIG_SPIRAM_BOOT_INIT */ #endif
log_i("PSRAM enabled");
spiramDetected = true; spiramDetected = true;
log_d("PSRAM enabled");
return true; return true;
} }

File diff suppressed because it is too large Load Diff

View File

@ -25,9 +25,6 @@ extern "C" {
#define RMT_FLAG_ERROR (4) #define RMT_FLAG_ERROR (4)
#define RMT_FLAGS_ALL (RMT_FLAG_TX_DONE | RMT_FLAG_RX_DONE | RMT_FLAG_ERROR) #define RMT_FLAGS_ALL (RMT_FLAG_TX_DONE | RMT_FLAG_RX_DONE | RMT_FLAG_ERROR)
#define RMT_TX_MODE true
#define RMT_RX_MODE false
struct rmt_obj_s; struct rmt_obj_s;
typedef enum { typedef enum {
@ -57,13 +54,6 @@ typedef struct {
}; };
} rmt_data_t; } rmt_data_t;
/**
* Prints object information
*
*/
void _rmtDumpStatus(rmt_obj_t* rmt);
/** /**
* Initialize the object * Initialize the object
* *
@ -79,17 +69,10 @@ float rmtSetTick(rmt_obj_t* rmt, float tick);
/** /**
* Sending data in one-go mode or continual mode * Sending data in one-go mode or continual mode
* (more data being send while updating buffers in interrupts) * (more data being send while updating buffers in interrupts)
* Non-Blocking mode - returns right after executing *
*/ */
bool rmtWrite(rmt_obj_t* rmt, rmt_data_t* data, size_t size); bool rmtWrite(rmt_obj_t* rmt, rmt_data_t* data, size_t size);
/**
* Sending data in one-go mode or continual mode
* (more data being send while updating buffers in interrupts)
* Blocking mode - only returns when data has been sent
*/
bool rmtWriteBlocking(rmt_obj_t* rmt, rmt_data_t* data, size_t size);
/** /**
* Loop data up to the reserved memsize continuously * Loop data up to the reserved memsize continuously
* *

View File

@ -12,14 +12,36 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "esp32-hal.h" #include "esp32-hal.h"
#include "soc/soc_caps.h" #include "freertos/FreeRTOS.h"
#include "driver/sigmadelta.h" #include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp32-hal-matrix.h"
#include "soc/gpio_sd_reg.h"
#include "soc/gpio_sd_struct.h"
static uint8_t duty_set[SOC_SIGMADELTA_CHANNEL_NUM] = {0}; #include "esp_system.h"
static uint32_t prescaler_set[SOC_SIGMADELTA_CHANNEL_NUM] = {0}; #ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
#include "esp32/rom/ets_sys.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/ets_sys.h"
#else
#error Target CONFIG_IDF_TARGET is not supported
#endif
#else // ESP32 Before IDF 4.0
#include "rom/ets_sys.h"
#endif
#if CONFIG_DISABLE_HAL_LOCKS
#define SD_MUTEX_LOCK()
#define SD_MUTEX_UNLOCK()
#else
#define SD_MUTEX_LOCK() do {} while (xSemaphoreTake(_sd_sys_lock, portMAX_DELAY) != pdPASS)
#define SD_MUTEX_UNLOCK() xSemaphoreGive(_sd_sys_lock)
xSemaphoreHandle _sd_sys_lock;
#endif
static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){ static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){
if(old_apb == new_apb){ if(old_apb == new_apb){
@ -27,60 +49,79 @@ static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb
} }
uint32_t iarg = (uint32_t)arg; uint32_t iarg = (uint32_t)arg;
uint8_t channel = iarg; uint8_t channel = iarg;
if(ev_type == APB_AFTER_CHANGE){ if(ev_type == APB_BEFORE_CHANGE){
SIGMADELTA.cg.clk_en = 0;
} else {
old_apb /= 1000000; old_apb /= 1000000;
new_apb /= 1000000; new_apb /= 1000000;
uint32_t old_prescale = prescaler_set[channel] + 1; SD_MUTEX_LOCK();
uint32_t new_prescale = ((new_apb * old_prescale) / old_apb) - 1; uint32_t old_prescale = SIGMADELTA.channel[channel].prescale + 1;
sigmadelta_set_prescale(channel,new_prescale); SIGMADELTA.channel[channel].prescale = ((new_apb * old_prescale) / old_apb) - 1;
prescaler_set[channel] = new_prescale; SIGMADELTA.cg.clk_en = 0;
SIGMADELTA.cg.clk_en = 1;
SD_MUTEX_UNLOCK();
} }
} }
uint32_t sigmaDeltaSetup(uint8_t pin, uint8_t channel, uint32_t freq) //chan 0-x according to SOC, freq 1220-312500 uint32_t sigmaDeltaSetup(uint8_t channel, uint32_t freq) //chan 0-7 freq 1220-312500
{ {
if(channel >= SOC_SIGMADELTA_CHANNEL_NUM){ if(channel > 7) {
return 0; return 0;
} }
#if !CONFIG_DISABLE_HAL_LOCKS
static bool tHasStarted = false;
if(!tHasStarted) {
tHasStarted = true;
_sd_sys_lock = xSemaphoreCreateMutex();
}
#endif
uint32_t apb_freq = getApbFrequency(); uint32_t apb_freq = getApbFrequency();
uint32_t prescale = (apb_freq/(freq*256)) - 1; uint32_t prescale = (apb_freq/(freq*256)) - 1;
if(prescale > 0xFF) { if(prescale > 0xFF) {
prescale = 0xFF; prescale = 0xFF;
} }
SD_MUTEX_LOCK();
sigmadelta_config_t sigmadelta_cfg = { #ifndef CONFIG_IDF_TARGET_ESP32
.channel = channel, SIGMADELTA.misc.function_clk_en = 1;
.sigmadelta_prescale = prescale, #endif
.sigmadelta_duty = 0, SIGMADELTA.channel[channel].prescale = prescale;
.sigmadelta_gpio = pin, SIGMADELTA.cg.clk_en = 0;
}; SIGMADELTA.cg.clk_en = 1;
sigmadelta_config(&sigmadelta_cfg); SD_MUTEX_UNLOCK();
prescaler_set[channel] = prescale;
uint32_t iarg = channel; uint32_t iarg = channel;
addApbChangeCallback((void*)iarg, _on_apb_change); addApbChangeCallback((void*)iarg, _on_apb_change);
return apb_freq/((prescale + 1) * 256); return apb_freq/((prescale + 1) * 256);
} }
void sigmaDeltaWrite(uint8_t channel, uint8_t duty) //chan 0-x according to SOC duty 8 bit void sigmaDeltaWrite(uint8_t channel, uint8_t duty) //chan 0-7 duty 8 bit
{ {
if(channel >= SOC_SIGMADELTA_CHANNEL_NUM){ if(channel > 7) {
return; return;
} }
duty -= 128; duty -= 128;
SD_MUTEX_LOCK();
sigmadelta_set_duty(channel,duty); SIGMADELTA.channel[channel].duty = duty;
duty_set[channel] = duty; SD_MUTEX_UNLOCK();
} }
uint8_t sigmaDeltaRead(uint8_t channel) //chan 0-x according to SOC uint8_t sigmaDeltaRead(uint8_t channel) //chan 0-7
{ {
if(channel >= SOC_SIGMADELTA_CHANNEL_NUM){ if(channel > 7) {
return 0; return 0;
} }
return duty_set[channel]+128; SD_MUTEX_LOCK();
uint8_t duty = SIGMADELTA.channel[channel].duty + 128;
SD_MUTEX_UNLOCK();
return duty;
}
void sigmaDeltaAttachPin(uint8_t pin, uint8_t channel) //channel 0-7
{
if(channel > 7) {
return;
}
pinMode(pin, OUTPUT);
pinMatrixOutAttach(pin, GPIO_SD0_OUT_IDX + channel, false, false);
} }
void sigmaDeltaDetachPin(uint8_t pin) void sigmaDeltaDetachPin(uint8_t pin)

View File

@ -23,9 +23,10 @@ extern "C" {
#include <stdbool.h> #include <stdbool.h>
//channel 0-7 freq 1220-312500 duty 0-255 //channel 0-7 freq 1220-312500 duty 0-255
uint32_t sigmaDeltaSetup(uint8_t pin, uint8_t channel, uint32_t freq); uint32_t sigmaDeltaSetup(uint8_t channel, uint32_t freq);
void sigmaDeltaWrite(uint8_t channel, uint8_t duty); void sigmaDeltaWrite(uint8_t channel, uint8_t duty);
uint8_t sigmaDeltaRead(uint8_t channel); uint8_t sigmaDeltaRead(uint8_t channel);
void sigmaDeltaAttachPin(uint8_t pin, uint8_t channel);
void sigmaDeltaDetachPin(uint8_t pin); void sigmaDeltaDetachPin(uint8_t pin);

View File

@ -22,30 +22,19 @@
#include "soc/spi_struct.h" #include "soc/spi_struct.h"
#include "soc/io_mux_reg.h" #include "soc/io_mux_reg.h"
#include "soc/gpio_sig_map.h" #include "soc/gpio_sig_map.h"
#include "soc/dport_reg.h"
#include "soc/rtc.h" #include "soc/rtc.h"
#include "driver/periph_ctrl.h"
#include "esp_system.h" #include "esp_system.h"
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+ #ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 #if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
#include "soc/dport_reg.h"
#include "esp32/rom/ets_sys.h" #include "esp32/rom/ets_sys.h"
#include "esp32/rom/gpio.h" #include "esp32/rom/gpio.h"
#include "esp_intr_alloc.h" #include "esp_intr_alloc.h"
#elif CONFIG_IDF_TARGET_ESP32S2 #elif CONFIG_IDF_TARGET_ESP32S2
#include "soc/dport_reg.h"
#include "esp32s2/rom/ets_sys.h" #include "esp32s2/rom/ets_sys.h"
#include "esp32s2/rom/gpio.h" #include "esp32s2/rom/gpio.h"
#include "esp_intr_alloc.h" #include "esp_intr_alloc.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "soc/dport_reg.h"
#include "esp32s3/rom/ets_sys.h"
#include "esp32s3/rom/gpio.h"
#include "esp_intr_alloc.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/ets_sys.h"
#include "esp32c3/rom/gpio.h"
#include "esp_intr_alloc.h"
#else #else
#error Target CONFIG_IDF_TARGET is not supported #error Target CONFIG_IDF_TARGET is not supported
#endif #endif
@ -73,31 +62,10 @@ struct spi_struct_t {
#define SPI_SPI_SS_IDX(n) ((n==0)?SPICS0_OUT_IDX:((n==1)?SPICS1_OUT_IDX:0)) #define SPI_SPI_SS_IDX(n) ((n==0)?SPICS0_OUT_IDX:((n==1)?SPICS1_OUT_IDX:0))
#define SPI_HSPI_SS_IDX(n) ((n==0)?SPI3_CS0_OUT_IDX:((n==1)?SPI3_CS1_OUT_IDX:((n==2)?SPI3_CS2_OUT_IDX:SPI3_CS0_OUT_IDX))) #define SPI_HSPI_SS_IDX(n) ((n==0)?SPI3_CS0_OUT_IDX:((n==1)?SPI3_CS1_OUT_IDX:((n==2)?SPI3_CS2_OUT_IDX:SPI3_CS0_OUT_IDX)))
#define SPI_FSPI_SS_IDX(n) ((n==0)?FSPICS0_OUT_IDX:((n==1)?FSPICS1_OUT_IDX:((n==2)?FSPICS2_OUT_IDX:FSPICS0_OUT_IDX))) #define SPI_FSPI_SS_IDX(n) ((n==0)?FSPICS0_OUT_IDX:((n==1)?FSPICS1_OUT_IDX:((n==2)?FSPICS2_OUT_IDX:VSPICS0_OUT_IDX)))
#define SPI_SS_IDX(p, n) ((p==0)?SPI_SPI_SS_IDX(n):((p==1)?SPI_SPI_SS_IDX(n):((p==2)?SPI_HSPI_SS_IDX(n):0))) #define SPI_SS_IDX(p, n) ((p==0)?SPI_SPI_SS_IDX(n):((p==1)?SPI_SPI_SS_IDX(n):((p==2)?SPI_HSPI_SS_IDX(n):0)))
#elif CONFIG_IDF_TARGET_ESP32S3 #define SPI_INTR_SOURCE(u) ((u==0)?ETS_SPI1_INTR_SOURCE:((u==1)?ETS_SPI2_INTR_SOURCE:((u==2)?ETS_SPI3_INTR_SOURCE:0)))
// ESP32S3
#define SPI_COUNT (2)
#define SPI_CLK_IDX(p) ((p==0)?FSPICLK_OUT_IDX:((p==1)?SPI3_CLK_OUT_IDX:0))
#define SPI_MISO_IDX(p) ((p==0)?FSPIQ_OUT_IDX:((p==1)?SPI3_Q_OUT_IDX:0))
#define SPI_MOSI_IDX(p) ((p==0)?FSPID_IN_IDX:((p==1)?SPI3_D_IN_IDX:0))
#define SPI_HSPI_SS_IDX(n) ((n==0)?SPI3_CS0_OUT_IDX:((n==1)?SPI3_CS1_OUT_IDX:0))
#define SPI_FSPI_SS_IDX(n) ((n==0)?FSPICS0_OUT_IDX:((n==1)?FSPICS1_OUT_IDX:0))
#define SPI_SS_IDX(p, n) ((p==0)?SPI_FSPI_SS_IDX(n):((p==1)?SPI_HSPI_SS_IDX(n):0))
#elif CONFIG_IDF_TARGET_ESP32C3
// ESP32C3
#define SPI_COUNT (1)
#define SPI_CLK_IDX(p) FSPICLK_OUT_IDX
#define SPI_MISO_IDX(p) FSPIQ_OUT_IDX
#define SPI_MOSI_IDX(p) FSPID_IN_IDX
#define SPI_SPI_SS_IDX(n) ((n==0)?FSPICS0_OUT_IDX:((n==1)?FSPICS1_OUT_IDX:((n==2)?FSPICS2_OUT_IDX:FSPICS0_OUT_IDX)))
#define SPI_SS_IDX(p, n) SPI_SPI_SS_IDX(n)
#else #else
// ESP32 // ESP32
@ -112,6 +80,8 @@ struct spi_struct_t {
#define SPI_VSPI_SS_IDX(n) ((n==0)?VSPICS0_OUT_IDX:((n==1)?VSPICS1_OUT_IDX:((n==2)?VSPICS2_OUT_IDX:VSPICS0_OUT_IDX))) #define SPI_VSPI_SS_IDX(n) ((n==0)?VSPICS0_OUT_IDX:((n==1)?VSPICS1_OUT_IDX:((n==2)?VSPICS2_OUT_IDX:VSPICS0_OUT_IDX)))
#define SPI_SS_IDX(p, n) ((p==0)?SPI_SPI_SS_IDX(n):((p==1)?SPI_SPI_SS_IDX(n):((p==2)?SPI_HSPI_SS_IDX(n):((p==3)?SPI_VSPI_SS_IDX(n):0)))) #define SPI_SS_IDX(p, n) ((p==0)?SPI_SPI_SS_IDX(n):((p==1)?SPI_SPI_SS_IDX(n):((p==2)?SPI_HSPI_SS_IDX(n):((p==3)?SPI_VSPI_SS_IDX(n):0))))
#define SPI_INTR_SOURCE(u) ((u==0)?ETS_SPI0_INTR_SOURCE:((u==1)?ETS_SPI1_INTR_SOURCE:((u==2)?ETS_SPI2_INTR_SOURCE:((p==3)?ETS_SPI3_INTR_SOURCE:0))))
#endif #endif
#if CONFIG_DISABLE_HAL_LOCKS #if CONFIG_DISABLE_HAL_LOCKS
@ -123,11 +93,6 @@ static spi_t _spi_bus_array[] = {
{(volatile spi_dev_t *)(DR_REG_SPI1_BASE), 0}, {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), 0},
{(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 1}, {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 1},
{(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 2} {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 2}
#elif CONFIG_IDF_TARGET_ESP32S3
{(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 0},
{(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 1}
#elif CONFIG_IDF_TARGET_ESP32C3
{(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 0}
#else #else
{(volatile spi_dev_t *)(DR_REG_SPI0_BASE), 0}, {(volatile spi_dev_t *)(DR_REG_SPI0_BASE), 0},
{(volatile spi_dev_t *)(DR_REG_SPI1_BASE), 1}, {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), 1},
@ -144,11 +109,6 @@ static spi_t _spi_bus_array[] = {
{(volatile spi_dev_t *)(DR_REG_SPI1_BASE), NULL, 0}, {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), NULL, 0},
{(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 1}, {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 1},
{(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 2} {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 2}
#elif CONFIG_IDF_TARGET_ESP32S3
{(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 0},
{(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 1}
#elif CONFIG_IDF_TARGET_ESP32C3
{(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 0}
#else #else
{(volatile spi_dev_t *)(DR_REG_SPI0_BASE), NULL, 0}, {(volatile spi_dev_t *)(DR_REG_SPI0_BASE), NULL, 0},
{(volatile spi_dev_t *)(DR_REG_SPI1_BASE), NULL, 1}, {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), NULL, 1},
@ -171,14 +131,7 @@ void spiAttachSCK(spi_t * spi, int8_t sck)
log_e("HSPI Does not have default pins on ESP32S2!"); log_e("HSPI Does not have default pins on ESP32S2!");
return; return;
} }
#elif CONFIG_IDF_TARGET_ESP32S3 #else
if(spi->num == FSPI) {
sck = 12;
} else {
log_e("HSPI Does not have default pins on ESP32S3!");
return;
}
#elif CONFIG_IDF_TARGET_ESP32
if(spi->num == HSPI) { if(spi->num == HSPI) {
sck = 14; sck = 14;
} else if(spi->num == VSPI) { } else if(spi->num == VSPI) {
@ -186,9 +139,6 @@ void spiAttachSCK(spi_t * spi, int8_t sck)
} else { } else {
sck = 6; sck = 6;
} }
#elif CONFIG_IDF_TARGET_ESP32C3
log_e("SPI Does not have default pins on ESP32C3!");
return;
#endif #endif
} }
pinMode(sck, OUTPUT); pinMode(sck, OUTPUT);
@ -208,14 +158,7 @@ void spiAttachMISO(spi_t * spi, int8_t miso)
log_e("HSPI Does not have default pins on ESP32S2!"); log_e("HSPI Does not have default pins on ESP32S2!");
return; return;
} }
#elif CONFIG_IDF_TARGET_ESP32S3 #else
if(spi->num == FSPI) {
miso = 13;
} else {
log_e("HSPI Does not have default pins on ESP32S3!");
return;
}
#elif CONFIG_IDF_TARGET_ESP32
if(spi->num == HSPI) { if(spi->num == HSPI) {
miso = 12; miso = 12;
} else if(spi->num == VSPI) { } else if(spi->num == VSPI) {
@ -223,9 +166,6 @@ void spiAttachMISO(spi_t * spi, int8_t miso)
} else { } else {
miso = 7; miso = 7;
} }
#elif CONFIG_IDF_TARGET_ESP32C3
log_e("SPI Does not have default pins on ESP32C3!");
return;
#endif #endif
} }
SPI_MUTEX_LOCK(); SPI_MUTEX_LOCK();
@ -240,21 +180,14 @@ void spiAttachMOSI(spi_t * spi, int8_t mosi)
return; return;
} }
if(mosi < 0) { if(mosi < 0) {
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 #if CONFIG_IDF_TARGET_ESP32S2
if(spi->num == FSPI) { if(spi->num == FSPI) {
mosi = 35; mosi = 35;
} else { } else {
log_e("HSPI Does not have default pins on ESP32S2!"); log_e("HSPI Does not have default pins on ESP32S2!");
return; return;
} }
#elif CONFIG_IDF_TARGET_ESP32S3 #else
if(spi->num == FSPI) {
mosi = 11;
} else {
log_e("HSPI Does not have default pins on ESP32S3!");
return;
}
#elif CONFIG_IDF_TARGET_ESP32
if(spi->num == HSPI) { if(spi->num == HSPI) {
mosi = 13; mosi = 13;
} else if(spi->num == VSPI) { } else if(spi->num == VSPI) {
@ -262,9 +195,6 @@ void spiAttachMOSI(spi_t * spi, int8_t mosi)
} else { } else {
mosi = 8; mosi = 8;
} }
#elif CONFIG_IDF_TARGET_ESP32C3
log_e("SPI Does not have default pins on ESP32C3!");
return;
#endif #endif
} }
pinMode(mosi, OUTPUT); pinMode(mosi, OUTPUT);
@ -277,21 +207,14 @@ void spiDetachSCK(spi_t * spi, int8_t sck)
return; return;
} }
if(sck < 0) { if(sck < 0) {
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 #if CONFIG_IDF_TARGET_ESP32S2
if(spi->num == FSPI) { if(spi->num == FSPI) {
sck = 36; sck = 36;
} else { } else {
log_e("HSPI Does not have default pins on ESP32S2!"); log_e("HSPI Does not have default pins on ESP32S2!");
return; return;
} }
#elif CONFIG_IDF_TARGET_ESP32S3 #else
if(spi->num == FSPI) {
sck = 12;
} else {
log_e("HSPI Does not have default pins on ESP32S3!");
return;
}
#elif CONFIG_IDF_TARGET_ESP32
if(spi->num == HSPI) { if(spi->num == HSPI) {
sck = 14; sck = 14;
} else if(spi->num == VSPI) { } else if(spi->num == VSPI) {
@ -299,9 +222,6 @@ void spiDetachSCK(spi_t * spi, int8_t sck)
} else { } else {
sck = 6; sck = 6;
} }
#elif CONFIG_IDF_TARGET_ESP32C3
log_e("SPI Does not have default pins on ESP32C3!");
return;
#endif #endif
} }
pinMatrixOutDetach(sck, false, false); pinMatrixOutDetach(sck, false, false);
@ -314,21 +234,14 @@ void spiDetachMISO(spi_t * spi, int8_t miso)
return; return;
} }
if(miso < 0) { if(miso < 0) {
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 #if CONFIG_IDF_TARGET_ESP32S2
if(spi->num == FSPI) { if(spi->num == FSPI) {
miso = 37; miso = 37;
} else { } else {
log_e("HSPI Does not have default pins on ESP32S2!"); log_e("HSPI Does not have default pins on ESP32S2!");
return; return;
} }
#elif CONFIG_IDF_TARGET_ESP32S3 #else
if(spi->num == FSPI) {
miso = 13;
} else {
log_e("HSPI Does not have default pins on ESP32S3!");
return;
}
#elif CONFIG_IDF_TARGET_ESP32
if(spi->num == HSPI) { if(spi->num == HSPI) {
miso = 12; miso = 12;
} else if(spi->num == VSPI) { } else if(spi->num == VSPI) {
@ -336,9 +249,6 @@ void spiDetachMISO(spi_t * spi, int8_t miso)
} else { } else {
miso = 7; miso = 7;
} }
#elif CONFIG_IDF_TARGET_ESP32C3
log_e("SPI Does not have default pins on ESP32C3!");
return;
#endif #endif
} }
pinMatrixInDetach(SPI_MISO_IDX(spi->num), false, false); pinMatrixInDetach(SPI_MISO_IDX(spi->num), false, false);
@ -351,21 +261,14 @@ void spiDetachMOSI(spi_t * spi, int8_t mosi)
return; return;
} }
if(mosi < 0) { if(mosi < 0) {
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 #if CONFIG_IDF_TARGET_ESP32S2
if(spi->num == FSPI) { if(spi->num == FSPI) {
mosi = 35; mosi = 35;
} else { } else {
log_e("HSPI Does not have default pins on ESP32S2!"); log_e("HSPI Does not have default pins on ESP32S2!");
return; return;
} }
#elif CONFIG_IDF_TARGET_ESP32S3 #else
if(spi->num == FSPI) {
mosi = 11;
} else {
log_e("HSPI Does not have default pins on ESP32S3!");
return;
}
#elif CONFIG_IDF_TARGET_ESP32
if(spi->num == HSPI) { if(spi->num == HSPI) {
mosi = 13; mosi = 13;
} else if(spi->num == VSPI) { } else if(spi->num == VSPI) {
@ -373,9 +276,6 @@ void spiDetachMOSI(spi_t * spi, int8_t mosi)
} else { } else {
mosi = 8; mosi = 8;
} }
#elif CONFIG_IDF_TARGET_ESP32C3
log_e("SPI Does not have default pins on ESP32C3!");
return;
#endif #endif
} }
pinMatrixOutDetach(mosi, false, false); pinMatrixOutDetach(mosi, false, false);
@ -399,14 +299,7 @@ void spiAttachSS(spi_t * spi, uint8_t cs_num, int8_t ss)
log_e("HSPI Does not have default pins on ESP32S2!"); log_e("HSPI Does not have default pins on ESP32S2!");
return; return;
} }
#elif CONFIG_IDF_TARGET_ESP32S3 #else
if(spi->num == FSPI) {
ss = 10;
} else {
log_e("HSPI Does not have default pins on ESP32S3!");
return;
}
#elif CONFIG_IDF_TARGET_ESP32
if(spi->num == HSPI) { if(spi->num == HSPI) {
ss = 15; ss = 15;
} else if(spi->num == VSPI) { } else if(spi->num == VSPI) {
@ -414,9 +307,6 @@ void spiAttachSS(spi_t * spi, uint8_t cs_num, int8_t ss)
} else { } else {
ss = 11; ss = 11;
} }
#elif CONFIG_IDF_TARGET_ESP32C3
log_e("SPI Does not have default pins on ESP32C3!");
return;
#endif #endif
} }
pinMode(ss, OUTPUT); pinMode(ss, OUTPUT);
@ -437,14 +327,7 @@ void spiDetachSS(spi_t * spi, int8_t ss)
log_e("HSPI Does not have default pins on ESP32S2!"); log_e("HSPI Does not have default pins on ESP32S2!");
return; return;
} }
#elif CONFIG_IDF_TARGET_ESP32S3 #else
if(spi->num == FSPI) {
ss = 10;
} else {
log_e("HSPI Does not have default pins on ESP32S3!");
return;
}
#elif CONFIG_IDF_TARGET_ESP32
if(spi->num == HSPI) { if(spi->num == HSPI) {
ss = 15; ss = 15;
} else if(spi->num == VSPI) { } else if(spi->num == VSPI) {
@ -452,9 +335,6 @@ void spiDetachSS(spi_t * spi, int8_t ss)
} else { } else {
ss = 11; ss = 11;
} }
#elif CONFIG_IDF_TARGET_ESP32C3
log_e("SPI Does not have default pins on ESP32C3!");
return;
#endif #endif
} }
pinMatrixOutDetach(ss, false, false); pinMatrixOutDetach(ss, false, false);
@ -467,7 +347,7 @@ void spiEnableSSPins(spi_t * spi, uint8_t cs_mask)
return; return;
} }
SPI_MUTEX_LOCK(); SPI_MUTEX_LOCK();
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 #if CONFIG_IDF_TARGET_ESP32S2
spi->dev->misc.val &= ~(cs_mask & SPI_CS_MASK_ALL); spi->dev->misc.val &= ~(cs_mask & SPI_CS_MASK_ALL);
#else #else
spi->dev->pin.val &= ~(cs_mask & SPI_CS_MASK_ALL); spi->dev->pin.val &= ~(cs_mask & SPI_CS_MASK_ALL);
@ -481,7 +361,7 @@ void spiDisableSSPins(spi_t * spi, uint8_t cs_mask)
return; return;
} }
SPI_MUTEX_LOCK(); SPI_MUTEX_LOCK();
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 #if CONFIG_IDF_TARGET_ESP32S2
spi->dev->misc.val |= (cs_mask & SPI_CS_MASK_ALL); spi->dev->misc.val |= (cs_mask & SPI_CS_MASK_ALL);
#else #else
spi->dev->pin.val |= (cs_mask & SPI_CS_MASK_ALL); spi->dev->pin.val |= (cs_mask & SPI_CS_MASK_ALL);
@ -517,7 +397,7 @@ void spiSSSet(spi_t * spi)
return; return;
} }
SPI_MUTEX_LOCK(); SPI_MUTEX_LOCK();
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 #if CONFIG_IDF_TARGET_ESP32S2
spi->dev->misc.cs_keep_active = 1; spi->dev->misc.cs_keep_active = 1;
#else #else
spi->dev->pin.cs_keep_active = 1; spi->dev->pin.cs_keep_active = 1;
@ -531,7 +411,7 @@ void spiSSClear(spi_t * spi)
return; return;
} }
SPI_MUTEX_LOCK(); SPI_MUTEX_LOCK();
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 #if CONFIG_IDF_TARGET_ESP32S2
spi->dev->misc.cs_keep_active = 0; spi->dev->misc.cs_keep_active = 0;
#else #else
spi->dev->pin.cs_keep_active = 0; spi->dev->pin.cs_keep_active = 0;
@ -562,7 +442,7 @@ uint8_t spiGetDataMode(spi_t * spi)
if(!spi) { if(!spi) {
return 0; return 0;
} }
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 #if CONFIG_IDF_TARGET_ESP32S2
bool idleEdge = spi->dev->misc.ck_idle_edge; bool idleEdge = spi->dev->misc.ck_idle_edge;
#else #else
bool idleEdge = spi->dev->pin.ck_idle_edge; bool idleEdge = spi->dev->pin.ck_idle_edge;
@ -588,7 +468,7 @@ void spiSetDataMode(spi_t * spi, uint8_t dataMode)
SPI_MUTEX_LOCK(); SPI_MUTEX_LOCK();
switch (dataMode) { switch (dataMode) {
case SPI_MODE1: case SPI_MODE1:
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 #if CONFIG_IDF_TARGET_ESP32S2
spi->dev->misc.ck_idle_edge = 0; spi->dev->misc.ck_idle_edge = 0;
#else #else
spi->dev->pin.ck_idle_edge = 0; spi->dev->pin.ck_idle_edge = 0;
@ -596,7 +476,7 @@ void spiSetDataMode(spi_t * spi, uint8_t dataMode)
spi->dev->user.ck_out_edge = 1; spi->dev->user.ck_out_edge = 1;
break; break;
case SPI_MODE2: case SPI_MODE2:
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 #if CONFIG_IDF_TARGET_ESP32S2
spi->dev->misc.ck_idle_edge = 1; spi->dev->misc.ck_idle_edge = 1;
#else #else
spi->dev->pin.ck_idle_edge = 1; spi->dev->pin.ck_idle_edge = 1;
@ -604,7 +484,7 @@ void spiSetDataMode(spi_t * spi, uint8_t dataMode)
spi->dev->user.ck_out_edge = 1; spi->dev->user.ck_out_edge = 1;
break; break;
case SPI_MODE3: case SPI_MODE3:
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 #if CONFIG_IDF_TARGET_ESP32S2
spi->dev->misc.ck_idle_edge = 1; spi->dev->misc.ck_idle_edge = 1;
#else #else
spi->dev->pin.ck_idle_edge = 1; spi->dev->pin.ck_idle_edge = 1;
@ -613,7 +493,7 @@ void spiSetDataMode(spi_t * spi, uint8_t dataMode)
break; break;
case SPI_MODE0: case SPI_MODE0:
default: default:
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 #if CONFIG_IDF_TARGET_ESP32S2
spi->dev->misc.ck_idle_edge = 0; spi->dev->misc.ck_idle_edge = 0;
#else #else
spi->dev->pin.ck_idle_edge = 0; spi->dev->pin.ck_idle_edge = 0;
@ -662,11 +542,9 @@ static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb
static void spiInitBus(spi_t * spi) static void spiInitBus(spi_t * spi)
{ {
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32
spi->dev->slave.trans_done = 0; spi->dev->slave.trans_done = 0;
#endif spi->dev->slave.slave_mode = 0;
spi->dev->slave.val = 0; #if CONFIG_IDF_TARGET_ESP32S2
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3
spi->dev->misc.val = 0; spi->dev->misc.val = 0;
#else #else
spi->dev->pin.val = 0; spi->dev->pin.val = 0;
@ -674,15 +552,8 @@ static void spiInitBus(spi_t * spi)
spi->dev->user.val = 0; spi->dev->user.val = 0;
spi->dev->user1.val = 0; spi->dev->user1.val = 0;
spi->dev->ctrl.val = 0; spi->dev->ctrl.val = 0;
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32
spi->dev->ctrl1.val = 0; spi->dev->ctrl1.val = 0;
spi->dev->ctrl2.val = 0; spi->dev->ctrl2.val = 0;
#else
spi->dev->clk_gate.val = 0;
spi->dev->dma_conf.val = 0;
spi->dev->dma_conf.rx_afifo_rst = 1;
spi->dev->dma_conf.buf_afifo_rst = 1;
#endif
spi->dev->clock.val = 0; spi->dev->clock.val = 0;
} }
@ -727,15 +598,7 @@ spi_t * spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI01_CLK_EN); DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI01_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI01_RST); DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI01_RST);
} }
#elif CONFIG_IDF_TARGET_ESP32S3 #else
if(spi_num == FSPI) {
periph_module_reset( PERIPH_SPI2_MODULE );
periph_module_enable( PERIPH_SPI2_MODULE );
} else if(spi_num == HSPI) {
periph_module_reset( PERIPH_SPI3_MODULE );
periph_module_enable( PERIPH_SPI3_MODULE );
}
#elif CONFIG_IDF_TARGET_ESP32
if(spi_num == HSPI) { if(spi_num == HSPI) {
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI2_CLK_EN); DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI2_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI2_RST); DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI2_RST);
@ -746,24 +609,14 @@ spi_t * spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI01_CLK_EN); DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI01_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI01_RST); DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI01_RST);
} }
#elif CONFIG_IDF_TARGET_ESP32C3
periph_module_reset( PERIPH_SPI2_MODULE );
periph_module_enable( PERIPH_SPI2_MODULE );
#endif #endif
SPI_MUTEX_LOCK(); SPI_MUTEX_LOCK();
spiInitBus(spi); spiInitBus(spi);
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
spi->dev->clk_gate.clk_en = 1;
spi->dev->clk_gate.mst_clk_sel = 1;
spi->dev->clk_gate.mst_clk_active = 1;
spi->dev->dma_conf.tx_seg_trans_clr_en = 1;
spi->dev->dma_conf.rx_seg_trans_clr_en = 1;
spi->dev->dma_conf.dma_seg_trans_en = 0;
#endif
spi->dev->user.usr_mosi = 1; spi->dev->user.usr_mosi = 1;
spi->dev->user.usr_miso = 1; spi->dev->user.usr_miso = 1;
spi->dev->user.doutdin = 1; spi->dev->user.doutdin = 1;
int i; int i;
for(i=0; i<16; i++) { for(i=0; i<16; i++) {
spi->dev->data_buf[i] = 0x00000000; spi->dev->data_buf[i] = 0x00000000;
@ -775,7 +628,6 @@ spi_t * spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_
spiSetClockDiv(spi, clockDiv); spiSetClockDiv(spi, clockDiv);
addApbChangeCallback(spi, _on_apb_change); addApbChangeCallback(spi, _on_apb_change);
return spi; return spi;
} }
@ -790,11 +642,6 @@ void spiWaitReady(spi_t * spi)
#if CONFIG_IDF_TARGET_ESP32S2 #if CONFIG_IDF_TARGET_ESP32S2
#define usr_mosi_dbitlen usr_mosi_bit_len #define usr_mosi_dbitlen usr_mosi_bit_len
#define usr_miso_dbitlen usr_miso_bit_len #define usr_miso_dbitlen usr_miso_bit_len
#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
#define usr_mosi_dbitlen ms_data_bitlen
#define usr_miso_dbitlen ms_data_bitlen
#define mosi_dlen ms_dlen
#define miso_dlen ms_dlen
#endif #endif
void spiWrite(spi_t * spi, const uint32_t *data, uint8_t len) void spiWrite(spi_t * spi, const uint32_t *data, uint8_t len)
@ -808,16 +655,10 @@ void spiWrite(spi_t * spi, const uint32_t *data, uint8_t len)
} }
SPI_MUTEX_LOCK(); SPI_MUTEX_LOCK();
spi->dev->mosi_dlen.usr_mosi_dbitlen = (len * 32) - 1; spi->dev->mosi_dlen.usr_mosi_dbitlen = (len * 32) - 1;
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32
spi->dev->miso_dlen.usr_miso_dbitlen = 0; spi->dev->miso_dlen.usr_miso_dbitlen = 0;
#endif
for(i=0; i<len; i++) { for(i=0; i<len; i++) {
spi->dev->data_buf[i] = data[i]; spi->dev->data_buf[i] = data[i];
} }
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1; spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr); while(spi->dev->cmd.usr);
SPI_MUTEX_UNLOCK(); SPI_MUTEX_UNLOCK();
@ -838,10 +679,6 @@ void spiTransfer(spi_t * spi, uint32_t *data, uint8_t len)
for(i=0; i<len; i++) { for(i=0; i<len; i++) {
spi->dev->data_buf[i] = data[i]; spi->dev->data_buf[i] = data[i];
} }
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1; spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr); while(spi->dev->cmd.usr);
for(i=0; i<len; i++) { for(i=0; i<len; i++) {
@ -857,14 +694,8 @@ void spiWriteByte(spi_t * spi, uint8_t data)
} }
SPI_MUTEX_LOCK(); SPI_MUTEX_LOCK();
spi->dev->mosi_dlen.usr_mosi_dbitlen = 7; spi->dev->mosi_dlen.usr_mosi_dbitlen = 7;
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32
spi->dev->miso_dlen.usr_miso_dbitlen = 0; spi->dev->miso_dlen.usr_miso_dbitlen = 0;
#endif
spi->dev->data_buf[0] = data; spi->dev->data_buf[0] = data;
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1; spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr); while(spi->dev->cmd.usr);
SPI_MUTEX_UNLOCK(); SPI_MUTEX_UNLOCK();
@ -879,10 +710,6 @@ uint8_t spiTransferByte(spi_t * spi, uint8_t data)
spi->dev->mosi_dlen.usr_mosi_dbitlen = 7; spi->dev->mosi_dlen.usr_mosi_dbitlen = 7;
spi->dev->miso_dlen.usr_miso_dbitlen = 7; spi->dev->miso_dlen.usr_miso_dbitlen = 7;
spi->dev->data_buf[0] = data; spi->dev->data_buf[0] = data;
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1; spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr); while(spi->dev->cmd.usr);
data = spi->dev->data_buf[0] & 0xFF; data = spi->dev->data_buf[0] & 0xFF;
@ -910,14 +737,8 @@ void spiWriteWord(spi_t * spi, uint16_t data)
} }
SPI_MUTEX_LOCK(); SPI_MUTEX_LOCK();
spi->dev->mosi_dlen.usr_mosi_dbitlen = 15; spi->dev->mosi_dlen.usr_mosi_dbitlen = 15;
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32
spi->dev->miso_dlen.usr_miso_dbitlen = 0; spi->dev->miso_dlen.usr_miso_dbitlen = 0;
#endif
spi->dev->data_buf[0] = data; spi->dev->data_buf[0] = data;
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1; spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr); while(spi->dev->cmd.usr);
SPI_MUTEX_UNLOCK(); SPI_MUTEX_UNLOCK();
@ -935,10 +756,6 @@ uint16_t spiTransferWord(spi_t * spi, uint16_t data)
spi->dev->mosi_dlen.usr_mosi_dbitlen = 15; spi->dev->mosi_dlen.usr_mosi_dbitlen = 15;
spi->dev->miso_dlen.usr_miso_dbitlen = 15; spi->dev->miso_dlen.usr_miso_dbitlen = 15;
spi->dev->data_buf[0] = data; spi->dev->data_buf[0] = data;
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1; spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr); while(spi->dev->cmd.usr);
data = spi->dev->data_buf[0]; data = spi->dev->data_buf[0];
@ -959,14 +776,8 @@ void spiWriteLong(spi_t * spi, uint32_t data)
} }
SPI_MUTEX_LOCK(); SPI_MUTEX_LOCK();
spi->dev->mosi_dlen.usr_mosi_dbitlen = 31; spi->dev->mosi_dlen.usr_mosi_dbitlen = 31;
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32
spi->dev->miso_dlen.usr_miso_dbitlen = 0; spi->dev->miso_dlen.usr_miso_dbitlen = 0;
#endif
spi->dev->data_buf[0] = data; spi->dev->data_buf[0] = data;
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1; spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr); while(spi->dev->cmd.usr);
SPI_MUTEX_UNLOCK(); SPI_MUTEX_UNLOCK();
@ -984,10 +795,6 @@ uint32_t spiTransferLong(spi_t * spi, uint32_t data)
spi->dev->mosi_dlen.usr_mosi_dbitlen = 31; spi->dev->mosi_dlen.usr_mosi_dbitlen = 31;
spi->dev->miso_dlen.usr_miso_dbitlen = 31; spi->dev->miso_dlen.usr_miso_dbitlen = 31;
spi->dev->data_buf[0] = data; spi->dev->data_buf[0] = data;
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1; spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr); while(spi->dev->cmd.usr);
data = spi->dev->data_buf[0]; data = spi->dev->data_buf[0];
@ -1027,10 +834,6 @@ static void __spiTransferBytes(spi_t * spi, const uint8_t * data, uint8_t * out,
spi->dev->data_buf[i] = wordsBuf[i]; //copy buffer to spi fifo spi->dev->data_buf[i] = wordsBuf[i]; //copy buffer to spi fifo
} }
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1; spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr); while(spi->dev->cmd.usr);
@ -1095,7 +898,7 @@ void spiTransaction(spi_t * spi, uint32_t clockDiv, uint8_t dataMode, uint8_t bi
spi->dev->clock.val = clockDiv; spi->dev->clock.val = clockDiv;
switch (dataMode) { switch (dataMode) {
case SPI_MODE1: case SPI_MODE1:
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 #if CONFIG_IDF_TARGET_ESP32S2
spi->dev->misc.ck_idle_edge = 0; spi->dev->misc.ck_idle_edge = 0;
#else #else
spi->dev->pin.ck_idle_edge = 0; spi->dev->pin.ck_idle_edge = 0;
@ -1103,7 +906,7 @@ void spiTransaction(spi_t * spi, uint32_t clockDiv, uint8_t dataMode, uint8_t bi
spi->dev->user.ck_out_edge = 1; spi->dev->user.ck_out_edge = 1;
break; break;
case SPI_MODE2: case SPI_MODE2:
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 #if CONFIG_IDF_TARGET_ESP32S2
spi->dev->misc.ck_idle_edge = 1; spi->dev->misc.ck_idle_edge = 1;
#else #else
spi->dev->pin.ck_idle_edge = 1; spi->dev->pin.ck_idle_edge = 1;
@ -1111,7 +914,7 @@ void spiTransaction(spi_t * spi, uint32_t clockDiv, uint8_t dataMode, uint8_t bi
spi->dev->user.ck_out_edge = 1; spi->dev->user.ck_out_edge = 1;
break; break;
case SPI_MODE3: case SPI_MODE3:
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 #if CONFIG_IDF_TARGET_ESP32S2
spi->dev->misc.ck_idle_edge = 1; spi->dev->misc.ck_idle_edge = 1;
#else #else
spi->dev->pin.ck_idle_edge = 1; spi->dev->pin.ck_idle_edge = 1;
@ -1120,7 +923,7 @@ void spiTransaction(spi_t * spi, uint32_t clockDiv, uint8_t dataMode, uint8_t bi
break; break;
case SPI_MODE0: case SPI_MODE0:
default: default:
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 #if CONFIG_IDF_TARGET_ESP32S2
spi->dev->misc.ck_idle_edge = 0; spi->dev->misc.ck_idle_edge = 0;
#else #else
spi->dev->pin.ck_idle_edge = 0; spi->dev->pin.ck_idle_edge = 0;
@ -1159,14 +962,8 @@ void ARDUINO_ISR_ATTR spiWriteByteNL(spi_t * spi, uint8_t data)
return; return;
} }
spi->dev->mosi_dlen.usr_mosi_dbitlen = 7; spi->dev->mosi_dlen.usr_mosi_dbitlen = 7;
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32
spi->dev->miso_dlen.usr_miso_dbitlen = 0; spi->dev->miso_dlen.usr_miso_dbitlen = 0;
#endif
spi->dev->data_buf[0] = data; spi->dev->data_buf[0] = data;
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1; spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr); while(spi->dev->cmd.usr);
} }
@ -1179,10 +976,6 @@ uint8_t spiTransferByteNL(spi_t * spi, uint8_t data)
spi->dev->mosi_dlen.usr_mosi_dbitlen = 7; spi->dev->mosi_dlen.usr_mosi_dbitlen = 7;
spi->dev->miso_dlen.usr_miso_dbitlen = 7; spi->dev->miso_dlen.usr_miso_dbitlen = 7;
spi->dev->data_buf[0] = data; spi->dev->data_buf[0] = data;
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1; spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr); while(spi->dev->cmd.usr);
data = spi->dev->data_buf[0] & 0xFF; data = spi->dev->data_buf[0] & 0xFF;
@ -1198,14 +991,8 @@ void ARDUINO_ISR_ATTR spiWriteShortNL(spi_t * spi, uint16_t data)
MSB_16_SET(data, data); MSB_16_SET(data, data);
} }
spi->dev->mosi_dlen.usr_mosi_dbitlen = 15; spi->dev->mosi_dlen.usr_mosi_dbitlen = 15;
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32
spi->dev->miso_dlen.usr_miso_dbitlen = 0; spi->dev->miso_dlen.usr_miso_dbitlen = 0;
#endif
spi->dev->data_buf[0] = data; spi->dev->data_buf[0] = data;
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1; spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr); while(spi->dev->cmd.usr);
} }
@ -1221,10 +1008,6 @@ uint16_t spiTransferShortNL(spi_t * spi, uint16_t data)
spi->dev->mosi_dlen.usr_mosi_dbitlen = 15; spi->dev->mosi_dlen.usr_mosi_dbitlen = 15;
spi->dev->miso_dlen.usr_miso_dbitlen = 15; spi->dev->miso_dlen.usr_miso_dbitlen = 15;
spi->dev->data_buf[0] = data; spi->dev->data_buf[0] = data;
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1; spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr); while(spi->dev->cmd.usr);
data = spi->dev->data_buf[0] & 0xFFFF; data = spi->dev->data_buf[0] & 0xFFFF;
@ -1243,14 +1026,8 @@ void ARDUINO_ISR_ATTR spiWriteLongNL(spi_t * spi, uint32_t data)
MSB_32_SET(data, data); MSB_32_SET(data, data);
} }
spi->dev->mosi_dlen.usr_mosi_dbitlen = 31; spi->dev->mosi_dlen.usr_mosi_dbitlen = 31;
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32
spi->dev->miso_dlen.usr_miso_dbitlen = 0; spi->dev->miso_dlen.usr_miso_dbitlen = 0;
#endif
spi->dev->data_buf[0] = data; spi->dev->data_buf[0] = data;
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1; spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr); while(spi->dev->cmd.usr);
} }
@ -1266,10 +1043,6 @@ uint32_t spiTransferLongNL(spi_t * spi, uint32_t data)
spi->dev->mosi_dlen.usr_mosi_dbitlen = 31; spi->dev->mosi_dlen.usr_mosi_dbitlen = 31;
spi->dev->miso_dlen.usr_miso_dbitlen = 31; spi->dev->miso_dlen.usr_miso_dbitlen = 31;
spi->dev->data_buf[0] = data; spi->dev->data_buf[0] = data;
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1; spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr); while(spi->dev->cmd.usr);
data = spi->dev->data_buf[0]; data = spi->dev->data_buf[0];
@ -1280,9 +1053,6 @@ uint32_t spiTransferLongNL(spi_t * spi, uint32_t data)
} }
void spiWriteNL(spi_t * spi, const void * data_in, uint32_t len){ void spiWriteNL(spi_t * spi, const void * data_in, uint32_t len){
if(!spi) {
return;
}
size_t longs = len >> 2; size_t longs = len >> 2;
if(len & 3){ if(len & 3){
longs++; longs++;
@ -1295,16 +1065,10 @@ void spiWriteNL(spi_t * spi, const void * data_in, uint32_t len){
c_longs = (longs > 16)?16:longs; c_longs = (longs > 16)?16:longs;
spi->dev->mosi_dlen.usr_mosi_dbitlen = (c_len*8)-1; spi->dev->mosi_dlen.usr_mosi_dbitlen = (c_len*8)-1;
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32
spi->dev->miso_dlen.usr_miso_dbitlen = 0; spi->dev->miso_dlen.usr_miso_dbitlen = 0;
#endif
for (int i=0; i<c_longs; i++) { for (int i=0; i<c_longs; i++) {
spi->dev->data_buf[i] = data[i]; spi->dev->data_buf[i] = data[i];
} }
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1; spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr); while(spi->dev->cmd.usr);
@ -1341,29 +1105,13 @@ void spiTransferBytesNL(spi_t * spi, const void * data_in, uint8_t * data_out, u
spi->dev->data_buf[i] = 0xFFFFFFFF; spi->dev->data_buf[i] = 0xFFFFFFFF;
} }
} }
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1; spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr); while(spi->dev->cmd.usr);
if(result){ if(result){
if(c_len & 3){
for (int i=0; i<(c_longs-1); i++) {
result[i] = spi->dev->data_buf[i];
}
uint32_t last_data = spi->dev->data_buf[c_longs-1];
uint8_t * last_out8 = (uint8_t *)&result[c_longs-1];
uint8_t * last_data8 = (uint8_t *)&last_data;
for (int i=0; i<(c_len & 3); i++) {
last_out8[i] = last_data8[i];
}
} else {
for (int i=0; i<c_longs; i++) { for (int i=0; i<c_longs; i++) {
result[i] = spi->dev->data_buf[i]; result[i] = spi->dev->data_buf[i];
} }
} }
}
if(data){ if(data){
data += c_longs; data += c_longs;
} }
@ -1400,10 +1148,6 @@ void spiTransferBitsNL(spi_t * spi, uint32_t data, uint32_t * out, uint8_t bits)
spi->dev->mosi_dlen.usr_mosi_dbitlen = (bits - 1); spi->dev->mosi_dlen.usr_mosi_dbitlen = (bits - 1);
spi->dev->miso_dlen.usr_miso_dbitlen = (bits - 1); spi->dev->miso_dlen.usr_miso_dbitlen = (bits - 1);
spi->dev->data_buf[0] = data; spi->dev->data_buf[0] = data;
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1; spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr); while(spi->dev->cmd.usr);
data = spi->dev->data_buf[0]; data = spi->dev->data_buf[0];
@ -1436,9 +1180,7 @@ void ARDUINO_ISR_ATTR spiWritePixelsNL(spi_t * spi, const void * data_in, uint32
l_bytes = (c_len & 3); l_bytes = (c_len & 3);
spi->dev->mosi_dlen.usr_mosi_dbitlen = (c_len*8)-1; spi->dev->mosi_dlen.usr_mosi_dbitlen = (c_len*8)-1;
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32
spi->dev->miso_dlen.usr_miso_dbitlen = 0; spi->dev->miso_dlen.usr_miso_dbitlen = 0;
#endif
for (int i=0; i<c_longs; i++) { for (int i=0; i<c_longs; i++) {
if(msb){ if(msb){
if(l_bytes && i == (c_longs - 1)){ if(l_bytes && i == (c_longs - 1)){
@ -1454,10 +1196,6 @@ void ARDUINO_ISR_ATTR spiWritePixelsNL(spi_t * spi, const void * data_in, uint32
spi->dev->data_buf[i] = data[i]; spi->dev->data_buf[i] = data[i];
} }
} }
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1; spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr); while(spi->dev->cmd.usr);
@ -1480,12 +1218,7 @@ typedef union {
uint32_t clkcnt_l: 6; /*it must be equal to spi_clkcnt_N.*/ uint32_t clkcnt_l: 6; /*it must be equal to spi_clkcnt_N.*/
uint32_t clkcnt_h: 6; /*it must be floor((spi_clkcnt_N+1)/2-1).*/ uint32_t clkcnt_h: 6; /*it must be floor((spi_clkcnt_N+1)/2-1).*/
uint32_t clkcnt_n: 6; /*it is the divider of spi_clk. So spi_clk frequency is system/(spi_clkdiv_pre+1)/(spi_clkcnt_N+1)*/ uint32_t clkcnt_n: 6; /*it is the divider of spi_clk. So spi_clk frequency is system/(spi_clkdiv_pre+1)/(spi_clkcnt_N+1)*/
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
uint32_t clkdiv_pre: 4; /*it is pre-divider of spi_clk.*/
uint32_t reserved: 9; /*reserved*/
#else
uint32_t clkdiv_pre: 13; /*it is pre-divider of spi_clk.*/ uint32_t clkdiv_pre: 13; /*it is pre-divider of spi_clk.*/
#endif
uint32_t clk_equ_sysclk: 1; /*1: spi_clk is eqaul to system 0: spi_clk is divided from system clock.*/ uint32_t clk_equ_sysclk: 1; /*1: spi_clk is eqaul to system 0: spi_clk is divided from system clock.*/
}; };
} spiClk_t; } spiClk_t;
@ -1527,13 +1260,8 @@ uint32_t spiFrequencyToClockDiv(uint32_t freq)
while(calPreVari++ <= 1) { while(calPreVari++ <= 1) {
calPre = (((apb_freq / (reg.clkcnt_n + 1)) / freq) - 1) + calPreVari; calPre = (((apb_freq / (reg.clkcnt_n + 1)) / freq) - 1) + calPreVari;
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
if(calPre > 0xF) {
reg.clkdiv_pre = 0xF;
#else
if(calPre > 0x1FFF) { if(calPre > 0x1FFF) {
reg.clkdiv_pre = 0x1FFF; reg.clkdiv_pre = 0x1FFF;
#endif
} else if(calPre <= 0) { } else if(calPre <= 0) {
reg.clkdiv_pre = 0; reg.clkdiv_pre = 0;
} else { } else {
@ -1558,3 +1286,4 @@ uint32_t spiFrequencyToClockDiv(uint32_t freq)
} }
return bestReg.value; return bestReg.value;
} }

View File

@ -25,16 +25,11 @@ extern "C" {
#define SPI_HAS_TRANSACTION #define SPI_HAS_TRANSACTION
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
#define FSPI 0
#define HSPI 1
#else
#define FSPI 1 //SPI bus attached to the flash (can use the same data lines but different SS) #define FSPI 1 //SPI bus attached to the flash (can use the same data lines but different SS)
#define HSPI 2 //SPI bus normally mapped to pins 12 - 15, but can be matrixed to any pins #define HSPI 2 //SPI bus normally mapped to pins 12 - 15, but can be matrixed to any pins
#if CONFIG_IDF_TARGET_ESP32 #if CONFIG_IDF_TARGET_ESP32
#define VSPI 3 //SPI bus normally attached to pins 5, 18, 19 and 23, but can be matrixed to any pins #define VSPI 3 //SPI bus normally attached to pins 5, 18, 19 and 23, but can be matrixed to any pins
#endif #endif
#endif
// This defines are not representing the real Divider of the ESP32 // This defines are not representing the real Divider of the ESP32
// the Defines match to an AVR Arduino on 16MHz for better compatibility // the Defines match to an AVR Arduino on 16MHz for better compatibility

View File

@ -13,10 +13,36 @@
// limitations under the License. // limitations under the License.
#include "esp32-hal-timer.h" #include "esp32-hal-timer.h"
#include "driver/timer.h" #include "freertos/FreeRTOS.h"
#include "soc/soc_caps.h" #include "freertos/xtensa_api.h"
#include "freertos/task.h"
#include "soc/timer_group_struct.h"
#include "soc/dport_reg.h"
#include "esp_attr.h"
#include "driver/periph_ctrl.h"
typedef union { #include "esp_system.h"
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
#include "esp32/rom/ets_sys.h"
#include "esp_intr_alloc.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/ets_sys.h"
#include "esp_intr_alloc.h"
#include "soc/periph_defs.h"
#else
#error Target CONFIG_IDF_TARGET is not supported
#endif
#else // ESP32 Before IDF 4.0
#include "rom/ets_sys.h"
#include "esp_intr.h"
#endif
#define HWTIMER_LOCK() portENTER_CRITICAL(timer->lock)
#define HWTIMER_UNLOCK() portEXIT_CRITICAL(timer->lock)
typedef struct {
union {
struct { struct {
uint32_t reserved0: 10; uint32_t reserved0: 10;
uint32_t alarm_en: 1; /*When set alarm is enabled*/ uint32_t alarm_en: 1; /*When set alarm is enabled*/
@ -28,208 +54,283 @@ typedef union {
uint32_t enable: 1; /*When set timer 0/1 time-base counter is enabled*/ uint32_t enable: 1; /*When set timer 0/1 time-base counter is enabled*/
}; };
uint32_t val; uint32_t val;
} timer_cfg_t; } config;
uint32_t cnt_low; /*Register to store timer 0/1 time-base counter current value lower 32 bits.*/
uint32_t cnt_high; /*Register to store timer 0 time-base counter current value higher 32 bits.*/
uint32_t update; /*Write any value will trigger a timer 0 time-base counter value update (timer 0 current value will be stored in registers above)*/
uint32_t alarm_low; /*Timer 0 time-base counter value lower 32 bits that will trigger the alarm*/
uint32_t alarm_high; /*Timer 0 time-base counter value higher 32 bits that will trigger the alarm*/
uint32_t load_low; /*Lower 32 bits of the value that will load into timer 0 time-base counter*/
uint32_t load_high; /*higher 32 bits of the value that will load into timer 0 time-base counter*/
uint32_t reload; /*Write any value will trigger timer 0 time-base counter reload*/
} hw_timer_reg_t;
#define NUM_OF_TIMERS SOC_TIMER_GROUP_TOTAL_TIMERS typedef struct hw_timer_s {
hw_timer_reg_t * dev;
typedef struct hw_timer_s
{
uint8_t group;
uint8_t num; uint8_t num;
uint8_t group;
uint8_t timer;
portMUX_TYPE lock;
} hw_timer_t; } hw_timer_t;
// Works for all chips static hw_timer_t hw_timer[4] = {
static hw_timer_t timer_dev[4] = { {(hw_timer_reg_t *)(DR_REG_TIMERGROUP0_BASE),0,0,0,portMUX_INITIALIZER_UNLOCKED},
{0,0}, {1,0}, {0,1}, {1,1} {(hw_timer_reg_t *)(DR_REG_TIMERGROUP0_BASE + 0x0024),1,0,1,portMUX_INITIALIZER_UNLOCKED},
{(hw_timer_reg_t *)(DR_REG_TIMERGROUP0_BASE + 0x1000),2,1,0,portMUX_INITIALIZER_UNLOCKED},
{(hw_timer_reg_t *)(DR_REG_TIMERGROUP0_BASE + 0x1024),3,1,1,portMUX_INITIALIZER_UNLOCKED}
}; };
// NOTE: (in IDF 5.0 there wont be need to know groups/numbers typedef void (*voidFuncPtr)(void);
// timer_init() will list thru all timers and return free timer handle) static voidFuncPtr __timerInterruptHandlers[4] = {0,0,0,0};
void ARDUINO_ISR_ATTR __timerISR(void * arg){
#if CONFIG_IDF_TARGET_ESP32
uint32_t s0 = TIMERG0.int_st_timers.val;
uint32_t s1 = TIMERG1.int_st_timers.val;
TIMERG0.int_clr_timers.val = s0;
TIMERG1.int_clr_timers.val = s1;
#else
uint32_t s0 = TIMERG0.int_st.val;
uint32_t s1 = TIMERG1.int_st.val;
TIMERG0.int_clr.val = s0;
TIMERG1.int_clr.val = s1;
#endif
uint8_t status = (s1 & 3) << 2 | (s0 & 3);
uint8_t i = 4;
//restart the timers that should autoreload
while(i--){
hw_timer_reg_t * dev = hw_timer[i].dev;
if((status & (1 << i)) && dev->config.autoreload){
dev->config.alarm_en = 1;
}
}
i = 4;
//call callbacks
while(i--){
if(__timerInterruptHandlers[i] && (status & (1 << i))){
__timerInterruptHandlers[i]();
}
}
}
uint64_t inline timerRead(hw_timer_t *timer){ uint64_t timerRead(hw_timer_t *timer){
timer->dev->update = 1;
uint64_t value; uint64_t h = timer->dev->cnt_high;
timer_get_counter_value(timer->group, timer->num,&value); uint64_t l = timer->dev->cnt_low;
return value; return (h << 32) | l;
} }
uint64_t timerAlarmRead(hw_timer_t *timer){ uint64_t timerAlarmRead(hw_timer_t *timer){
uint64_t value; uint64_t h = timer->dev->alarm_high;
timer_get_alarm_value(timer->group, timer->num, &value); uint64_t l = timer->dev->alarm_low;
return value; return (h << 32) | l;
} }
void timerWrite(hw_timer_t *timer, uint64_t val){ void timerWrite(hw_timer_t *timer, uint64_t val){
timer_set_counter_value(timer->group, timer->num, val); timer->dev->load_high = (uint32_t) (val >> 32);
timer->dev->load_low = (uint32_t) (val);
timer->dev->reload = 1;
} }
void timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload){ void timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload){
timer_set_alarm_value(timer->group, timer->num, alarm_value); timer->dev->alarm_high = (uint32_t) (alarm_value >> 32);
timerSetAutoReload(timer,autoreload); timer->dev->alarm_low = (uint32_t) alarm_value;
timer->dev->config.autoreload = autoreload;
} }
void timerSetConfig(hw_timer_t *timer, uint32_t config){ void timerSetConfig(hw_timer_t *timer, uint32_t config){
timer_cfg_t cfg; timer->dev->config.val = config;
cfg.val = config;
timer_set_alarm(timer->group, timer->num, cfg.alarm_en);
timerSetDivider(timer,cfg.divider);
timerSetAutoReload(timer,cfg.autoreload);
timerSetCountUp(timer, cfg.increase);
if (cfg.enable) {
timerStart(timer);
}
else{
timerStop(timer);
}
return;
} }
uint32_t timerGetConfig(hw_timer_t *timer){ uint32_t timerGetConfig(hw_timer_t *timer){
timer_config_t timer_cfg; return timer->dev->config.val;
timer_get_config(timer->group, timer->num,&timer_cfg);
//Translate to default uint32_t
timer_cfg_t cfg;
cfg.alarm_en = timer_cfg.alarm_en;
cfg.autoreload = timer_cfg.auto_reload;
cfg.divider = timer_cfg.divider;
cfg.edge_int_en = timer_cfg.intr_type;
cfg.level_int_en = !timer_cfg.intr_type;
cfg.enable = timer_cfg.counter_en;
cfg.increase = timer_cfg.counter_dir;
return cfg.val;
} }
void timerSetCountUp(hw_timer_t *timer, bool countUp){ void timerSetCountUp(hw_timer_t *timer, bool countUp){
timer_set_counter_mode(timer->group, timer->num,countUp); timer->dev->config.increase = countUp;
} }
bool timerGetCountUp(hw_timer_t *timer){ bool timerGetCountUp(hw_timer_t *timer){
timer_cfg_t config; return timer->dev->config.increase;
config.val = timerGetConfig(timer);
return config.increase;
} }
void timerSetAutoReload(hw_timer_t *timer, bool autoreload){ void timerSetAutoReload(hw_timer_t *timer, bool autoreload){
timer_set_auto_reload(timer->group, timer->num,autoreload); timer->dev->config.autoreload = autoreload;
} }
bool timerGetAutoReload(hw_timer_t *timer){ bool timerGetAutoReload(hw_timer_t *timer){
timer_cfg_t config; return timer->dev->config.autoreload;
config.val= timerGetConfig(timer);
return config.autoreload;
} }
// Set divider from 2 to 65535 void timerSetDivider(hw_timer_t *timer, uint16_t divider){//2 to 65536
void timerSetDivider(hw_timer_t *timer, uint16_t divider){ if(!divider){
if(divider < 2) divider = 0xFFFF;
{ } else if(divider == 1){
log_e("Timer divider must be set in range of 2 to 65535"); divider = 2;
return;
} }
timer_set_divider(timer->group, timer->num,divider); int timer_en = timer->dev->config.enable;
timer->dev->config.enable = 0;
timer->dev->config.divider = divider;
timer->dev->config.enable = timer_en;
} }
uint16_t timerGetDivider(hw_timer_t *timer){ uint16_t timerGetDivider(hw_timer_t *timer){
timer_cfg_t config; return timer->dev->config.divider;
config.val = timerGetConfig(timer);
return config.divider;
} }
void timerStart(hw_timer_t *timer){ void timerStart(hw_timer_t *timer){
timer_start(timer->group, timer->num); timer->dev->config.enable = 1;
} }
void timerStop(hw_timer_t *timer){ void timerStop(hw_timer_t *timer){
timer_pause(timer->group, timer->num); timer->dev->config.enable = 0;
} }
void timerRestart(hw_timer_t *timer){ void timerRestart(hw_timer_t *timer){
timerWrite(timer,0); timer->dev->config.enable = 0;
timer->dev->reload = 1;
timer->dev->config.enable = 1;
} }
bool timerStarted(hw_timer_t *timer){ bool timerStarted(hw_timer_t *timer){
timer_cfg_t config; return timer->dev->config.enable;
config.val = timerGetConfig(timer);
return config.enable;
} }
void timerAlarmEnable(hw_timer_t *timer){ void timerAlarmEnable(hw_timer_t *timer){
timer_set_alarm(timer->group, timer->num,true); timer->dev->config.alarm_en = 1;
} }
void timerAlarmDisable(hw_timer_t *timer){ void timerAlarmDisable(hw_timer_t *timer){
timer_set_alarm(timer->group, timer->num,false); timer->dev->config.alarm_en = 0;
} }
bool timerAlarmEnabled(hw_timer_t *timer){ bool timerAlarmEnabled(hw_timer_t *timer){
timer_cfg_t config; return timer->dev->config.alarm_en;
config.val = timerGetConfig(timer);
return config.alarm_en;
} }
static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){ static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){
hw_timer_t * timer = (hw_timer_t *)arg; hw_timer_t * timer = (hw_timer_t *)arg;
if(ev_type == APB_BEFORE_CHANGE){ if(ev_type == APB_BEFORE_CHANGE){
timerStop(timer); timer->dev->config.enable = 0;
} else { } else {
old_apb /= 1000000; old_apb /= 1000000;
new_apb /= 1000000; new_apb /= 1000000;
uint16_t divider = (new_apb * timerGetDivider(timer)) / old_apb; timer->dev->config.divider = (new_apb * timer->dev->config.divider) / old_apb;
timerSetDivider(timer,divider); timer->dev->config.enable = 1;
timerStart(timer);
} }
} }
hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp){ hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp){
if(num >= NUM_OF_TIMERS) if(num > 3){
{
log_e("Timer number %u exceeds available number of Timers.", num);
return NULL; return NULL;
} }
hw_timer_t * timer = &hw_timer[num];
hw_timer_t * timer = &timer_dev[num]; //Get Timer group/num from 0-3 number if(timer->group) {
periph_module_enable(PERIPH_TIMG1_MODULE);
timer_config_t config = { } else {
.divider = divider, periph_module_enable(PERIPH_TIMG0_MODULE);
.counter_dir = countUp, }
.counter_en = TIMER_PAUSE, timer->dev->config.enable = 0;
.alarm_en = TIMER_ALARM_DIS, if(timer->group) {
.auto_reload = false, TIMERG1.int_ena.val &= ~BIT(timer->timer);
}; #if CONFIG_IDF_TARGET_ESP32
TIMERG1.int_clr_timers.val |= BIT(timer->timer);
timer_init(timer->group, timer->num, &config); #else
timer_set_counter_value(timer->group, timer->num, 0); TIMERG1.int_clr.val = BIT(timer->timer);
timerStart(timer); #endif
} else {
TIMERG0.int_ena.val &= ~BIT(timer->timer);
#if CONFIG_IDF_TARGET_ESP32
TIMERG0.int_clr_timers.val |= BIT(timer->timer);
#else
TIMERG0.int_clr.val = BIT(timer->timer);
#endif
}
#ifdef TIMER_GROUP_SUPPORTS_XTAL_CLOCK
timer->dev->config.use_xtal = 0;
#endif
timerSetDivider(timer, divider);
timerSetCountUp(timer, countUp);
timerSetAutoReload(timer, false);
timerAttachInterrupt(timer, NULL, false);
timerWrite(timer, 0);
timer->dev->config.enable = 1;
addApbChangeCallback(timer, _on_apb_change); addApbChangeCallback(timer, _on_apb_change);
return timer; return timer;
} }
void timerEnd(hw_timer_t *timer){ void timerEnd(hw_timer_t *timer){
timer->dev->config.enable = 0;
timerAttachInterrupt(timer, NULL, false);
removeApbChangeCallback(timer, _on_apb_change); removeApbChangeCallback(timer, _on_apb_change);
timer_deinit(timer->group, timer->num);
}
bool IRAM_ATTR timerFnWrapper(void *arg){
void (*fn)(void) = arg;
fn();
// some additional logic or handling may be required here to approriately yield or not
return false;
} }
void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){ void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){
if(edge){ // EDGE DOES NOT WORK CURRENTLY
log_w("EDGE timer interrupt is not supported! Setting to LEVEL..."); edge = false;
static bool initialized = false;
static intr_handle_t intr_handle = NULL;
if(intr_handle){
esp_intr_disable(intr_handle);
}
if(fn == NULL){
timer->dev->config.level_int_en = 0;
timer->dev->config.edge_int_en = 0;
timer->dev->config.alarm_en = 0;
if(timer->num & 2){
TIMERG1.int_ena.val &= ~BIT(timer->timer);
#if CONFIG_IDF_TARGET_ESP32
TIMERG1.int_clr_timers.val |= BIT(timer->timer);
#else
TIMERG1.int_clr.val = BIT(timer->timer);
#endif
} else {
TIMERG0.int_ena.val &= ~BIT(timer->timer);
#if CONFIG_IDF_TARGET_ESP32
TIMERG0.int_clr_timers.val |= BIT(timer->timer);
#else
TIMERG0.int_clr.val = BIT(timer->timer);
#endif
}
__timerInterruptHandlers[timer->num] = NULL;
} else {
__timerInterruptHandlers[timer->num] = fn;
timer->dev->config.level_int_en = edge?0:1;//When set, an alarm will generate a level type interrupt.
timer->dev->config.edge_int_en = edge?1:0;//When set, an alarm will generate an edge type interrupt.
int intr_source = 0;
if(!edge){
if(timer->group){
intr_source = ETS_TG1_T0_LEVEL_INTR_SOURCE + timer->timer;
} else {
intr_source = ETS_TG0_T0_LEVEL_INTR_SOURCE + timer->timer;
}
} else {
if(timer->group){
intr_source = ETS_TG1_T0_EDGE_INTR_SOURCE + timer->timer;
} else {
intr_source = ETS_TG0_T0_EDGE_INTR_SOURCE + timer->timer;
}
}
if(!initialized){
initialized = true;
esp_intr_alloc(intr_source, (int)(ARDUINO_ISR_FLAG|ESP_INTR_FLAG_LOWMED), __timerISR, NULL, &intr_handle);
} else {
intr_matrix_set(esp_intr_get_cpu(intr_handle), intr_source, esp_intr_get_intno(intr_handle));
}
if(timer->group){
TIMERG1.int_ena.val |= BIT(timer->timer);
} else {
TIMERG0.int_ena.val |= BIT(timer->timer);
}
}
if(intr_handle){
esp_intr_enable(intr_handle);
} }
timer_isr_callback_add(timer->group, timer->num, timerFnWrapper, fn, 0);
} }
void timerDetachInterrupt(hw_timer_t *timer){ void timerDetachInterrupt(hw_timer_t *timer){
timer_isr_callback_remove(timer->group, timer->num); timerAttachInterrupt(timer, NULL, false);
} }
uint64_t timerReadMicros(hw_timer_t *timer){ uint64_t timerReadMicros(hw_timer_t *timer){
@ -238,12 +339,6 @@ uint64_t timerReadMicros(hw_timer_t *timer){
return timer_val * div / (getApbFrequency() / 1000000); return timer_val * div / (getApbFrequency() / 1000000);
} }
uint64_t timerReadMilis(hw_timer_t *timer){
uint64_t timer_val = timerRead(timer);
uint16_t div = timerGetDivider(timer);
return timer_val * div / (getApbFrequency() / 1000);
}
double timerReadSeconds(hw_timer_t *timer){ double timerReadSeconds(hw_timer_t *timer){
uint64_t timer_val = timerRead(timer); uint64_t timer_val = timerRead(timer);
uint16_t div = timerGetDivider(timer); uint16_t div = timerGetDivider(timer);
@ -256,12 +351,6 @@ uint64_t timerAlarmReadMicros(hw_timer_t *timer){
return timer_val * div / (getApbFrequency() / 1000000); return timer_val * div / (getApbFrequency() / 1000000);
} }
uint64_t timerAlarmReadMilis(hw_timer_t *timer){
uint64_t timer_val = timerAlarmRead(timer);
uint16_t div = timerGetDivider(timer);
return timer_val * div / (getApbFrequency() / 1000);
}
double timerAlarmReadSeconds(hw_timer_t *timer){ double timerAlarmReadSeconds(hw_timer_t *timer){
uint64_t timer_val = timerAlarmRead(timer); uint64_t timer_val = timerAlarmRead(timer);
uint16_t div = timerGetDivider(timer); uint16_t div = timerGetDivider(timer);

View File

@ -20,13 +20,13 @@
#ifndef MAIN_ESP32_HAL_TIMER_H_ #ifndef MAIN_ESP32_HAL_TIMER_H_
#define MAIN_ESP32_HAL_TIMER_H_ #define MAIN_ESP32_HAL_TIMER_H_
#include "esp32-hal.h"
#include "freertos/FreeRTOS.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#include "esp32-hal.h"
#include "freertos/FreeRTOS.h"
struct hw_timer_s; struct hw_timer_s;
typedef struct hw_timer_s hw_timer_t; typedef struct hw_timer_s hw_timer_t;
@ -50,7 +50,6 @@ void timerSetAutoReload(hw_timer_t *timer, bool autoreload);
bool timerStarted(hw_timer_t *timer); bool timerStarted(hw_timer_t *timer);
uint64_t timerRead(hw_timer_t *timer); uint64_t timerRead(hw_timer_t *timer);
uint64_t timerReadMicros(hw_timer_t *timer); uint64_t timerReadMicros(hw_timer_t *timer);
uint64_t timerReadMilis(hw_timer_t *timer);
double timerReadSeconds(hw_timer_t *timer); double timerReadSeconds(hw_timer_t *timer);
uint16_t timerGetDivider(hw_timer_t *timer); uint16_t timerGetDivider(hw_timer_t *timer);
bool timerGetCountUp(hw_timer_t *timer); bool timerGetCountUp(hw_timer_t *timer);
@ -58,7 +57,7 @@ bool timerGetAutoReload(hw_timer_t *timer);
void timerAlarmEnable(hw_timer_t *timer); void timerAlarmEnable(hw_timer_t *timer);
void timerAlarmDisable(hw_timer_t *timer); void timerAlarmDisable(hw_timer_t *timer);
void timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload); void timerAlarmWrite(hw_timer_t *timer, uint64_t interruptAt, bool autoreload);
bool timerAlarmEnabled(hw_timer_t *timer); bool timerAlarmEnabled(hw_timer_t *timer);
uint64_t timerAlarmRead(hw_timer_t *timer); uint64_t timerAlarmRead(hw_timer_t *timer);

View File

@ -1,8 +1,7 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#if CONFIG_TINYUSB_ENABLED #if CONFIG_USB_ENABLED
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h>
#include "esp_log.h" #include "esp_log.h"
@ -13,14 +12,10 @@
#include "soc/usb_reg.h" #include "soc/usb_reg.h"
#include "soc/usb_wrap_reg.h" #include "soc/usb_wrap_reg.h"
#include "soc/usb_wrap_struct.h" #include "soc/usb_wrap_struct.h"
#include "soc/usb_periph.h"
#include "soc/periph_defs.h" #include "soc/periph_defs.h"
#include "soc/timer_group_struct.h" #include "soc/timer_group_struct.h"
#include "soc/system_reg.h" #include "soc/system_reg.h"
#include "hal/usb_hal.h"
#include "hal/gpio_ll.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
@ -29,76 +24,14 @@
#include "esp_efuse.h" #include "esp_efuse.h"
#include "esp_efuse_table.h" #include "esp_efuse_table.h"
#include "esp_rom_gpio.h"
#include "tinyusb.h"
#include "esp32-hal.h" #include "esp32-hal.h"
#include "esp32-hal-tinyusb.h" #include "esp32-hal-tinyusb.h"
#if CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/usb/usb_persist.h" #include "esp32s2/rom/usb/usb_persist.h"
#include "esp32s2/rom/usb/usb_dc.h" #include "esp32s2/rom/usb/usb_dc.h"
#include "esp32s2/rom/usb/chip_usb_dw_wrapper.h" #include "esp32s2/rom/usb/chip_usb_dw_wrapper.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "hal/usb_serial_jtag_ll.h"
#include "esp32s3/rom/usb/usb_persist.h"
#include "esp32s3/rom/usb/usb_dc.h"
#include "esp32s3/rom/usb/chip_usb_dw_wrapper.h"
#endif
typedef enum{
TINYUSB_USBDEV_0,
} tinyusb_usbdev_t;
typedef char *tusb_desc_strarray_device_t[USB_STRING_DESCRIPTOR_ARRAY_SIZE];
typedef struct {
bool external_phy;
} tinyusb_config_t;
static void configure_pins(usb_hal_context_t *usb)
{
for (const usb_iopin_dsc_t *iopin = usb_periph_iopins; iopin->pin != -1; ++iopin) {
if ((usb->use_external_phy) || (iopin->ext_phy_only == 0)) {
esp_rom_gpio_pad_select_gpio(iopin->pin);
if (iopin->is_output) {
esp_rom_gpio_connect_out_signal(iopin->pin, iopin->func, false, false);
} else {
esp_rom_gpio_connect_in_signal(iopin->pin, iopin->func, false);
if ((iopin->pin != GPIO_FUNC_IN_LOW) && (iopin->pin != GPIO_FUNC_IN_HIGH)) {
gpio_ll_input_enable(&GPIO, iopin->pin);
}
}
esp_rom_gpio_pad_unhold(iopin->pin);
}
}
if (!usb->use_external_phy) {
gpio_set_drive_capability(USBPHY_DM_NUM, GPIO_DRIVE_CAP_3);
gpio_set_drive_capability(USBPHY_DP_NUM, GPIO_DRIVE_CAP_3);
}
}
esp_err_t tinyusb_driver_install(const tinyusb_config_t *config)
{
usb_hal_context_t hal = {
.use_external_phy = config->external_phy
};
usb_hal_init(&hal);
configure_pins(&hal);
if (!tusb_init()) {
log_e("Can't initialize the TinyUSB stack.");
return ESP_FAIL;
}
return ESP_OK;
}
typedef char tusb_str_t[127]; typedef char tusb_str_t[127];
@ -108,7 +41,6 @@ static tusb_str_t WEBUSB_URL = "";
static tusb_str_t USB_DEVICE_PRODUCT = ""; static tusb_str_t USB_DEVICE_PRODUCT = "";
static tusb_str_t USB_DEVICE_MANUFACTURER = ""; static tusb_str_t USB_DEVICE_MANUFACTURER = "";
static tusb_str_t USB_DEVICE_SERIAL = ""; static tusb_str_t USB_DEVICE_SERIAL = "";
static tusb_str_t USB_DEVICE_LANGUAGE = "\x09\x04";//English (0x0409)
static uint8_t USB_DEVICE_ATTRIBUTES = 0; static uint8_t USB_DEVICE_ATTRIBUTES = 0;
static uint16_t USB_DEVICE_POWER = 0; static uint16_t USB_DEVICE_POWER = 0;
@ -143,7 +75,7 @@ static tusb_desc_device_t tinyusb_device_descriptor = {
static uint32_t tinyusb_string_descriptor_len = 4; static uint32_t tinyusb_string_descriptor_len = 4;
static char * tinyusb_string_descriptor[MAX_STRING_DESCRIPTORS] = { static char * tinyusb_string_descriptor[MAX_STRING_DESCRIPTORS] = {
// array of pointer to string descriptors // array of pointer to string descriptors
USB_DEVICE_LANGUAGE, // 0: is supported language "\x09\x04", // 0: is supported language is English (0x0409)
USB_DEVICE_MANUFACTURER,// 1: Manufacturer USB_DEVICE_MANUFACTURER,// 1: Manufacturer
USB_DEVICE_PRODUCT, // 2: Product USB_DEVICE_PRODUCT, // 2: Product
USB_DEVICE_SERIAL, // 3: Serials, should use chip ID USB_DEVICE_SERIAL, // 3: Serials, should use chip ID
@ -231,7 +163,7 @@ typedef struct TU_ATTR_PACKED {
static tinyusb_desc_webusb_url_t tinyusb_url_descriptor = { static tinyusb_desc_webusb_url_t tinyusb_url_descriptor = {
.bLength = 3, .bLength = 3,
.bDescriptorType = 3, // WEBUSB URL type .bDescriptorType = 3, // WEBUSB URL type
.bScheme = 255, // URL Scheme Prefix: 0: "http://", 1: "https://", 255: "" .bScheme = 1, // URL Scheme Prefix: 0: "http://", 1: "https://", 255: ""
.url = "" .url = ""
}; };
@ -266,7 +198,7 @@ static tinyusb_endpoints_usage_t tinyusb_endpoints;
/** /**
* @brief Invoked when received GET CONFIGURATION DESCRIPTOR. * @brief Invoked when received GET CONFIGURATION DESCRIPTOR.
*/ */
__attribute__ ((weak)) uint8_t const *tud_descriptor_configuration_cb(uint8_t index) uint8_t const *tud_descriptor_configuration_cb(uint8_t index)
{ {
//log_d("%u", index); //log_d("%u", index);
return tinyusb_config_descriptor; return tinyusb_config_descriptor;
@ -275,7 +207,7 @@ __attribute__ ((weak)) uint8_t const *tud_descriptor_configuration_cb(uint8_t in
/** /**
* @brief Invoked when received GET DEVICE DESCRIPTOR. * @brief Invoked when received GET DEVICE DESCRIPTOR.
*/ */
__attribute__ ((weak)) uint8_t const *tud_descriptor_device_cb(void) uint8_t const *tud_descriptor_device_cb(void)
{ {
//log_d(""); //log_d("");
return (uint8_t const *)&tinyusb_device_descriptor; return (uint8_t const *)&tinyusb_device_descriptor;
@ -284,7 +216,7 @@ __attribute__ ((weak)) uint8_t const *tud_descriptor_device_cb(void)
/** /**
* @brief Invoked when received GET STRING DESCRIPTOR request. * @brief Invoked when received GET STRING DESCRIPTOR request.
*/ */
__attribute__ ((weak)) uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid)
{ {
//log_d("%u (0x%x)", index, langid); //log_d("%u (0x%x)", index, langid);
static uint16_t _desc_str[127]; static uint16_t _desc_str[127];
@ -320,21 +252,20 @@ __attribute__ ((weak)) uint16_t const *tud_descriptor_string_cb(uint8_t index, u
*/ */
uint8_t const * tud_descriptor_bos_cb(void) uint8_t const * tud_descriptor_bos_cb(void)
{ {
//log_v(""); //log_d("");
return tinyusb_bos_descriptor; return tinyusb_bos_descriptor;
} }
__attribute__ ((weak)) bool tinyusb_vendor_control_request_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request){ return false; } __attribute__ ((weak)) bool tinyusb_vendor_control_request_cb(uint8_t rhport, tusb_control_request_t const * request){ return false; }
__attribute__ ((weak)) bool tinyusb_vendor_control_complete_cb(uint8_t rhport, tusb_control_request_t const * request){ return true; }
/** /**
* @brief Handle WebUSB and Vendor requests. * @brief Handle WebUSB and Vendor requests.
*/ */
bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) bool tud_vendor_control_request_cb(uint8_t rhport, tusb_control_request_t const * request)
{ {
if(WEBUSB_ENABLED && (request->bRequest == VENDOR_REQUEST_WEBUSB if(WEBUSB_ENABLED && (request->bRequest == VENDOR_REQUEST_WEBUSB
|| (request->bRequest == VENDOR_REQUEST_MICROSOFT && request->wIndex == 7))){ || (request->bRequest == VENDOR_REQUEST_MICROSOFT && request->wIndex == 7))){
// we only care for SETUP stage
if (stage == CONTROL_STAGE_SETUP) {
if(request->bRequest == VENDOR_REQUEST_WEBUSB){ if(request->bRequest == VENDOR_REQUEST_WEBUSB){
// match vendor request in BOS descriptor // match vendor request in BOS descriptor
// Get landing page url // Get landing page url
@ -347,19 +278,25 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ
memcpy(&total_len, tinyusb_ms_os_20_descriptor + 8, 2); memcpy(&total_len, tinyusb_ms_os_20_descriptor + 8, 2);
return tud_control_xfer(rhport, request, (void*) tinyusb_ms_os_20_descriptor, total_len); return tud_control_xfer(rhport, request, (void*) tinyusb_ms_os_20_descriptor, total_len);
} }
return true; return tinyusb_vendor_control_request_cb(rhport, request);
}
bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_request_t const * request)
{
if(!WEBUSB_ENABLED || !(request->bRequest == VENDOR_REQUEST_WEBUSB
|| (request->bRequest == VENDOR_REQUEST_MICROSOFT && request->wIndex == 7))){
return tinyusb_vendor_control_complete_cb(rhport, request);
} }
log_v("rhport: %u, stage: %u, type: 0x%x, request: 0x%x", rhport, stage, request->bmRequestType_bit.type, request->bRequest); return true;
return tinyusb_vendor_control_request_cb(rhport, stage, request);
} }
/* /*
* Required Callbacks * Required Callbacks
* */ * */
#if CFG_TUD_HID #if CFG_TUD_HID
__attribute__ ((weak)) const uint8_t * tud_hid_descriptor_report_cb(uint8_t itf){return NULL;} __attribute__ ((weak)) const uint8_t * tud_hid_descriptor_report_cb(void){return NULL;}
__attribute__ ((weak)) uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen){return 0;} __attribute__ ((weak)) uint16_t tud_hid_get_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen){return 0;}
__attribute__ ((weak)) void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, const uint8_t * buffer, uint16_t bufsize){} __attribute__ ((weak)) void tud_hid_set_report_cb(uint8_t report_id, hid_report_type_t report_type, const uint8_t * buffer, uint16_t bufsize){}
#endif #endif
#if CFG_TUD_MSC #if CFG_TUD_MSC
__attribute__ ((weak)) bool tud_msc_test_unit_ready_cb(uint8_t lun){return false;} __attribute__ ((weak)) bool tud_msc_test_unit_ready_cb(uint8_t lun){return false;}
@ -377,120 +314,6 @@ __attribute__ ((weak)) int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_
static bool usb_persist_enabled = false; static bool usb_persist_enabled = false;
static restart_type_t usb_persist_mode = RESTART_NO_PERSIST; static restart_type_t usb_persist_mode = RESTART_NO_PERSIST;
#if CONFIG_IDF_TARGET_ESP32S3
static void hw_cdc_reset_handler(void *arg) {
portBASE_TYPE xTaskWoken = 0;
uint32_t usbjtag_intr_status = usb_serial_jtag_ll_get_intsts_mask();
usb_serial_jtag_ll_clr_intsts_mask(usbjtag_intr_status);
if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_BUS_RESET) {
xSemaphoreGiveFromISR((xSemaphoreHandle)arg, &xTaskWoken);
}
if (xTaskWoken == pdTRUE) {
portYIELD_FROM_ISR();
}
}
static void usb_switch_to_cdc_jtag(){
// Disable USB-OTG
periph_module_reset(PERIPH_USB_MODULE);
//periph_module_enable(PERIPH_USB_MODULE);
periph_module_disable(PERIPH_USB_MODULE);
// Switch to hardware CDC+JTAG
CLEAR_PERI_REG_MASK(RTC_CNTL_USB_CONF_REG, (RTC_CNTL_SW_HW_USB_PHY_SEL|RTC_CNTL_SW_USB_PHY_SEL|RTC_CNTL_USB_PAD_ENABLE));
// Do not use external PHY
CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_PHY_SEL);
// Release GPIO pins from CDC+JTAG
CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE);
// Force the host to re-enumerate (BUS_RESET)
pinMode(USBPHY_DM_NUM, OUTPUT_OPEN_DRAIN);
pinMode(USBPHY_DP_NUM, OUTPUT_OPEN_DRAIN);
digitalWrite(USBPHY_DM_NUM, LOW);
digitalWrite(USBPHY_DP_NUM, LOW);
// Initialize CDC+JTAG ISR to listen for BUS_RESET
usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_LL_INTR_MASK);
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_LL_INTR_MASK);
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_BUS_RESET);
intr_handle_t intr_handle = NULL;
xSemaphoreHandle reset_sem = xSemaphoreCreateBinary();
if(reset_sem){
if(esp_intr_alloc(ETS_USB_SERIAL_JTAG_INTR_SOURCE, 0, hw_cdc_reset_handler, reset_sem, &intr_handle) != ESP_OK){
vSemaphoreDelete(reset_sem);
reset_sem = NULL;
log_e("HW USB CDC failed to init interrupts");
}
} else {
log_e("reset_sem init failed");
}
// Connect GPIOs to integrated CDC+JTAG
SET_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE);
// Wait for BUS_RESET to give us back the semaphore
if(reset_sem){
if(xSemaphoreTake(reset_sem, 1000 / portTICK_PERIOD_MS) != pdPASS){
log_e("reset_sem timeout");
}
usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_LL_INTR_MASK);
esp_intr_free(intr_handle);
vSemaphoreDelete(reset_sem);
}
}
#endif
static void IRAM_ATTR usb_persist_shutdown_handler(void)
{
if(usb_persist_mode != RESTART_NO_PERSIST){
if (usb_persist_enabled) {
usb_dc_prepare_persist();
}
if (usb_persist_mode == RESTART_BOOTLOADER) {
//USB CDC Download
if (usb_persist_enabled) {
chip_usb_set_persist_flags(USBDC_PERSIST_ENA);
#if CONFIG_IDF_TARGET_ESP32S2
} else {
periph_module_reset(PERIPH_USB_MODULE);
periph_module_enable(PERIPH_USB_MODULE);
#endif
}
REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT);
} else if (usb_persist_mode == RESTART_BOOTLOADER_DFU) {
//DFU Download
#if CONFIG_IDF_TARGET_ESP32S2
// Reset USB Core
USB0.grstctl |= USB_CSFTRST;
while ((USB0.grstctl & USB_CSFTRST) == USB_CSFTRST){}
#endif
chip_usb_set_persist_flags(USBDC_BOOT_DFU);
REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT);
} else if (usb_persist_enabled) {
//USB Persist reboot
chip_usb_set_persist_flags(USBDC_PERSIST_ENA);
}
}
}
void usb_persist_restart(restart_type_t mode)
{
if (mode < RESTART_TYPE_MAX && esp_register_shutdown_handler(usb_persist_shutdown_handler) == ESP_OK) {
usb_persist_mode = mode;
#if CONFIG_IDF_TARGET_ESP32S3
if (mode == RESTART_BOOTLOADER) {
usb_switch_to_cdc_jtag();
}
#endif
esp_restart();
}
}
static bool tinyusb_reserve_in_endpoint(uint8_t endpoint){ static bool tinyusb_reserve_in_endpoint(uint8_t endpoint){
if(endpoint > 6 || (tinyusb_endpoints.in & BIT(endpoint)) != 0){ if(endpoint > 6 || (tinyusb_endpoints.in & BIT(endpoint)) != 0){
return false; return false;
@ -545,6 +368,12 @@ static bool tinyusb_load_enabled_interfaces(){
log_e("Descriptor Load Failed"); log_e("Descriptor Load Failed");
return false; return false;
} else { } else {
if(i == USB_INTERFACE_CDC){
if(!tinyusb_reserve_out_endpoint(3) ||!tinyusb_reserve_in_endpoint(4) || !tinyusb_reserve_in_endpoint(5)){
log_e("CDC Reserve Endpoints Failed");
return false;
}
}
dst += len; dst += len;
} }
} }
@ -556,8 +385,8 @@ static bool tinyusb_load_enabled_interfaces(){
}; };
memcpy(tinyusb_config_descriptor, descriptor, TUD_CONFIG_DESC_LEN); memcpy(tinyusb_config_descriptor, descriptor, TUD_CONFIG_DESC_LEN);
if ((tinyusb_loaded_interfaces_mask == (BIT(USB_INTERFACE_CDC) | BIT(USB_INTERFACE_DFU))) || (tinyusb_loaded_interfaces_mask == BIT(USB_INTERFACE_CDC))) { if ((tinyusb_loaded_interfaces_mask == (BIT(USB_INTERFACE_CDC) | BIT(USB_INTERFACE_DFU))) || (tinyusb_loaded_interfaces_mask == BIT(USB_INTERFACE_CDC))) {
//usb_persist_enabled = true; usb_persist_enabled = true;
//log_d("USB Persist enabled"); log_d("USB Persist enabled");
} }
log_d("Load Done: if_num: %u, descr_len: %u, if_mask: 0x%x", tinyusb_loaded_interfaces_num, tinyusb_config_descriptor_len, tinyusb_loaded_interfaces_mask); log_d("Load Done: if_num: %u, descr_len: %u, if_mask: 0x%x", tinyusb_loaded_interfaces_num, tinyusb_config_descriptor_len, tinyusb_loaded_interfaces_mask);
return true; return true;
@ -613,16 +442,6 @@ static void tinyusb_apply_device_config(tinyusb_device_config_t *config){
snprintf(WEBUSB_URL, 126, "%s", config->webusb_url); snprintf(WEBUSB_URL, 126, "%s", config->webusb_url);
} }
// Windows 10 will not recognize the CDC device if WebUSB is enabled and USB Class is not 2 (CDC)
if(
(tinyusb_loaded_interfaces_mask & BIT(USB_INTERFACE_CDC))
&& config->webusb_enabled
&& (config->usb_class != TUSB_CLASS_CDC)
){
config->usb_class = TUSB_CLASS_CDC;
config->usb_protocol = 0x00;
}
WEBUSB_ENABLED = config->webusb_enabled; WEBUSB_ENABLED = config->webusb_enabled;
USB_DEVICE_ATTRIBUTES = config->usb_attributes; USB_DEVICE_ATTRIBUTES = config->usb_attributes;
USB_DEVICE_POWER = config->usb_power_ma; USB_DEVICE_POWER = config->usb_power_ma;
@ -636,6 +455,29 @@ static void tinyusb_apply_device_config(tinyusb_device_config_t *config){
tinyusb_device_descriptor.bDeviceProtocol = config->usb_protocol; tinyusb_device_descriptor.bDeviceProtocol = config->usb_protocol;
} }
static void IRAM_ATTR usb_persist_shutdown_handler(void)
{
if(usb_persist_mode != RESTART_NO_PERSIST){
if (usb_persist_enabled) {
usb_dc_prepare_persist();
}
if (usb_persist_mode == RESTART_BOOTLOADER) {
//USB CDC Download
if (usb_persist_enabled) {
chip_usb_set_persist_flags(USBDC_PERSIST_ENA);
}
REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT);
} else if (usb_persist_mode == RESTART_BOOTLOADER_DFU) {
//DFU Download
chip_usb_set_persist_flags(USBDC_BOOT_DFU);
REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT);
} else if (usb_persist_enabled) {
//USB Persist reboot
chip_usb_set_persist_flags(USBDC_PERSIST_ENA);
}
}
}
// USB Device Driver task // USB Device Driver task
// This top level thread processes all usb events and invokes callbacks // This top level thread processes all usb events and invokes callbacks
static void usb_device_task(void *param) { static void usb_device_task(void *param) {
@ -646,72 +488,71 @@ static void usb_device_task(void *param) {
/* /*
* PUBLIC API * PUBLIC API
* */ * */
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
const char *tinyusb_interface_names[USB_INTERFACE_MAX] = {"MSC", "DFU", "HID", "VENDOR", "CDC", "MIDI", "CUSTOM"};
#endif
static bool tinyusb_is_initialized = false;
esp_err_t tinyusb_enable_interface(tinyusb_interface_t interface, uint16_t descriptor_len, tinyusb_descriptor_cb_t cb) esp_err_t tinyusb_enable_interface(tinyusb_interface_t interface, uint16_t descriptor_len, tinyusb_descriptor_cb_t cb)
{ {
if(tinyusb_is_initialized){
log_e("TinyUSB has already started! Interface %s not enabled", (interface >= USB_INTERFACE_MAX)?"":tinyusb_interface_names[interface]);
return ESP_FAIL;
}
if((interface >= USB_INTERFACE_MAX) || (tinyusb_loaded_interfaces_mask & (1U << interface))){ if((interface >= USB_INTERFACE_MAX) || (tinyusb_loaded_interfaces_mask & (1U << interface))){
log_e("Interface %s invalid or already enabled", (interface >= USB_INTERFACE_MAX)?"":tinyusb_interface_names[interface]); log_e("Interface %u not enabled", interface);
return ESP_FAIL; return ESP_FAIL;
} }
if(interface == USB_INTERFACE_CDC){
if(!tinyusb_reserve_out_endpoint(3) ||!tinyusb_reserve_in_endpoint(4) || !tinyusb_reserve_in_endpoint(5)){
log_e("CDC Reserve Endpoints Failed");
return ESP_FAIL;
}
}
tinyusb_loaded_interfaces_mask |= (1U << interface); tinyusb_loaded_interfaces_mask |= (1U << interface);
tinyusb_config_descriptor_len += descriptor_len; tinyusb_config_descriptor_len += descriptor_len;
tinyusb_loaded_interfaces_callbacks[interface] = cb; tinyusb_loaded_interfaces_callbacks[interface] = cb;
log_d("Interface %s enabled", tinyusb_interface_names[interface]); log_d("Interface %u enabled", interface);
return ESP_OK; return ESP_OK;
} }
esp_err_t tinyusb_init(tinyusb_device_config_t *config) { esp_err_t tinyusb_init(tinyusb_device_config_t *config) {
if(tinyusb_is_initialized){ static bool initialized = false;
if(initialized){
return ESP_OK; return ESP_OK;
} }
tinyusb_is_initialized = true; initialized = true;
//tinyusb_endpoints.val = 0; tinyusb_endpoints.val = 0;
tinyusb_apply_device_config(config); tinyusb_apply_device_config(config);
if (!tinyusb_load_enabled_interfaces()) { if (!tinyusb_load_enabled_interfaces()) {
tinyusb_is_initialized = false; initialized = false;
return ESP_FAIL; return ESP_FAIL;
} }
bool usb_did_persist = (USB_WRAP.date.val == USBDC_PERSIST_ENA); bool usb_did_persist = (USB_WRAP.date.val == USBDC_PERSIST_ENA);
//if(usb_did_persist && usb_persist_enabled){ if(usb_did_persist && usb_persist_enabled){
// Enable USB/IO_MUX peripheral reset, if coming from persistent reboot // Enable USB/IO_MUX peripheral reset, if coming from persistent reboot
REG_CLR_BIT(RTC_CNTL_USB_CONF_REG, RTC_CNTL_IO_MUX_RESET_DISABLE); REG_CLR_BIT(RTC_CNTL_USB_CONF_REG, RTC_CNTL_IO_MUX_RESET_DISABLE);
REG_CLR_BIT(RTC_CNTL_USB_CONF_REG, RTC_CNTL_USB_RESET_DISABLE); REG_CLR_BIT(RTC_CNTL_USB_CONF_REG, RTC_CNTL_USB_RESET_DISABLE);
//} else } else {
if(!usb_did_persist || !usb_persist_enabled){
// Reset USB module // Reset USB module
periph_module_reset(PERIPH_USB_MODULE); periph_module_reset(PERIPH_USB_MODULE);
periph_module_enable(PERIPH_USB_MODULE); periph_module_enable(PERIPH_USB_MODULE);
} }
if (esp_register_shutdown_handler(usb_persist_shutdown_handler) != ESP_OK) {
initialized = false;
return ESP_FAIL;
}
tinyusb_config_t tusb_cfg = { tinyusb_config_t tusb_cfg = {
.external_phy = false // In the most cases you need to use a `false` value .external_phy = false // In the most cases you need to use a `false` value
}; };
esp_err_t err = tinyusb_driver_install(&tusb_cfg); esp_err_t err = tinyusb_driver_install(&tusb_cfg);
if (err != ESP_OK) { if (err != ESP_OK) {
tinyusb_is_initialized = false; initialized = false;
return err; return err;
} }
xTaskCreate(usb_device_task, "usbd", 4096, NULL, configMAX_PRIORITIES - 1, NULL); xTaskCreate(usb_device_task, "usbd", 4096, NULL, configMAX_PRIORITIES - 1, NULL);
return err; return err;
} }
void usb_persist_restart(restart_type_t mode)
{
if (mode < RESTART_TYPE_MAX) {
usb_persist_mode = mode;
esp_restart();
}
}
uint8_t tinyusb_add_string_descriptor(const char * str){ uint8_t tinyusb_add_string_descriptor(const char * str){
if(str == NULL || tinyusb_string_descriptor_len >= MAX_STRING_DESCRIPTORS){ if(str == NULL || tinyusb_string_descriptor_len >= MAX_STRING_DESCRIPTORS){
return 0; return 0;
@ -773,4 +614,84 @@ uint8_t tinyusb_get_free_out_endpoint(void){
return 0; return 0;
} }
#endif /* CONFIG_TINYUSB_ENABLED */ /*
void usb_dw_reg_dump(void)
{
#define USB_PRINT_REG(r) printf("USB0." #r " = 0x%x;\n", USB0.r)
#define USB_PRINT_IREG(i, r) printf("USB0.in_ep_reg[%u]." #r " = 0x%x;\n", i, USB0.in_ep_reg[i].r)
#define USB_PRINT_OREG(i, r) printf("USB0.out_ep_reg[%u]." #r " = 0x%x;\n", i, USB0.out_ep_reg[i].r)
uint8_t i;
USB_PRINT_REG(gotgctl);
USB_PRINT_REG(gotgint);
USB_PRINT_REG(gahbcfg);
USB_PRINT_REG(gusbcfg);
USB_PRINT_REG(grstctl);
USB_PRINT_REG(gintsts);
USB_PRINT_REG(gintmsk);
USB_PRINT_REG(grxstsr);
USB_PRINT_REG(grxstsp);
USB_PRINT_REG(grxfsiz);
USB_PRINT_REG(gnptxsts);
USB_PRINT_REG(gpvndctl);
USB_PRINT_REG(ggpio);
USB_PRINT_REG(guid);
USB_PRINT_REG(gsnpsid);
USB_PRINT_REG(ghwcfg1);
USB_PRINT_REG(ghwcfg2);
USB_PRINT_REG(ghwcfg3);
USB_PRINT_REG(ghwcfg4);
USB_PRINT_REG(glpmcfg);
USB_PRINT_REG(gpwrdn);
USB_PRINT_REG(gdfifocfg);
USB_PRINT_REG(gadpctl);
USB_PRINT_REG(hptxfsiz);
USB_PRINT_REG(hcfg);
USB_PRINT_REG(hfir);
USB_PRINT_REG(hfnum);
USB_PRINT_REG(hptxsts);
USB_PRINT_REG(haint);
USB_PRINT_REG(haintmsk);
USB_PRINT_REG(hflbaddr);
USB_PRINT_REG(hprt);
USB_PRINT_REG(dcfg);
USB_PRINT_REG(dctl);
USB_PRINT_REG(dsts);
USB_PRINT_REG(diepmsk);
USB_PRINT_REG(doepmsk);
USB_PRINT_REG(daint);
USB_PRINT_REG(daintmsk);
USB_PRINT_REG(dtknqr1);
USB_PRINT_REG(dtknqr2);
USB_PRINT_REG(dvbusdis);
USB_PRINT_REG(dvbuspulse);
USB_PRINT_REG(dtknqr3_dthrctl);
USB_PRINT_REG(dtknqr4_fifoemptymsk);
USB_PRINT_REG(deachint);
USB_PRINT_REG(deachintmsk);
USB_PRINT_REG(pcgctrl);
USB_PRINT_REG(pcgctrl1);
USB_PRINT_REG(gnptxfsiz);
for (i = 0; i < 4; i++) {
printf("USB0.dieptxf[%u] = 0x%x;\n", i, USB0.dieptxf[i]);
}
// for (i = 0; i < 16; i++) {
// printf("USB0.diepeachintmsk[%u] = 0x%x;\n", i, USB0.diepeachintmsk[i]);
// }
// for (i = 0; i < 16; i++) {
// printf("USB0.doepeachintmsk[%u] = 0x%x;\n", i, USB0.doepeachintmsk[i]);
// }
for (i = 0; i < 7; i++) {
printf("// EP %u:\n", i);
USB_PRINT_IREG(i, diepctl);
USB_PRINT_IREG(i, diepint);
USB_PRINT_IREG(i, dieptsiz);
USB_PRINT_IREG(i, diepdma);
USB_PRINT_IREG(i, dtxfsts);
USB_PRINT_OREG(i, doepctl);
USB_PRINT_OREG(i, doepint);
USB_PRINT_OREG(i, doeptsiz);
USB_PRINT_OREG(i, doepdma);
}
}
*/
#endif /* CONFIG_USB_ENABLED */

View File

@ -15,18 +15,14 @@
#include "esp32-hal.h" #include "esp32-hal.h"
#if CONFIG_TINYUSB_ENABLED #if CONFIG_IDF_TARGET_ESP32S2
#if CONFIG_USB_ENABLED
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#include "tusb.h" #include "tinyusb.h"
#include "tusb_option.h"
#include "tusb_config.h"
#define USB_ESPRESSIF_VID 0x303A
#define USB_STRING_DESCRIPTOR_ARRAY_SIZE 10
typedef struct { typedef struct {
uint16_t vid; uint16_t vid;
@ -50,10 +46,10 @@ typedef struct {
#define TINYUSB_CONFIG_DEFAULT() { \ #define TINYUSB_CONFIG_DEFAULT() { \
.vid = USB_ESPRESSIF_VID, \ .vid = USB_ESPRESSIF_VID, \
.pid = 0x0002, \ .pid = 0x0002, \
.product_name = CONFIG_TINYUSB_DESC_PRODUCT_STRING, \ .product_name = CONFIG_USB_DESC_PRODUCT_STRING, \
.manufacturer_name = CONFIG_TINYUSB_DESC_MANUFACTURER_STRING, \ .manufacturer_name = CONFIG_USB_DESC_MANUFACTURER_STRING, \
.serial_number = CONFIG_TINYUSB_DESC_SERIAL_STRING, \ .serial_number = CONFIG_USB_DESC_SERIAL_STRING, \
.fw_version = CONFIG_TINYUSB_DESC_BCDDEVICE, \ .fw_version = CONFIG_USB_DESC_BCDDEVICE, \
.usb_version = 0x0200, \ .usb_version = 0x0200, \
.usb_class = TUSB_CLASS_MISC, \ .usb_class = TUSB_CLASS_MISC, \
.usb_subclass = MISC_SUBCLASS_COMMON, \ .usb_subclass = MISC_SUBCLASS_COMMON, \
@ -81,11 +77,11 @@ void usb_persist_restart(restart_type_t mode);
// The following definitions and functions are to be used only by the drivers // The following definitions and functions are to be used only by the drivers
typedef enum { typedef enum {
USB_INTERFACE_MSC, USB_INTERFACE_CDC,
USB_INTERFACE_DFU, USB_INTERFACE_DFU,
USB_INTERFACE_HID, USB_INTERFACE_HID,
USB_INTERFACE_VENDOR, USB_INTERFACE_VENDOR,
USB_INTERFACE_CDC, USB_INTERFACE_MSC,
USB_INTERFACE_MIDI, USB_INTERFACE_MIDI,
USB_INTERFACE_CUSTOM, USB_INTERFACE_CUSTOM,
USB_INTERFACE_MAX USB_INTERFACE_MAX
@ -103,4 +99,5 @@ uint8_t tinyusb_get_free_out_endpoint(void);
} }
#endif #endif
#endif /* CONFIG_TINYUSB_ENABLED */ #endif /* CONFIG_USB_ENABLED */
#endif /* CONFIG_IDF_TARGET_ESP32S2 */

View File

@ -12,268 +12,216 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "soc/soc_caps.h"
#if SOC_TOUCH_SENSOR_NUM > 0
#include "driver/touch_sensor.h"
#include "esp32-hal-touch.h" #include "esp32-hal-touch.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_attr.h"
#include "soc/rtc_io_reg.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/sens_reg.h"
#include "soc/sens_struct.h"
#include "driver/touch_sensor.h"
/* #include "esp_system.h"
Internal Private Touch Data Structure and Functions #ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
*/ #if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
#include "esp32/rom/ets_sys.h"
#include "esp_intr_alloc.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/ets_sys.h"
#include "esp_intr_alloc.h"
#include "soc/periph_defs.h"
#else
#error Target CONFIG_IDF_TARGET is not supported
#endif
#else // ESP32 Before IDF 4.0
#include "rom/ets_sys.h"
#include "esp_intr.h"
#endif
#if SOC_TOUCH_VERSION_1 // ESP32
static uint16_t __touchSleepCycles = 0x1000; static uint16_t __touchSleepCycles = 0x1000;
static uint16_t __touchMeasureCycles = 0x1000; static uint16_t __touchMeasureCycles = 0x1000;
#elif SOC_TOUCH_VERSION_2 // ESP32S2, ESP32S3
static uint16_t __touchSleepCycles = TOUCH_PAD_SLEEP_CYCLE_DEFAULT;
static uint16_t __touchMeasureCycles = TOUCH_PAD_MEASURE_CYCLE_DEFAULT;
#endif
typedef void (*voidFuncPtr)(void); typedef void (*voidFuncPtr)(void);
typedef void (*voidArgFuncPtr)(void *); static voidFuncPtr __touchInterruptHandlers[10] = {0,};
static intr_handle_t touch_intr_handle = NULL;
typedef struct { void ARDUINO_ISR_ATTR __touchISR(void * arg)
voidFuncPtr fn;
bool callWithArgs;
void* arg;
#if SOC_TOUCH_VERSION_2 // Only for ESP32S2 and ESP32S3
bool lastStatusIsPressed;
#endif
} TouchInterruptHandle_t;
static TouchInterruptHandle_t __touchInterruptHandlers[SOC_TOUCH_SENSOR_NUM] = {0,};
static void ARDUINO_ISR_ATTR __touchISR(void * arg)
{ {
#if SOC_TOUCH_VERSION_1 // ESP32 #if CONFIG_IDF_TARGET_ESP32
uint32_t pad_intr = touch_pad_get_status(); uint32_t pad_intr = READ_PERI_REG(SENS_SAR_TOUCH_CTRL2_REG) & 0x3ff;
uint32_t rtc_intr = READ_PERI_REG(RTC_CNTL_INT_ST_REG);
uint8_t i = 0;
//clear interrupt //clear interrupt
touch_pad_clear_status(); WRITE_PERI_REG(RTC_CNTL_INT_CLR_REG, rtc_intr);
// call Pad ISR User callback SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_MEAS_EN_CLR);
for (int i = 0; i < SOC_TOUCH_SENSOR_NUM; i++) {
if (rtc_intr & RTC_CNTL_TOUCH_INT_ST) {
for (i = 0; i < 10; ++i) {
if ((pad_intr >> i) & 0x01) { if ((pad_intr >> i) & 0x01) {
if(__touchInterruptHandlers[i].fn){ if(__touchInterruptHandlers[i]){
// keeping backward compatibility with "void cb(void)" and with new "void cb(vooid *)" __touchInterruptHandlers[i]();
if (__touchInterruptHandlers[i].callWithArgs) {
((voidArgFuncPtr)__touchInterruptHandlers[i].fn)(__touchInterruptHandlers[i].arg);
} else {
__touchInterruptHandlers[i].fn();
} }
} }
} }
} }
#elif SOC_TOUCH_VERSION_2 // ESP32S2, ESP32S3
touch_pad_intr_mask_t evt = touch_pad_read_intr_status_mask();
uint8_t pad_num = touch_pad_get_current_meas_channel();
if (evt & TOUCH_PAD_INTR_MASK_ACTIVE) {
// touch has been pressed / touched
__touchInterruptHandlers[pad_num].lastStatusIsPressed = true;
}
if (evt & TOUCH_PAD_INTR_MASK_INACTIVE) {
// touch has been released / untouched
__touchInterruptHandlers[pad_num].lastStatusIsPressed = false;
}
if(__touchInterruptHandlers[pad_num].fn){
// keeping backward compatibility with "void cb(void)" and with new "void cb(vooid *)"
if (__touchInterruptHandlers[pad_num].callWithArgs) {
((voidArgFuncPtr)__touchInterruptHandlers[pad_num].fn)(__touchInterruptHandlers[pad_num].arg);
} else {
__touchInterruptHandlers[pad_num].fn();
}
}
#endif #endif
} }
void __touchSetCycles(uint16_t measure, uint16_t sleep)
static void __touchSetCycles(uint16_t measure, uint16_t sleep)
{ {
__touchSleepCycles = sleep; __touchSleepCycles = sleep;
__touchMeasureCycles = measure; __touchMeasureCycles = measure;
#if CONFIG_IDF_TARGET_ESP32
//Touch pad SleepCycle Time
SET_PERI_REG_BITS(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_SLEEP_CYCLES, __touchSleepCycles, SENS_TOUCH_SLEEP_CYCLES_S);
//Touch Pad Measure Time
SET_PERI_REG_BITS(SENS_SAR_TOUCH_CTRL1_REG, SENS_TOUCH_MEAS_DELAY, __touchMeasureCycles, SENS_TOUCH_MEAS_DELAY_S);
#else
touch_pad_set_meas_time(sleep, measure); touch_pad_set_meas_time(sleep, measure);
#endif
} }
void __touchInit()
static void __touchInit()
{ {
static bool initialized = false; static bool initialized = false;
if(initialized){ if(initialized){
return; return;
} }
initialized = true;
esp_err_t err = ESP_OK; #if CONFIG_IDF_TARGET_ESP32
SET_PERI_REG_BITS(RTC_IO_TOUCH_CFG_REG, RTC_IO_TOUCH_XPD_BIAS, 1, RTC_IO_TOUCH_XPD_BIAS_S);
#if SOC_TOUCH_VERSION_1 // ESP32 SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_MEAS_EN_CLR);
err = touch_pad_init(); //clear touch enable
if (err != ESP_OK) { WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG, 0x0);
goto err; __touchSetCycles(__touchMeasureCycles, __touchSleepCycles);
} esp_intr_alloc(ETS_RTC_CORE_INTR_SOURCE, (int)ARDUINO_ISR_FLAG, __touchISR, NULL, &touch_intr_handle);
// the next two lines will drive the touch reading values -- both will return ESP_OK #else
touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_0V); touch_pad_init();
touch_pad_set_meas_time(__touchMeasureCycles, __touchSleepCycles); touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_0V5);
// Touch Sensor Timer initiated touch_pad_set_idle_channel_connect(TOUCH_PAD_CONN_GND);
touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); // returns ESP_OK __touchSetCycles(__touchMeasureCycles, __touchSleepCycles);
err = touch_pad_filter_start(10);
if (err != ESP_OK) {
goto err;
}
// keep ISR activated - it can run all together (ISR + touchRead())
err = touch_pad_isr_register(__touchISR, NULL);
if (err != ESP_OK) {
goto err;
}
touch_pad_intr_enable(); // returns ESP_OK
#elif SOC_TOUCH_VERSION_2 // ESP32S2, ESP32S3
err = touch_pad_init();
if (err != ESP_OK) {
goto err;
}
// the next lines will drive the touch reading values -- all os them return ESP_OK
touch_pad_set_meas_time(__touchSleepCycles, __touchMeasureCycles);
touch_pad_set_voltage(TOUCH_PAD_HIGH_VOLTAGE_THRESHOLD, TOUCH_PAD_LOW_VOLTAGE_THRESHOLD, TOUCH_PAD_ATTEN_VOLTAGE_THRESHOLD);
touch_pad_set_idle_channel_connect(TOUCH_PAD_IDLE_CH_CONNECT_DEFAULT);
touch_pad_denoise_t denoise = { touch_pad_denoise_t denoise = {
.grade = TOUCH_PAD_DENOISE_BIT4, .grade = TOUCH_PAD_DENOISE_BIT4,
.cap_level = TOUCH_PAD_DENOISE_CAP_L4, .cap_level = TOUCH_PAD_DENOISE_CAP_L4,
}; };
touch_pad_denoise_set_config(&denoise); touch_pad_denoise_set_config(&denoise);
touch_pad_denoise_enable(); touch_pad_denoise_enable();
// Touch Sensor Timer initiated touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);
touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); // returns ESP_OK touch_pad_fsm_start();
touch_pad_fsm_start(); // returns ESP_OK
//ISR setup moved to __touchChannelInit
#endif #endif
initialized = true;
return;
err:
log_e(" Touch sensor initialization error.");
initialized = false;
return;
} }
static void __touchChannelInit(int pad) uint16_t __touchRead(uint8_t pin)
{
static bool channels_initialized[SOC_TOUCH_SENSOR_NUM] = { false };
if(channels_initialized[pad]){
return;
}
#if SOC_TOUCH_VERSION_1 // ESP32
// Initial no Threshold and setup
__touchInterruptHandlers[pad].fn = NULL;
touch_pad_config(pad, SOC_TOUCH_PAD_THRESHOLD_MAX); // returns ESP_OK
#elif SOC_TOUCH_VERSION_2 // ESP32S2, ESP32S3
// Initial no Threshold and setup
__touchInterruptHandlers[pad].fn = NULL;
touch_pad_config(pad); // returns ESP_OK
// keep ISR activated - it can run all together (ISR + touchRead())
esp_err_t err = touch_pad_isr_register(__touchISR, NULL, TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE);
if (err != ESP_OK) {
log_e(" Touch sensor initialization error.");
return;
}
touch_pad_intr_enable(TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE); // returns ESP_OK
#endif
channels_initialized[pad] = true;
delay(20); //delay needed before reading from touch channel after config
}
static touch_value_t __touchRead(uint8_t pin)
{ {
int8_t pad = digitalPinToTouchChannel(pin); int8_t pad = digitalPinToTouchChannel(pin);
if(pad < 0){ if(pad < 0){
return 0; return 0;
} }
pinMode(pin, ANALOG);
__touchInit(); __touchInit();
__touchChannelInit(pad);
touch_value_t touch_value; #if CONFIG_IDF_TARGET_ESP32
touch_pad_read_raw_data(pad, &touch_value); uint32_t v0 = READ_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG);
//Disable Intr & enable touch pad
WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG,
(v0 & ~((1 << (pad + SENS_TOUCH_PAD_OUTEN2_S)) | (1 << (pad + SENS_TOUCH_PAD_OUTEN1_S))))
| (1 << (pad + SENS_TOUCH_PAD_WORKEN_S)));
SET_PERI_REG_MASK(SENS_SAR_TOUCH_ENABLE_REG, (1 << (pad + SENS_TOUCH_PAD_WORKEN_S)));
uint32_t rtc_tio_reg = RTC_IO_TOUCH_PAD0_REG + pad * 4;
WRITE_PERI_REG(rtc_tio_reg, (READ_PERI_REG(rtc_tio_reg)
& ~(RTC_IO_TOUCH_PAD0_DAC_M))
| (7 << RTC_IO_TOUCH_PAD0_DAC_S)//Touch Set Slope
| RTC_IO_TOUCH_PAD0_TIE_OPT_M //Enable Tie,Init Level
| RTC_IO_TOUCH_PAD0_START_M //Enable Touch Pad IO
| RTC_IO_TOUCH_PAD0_XPD_M); //Enable Touch Pad Power on
//force oneTime test start
SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_EN_M|SENS_TOUCH_START_FORCE_M);
SET_PERI_REG_BITS(SENS_SAR_TOUCH_CTRL1_REG, SENS_TOUCH_XPD_WAIT, 10, SENS_TOUCH_XPD_WAIT_S);
while (GET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_MEAS_DONE) == 0) {};
uint16_t touch_value = READ_PERI_REG(SENS_SAR_TOUCH_OUT1_REG + (pad / 2) * 4) >> ((pad & 1) ? SENS_TOUCH_MEAS_OUT1_S : SENS_TOUCH_MEAS_OUT0_S);
//clear touch force ,select the Touch mode is Timer
CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_EN_M|SENS_TOUCH_START_FORCE_M);
//restore previous value
WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG, v0);
return touch_value; return touch_value;
#else
static uint32_t chan_mask = 0;
uint32_t value = 0;
if((chan_mask & (1 << pad)) == 0){
if(touch_pad_set_thresh((touch_pad_t)pad, TOUCH_PAD_THRESHOLD_MAX) != ESP_OK){
log_e("touch_pad_set_thresh failed");
} else if(touch_pad_config((touch_pad_t)pad) != ESP_OK){
log_e("touch_pad_config failed");
} else {
chan_mask |= (1 << pad);
}
}
if((chan_mask & (1 << pad)) != 0) {
if(touch_pad_read_raw_data((touch_pad_t)pad, &value) != ESP_OK){
log_e("touch_pad_read_raw_data failed");
}
}
return value;
#endif
} }
static void __touchConfigInterrupt(uint8_t pin, void (*userFunc)(void), void *Args, touch_value_t threshold, bool callWithArgs) void __touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), uint16_t threshold)
{ {
int8_t pad = digitalPinToTouchChannel(pin); int8_t pad = digitalPinToTouchChannel(pin);
if(pad < 0){ if(pad < 0){
return; return;
} }
if (userFunc == NULL) { pinMode(pin, ANALOG);
// dettach ISR User Call
__touchInterruptHandlers[pad].fn = NULL;
threshold = SOC_TOUCH_PAD_THRESHOLD_MAX; // deactivate the ISR with SOC_TOUCH_PAD_THRESHOLD_MAX
} else {
// attach ISR User Call
__touchInit(); __touchInit();
#if SOC_TOUCH_VERSION_2 // ESP32S2, ESP32S3
__touchChannelInit(pad);
#endif
__touchInterruptHandlers[pad].fn = userFunc;
__touchInterruptHandlers[pad].callWithArgs = callWithArgs;
__touchInterruptHandlers[pad].arg = Args;
}
#if SOC_TOUCH_VERSION_1 // ESP32 __touchInterruptHandlers[pad] = userFunc;
touch_pad_config(pad, threshold);
#elif SOC_TOUCH_VERSION_2 // ESP32S2, ESP32S3 #if CONFIG_IDF_TARGET_ESP32
touch_pad_set_thresh(pad, threshold); //clear touch force ,select the Touch mode is Timer
CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_EN_M|SENS_TOUCH_START_FORCE_M);
//interrupt when touch value < threshold
CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_TOUCH_OUT_SEL);
//Intr will give ,when SET0 < threshold
SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_TOUCH_OUT_1EN);
//Enable Rtc Touch Module Intr,the Interrupt need Rtc out Enable
SET_PERI_REG_MASK(RTC_CNTL_INT_ENA_REG, RTC_CNTL_TOUCH_INT_ENA);
//set threshold
uint8_t shift = (pad & 1) ? SENS_TOUCH_OUT_TH1_S : SENS_TOUCH_OUT_TH0_S;
SET_PERI_REG_BITS((SENS_SAR_TOUCH_THRES1_REG + (pad / 2) * 4), SENS_TOUCH_OUT_TH0, threshold, shift);
uint32_t rtc_tio_reg = RTC_IO_TOUCH_PAD0_REG + pad * 4;
WRITE_PERI_REG(rtc_tio_reg, (READ_PERI_REG(rtc_tio_reg)
& ~(RTC_IO_TOUCH_PAD0_DAC_M))
| (7 << RTC_IO_TOUCH_PAD0_DAC_S)//Touch Set Slope
| RTC_IO_TOUCH_PAD0_TIE_OPT_M //Enable Tie,Init Level
| RTC_IO_TOUCH_PAD0_START_M //Enable Touch Pad IO
| RTC_IO_TOUCH_PAD0_XPD_M); //Enable Touch Pad Power on
//Enable Digital rtc control :work mode and out mode
SET_PERI_REG_MASK(SENS_SAR_TOUCH_ENABLE_REG,
(1 << (pad + SENS_TOUCH_PAD_WORKEN_S)) | \
(1 << (pad + SENS_TOUCH_PAD_OUTEN2_S)) | \
(1 << (pad + SENS_TOUCH_PAD_OUTEN1_S)));
#else
#endif #endif
} }
// it keeps backwards compatibility extern uint16_t touchRead(uint8_t pin) __attribute__ ((weak, alias("__touchRead")));
static void __touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), touch_value_t threshold) extern void touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), uint16_t threshold) __attribute__ ((weak, alias("__touchAttachInterrupt")));
{ extern void touchSetCycles(uint16_t measure, uint16_t sleep) __attribute__ ((weak, alias("__touchSetCycles")));
__touchConfigInterrupt(pin, userFunc, NULL, threshold, false);
}
// new additional version of the API with User Args
static void __touchAttachArgsInterrupt(uint8_t pin, void (*userFunc)(void), void *args, touch_value_t threshold)
{
__touchConfigInterrupt(pin, userFunc, args, threshold, true);
}
// new additional API to dettach touch ISR
static void __touchDettachInterrupt(uint8_t pin)
{
__touchConfigInterrupt(pin, NULL, NULL, 0, false); // userFunc as NULL acts as dettaching
}
/*
External Public Touch API Functions
*/
#if SOC_TOUCH_VERSION_1 // Only for ESP32 SoC
void touchInterruptSetThresholdDirection(bool mustbeLower) {
if (mustbeLower) {
touch_pad_set_trigger_mode(TOUCH_TRIGGER_BELOW);
} else {
touch_pad_set_trigger_mode(TOUCH_TRIGGER_ABOVE);
}
}
#elif SOC_TOUCH_VERSION_2 // Only for ESP32S2 and ESP32S3
// returns true if touch pad has been and continues pressed and false otherwise
bool touchInterruptGetLastStatus(uint8_t pin) {
int8_t pad = digitalPinToTouchChannel(pin);
if(pad < 0){
return false;
}
return __touchInterruptHandlers[pad].lastStatusIsPressed;
}
#endif
extern touch_value_t touchRead(uint8_t) __attribute__ ((weak, alias("__touchRead")));
extern void touchAttachInterrupt(uint8_t, voidFuncPtr, touch_value_t) __attribute__ ((weak, alias("__touchAttachInterrupt")));
extern void touchAttachInterruptArg(uint8_t, voidArgFuncPtr, void *, touch_value_t) __attribute__ ((weak, alias("__touchAttachArgsInterrupt")));
extern void touchDetachInterrupt(uint8_t) __attribute__ ((weak, alias("__touchDettachInterrupt")));
extern void touchSetCycles(uint16_t, uint16_t) __attribute__ ((weak, alias("__touchSetCycles")));
#endif // #if SOC_TOUCH_SENSOR_NUM > 0

View File

@ -24,21 +24,8 @@
extern "C" { extern "C" {
#endif #endif
#include "soc/soc_caps.h"
#include "esp32-hal.h" #include "esp32-hal.h"
#if SOC_TOUCH_SENSOR_NUM > 0
#if !defined(SOC_TOUCH_VERSION_1) && !defined(SOC_TOUCH_VERSION_2)
#error Touch IDF driver Not supported!
#endif
#if SOC_TOUCH_VERSION_1 // ESP32
typedef uint16_t touch_value_t;
#elif SOC_TOUCH_VERSION_2 // ESP32S2 ESP32S3
typedef uint32_t touch_value_t;
#endif
/* /*
* Set cycles that measurement operation takes * Set cycles that measurement operation takes
* The result from touchRead, threshold and detection * The result from touchRead, threshold and detection
@ -53,44 +40,17 @@ void touchSetCycles(uint16_t measure, uint16_t sleep);
* You can use this method to chose a good threshold value * You can use this method to chose a good threshold value
* to use as value for touchAttachInterrupt * to use as value for touchAttachInterrupt
* */ * */
touch_value_t touchRead(uint8_t pin); uint16_t touchRead(uint8_t pin);
/* /*
* Set function to be called if touch pad value falls (ESP32) * Set function to be called if touch pad value falls
* below the given threshold / rises (ESP32-S2/S3) by given increment (threshold). * below the given threshold. Use touchRead to determine
* Use touchRead to determine a proper threshold between touched and untouched state * a proper threshold between touched and untouched state
* */ * */
void touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), touch_value_t threshold); void touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), uint16_t threshold);
void touchAttachInterruptArg(uint8_t pin, void (*userFunc)(void*), void *arg, touch_value_t threshold);
void touchDetachInterrupt(uint8_t pin);
/*
* Specific functions to ESP32
* Tells the driver if it shall activate the ISR if the sensor is Lower or Higher than the Threshold
* Default if Lower.
**/
#if SOC_TOUCH_VERSION_1 // Only for ESP32 SoC
void touchInterruptSetThresholdDirection(bool mustbeLower);
#endif
/*
* Specific functions to ESP32-S2 and ESP32-S3
* Returns true when the latest ISR status for the Touchpad is that it is touched (Active)
* and false when the Touchpad is untoouched (Inactive)
* This function can be used in conjunction with ISR User callback in order to take action
* as soon as the touchpad is touched and/or released
**/
#if SOC_TOUCH_VERSION_2 // Only for ESP32S2 and ESP32S3
// returns true if touch pad has been and continues pressed and false otherwise
bool touchInterruptGetLastStatus(uint8_t pin);
#endif
#endif // SOC_TOUCH_SENSOR_NUM > 0
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* MAIN_ESP32_HAL_TOUCH_H_ */ #endif /* MAIN_ESP32_HAL_TOUCH_H_ */

View File

@ -14,134 +14,202 @@
#include "esp32-hal-uart.h" #include "esp32-hal-uart.h"
#include "esp32-hal.h" #include "esp32-hal.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h" #include "freertos/semphr.h"
#include "esp_attr.h"
#include "driver/uart.h" #include "soc/uart_reg.h"
#include "hal/uart_ll.h"
#include "soc/soc_caps.h"
#include "soc/uart_struct.h" #include "soc/uart_struct.h"
#include "soc/io_mux_reg.h"
#include "soc/gpio_sig_map.h"
#include "soc/dport_reg.h"
#include "soc/rtc.h"
#include "esp_intr_alloc.h"
#include "esp_system.h"
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
#include "esp32/rom/ets_sys.h"
#include "esp32/rom/uart.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/ets_sys.h"
#include "esp32s2/rom/uart.h"
#include "soc/periph_defs.h"
#else
#error Target CONFIG_IDF_TARGET is not supported
#endif
#else // ESP32 Before IDF 4.0
#include "rom/ets_sys.h"
#include "rom/uart.h"
#include "esp_intr.h"
#endif
#if CONFIG_IDF_TARGET_ESP32S2
#define UART_PORTS_NUM 2
#define UART_REG_BASE(u) ((u==0)?DR_REG_UART_BASE:( (u==1)?DR_REG_UART1_BASE:0))
#define UART_RXD_IDX(u) ((u==0)?U0RXD_IN_IDX:( (u==1)?U1RXD_IN_IDX:0))
#define UART_TXD_IDX(u) ((u==0)?U0TXD_OUT_IDX:( (u==1)?U1TXD_OUT_IDX:0))
#define UART_INTR_SOURCE(u) ((u==0)?ETS_UART0_INTR_SOURCE:( (u==1)?ETS_UART1_INTR_SOURCE:0))
#else
#define UART_PORTS_NUM 3
#define UART_REG_BASE(u) ((u==0)?DR_REG_UART_BASE:( (u==1)?DR_REG_UART1_BASE:( (u==2)?DR_REG_UART2_BASE:0)))
#define UART_RXD_IDX(u) ((u==0)?U0RXD_IN_IDX:( (u==1)?U1RXD_IN_IDX:( (u==2)?U2RXD_IN_IDX:0)))
#define UART_TXD_IDX(u) ((u==0)?U0TXD_OUT_IDX:( (u==1)?U1TXD_OUT_IDX:( (u==2)?U2TXD_OUT_IDX:0)))
#define UART_INTR_SOURCE(u) ((u==0)?ETS_UART0_INTR_SOURCE:( (u==1)?ETS_UART1_INTR_SOURCE:((u==2)?ETS_UART2_INTR_SOURCE:0)))
#endif
static int s_uart_debug_nr = 0; static int s_uart_debug_nr = 0;
struct uart_struct_t { struct uart_struct_t {
uart_dev_t * dev;
#if !CONFIG_DISABLE_HAL_LOCKS #if !CONFIG_DISABLE_HAL_LOCKS
xSemaphoreHandle lock; xSemaphoreHandle lock;
#endif #endif
uint8_t num; uint8_t num;
bool has_peek; xQueueHandle queue;
uint8_t peek_byte; intr_handle_t intr_handle;
QueueHandle_t uart_event_queue; // export it by some uartGetEventQueue() function
}; };
#if CONFIG_DISABLE_HAL_LOCKS #if CONFIG_DISABLE_HAL_LOCKS
#define UART_MUTEX_LOCK() #define UART_MUTEX_LOCK()
#define UART_MUTEX_UNLOCK() #define UART_MUTEX_UNLOCK()
static uart_t _uart_bus_array[] = { static uart_t _uart_bus_array[] = {
{0, false, 0, NULL}, {&UART0, 0, NULL, NULL},
#if SOC_UART_NUM > 1 {&UART1, 1, NULL, NULL},
{1, false, 0, NULL}, #if CONFIG_IDF_TARGET_ESP32
#endif {&UART2, 2, NULL, NULL}
#if SOC_UART_NUM > 2
{2, false, 0, NULL},
#endif #endif
}; };
#else #else
#define UART_MUTEX_LOCK() do {} while (xSemaphoreTake(uart->lock, portMAX_DELAY) != pdPASS) #define UART_MUTEX_LOCK() do {} while (xSemaphoreTake(uart->lock, portMAX_DELAY) != pdPASS)
#define UART_MUTEX_UNLOCK() xSemaphoreGive(uart->lock) #define UART_MUTEX_UNLOCK() xSemaphoreGive(uart->lock)
static uart_t _uart_bus_array[] = { static uart_t _uart_bus_array[] = {
{NULL, 0, false, 0, NULL}, {&UART0, NULL, 0, NULL, NULL},
#if SOC_UART_NUM > 1 {&UART1, NULL, 1, NULL, NULL},
{NULL, 1, false, 0, NULL}, #if CONFIG_IDF_TARGET_ESP32
#endif {&UART2, NULL, 2, NULL, NULL}
#if SOC_UART_NUM > 2
{NULL, 2, false, 0, NULL},
#endif #endif
}; };
#endif #endif
// solves issue https://github.com/espressif/arduino-esp32/issues/6032 static void uart_on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb);
// baudrate must be multiplied when CPU Frequency is lower than APB 80MHz
uint32_t _get_effective_baudrate(uint32_t baudrate) static void ARDUINO_ISR_ATTR _uart_isr(void *arg)
{ {
uint32_t Freq = getApbFrequency()/1000000; uint8_t i, c;
if (Freq < 80) { BaseType_t xHigherPriorityTaskWoken;
return 80 / Freq * baudrate; uart_t* uart;
for(i=0;i<UART_PORTS_NUM;i++){
uart = &_uart_bus_array[i];
if(uart->intr_handle == NULL){
continue;
} }
else { uart->dev->int_clr.rxfifo_full = 1;
return baudrate; uart->dev->int_clr.frm_err = 1;
uart->dev->int_clr.rxfifo_tout = 1;
#if CONFIG_IDF_TARGET_ESP32
while(uart->dev->status.rxfifo_cnt || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) {
c = uart->dev->fifo.rw_byte;
#else
uint32_t fifo_reg = UART_FIFO_AHB_REG(i);
while(uart->dev->status.rxfifo_cnt) {
c = ESP_REG(fifo_reg);
#endif
if(uart->queue != NULL) {
xQueueSendFromISR(uart->queue, &c, &xHigherPriorityTaskWoken);
}
}
}
if (xHigherPriorityTaskWoken) {
portYIELD_FROM_ISR();
} }
} }
// Routines that take care of UART events will be in the HardwareSerial Class code void uartEnableInterrupt(uart_t* uart)
void uartGetEventQueue(uart_t* uart, QueueHandle_t *q)
{ {
// passing back NULL for the Queue pointer when UART is not initialized yet
*q = NULL;
if(uart == NULL) {
return;
}
*q = uart->uart_event_queue;
return;
}
bool uartIsDriverInstalled(uart_t* uart)
{
if(uart == NULL) {
return false;
}
if (uart_is_driver_installed(uart->num)) {
return true;
}
return false;
}
// Valid pin UART_PIN_NO_CHANGE is defined to (-1)
// Negative Pin Number will keep it unmodified, thus this function can set individual pins
void uartSetPins(uart_t* uart, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin)
{
if(uart == NULL) {
return;
}
UART_MUTEX_LOCK(); UART_MUTEX_LOCK();
// IDF uart_set_pin() will issue necessary Error Message and take care of all GPIO Number validation. uart->dev->conf1.rxfifo_full_thrhd = 112;
uart_set_pin(uart->num, txPin, rxPin, rtsPin, ctsPin); #if CONFIG_IDF_TARGET_ESP32
uart->dev->conf1.rx_tout_thrhd = 2;
#else
uart->dev->mem_conf.rx_tout_thrhd = 2;
#endif
uart->dev->conf1.rx_tout_en = 1;
uart->dev->int_ena.rxfifo_full = 1;
uart->dev->int_ena.frm_err = 1;
uart->dev->int_ena.rxfifo_tout = 1;
uart->dev->int_clr.val = 0xffffffff;
esp_intr_alloc(UART_INTR_SOURCE(uart->num), (int)ARDUINO_ISR_FLAG, _uart_isr, NULL, &uart->intr_handle);
UART_MUTEX_UNLOCK(); UART_MUTEX_UNLOCK();
} }
// void uartDisableInterrupt(uart_t* uart)
void uartSetHwFlowCtrlMode(uart_t *uart, uint8_t mode, uint8_t threshold) { {
UART_MUTEX_LOCK();
uart->dev->conf1.val = 0;
uart->dev->int_ena.val = 0;
uart->dev->int_clr.val = 0xffffffff;
esp_intr_free(uart->intr_handle);
uart->intr_handle = NULL;
UART_MUTEX_UNLOCK();
}
void uartDetachRx(uart_t* uart, uint8_t rxPin)
{
if(uart == NULL) { if(uart == NULL) {
return; return;
} }
// IDF will issue corresponding error message when mode or threshold are wrong and prevent crashing pinMatrixInDetach(rxPin, false, false);
// IDF will check (mode > HW_FLOWCTRL_CTS_RTS || threshold >= SOC_UART_FIFO_LEN) uartDisableInterrupt(uart);
uart_set_hw_flow_ctrl(uart->num, (uart_hw_flowcontrol_t) mode, threshold);
} }
void uartDetachTx(uart_t* uart, uint8_t txPin)
uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t rx_buffer_size, uint16_t tx_buffer_size, bool inverted, uint8_t rxfifo_full_thrhd)
{ {
if(uart_nr >= SOC_UART_NUM) { if(uart == NULL) {
return;
}
pinMatrixOutDetach(txPin, false, false);
}
void uartAttachRx(uart_t* uart, uint8_t rxPin, bool inverted)
{
if(uart == NULL || rxPin >= GPIO_PIN_COUNT) {
return;
}
pinMode(rxPin, INPUT);
uartEnableInterrupt(uart);
pinMatrixInAttach(rxPin, UART_RXD_IDX(uart->num), inverted);
}
void uartAttachTx(uart_t* uart, uint8_t txPin, bool inverted)
{
if(uart == NULL || txPin >= GPIO_PIN_COUNT) {
return;
}
pinMode(txPin, OUTPUT);
pinMatrixOutAttach(txPin, UART_TXD_IDX(uart->num), inverted, false);
}
uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t queueLen, bool inverted)
{
if(uart_nr >= UART_PORTS_NUM) {
return NULL;
}
if(rxPin == -1 && txPin == -1) {
return NULL; return NULL;
} }
uart_t* uart = &_uart_bus_array[uart_nr]; uart_t* uart = &_uart_bus_array[uart_nr];
if (uart_is_driver_installed(uart_nr)) {
uartEnd(uart);
}
#if !CONFIG_DISABLE_HAL_LOCKS #if !CONFIG_DISABLE_HAL_LOCKS
if(uart->lock == NULL) { if(uart->lock == NULL) {
uart->lock = xSemaphoreCreateMutex(); uart->lock = xSemaphoreCreateMutex();
@ -151,143 +219,175 @@ uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rx
} }
#endif #endif
UART_MUTEX_LOCK(); if(queueLen && uart->queue == NULL) {
uart->queue = xQueueCreate(queueLen, sizeof(uint8_t)); //initialize the queue
uart_config_t uart_config; if(uart->queue == NULL) {
uart_config.baud_rate = _get_effective_baudrate(baudrate); return NULL;
uart_config.data_bits = (config & 0xc) >> 2;
uart_config.parity = (config & 0x3);
uart_config.stop_bits = (config & 0x30) >> 4;
uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
uart_config.rx_flow_ctrl_thresh = rxfifo_full_thrhd;
uart_config.source_clk = UART_SCLK_APB;
ESP_ERROR_CHECK(uart_driver_install(uart_nr, rx_buffer_size, tx_buffer_size, 20, &(uart->uart_event_queue), 0));
ESP_ERROR_CHECK(uart_param_config(uart_nr, &uart_config));
ESP_ERROR_CHECK(uart_set_pin(uart_nr, txPin, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
// Is it right or the idea is to swap rx and tx pins?
if (inverted) {
// invert signal for both Rx and Tx
ESP_ERROR_CHECK(uart_set_line_inverse(uart_nr, UART_SIGNAL_TXD_INV | UART_SIGNAL_RXD_INV));
} }
}
if(uart_nr == 1){
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART1_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART1_RST);
#if CONFIG_IDF_TARGET_ESP32
} else if(uart_nr == 2){
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART2_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART2_RST);
#endif
} else {
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART_RST);
}
uartFlush(uart);
uartSetBaudRate(uart, baudrate);
UART_MUTEX_LOCK();
uart->dev->conf0.val = config;
#define TWO_STOP_BITS_CONF 0x3
#define ONE_STOP_BITS_CONF 0x1
if ( uart->dev->conf0.stop_bit_num == TWO_STOP_BITS_CONF) {
uart->dev->conf0.stop_bit_num = ONE_STOP_BITS_CONF;
uart->dev->rs485_conf.dl1_en = 1;
}
// tx_idle_num : idle interval after tx FIFO is empty(unit: the time it takes to send one bit under current baudrate)
// Setting it to 0 prevents line idle time/delays when sending messages with small intervals
uart->dev->idle_conf.tx_idle_num = 0; //
UART_MUTEX_UNLOCK(); UART_MUTEX_UNLOCK();
uartFlush(uart); if(rxPin != -1) {
uartAttachRx(uart, rxPin, inverted);
}
if(txPin != -1) {
uartAttachTx(uart, txPin, inverted);
}
addApbChangeCallback(uart, uart_on_apb_change);
return uart; return uart;
} }
void uartEnd(uart_t* uart) void uartEnd(uart_t* uart, uint8_t txPin, uint8_t rxPin)
{ {
if(uart == NULL) { if(uart == NULL) {
return; return;
} }
removeApbChangeCallback(uart, uart_on_apb_change);
UART_MUTEX_LOCK(); UART_MUTEX_LOCK();
uart_driver_delete(uart->num); if(uart->queue != NULL) {
vQueueDelete(uart->queue);
uart->queue = NULL;
}
uart->dev->conf0.val = 0;
UART_MUTEX_UNLOCK(); UART_MUTEX_UNLOCK();
uartDetachRx(uart, rxPin);
uartDetachTx(uart, txPin);
} }
size_t uartResizeRxBuffer(uart_t * uart, size_t new_size) {
void uartSetRxInvert(uart_t* uart, bool invert)
{
if (uart == NULL)
return;
#if 0
// POTENTIAL ISSUE :: original code only set/reset rxd_inv bit
// IDF or LL set/reset the whole inv_mask!
if (invert)
ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_RXD_INV));
else
ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_INV_DISABLE));
#else
// this implementation is better over IDF API because it only affects RXD
// this is supported in ESP32, ESP32-S2 and ESP32-C3
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
if (invert)
hw->conf0.rxd_inv = 1;
else
hw->conf0.rxd_inv = 0;
#endif
}
uint32_t uartAvailable(uart_t* uart)
{
if(uart == NULL) { if(uart == NULL) {
return 0; return 0;
} }
UART_MUTEX_LOCK(); UART_MUTEX_LOCK();
size_t available; if(uart->queue != NULL) {
uart_get_buffered_data_len(uart->num, &available); vQueueDelete(uart->queue);
if (uart->has_peek) available++; uart->queue = xQueueCreate(new_size, sizeof(uint8_t));
if(uart->queue == NULL) {
UART_MUTEX_UNLOCK(); UART_MUTEX_UNLOCK();
return available; return 0;
}
}
UART_MUTEX_UNLOCK();
return new_size;
} }
void uartSetRxInvert(uart_t* uart, bool invert)
{
if (uart == NULL)
return;
if (invert)
uart->dev->conf0.rxd_inv = 1;
else
uart->dev->conf0.rxd_inv = 0;
}
uint32_t uartAvailable(uart_t* uart)
{
if(uart == NULL || uart->queue == NULL) {
return 0;
}
return (uxQueueMessagesWaiting(uart->queue) + uart->dev->status.rxfifo_cnt) ;
}
uint32_t uartAvailableForWrite(uart_t* uart) uint32_t uartAvailableForWrite(uart_t* uart)
{ {
if(uart == NULL) { if(uart == NULL) {
return 0; return 0;
} }
UART_MUTEX_LOCK(); return 0x7f - uart->dev->status.txfifo_cnt;
uint32_t available = uart_ll_get_txfifo_len(UART_LL_GET_HW(uart->num));
UART_MUTEX_UNLOCK();
return available;
} }
void uartRxFifoToQueue(uart_t* uart)
{
uint8_t c;
UART_MUTEX_LOCK();
//disable interrupts
uart->dev->int_ena.val = 0;
uart->dev->int_clr.val = 0xffffffff;
#if CONFIG_IDF_TARGET_ESP32
while (uart->dev->status.rxfifo_cnt || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) {
c = uart->dev->fifo.rw_byte;
#else
uint32_t fifo_reg = UART_FIFO_AHB_REG(uart->num);
while (uart->dev->status.rxfifo_cnt) {
c = ESP_REG(fifo_reg);
#endif
xQueueSend(uart->queue, &c, 0);
}
//enable interrupts
uart->dev->int_ena.rxfifo_full = 1;
uart->dev->int_ena.frm_err = 1;
uart->dev->int_ena.rxfifo_tout = 1;
uart->dev->int_clr.val = 0xffffffff;
UART_MUTEX_UNLOCK();
}
uint8_t uartRead(uart_t* uart) uint8_t uartRead(uart_t* uart)
{ {
if(uart == NULL) { if(uart == NULL || uart->queue == NULL) {
return 0; return 0;
} }
uint8_t c = 0; uint8_t c;
if ((uxQueueMessagesWaiting(uart->queue) == 0) && (uart->dev->status.rxfifo_cnt > 0))
UART_MUTEX_LOCK(); {
uartRxFifoToQueue(uart);
if (uart->has_peek) {
uart->has_peek = false;
c = uart->peek_byte;
} else {
int len = uart_read_bytes(uart->num, &c, 1, 20 / portTICK_RATE_MS);
if (len == 0) {
c = 0;
} }
} if(xQueueReceive(uart->queue, &c, 0)) {
UART_MUTEX_UNLOCK();
return c; return c;
}
return 0;
} }
uint8_t uartPeek(uart_t* uart) uint8_t uartPeek(uart_t* uart)
{ {
if(uart == NULL) { if(uart == NULL || uart->queue == NULL) {
return 0; return 0;
} }
uint8_t c = 0; uint8_t c;
if ((uxQueueMessagesWaiting(uart->queue) == 0) && (uart->dev->status.rxfifo_cnt > 0))
UART_MUTEX_LOCK(); {
uartRxFifoToQueue(uart);
if (uart->has_peek) {
c = uart->peek_byte;
} else {
int len = uart_read_bytes(uart->num, &c, 1, 20 / portTICK_RATE_MS);
if (len == 0) {
c = 0;
} else {
uart->has_peek = true;
uart->peek_byte = c;
} }
} if(xQueuePeek(uart->queue, &c, 0)) {
UART_MUTEX_UNLOCK();
return c; return c;
}
return 0;
} }
void uartWrite(uart_t* uart, uint8_t c) void uartWrite(uart_t* uart, uint8_t c)
@ -296,24 +396,39 @@ void uartWrite(uart_t* uart, uint8_t c)
return; return;
} }
UART_MUTEX_LOCK(); UART_MUTEX_LOCK();
uart_write_bytes(uart->num, &c, 1); while(uart->dev->status.txfifo_cnt == 0x7F);
#if CONFIG_IDF_TARGET_ESP32
uart->dev->fifo.rw_byte = c;
#else
ESP_REG(UART_FIFO_AHB_REG(uart->num)) = c;
#endif
UART_MUTEX_UNLOCK(); UART_MUTEX_UNLOCK();
} }
void uartWriteBuf(uart_t* uart, const uint8_t * data, size_t len) void uartWriteBuf(uart_t* uart, const uint8_t * data, size_t len)
{ {
if(uart == NULL || data == NULL || !len) { if(uart == NULL) {
return; return;
} }
UART_MUTEX_LOCK(); UART_MUTEX_LOCK();
uart_write_bytes(uart->num, data, len); #ifndef CONFIG_IDF_TARGET_ESP32
uint32_t fifo_reg = UART_FIFO_AHB_REG(uart->num);
#endif
while(len) {
while(uart->dev->status.txfifo_cnt == 0x7F);
#if CONFIG_IDF_TARGET_ESP32
uart->dev->fifo.rw_byte = *data++;
#else
ESP_REG(fifo_reg) = *data++;
#endif
len--;
}
UART_MUTEX_UNLOCK(); UART_MUTEX_UNLOCK();
} }
void uartFlush(uart_t* uart) void uartFlush(uart_t* uart)
{ {
uartFlushTxOnly(uart, true); uartFlushTxOnly(uart,true);
} }
void uartFlushTxOnly(uart_t* uart, bool txOnly) void uartFlushTxOnly(uart_t* uart, bool txOnly)
@ -323,11 +438,26 @@ void uartFlushTxOnly(uart_t* uart, bool txOnly)
} }
UART_MUTEX_LOCK(); UART_MUTEX_LOCK();
while(!uart_ll_is_tx_idle(UART_LL_GET_HW(uart->num))); #if CONFIG_IDF_TARGET_ESP32
while(uart->dev->status.txfifo_cnt || uart->dev->status.st_utx_out);
if ( !txOnly ) { if( !txOnly ){
ESP_ERROR_CHECK(uart_flush_input(uart->num)); //Due to hardware issue, we can not use fifo_rst to reset uart fifo.
//See description about UART_TXFIFO_RST and UART_RXFIFO_RST in <<esp32_technical_reference_manual>> v2.6 or later.
// we read the data out and make `fifo_len == 0 && rd_addr == wr_addr`.
while(uart->dev->status.rxfifo_cnt != 0 || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) {
READ_PERI_REG(UART_FIFO_REG(uart->num));
} }
xQueueReset(uart->queue);
}
#else
while(uart->dev->status.txfifo_cnt);
uart->dev->conf0.txfifo_rst = 1;
uart->dev->conf0.txfifo_rst = 0;
#endif
UART_MUTEX_UNLOCK(); UART_MUTEX_UNLOCK();
} }
@ -337,41 +467,102 @@ void uartSetBaudRate(uart_t* uart, uint32_t baud_rate)
return; return;
} }
UART_MUTEX_LOCK(); UART_MUTEX_LOCK();
uart_ll_set_baudrate(UART_LL_GET_HW(uart->num), _get_effective_baudrate(baud_rate)); uint32_t clk_div = ((getApbFrequency()<<4)/baud_rate);
uart->dev->clk_div.div_int = clk_div>>4 ;
uart->dev->clk_div.div_frag = clk_div & 0xf;
UART_MUTEX_UNLOCK(); UART_MUTEX_UNLOCK();
} }
static void uart_on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb)
{
uart_t* uart = (uart_t*)arg;
if(ev_type == APB_BEFORE_CHANGE){
UART_MUTEX_LOCK();
//disabple interrupt
uart->dev->int_ena.val = 0;
uart->dev->int_clr.val = 0xffffffff;
// read RX fifo
uint8_t c;
// BaseType_t xHigherPriorityTaskWoken;
#if CONFIG_IDF_TARGET_ESP32
while(uart->dev->status.rxfifo_cnt != 0 || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) {
c = uart->dev->fifo.rw_byte;
#else
uint32_t fifo_reg = UART_FIFO_AHB_REG(uart->num);
while(uart->dev->status.rxfifo_cnt != 0) {
c = ESP_REG(fifo_reg);
#endif
if(uart->queue != NULL ) {
xQueueSend(uart->queue, &c, 1); //&xHigherPriorityTaskWoken);
}
}
UART_MUTEX_UNLOCK();
// wait TX empty
#if CONFIG_IDF_TARGET_ESP32
while(uart->dev->status.txfifo_cnt || uart->dev->status.st_utx_out);
#else
while(uart->dev->status.txfifo_cnt);
#endif
} else {
//todo:
// set baudrate
UART_MUTEX_LOCK();
uint32_t clk_div = (uart->dev->clk_div.div_int << 4) | (uart->dev->clk_div.div_frag & 0x0F);
uint32_t baud_rate = ((old_apb<<4)/clk_div);
clk_div = ((new_apb<<4)/baud_rate);
uart->dev->clk_div.div_int = clk_div>>4 ;
uart->dev->clk_div.div_frag = clk_div & 0xf;
//enable interrupts
uart->dev->int_ena.rxfifo_full = 1;
uart->dev->int_ena.frm_err = 1;
uart->dev->int_ena.rxfifo_tout = 1;
uart->dev->int_clr.val = 0xffffffff;
UART_MUTEX_UNLOCK();
}
}
uint32_t uartGetBaudRate(uart_t* uart) uint32_t uartGetBaudRate(uart_t* uart)
{ {
if(uart == NULL) { if(uart == NULL) {
return 0; return 0;
} }
UART_MUTEX_LOCK(); uint32_t clk_div = (uart->dev->clk_div.div_int << 4) | (uart->dev->clk_div.div_frag & 0x0F);
uint32_t baud_rate = uart_ll_get_baudrate(UART_LL_GET_HW(uart->num)); if(!clk_div) {
UART_MUTEX_UNLOCK(); return 0;
return baud_rate; }
return ((getApbFrequency()<<4)/clk_div);
} }
static void ARDUINO_ISR_ATTR uart0_write_char(char c) static void ARDUINO_ISR_ATTR uart0_write_char(char c)
{ {
while (uart_ll_get_txfifo_len(&UART0) == 0); #if CONFIG_IDF_TARGET_ESP32
uart_ll_write_txfifo(&UART0, (const uint8_t *) &c, 1); while(((ESP_REG(0x01C+DR_REG_UART_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) == 0x7F);
ESP_REG(DR_REG_UART_BASE) = c;
#else
while(UART0.status.txfifo_cnt == 0x7F);
WRITE_PERI_REG(UART_FIFO_AHB_REG(0), c);
#endif
} }
#if SOC_UART_NUM > 1
static void ARDUINO_ISR_ATTR uart1_write_char(char c) static void ARDUINO_ISR_ATTR uart1_write_char(char c)
{ {
while (uart_ll_get_txfifo_len(&UART1) == 0); #if CONFIG_IDF_TARGET_ESP32
uart_ll_write_txfifo(&UART1, (const uint8_t *) &c, 1); while(((ESP_REG(0x01C+DR_REG_UART1_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) == 0x7F);
} ESP_REG(DR_REG_UART1_BASE) = c;
#else
while(UART1.status.txfifo_cnt == 0x7F);
WRITE_PERI_REG(UART_FIFO_AHB_REG(1), c);
#endif #endif
}
#if SOC_UART_NUM > 2 #if CONFIG_IDF_TARGET_ESP32
static void ARDUINO_ISR_ATTR uart2_write_char(char c) static void ARDUINO_ISR_ATTR uart2_write_char(char c)
{ {
while (uart_ll_get_txfifo_len(&UART2) == 0); while(((ESP_REG(0x01C+DR_REG_UART2_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) == 0x7F);
uart_ll_write_txfifo(&UART2, (const uint8_t *) &c, 1); ESP_REG(DR_REG_UART2_BASE) = c;
} }
#endif #endif
@ -381,12 +572,10 @@ void uart_install_putc()
case 0: case 0:
ets_install_putc1((void (*)(char)) &uart0_write_char); ets_install_putc1((void (*)(char)) &uart0_write_char);
break; break;
#if SOC_UART_NUM > 1
case 1: case 1:
ets_install_putc1((void (*)(char)) &uart1_write_char); ets_install_putc1((void (*)(char)) &uart1_write_char);
break; break;
#endif #if CONFIG_IDF_TARGET_ESP32
#if SOC_UART_NUM > 2
case 2: case 2:
ets_install_putc1((void (*)(char)) &uart2_write_char); ets_install_putc1((void (*)(char)) &uart2_write_char);
break; break;
@ -399,11 +588,15 @@ void uart_install_putc()
void uartSetDebug(uart_t* uart) void uartSetDebug(uart_t* uart)
{ {
if(uart == NULL || uart->num >= SOC_UART_NUM) { if(uart == NULL || uart->num >= UART_PORTS_NUM) {
s_uart_debug_nr = -1; s_uart_debug_nr = -1;
} else { //ets_install_putc1(NULL);
//return;
} else
if(s_uart_debug_nr == uart->num) {
return;
} else
s_uart_debug_nr = uart->num; s_uart_debug_nr = uart->num;
}
uart_install_putc(); uart_install_putc();
} }
@ -421,28 +614,25 @@ int log_printf(const char *format, ...)
va_list copy; va_list copy;
va_start(arg, format); va_start(arg, format);
va_copy(copy, arg); va_copy(copy, arg);
len = vsnprintf(NULL, 0, format, copy); len = vsnprintf(NULL, 0, format, arg);
va_end(copy); va_end(copy);
if(len >= sizeof(loc_buf)){ if(len >= sizeof(loc_buf)){
temp = (char*)malloc(len+1); temp = (char*)malloc(len+1);
if(temp == NULL) { if(temp == NULL) {
va_end(arg);
return 0; return 0;
} }
} }
vsnprintf(temp, len+1, format, arg);
#if !CONFIG_DISABLE_HAL_LOCKS #if !CONFIG_DISABLE_HAL_LOCKS
if(s_uart_debug_nr != -1 && _uart_bus_array[s_uart_debug_nr].lock){ if(s_uart_debug_nr != -1 && _uart_bus_array[s_uart_debug_nr].lock){
xSemaphoreTake(_uart_bus_array[s_uart_debug_nr].lock, portMAX_DELAY); xSemaphoreTake(_uart_bus_array[s_uart_debug_nr].lock, portMAX_DELAY);
}
#endif
vsnprintf(temp, len+1, format, arg);
ets_printf("%s", temp); ets_printf("%s", temp);
#if !CONFIG_DISABLE_HAL_LOCKS
if(s_uart_debug_nr != -1 && _uart_bus_array[s_uart_debug_nr].lock){
xSemaphoreGive(_uart_bus_array[s_uart_debug_nr].lock); xSemaphoreGive(_uart_bus_array[s_uart_debug_nr].lock);
} else {
ets_printf("%s", temp);
} }
#else
ets_printf("%s", temp);
#endif #endif
va_end(arg); va_end(arg);
if(len >= sizeof(loc_buf)){ if(len >= sizeof(loc_buf)){
@ -451,128 +641,46 @@ int log_printf(const char *format, ...)
return len; return len;
} }
static void log_print_buf_line(const uint8_t *b, size_t len, size_t total_len){
for(size_t i = 0; i<len; i++){
log_printf("%s0x%02x,",i?" ":"", b[i]);
}
if(total_len > 16){
for(size_t i = len; i<16; i++){
log_printf(" ");
}
log_printf(" // ");
} else {
log_printf(" // ");
}
for(size_t i = 0; i<len; i++){
log_printf("%c",((b[i] >= 0x20) && (b[i] < 0x80))?b[i]:'.');
}
log_printf("\n");
}
void log_print_buf(const uint8_t *b, size_t len){
if(!len || !b){
return;
}
for(size_t i = 0; i<len; i+=16){
if(len > 16){
log_printf("/* 0x%04X */ ", i);
}
log_print_buf_line(b+i, ((len-i)<16)?(len - i):16, len);
}
}
/* /*
* if enough pulses are detected return the minimum high pulse duration + minimum low pulse duration divided by two. * if enough pulses are detected return the minimum high pulse duration + minimum low pulse duration divided by two.
* This equals one bit period. If flag is true the function return inmediately, otherwise it waits for enough pulses. * This equals one bit period. If flag is true the function return inmediately, otherwise it waits for enough pulses.
*/ */
unsigned long uartBaudrateDetect(uart_t *uart, bool flg) unsigned long uartBaudrateDetect(uart_t *uart, bool flg)
{ {
#ifndef CONFIG_IDF_TARGET_ESP32S3 while(uart->dev->rxd_cnt.edge_cnt < 30) { // UART_PULSE_NUM(uart_num)
if(uart == NULL) {
return 0;
}
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
while(hw->rxd_cnt.edge_cnt < 30) { // UART_PULSE_NUM(uart_num)
if(flg) return 0; if(flg) return 0;
ets_delay_us(1000); ets_delay_us(1000);
} }
UART_MUTEX_LOCK(); UART_MUTEX_LOCK();
//log_i("lowpulse_min_cnt = %d hightpulse_min_cnt = %d", hw->lowpulse.min_cnt, hw->highpulse.min_cnt); unsigned long ret = ((uart->dev->lowpulse.min_cnt + uart->dev->highpulse.min_cnt) >> 1) + 12;
unsigned long ret = ((hw->lowpulse.min_cnt + hw->highpulse.min_cnt) >> 1);
UART_MUTEX_UNLOCK(); UART_MUTEX_UNLOCK();
return ret; return ret;
#else
return 0;
#endif
} }
/* /*
* To start detection of baud rate with the uart the auto_baud.en bit needs to be cleared and set. The bit period is * To start detection of baud rate with the uart the auto_baud.en bit needs to be cleared and set. The bit period is
* detected calling uartBadrateDetect(). The raw baudrate is computed using the UART_CLK_FREQ. The raw baudrate is * detected calling uartBadrateDetect(). The raw baudrate is computed using the UART_CLK_FREQ. The raw baudrate is
* rounded to the closed real baudrate. * rounded to the closed real baudrate.
*
* ESP32-C3 reports wrong baud rate detection as shown below:
*
* This will help in a future recall for the C3.
* Baud Sent: Baud Read:
* 300 --> 19536
* 2400 --> 19536
* 4800 --> 19536
* 9600 --> 28818
* 19200 --> 57678
* 38400 --> 115440
* 57600 --> 173535
* 115200 --> 347826
* 230400 --> 701754
*
*
*/ */
void uartStartDetectBaudrate(uart_t *uart) { void uartStartDetectBaudrate(uart_t *uart) {
if(uart == NULL) { if(!uart) return;
return;
}
#ifdef CONFIG_IDF_TARGET_ESP32C3 uart->dev->auto_baud.glitch_filt = 0x08;
uart->dev->auto_baud.en = 0;
// ESP32-C3 requires further testing uart->dev->auto_baud.en = 1;
// Baud rate detection returns wrong values
log_e("ESP32-C3 baud rate detection is not supported.");
return;
// Code bellow for C3 kept for future recall
//hw->rx_filt.glitch_filt = 0x08;
//hw->rx_filt.glitch_filt_en = 1;
//hw->conf0.autobaud_en = 0;
//hw->conf0.autobaud_en = 1;
#elif CONFIG_IDF_TARGET_ESP32S3
#else
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
hw->auto_baud.glitch_filt = 0x08;
hw->auto_baud.en = 0;
hw->auto_baud.en = 1;
#endif
} }
unsigned long unsigned long
uartDetectBaudrate(uart_t *uart) uartDetectBaudrate(uart_t *uart)
{ {
if(uart == NULL) {
return 0;
}
#ifndef CONFIG_IDF_TARGET_ESP32C3 // ESP32-C3 requires further testing - Baud rate detection returns wrong values
static bool uartStateDetectingBaudrate = false; static bool uartStateDetectingBaudrate = false;
if(!uartStateDetectingBaudrate) { if(!uartStateDetectingBaudrate) {
uartStartDetectBaudrate(uart); uart->dev->auto_baud.glitch_filt = 0x08;
uart->dev->auto_baud.en = 0;
uart->dev->auto_baud.en = 1;
uartStateDetectingBaudrate = true; uartStateDetectingBaudrate = true;
} }
@ -580,23 +688,11 @@ uartDetectBaudrate(uart_t *uart)
if (!divisor) { if (!divisor) {
return 0; return 0;
} }
// log_i(...) below has been used to check C3 baud rate detection results
//log_i("Divisor = %d\n", divisor);
//log_i("BAUD RATE based on Positive Pulse %d\n", getApbFrequency()/((hw->pospulse.min_cnt + 1)/2));
//log_i("BAUD RATE based on Negative Pulse %d\n", getApbFrequency()/((hw->negpulse.min_cnt + 1)/2));
uart->dev->auto_baud.en = 0;
#ifdef CONFIG_IDF_TARGET_ESP32C3
//hw->conf0.autobaud_en = 0;
#elif CONFIG_IDF_TARGET_ESP32S3
#else
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
hw->auto_baud.en = 0;
#endif
uartStateDetectingBaudrate = false; // Initialize for the next round uartStateDetectingBaudrate = false; // Initialize for the next round
unsigned long baudrate = getApbFrequency() / divisor; unsigned long baudrate = getApbFrequency() / divisor;
//log_i("APB_FREQ = %d\nraw baudrate detected = %d", getApbFrequency(), baudrate);
static const unsigned long default_rates[] = {300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 74880, 115200, 230400, 256000, 460800, 921600, 1843200, 3686400}; static const unsigned long default_rates[] = {300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 74880, 115200, 230400, 256000, 460800, 921600, 1843200, 3686400};
@ -613,8 +709,15 @@ uartDetectBaudrate(uart_t *uart)
} }
return default_rates[i]; return default_rates[i];
}
/*
* Returns the status of the RX state machine, if the value is non-zero the state machine is active.
*/
bool uartRxActive(uart_t* uart) {
#if CONFIG_IDF_TARGET_ESP32
return uart->dev->status.st_urx_out != 0;
#else #else
log_e("ESP32-C3 baud rate detection is not supported.");
return 0; return 0;
#endif #endif
} }

View File

@ -22,8 +22,6 @@ extern "C" {
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#define SERIAL_5N1 0x8000010 #define SERIAL_5N1 0x8000010
#define SERIAL_6N1 0x8000014 #define SERIAL_6N1 0x8000014
@ -50,22 +48,11 @@ extern "C" {
#define SERIAL_7O2 0x800003b #define SERIAL_7O2 0x800003b
#define SERIAL_8O2 0x800003f #define SERIAL_8O2 0x800003f
// These are Hardware Flow Contol possible usage
// equivalent to UDF enum uart_hw_flowcontrol_t from
// https://github.com/espressif/esp-idf/blob/master/components/hal/include/hal/uart_types.h#L75-L81
#define HW_FLOWCTRL_DISABLE 0x0 // disable HW Flow Control
#define HW_FLOWCTRL_RTS 0x1 // use only RTS PIN for HW Flow Control
#define HW_FLOWCTRL_CTS 0x2 // use only CTS PIN for HW Flow Control
#define HW_FLOWCTRL_CTS_RTS 0x3 // use both CTS and RTS PIN for HW Flow Control
struct uart_struct_t; struct uart_struct_t;
typedef struct uart_struct_t uart_t; typedef struct uart_struct_t uart_t;
uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t rx_buffer_size, uint16_t tx_buffer_size, bool inverted, uint8_t rxfifo_full_thrhd); uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t queueLen, bool inverted);
void uartEnd(uart_t* uart); void uartEnd(uart_t* uart, uint8_t rxPin, uint8_t txPin);
// This is used to retrieve the Event Queue pointer from a UART IDF Driver in order to allow user to deal with its events
void uartGetEventQueue(uart_t* uart, QueueHandle_t *q);
uint32_t uartAvailable(uart_t* uart); uint32_t uartAvailable(uart_t* uart);
uint32_t uartAvailableForWrite(uart_t* uart); uint32_t uartAvailableForWrite(uart_t* uart);
@ -81,22 +68,17 @@ void uartFlushTxOnly(uart_t* uart, bool txOnly );
void uartSetBaudRate(uart_t* uart, uint32_t baud_rate); void uartSetBaudRate(uart_t* uart, uint32_t baud_rate);
uint32_t uartGetBaudRate(uart_t* uart); uint32_t uartGetBaudRate(uart_t* uart);
size_t uartResizeRxBuffer(uart_t* uart, size_t new_size);
void uartSetRxInvert(uart_t* uart, bool invert); void uartSetRxInvert(uart_t* uart, bool invert);
void uartSetDebug(uart_t* uart); void uartSetDebug(uart_t* uart);
int uartGetDebug(); int uartGetDebug();
bool uartIsDriverInstalled(uart_t* uart);
// Negative Pin Number will keep it unmodified, thus this function can set individual pins
void uartSetPins(uart_t* uart, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin);
// Enables or disables HW Flow Control function -- needs also to set CTS and/or RTS pins
void uartSetHwFlowCtrlMode(uart_t *uart, uint8_t mode, uint8_t threshold);
void uartStartDetectBaudrate(uart_t *uart); void uartStartDetectBaudrate(uart_t *uart);
unsigned long uartDetectBaudrate(uart_t *uart); unsigned long uartDetectBaudrate(uart_t *uart);
bool uartRxActive(uart_t* uart);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -31,11 +31,6 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#include "esp_system.h" #include "esp_system.h"
#include "esp_sleep.h" #include "esp_sleep.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "freertos/event_groups.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -90,14 +85,9 @@ void yield(void);
#include "esp32-hal-psram.h" #include "esp32-hal-psram.h"
#include "esp32-hal-cpu.h" #include "esp32-hal-cpu.h"
void analogWrite(uint8_t pin, int value);
//returns chip temperature in Celsius //returns chip temperature in Celsius
float temperatureRead(); float temperatureRead();
//allows user to bypass SPI RAM test routine
bool testSPIRAM(void);
#if CONFIG_AUTOSTART_ARDUINO #if CONFIG_AUTOSTART_ARDUINO
//enable/disable WDT for Arduino's setup and loop functions //enable/disable WDT for Arduino's setup and loop functions
void enableLoopWDT(); void enableLoopWDT();

View File

@ -23,7 +23,7 @@ extern "C" {
/** Minor version number (x.X.x) */ /** Minor version number (x.X.x) */
#define ESP_ARDUINO_VERSION_MINOR 0 #define ESP_ARDUINO_VERSION_MINOR 0
/** Patch version number (x.x.X) */ /** Patch version number (x.x.X) */
#define ESP_ARDUINO_VERSION_PATCH 4 #define ESP_ARDUINO_VERSION_PATCH 0
/** /**
* Macro to convert ARDUINO version number into an integer * Macro to convert ARDUINO version number into an integer

View File

@ -1,204 +0,0 @@
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "firmware_msc_fat.h"
//copy up to max_len chars from src to dst and do not terminate
static size_t cplstr(void *dst, const void * src, size_t max_len){
if(!src || !dst || !max_len){
return 0;
}
size_t l = strlen((const char *)src);
if(l > max_len){
l = max_len;
}
memcpy(dst, src, l);
return l;
}
//copy up to max_len chars from src to dst, adding spaces up to max_len. do not terminate
static void cplstrsp(void *dst, const void * src, size_t max_len){
size_t l = cplstr(dst, src, max_len);
for(; l < max_len; l++){
((uint8_t*)dst)[l] = 0x20;
}
}
// FAT12
static const char * FAT12_FILE_SYSTEM_TYPE = "FAT12";
static uint16_t fat12_sectors_per_alloc_table(uint32_t sector_num){
uint32_t required_bytes = (((sector_num * 3)+1)/2);
return (required_bytes / DISK_SECTOR_SIZE) + ((required_bytes & (DISK_SECTOR_SIZE - 1))?1:0);
}
static uint8_t * fat12_add_table(uint8_t * dst, fat_boot_sector_t * boot){
memset(dst+DISK_SECTOR_SIZE, 0, boot->sectors_per_alloc_table * DISK_SECTOR_SIZE);
uint8_t * d = dst + DISK_SECTOR_SIZE;
d[0] = 0xF8;
d[1] = 0xFF;
d[2] = 0xFF;
return d;
}
static void fat12_set_table_index(uint8_t * table, uint16_t index, uint16_t value){
uint16_t offset = (index >> 1) * 3;
uint8_t * data = table + offset;
if(index & 1){
data[2] = (value >> 4) & 0xFF;
data[1] = (data[1] & 0xF) | ((value & 0xF) << 4);
} else {
data[0] = value & 0xFF;
data[1] = (data[1] & 0xF0) | ((value >> 8) & 0xF);
}
}
//FAT16
static const char * FAT16_FILE_SYSTEM_TYPE = "FAT16";
static uint16_t fat16_sectors_per_alloc_table(uint32_t sector_num){
uint32_t required_bytes = sector_num * 2;
return (required_bytes / DISK_SECTOR_SIZE) + ((required_bytes & (DISK_SECTOR_SIZE - 1))?1:0);
}
static uint8_t * fat16_add_table(uint8_t * dst, fat_boot_sector_t * boot){
memset(dst+DISK_SECTOR_SIZE, 0, boot->sectors_per_alloc_table * DISK_SECTOR_SIZE);
uint16_t * d = (uint16_t *)(dst + DISK_SECTOR_SIZE);
d[0] = 0xFFF8;
d[1] = 0xFFFF;
return (uint8_t *)d;
}
static void fat16_set_table_index(uint8_t * table, uint16_t index, uint16_t value){
uint16_t offset = index * 2;
*(uint16_t *)(table + offset) = value;
}
//Interface
const char * fat_file_system_type(bool fat16) {
return ((fat16)?FAT16_FILE_SYSTEM_TYPE:FAT12_FILE_SYSTEM_TYPE);
}
uint16_t fat_sectors_per_alloc_table(uint32_t sector_num, bool fat16){
if(fat16){
return fat16_sectors_per_alloc_table(sector_num);
}
return fat12_sectors_per_alloc_table(sector_num);
}
uint8_t * fat_add_table(uint8_t * dst, fat_boot_sector_t * boot, bool fat16){
if(fat16){
return fat16_add_table(dst, boot);
}
return fat12_add_table(dst, boot);
}
void fat_set_table_index(uint8_t * table, uint16_t index, uint16_t value, bool fat16){
if(fat16){
fat16_set_table_index(table, index, value);
} else {
fat12_set_table_index(table, index, value);
}
}
fat_boot_sector_t * fat_add_boot_sector(uint8_t * dst, uint16_t sector_num, uint16_t table_sectors, const char * file_system_type, const char * volume_label, uint32_t serial_number){
fat_boot_sector_t *boot = (fat_boot_sector_t*)dst;
boot->jump_instruction[0] = 0xEB;
boot->jump_instruction[1] = 0x3C;
boot->jump_instruction[2] = 0x90;
cplstr(boot->oem_name, "MSDOS5.0", 8);
boot->bytes_per_sector = DISK_SECTOR_SIZE;
boot->sectors_per_cluster = 1;
boot->reserved_sectors_count = 1;
boot->file_alloc_tables_num = 1;
boot->max_root_dir_entries = 16;
boot->fat12_sector_num = sector_num;
boot->media_descriptor = 0xF8;
boot->sectors_per_alloc_table = table_sectors;
boot->sectors_per_track = 1;
boot->num_heads = 1;
boot->hidden_sectors_count = 0;
boot->total_sectors_32 = 0;
boot->physical_drive_number = 0x80;
boot->reserved0 = 0x00;
boot->extended_boot_signature = 0x29;
boot->serial_number = serial_number;
cplstrsp(boot->volume_label, volume_label, 11);
memset(boot->reserved, 0, 448);
cplstrsp(boot->file_system_type, file_system_type, 8);
boot->signature = 0xAA55;
return boot;
}
fat_dir_entry_t * fat_add_label(uint8_t * dst, const char * volume_label){
fat_boot_sector_t * boot = (fat_boot_sector_t *)dst;
fat_dir_entry_t * entry = (fat_dir_entry_t *)(dst + ((boot->sectors_per_alloc_table+1) * DISK_SECTOR_SIZE));
memset(entry, 0, sizeof(fat_dir_entry_t));
cplstrsp(entry->volume_label, volume_label, 11);
entry->file_attr = FAT_FILE_ATTR_VOLUME_LABEL;
return entry;
}
fat_dir_entry_t * fat_add_root_file(uint8_t * dst, uint8_t index, const char * file_name, const char * file_extension, size_t file_size, uint16_t data_start_sector, bool is_fat16){
fat_boot_sector_t * boot = (fat_boot_sector_t *)dst;
uint8_t * table = dst + DISK_SECTOR_SIZE;
fat_dir_entry_t * entry = (fat_dir_entry_t *)(dst + ((boot->sectors_per_alloc_table+1) * DISK_SECTOR_SIZE) + (index * sizeof(fat_dir_entry_t)));
memset(entry, 0, sizeof(fat_dir_entry_t));
cplstrsp(entry->file_name, file_name, 8);
cplstrsp(entry->file_extension, file_extension, 3);
entry->file_attr = FAT_FILE_ATTR_ARCHIVE;
entry->file_size = file_size;
entry->data_start_sector = data_start_sector;
entry->extended_attr = 0;
uint16_t file_sectors = file_size / DISK_SECTOR_SIZE;
if(file_size % DISK_SECTOR_SIZE){
file_sectors++;
}
uint16_t data_end_sector = data_start_sector + file_sectors;
for(uint16_t i=data_start_sector; i<(data_end_sector-1); i++){
fat_set_table_index(table, i, i+1, is_fat16);
}
fat_set_table_index(table, data_end_sector-1, 0xFFFF, is_fat16);
//Set Firmware Date based on the build time
static const char * month_names_short[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
char mstr[8] = {'\0',};
const char *str = __DATE__ " " __TIME__;
int ms=0, seconds=0, minutes=0, hours=0, year=0, date=0, month=0;
int r = sscanf(str,"%s %d %d %d:%d:%d", mstr, &date, &year, &hours, &minutes, &seconds);
if(r >= 0){
for(int i=0; i<12; i++){
if(!strcmp(mstr, month_names_short[i])){
month = i;
break;
}
}
entry->creation_time_ms = FAT_MS2V(seconds, ms);
entry->creation_time_hms = FAT_HMS2V(hours, minutes, seconds);
entry->creation_time_ymd = FAT_YMD2V(year, month, date);
entry->last_access_ymd = entry->creation_time_ymd;
entry->last_modified_hms = entry->creation_time_hms;
entry->last_modified_ymd = entry->creation_time_ymd;
}
return entry;
}
uint8_t fat_lfn_checksum(const uint8_t *short_filename){
uint8_t sum = 0;
for (uint8_t i = 11; i; i--) {
sum = ((sum & 1) << 7) + (sum >> 1) + *short_filename++;
}
return sum;
}

View File

@ -1,141 +0,0 @@
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
#define FAT_U8(v) ((v) & 0xFF)
#define FAT_U16(v) FAT_U8(v), FAT_U8((v) >> 8)
#define FAT_U32(v) FAT_U8(v), FAT_U8((v) >> 8), FAT_U8((v) >> 16), FAT_U8((v) >> 24)
#define FAT12_TBL2B(l,h) FAT_U8(l), FAT_U8(((l >> 8) & 0xF) | ((h << 4) & 0xF0)), FAT_U8(h >> 4)
#define FAT_MS2B(s,ms) FAT_U8(((((s) & 0x1) * 1000) + (ms)) / 10)
#define FAT_HMS2B(h,m,s) FAT_U8(((s) >> 1)|(((m) & 0x7) << 5)), FAT_U8((((m) >> 3) & 0x7)|((h) << 3))
#define FAT_YMD2B(y,m,d) FAT_U8(((d) & 0x1F)|(((m) & 0x7) << 5)), FAT_U8((((m) >> 3) & 0x1)|((((y) - 1980) & 0x7F) << 1))
#define FAT_MS2V(s,ms) FAT_U8(((((s) & 0x1) * 1000) + (ms)) / 10)
#define FAT_HMS2V(h,m,s) (FAT_U8(((s) >> 1)|(((m) & 0x7) << 5)) | (FAT_U8((((m) >> 3) & 0x7)|((h) << 3)) << 8))
#define FAT_YMD2V(y,m,d) (FAT_U8(((d) & 0x1F)|(((m) & 0x7) << 5)) | (FAT_U8((((m) >> 3) & 0x1)|((((y) - 1980) & 0x7F) << 1)) << 8))
#define FAT_B2HMS(hms) ((hms >> 11) & 0x1F), ((hms >> 5) & 0x3F), ((hms & 0x1F) << 1)
#define FAT_B2YMD(ymd) (((ymd >> 9) & 0x7F) + 1980), ((ymd >> 5) & 0x0F), (ymd & 0x1F)
#define FAT_FILE_ATTR_READ_ONLY 0x01
#define FAT_FILE_ATTR_HIDDEN 0x02
#define FAT_FILE_ATTR_SYSTEM 0x04
#define FAT_FILE_ATTR_VOLUME_LABEL 0x08
#define FAT_FILE_ATTR_SUBDIRECTORY 0x10
#define FAT_FILE_ATTR_ARCHIVE 0x20
#define FAT_FILE_ATTR_DEVICE 0x40
static const uint16_t DISK_SECTOR_SIZE = 512;
#define FAT_SIZE_TO_SECTORS(bytes) ((bytes) / DISK_SECTOR_SIZE) + (((bytes) % DISK_SECTOR_SIZE)?1:0)
typedef struct __attribute__ ((packed)) {
uint8_t jump_instruction[3];
char oem_name[8];//padded with spaces (0x20)
uint16_t bytes_per_sector;//DISK_SECTOR_SIZE usually 512
uint8_t sectors_per_cluster;//Allowed values are 1, 2, 4, 8, 16, 32, 64, and 128
uint16_t reserved_sectors_count;//At least 1 for this sector, usually 32 for FAT32
uint8_t file_alloc_tables_num;//Almost always 2; RAM disks might use 1
uint16_t max_root_dir_entries;//FAT12 and FAT16
uint16_t fat12_sector_num;//DISK_SECTOR_NUM FAT12 and FAT16
uint8_t media_descriptor;
uint16_t sectors_per_alloc_table;//FAT12 and FAT16
uint16_t sectors_per_track;//A value of 0 may indicate LBA-only access
uint16_t num_heads;
uint32_t hidden_sectors_count;
uint32_t total_sectors_32;
uint8_t physical_drive_number;//0x00 for (first) removable media, 0x80 for (first) fixed disk
uint8_t reserved0;
uint8_t extended_boot_signature;//should be 0x29
uint32_t serial_number;//0x1234 => 1234
char volume_label[11];//padded with spaces (0x20)
char file_system_type[8];//padded with spaces (0x20)
uint8_t reserved[448];
uint16_t signature;//should be 0xAA55
} fat_boot_sector_t;
typedef struct __attribute__ ((packed)) {
union {
struct {
char file_name[8];//padded with spaces (0x20)
char file_extension[3];//padded with spaces (0x20)
};
struct {
uint8_t file_magic;// 0xE5:deleted, 0x05:will_be_deleted, 0x00:end_marker, 0x2E:dot_marker(. or ..)
char file_magic_data[10];
};
char volume_label[11];//padded with spaces (0x20)
};
uint8_t file_attr;//mask of FAT_FILE_ATTR_*
uint8_t reserved;//always 0
uint8_t creation_time_ms;//ms * 10; max 1990 (1s 990ms)
uint16_t creation_time_hms; // [5:6:5] => h:m:(s/2)
uint16_t creation_time_ymd; // [7:4:5] => (y+1980):m:d
uint16_t last_access_ymd;
uint16_t extended_attr;
uint16_t last_modified_hms;
uint16_t last_modified_ymd;
uint16_t data_start_sector;
uint32_t file_size;
} fat_dir_entry_t;
typedef struct __attribute__ ((packed)) {
union {
struct {
uint8_t number:5;
uint8_t reserved0:1;
uint8_t llfp:1;
uint8_t reserved1:1;
} seq;
uint8_t seq_num; //0xE5: Deleted Entry
};
uint16_t name0[5];
uint8_t attr; //ALWAYS 0x0F
uint8_t type; //ALWAYS 0x00
uint8_t dos_checksum;
uint16_t name1[6];
uint16_t first_cluster; //ALWAYS 0x0000
uint16_t name2[2];
} fat_lfn_entry_t;
typedef union {
fat_dir_entry_t dir;
fat_lfn_entry_t lfn;
} fat_entry_t;
const char * fat_file_system_type(bool fat16);
uint16_t fat_sectors_per_alloc_table(uint32_t sector_num, bool fat16);
uint8_t * fat_add_table(uint8_t * dst, fat_boot_sector_t * boot, bool fat16);
void fat_set_table_index(uint8_t * table, uint16_t index, uint16_t value, bool fat16);
fat_boot_sector_t * fat_add_boot_sector(uint8_t * dst, uint16_t sector_num, uint16_t table_sectors, const char * file_system_type, const char * volume_label, uint32_t serial_number);
fat_dir_entry_t * fat_add_label(uint8_t * dst, const char * volume_label);
fat_dir_entry_t * fat_add_root_file(uint8_t * dst, uint8_t index, const char * file_name, const char * file_extension, size_t file_size, uint16_t data_start_sector, bool is_fat16);
uint8_t fat_lfn_checksum(const uint8_t *short_filename);
#ifdef __cplusplus
}
#endif

0
cores/esp32/libb64/AUTHORS Normal file → Executable file
View File

0
cores/esp32/libb64/LICENSE Normal file → Executable file
View File

5
cores/esp32/libb64/cdecode.c Normal file → Executable file
View File

@ -12,7 +12,7 @@ static int base64_decode_value_signed(int8_t value_in){
static const int8_t decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51}; static const int8_t decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51};
static const int8_t decoding_size = sizeof(decoding); static const int8_t decoding_size = sizeof(decoding);
value_in -= 43; value_in -= 43;
if (value_in < 0 || value_in >= decoding_size) return -1; if (value_in < 0 || value_in > decoding_size) return -1;
return decoding[(int)value_in]; return decoding[(int)value_in];
} }
@ -40,7 +40,6 @@ static int base64_decode_block_signed(const int8_t* code_in, const int length_in
fragment = (int8_t)base64_decode_value_signed(*codechar++); fragment = (int8_t)base64_decode_value_signed(*codechar++);
} while (fragment < 0); } while (fragment < 0);
*plainchar = (fragment & 0x03f) << 2; *plainchar = (fragment & 0x03f) << 2;
// fall through
case step_b: case step_b:
do { do {
if (codechar == code_in+length_in){ if (codechar == code_in+length_in){
@ -52,7 +51,6 @@ static int base64_decode_block_signed(const int8_t* code_in, const int length_in
} while (fragment < 0); } while (fragment < 0);
*plainchar++ |= (fragment & 0x030) >> 4; *plainchar++ |= (fragment & 0x030) >> 4;
*plainchar = (fragment & 0x00f) << 4; *plainchar = (fragment & 0x00f) << 4;
// fall through
case step_c: case step_c:
do { do {
if (codechar == code_in+length_in){ if (codechar == code_in+length_in){
@ -64,7 +62,6 @@ static int base64_decode_block_signed(const int8_t* code_in, const int length_in
} while (fragment < 0); } while (fragment < 0);
*plainchar++ |= (fragment & 0x03c) >> 2; *plainchar++ |= (fragment & 0x03c) >> 2;
*plainchar = (fragment & 0x003) << 6; *plainchar = (fragment & 0x003) << 6;
// fall through
case step_d: case step_d:
do { do {
if (codechar == code_in+length_in){ if (codechar == code_in+length_in){

0
cores/esp32/libb64/cdecode.h Normal file → Executable file
View File

Some files were not shown because too many files have changed in this diff Show More