Compare commits

..

179 Commits

Author SHA1 Message Date
caef4006af Implement SigmaDelta based on ESP-IDF API (#6053)
Summary

This PR is refactoring of SigmaDelta HAL in order to use IDF instead of current Register manipulation approach.

Impact

Change in API:

uint32_t sigmaDeltaSetup(uint8_t channel, uint32_t freq);
changed to -->
uint32_t sigmaDeltaSetup(uint8_t pin, uint8_t channel, uint32_t freq);

void sigmaDeltaAttachPin(uint8_t pin); removed, no longer needed. Pin is attached in sigmaDeltaSetup()
2021-12-22 16:41:52 +02:00
44fbde0189 Fixes Lib Builder compiling errors (#6052) 2021-12-22 14:37:40 +02:00
8c88ecbf77 add GPIO defines for C3 (#6005) 2021-12-22 14:36:54 +02:00
5724275cd8 fix tft feather pins for final version, qtpy spi pins, and add reversetft start (#6050)
SPI fix for QT Py, TFT fix for TFT Feather
2021-12-22 14:09:53 +02:00
1c94c38dbb IDF release/v4.4 a79dc75f0a (#6048) 2021-12-21 15:14:41 +02:00
7cf162346a RMT refactoring based on IDF (#6024)
Summary

RMT HAL refactoring based on IDF.

Impact

Improves RMT by adding IDF v4.4 support.
Receiving RMT can handle any size of data.
rmtInit() has a new parameter - RxBufferSize - to hold any number of data when receiving RMT.
rmtWrite() has a new parameter - wait_tx_done - to block writing until sending all data.

Related links

fix #5905
2021-12-21 15:02:40 +02:00
c66c7fe27e [Examples] README revision to include missing and remove old entries (#6049) 2021-12-21 15:00:37 +02:00
7ba11cc1ae [Docs] Added USB documentation (#6036)
Summary

Added USB documentation.

Closes: #5784
2021-12-21 12:51:38 +02:00
c3d41c9b54 Fixes baudrate with CPU Freq < 80MHz (#6037)
This PR fixes an issue with UART when CPUFreq is lower than 80MHz (APB Freq)
2021-12-21 10:10:31 +02:00
d6934a5289 Implement LEDC based on ESP-IDF API (#6045)
This PR is refactoring of LEDC HAL in order to use IDF instead of current Register manipulation approach.
Fixing duty -> if all bits in resolution are set -> FULL ON
2021-12-20 14:58:49 +02:00
6b90627b21 HID_BRAILLE_DISPLAY (#6043)
23 Braille Display Page (0x41)
Braille display allow visually impaired computer users to read out text using raised pins. The pins are electro-mechanically
activated. These devices also have support for controls that help navigate the computer screen. Typically, braille displays
interface with software known as a screen reader in order to perform this navigation.
2021-12-20 13:22:58 +02:00
063119ac87 fix variant wt32-eth01 (initializer not constant) (#6040)
fix not constant definitions in variant wt32-eth01 (error: initializer element is not constant)
2021-12-20 13:21:53 +02:00
7b96374ea6 [Fix] Added the Win32 not supported notice/warning (#6031)
Related to:
#6012
#5994
#5991
2021-12-20 13:11:22 +02:00
82ec74a072 Adds support to change LoopTask Stack size (#6025)
## Summary
Arduino ```setup()``` and ```loop()``` run under a Task with a fixed Stack size of 8KB.
Users may want to change this size.

This PR adds this possibility by just adding a line of code, as for example:
``` dart
ESP_LOOP_TASK_STACK_SIZE(16384);

void setup() { 
}

void loop() { 
}
```
## Impact
None. It adds a new functionality to ESP32 Arduino.
If ```ESP_LOOP_TASK_STACK_SIZE(newSize);``` is not declared/used, it will compile the sketch with the default stack size of 8KB.

## Related links
fix #6010 

https://github.com/espressif/arduino-esp32/issues/6010#issuecomment-992701658
Thanks @igrr for the suggestion!
2021-12-20 13:10:36 +02:00
5940d89e67 Fix wrongly applied patch to WiFi STA Init 2021-12-20 10:17:25 +02:00
bb09615391 Fix Arduino Core config for ESP32-S2
Fixes: https://github.com/espressif/arduino-esp32/issues/6019
2021-12-20 10:11:53 +02:00
c2c8d18992 Forces UART Flush() to wait until all bits are sent (#6026)
HardwareSerial flush() was returning before all data was sent out through serial port.
This is a problem to some RS485 libraries that depend on it to signaling.

This PR solves the issue by forcing it to block flush() until all data is sent.
2021-12-15 11:08:49 +02:00
39b9e1e533 Implement DAC based on ESP-IDF API (#5959)
This PR is refactoring of DAC HAL in order to use IDF instead of current Register manipulation approach.

Edited dacWrite() to use ESP-IDF api.
Added dacDisable() so there is an option to disable dac channel.

Co-authored-by: Me No Dev <me-no-dev@users.noreply.github.com>
2021-12-14 21:10:30 +02:00
40a5c1e461 Change default WiFi encryption to WIFI_AUTH_WPA2_PSK (#6022)
Fixes: https://github.com/espressif/arduino-esp32/issues/6020
2021-12-14 20:07:08 +02:00
2981bde88f Add some more adafruit boards and fix some board typos (#6014)
Co-authored-by: caternuson <caternuson@gmail.com>
Co-authored-by: Kattni Rembor <kattni@adafruit.com>
Co-authored-by: Jeff Epler <jeff@adafruit.com>
Co-authored-by: Jeff Epler <jepler@gmail.com>
Co-authored-by: Ha Thach <thach@tinyusb.org>
2021-12-14 18:17:04 +02:00
6d400df952 IDF release/v4.4 f23dcd3555 (#5996)
esp-dsp: master 6b25cbb
esp-face: master d141502
esp-rainmaker: f1b82c7
esp32-camera: master 61400bc
esp_littlefs: master 3c29afc
2021-12-14 16:38:06 +02:00
7bb30b3cf8 Refactoring TwoWire::requestFrom() headers in Wire.cpp (#5935)
* Refactoring function headers

Changing the header so the main TwoWire::requestFrom() definition uses a `size_t` instead of a `uint8_t`, removing the 255 bytes limit on I2C requests.

Co-authored-by: Flaviu Tamas <me@flaviutamas.com>
Co-authored-by: Me No Dev <me-no-dev@users.noreply.github.com>
2021-12-14 16:25:01 +02:00
4b638de19d using ksz8081 only from ESP-IDF 4.4 onwards (#5918)
* using ksz8081 only from ESP-IDF 4.4 onwards

The previous assertion only considerate the existance of ESP-IDF 4.3, but with the ESP-IDF 4.3.1 release this assertion would generate errors. Now only includes from ESP-IDF 4.4 onwards.

Co-authored-by: Me No Dev <me-no-dev@users.noreply.github.com>
2021-12-14 16:09:01 +02:00
2463f57246 Adding Issue and Feature template (#5999)
Summary

This PR contains adding:

Issue template using forms
Feature Template using forms
Update of Pull Request template
All yaml files have been checked by online validator.

Pages are rendered here (for easier review):
Feature Request template
Issue Template

Impact

These templates can help with more accurate issue/PR explanations which can improve handling these contribution and in overall have a positive influence on User experience.

Related links

This PR closed issue #5956
2021-12-14 16:05:36 +02:00
f29f4485b5 Fix memory leaks when SSL/TLS connection fails (#5945) 2021-12-14 15:59:26 +02:00
8a8f87d3a0 Fix for BluetoothSerial build when using nimBLE instead of Bluedroid (#5920) 2021-12-14 15:56:25 +02:00
082491d552 Add DPU ESP32 (#5884)
Co-authored-by: Me No Dev <me-no-dev@users.noreply.github.com>
2021-12-14 15:53:09 +02:00
794de50bf4 Migrate MD5Builder to use esp_rom functions directly rather than rely on wrappers that can be omitted from compilation based on sdkconfig. (#5941) 2021-12-14 15:49:43 +02:00
5e7db8dfac Timer based od ESP-IDF (#5931) 2021-12-14 15:46:39 +02:00
fb00b51f99 [DOCS] Writing a new Arduino documentation about GPIO (#5894)
* add new documation GPIO

Co-authored-by: pedro.minatel <pedro.minatel@espressif.com>
2021-12-14 15:39:54 +02:00
5dc8fb83c9 add board and variant for WT32-ETH01 (variant wt32-eth01) from Wireless-Tag (#5946)
- supports the WiFi/Ethernet board with WT32-S1 module and LAN8720A Ethernet PHY
- documentation available at http://www.wireless-tag.com/portfolio/wt32-eth01/
2021-12-14 15:37:59 +02:00
cb25fe8c7e Don't clear headers on redirect (#5973)
Current implementation clears _headers when request was sent. If the
user added custom request headers, they will be lost and the redirected
request will not contain them. This commit changes the scope of cleanup
so that the headers survive redirects but don't survive connection
reuse.
2021-12-14 15:37:31 +02:00
f5b04b9197 Use WIFI_FAST_SCAN if a specific channel was used (#5975)
1.0.6 changed scanning method to always scan all available channels during connect. This results in results in connect taking about ~3 seconds instead of ~1. This patch changes the behavior to use WIFI_FAST_SCAN if client used a specific channel.
2021-12-14 15:37:00 +02:00
8c5d18dd85 Merged all TTGO-LoRa32 Board profiles (see #5933) (#5961)
* Merged all TTGO-LoRa32 Board profiles (see #5933)

* Fix for LORA_RST (see #5966)
2021-12-14 14:55:55 +02:00
fa03966fcf [Feature] Added Sonoff DUALR3 support with RainMaker example (#5980)
* [Feature] Added Sonoff DUALR3 support with RainMaker example

* [Feature] Added skip files for C3 and S2
2021-12-14 14:35:10 +02:00
3750b14d74 Prevent self hosted jobs to run on forks. (#5983)
Signed-off-by: Abdelatif Guettouche <abdelatif.guettouche@espressif.com>
2021-12-14 14:26:59 +02:00
cebac569de Update Boards.txt (#5984)
fix boad error : "--elf-gcc.path}/bin/--elf-g++": file does not exist
and fix follow esp32 dev module
2021-12-14 14:26:10 +02:00
d0e73bd269 .github/workflows: Update checkout and setup-python actions to their V2 (#5985)
(latest) version.

Signed-off-by: Abdelatif Guettouche <abdelatif.guettouche@espressif.com>
2021-12-14 14:25:11 +02:00
26dddc5f94 Fix the execute bit of some files. (#5986)
- Remove the execute bit from source and text files.
- on-pages.sh script needs the execute bit to be set.

Signed-off-by: Abdelatif Guettouche <abdelatif.guettouche@espressif.com>
2021-12-14 14:24:44 +02:00
c87ede88df Delete .travis.yml file. (#5987)
All the workflows are now migrated to Github Actions.
Update the on-push.sh script to remove references to TravisCI variables.

Signed-off-by: Abdelatif Guettouche <abdelatif.guettouche@espressif.com>
2021-12-14 14:24:01 +02:00
c90dffef44 Edit sd_diskio to check card status (#5988) 2021-12-14 14:22:30 +02:00
1945fae795 update boards.txt for adafruit feather esp32s2 (#6006)
also update tinyuf2 bootloader for adafruit boards to 0.6.2
2021-12-14 13:58:18 +02:00
6e0b57784f [Docs] Update on the Windows install procedures (#6018) 2021-12-14 13:56:26 +02:00
399f4ecbb3 [DOCS] Editing usage of Arduino as a component in ESP-IDF (#5896)
* Editing esp-idf_component docs

* Changed idt to ESP-IDF

Co-authored-by: Pedro Minatel <pminatel@gmail.com>
2021-11-22 13:37:06 +00:00
a5002c86a0 IDF release/v4.4 ddc44956bf (#5911)
esp-dsp: master 6b25cbb
esp-face: master 859f32a
esp-rainmaker: f1b82c7
esp32-camera: master 61400bc
esp_littlefs: master 3c29afc
2021-11-22 15:02:37 +02:00
c9916c463f Fix I2C clock stretching issue with ESP32 (#5910)
It was found that when I2C device is holding the clock LOW, ESP32 master is failing to wait for the clock to be released.

Fixes: #5875
Fixes: sparkfun/SparkFun_u-blox_GNSS_Arduino_Library#77
2021-11-19 18:43:59 +02:00
bd2be80b54 cbuf: allow inheritance (#5883)
changes "private" vars to "protected" so that descendants are allowed to access them.
2021-11-18 14:25:04 +02:00
6f1f394680 Update boards.txt (#5903) 2021-11-18 13:58:03 +02:00
5de09a9a49 [Docs] Add link to supported soc list on README and ESP32-S3 datasheet (#5891)
* [Docs] Added the supported SoC table link on the README file

* [Docs] Added the ESP32-S3 datasheet link to the getting started page
2021-11-15 15:19:28 +00:00
b94b38c9d1 Fix compiler.libraries.ldflags Option (#5866)
I misplaced the additions.
2021-11-09 17:01:21 +02:00
d218e58f96 Update package_esp32_index.template.json 2021-11-09 10:47:31 +02:00
14ece43654 Update README.md 2021-11-09 10:41:20 +02:00
ae7173d4d5 cmake: error out of IDF version is outside of supported range 2021-11-09 10:31:46 +02:00
c7080b0a83 ci: run CMake in script mode when finding source files 2021-11-09 10:31:11 +02:00
96c184d213 Add basic analogWrite support based on LEDC (#5861) 2021-11-09 10:26:41 +02:00
da72bc90b7 eliminates error messages when using Ethernet Static IP (#5836)
Summary

Only affects ETH (not WiFi)

This PR solves #5733 by allowing the DHCP IDF server to complete its tasks and only then it sets a static IP.
This also solves another related failure reported in this issue (#5733 (comment)).

fix #5733

Impact

Adds a delay in order to wait for DHCP to actually terminate before setting the static IP configuration in ETH.
2021-11-09 10:23:29 +02:00
16a9cf781f Add another Wire requestFrom function signature (#5768)
* Re-add with clean master

* Address @me-no-dev's comments

* static_cast<size_t> to static_cast<uint8_t>
2021-11-08 14:29:04 +02:00
b1497fb257 [Docs] Peripheral list updated to include all supported SoCs (#5851) 2021-11-08 12:36:06 +02:00
5e04eb48b6 Add precompiled (#5854)
Added an option for using precompiled libraries.

Empty if there is no precompilation.

```
compiler.libraries.ldflags=
```

Compiler Message when there is precompilation.

```
Compiling libraries...
Compiling library "aquestalk-esp32"
Library aquestalk-esp32 has been declared precompiled:
Using precompiled library in C:\Users\tanaka\Documents\Arduino\libraries\aquestalk-esp32\src\esp32
```

The precompiler cannot be used because it is not set up now.
2021-11-08 12:13:45 +02:00
674cf812e7 [FEATURE] add -D ARDUINO_PARTITION_xxx build flag to platform.txt (#5804)
* [FEATURE]  ARDUINO_PARTITION_xxx build flag

Proposition: adding `-DARDUINO_PARTITION_{build.partitions}` flag to make the build partition information available at compile time.

Use cas example:

```C
#if defined ARDUINO_PARTITION_default
  // prevent compilation
  #error "This sketch needs 'Minimal SPIFFS' partition scheme to compile" 
  // or disable sketch features that need flash space
  #define USE_HUGE_BITMAP_IMAGES false
#endif
```

* Adding -DARDUINO_PARTITION_{build.partitions} (see #5804)
2021-11-06 13:58:48 +02:00
83884a0cda Fix SparkFun MicroMod compilation issues
Fixes: https://github.com/espressif/arduino-esp32/issues/5818
2021-11-04 19:18:31 +02:00
80b8262595 Update esp-idf_component.rst 2021-11-04 17:21:44 +01:00
5747bfab67 Merge branch 'master' of https://github.com/espressif/arduino-esp32 2021-11-04 16:59:11 +01:00
4b9dc61447 Solving *"wifi:channel=0 is invalid"* when using FTM example code (#5809)
When using the FTM examples I got an error in the FTM_Initiator.ino:

*"wifi:channel=0 is invalid"*

I solved it for myself by simply passing the channel argument to be 1 in *WiFi.initiateFTM*. However, a better fix would be to directly change the default channel here.
2021-11-04 16:08:50 +02:00
a2d7c0dcf6 [Examples] WiFi and Ethernet examples organization (#5830)
* examples: WiFi and Ethernet examples organization

* examples: Change on CI scripts to include new folder

* Library name reverted to WiFi

* examples: WiFi and Ethernet examples organization in a new folder

* examples: Eth files moved from WiFi to Ethernet lib and CMakeLists updated
2021-11-04 16:08:08 +02:00
666cd3cde5 [Docs] Added I2C driver docs (#5770)
* Added I2C driver docs
docs: Changes on the images and added more details about the I2C slave

* docs: Added slaveWrite description and added docs build folder to the gitignore file
2021-11-04 14:32:05 +02:00
3e851b537a [Docs] Added useStaticBuffers function description (#5820)
* docs: Added useStaticBuffers function description

* docs: Default useStaticBuffers configuration in highlight
2021-11-04 14:30:16 +02:00
f410728444 docs: Added supported peripherals list on libraries section (#5829) 2021-11-04 14:29:42 +02:00
79e0889a16 Allow use of log_x() in if (#5844)
if (1) log_e("error") produces a warning ("missing braces") and probably wrong code if no log level is defined.
This fixes that.
2021-11-04 14:25:44 +02:00
4aff6dde39 Support additional authorization schemes (#5845)
The client always appends "Basic" to the authorization header, however there are other auth schemes that can be used: https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication
For example "Bearer" when using OAuth.
This PR adds a `setAuthorizationType` method to the HTTPClient which allows this scheme to be configured by the caller. Authorization type is set to "Basic" by default so this will have no impact on existing usecases.
2021-11-04 14:25:12 +02:00
bb50046540 Fix double promotion in Stream::parseFloat() (#5846) 2021-11-04 14:24:28 +02:00
10258b4cc2 fix double promotions in rmtSetTick() (#5847) 2021-11-04 14:24:14 +02:00
418ac74be0 IDF release/v4.4 6a7d83af19
* Update toolchain to 2021r2 (#5828)
* Update C3 libs to support only ECO3 and newer
2021-11-04 14:22:34 +02:00
caa8d07aaf yay for esp32-s2 mini module with PSRAM :) (#5811) 2021-10-26 22:26:32 +03:00
15bbd0a187 Add ALPN support to WiFiClientSecure (#5633)
This adds a function to WiFiClientSecure to set the ALPN protocol.

This is required for an MQTT client to connect to AWS IoT when using an AWS Custom Authorizer, as described here.

Example code snippet:

...
WiFiClientSecure wiFiClient;

// ALPN protocol, needed with AWS custom authorizer
const char *aws_protos[] = {"mqtt", NULL};

void setup() {
  wiFiClient.setCACert(AWSCAPEM);
  wiFiClient.setAlpnProtocols(aws_protos);
}
...
2021-10-25 09:20:47 +03:00
02c3ec01cc remove _user_defined_size from EEPROM (#5775)
Summary

Related to the issue #5773 and #2280.

_user_defined_size is removed from EEPROMClass because it is redundant in the current code
EEPROMClass::length() returns _size that is the true available size of EEPROM
Impact

_user_defined_size is removed from EEPROMClass
EEPROMClass::length() returns _size that is the true available size of EEPROM
2021-10-25 09:15:47 +03:00
cb5a490616 Correct CDC on boot custom menu for Deneyap Mini (#5767)
The Deneyap Mini used a SerialMode custom menu item, which is not defined. The correct item, CDCOnBoot, has replaced it.
2021-10-25 09:13:48 +03:00
f257d6f126 IDF release/v4.4 2720d45e71 (#5801) 2021-10-25 09:12:37 +03:00
aabbed0bbc analogRead() now return value according to value set in analogReadResulotion() (#5776)
Function analogReadResolution set how many bits will analogRead return.

Find out that this functionality was added back 2017 by @me-no-dev in #161.

Related issues:
#5163
2021-10-24 13:01:05 +03:00
a418058a66 log statement missing parameter #5778 (#5796) 2021-10-23 11:34:00 -03:00
96ad341451 Merge pull request #5795 from SuGlider/esp_eth_clear_default_handlers
removes deprecated esp_eth_set_default_handlers()
2021-10-22 22:13:08 -03:00
2673b88582 removes deprecated esp_eth_set_default_handlers() 2021-10-22 21:56:14 -03:00
67c99142d2 Allows spiram malloc with wifi dynamic buffers - better free heap (#5791)
Summary

Modifies WiFi lib to allow dynamic buffer allocation along with SPIRAM MALLOC enabled
This gives more heap space to the users

Related PR in Arduino Lib Builder: espressif/esp32-arduino-lib-builder#47

Impact

WiFi will work the same as it was in version 1.0.6, restoring free heap.

close #5630
close #5474
close #5699
close #5697
2021-10-22 02:22:20 +03:00
951c8bece5 libraries/SPI/src/SPI.h: SPIClass: add method to get SS pin number (#5788)
* SPI.h add new call to return a SS pin number used.

As code example states, the SS pin needs to be explicitly set for output for SPI to work, but the pin number have to be coded in addition to the SPI logic in the library, which means this duplicates code. It is much better to just be able to get the pin number from library itself.

* Update SPI_Multiple_Buses.ino to use new pinSS method

Simplify the example case, to show usage of pinSS method. This also simplifies the example, removing duplicated code.
2021-10-21 16:48:55 +03:00
4413dbbd87 IDF master 4e03a9c34c (#5792)
esp-dsp: master e05fc36
esp-face: master f108a83
esp-rainmaker: f1b82c7
esp32-camera: master 3022601
esp_littlefs: master 05d55ab
2021-10-21 16:27:28 +03:00
ed53b6c8d4 Merge pull request #5746 from espressif/i2c-slave
I2C Slave Implementation
2021-10-14 12:52:20 +03:00
2e53300da5 IDF master b86fe0c66c
esp-dsp: master e05fc36
esp-face: master f108a83
esp-rainmaker: f1b82c7
esp32-camera: master 3022601
esp_littlefs: master f6e7108
2021-10-14 12:51:25 +03:00
64c7f746fd Merge pull request #5753 from pedrominatel/docs/troubleshooting_python_not_found
[Docs] Added Python is missing on the troubleshooting section
2021-10-14 09:48:15 +01:00
1049be7d56 Merge branch 'master' into docs/troubleshooting_python_not_found 2021-10-14 09:37:12 +01:00
34c81be93b IDF master b86fe0c66c 2021-10-13 18:21:12 +00:00
2fb2ef54ce Calculate properly Firmware MSC fat table sectors 2021-10-13 15:39:36 +03:00
49f525c91d Added Python is missing on the troubleshooting section 2021-10-12 13:26:13 +01:00
b145e65975 API Optimizations
- Support Wire::end() for Slave
- Prevent Master operations when in Slave mode
2021-10-11 14:46:31 +03:00
951c32056a Merge branch 'master' into i2c-slave 2021-10-11 13:13:13 +03:00
7a7bd37e51 feat: Add the ability to get the peer certificate of an SSL connection
Summary

New feature: Add the ability to get the peer certificate of an SSL connectio. This is useful for IoT when the root/cert trust chain has a shorter lifecylce than the device itself. Includes example code.

It adds two methods to the WiFiClientSecure client:

bool getFingerprintSHA256( uint8_t fingerprint_remote_sha256[32]) -- return true and the fingerprint (i.e. the SHA256 of the raw x509 as a DER - identical to what you see in for example your webbrowser). Or false on error.
const mbedtls_x509_crt* getPeerCertificate(); -- return the actual X509 struct or NULL on error.
Impact

No impact; backwards compatible (only adds to the API)
2021-10-11 13:04:13 +03:00
a75602dc68 Add support M5Stack Unit CAM (#5748)
In this PR, we add support for M5Stack Unit CAM to CameraWebServer.
https://docs.m5stack.com/en/unit/unit_cam
2021-10-11 13:01:10 +03:00
88789cd817 Fix build error when compiling with verbose logging (#5747)
When compiling with verbose logging, the build would error with a message saying `len` is not defined in `tud_vendor_rx_cb()`. This change fixes the error.
2021-10-11 13:00:25 +03:00
335cedf4f7 Update CMakeLists.txt 2021-10-09 14:37:10 +03:00
f9f70d2f73 I2C Slave Implementation 2021-10-09 14:30:20 +03:00
5b207104aa Fix: SD_MMC deinit (#5732)
* SD.open() new feature for creating all folders in path

This PR adds to the SD.open() function option to create all folders to the file.

SD.open(const char* path, const char* mode, const bool create)

Default value of create is false.
When true folders are created.

From issue #5019

* Update vfs_api.cpp

memccpy -> memcpy

* SD_MMC deinit fix

Wrong deinit function was called.
2021-10-09 14:12:25 +03:00
1706af4656 Add the ability to get the peer certificate of an SSL connection; useful for IoT when the root/cert trust chain has a shorter lifecylce than the device itself. Includes example 2021-10-08 14:20:43 +02:00
bd54ee442b Remove git submodule update (#5696)
We don't have submodules.
2021-10-01 18:11:59 +03:00
00214d5c2a IDF master 3e370c4296
* Fix build compilation due to changes in the HW_TIMER's structs

* Fix compilation warnings and errors with USB

* Update USBCDC.cpp

* Update CMakeLists.txt

* Update HWCDC.cpp
2021-10-01 17:52:29 +03:00
381e88ec75 [UART] check if write data is valid 2021-10-01 17:36:59 +03:00
f87107dedb Implement Thread-Safe I2C based on ESP-IDF API (#5683)
* Implement Thread-Safe I2C based on ESP-IDF API

* Update esp32-hal.h

* use proper types for size and timeout

* Allow disabling of the HAL locks

* Limit frequency settings to prevent Interrupt WDT
2021-10-01 17:34:20 +03:00
ce85cf03cc added comment for user clarity (#5724) 2021-10-01 17:17:42 +03:00
f2a20e8a38 SD.open() new feature for creating all folders in path (#5721)
* SD.open() new feature for creating all folders in path

This PR adds to the SD.open() function option to create all folders to the file.

SD.open(const char* path, const char* mode, const bool create)

Default value of create is false.
When true folders are created.

From issue #5019

* Update vfs_api.cpp

memccpy -> memcpy

* File f = open() edit

added false for create
2021-10-01 17:16:59 +03:00
c5bb8334d7 include pin_arduino.h for variant USB defines (#5719) 2021-10-01 16:15:15 +03:00
6de7f16f28 update adafruit boards for 2.0 (#5718) 2021-10-01 16:14:50 +03:00
1688b7c179 Fix analogWidth for ESP32S2 in esp32-hal-adc.c (#5711) 2021-10-01 16:13:24 +03:00
36ff442698 bugfix: off-by-one error (#5648) 2021-10-01 15:48:35 +03:00
93f10609f4 SDMMC frequency selection based on board type (#5688)
* SDMMC frequency selection based on board type

On Olimex ESP32 EVB I/O operations with SD card can cause error when LAN is used in same time.
Problem is disappearing if SD MMC frequency lower down from SDMMC_FREQ_HIGHSPEED to SDMMC_FREQ_DEFAULT.

No problem if WiFi used instead LAN.

* Code rewritten according to https://github.com/espressif/arduino-esp32/pull/5688#pullrequestreview-759359645
2021-10-01 15:48:20 +03:00
67583e84d6 Return size_t instead of uint8_t from BLECharacteristic::getLength(). Allows large MTU to be used. (#5687) 2021-10-01 15:47:42 +03:00
108e467164 Enable progress bar on ArduinoOTA upload (platform.txt) (#5657) 2021-10-01 15:06:55 +03:00
91bca6c074 Fix compilation of HardwareSerial.cpp (#5677)
Fix compilation in case NO_GLOBAL_INSTANCES || NO_GLOBAL_SERIAL is defined.
2021-10-01 15:06:16 +03:00
204f360dce Append '/' to an URL with empty path in HTTPClient::begin (#5634)
* Add an error check for empty path of an URL

* Append '/' to an URL with empty path instead of returning an error
2021-10-01 15:04:09 +03:00
3f06a38f69 SD_MMC max_freq_khz is set to HIGHSPEED by default (#5631) 2021-10-01 15:03:38 +03:00
2f6f251400 Fixes boards.txt entries for the atmegazero_esp32s2, and also the platform.txt --flash_size which is not letting the board compile due to its 32MB size. (#5673) 2021-10-01 14:39:08 +03:00
e4acfbc54a only use ksz8081 for idf versions later than 4.3 (this fixes compile as component for idf 4.3) (#5599)
esp_eth_phy_new_ksz8081 was added in IDF after version 4.3 and generates a compilation error with IDF-4.3. This change will only use esp_eth_phy_new_ksz8081 for IDF versions after 4.3
2021-10-01 14:38:45 +03:00
79d53bdc4c Update ESP.getChipModel() to support ESP32-S2 (#5598) 2021-10-01 14:37:17 +03:00
f3f6dad14a TTGO T-OI PLUS RISC-V ESP32-C3 Development Board Added (#5576) 2021-10-01 14:24:44 +03:00
0f174aae88 Update stale.yml 2021-09-30 17:12:45 +02:00
317be68cef Merge pull request #5685 from pedrominatel/docs/integration_with_wokwi
Docs integration with Wokwi - Blink Tutorial
2021-09-21 15:31:44 +01:00
1f4dd7f131 Merge branch 'master' into docs/integration_with_wokwi 2021-09-21 14:55:27 +01:00
8be2f7b1cc Changes according to the PR review 2021-09-21 14:34:21 +01:00
9f827a66d5 Update README.MD - "Type: For reference" labels link (#5619)
* Create PULL_REQUEST_TEMPLATE.md

Adding first version of PULL_REQUEST_TEMPLATE.md.

The purpose of this template is to improve and simplify writing more accurate Release Notes.

* Update PULL_REQUEST_TEMPLATE.md

Fix typo.

* Update README.MD - "Type: For reference" labels link

Updating a link to issues labeled with "Type: For reference". The old one is not working due to the updates of labels in the past.
2021-09-21 11:36:36 +03:00
e1cdbd7816 Minor changes on the blink tutorial 2021-09-20 12:39:05 +01:00
7a35be3e7e Added blink example with Wokwi embedded simulation 2021-09-20 12:00:52 +01:00
078671d273 [HWCDC] Improve HW CDC Implementation (#5643)
This pull request contains a few fixes and improvements to the HWCDC implementation.
- Rework `HWCDC::write()` to accept unlimited data
- Add Semaphore to guard the TX Ring Buffer
- Add events support
- Remove unnecessary 1200bps touch for flashing over HWCDC
- Fix `HardwareSerial::setDebugOutput()` not resetting `putc` if the port is already selected, causing debug output to also show on HWCDC even when not selected.
2021-09-15 19:37:09 +03:00
541cef9149 [USB CDC] Fix data might not be transmitted until more is written (#5652)
Depending on `tud_cdc_tx_complete_cb` can cause in some cases the last packet to not be transmitted until more data is written and flushed. It's a rare case, but if the other end is expecting those last bytes, transmission will hang.

This PR also fixes debug output on CDC
2021-09-15 15:23:11 +03:00
6dfaf6cdd4 Add dummy test for self hosted GitHub runners (#5521)
* Add dummy test for self hosted GitHub runners
2021-09-15 15:02:04 +03:00
92ce408f4c Merge pull request #5616 from pedrominatel/docs/update_for_release_2-0-0
Supported devices table updated due the 2.0.0 release
2021-08-31 12:16:57 +01:00
453af3800c Supported devices table updated due the 2.0.0 release 2021-08-31 11:29:10 +01:00
44c11981d2 Added UM FeatherS2 Neo to boards.txt and added appropriate variants. (#5615) 2021-08-31 09:28:56 +03:00
9eea85f9ff Check if m_pServerCallbacks is not null before calling method. (#5603)
Fixes: https://github.com/espressif/arduino-esp32/issues/5573

To reproduce:
1. Run any sample code that starts a BLE server, and does not call `setCallbacks`.
2. Connect to the device using the "LightBlue" app on iOS.
3. Observe crash shown in the issue linked above.
2021-08-31 09:20:02 +03:00
24b76cbb14 Add string constructor and concat routines taking explicit length args (#5586)
## Summary
Applies the upstream changes here: https://github.com/arduino/ArduinoCore-API/compare/3b88acac8%5E...0d83f1afc3367037dbde5323c2abd0ae1bd2c583

## Impact
Adds new String convenience methods that are now available in the mainline Arduino implementation, simplifying interoperability with C code that uses pointer+length strings rather than 0-termination. Also includes a change to avoid mutating the source string when taking a substring.
2021-08-31 09:12:27 +03:00
4a55ff970d Add support for the hardware CDC in ESP32-C3 (#5614)
* Add support for the hardware CDC in ESP32-C3
2021-08-31 08:47:55 +03:00
a62979d8a0 Add missing upload.flags (#5589) 2021-08-25 10:40:13 +03:00
1f59c5abec Adds HardwareSerial::setRxBufferSize() (#5583)
* Adds rxBufferSize parameter to begin()

* Adds HardwareSerial::setRXBufferSize()
2021-08-24 08:21:20 +03:00
0730e0ec93 Include nvs_commit() on three methods (#5309)
* Include nvs_commit() on three methods

In [Preferences.cpp](https://github.com/espressif/arduino-esp32/blob/master/libraries/Preferences/src/Preferences.cpp),  the functions:
```
Preferences::clear()
Preferences::remove()
Preferences::end()
```
should be revised to include a call to 
`nvs_commit()`
as required per 
[Non-volatile storage library](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/storage/nvs_flash.html)
when using 
```
nvs_erase_all()
nvs_erase_key()
nvs_close()
```
2021-08-23 21:23:42 +03:00
c45cff5f83 Implement USB HID Device Support for ESP32-S2 (#5538)
* Add support and example for USB HID Devices
* Add support and example for USB Vendor
2021-08-23 17:27:34 +03:00
b1d072df9f Implements UART SerialHardware Refactoring on top of IDF (#5549)
## Summary
This PR is a complete reffactoring of UART Serial Hardware and respective HAL in order to use IDF instead of current Register manipulation approach. 

It  implements Arduino SerialEvent functionality. 

Fix #5287  
Fix #5273 
Fix #5519 
Fix #5247 
Fix #5403
Fix #5429
Fix #5047
Fix #5463
Fix #5362 
Fix #5112  
Fix #5443 

## Impact
It solves many reported issues related to UART.
It was tested and works fine for ESP32, ESP-S2 and ESP32-C3.
2021-08-23 17:25:33 +03:00
929cf2c2d5 Add ATMegaZero ESP32-S2 microcontroller (#5569)
## Summary
Adds support for the new ATMegaZero ESP32-S2 board. Adds the relevant section to `boards.txt` and adds the folder for the `atmegazero-esp32s2` with the proper `pins_arduino.h` to the `variants` folder.

## Impact
Allows users to compile code properly for the ATMegaZero ESP32-S2 without having to use a similar board and manually entering pin numbers.

## Links
[ATMegaZero ESP32-S2](https://atmegazero.com/#/atmegazero_esp32s2_overview)

Thanks!
2021-08-23 17:21:48 +03:00
87853353db Add SparkFun ESP32 MicroMod microcontroller (#5556)
* Add SparkFun ESP32 MicroMod to boards.txt

Copied from the tarball found in the SparkFun board manager
[JSON](https://raw.githubusercontent.com/sparkfun/Arduino_Boards/main/IDE_Board_Manager/package_sparkfun_index.json),
v1.0.1 -- [tarball can be found here](https://github.com/sparkfun/Arduino_Boards/raw/main/IDE_Board_Manager/sparkfun-esp32-1.0.1.tar.bz2)

* Add `pins_arduino.h` for ESP32 MicroMod

Co-authored-by: Me No Dev <me-no-dev@users.noreply.github.com>
2021-08-23 17:20:35 +03:00
e265bd0d7c Add new board (Deneyap Mini) (#5531)
* The board.txt has been updated. Added variant folder.

Necessary additions for deneyapMiniKart were made in board.txt. Added pins_arduino to variant folder. deneyapMiniKart information has been added.

* Added variant files and added text in board.txt

Co-authored-by: Me No Dev <me-no-dev@users.noreply.github.com>
2021-08-23 17:20:21 +03:00
94809ce38b fix: timerRead() is returning the last read value, not the actual #3434 (#5498) 2021-08-23 17:19:37 +03:00
Tim
29455a0447 Fix issue #5507 "Constructor WebServer::WebServer(IPAddress addr, int… (#5509)
* Fix issue #5507 "Constructor WebServer::WebServer(IPAddress addr, int port) produces an unexpected result"

"The class Webserver is declared with two explicit constructors, one with signature:
WebServer::WebServer(IPAddress addr, int port)
Using this results in a server listening on the port number obtained by converting the value of the IPAddress addr argument (in host byte order) to a uint32_t and then to a uint16_t, which is manifestly not the result that would be expected.
...
As for a fix, we can assume from these results that this constructor is not being used and therefore could simply be deleted."

* Issue 5507
Reverse changes in commit bee1e7088cef913391155f096b42cd4bb89c5c6f after discussion.
Alternative fix to be done.

* Fix issue #5507 "Constructor WebServer::WebServer(IPAddress addr, int port) produces an unexpected result"

This change adds support for multi-homed servers to libraries/WiFi.  It was assumed to be there already by libraries/WebServer, but was not.
This led to unexpected results when the IP address-specific constructor of class WebServer was used (see issue 5507).

This change was tested using three concurrent instances of WebServer, one bound to the WiFi station address, one bound to the WiFi soft AP address,
and one bound to INADDR_ANY.  See libraries/WebServer/examples/MultiHomedServers for the test method.

* Fix issue #5507 "Constructor WebServer::WebServer(IPAddress addr, int port) produces an unexpected result" (cont.)
This fixes what I think might be the cause of CI failures on GitHub for the previous commit, namely the absence of an include file
in examples/MultiHomedServers.

* Fix issue #5507 "Constructor WebServer::WebServer(IPAddress addr, int port) produces an unexpected result" (cont.)

Change port numbers in examples/MultiHomedServers per pull-request comment from me-no-dev ...
"for this test to be valid, both servers should be on the same port. That is how you can make sure that the functionality works."
2021-08-23 15:51:06 +03:00
78499c459b Added Franzininho WiFi board support (#5570)
This PR adds the support for the Franzininho WiFi board in CDC and MSC modes.

References: https://franzininho.github.io/docs-franzininho-site/docs/franzininho-wifi/franzininho-wifi/
https://github.com/Franzininho/imagens-franzininho/blob/main/franzininho_wifi/pinagem-franzininho-wifi.png
2021-08-23 15:43:17 +03:00
ce680708ec Fixed the external link to a new tab (LOLIN boards) (#5571)
Moved links to the botton
2021-08-23 15:41:07 +03:00
90c01dab77 Fix build error in ESP-IDF
Fixes: https://github.com/espressif/arduino-esp32/issues/5562
2021-08-19 13:54:10 +03:00
000d967db3 Merge pull request #5547 from pedrominatel/docs/wemos_boards
[DOCS] Added LOLIN dev kits links to the boards list in the documentation
2021-08-18 12:19:22 +01:00
44dd99f5a5 Merge branch 'master' into docs/wemos_boards 2021-08-18 12:00:52 +01:00
b580bb23fd Add log_buf to pretty print buffers
```
/* 0x0000 */ 0x7b, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,    // {{..............
/* 0x0010 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,    // ................
```
2021-08-17 17:01:16 +03:00
a7ea737f30 Added LOLIN boards o the boards list. 2021-08-16 09:35:36 +01:00
2af8cc3485 Fixes Touchpad Interrupt (#5527)
Fixes #5493 

## Summary
PR #4996 has broken Touch Interrupt functionality by removing a single line of code used to set a Register.


## Impact
This PR fixes issue #5493 by reverting the removal of necessary code as described above.
2021-08-12 10:05:47 +03:00
e5bd18d6aa Fix I2C Scan for S2 and C3 (#5528)
Thanks @chegewara

I2C Scan was failing because i2c_master_write does not accept size of 0. This change checks and skips that call if no length is provided (usually when scanning)
2021-08-12 10:03:33 +03:00
a4118ea889 Add ET-Board BUILTIN_LED pin (#5490)
ET-Board
No internal LED pin
Missing internal LED pin have been added to this commit.
2021-08-11 14:32:37 +03:00
Tim
c4fcab28e4 Fix issue #5506 "WebServer serveStatic () can cause LoadProhibited exception in _svfprintf_r" (#5508)
"Using a Core Debug Level of Verbose and the WebServer serveStatic() function with the default value of nullptr for its cache_header argument, results in a LoadProhibited exception in _svfprintf_r().
This is because serveStatic() calls log_v() with cache_header corresponding to a "%s" in its format but without checking that cache_header is not nullptr, and then logv() (indirectly) calls _svfprintf_r().
On the other hand, with a Core Debug Level other than Verbose, this does not occur."

Changed serveStatic() to the check value of cache_header and if it is nullptr, instead pass an empty string to log_v().
2021-08-11 14:31:07 +03:00
0acbe781f5 Increase default timeout for WiFiClient from 3ms to 3s (#5496)
## Summary
https://github.com/espressif/arduino-esp32/pull/5487 introduced a default timeout for WiFiClient, however the default was specified in milliseconds instead of seconds, see be84c8219c (commitcomment-54358731)
This 3ms timeout breaks OTA when the processor is busy.

## Impact
Sets the default to a saner value, fixes OTA.
2021-08-11 14:17:38 +03:00
0b0dfab3cf Fix race in log_printf (#5523)
Fixes: https://github.com/espressif/arduino-esp32/issues/5513

Can still race if Serial.begin() is not called in setup()
2021-08-11 13:46:08 +03:00
5fd737925f Fix wrong attenuation being set to pins (#5522)
Fixes: https://github.com/espressif/arduino-esp32/issues/5503
2021-08-11 13:05:26 +03:00
5bb8177aa1 Add initial support for USB MSC (#5466)
* Add initial support for USB MSC

* Add Firmware Upload/Download With MSC

Current running firmware is available as file inside the MSC Disk. To update the firmware on the ESP, just copy a regular firmware bin into the drive

* Support overwriting of the firmware file

Overwriting a file is done totally differently on MacOS, Windows and Linux. This change supports it on all of them.

* Allow CDC, FirmwareMSC and DFU to be enabled on boot

* Add example ESP32-S2 USB-ONLY board

* Various device code optimizations

Added `end()` methods to MSC classes
Made begin() methods safe to be called multiple times
Optimized CDC class

* Fix CDC Connect/Disconnect detection in Arduino IDE on Windows

* Rework cdc_write

* Update ESP32-S2 board configs
2021-08-02 15:35:13 +03:00
be84c8219c [WiFiClient] Default connection timeout, when no timeout provided (#5487)
## The problem
WiFiClient's connect method variant where no timeout is passed can block esp32 MCU and may then cause watchdog to kick in and reset the device. This behavior is different from that, what is in arduino-esp8266 core.

## Summary
Some cross-esp libraries (working both on esp32 and 8266), like PubSubClient simply call connect method on WiFiClient, to get connected to remote server. However, connect behavior varies betwen esp arduino 8266 and esp arduino 32 cores. This pull request tries introduce same behavior - to make connect method non-blocking on esp32, like it is with 8266 arduino core.

## Proposed solution
Introduce default fixed timeout that can be changed by #define - by default set to 3 seconds.

### Affected components: 
WiFiClient

### Affected methods:
```c++ 
int connect(IPAddress ip, uint16_t port);
int connect(const char *host, uint16_t port);
```

### Impact
May impact projects or libraries using connect method variant without specified timeout, where:
- remote is located far away or
- connection is heavily limited, or
- remote is slow, when it comes to accept the connection
2021-08-02 15:05:44 +03:00
31127f4260 Support for Transfer-Encoding headers that specify "identify" (#5486)
In [HTTPClient](https://github.com/espressif/arduino-esp32/tree/master/libraries/HTTPClient), if the `Transfer-Encoding` header is set to `identity`, an error (Transfer-Encoding not supported) will occur.

HTTPClient will consider the request as `identity` if the `Transfer-Encoding` header is not set. But it is also defined a response with `identity` explicitly set in the `Transfer-Encoding` header (ref:[MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding)).

This pull request will allow the request to be processed normally even when `identity` is explicitly set.
2021-08-02 15:04:48 +03:00
4365a45401 Fix WiFi Deinit bug
Fixes: https://github.com/espressif/arduino-esp32/issues/4842
2021-08-02 14:57:55 +03:00
023ae75b97 Rework pulseIn to work on ESP32-C3
Fixes: https://github.com/espressif/arduino-esp32/issues/5488
2021-08-02 14:53:11 +03:00
c5a1f3efd7 Corrected CLASSIC_BT_ENABLED to CONFIG_BT_CLASSIC_ENABLED. (#5471)
CLASSIC_BT_ENABLED never worked as was incorrectly named, e.g. see
https://github.com/nkolban/esp32-snippets/issues/890#issuecomment-521520934
Now corrected to the update-to-date name CONFIG_BT_CLASSIC_ENABLED.
2021-07-29 15:06:43 +03:00
9406f8e464 Weaken tinyusb callbacks (#5475) 2021-07-29 14:52:30 +03:00
65eafd16b5 Fixes ESP32-S2 LEDC PWM #5375 #5050 (#5452)
Fixes: #5375
Fixes: #5050
2021-07-26 20:37:44 +03:00
d5a98f9a39 Doc: Updated Troubleshooting file (#5430) 2021-07-26 20:37:12 +03:00
3780b5c924 Unbreak integer to string conversion functions. (#5423) (#5438) 2021-07-26 16:06:13 +03:00
1775dd1faa Add ReadTheDocs CI (#5456) 2021-07-26 16:04:20 +03:00
6972695d95 IDF master c69f0ec32 (#5449)
esp-dsp: master f4d7d6e
esp-face: master 420fc7e
esp-rainmaker: f1b82c7
esp32-camera: master 6a9497b
esp_littlefs: master b58f00c
2021-07-26 15:56:05 +03:00
e0e5c88658 Create PULL_REQUEST_TEMPLATE.md (#5439)
Adding first version of PULL_REQUEST_TEMPLATE.md.

The purpose of this template is to improve and simplify writing more accurate Release Notes.
2021-07-26 15:37:14 +03:00
6e47e18a1b Add files via upload (#5433)
Newly compiled esp32-camera driver from https://github.com/espressif/esp32-camera
2021-07-22 20:10:49 +03:00
34125cee1d Examples update, add a note for configTime() that only one ntp server is supported by lwip (#5343)
lwip lib bundled with esp32 Arduino supports only one ntp server. Any additional servers set are just silently ignored.
This default is different from esp8266 Arduino core and very confusing. Most of the examples provided uses 3 different ntp servers for redundancy while only the first one is used actually.
Addressing issue #4964
2021-07-22 20:09:28 +03:00
ee24736042 Update README.md 2021-07-22 17:05:54 +03:00
5458df0a54 Fixes Serial.end() hanging on ESP32-S2 (#5434)
Fixes: #5429
2021-07-21 17:02:06 +03:00
e12d8c8ff1 fix: WiFiClientSecure connection timeout (#5398) (#5418)
Closes #5398

Using the same non-blocking socket connect pattern for respecting connection timeout, copied from WiFiClient::connect.

WiFiClient::connect uses lwip_connect_r, whereas start_ssl_client uses lwip_connect. I haven't found what is the difference between them. I tested both, both work ok, so I kept lwip_connect.
2021-07-21 13:20:23 +03:00
2148 changed files with 144306 additions and 59357 deletions

View File

@ -0,0 +1,54 @@
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 ...

130
.github/ISSUE_TEMPLATE/Issue-report.yml vendored Normal file
View File

@ -0,0 +1,130 @@
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
- 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, IDF component...
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 your sketch/code which was run
placeholder: ex. related part of the code
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

View File

@ -1,54 +0,0 @@
---
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
```

8
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,8 @@
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

18
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,18 @@
*By completing this PR sufficiently, you help us to 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, other Project, submodule PR..)
3. [ ] 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.*
-----------
## Summary
Please describe your proposed PR and what it contains.
## Impact
Please describe impact of your PR and it's function.
## Related links
Please provide links to related issue, PRs etc.

View File

@ -1,6 +1,6 @@
#!/bin/bash
#
# This script is for Travis. It checks all non-examples source files in libraries/ and cores/ are listed in
# This script is used in the CI workflow. It checks all non-examples source files in libraries/ and cores/ are listed in
# 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
@ -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`
# find all source files named in CMakeLists.txt COMPONENT_SRCS
CMAKE_SRCS=`cmake --trace-expand -C CMakeLists.txt 2>&1 | grep set\(srcs | cut -d'(' -f3 | sed 's/ )//' | sed 's/srcs //' | tr ' ;' '\n' | sort`
CMAKE_SRCS=`cmake --trace-expand -P 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
echo "Source files in repo (-) and source files in CMakeLists.txt (+) don't match"

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

View File

@ -2,18 +2,7 @@
set -e
if [ ! -z "$TRAVIS_TAG" ]; then
echo "Skipping Test: Tagged build"
exit 0
fi
if [ ! -z "$GITHUB_WORKSPACE" ]; then
export TRAVIS_BUILD_DIR="$GITHUB_WORKSPACE"
export TRAVIS_REPO_SLUG="$GITHUB_REPOSITORY"
elif [ ! -z "$TRAVIS_BUILD_DIR" ]; then
export GITHUB_WORKSPACE="$TRAVIS_BUILD_DIR"
export GITHUB_REPOSITORY="$TRAVIS_REPO_SLUG"
else
if [ -z "$GITHUB_WORKSPACE" ]; then
export GITHUB_WORKSPACE="$PWD"
export GITHUB_REPOSITORY="espressif/arduino-esp32"
fi

79
.github/stale.yml vendored
View File

@ -1,61 +1,26 @@
# Configuration for probot-stale - https://github.com/probot/stale
# This workflow firstly warns and then closes issues that have had no activity for a specified amount of time.
#
# You can adjust the behavior by modifying this file.
# For more information can be found here: https://github.com/actions/stale
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 60
name: Mark stale issues
on:
schedule:
- cron: '30 9 * * *'
# 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
jobs:
stale:
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
onlyLabels: []
runs-on: ubuntu-latest
permissions:
issues: write
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
exemptLabels:
- "Type: For reference"
- "Type: To be implemented"
- "Type: Feature request"
# 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: "Status: 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
steps:
- uses: actions/stale@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: '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.'
days-before-stale: 60
days-before-close: 14
exempt-issue-labels: 'Type: For reference,Type: To be implemented,Type: Feature request'
stale-issue-label: 'Status: Stale'

38
.github/workflows/docs.yml vendored Normal file
View File

@ -0,0 +1,38 @@
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

@ -16,7 +16,7 @@ jobs:
name: Build GitHub Pages
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v2
- name: Copy Files
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -18,8 +18,8 @@ jobs:
chunk: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
steps:
- uses: actions/checkout@v1
- uses: actions/setup-python@v1
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Build Sketches
@ -34,8 +34,8 @@ jobs:
os: [windows-latest, macOS-latest]
steps:
- uses: actions/checkout@v1
- uses: actions/setup-python@v1
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Build Sketches
@ -50,8 +50,8 @@ jobs:
os: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- uses: actions/checkout@v1
- uses: actions/setup-python@v1
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Build Sketches

View File

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

View File

@ -0,0 +1,28 @@
name: Test Github action on self hosted RPI runnes
on:
push:
branches:
- master
pull_request:
jobs:
build:
name: Dummy test - self hosted GHR
runs-on: self-hosted
if: github.repository == 'espressif/arduino-esp32'
steps:
- name: Check out repo
uses: actions/checkout@v2
- name: Test message 1
run: echo "This is test message"
- name: Test message 2
run: echo "This is test message2"
- name: List directory
run: ls
- name: Create copy of README
run: cp README.md README2.md
- name: Read README2
run: cat README2.md
- name: Delete README2
run: rm README2.md

1
.gitignore vendored
View File

@ -21,3 +21,4 @@ boards.sloeber.txt
# Ignore docs build (Sphinx)
docs/build
docs/source/_build

View File

@ -1,55 +0,0 @@
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,3 +1,27 @@
# 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
cores/esp32/base64.cpp
cores/esp32/cbuf.cpp
@ -7,6 +31,7 @@ set(CORE_SRCS
cores/esp32/esp32-hal-dac.c
cores/esp32/esp32-hal-gpio.c
cores/esp32/esp32-hal-i2c.c
cores/esp32/esp32-hal-i2c-slave.c
cores/esp32/esp32-hal-ledc.c
cores/esp32/esp32-hal-matrix.c
cores/esp32/esp32-hal-misc.c
@ -32,8 +57,12 @@ set(CORE_SRCS
cores/esp32/stdlib_noniso.c
cores/esp32/Stream.cpp
cores/esp32/StreamString.cpp
cores/esp32/HWCDC.cpp
cores/esp32/USB.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_shift.c
cores/esp32/WMath.cpp
@ -50,6 +79,7 @@ set(LIBRARY_SRCS
libraries/DNSServer/src/DNSServer.cpp
libraries/EEPROM/src/EEPROM.cpp
libraries/ESPmDNS/src/ESPmDNS.cpp
libraries/Ethernet/src/ETH.cpp
libraries/FFat/src/FFat.cpp
libraries/FS/src/FS.cpp
libraries/FS/src/vfs_api.cpp
@ -73,12 +103,19 @@ set(LIBRARY_SRCS
libraries/Ticker/src/Ticker.cpp
libraries/Update/src/Updater.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/Parsing.cpp
libraries/WebServer/src/detail/mimetable.cpp
libraries/WiFiClientSecure/src/ssl_client.cpp
libraries/WiFiClientSecure/src/WiFiClientSecure.cpp
libraries/WiFi/src/ETH.cpp
libraries/WiFi/src/WiFiAP.cpp
libraries/WiFi/src/WiFiClient.cpp
libraries/WiFi/src/WiFi.cpp
@ -151,6 +188,7 @@ set(includedirs
libraries/SPI/src
libraries/Ticker/src
libraries/Update/src
libraries/USB/src
libraries/WebServer/src
libraries/WiFiClientSecure/src
libraries/WiFi/src
@ -161,7 +199,7 @@ set(includedirs
set(srcs ${CORE_SRCS} ${LIBRARY_SRCS} ${BLE_SRCS})
set(priv_includes cores/esp32/libb64)
set(requires spi_flash mbedtls mdns esp_adc_cal wifi_provisioning nghttp)
set(priv_requires fatfs nvs_flash app_update spiffs bootloader_support openssl bt esp_ipc)
set(priv_requires fatfs nvs_flash app_update spiffs bootloader_support openssl bt esp_ipc esp_hid)
idf_component_register(INCLUDE_DIRS ${includedirs} PRIV_INCLUDE_DIRS ${priv_includes} SRCS ${srcs} REQUIRES ${requires} PRIV_REQUIRES ${priv_requires})

View File

@ -1,31 +1,20 @@
# Arduino core for the ESP32
# Arduino core for the ESP32, ESP32-S2 and ESP32-C3
[![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) [![Documentation Status](https://readthedocs.com/projects/espressif-arduino-esp32/badge/?version=latest)](https://docs.espressif.com/projects/arduino-esp32/en/latest/?badge=latest)
![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)
## Contents
- [ESP32-S2 and ESP32-C3 Support](#esp32-s2-and-esp32-c3-support)
- [Development Status](#development-status)
- [Decoding Exceptions](#decoding-exceptions)
- [Issue/Bug report template](#issuebug-report-template)
### ESP32-S2 and ESP32-C3 Support
If you want to test ESP32-S2 and/or ESP32-C3 through the board manager, please use the development release link:
```
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json
```
Now you can install the latest 2.0.0 version from the boards manager.
### 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 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/)
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/)
### Documentation
@ -38,14 +27,18 @@ You can use [Arduino-ESP32 Online Documentation](https://docs.espressif.com/proj
* [FAQ](https://docs.espressif.com/projects/arduino-esp32/en/latest/faq.html)
* [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
You can use [EspExceptionDecoder](https://github.com/me-no-dev/EspExceptionDecoder) to get meaningful call trace.
### 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).
### Contributing

2418
boards.txt

File diff suppressed because it is too large Load Diff

View File

@ -179,6 +179,9 @@ uint16_t makeWord(uint8_t h, uint8_t l);
#define word(...) makeWord(__VA_ARGS__)
size_t getArduinoLoopTaskStackSize(void);
#define SET_LOOP_TASK_STACK_SIZE(sz) size_t getArduinoLoopTaskStackSize() { return sz;}
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);

View File

@ -38,6 +38,7 @@ extern "C" {
#define ESP_FLASH_IMAGE_BASE 0x1000 // Flash offset containing flash size and spi mode
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/spi_flash.h"
#include "soc/efuse_reg.h"
#define ESP_FLASH_IMAGE_BASE 0x1000
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/spi_flash.h"
@ -270,7 +271,17 @@ const char * EspClass::getChipModel(void)
return "Unknown";
}
#elif CONFIG_IDF_TARGET_ESP32S2
return "ESP32-S2";
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";
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

424
cores/esp32/FirmwareMSC.cpp Normal file
View File

@ -0,0 +1,424 @@
// 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 */

70
cores/esp32/FirmwareMSC.h Normal file
View File

@ -0,0 +1,70 @@
// 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 */

388
cores/esp32/HWCDC.cpp Normal file
View File

@ -0,0 +1,388 @@
// 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
#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_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY | USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT | USB_SERIAL_JTAG_INTR_BUS_RESET);
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;
}
}
void HWCDC::end()
{
//Disable tx/rx interrupt.
usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY | USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT | USB_SERIAL_JTAG_INTR_BUS_RESET);
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_HW_CDC_ON_BOOT //Serial used for USB CDC
HWCDC Serial;
#else
HWCDC USBSerial;
#endif
#endif /* CONFIG_TINYUSB_CDC_ENABLED */

107
cores/esp32/HWCDC.h Normal file
View File

@ -0,0 +1,107 @@
// 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
#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_HW_CDC_ON_BOOT //Serial used for USB CDC
extern HWCDC Serial;
#else
extern HWCDC USBSerial;
#endif
#endif /* CONFIG_IDF_TARGET_ESP32C3 */

View File

@ -5,87 +5,141 @@
#include "pins_arduino.h"
#include "HardwareSerial.h"
#include "soc/soc_caps.h"
#ifndef SOC_RX0
#if CONFIG_IDF_TARGET_ESP32
#define SOC_RX0 3
#elif CONFIG_IDF_TARGET_ESP32S2
#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
#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
#if CONFIG_IDF_TARGET_ESP32
#define RX1 9
#elif CONFIG_IDF_TARGET_ESP32S2
#define RX1 18
#elif CONFIG_IDF_TARGET_ESP32C3
#define RX1 18
#endif
#endif
#ifndef TX1
#if CONFIG_IDF_TARGET_ESP32
#define TX1 10
#elif CONFIG_IDF_TARGET_ESP32S2
#define TX1 17
#elif CONFIG_IDF_TARGET_ESP32C3
#define TX1 19
#endif
#endif
void serialEvent1(void) __attribute__((weak));
void serialEvent1(void) {}
#endif /* SOC_UART_NUM > 1 */
#if SOC_UART_NUM > 2
#ifndef RX2
#if CONFIG_IDF_TARGET_ESP32
#define RX2 16
#endif
#endif
#ifndef TX2
#if CONFIG_IDF_TARGET_ESP32
#define TX2 17
#endif
#else
#ifndef RX1
#define RX1 18
#endif
#ifndef TX1
#define TX1 17
#endif
#endif
void serialEvent2(void) __attribute__((weak));
void serialEvent2(void) {}
#endif /* SOC_UART_NUM > 2 */
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
#if ARDUINO_SERIAL_PORT //Serial used for USB CDC
#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC
HardwareSerial Serial0(0);
#elif ARDUINO_HW_CDC_ON_BOOT
HardwareSerial Serial0(0);
#else
HardwareSerial Serial(0);
#endif
#if SOC_UART_NUM > 1
HardwareSerial Serial1(1);
#if CONFIG_IDF_TARGET_ESP32
#endif
#if SOC_UART_NUM > 2
HardwareSerial Serial2(2);
#endif
void serialEventRun(void)
{
#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC
if(Serial0.available()) serialEvent();
#elif ARDUINO_HW_CDC_ON_BOOT
if(Serial0.available()) serialEvent();
#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
HardwareSerial::HardwareSerial(int uart_nr) : _uart_nr(uart_nr), _uart(NULL) {}
HardwareSerial::HardwareSerial(int uart_nr) : _uart_nr(uart_nr), _uart(NULL), _rxBufferSize(256) {}
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 > 2) {
log_e("Serial number is invalid, please use 0, 1 or 2");
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(_uart) {
end();
// in this case it is a begin() over a previous begin() - maybe to change baud rate
// thus do not disable debug output
end(false);
}
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;
#elif CONFIG_IDF_TARGET_ESP32C3
rxPin = 20;
txPin = 21;
#endif
rxPin = SOC_RX0;
txPin = SOC_TX0;
}
#if SOC_UART_NUM > 1
if(_uart_nr == 1 && rxPin < 0 && txPin < 0) {
rxPin = RX1;
txPin = TX1;
}
#if CONFIG_IDF_TARGET_ESP32
#endif
#if SOC_UART_NUM > 2
if(_uart_nr == 2 && rxPin < 0 && txPin < 0) {
rxPin = RX2;
txPin = TX2;
}
#endif
_uart = uartBegin(_uart_nr, baud ? baud : 9600, config, rxPin, txPin, 256, invert, rxfifo_full_thrhd);
_tx_pin = txPin;
_rx_pin = rxPin;
if(!baud) {
_uart = uartBegin(_uart_nr, baud ? baud : 9600, config, rxPin, txPin, _rxBufferSize, 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);
time_t startMillis = millis();
unsigned long detectedBaudRate = 0;
@ -93,16 +147,14 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
yield();
}
end();
end(false);
if(detectedBaudRate) {
delay(100); // Give some time...
_uart = uartBegin(_uart_nr, detectedBaudRate, config, rxPin, txPin, 256, invert, rxfifo_full_thrhd);
_uart = uartBegin(_uart_nr, detectedBaudRate, config, rxPin, txPin, _rxBufferSize, invert, rxfifo_full_thrhd);
} else {
log_e("Could not detect baudrate. Serial data at the port must be present within the timeout for detection to be possible");
_uart = NULL;
_tx_pin = 255;
_rx_pin = 255;
}
}
}
@ -112,21 +164,16 @@ void HardwareSerial::updateBaudRate(unsigned long baud)
uartSetBaudRate(_uart, baud);
}
void HardwareSerial::end()
void HardwareSerial::end(bool turnOffDebug)
{
if(uartGetDebug() == _uart_nr) {
if(turnOffDebug && uartGetDebug() == _uart_nr) {
uartSetDebug(0);
}
delay(10);
log_v("pins %d %d",_tx_pin, _rx_pin);
uartEnd(_uart, _tx_pin, _rx_pin);
uartEnd(_uart);
_uart = 0;
}
size_t HardwareSerial::setRxBufferSize(size_t new_size) {
return uartResizeRxBuffer(_uart, new_size);
}
void HardwareSerial::setDebugOutput(bool en)
{
if(_uart == 0) {
@ -212,10 +259,31 @@ uint32_t HardwareSerial::baudRate()
}
HardwareSerial::operator bool() const
{
return true;
return uartIsDriverInstalled(_uart);
}
void HardwareSerial::setRxInvert(bool invert)
{
uartSetRxInvert(_uart, invert);
}
void HardwareSerial::setPins(uint8_t rxPin, uint8_t txPin)
{
uartSetPins(_uart, rxPin, txPin);
}
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);
return 0;
}
_rxBufferSize = new_size;
return _rxBufferSize;
}

View File

@ -49,6 +49,8 @@
#include "Stream.h"
#include "esp32-hal.h"
#include "soc/soc_caps.h"
#include "HWCDC.h"
class HardwareSerial: public Stream
{
@ -56,7 +58,7 @@ public:
HardwareSerial(int uart_nr);
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();
void end(bool turnOffDebug = true);
void updateBaudRate(unsigned long baud);
int available(void);
int availableForWrite(void);
@ -98,33 +100,37 @@ public:
uint32_t baudRate();
operator bool() const;
size_t setRxBufferSize(size_t);
void setDebugOutput(bool);
void setRxInvert(bool);
void setPins(uint8_t rxPin, uint8_t txPin);
size_t setRxBufferSize(size_t new_size);
protected:
int _uart_nr;
uart_t* _uart;
uint8_t _tx_pin;
uint8_t _rx_pin;
size_t _rxBufferSize;
};
extern void serialEventRun(void) __attribute__((weak));
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
#ifndef ARDUINO_SERIAL_PORT
#define ARDUINO_SERIAL_PORT 0
#ifndef ARDUINO_USB_CDC_ON_BOOT
#define ARDUINO_USB_CDC_ON_BOOT 0
#endif
#if ARDUINO_SERIAL_PORT //Serial used for USB CDC
#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC
#include "USB.h"
#include "USBCDC.h"
extern HardwareSerial Serial0;
#elif ARDUINO_HW_CDC_ON_BOOT
extern HardwareSerial Serial0;
#else
extern HardwareSerial Serial;
#endif
#if SOC_UART_NUM > 1
extern HardwareSerial Serial1;
#if CONFIG_IDF_TARGET_ESP32
#endif
#if SOC_UART_NUM > 2
extern HardwareSerial Serial2;
#endif
#endif

View File

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

View File

@ -23,25 +23,13 @@
#include <Stream.h>
#include "esp_system.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"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/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
#include "esp_rom_md5.h"
class MD5Builder
{
private:
struct MD5Context _ctx;
uint8_t _buf[16];
md5_context_t _ctx;
uint8_t _buf[ESP_ROM_MD5_DIGEST_LEN];
public:
void begin(void);
void add(uint8_t * data, uint16_t len);

View File

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

View File

@ -11,10 +11,14 @@
// 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_TINYUSB_ENABLED
#include "pins_arduino.h"
#include "esp32-hal.h"
#include "esp32-hal-tinyusb.h"
#include "USB.h"
#if CONFIG_TINYUSB_ENABLED
#include "common/tusb_common.h"
#ifndef USB_VID
#define USB_VID USB_ESPRESSIF_VID
@ -31,14 +35,16 @@
#ifndef USB_SERIAL
#define USB_SERIAL "0"
#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
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)
uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB DFU_RT");
@ -80,14 +86,14 @@ static bool tinyusb_device_suspended = false;
// Invoked when device is mounted (configured)
void tud_mount_cb(void){
tinyusb_device_mounted = true;
arduino_usb_event_data_t p = {0};
arduino_usb_event_data_t p;
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
void tud_umount_cb(void){
tinyusb_device_mounted = false;
arduino_usb_event_data_t p = {0};
arduino_usb_event_data_t p;
arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY);
}
@ -95,7 +101,7 @@ void tud_umount_cb(void){
// Within 7ms, device must draw an average of current less than 2.5 mA from bus
void tud_suspend_cb(bool remote_wakeup_en){
tinyusb_device_suspended = true;
arduino_usb_event_data_t p = {0};
arduino_usb_event_data_t p;
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);
}
@ -103,7 +109,7 @@ void tud_suspend_cb(bool remote_wakeup_en){
// Invoked when usb bus is resumed
void tud_resume_cb(void){
tinyusb_device_suspended = false;
arduino_usb_event_data_t p = {0};
arduino_usb_event_data_t p;
arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_RESUME_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY);
}
@ -120,8 +126,8 @@ ESPUSB::ESPUSB(size_t task_stack_size, uint8_t event_task_priority)
,usb_protocol(MISC_PROTOCOL_IAD)
,usb_attributes(TUSB_DESC_CONFIG_ATT_SELF_POWERED)
,usb_power_ma(500)
,webusb_enabled(false)
,webusb_url("https://espressif.github.io/arduino-esp32/webusb.html")
,webusb_enabled(USB_WEBUSB_ENABLED)
,webusb_url(USB_WEBUSB_URL)
,_started(false)
,_task_stack_size(task_stack_size)
,_event_task_priority(event_task_priority)

View File

@ -14,12 +14,13 @@
#pragma once
#include "sdkconfig.h"
#if CONFIG_TINYUSB_ENABLED
#include "Arduino.h"
#include "esp_event.h"
#include "USBCDC.h"
#include "esp_event.h"
#define ARDUINO_USB_ON_BOOT (ARDUINO_USB_CDC_ON_BOOT|ARDUINO_USB_MSC_ON_BOOT|ARDUINO_USB_DFU_ON_BOOT)
ESP_EVENT_DECLARE_BASE(ARDUINO_USB_EVENTS);

View File

@ -11,24 +11,22 @@
// 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 "esp32-hal.h"
#include "esp32-hal-tinyusb.h"
#include "USB.h"
#if CONFIG_TINYUSB_CDC_ENABLED
#include "USBCDC.h"
#if CONFIG_TINYUSB_ENABLED
#include "esp32-hal-tinyusb.h"
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_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg);
#if CFG_TUD_CDC
#define MAX_USB_CDC_DEVICES 2
USBCDC * devices[MAX_USB_CDC_DEVICES] = {NULL, NULL};
static uint16_t load_cdc_descriptor(uint8_t * dst, uint8_t * itf)
{
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] = {
// 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)
@ -41,7 +39,6 @@ static uint16_t load_cdc_descriptor(uint8_t * dst, uint8_t * itf)
// 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)
{
//isr_log_v("itf: %u, dtr: %u, rts: %u", itf, dtr, rts);
if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){
devices[itf]->_onLineState(dtr, rts);
}
@ -50,7 +47,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)
{
//isr_log_v("itf: %u, bit_rate: %u, data_bits: %u, stop_bits: %u, parity: %u", itf, p_line_coding->bit_rate, p_line_coding->data_bits, p_line_coding->stop_bits, p_line_coding->parity);
if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){
devices[itf]->_onLineCoding(p_line_coding->bit_rate, p_line_coding->stop_bits, p_line_coding->parity, p_line_coding->data_bits);
}
@ -59,7 +55,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)
{
//isr_log_v("itf: %u", itf);
if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){
devices[itf]->_onRX();
}
@ -67,67 +62,50 @@ 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){
//isr_log_v("itf: %u, duration_ms: %u", itf, duration_ms);
//log_v("itf: %u, duration_ms: %u", itf, duration_ms);
}
// Invoked when space becomes available in TX buffer
void tud_cdc_tx_complete_cb(uint8_t itf){
//isr_log_v("itf: %u", itf);
if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){
xSemaphoreGive(devices[itf]->tx_sem);
devices[itf]->_onTX();
}
}
static size_t tinyusb_cdc_write(uint8_t itf, const uint8_t *buffer, size_t size){
if(itf >= MAX_USB_CDC_DEVICES){
return 0;
static void ARDUINO_ISR_ATTR cdc0_write_char(char c){
if(devices[0] != NULL){
devices[0]->write(c);
}
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);
xSemaphoreTake(devices[itf]->tx_sem, portMAX_DELAY);
}
return sofar;
}
static void ARDUINO_ISR_ATTR cdc0_write_char(char c)
{
tinyusb_cdc_write(0, (const uint8_t *)&c, 1);
}
//void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char);
static void usb_unplugged_cb(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data){
((USBCDC*)arg)->_onUnplugged();
}
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) {
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)
, tx_lock(NULL)
, tx_timeout_ms(250)
{
tinyusb_enable_interface(USB_INTERFACE_CDC, TUD_CDC_DESC_LEN, load_cdc_descriptor);
if(itf < MAX_USB_CDC_DEVICES){
devices[itf] = this;
tx_sem = NULL;
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){
onEvent(ARDUINO_USB_CDC_ANY_EVENT, callback);
}
@ -137,6 +115,10 @@ void USBCDC::onEvent(arduino_usb_cdc_event_t event, esp_event_handler_t callback
size_t USBCDC::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));
@ -148,27 +130,33 @@ size_t USBCDC::setRxBufferSize(size_t rx_queue_len){
void USBCDC::begin(unsigned long baud)
{
setRxBufferSize(256);//default if not preset
if(tx_sem == NULL){
tx_sem = xSemaphoreCreateBinary();
xSemaphoreTake(tx_sem, 0);
if(tx_lock == NULL) {
tx_lock = xSemaphoreCreateMutex();
}
setRxBufferSize(256);//default if not preset
devices[itf] = this;
}
void USBCDC::end()
{
if (tx_sem != NULL) {
vSemaphoreDelete(tx_sem);
tx_sem = NULL;
connected = false;
devices[itf] = NULL;
setRxBufferSize(0);
if(tx_lock != NULL) {
vSemaphoreDelete(tx_lock);
}
}
void USBCDC::setTxTimeoutMs(uint32_t timeout){
tx_timeout_ms = timeout;
}
void USBCDC::_onUnplugged(void){
if(connected){
connected = false;
dtr = false;
rts = false;
arduino_usb_cdc_event_data_t p = {0};
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);
}
}
@ -176,6 +164,11 @@ void USBCDC::_onUnplugged(void){
enum { CDC_LINE_IDLE, CDC_LINE_1, CDC_LINE_2, CDC_LINE_3 };
void USBCDC::_onLineState(bool _dtr, bool _rts){
static uint8_t lineState = CDC_LINE_IDLE;
if(dtr == _dtr && rts == _rts){
return; // Skip duplicate events
}
dtr = _dtr;
rts = _rts;
@ -183,6 +176,11 @@ void USBCDC::_onLineState(bool _dtr, bool _rts){
if(!dtr && rts){
if(lineState == CDC_LINE_IDLE){
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 {
lineState = CDC_LINE_IDLE;
}
@ -210,14 +208,14 @@ void USBCDC::_onLineState(bool _dtr, bool _rts){
if(lineState == CDC_LINE_IDLE){
if(dtr && rts && !connected){
connected = true;
arduino_usb_cdc_event_data_t p = {0};
arduino_usb_cdc_event_data_t p;
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 && !rts && connected){
} else if(!dtr && connected){
connected = false;
arduino_usb_cdc_event_data_t p = {0};
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);
}
arduino_usb_cdc_event_data_t l = {0};
arduino_usb_cdc_event_data_t l;
l.line_state.dtr = dtr;
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);
@ -228,14 +226,14 @@ 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){
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(_bit_rate == 1200){
if(reboot_enable && _bit_rate == 1200){
usb_persist_restart(RESTART_BOOTLOADER);
} else {
bit_rate = _bit_rate;
data_bits = _data_bits;
stop_bits = _stop_bits;
parity = _parity;
arduino_usb_cdc_event_data_t p = {0};
arduino_usb_cdc_event_data_t p;
p.line_coding.bit_rate = bit_rate;
p.line_coding.data_bits = data_bits;
p.line_coding.stop_bits = stop_bits;
@ -253,13 +251,13 @@ void USBCDC::_onRX(){
return;
}
}
arduino_usb_cdc_event_data_t p = {0};
arduino_usb_cdc_event_data_t p;
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);
}
void USBCDC::_onTX(){
arduino_usb_cdc_event_data_t p = {0};
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);
}
@ -317,23 +315,73 @@ size_t USBCDC::read(uint8_t *buffer, size_t size)
void USBCDC::flush(void)
{
if(itf >= MAX_USB_CDC_DEVICES){
if(itf >= MAX_USB_CDC_DEVICES || tx_lock == NULL || !tud_cdc_n_connected(itf)){
return;
}
if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){
return;
}
tud_cdc_n_write_flush(itf);
xSemaphoreGive(tx_lock);
}
int USBCDC::availableForWrite(void)
{
if(itf >= MAX_USB_CDC_DEVICES){
return -1;
if(itf >= MAX_USB_CDC_DEVICES || tx_lock == NULL || !tud_cdc_n_connected(itf)){
return 0;
}
return tud_cdc_n_write_available(itf);
if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){
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)
{
return tinyusb_cdc_write(itf, buffer, size);
if(itf >= MAX_USB_CDC_DEVICES || tx_lock == NULL || buffer == NULL || size == 0 || !tud_cdc_n_connected(itf)){
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)
@ -364,10 +412,8 @@ USBCDC::operator bool() const
return connected;
}
#if ARDUINO_SERIAL_PORT //Serial used for USB CDC
#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC
USBCDC Serial(0);
#endif
#endif /* CONFIG_TINYUSB_CDC_ENABLED */
#endif /* CONFIG_TINYUSB_ENABLED */

View File

@ -13,13 +13,15 @@
// limitations under the License.
#pragma once
#include <inttypes.h>
#include "Stream.h"
#include "esp32-hal.h"
#include "sdkconfig.h"
#if CONFIG_TINYUSB_CDC_ENABLED
#include <inttypes.h>
#include "esp_event.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "Stream.h"
ESP_EVENT_DECLARE_BASE(ARDUINO_USB_CDC_EVENTS);
@ -54,11 +56,13 @@ class USBCDC: public Stream
{
public:
USBCDC(uint8_t itf=0);
~USBCDC();
void onEvent(esp_event_handler_t callback);
void onEvent(arduino_usb_cdc_event_t event, esp_event_handler_t callback);
size_t setRxBufferSize(size_t);
size_t setRxBufferSize(size_t size);
void setTxTimeoutMs(uint32_t timeout);
void begin(unsigned long baud=0);
void end();
@ -113,7 +117,6 @@ public:
void _onRX(void);
void _onTX(void);
void _onUnplugged(void);
xSemaphoreHandle tx_sem;
protected:
uint8_t itf;
@ -126,10 +129,12 @@ protected:
bool connected;
bool reboot_enable;
xQueueHandle rx_queue;
xSemaphoreHandle tx_lock;
uint32_t tx_timeout_ms;
};
#if ARDUINO_SERIAL_PORT //Serial used for USB CDC
#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC
extern USBCDC Serial;
#endif

260
cores/esp32/USBMSC.cpp Normal file
View File

@ -0,0 +1,260 @@
// 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 */

51
cores/esp32/USBMSC.h Normal file
View File

@ -0,0 +1,51 @@
// 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

@ -35,6 +35,12 @@ String::String(const char *cstr) {
copy(cstr, strlen(cstr));
}
String::String(const char *cstr, unsigned int length) {
init();
if (cstr)
copy(cstr, length);
}
String::String(const String &value) {
init();
*this = value;
@ -705,10 +711,7 @@ String String::substring(unsigned int left, unsigned int right) const {
return out;
if(right > len())
right = len();
char temp = buffer()[right]; // save the replaced character
wbuffer()[right] = '\0';
out = wbuffer() + left; // pointer arithmetic
wbuffer()[right] = temp; //restore character
out.copy(buffer() + left, right - left);
return out;
}

View File

@ -55,6 +55,10 @@ class String {
// fails, the string will be marked as invalid (i.e. "if (s)" will
// be false).
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 __FlashStringHelper *str);
#ifdef __GXX_EXPERIMENTAL_CXX0X__
@ -108,6 +112,8 @@ class String {
// concatenation is considered unsuccessful.
unsigned char concat(const String &str);
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(unsigned char c);
unsigned char concat(int num);
@ -326,7 +332,6 @@ class String {
void init(void);
void invalidate(void);
unsigned char changeBuffer(unsigned int maxStrLen);
unsigned char concat(const char *cstr, unsigned int length);
// copy and move
String & copy(const char *cstr, unsigned int length);

View File

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

View File

@ -37,7 +37,7 @@ static uint8_t __analogVRefPin = 0;
#include "soc/rtc_io_reg.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/ets_sys.h"
#else
#else
#error Target CONFIG_IDF_TARGET is not supported
#endif
#else // ESP32 Before IDF 4.0
@ -46,10 +46,23 @@ static uint8_t __analogVRefPin = 0;
#endif
static uint8_t __analogAttenuation = 3;//11db
static uint8_t __analogWidth = 3;//12 bits
static uint8_t __analogWidth = ADC_WIDTH_MAX - 1; //3 for ESP32/ESP32C3; 4 for ESP32S2
static uint8_t __analogReturnedWidth = SOC_ADC_MAX_BITWIDTH; //12 for ESP32/ESP32C3; 13 for ESP32S2
static uint8_t __analogClockDiv = 1;
static adc_attenuation_t __pin_attenuation[SOC_GPIO_PIN_COUNT];
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){
if(!clockDiv){
clockDiv = 1;
@ -104,7 +117,9 @@ void __analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation)
adc1_config_channel_atten(channel, attenuation);
}
__analogInit();
__pin_attenuation[pin] = attenuation;
if((__pin_attenuation[pin] != ADC_ATTENDB_MAX) || (attenuation != __analogAttenuation)){
__pin_attenuation[pin] = attenuation;
}
}
bool __adcAttachPin(uint8_t pin){
@ -113,6 +128,7 @@ bool __adcAttachPin(uint8_t pin){
log_e("Pin %u is not ADC pin!", pin);
return false;
}
__analogInit();
int8_t pad = digitalPinToTouchChannel(pin);
if(pad >= 0){
#if CONFIG_IDF_TARGET_ESP32
@ -143,6 +159,7 @@ void __analogReadResolution(uint8_t bits)
if(!bits || bits > 16){
return;
}
__analogReturnedWidth = bits;
#if CONFIG_IDF_TARGET_ESP32
__analogSetWidth(bits); // hadware from 9 to 12
#endif
@ -162,7 +179,7 @@ uint16_t __analogRead(uint8_t pin)
channel -= 10;
r = adc2_get_raw( channel, __analogWidth, &value);
if ( r == ESP_OK ) {
return value;
return mapResolution(value);
} else if ( r == ESP_ERR_INVALID_STATE ) {
log_e("GPIO%u: %s: ADC2 not initialized yet.", pin, esp_err_to_name(r));
} else if ( r == ESP_ERR_TIMEOUT ) {
@ -171,9 +188,10 @@ uint16_t __analogRead(uint8_t pin)
log_e("GPIO%u: %s", pin, esp_err_to_name(r));
}
} else {
return adc1_get_raw(channel);
value = adc1_get_raw(channel);
return mapResolution(value);
}
return value;
return mapResolution(value);
}
uint32_t __analogReadMilliVolts(uint8_t pin){

View File

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

View File

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

View File

@ -37,7 +37,13 @@
#include "soc/periph_defs.h"
#include "soc/rtc_io_reg.h"
#define GPIO_FUNC 1
#else
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/ets_sys.h"
#include "esp32c3/rom/gpio.h"
#include "esp_intr_alloc.h"
#include "soc/periph_defs.h"
#define USE_ESP_IDF_GPIO 1
#else
#define USE_ESP_IDF_GPIO 1
#endif
#else // ESP32 Before IDF 4.0
@ -143,6 +149,29 @@ const DRAM_ATTR esp32_gpioMux_t esp32_gpioMux[SOC_GPIO_PIN_COUNT]={
{0xb8, -1, -1, -1},//SCL?
{0xbc, -1, -1, -1},//INPUT ONLY
{0, -1, -1, -1}
#elif CONFIG_IDF_TARGET_ESP32C3
{0x04, -1, 0, -1}, // ADC1_CH0
{0x08, -1, 1, -1}, // ADC1_CH1
{0x0c, -1, 2, -1}, // ADC1_CH2 | FSPIQ
{0x10, -1, 3, -1}, // ADC1_CH3
{0x14, -1, 4, -1}, // MTMS | ADC1_CH4 | FSPIHD
{0x18, -1, 5, -1}, // MTDI | ADC2_CH0 | FSPIWP
{0x1c, -1, -1, -1}, // MTCK | FSPICLK
{0x20, -1, -1, -1}, // MTDO | FSPID
{0x24, -1, -1, -1}, //
{0x28, -1, -1, -1}, //
{0x2c, -1, -1, -1}, // FSPICSO
{0x30, -1, -1, -1}, //
{0x34, -1, -1, -1}, // SPIHD
{0x38, -1, -1, -1}, // SPIWP
{0x3c, -1, -1, -1}, // SPICSO
{0x40, -1, -1, -1}, // SPICLK
{0x44, -1, -1, -1}, // SPID
{0x48, -1, -1, -1}, // SPIQ
{0x4c, -1, -1, -1}, // USB-
{0x50, -1, -1, -1}, // USB+
{0x54, -1, -1, -1}, // U0RXD
{0x58, -1, -1, -1}, // U0TXD
#endif
};
@ -481,4 +510,3 @@ 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 attachInterruptArg(uint8_t pin, voidFuncPtrArg handler, void * arg, int mode) __attribute__ ((weak, alias("__attachInterruptArg")));
extern void detachInterrupt(uint8_t pin) __attribute__ ((weak, alias("__detachInterrupt")));

View File

@ -0,0 +1,848 @@
// 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
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
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
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(!i2c->lock){
log_e("Lock is not initialized! Did you call i2c_slave_init()?");
return ESP_ERR_NO_MEM;
}
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(!i2c->lock){
log_e("Lock is not initialized! Did you call i2c_slave_init()?");
return ESP_ERR_NO_MEM;
}
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);
uint8_t tx_fifo_len = SOC_I2C_FIFO_LEN - i2c_ll_get_txfifo_len(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
//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

@ -0,0 +1,35 @@
// 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,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// 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_
#define _ESP32_HAL_I2C_H_
@ -22,58 +23,16 @@ extern "C" {
#include <stdint.h>
#include <stdbool.h>
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include <esp_err.h>
// External Wire.h equivalent error Codes
typedef enum {
I2C_ERROR_OK=0,
I2C_ERROR_DEV,
I2C_ERROR_ACK,
I2C_ERROR_TIMEOUT,
I2C_ERROR_BUS,
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
esp_err_t i2cInit(uint8_t i2c_num, int8_t sda, int8_t scl, uint32_t clk_speed);
esp_err_t i2cDeinit(uint8_t i2c_num);
esp_err_t i2cSetClock(uint8_t i2c_num, uint32_t frequency);
esp_err_t i2cGetClock(uint8_t i2c_num, uint32_t * frequency);
esp_err_t i2cWrite(uint8_t i2c_num, uint16_t address, const uint8_t* buff, size_t size, uint32_t timeOutMillis);
esp_err_t i2cRead(uint8_t i2c_num, uint16_t address, uint8_t* buff, size_t size, uint32_t timeOutMillis, size_t *readCount);
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);
bool i2cIsInit(uint8_t i2c_num);
#ifdef __cplusplus
}

View File

@ -13,45 +13,25 @@
// limitations under the License.
#include "esp32-hal.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp32-hal-matrix.h"
#include "soc/ledc_reg.h"
#include "soc/ledc_struct.h"
#include "driver/periph_ctrl.h"
#include "soc/soc_caps.h"
#include "driver/ledc.h"
#include "esp_system.h"
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
#include "soc/dport_reg.h"
#include "esp32/rom/ets_sys.h"
#define LAST_CHAN (15)
#elif CONFIG_IDF_TARGET_ESP32S2
#include "soc/dport_reg.h"
#include "esp32s2/rom/ets_sys.h"
#define LAST_CHAN (7)
#define LEDC_DIV_NUM_HSTIMER0_V LEDC_CLK_DIV_LSTIMER0_V
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/ets_sys.h"
#define LAST_CHAN (7)
#define LEDC_DIV_NUM_HSTIMER0_V LEDC_CLK_DIV_LSTIMER0_V
#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 LEDC_MUTEX_LOCK()
#define LEDC_MUTEX_UNLOCK()
#ifdef SOC_LEDC_SUPPORT_HS_MODE
#define LEDC_CHANNELS (SOC_LEDC_CHANNEL_NUM<<1)
#else
#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;
#define LEDC_CHANNELS (SOC_LEDC_CHANNEL_NUM)
#endif
//Use XTAL clock if possible to avoid timer frequency error when setting APB clock < 80 Mhz
//Need to be fixed in ESP-IDF
#ifdef SOC_LEDC_SUPPORT_XTAL_CLOCK
#define LEDC_DEFAULT_CLK LEDC_USE_XTAL_CLK
#else
#define LEDC_DEFAULT_CLK LEDC_AUTO_CLK
#endif
#define LEDC_MAX_BIT_WIDTH SOC_LEDC_TIMER_BIT_WIDE_NUM
/*
* LEDC Chan to Group/Channel/Timer Mapping
** ledc: 0 => Group: 0, Channel: 0, Timer: 0
@ -71,199 +51,55 @@ xSemaphoreHandle _ledc_sys_lock = NULL;
** ledc: 14 => Group: 1, Channel: 6, 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)]
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){
uint16_t iarg = *(uint16_t*)arg;
uint8_t chan = 0;
old_apb /= 1000000;
new_apb /= 1000000;
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);
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++;
}
}
}
//uint32_t frequency = (80MHz or 1MHz)/((div_num / 256.0)*(1 << bit_num));
static void _ledcSetupTimer(uint8_t chan, uint32_t div_num, uint8_t bit_num, bool apb_clk)
{
uint8_t group=(chan/8), timer=((chan/2)%4);
static bool tHasStarted = false;
static uint16_t _activeChannels = 0;
if(!tHasStarted) {
tHasStarted = true;
periph_module_enable(PERIPH_LEDC_MODULE);
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();
}
uint8_t channels_resolution[LEDC_CHANNELS] = {0};
double ledcSetup(uint8_t chan, double freq, uint8_t bit_num)
{
if(chan > LAST_CHAN) {
if(chan >= LEDC_CHANNELS){
log_e("No more LEDC channels available! You can have maximum %u", LEDC_CHANNELS);
return 0;
}
double res_freq = _ledcSetupTimerFreq(chan, freq, bit_num);
_ledcSetupChannel(chan, LOW);
return res_freq;
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
};
ledc_timer_config(&ledc_timer);
channels_resolution[chan] = bit_num;
return ledc_get_freq(group,timer);
}
void ledcWrite(uint8_t chan, uint32_t duty)
{
if(chan > LAST_CHAN) {
if(chan >= LEDC_CHANNELS){
return;
}
uint8_t group=(chan/8), channel=(chan%8);
LEDC_MUTEX_LOCK();
LEDC_CHAN(group, channel).duty.duty = duty << 4;//25 bit (21.4)
if(duty) {
LEDC_CHAN(group, channel).conf0.sig_out_en = 1;//This is the output enable control bit for channel
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.
#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
} else {
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
//Fixing if all bits in resolution is set = LEDC FULL ON
uint32_t max_duty = (1 << channels_resolution[chan]) - 1;
if(duty == max_duty){
duty = max_duty + 1;
}
LEDC_MUTEX_UNLOCK();
ledc_set_duty(group, channel, duty);
ledc_update_duty(group, channel);
}
uint32_t ledcRead(uint8_t chan)
{
if(chan > LAST_CHAN) {
if(chan >= LEDC_CHANNELS){
return 0;
}
return LEDC.channel_group[chan/8].channel[chan%8].duty.duty >> 4;
uint8_t group=(chan/8), channel=(chan%8);
return ledc_get_duty(group,channel);
}
double ledcReadFreq(uint8_t chan)
@ -271,19 +107,33 @@ double ledcReadFreq(uint8_t chan)
if(!ledcRead(chan)){
return 0;
}
return _ledcTimerRead(chan);
uint8_t group=(chan/8), timer=((chan/2)%4);
return ledc_get_freq(group,timer);
}
double ledcWriteTone(uint8_t chan, double freq)
{
if(chan > LAST_CHAN) {
if(chan >= LEDC_CHANNELS){
return 0;
}
if(!freq) {
if(!freq){
ledcWrite(chan, 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
};
ledc_timer_config(&ledc_timer);
channels_resolution[chan] = 10;
double res_freq = ledc_get_freq(group,timer);
ledcWrite(chan, 0x1FF);
return res_freq;
}
@ -303,15 +153,21 @@ double ledcWriteNote(uint8_t chan, note_t note, uint8_t octave){
void ledcAttachPin(uint8_t pin, uint8_t chan)
{
if(chan > LAST_CHAN) {
if(chan >= LEDC_CHANNELS){
return;
}
pinMode(pin, OUTPUT);
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
pinMatrixOutAttach(pin, LEDC_LS_SIG_OUT0_IDX + chan, false, false);
#else
pinMatrixOutAttach(pin, ((chan/8)?LEDC_LS_SIG_OUT0_IDX:LEDC_HS_SIG_OUT0_IDX) + (chan%8), false, false);
#endif
uint8_t group=(chan/8), channel=(chan%8), timer=((chan/2)%4);
ledc_channel_config_t ledc_channel = {
.speed_mode = group,
.channel = channel,
.timer_sel = timer,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = pin,
.duty = 0,
.hpoint = 0
};
ledc_channel_config(&ledc_channel);
}
void ledcDetachPin(uint8_t pin)
@ -321,9 +177,38 @@ void ledcDetachPin(uint8_t pin)
double ledcChangeFrequency(uint8_t chan, double freq, uint8_t bit_num)
{
if (chan > 15) {
if(chan >= LEDC_CHANNELS){
return 0;
}
double res_freq = _ledcSetupTimerFreq(chan, freq, bit_num);
return res_freq;
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
};
ledc_timer_config(&ledc_timer);
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

@ -66,6 +66,8 @@ extern "C"
#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_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
#define ARDUHAL_LOG_COLOR_E
#define ARDUHAL_LOG_COLOR_W
@ -73,12 +75,15 @@ extern "C"
#define ARDUHAL_LOG_COLOR_D
#define ARDUHAL_LOG_COLOR_V
#define ARDUHAL_LOG_RESET_COLOR
#define ARDUHAL_LOG_COLOR_PRINT(letter)
#define ARDUHAL_LOG_COLOR_PRINT_END
#endif
const char * pathToFileName(const char * path);
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_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__
@ -87,78 +92,96 @@ int log_printf(const char *fmt, ...);
#ifndef USE_ESP_IDF_LOG
#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 log_buf_v(b,l) do{ARDUHAL_LOG_COLOR_PRINT(V);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0)
#else
#define log_v(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_VERBOSE, TAG, format, ##__VA_ARGS__);}while(0)
#define isr_log_v(format, ...) do {ets_printf(LOG_FORMAT(V, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0)
#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, ...)
#define isr_log_v(format, ...)
#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
#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 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
#define log_d(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_DEBUG, TAG, format, ##__VA_ARGS__);}while(0)
#define isr_log_d(format, ...) do {ets_printf(LOG_FORMAT(D, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0)
#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, ...)
#define isr_log_d(format, ...)
#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
#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 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
#define log_i(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_INFO, TAG, format, ##__VA_ARGS__);}while(0)
#define isr_log_i(format, ...) do {ets_printf(LOG_FORMAT(I, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0)
#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, ...)
#define isr_log_i(format, ...)
#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
#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 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
#define log_w(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_WARN, TAG, format, ##__VA_ARGS__);}while(0)
#define isr_log_w(format, ...) do {ets_printf(LOG_FORMAT(W, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0)
#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, ...)
#define isr_log_w(format, ...)
#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
#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 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
#define log_e(format, ...) do {log_to_esp(TAG, ESP_LOG_ERROR, format, ##__VA_ARGS__);}while(0)
#define isr_log_e(format, ...) do {ets_printf(LOG_FORMAT(E, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0)
#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, ...)
#define isr_log_e(format, ...)
#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
#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 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
#define log_n(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_ERROR, TAG, format, ##__VA_ARGS__);}while(0)
#define isr_log_n(format, ...) do {ets_printf(LOG_FORMAT(E, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0)
#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, ...)
#define isr_log_n(format, ...)
#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
#include "esp_log.h"

File diff suppressed because it is too large Load Diff

View File

@ -25,6 +25,9 @@ extern "C" {
#define RMT_FLAG_ERROR (4)
#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;
typedef enum {
@ -54,6 +57,13 @@ typedef struct {
};
} rmt_data_t;
/**
* Prints object information
*
*/
void _rmtDumpStatus(rmt_obj_t* rmt);
/**
* Initialize the object
*
@ -69,10 +79,17 @@ float rmtSetTick(rmt_obj_t* rmt, float tick);
/**
* Sending data in one-go mode or continual mode
* (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);
/**
* 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
*

View File

@ -12,38 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "esp32-hal.h"
#include "freertos/FreeRTOS.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"
#include "soc/soc_caps.h"
#include "driver/sigmadelta.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"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/ets_sys.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/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 uint8_t duty_set[SOC_SIGMADELTA_CHANNEL_NUM] = {0};
static uint32_t prescaler_set[SOC_SIGMADELTA_CHANNEL_NUM] = {0};
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){
@ -51,82 +27,63 @@ static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb
}
uint32_t iarg = (uint32_t)arg;
uint8_t channel = iarg;
if(ev_type == APB_BEFORE_CHANGE){
SIGMADELTA.cg.clk_en = 0;
} else {
if(ev_type == APB_AFTER_CHANGE){
old_apb /= 1000000;
new_apb /= 1000000;
SD_MUTEX_LOCK();
uint32_t old_prescale = SIGMADELTA.channel[channel].prescale + 1;
SIGMADELTA.channel[channel].prescale = ((new_apb * old_prescale) / old_apb) - 1;
SIGMADELTA.cg.clk_en = 0;
SIGMADELTA.cg.clk_en = 1;
SD_MUTEX_UNLOCK();
uint32_t old_prescale = prescaler_set[channel] + 1;
uint32_t new_prescale = ((new_apb * old_prescale) / old_apb) - 1;
sigmadelta_set_prescale(channel,new_prescale);
prescaler_set[channel] = new_prescale;
}
}
uint32_t sigmaDeltaSetup(uint8_t channel, uint32_t freq) //chan 0-7 freq 1220-312500
uint32_t sigmaDeltaSetup(uint8_t pin, uint8_t channel, uint32_t freq) //chan 0-x according to SOC, freq 1220-312500
{
if(channel > 7) {
if(channel >= SOC_SIGMADELTA_CHANNEL_NUM){
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 prescale = (apb_freq/(freq*256)) - 1;
if(prescale > 0xFF) {
prescale = 0xFF;
}
SD_MUTEX_LOCK();
#ifndef CONFIG_IDF_TARGET_ESP32
SIGMADELTA.misc.function_clk_en = 1;
#endif
SIGMADELTA.channel[channel].prescale = prescale;
SIGMADELTA.cg.clk_en = 0;
SIGMADELTA.cg.clk_en = 1;
SD_MUTEX_UNLOCK();
sigmadelta_config_t sigmadelta_cfg = {
.channel = channel,
.sigmadelta_prescale = prescale,
.sigmadelta_duty = 0,
.sigmadelta_gpio = pin,
};
sigmadelta_config(&sigmadelta_cfg);
prescaler_set[channel] = prescale;
uint32_t iarg = channel;
addApbChangeCallback((void*)iarg, _on_apb_change);
return apb_freq/((prescale + 1) * 256);
}
void sigmaDeltaWrite(uint8_t channel, uint8_t duty) //chan 0-7 duty 8 bit
void sigmaDeltaWrite(uint8_t channel, uint8_t duty) //chan 0-x according to SOC duty 8 bit
{
if(channel > 7) {
if(channel >= SOC_SIGMADELTA_CHANNEL_NUM){
return;
}
duty -= 128;
SD_MUTEX_LOCK();
SIGMADELTA.channel[channel].duty = duty;
SD_MUTEX_UNLOCK();
duty -= 128;
sigmadelta_set_duty(channel,duty);
duty_set[channel] = duty;
}
uint8_t sigmaDeltaRead(uint8_t channel) //chan 0-7
uint8_t sigmaDeltaRead(uint8_t channel) //chan 0-x according to SOC
{
if(channel > 7) {
if(channel >= SOC_SIGMADELTA_CHANNEL_NUM){
return 0;
}
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);
return duty_set[channel]+128;
}
void sigmaDeltaDetachPin(uint8_t pin)
{
pinMatrixOutDetach(pin, false, false);
}
}

View File

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

View File

@ -44,6 +44,8 @@ static void setTimeZone(long offset, int daylight)
/*
* configTime
* Source: https://github.com/esp8266/Arduino/blob/master/cores/esp8266/time.c
* Note: Bundled Arduino lwip supports only ONE ntp server, 2nd and 3rd options are silently ignored
* see CONFIG_LWIP_DHCP_MAX_NTP_SERVERS define in ./tools/sdk/esp32/sdkconfig
* */
void configTime(long gmtOffset_sec, int daylightOffset_sec, const char* server1, const char* server2, const char* server3)
{
@ -63,6 +65,8 @@ void configTime(long gmtOffset_sec, int daylightOffset_sec, const char* server1,
/*
* configTzTime
* sntp setup using TZ environment variable
* Note: Bundled Arduino lwip supports only ONE ntp server, 2nd and 3rd options are silently ignored
* see CONFIG_LWIP_DHCP_MAX_NTP_SERVERS define in ./tools/sdk/esp32/sdkconfig
* */
void configTzTime(const char* tz, const char* server1, const char* server2, const char* server3)
{

View File

@ -13,333 +13,227 @@
// limitations under the License.
#include "esp32-hal-timer.h"
#include "freertos/FreeRTOS.h"
#ifndef CONFIG_IDF_TARGET_ESP32C3
#include "freertos/xtensa_api.h"
#include "soc/dport_reg.h"
#endif
#include "freertos/task.h"
#include "soc/timer_group_struct.h"
#include "esp_attr.h"
#include "driver/periph_ctrl.h"
#include "driver/timer.h"
#include "soc/soc_caps.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 "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"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/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
typedef union {
struct {
uint32_t reserved0: 10;
uint32_t alarm_en: 1; /*When set alarm is enabled*/
uint32_t level_int_en: 1; /*When set level type interrupt will be generated during alarm*/
uint32_t edge_int_en: 1; /*When set edge type interrupt will be generated during alarm*/
uint32_t divider: 16; /*Timer clock (T0/1_clk) pre-scale value.*/
uint32_t autoreload: 1; /*When set timer 0/1 auto-reload at alarming is enabled*/
uint32_t increase: 1; /*When set timer 0/1 time-base counter increment. When cleared timer 0 time-base counter decrement.*/
uint32_t enable: 1; /*When set timer 0/1 time-base counter is enabled*/
};
uint32_t val;
} timer_cfg_t;
#define HWTIMER_LOCK() portENTER_CRITICAL(timer->lock)
#define HWTIMER_UNLOCK() portEXIT_CRITICAL(timer->lock)
#define NUM_OF_TIMERS SOC_TIMER_GROUP_TOTAL_TIMERS
typedef volatile struct {
union {
struct {
uint32_t reserved0: 10;
uint32_t alarm_en: 1; /*When set alarm is enabled*/
uint32_t level_int_en: 1; /*When set level type interrupt will be generated during alarm*/
uint32_t edge_int_en: 1; /*When set edge type interrupt will be generated during alarm*/
uint32_t divider: 16; /*Timer clock (T0/1_clk) pre-scale value.*/
uint32_t autoreload: 1; /*When set timer 0/1 auto-reload at alarming is enabled*/
uint32_t increase: 1; /*When set timer 0/1 time-base counter increment. When cleared timer 0 time-base counter decrement.*/
uint32_t enable: 1; /*When set timer 0/1 time-base counter is enabled*/
};
uint32_t val;
} 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;
typedef struct {
int timer_group;
int timer_idx;
int alarm_interval;
bool auto_reload;
} timer_info_t;
typedef struct hw_timer_s {
hw_timer_reg_t * dev;
uint8_t num;
uint8_t group;
uint8_t timer;
portMUX_TYPE lock;
typedef struct hw_timer_s
{
uint8_t group;
uint8_t num;
} hw_timer_t;
static hw_timer_t hw_timer[4] = {
{(hw_timer_reg_t *)(DR_REG_TIMERGROUP0_BASE),0,0,0,portMUX_INITIALIZER_UNLOCKED},
{(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}
// Works for all chips
static hw_timer_t timer_dev[4] = {
{0,0}, {1,0}, {1,0}, {1,1}
};
typedef void (*voidFuncPtr)(void);
static voidFuncPtr __timerInterruptHandlers[4] = {0,0,0,0};
// NOTE: (in IDF 5.0 there wont be need to know groups/numbers
// timer_init() will list thru all timers and return free timer handle)
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 timerRead(hw_timer_t *timer){
timer->dev->update = 1;
uint64_t h = timer->dev->cnt_high;
uint64_t l = timer->dev->cnt_low;
return (h << 32) | l;
uint64_t inline timerRead(hw_timer_t *timer){
uint64_t value;
timer_get_counter_value(timer->group, timer->num,&value);
return value;
}
uint64_t timerAlarmRead(hw_timer_t *timer){
uint64_t h = timer->dev->alarm_high;
uint64_t l = timer->dev->alarm_low;
return (h << 32) | l;
uint64_t value;
timer_get_alarm_value(timer->group, timer->num, &value);
return value;
}
void timerWrite(hw_timer_t *timer, uint64_t val){
timer->dev->load_high = (uint32_t) (val >> 32);
timer->dev->load_low = (uint32_t) (val);
timer->dev->reload = 1;
timer_set_counter_value(timer->group, timer->num, val);
}
void timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload){
timer->dev->alarm_high = (uint32_t) (alarm_value >> 32);
timer->dev->alarm_low = (uint32_t) alarm_value;
timer->dev->config.autoreload = autoreload;
timer_set_alarm_value(timer->group, timer->num, alarm_value);
timerSetAutoReload(timer,autoreload);
}
void timerSetConfig(hw_timer_t *timer, uint32_t config){
timer->dev->config.val = config;
timer_cfg_t cfg;
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){
return timer->dev->config.val;
timer_config_t timer_cfg;
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){
timer->dev->config.increase = countUp;
timer_set_counter_mode(timer->group, timer->num,countUp);
}
bool timerGetCountUp(hw_timer_t *timer){
return timer->dev->config.increase;
timer_cfg_t config;
config.val = timerGetConfig(timer);
return config.increase;
}
void timerSetAutoReload(hw_timer_t *timer, bool autoreload){
timer->dev->config.autoreload = autoreload;
timer_set_auto_reload(timer->group, timer->num,autoreload);
}
bool timerGetAutoReload(hw_timer_t *timer){
return timer->dev->config.autoreload;
timer_cfg_t config;
config.val= timerGetConfig(timer);
return config.autoreload;
}
void timerSetDivider(hw_timer_t *timer, uint16_t divider){//2 to 65536
if(!divider){
divider = 0xFFFF;
} else if(divider == 1){
divider = 2;
// Set divider from 2 to 65535
void timerSetDivider(hw_timer_t *timer, uint16_t divider){
if(divider < 2)
{
log_e("Timer divider must be set in range of 2 to 65535");
return;
}
int timer_en = timer->dev->config.enable;
timer->dev->config.enable = 0;
timer->dev->config.divider = divider;
timer->dev->config.enable = timer_en;
timer_set_divider(timer->group, timer->num,divider);
}
uint16_t timerGetDivider(hw_timer_t *timer){
return timer->dev->config.divider;
timer_cfg_t config;
config.val = timerGetConfig(timer);
return config.divider;
}
void timerStart(hw_timer_t *timer){
timer->dev->config.enable = 1;
timer_start(timer->group, timer->num);
}
void timerStop(hw_timer_t *timer){
timer->dev->config.enable = 0;
timer_pause(timer->group, timer->num);
}
void timerRestart(hw_timer_t *timer){
timer->dev->config.enable = 0;
timer->dev->reload = 1;
timer->dev->config.enable = 1;
timerWrite(timer,0);
}
bool timerStarted(hw_timer_t *timer){
return timer->dev->config.enable;
timer_cfg_t config;
config.val = timerGetConfig(timer);
return config.enable;
}
void timerAlarmEnable(hw_timer_t *timer){
timer->dev->config.alarm_en = 1;
timer_set_alarm(timer->group, timer->num,true);
}
void timerAlarmDisable(hw_timer_t *timer){
timer->dev->config.alarm_en = 0;
timer_set_alarm(timer->group, timer->num,false);
}
bool timerAlarmEnabled(hw_timer_t *timer){
return timer->dev->config.alarm_en;
timer_cfg_t config;
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){
hw_timer_t * timer = (hw_timer_t *)arg;
if(ev_type == APB_BEFORE_CHANGE){
timer->dev->config.enable = 0;
timerStop(timer);
} else {
old_apb /= 1000000;
new_apb /= 1000000;
timer->dev->config.divider = (new_apb * timer->dev->config.divider) / old_apb;
timer->dev->config.enable = 1;
uint16_t divider = (new_apb * timerGetDivider(timer)) / old_apb;
timerSetDivider(timer,divider);
timerStart(timer);
}
}
hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp){
if(num > 3){
if(num >= NUM_OF_TIMERS)
{
log_e("Timer dont have that timer number.");
return NULL;
}
hw_timer_t * timer = &hw_timer[num];
if(timer->group) {
periph_module_enable(PERIPH_TIMG1_MODULE);
} else {
periph_module_enable(PERIPH_TIMG0_MODULE);
}
timer->dev->config.enable = 0;
if(timer->group) {
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
}
#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;
hw_timer_t * timer = &timer_dev[num]; //Get Timer group/num from 0-3 number
timer_config_t config = {
.divider = divider,
.counter_dir = countUp,
.counter_en = TIMER_PAUSE,
.alarm_en = TIMER_ALARM_DIS,
.auto_reload = false,
};
timer_init(timer->group, timer->num, &config);
timer_set_counter_value(timer->group, timer->num, 0);
timerStart(timer);
addApbChangeCallback(timer, _on_apb_change);
return timer;
}
void timerEnd(hw_timer_t *timer){
timer->dev->config.enable = 0;
timerAttachInterrupt(timer, NULL, false);
removeApbChangeCallback(timer, _on_apb_change);
timer_deinit(timer->group, timer->num);
}
void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){
#if CONFIG_IDF_TARGET_ESP32
if(edge){
log_w("EDGE timer interrupt does not work properly on ESP32! Setting to LEVEL...");
log_w("EDGE timer interrupt is not supported! Setting to LEVEL...");
edge = false;
}
#endif
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;
#ifndef CONFIG_IDF_TARGET_ESP32C3
if(!edge){
#endif
if(timer->group){
intr_source = ETS_TG1_T0_LEVEL_INTR_SOURCE + timer->timer;
} else {
intr_source = ETS_TG0_T0_LEVEL_INTR_SOURCE + timer->timer;
}
#ifndef CONFIG_IDF_TARGET_ESP32C3
} 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;
}
}
#endif
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_enable_intr(timer->group, timer->num);
timer_info_t *timer_info = calloc(1, sizeof(timer_info_t));
timer_info->timer_group = timer->group;
timer_info->timer_idx = timer->num;
timer_info->auto_reload = timerGetAutoReload(timer);
timer_info->alarm_interval = timerAlarmRead(timer);
timer_isr_callback_add(timer->group, timer->num, (timer_isr_t)fn, timer_info, 0);
}
void timerDetachInterrupt(hw_timer_t *timer){
@ -352,6 +246,12 @@ uint64_t timerReadMicros(hw_timer_t *timer){
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){
uint64_t timer_val = timerRead(timer);
uint16_t div = timerGetDivider(timer);
@ -364,6 +264,12 @@ uint64_t timerAlarmReadMicros(hw_timer_t *timer){
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){
uint64_t timer_val = timerAlarmRead(timer);
uint16_t div = timerGetDivider(timer);

View File

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

View File

@ -72,20 +72,15 @@ static void configure_pins(usb_hal_context_t *usb)
esp_err_t tinyusb_driver_install(const tinyusb_config_t *config)
{
log_i("Driver installation...");
// Hal init
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;
}
log_i("Driver installed");
return ESP_OK;
}
@ -106,6 +101,7 @@ static tusb_str_t WEBUSB_URL = "";
static tusb_str_t USB_DEVICE_PRODUCT = "";
static tusb_str_t USB_DEVICE_MANUFACTURER = "";
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 uint16_t USB_DEVICE_POWER = 0;
@ -140,7 +136,7 @@ static tusb_desc_device_t tinyusb_device_descriptor = {
static uint32_t tinyusb_string_descriptor_len = 4;
static char * tinyusb_string_descriptor[MAX_STRING_DESCRIPTORS] = {
// array of pointer to string descriptors
"\x09\x04", // 0: is supported language is English (0x0409)
USB_DEVICE_LANGUAGE, // 0: is supported language
USB_DEVICE_MANUFACTURER,// 1: Manufacturer
USB_DEVICE_PRODUCT, // 2: Product
USB_DEVICE_SERIAL, // 3: Serials, should use chip ID
@ -263,7 +259,7 @@ static tinyusb_endpoints_usage_t tinyusb_endpoints;
/**
* @brief Invoked when received GET CONFIGURATION DESCRIPTOR.
*/
uint8_t const *tud_descriptor_configuration_cb(uint8_t index)
__attribute__ ((weak)) uint8_t const *tud_descriptor_configuration_cb(uint8_t index)
{
//log_d("%u", index);
return tinyusb_config_descriptor;
@ -272,7 +268,7 @@ uint8_t const *tud_descriptor_configuration_cb(uint8_t index)
/**
* @brief Invoked when received GET DEVICE DESCRIPTOR.
*/
uint8_t const *tud_descriptor_device_cb(void)
__attribute__ ((weak)) uint8_t const *tud_descriptor_device_cb(void)
{
//log_d("");
return (uint8_t const *)&tinyusb_device_descriptor;
@ -281,7 +277,7 @@ uint8_t const *tud_descriptor_device_cb(void)
/**
* @brief Invoked when received GET STRING DESCRIPTOR request.
*/
uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid)
__attribute__ ((weak)) uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid)
{
//log_d("%u (0x%x)", index, langid);
static uint16_t _desc_str[127];
@ -428,12 +424,6 @@ static bool tinyusb_load_enabled_interfaces(){
log_e("Descriptor Load Failed");
return false;
} 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;
}
}
@ -509,6 +499,7 @@ static void tinyusb_apply_device_config(tinyusb_device_config_t *config){
&& (config->usb_class != TUSB_CLASS_CDC)
){
config->usb_class = TUSB_CLASS_CDC;
config->usb_protocol = 0x00;
}
WEBUSB_ENABLED = config->webusb_enabled;
@ -563,31 +554,43 @@ static void usb_device_task(void *param) {
/*
* PUBLIC API
* */
static const char *tinyusb_interface_names[USB_INTERFACE_MAX] = {"MSC", "DFU", "HID", "VENDOR", "CDC", "MIDI", "CUSTOM"};
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)
{
if((interface >= USB_INTERFACE_MAX) || (tinyusb_loaded_interfaces_mask & (1U << interface))){
log_e("Interface %u not enabled", interface);
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))){
log_e("Interface %s invalid or already enabled", (interface >= USB_INTERFACE_MAX)?"":tinyusb_interface_names[interface]);
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_config_descriptor_len += descriptor_len;
tinyusb_loaded_interfaces_callbacks[interface] = cb;
log_d("Interface %u enabled", interface);
log_d("Interface %s enabled", tinyusb_interface_names[interface]);
return ESP_OK;
}
esp_err_t tinyusb_init(tinyusb_device_config_t *config) {
static bool initialized = false;
if(initialized){
if(tinyusb_is_initialized){
return ESP_OK;
}
initialized = true;
tinyusb_is_initialized = true;
tinyusb_endpoints.val = 0;
//tinyusb_endpoints.val = 0;
tinyusb_apply_device_config(config);
if (!tinyusb_load_enabled_interfaces()) {
initialized = false;
tinyusb_is_initialized = false;
return ESP_FAIL;
}
@ -605,7 +608,7 @@ esp_err_t tinyusb_init(tinyusb_device_config_t *config) {
}
if (esp_register_shutdown_handler(usb_persist_shutdown_handler) != ESP_OK) {
initialized = false;
tinyusb_is_initialized = false;
return ESP_FAIL;
}
@ -614,7 +617,7 @@ esp_err_t tinyusb_init(tinyusb_device_config_t *config) {
};
esp_err_t err = tinyusb_driver_install(&tusb_cfg);
if (err != ESP_OK) {
initialized = false;
tinyusb_is_initialized = false;
return err;
}
xTaskCreate(usb_device_task, "usbd", 4096, NULL, configMAX_PRIORITIES - 1, NULL);
@ -690,84 +693,4 @@ uint8_t tinyusb_get_free_out_endpoint(void){
return 0;
}
/*
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_TINYUSB_ENABLED */

View File

@ -82,11 +82,11 @@ void usb_persist_restart(restart_type_t mode);
// The following definitions and functions are to be used only by the drivers
typedef enum {
USB_INTERFACE_CDC,
USB_INTERFACE_MSC,
USB_INTERFACE_DFU,
USB_INTERFACE_HID,
USB_INTERFACE_VENDOR,
USB_INTERFACE_MSC,
USB_INTERFACE_CDC,
USB_INTERFACE_MIDI,
USB_INTERFACE_CUSTOM,
USB_INTERFACE_MAX

View File

@ -95,6 +95,7 @@ void __touchInit()
SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_MEAS_EN_CLR);
//clear touch enable
WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG, 0x0);
SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_TOUCH_SLP_TIMER_EN);
__touchSetCycles(__touchMeasureCycles, __touchSleepCycles);
esp_intr_alloc(ETS_RTC_CORE_INTR_SOURCE, (int)ARDUINO_ISR_FLAG, __touchISR, NULL, &touch_intr_handle);
#else

View File

@ -14,205 +14,101 @@
#include "esp32-hal-uart.h"
#include "esp32-hal.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "esp_attr.h"
#include "soc/uart_reg.h"
#include "soc/uart_struct.h"
#include "soc/io_mux_reg.h"
#include "soc/gpio_sig_map.h"
#include "soc/rtc.h"
#include "driver/uart.h"
#include "hal/uart_ll.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 "soc/dport_reg.h"
#include "esp32/rom/ets_sys.h"
#include "esp32/rom/uart.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "soc/dport_reg.h"
#include "esp32s2/rom/ets_sys.h"
#include "esp32s2/rom/uart.h"
#include "soc/periph_defs.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/ets_sys.h"
#include "esp32c3/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_ESP32
#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)))
#elif 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 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))
#endif
#include "soc/soc_caps.h"
#include "soc/uart_struct.h"
static int s_uart_debug_nr = 0;
struct uart_struct_t {
uart_dev_t * dev;
#if !CONFIG_DISABLE_HAL_LOCKS
xSemaphoreHandle lock;
#endif
uint8_t num;
xQueueHandle queue;
intr_handle_t intr_handle;
bool has_peek;
uint8_t peek_byte;
};
#if CONFIG_DISABLE_HAL_LOCKS
#define UART_MUTEX_LOCK()
#define UART_MUTEX_UNLOCK()
static uart_t _uart_bus_array[] = {
{&UART0, 0, NULL, NULL},
{&UART1, 1, NULL, NULL},
#if CONFIG_IDF_TARGET_ESP32
{&UART2, 2, NULL, NULL}
{0, false, 0},
#if SOC_UART_NUM > 1
{1, false, 0},
#endif
#if SOC_UART_NUM > 2
{2, false, 0},
#endif
};
#else
#define UART_MUTEX_LOCK() do {} while (xSemaphoreTake(uart->lock, portMAX_DELAY) != pdPASS)
#define UART_MUTEX_UNLOCK() xSemaphoreGive(uart->lock)
static uart_t _uart_bus_array[] = {
{&UART0, NULL, 0, NULL, NULL},
{&UART1, NULL, 1, NULL, NULL},
#if CONFIG_IDF_TARGET_ESP32
{&UART2, NULL, 2, NULL, NULL}
{NULL, 0, false, 0},
#if SOC_UART_NUM > 1
{NULL, 1, false, 0},
#endif
#if SOC_UART_NUM > 2
{NULL, 2, false, 0},
#endif
};
#endif
static void uart_on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb);
static void ARDUINO_ISR_ATTR _uart_isr(void *arg)
// solves issue https://github.com/espressif/arduino-esp32/issues/6032
// baudrate must be multiplied when CPU Frequency is lower than APB 80MHz
uint32_t _get_effective_baudrate(uint32_t baudrate)
{
uint8_t i, c;
BaseType_t xHigherPriorityTaskWoken;
uart_t* uart;
for(i=0;i<UART_PORTS_NUM;i++){
uart = &_uart_bus_array[i];
if(uart->intr_handle == NULL){
continue;
}
uart->dev->int_clr.rxfifo_full = 1;
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();
uint32_t Freq = getApbFrequency()/1000000;
if (Freq < 80) {
return 80 / Freq * baudrate;
}
else {
return baudrate;
}
}
static void uartEnableInterrupt(uart_t* uart, uint8_t rxfifo_full_thrhd)
{
UART_MUTEX_LOCK();
uart->dev->conf1.rxfifo_full_thrhd = rxfifo_full_thrhd;
#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();
}
static void uartDisableInterrupt(uart_t* uart)
{
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();
}
static void uartDetachRx(uart_t* uart, uint8_t rxPin)
bool uartIsDriverInstalled(uart_t* uart)
{
if(uart == NULL) {
return;
return 0;
}
pinMatrixInDetach(UART_RXD_IDX(uart->num), false, false);
uartDisableInterrupt(uart);
if (uart_is_driver_installed(uart->num)) {
return true;
}
return false;
}
static void uartDetachTx(uart_t* uart, uint8_t txPin)
void uartSetPins(uart_t* uart, uint8_t rxPin, uint8_t txPin)
{
if(uart == NULL) {
if(uart == NULL || rxPin >= SOC_GPIO_PIN_COUNT || txPin >= SOC_GPIO_PIN_COUNT) {
return;
}
pinMatrixOutDetach(txPin, false, false);
UART_MUTEX_LOCK();
ESP_ERROR_CHECK(uart_set_pin(uart->num, txPin, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
UART_MUTEX_UNLOCK();
}
static void uartAttachRx(uart_t* uart, uint8_t rxPin, bool inverted, uint8_t rxfifo_full_thrhd)
{
if(uart == NULL || rxPin >= GPIO_PIN_COUNT) {
return;
}
pinMode(rxPin, INPUT);
uartEnableInterrupt(uart, rxfifo_full_thrhd);
pinMatrixInAttach(rxPin, UART_RXD_IDX(uart->num), inverted);
}
static 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, uint8_t rxfifo_full_thrhd)
{
if(uart_nr >= UART_PORTS_NUM) {
if(uart_nr >= SOC_UART_NUM) {
return NULL;
}
@ -222,6 +118,10 @@ uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rx
uart_t* uart = &_uart_bus_array[uart_nr];
if (uart_is_driver_installed(uart_nr)) {
uartEnd(uart);
}
#if !CONFIG_DISABLE_HAL_LOCKS
if(uart->lock == NULL) {
uart->lock = xSemaphoreCreateMutex();
@ -231,189 +131,146 @@ uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rx
}
#endif
if(queueLen && uart->queue == NULL) {
uart->queue = xQueueCreate(queueLen, sizeof(uint8_t)); //initialize the queue
if(uart->queue == NULL) {
return NULL;
}
}
#if CONFIG_IDF_TARGET_ESP32C3
#else
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);
}
#endif
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;
uart_config_t uart_config;
uart_config.baud_rate = _get_effective_baudrate(baudrate);
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, 2*queueLen, 0, 0, NULL, 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));
}
// 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; //
// Set RS485 half duplex mode on UART. This shall force flush to wait up to sending all bits out
ESP_ERROR_CHECK(uart_set_mode(uart_nr, UART_MODE_RS485_HALF_DUPLEX));
UART_MUTEX_UNLOCK();
if(rxPin != -1) {
uartAttachRx(uart, rxPin, inverted, rxfifo_full_thrhd);
}
if(txPin != -1) {
uartAttachTx(uart, txPin, inverted);
}
addApbChangeCallback(uart, uart_on_apb_change);
uartFlush(uart);
return uart;
}
void uartEnd(uart_t* uart, uint8_t txPin, uint8_t rxPin)
void uartEnd(uart_t* uart)
{
if(uart == NULL) {
return;
}
removeApbChangeCallback(uart, uart_on_apb_change);
UART_MUTEX_LOCK();
if(uart->queue != NULL) {
vQueueDelete(uart->queue);
uart->queue = NULL;
}
uart->dev->conf0.val = 0;
uart_driver_delete(uart->num);
UART_MUTEX_UNLOCK();
uartDetachRx(uart, rxPin);
uartDetachTx(uart, txPin);
}
size_t uartResizeRxBuffer(uart_t * uart, size_t new_size) {
if(uart == NULL) {
return 0;
}
UART_MUTEX_LOCK();
if(uart->queue != NULL) {
vQueueDelete(uart->queue);
uart->queue = xQueueCreate(new_size, sizeof(uint8_t));
if(uart->queue == NULL) {
UART_MUTEX_UNLOCK();
return 0;
}
}
UART_MUTEX_UNLOCK();
return 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)
uart->dev->conf0.rxd_inv = 1;
ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_RXD_INV));
else
uart->dev->conf0.rxd_inv = 0;
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 || uart->queue == NULL) {
if(uart == NULL) {
return 0;
}
#ifdef UART_READ_RX_FIFO
return (uxQueueMessagesWaiting(uart->queue) + uart->dev->status.rxfifo_cnt) ;
#else
return uxQueueMessagesWaiting(uart->queue);
#endif
UART_MUTEX_LOCK();
size_t available;
uart_get_buffered_data_len(uart->num, &available);
if (uart->has_peek) available++;
UART_MUTEX_UNLOCK();
return available;
}
uint32_t uartAvailableForWrite(uart_t* uart)
{
if(uart == NULL) {
return 0;
}
return 0x7f - uart->dev->status.txfifo_cnt;
UART_MUTEX_LOCK();
uint32_t available = uart_ll_get_txfifo_len(UART_LL_GET_HW(uart->num));
UART_MUTEX_UNLOCK();
return available;
}
#ifdef UART_READ_RX_FIFO
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();
}
#endif
uint8_t uartRead(uart_t* uart)
{
if(uart == NULL || uart->queue == NULL) {
if(uart == NULL) {
return 0;
}
uint8_t c;
#ifdef UART_READ_RX_FIFO
if ((uxQueueMessagesWaiting(uart->queue) == 0) && (uart->dev->status.rxfifo_cnt > 0))
{
uartRxFifoToQueue(uart);
uint8_t c = 0;
UART_MUTEX_LOCK();
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;
}
}
#endif
if(xQueueReceive(uart->queue, &c, 0)) {
return c;
}
return 0;
UART_MUTEX_UNLOCK();
return c;
}
uint8_t uartPeek(uart_t* uart)
{
if(uart == NULL || uart->queue == NULL) {
if(uart == NULL) {
return 0;
}
uint8_t c;
#ifdef UART_READ_RX_FIFO
if ((uxQueueMessagesWaiting(uart->queue) == 0) && (uart->dev->status.rxfifo_cnt > 0))
{
uartRxFifoToQueue(uart);
uint8_t c = 0;
UART_MUTEX_LOCK();
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;
}
}
#endif
if(xQueuePeek(uart->queue, &c, 0)) {
return c;
}
return 0;
UART_MUTEX_UNLOCK();
return c;
}
void uartWrite(uart_t* uart, uint8_t c)
@ -422,39 +279,24 @@ void uartWrite(uart_t* uart, uint8_t c)
return;
}
UART_MUTEX_LOCK();
while(uart->dev->status.txfifo_cnt >= 0x7E);
#if CONFIG_IDF_TARGET_ESP32
uart->dev->fifo.rw_byte = c;
#else
ESP_REG(UART_FIFO_AHB_REG(uart->num)) = c;
#endif
uart_write_bytes(uart->num, &c, 1);
UART_MUTEX_UNLOCK();
}
void uartWriteBuf(uart_t* uart, const uint8_t * data, size_t len)
{
if(uart == NULL) {
if(uart == NULL || data == NULL || !len) {
return;
}
UART_MUTEX_LOCK();
#ifndef CONFIG_IDF_TARGET_ESP32
uint32_t fifo_reg = UART_FIFO_AHB_REG(uart->num);
#endif
while(len) {
while(uart->dev->status.txfifo_cnt >= 0x7E);
#if CONFIG_IDF_TARGET_ESP32
uart->dev->fifo.rw_byte = *data++;
#else
ESP_REG(fifo_reg) = *data++;
#endif
len--;
}
uart_write_bytes(uart->num, data, len);
UART_MUTEX_UNLOCK();
}
void uartFlush(uart_t* uart)
{
uartFlushTxOnly(uart,true);
uartFlushTxOnly(uart, true);
}
void uartFlushTxOnly(uart_t* uart, bool txOnly)
@ -462,28 +304,13 @@ void uartFlushTxOnly(uart_t* uart, bool txOnly)
if(uart == NULL) {
return;
}
UART_MUTEX_LOCK();
#if CONFIG_IDF_TARGET_ESP32
while(uart->dev->status.txfifo_cnt || uart->dev->status.st_utx_out);
if( !txOnly ){
//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.
ESP_ERROR_CHECK(uart_wait_tx_done(uart->num, portMAX_DELAY));
// 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);
if ( !txOnly ) {
ESP_ERROR_CHECK(uart_flush_input(uart->num));
}
#else
while(uart->dev->status.txfifo_cnt);
uart->dev->conf0.txfifo_rst = 1;
uart->dev->conf0.txfifo_rst = 0;
#endif
UART_MUTEX_UNLOCK();
}
@ -493,100 +320,41 @@ void uartSetBaudRate(uart_t* uart, uint32_t baud_rate)
return;
}
UART_MUTEX_LOCK();
uart_ll_set_baudrate(uart->dev, baud_rate);
uart_ll_set_baudrate(UART_LL_GET_HW(uart->num), _get_effective_baudrate(baud_rate));
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)
{
if(uart == NULL) {
return 0;
}
uint32_t clk_div = (uart->dev->clk_div.div_int << 4) | (uart->dev->clk_div.div_frag & 0x0F);
if(!clk_div) {
return 0;
}
return ((getApbFrequency()<<4)/clk_div);
UART_MUTEX_LOCK();
uint32_t baud_rate = uart_ll_get_baudrate(UART_LL_GET_HW(uart->num));
UART_MUTEX_UNLOCK();
return baud_rate;
}
static void ARDUINO_ISR_ATTR uart0_write_char(char c)
{
#if CONFIG_IDF_TARGET_ESP32
while(((ESP_REG(0x01C+DR_REG_UART_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) >= 0x7E);
ESP_REG(DR_REG_UART_BASE) = c;
#else
while(UART0.status.txfifo_cnt == 0x7F);
WRITE_PERI_REG(UART_FIFO_AHB_REG(0), c);
#endif
while (uart_ll_get_txfifo_len(&UART0) == 0);
uart_ll_write_txfifo(&UART0, (const uint8_t *) &c, 1);
}
#if SOC_UART_NUM > 1
static void ARDUINO_ISR_ATTR uart1_write_char(char c)
{
#if CONFIG_IDF_TARGET_ESP32
while(((ESP_REG(0x01C+DR_REG_UART1_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) >= 0x7E);
ESP_REG(DR_REG_UART1_BASE) = c;
#else
while(UART1.status.txfifo_cnt == 0x7F);
WRITE_PERI_REG(UART_FIFO_AHB_REG(1), c);
#endif
while (uart_ll_get_txfifo_len(&UART1) == 0);
uart_ll_write_txfifo(&UART1, (const uint8_t *) &c, 1);
}
#endif
#if CONFIG_IDF_TARGET_ESP32
#if SOC_UART_NUM > 2
static void ARDUINO_ISR_ATTR uart2_write_char(char c)
{
while(((ESP_REG(0x01C+DR_REG_UART2_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) >= 0x7E);
ESP_REG(DR_REG_UART2_BASE) = c;
while (uart_ll_get_txfifo_len(&UART2) == 0);
uart_ll_write_txfifo(&UART2, (const uint8_t *) &c, 1);
}
#endif
@ -596,10 +364,12 @@ void uart_install_putc()
case 0:
ets_install_putc1((void (*)(char)) &uart0_write_char);
break;
#if SOC_UART_NUM > 1
case 1:
ets_install_putc1((void (*)(char)) &uart1_write_char);
break;
#if CONFIG_IDF_TARGET_ESP32
#endif
#if SOC_UART_NUM > 2
case 2:
ets_install_putc1((void (*)(char)) &uart2_write_char);
break;
@ -612,15 +382,11 @@ void uart_install_putc()
void uartSetDebug(uart_t* uart)
{
if(uart == NULL || uart->num >= UART_PORTS_NUM) {
if(uart == NULL || uart->num >= SOC_UART_NUM) {
s_uart_debug_nr = -1;
//ets_install_putc1(NULL);
//return;
} else
if(s_uart_debug_nr == uart->num) {
return;
} else
s_uart_debug_nr = uart->num;
} else {
s_uart_debug_nr = uart->num;
}
uart_install_putc();
}
@ -646,17 +412,19 @@ int log_printf(const char *format, ...)
return 0;
}
}
vsnprintf(temp, len+1, format, arg);
#if !CONFIG_DISABLE_HAL_LOCKS
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);
ets_printf("%s", temp);
xSemaphoreGive(_uart_bus_array[s_uart_debug_nr].lock);
} else {
ets_printf("%s", temp);
}
#else
#endif
vsnprintf(temp, len+1, format, arg);
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);
}
#endif
va_end(arg);
if(len >= sizeof(loc_buf)){
@ -665,48 +433,126 @@ int log_printf(const char *format, ...)
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.
* 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)
{
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;
ets_delay_us(1000);
}
UART_MUTEX_LOCK();
unsigned long ret = ((uart->dev->lowpulse.min_cnt + uart->dev->highpulse.min_cnt) >> 1) + 12;
//log_i("lowpulse_min_cnt = %d hightpulse_min_cnt = %d", hw->lowpulse.min_cnt, hw->highpulse.min_cnt);
unsigned long ret = ((hw->lowpulse.min_cnt + hw->highpulse.min_cnt) >> 1);
UART_MUTEX_UNLOCK();
return ret;
}
/*
* 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
* 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) {
if(!uart) return;
#ifndef CONFIG_IDF_TARGET_ESP32C3
uart->dev->auto_baud.glitch_filt = 0x08;
uart->dev->auto_baud.en = 0;
uart->dev->auto_baud.en = 1;
if(uart == NULL) {
return;
}
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
#ifdef CONFIG_IDF_TARGET_ESP32C3
// ESP32-C3 requires further testing
// 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;
#else
hw->auto_baud.glitch_filt = 0x08;
hw->auto_baud.en = 0;
hw->auto_baud.en = 1;
#endif
}
unsigned long
uartDetectBaudrate(uart_t *uart)
{
#ifndef CONFIG_IDF_TARGET_ESP32C3
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;
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
if(!uartStateDetectingBaudrate) {
uart->dev->auto_baud.glitch_filt = 0x08;
uart->dev->auto_baud.en = 0;
uart->dev->auto_baud.en = 1;
uartStartDetectBaudrate(uart);
uartStateDetectingBaudrate = true;
}
@ -714,11 +560,21 @@ uartDetectBaudrate(uart_t *uart)
if (!divisor) {
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;
#else
hw->auto_baud.en = 0;
#endif
uartStateDetectingBaudrate = false; // Initialize for the next round
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};
@ -736,17 +592,7 @@ uartDetectBaudrate(uart_t *uart)
return default_rates[i];
#else
return 0;
#endif
}
/*
* 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
log_e("ESP32-C3 baud rate detection is not supported.");
return 0;
#endif
}

View File

@ -52,7 +52,7 @@ struct uart_struct_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 queueLen, bool inverted, uint8_t rxfifo_full_thrhd);
void uartEnd(uart_t* uart, uint8_t rxPin, uint8_t txPin);
void uartEnd(uart_t* uart);
uint32_t uartAvailable(uart_t* uart);
uint32_t uartAvailableForWrite(uart_t* uart);
@ -68,17 +68,17 @@ void uartFlushTxOnly(uart_t* uart, bool txOnly );
void uartSetBaudRate(uart_t* uart, uint32_t baud_rate);
uint32_t uartGetBaudRate(uart_t* uart);
size_t uartResizeRxBuffer(uart_t* uart, size_t new_size);
void uartSetRxInvert(uart_t* uart, bool invert);
void uartSetDebug(uart_t* uart);
int uartGetDebug();
bool uartIsDriverInstalled(uart_t* uart);
void uartSetPins(uart_t* uart, uint8_t rxPin, uint8_t txPin);
void uartStartDetectBaudrate(uart_t *uart);
unsigned long uartDetectBaudrate(uart_t *uart);
bool uartRxActive(uart_t* uart);
#ifdef __cplusplus
}

View File

@ -31,6 +31,11 @@
#include "sdkconfig.h"
#include "esp_system.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
extern "C" {
@ -85,6 +90,8 @@ void yield(void);
#include "esp32-hal-psram.h"
#include "esp32-hal-cpu.h"
void analogWrite(uint8_t pin, int value);
//returns chip temperature in Celsius
float temperatureRead();

View File

@ -0,0 +1,204 @@
// 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

@ -0,0 +1,141 @@
// 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 Executable file → Normal file
View File

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

2
cores/esp32/libb64/cdecode.c Executable file → Normal 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_size = sizeof(decoding);
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];
}

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

0
cores/esp32/libb64/cencode.c Executable file → Normal file
View File

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

View File

@ -2,8 +2,11 @@
#include "freertos/task.h"
#include "esp_task_wdt.h"
#include "Arduino.h"
#if ARDUINO_SERIAL_PORT //Serial used for USB CDC
#if (ARDUINO_USB_CDC_ON_BOOT|ARDUINO_USB_MSC_ON_BOOT|ARDUINO_USB_DFU_ON_BOOT)
#include "USB.h"
#if ARDUINO_USB_MSC_ON_BOOT
#include "FirmwareMSC.h"
#endif
#endif
#ifndef ARDUINO_LOOP_STACK_SIZE
@ -30,6 +33,10 @@ void yieldIfNecessary(void){
bool loopTaskWDTEnabled;
__attribute__((weak)) size_t getArduinoLoopTaskStackSize(void) {
return ARDUINO_LOOP_STACK_SIZE;
}
void loopTask(void *pvParameters)
{
setup();
@ -47,13 +54,21 @@ void loopTask(void *pvParameters)
extern "C" void app_main()
{
#if ARDUINO_SERIAL_PORT //Serial used for USB CDC
USB.begin();
#if ARDUINO_USB_CDC_ON_BOOT
Serial.begin();
#endif
#if ARDUINO_USB_MSC_ON_BOOT
MSC_Update.begin();
#endif
#if ARDUINO_USB_DFU_ON_BOOT
USB.enableDFU();
#endif
#if ARDUINO_USB_ON_BOOT
USB.begin();
#endif
loopTaskWDTEnabled = false;
initArduino();
xTaskCreateUniversal(loopTask, "loopTask", ARDUINO_LOOP_STACK_SIZE, NULL, 1, &loopTaskHandle, ARDUINO_RUNNING_CORE);
xTaskCreateUniversal(loopTask, "loopTask", getArduinoLoopTaskStackSize(), NULL, 1, &loopTaskHandle, ARDUINO_RUNNING_CORE);
}
#endif

View File

@ -30,8 +30,7 @@
#include "stdlib_noniso.h"
#include "esp_system.h"
#if !CONFIG_DSP_ANSI && !CONFIG_DSP_OPTIMIZED
void reverse(char* begin, char* end) {
static void reverse(char* begin, char* end) {
char *is = begin;
char *ie = end - 1;
while(is < ie) {
@ -42,9 +41,6 @@ void reverse(char* begin, char* end) {
--ie;
}
}
#else
void reverse(char* begin, char* end);
#endif
char* ltoa(long value, char* result, int base) {
if(base < 2 || base > 16) {

View File

@ -17,13 +17,11 @@
//#include <limits.h>
#include "wiring_private.h"
#include "pins_arduino.h"
extern uint32_t xthal_get_ccount();
#include <hal/cpu_hal.h>
#define WAIT_FOR_PIN_STATE(state) \
while (digitalRead(pin) != (state)) { \
if (xthal_get_ccount() - start_cycle_count > timeout_cycles) { \
if (cpu_hal_get_cycle_count() - start_cycle_count > timeout_cycles) { \
return 0; \
} \
}
@ -36,12 +34,12 @@ unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
timeout = max_timeout_us;
}
const uint32_t timeout_cycles = microsecondsToClockCycles(timeout);
const uint32_t start_cycle_count = xthal_get_ccount();
const uint32_t start_cycle_count = cpu_hal_get_cycle_count();
WAIT_FOR_PIN_STATE(!state);
WAIT_FOR_PIN_STATE(state);
const uint32_t pulse_start_cycle_count = xthal_get_ccount();
const uint32_t pulse_start_cycle_count = cpu_hal_get_cycle_count();
WAIT_FOR_PIN_STATE(!state);
return clockCyclesToMicroseconds(xthal_get_ccount() - pulse_start_cycle_count);
return clockCyclesToMicroseconds(cpu_hal_get_cycle_count() - pulse_start_cycle_count);
}
unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout)

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -1,3 +1,170 @@
####
GPIO
####
About
-----
One of the most used and versatile peripheral in a microcontroller is the GPIO. The GPIO is commonly used to write and read the pin state.
GPIO stands to General Purpose Input Output, and is responsible to control or read the state of a specific pin in the digital world. For example, this peripheral is widely used to create the LED blinking or to read a simple button.
.. note:: There are some GPIOs with special restrictions, and not all GPIOs are accessible through the developemnt board. For more information about it, see the corresponding board pin layout information.
GPIOs Modes
***********
There are two different modes in the GPIO configuration:
- **Input Mode**
In this mode, the GPIO will receive the digital state from a specific device. This device could be a button or a switch.
- **Output Mode**
For the output mode, the GPIO will change the GPIO digital state to a specific device. You can drive an LED for example.
GPIO API
--------
Here is the common functions used for the GPIO peripheral.
pinMode
*******
The ``pinMode`` function is used to define the GPIO operation mode for a specific pin.
.. code-block:: arduino
void pinMode(uint8_t pin, uint8_t mode);
* ``pin`` defines the GPIO pin number.
* ``mode`` sets operation mode.
The following modes are supported for the basic `input` and `output`:
* **INPUT** sets the GPIO as input without pullup or pulldown (high impedance).
* **OUTPUT** sets the GPIO as output/read mode.
* **INPUT_PULLDOWN** sets the GPIO as input with the internal pulldown.
* **INPUT_PULLUP** sets the GPIO as input with the internal pullup.
Internal Pullup and Pulldown
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The ESP32 SoC families supports the internal pullup and pulldown throught a 45kR resistor, that can be enabled when configuring the GPIO mode as ``INPUT`` mode.
If the pullup or pulldown mode is not defined, the pin will stay in the high impedance mode.
digitalWrite
*************
The function ``digitalWrite`` sets the state of the selected GPIO to ``HIGH`` or ``LOW``. This function is only used if the ``pinMode`` was configured as ``OUTPUT``.
.. code-block:: arduino
void digitalWrite(uint8_t pin, uint8_t val);
* ``pin`` defines the GPIO pin number.
* ``val`` set the output digital state to ``HIGH`` or ``LOW``.
digitalRead
***********
To read the state of a given pin configured as ``INPUT``, the function ``digitalRead`` is used.
.. code-block:: arduino
int digitalRead(uint8_t pin);
* ``pin`` select GPIO
This function will return the logical state of the selected pin as ``HIGH`` or ``LOW``.
Interrupts
----------
The GPIO peripheral on the ESP32 supports interruptions.
attachInterrupt
***************
The function ``attachInterruptArg`` is used to attach the interrupt to the defined pin.
.. code-block:: arduino
attachInterrupt(uint8_t pin, voidFuncPtr handler, int mode);
* ``pin`` defines the GPIO pin number.
* ``handler`` set the handler function.
* ``mode`` set the interrupt mode.
Here are the supported interrupt modes:
* **DISABLED**
* **RISING**
* **FALLING**
* **CHANGE**
* **ONLOW**
* **ONHIGH**
* **ONLOW_WE**
* **ONHIGH_WE**
attachInterruptArg
******************
The function ``attachInterruptArg`` is used to attach the interrupt to the defined pin using arguments.
.. code-block:: arduino
attachInterruptArg(uint8_t pin, voidFuncPtrArg handler, void * arg, int mode);
* ``pin`` defines the GPIO pin number.
* ``handler`` set the handler function.
* ``arg`` pointer to the interrupt arguments.
* ``mode`` set the interrupt mode.
detachInterrupt
***************
To detach the interruption from a specific pin, use the ``detachInterrupt`` function giving the GPIO to be detached.
.. code-block:: arduino
detachInterrupt(uint8_t pin);
* ``pin`` defines the GPIO pin number.
.. _gpio_example_code:
Example Code
------------
GPIO Input and Output Modes
***************************
.. code-block:: arduino
#define LED 12
#define BUTTON 2
uint8_t stateLED = 0;
void setup() {
pinMode(LED, OUTPUT);
pinMode(BUTTON,INPUT_PULLUP);
}
void loop() {
if(!digitalRead(BUTTON)){
stateLED = stateLED^1;
digitalWrite(LED,stateLED);
}
}
GPIO Interrupt
**************
.. literalinclude:: ../../../libraries/ESP32/examples/GPIO/GPIOInterrupt/GPIOInterrupt.ino
:language: arduino
.. _datasheet: https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf

384
docs/source/api/i2c.rst Normal file
View File

@ -0,0 +1,384 @@
###
I2C
###
About
-----
I2C (Inter-Integrated Circuit) / TWI (Two-wire Interface) is a widely used serial communication to connect devices in a short distance. This is one of the most common peripherals used to connect sensors, EEPROMs, RTC, ADC, DAC, displays, OLED, and many other devices and microcontrollers.
This serial communication is considered as a low-speed bus, and multiple devices can be connected on the same two-wires bus, each with a unique 7-bits address (up to 128 devices). These two wires are called SDA (serial data line) and SCL (serial clock line).
.. note:: The SDA and SCL lines require pull-up resistors. See the device datasheet for more details about the resistors' values and the operating voltage.
I2C Modes
*********
The I2C can be used in two different modes:
* **I2C Master Mode**
* In this mode, the ESP32 generates the clock signal and initiates the communication with the slave device.
.. figure:: ../_static/arduino_i2c_master.png
:align: center
:width: 720
:figclass: align-center
* **I2C Slave Mode**
* The slave mode, the clock is generated by the master device and responds to the master if the destination address is the same as the destination.
.. figure:: ../_static/arduino_i2c_slave.png
:align: center
:width: 520
:figclass: align-center
Arduino-ESP32 I2C API
---------------------
The ESP32 I2C library is based on the `Arduino Wire Library`_ and implements a few more APIs, described in this documentation.
I2C Common API
**************
Here are the common functions used for master and slave modes.
begin
^^^^^
This function is used to start the peripheral using the default configuration.
.. code-block:: arduino
bool begin();
This function will return ``true`` if the peripheral was initialized correctly.
setPins
^^^^^^^
This function is used to define the ``SDA`` and ``SCL`` pins.
.. note:: Call this function before ``begin`` to change the pins from the default ones.
.. code-block:: arduino
bool setPins(int sdaPin, int sclPin);
* ``sdaPin`` sets the GPIO to be used as the I2C peripheral data line.
* ``sclPin`` sets the GPIO to be used as the I2C peripheral clock line.
The default pins may vary from board to board. On the *Generic ESP32* the default I2C pins are:
* ``sdaPin`` **GPIO21**
* ``sclPin`` **GPIO22**
This function will return ``true`` if the peripheral was configured correctly.
setClock
^^^^^^^^
Use this function to set the bus clock. The default value will be used if this function is not used.
.. code-block:: arduino
bool setClock(uint32_t frequency);
* ``frequency`` sets the bus frequency clock.
This function will return ``true`` if the clock was configured correctly.
getClock
^^^^^^^^
Use this function to get the bus clock.
.. code-block:: arduino
uint32_t getClock();
This function will return the current frequency configuration.
setTimeOut
^^^^^^^^^^
Set the bus timeout given in milliseconds. The default value is 50ms.
.. code-block:: arduino
void setTimeOut(uint16_t timeOutMillis);
* ``timeOutMillis`` sets the timeout in ms.
getTimeOut
^^^^^^^^^^
Get the bus timeout in milliseconds.
.. code-block:: arduino
uint16_t getTimeOut();
This function will return the current timeout configuration.
.. _i2c write:
write
^^^^^
This function writes data to the buffer.
.. code-block:: arduino
size_t write(uint8_t);
or
.. code-block:: arduino
size_t write(const uint8_t *, size_t);
The return will be the size of the data added to the buffer.
.. _i2c end:
end
^^^
This function will finish the communication and release all the allocated resources. After calling ``end`` you need to use ``begin`` again in order to initialize the I2C driver again.
.. code-block:: arduino
bool end();
I2C Master Mode
***************
This mode is used to initiate communication to the slave.
Basic Usage
^^^^^^^^^^^
To start using I2C master mode on the Arduino, the first step is to include the ``Wire.h`` header to the sketch.
.. code-block:: arduino
#include "Wire.h"
Now, we can start the peripheral configuration by calling ``begin`` function.
.. code-block:: arduino
Wire.begin();
By using ``begin`` without any arguments, all the settings will be done by using the default values. To set the values by your own, see the function description. This function is described here: `i2c begin`_
After calling ``begin``, we can start the transmission by calling ``beginTransmission`` and passing the I2C slave address:
.. code-block:: arduino
Wire.beginTransmission(I2C_DEV_ADDR);
To write some bytes to the slave, use the ``write`` function.
.. code-block:: arduino
Wire.write(x);
You can pass different data types using ``write`` function. This function is described here: `i2c write`_
.. note:: The ``write`` function does not write directly to the slave device but adds to the I2C buffer. To do so, you need to use the ``endTransmission`` function to send the buffered bytes to the slave device.
.. code-block:: arduino
Wire.endTransmission(true);
After calling ``endTransmission``, the data stored in the I2C buffer will be transmitted to the slave device.
Now you can request a reading from the slave device. The ``requestFrom`` will ask for a readout to the selected device by giving the address and the size.
.. code-block:: arduino
Wire.requestFrom(I2C_DEV_ADDR, SIZE);
and the ``readBytes`` will read it.
.. code-block:: arduino
Wire.readBytes(temp, error);
.. _i2c begin:
I2C Master APIs
***************
Here are the I2C master APIs. These function are intended to be used only for master mode.
begin
^^^^^
In master mode, the ``begin`` function can be used by passing the **pins** and **bus frequency**. Use this function only for the master mode.
.. code-block:: arduino
bool begin(int sdaPin, int sclPin, uint32_t frequency)
Alternatively, you can use the ``begin`` function without any argument to use all default values.
This function will return ``true`` if the peripheral was initialized correctly.
beginTransmission
^^^^^^^^^^^^^^^^^
This function is used to star a communication process with the slave device. Call this function by passing the slave ``address`` before writing the message to the buffer.
.. code-block:: arduino
void beginTransmission(uint16_t address)
endTransmission
^^^^^^^^^^^^^^^
After writing to the buffer using `i2c write`_, use the function ``endTransmission`` to send the message to the slave device address defined on the ``beginTransmission`` function.
.. code-block:: arduino
uint8_t endTransmission(bool sendStop);
* ``sendStop`` enables **(true)** or disables **(false)** the stop signal *(only used in master mode)*.
Calling the this function without ``sendStop`` is equivalent to ``sendStop = true``.
.. code-block:: arduino
uint8_t endTransmission(void);
This function will return the error code.
requestFrom
^^^^^^^^^^^
To read from the slave device, use the ``requestFrom`` function.
.. code-block:: arduino
uint8_t requestFrom(uint16_t address, uint8_t size, bool sendStop)
* ``address`` set the device address.
* ``size`` define the size to be requested.
* ``sendStop`` enables (true) or disables (false) the stop signal.
This function will return the number of bytes read from the device.
Example Application - WireMaster.ino
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Here is an example of how to use the I2C in Master Mode.
.. literalinclude:: ../../../libraries/Wire/examples/WireMaster/WireMaster.ino
:language: arduino
I2C Slave Mode
**************
This mode is used to accept communication from the master.
Basic Usage
^^^^^^^^^^^
To start using I2C as slave mode on the Arduino, the first step is to include the ``Wire.h`` header to the scketch.
.. code-block:: arduino
#include "Wire.h"
Before calling ``begin`` we must create two callback functions to handle the communication with the master device.
.. code-block:: arduino
Wire.onReceive(onReceive);
and
.. code-block:: arduino
Wire.onRequest(onRequest);
The ``onReceive`` will handle the request from the master device uppon a slave read request and the ``onRequest`` will handle the answer to the master.
Now, we can start the peripheral configuration by calling ``begin`` function with the device address.
.. code-block:: arduino
Wire.begin((uint8_t)I2C_DEV_ADDR);
By using ``begin`` without any arguments, all the settings will be done by using the default values. To set the values by your own, see the function description. This function is described here: `i2c begin`_
**For ESP32 only!**
Use the function ``slaveWrite`` in order to pre-write to the slave response buffer. This is used only for the ESP32 in order to add the slave capability on the chip and keep compatability with Arduino.
.. code-block:: arduino
Wire.slaveWrite((uint8_t *)message, strlen(message));
I2C Slave APIs
**************
Here are the I2C slave APIs. These function are intended to be used only for slave mode.
begin
^^^^^
In slave mode, the ``begin`` function must be used by passing the **slave address**. You can also define the **pins** and the **bus frequency**.
.. code-block:: arduino
bool Wire.begin(uint8_t addr, int sdaPin, int sclPin, uint32_t frequency)
This function will return ``true`` if the peripheral was initialized correctly.
onReceive
^^^^^^^^^
The ``onReceive`` function is used to define the callback for the data received from the master.
.. code-block:: arduino
void onReceive( void (*)(int) );
onRequest
^^^^^^^^^
The ``onRequest`` function is used to define the callback for the data to be send to the master.
.. code-block:: arduino
void onRequest( void (*)(void) );
slaveWrite
^^^^^^^^^^
The ``slaveWrite`` function writes on the slave response buffer before receiving the response message. This function is only used for adding the slave compatability for the ESP32.
.. warning:: This function is only required for the ESP32. You **don't** need to use for ESP32-S2 and ESP32-C3.
.. code-block:: arduino
size_t slaveWrite(const uint8_t *, size_t);
Example Application - WireSlave.ino
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Here is an example of how to use the I2C in Slave Mode.
.. literalinclude:: ../../../libraries/Wire/examples/WireSlave/WireSlave.ino
:language: arduino
.. _Arduino Wire Library: https://www.arduino.cc/en/reference/wire

331
docs/source/api/usb.rst Normal file
View File

@ -0,0 +1,331 @@
#######
USB API
#######
.. note:: This feature is only supported on ESP chips that have USB peripheral, like the ESP32-S2 and ESP32-S3. Some chips, like the ESP32-C3 include native CDC+JTAG peripheral that is not covered here.
About
-----
The **Universal Serial Bus** is a widely used peripheral to exchange data between devices. USB was introduced on the ESP32, supporting both device and host mode.
To learn about the USB, see the `USB.org`_ for developers.
USB as Device
*************
In the device mode, the ESP32 acts as an USB device, like a mouse or keyboard to be connected to a host device, like your computer or smartphone.
USB as Host
***********
The USB host mode, you can connect devices on the ESP32, like external modems, mouse and keyboards.
.. note:: This mode is still under development for the ESP32.
API Description
---------------
This is the common USB API description.
For more supported USB classes implementation, see the following sections:
.. toctree::
:maxdepth: 1
:caption: Classes:
USB CDC <usb_cdc>
USB MSC <usb_msc>
USB Common
**********
These are the common APIs for the USB driver.
onEvent
^^^^^^^
Event handling function to set the callback.
.. code-block:: arduino
void onEvent(esp_event_handler_t callback);
Event handling function for the specific event.
.. code-block:: arduino
void onEvent(arduino_usb_event_t event, esp_event_handler_t callback);
Where ``event`` can be:
* ARDUINO_USB_ANY_EVENT
* ARDUINO_USB_STARTED_EVENT
* ARDUINO_USB_STOPPED_EVENT
* ARDUINO_USB_SUSPEND_EVENT
* ARDUINO_USB_RESUME_EVENT
* ARDUINO_USB_MAX_EVENT
VID
^^^
Set the Vendor ID. This 16 bits identification is used to identify the company that develops the product.
.. note:: You can't define your own VID. If you need your own VID, you need to buy one. See https://www.usb.org/getting-vendor-id for more details.
.. code-block:: arduino
bool VID(uint16_t v);
Get the Vendor ID.
.. code-block:: arduino
uint16_t VID(void);
Returns the Vendor ID. The default value for the VID is: ``0x303A``.
PID
^^^
Set the Product ID. This 16 bits identification is used to identify the product.
.. code-block:: arduino
bool PID(uint16_t p);
Get the Product ID.
.. code-block:: arduino
uint16_t PID(void);
Returns the Product ID. The default PID is: ``0x0002``.
firmwareVersion
^^^^^^^^^^^^^^^
Set the firmware version. This is a 16 bits unsigned value.
.. code-block:: arduino
bool firmwareVersion(uint16_t version);
Get the firmware version.
.. code-block:: arduino
uint16_t firmwareVersion(void);
Return the 16 bits unsigned value. The default value is: ``0x100``.
usbVersion
^^^^^^^^^^
Set the USB version.
.. code-block:: arduino
bool usbVersion(uint16_t version);
Get the USB version.
.. code-block:: arduino
uint16_t usbVersion(void);
Return the USB version. The default value is: ``0x200`` (USB 2.0).
usbPower
^^^^^^^^
Set the USB power as mA (current).
.. note:: This configuration does not change the physical power output. This is only used for the USB device information.
.. code-block:: arduino
bool usbPower(uint16_t mA);
Get the USB power configuration.
.. code-block:: arduino
uint16_t usbPower(void);
Return the current in mA. The default value is: ``0x500`` (500mA).
usbClass
^^^^^^^^
Set the USB class.
.. code-block:: arduino
bool usbClass(uint8_t _class);
Get the USB class.
.. code-block:: arduino
uint8_t usbClass(void);
Return the USB class. The default value is: ``TUSB_CLASS_MISC``.
usbSubClass
^^^^^^^^^^^
Set the USB sub-class.
.. code-block:: arduino
bool usbSubClass(uint8_t subClass);
Get the USB sub-class.
.. code-block:: arduino
uint8_t usbSubClass(void);
Return the USB sub-class. The default value is: ``MISC_SUBCLASS_COMMON``.
usbProtocol
^^^^^^^^^^^
Define the USB protocol.
.. code-block:: arduino
bool usbProtocol(uint8_t protocol);
Get the USB protocol.
.. code-block:: arduino
uint8_t usbProtocol(void);
Return the USB protocol. The default value is: ``MISC_PROTOCOL_IAD``
usbAttributes
^^^^^^^^^^^^^
Set the USB attributes.
.. code-block:: arduino
bool usbAttributes(uint8_t attr);
Get the USB attributes.
.. code-block:: arduino
uint8_t usbAttributes(void);
Return the USB attributes. The default value is: ``TUSB_DESC_CONFIG_ATT_SELF_POWERED``
webUSB
^^^^^^
This function is used to enable the ``webUSB`` functionality.
.. code-block:: arduino
bool webUSB(bool enabled);
This function is used to get the ``webUSB`` setting.
.. code-block:: arduino
bool webUSB(void);
Return the ``webUSB`` setting (`Enabled` or `Disabled`)
productName
^^^^^^^^^^^
This function is used to define the product name.
.. code-block:: arduino
bool productName(const char * name);
This function is used to get the product's name.
.. code-block:: arduino
const char * productName(void);
manufacturerName
^^^^^^^^^^^^^^^^
This function is used to define the manufacturer name.
.. code-block:: arduino
bool manufacturerName(const char * name);
This function is used to get the manufacturer's name.
.. code-block:: arduino
const char * manufacturerName(void);
serialNumber
^^^^^^^^^^^^
This function is used to define the serial number.
.. code-block:: arduino
bool serialNumber(const char * name);
This function is used to get the serial number.
.. code-block:: arduino
const char * serialNumber(void);
The default serial number is: ``0``.
webUSBURL
^^^^^^^^^
This function is used to define the ``webUSBURL``.
.. code-block:: arduino
bool webUSBURL(const char * name);
This function is used to get the ``webUSBURL``.
.. code-block:: arduino
const char * webUSBURL(void);
The default ``webUSBURL`` is: https://espressif.github.io/arduino-esp32/webusb.html
enableDFU
^^^^^^^^^
This function is used to enable the DFU capability.
.. code-block:: arduino
bool enableDFU();
begin
^^^^^
This function is used to start the peripheral using the default configuration.
.. code-block:: arduino
bool begin();
Example Code
------------
There are a collection of USB device examples on the project GitHub, including Firmware MSC update, USB CDC, HID and composite device.
.. _USB.org: https://www.usb.org/developers

192
docs/source/api/usb_cdc.rst Normal file
View File

@ -0,0 +1,192 @@
#######
USB CDC
#######
About
-----
USB Communications Device Class API. This class is used to enable communication between the host and the device.
This class is often used to enable serial communication and can be used to flash the firmware on the ESP32 without the external USB to Serial chip.
APIs
****
onEvent
^^^^^^^
Event handling functions.
.. code-block:: arduino
void onEvent(esp_event_handler_t callback);
.. code-block:: arduino
void onEvent(arduino_usb_cdc_event_t event, esp_event_handler_t callback);
Where ``event`` can be:
* ARDUINO_USB_CDC_ANY_EVENT
* ARDUINO_USB_CDC_CONNECTED_EVENT
* ARDUINO_USB_CDC_DISCONNECTED_EVENT
* ARDUINO_USB_CDC_LINE_STATE_EVENT
* ARDUINO_USB_CDC_LINE_CODING_EVENT
* ARDUINO_USB_CDC_RX_EVENT
* ARDUINO_USB_CDC_TX_EVENT
* ARDUINO_USB_CDC_MAX_EVENT
setRxBufferSize
^^^^^^^^^^^^^^^
The ``setRxBufferSize`` function is used to set the size of the RX buffer.
.. code-block:: arduino
size_t setRxBufferSize(size_t size);
setTxTimeoutMs
^^^^^^^^^^^^^^
This function is used to define the time to reach the timeout for the TX.
.. code-block:: arduino
void setTxTimeoutMs(uint32_t timeout);
begin
^^^^^
This function is used to start the peripheral using the default CDC configuration.
.. code-block:: arduino
void begin(unsigned long baud);
Where:
* ``baud`` is the baud rate.
end
^^^
This function will finish the peripheral as CDC and release all the allocated resources. After calling ``end`` you need to use ``begin`` again in order to initialize the USB CDC driver again.
.. code-block:: arduino
void end();
available
^^^^^^^^^
This function will return if there are messages in the queue.
.. code-block:: arduino
int available(void);
The return is the number of bytes available to read.
availableForWrite
^^^^^^^^^^^^^^^^^
This function will return if the hardware is available to write data.
.. code-block:: arduino
int availableForWrite(void);
peek
^^^^
This function is used to ``peek`` messages from the queue.
.. code-block:: arduino
int peek(void);
read
^^^^
This function is used to read the bytes available.
.. code-block:: arduino
size_t read(uint8_t *buffer, size_t size);
Where:
* ``buffer`` is the pointer to the buffer to be read.
* ``size`` is the number of bytes to be read.
write
^^^^^
This function is used to write the message.
.. code-block:: arduino
size_t write(const uint8_t *buffer, size_t size);
Where:
* ``buffer`` is the pointer to the buffer to be written.
* ``size`` is the number of bytes to be written.
flush
^^^^^
This function is used to flush the data.
.. code-block:: arduino
void flush(void);
baudRate
^^^^^^^^
This function is used to get the ``baudRate``.
.. code-block:: arduino
uint32_t baudRate();
setDebugOutput
^^^^^^^^^^^^^^
This function will enable the debug output, usually from the `UART0`, to the USB CDC.
.. code-block:: arduino
void setDebugOutput(bool);
enableReboot
^^^^^^^^^^^^
This function enables the device to reboot by the DTR as RTS signals.
.. code-block:: arduino
void enableReboot(bool enable);
rebootEnabled
^^^^^^^^^^^^^
This function will return if the reboot is enabled.
.. code-block:: arduino
bool rebootEnabled(void);
Example Code
------------
Here is an example of how to use the USB CDC.
USBSerial
*********
.. literalinclude:: ../../../libraries/USB/examples/USBSerial/USBSerial.ino
:language: arduino
.. _USB.org: https://www.usb.org/developers

114
docs/source/api/usb_msc.rst Normal file
View File

@ -0,0 +1,114 @@
#######
USB MSC
#######
About
-----
USB Mass Storage Class API. This class makes the device accessible as a mass storage device and allows you to transfer data between the host and the device.
One of the examples for this mode is to flash the device by dropping the firmware binary like a flash memory device when connecting the ESP32 to the host computer.
APIs
****
begin
^^^^^
This function is used to start the peripheral using the default MSC configuration.
.. code-block:: arduino
bool begin(uint32_t block_count, uint16_t block_size);
Where:
* ``block_count`` set the disk sector count.
* ``block_size`` set the disk sector size.
This function will return ``true`` if the configuration was successful.
end
^^^
This function will finish the peripheral as MSC and release all the allocated resources. After calling ``end`` you need to use ``begin`` again in order to initialize the USB MSC driver again.
.. code-block:: arduino
void end();
vendorID
^^^^^^^^
This function is used to define the vendor ID.
.. code-block:: arduino
void vendorID(const char * vid);//max 8 chars
productID
^^^^^^^^^
This function is used to define the product ID.
.. code-block:: arduino
void productID(const char * pid);//max 16 chars
productRevision
^^^^^^^^^^^^^^^
This function is used to define the product revision.
.. code-block:: arduino
void productRevision(const char * ver);//max 4 chars
mediaPresent
^^^^^^^^^^^^
Set the ``mediaPresent`` configuration.
.. code-block:: arduino
void mediaPresent(bool media_present);
onStartStop
^^^^^^^^^^^
Set the ``onStartStop`` callback function.
.. code-block:: arduino
void onStartStop(msc_start_stop_cb cb);
onRead
^^^^^^
Set the ``onRead`` callback function.
.. code-block:: arduino
void onRead(msc_read_cb cb);
onWrite
^^^^^^^
Set the ``onWrite`` callback function.
.. code-block:: arduino
void onWrite(msc_write_cb cb);
Example Code
------------
Here is an example of how to use the USB MSC.
FirmwareMSC
***********
.. literalinclude:: ../../../libraries/USB/examples/FirmwareMSC/FirmwareMSC.ino
:language: arduino
.. _USB.org: https://www.usb.org/developers

View File

@ -26,7 +26,7 @@ a Wi-Fi network.
:width: 520
:figclass: align-center
This mode can be used for serving a HTTP or HTTPS server inside the ESP32, for example.
This mode can be used for serving an HTTP or HTTPS server inside the ESP32, for example.
Working as STA
**************
@ -38,12 +38,34 @@ The STA mode is used to connect the ESP32 to a Wi-Fi network, provided by an Acc
:width: 520
:figclass: align-center
If you need to connect your project to the Internet, this is the mode you are looking for.
This is the mode to be used if you want to connect your project to the Internet.
API Description
---------------
Here is the description about the WiFi API.
Here is the description of the WiFi API.
Common API
----------
Here are the common APIs that are used for both modes, AP and STA.
useStaticBuffers
****************
This function is used to set the memory allocation mode for the Wi-Fi buffers.
.. code-block:: arduino
static void useStaticBuffers(bool bufferMode);
* Set ``true`` to use the Wi-Fi buffers memory allocation as **static**.
* Set ``false`` to set the buffers memory allocation to **dynamic**.
The use of dynamic allocation is recommended to save memory and reduce resources usage. However, the dynamic performs slightly slower than the static allocation.
Use static allocation if you want to have more performance and if your application is multi-tasking.
By default, the memory allocation will be set to **dynamic** if this function is not being used.
WiFiAP
------

View File

@ -81,16 +81,22 @@ Add here the third party boards, listed by vendors.
creating an `issue on GitHub <https://github.com/espressif/arduino-esp32/issues>`_ and directly
link/mention the vendor in the issue description.
LOLIN
*****
* |board_lolin_d32|
* |board_lolin_d32_pro|
Generic Vendor
**************
.. toctree::
:maxdepth: 1
Generic Board Name <generic>
.. note::
Create one file per board or one file with multiple boards. Do not add board information/description on this file.
.. toctree::
:maxdepth: 1
Generic Board Name <generic>
.. note::
Create one file per board or one file with multiple boards. Do not add board information/description on this file.
Resources
---------
@ -104,3 +110,11 @@ Resources
.. _ESP32 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf
.. _ESP32-S2 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf
.. _ESP32-C3 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf
.. |board_lolin_d32| raw:: html
<a href="https://www.wemos.cc/en/latest/d32/d32.html" target="_blank">LOLIN D32</a>
.. |board_lolin_d32_pro| raw:: html
<a href="https://www.wemos.cc/en/latest/d32/d32_pro.html" target="_blank">LOLIN D32 Pro</a>

View File

@ -56,7 +56,7 @@ exclude_patterns = []
# a list of builtin themes.
#
html_theme = 'default'
html_logo = 'logo_espressif.png'
html_logo = '_static/logo_espressif.png'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,

View File

@ -5,13 +5,15 @@ Arduino as a ESP-IDF component
ESP32 Arduino lib-builder
-------------------------
For a simplified method, see `lib-builder <lib_builder>`_.
For a simplified method, see `lib-builder <https://github.com/espressif/esp32-arduino-lib-builder>`_.
Installation
------------
.. note:: Latest Arduino Core ESP32 version is now compatible with `ESP-IDF v4.4 <https://github.com/espressif/esp-idf/tree/release/v4.4>`_. Please consider this compability when using Arduino as component in ESP-IDF.
- Download and install `ESP-IDF <https://github.com/espressif/esp-idf>`_.
- Create blank idf project (from one of the examples).
- Create blank ESP-IDF project (use sample_project from /examples/get-started) or choose one of the examples.
- In the project folder, create a new folder called `components` and clone this repository inside the new created folder.
.. code-block:: bash
@ -24,10 +26,19 @@ Installation
cd ../.. && \
idf.py menuconfig
Option 1. Using Arduino setup() and loop()
******************************************
- The `idf.py menuconfig` has some Arduino options.
- On `Autostart Arduino setup and loop on boot`.
- If you enable these options, your main.cpp should be formated like any other sketch.
- Turn on `Autostart Arduino setup and loop on boot`.
- In main folder rename file `main.c` to `main.cpp`.
- In main folder open file `CMakeList.txt` and change `main.c` to `main.cpp` as described below.
.. code-block:: bash
idf_component_register(SRCS "main.cpp" INCLUDE_DIRS ".")
- Your main.cpp should be formated like any other sketch.
.. code-block:: c
@ -43,14 +54,17 @@ Installation
delay(1000);
}
- Otherwise, you need to implement ```app_main()``` and call ```initArduino();``` in it.
Option 2. Using ESP-IDF appmain()
*********************************
- You need to implement ``app_main()`` and call ``initArduino();`` in it.
Keep in mind that setup() and loop() will not be called in this case.
If you plan to base your code on examples provided in `examples <https://github.com/espressif/esp-idf/tree/master/examples>`_, please make sure to move the app_main() function in main.cpp from the files in the example.
.. code-block:: cpp
//file: main.cpp
//file: main.c or main.cpp
#include "Arduino.h"
extern "C" void app_main()
@ -67,7 +81,11 @@ If you plan to base your code on examples provided in `examples <https://github.
- If enabled, WiFi will start with the last known configuration
- Otherwise it will wait for WiFi.begin
- ```idf.py -p <your-board-serial-port> flash monitor``` will build, upload and open serial monitor to your board
Build, flash and monitor
************************
- For both options use command ``idf.py -p <your-board-serial-port> flash monitor``
- It will build, upload and open serial monitor to your board.
Logging To Serial
-----------------

View File

@ -35,9 +35,9 @@ Here are the ESP32 series supported by the Arduino-ESP32 project:
SoC Stable Development Datasheet
======== ====== =========== ===================================
ESP32 Yes Yes `ESP32 Datasheet`_
ESP32-S2 No Yes `ESP32-S2 Datasheet`_
ESP32-C3 No Yes `ESP32-C3 Datasheet`_
ESP32-S3 No No Not Available Yet
ESP32-S2 Yes Yes `ESP32-S2 Datasheet`_
ESP32-C3 Yes Yes `ESP32-C3 Datasheet`_
ESP32-S3 No No `ESP32-S3 Datasheet`_
======== ====== =========== ===================================
See `Boards <boards/boards.html>`_ for more details about ESP32 development boards.
@ -122,6 +122,7 @@ Resources
.. _ESP32 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf
.. _ESP32-S2 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf
.. _ESP32-C3 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf
.. _ESP32-S3 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf
.. _Arduino.cc: https://www.arduino.cc/en/Main/Software
.. _Arduino Reference: https://www.arduino.cc/reference/en/
.. _ESP32 Forum: https://esp32.com

View File

@ -29,7 +29,7 @@ This is the preferred and easiest way to install Arduino-ESP32.
.. note::
Starting with the Arduino IDE version 1.6.4, Arduino allows installation of third-party platform
packages using Boards Manager. We have packages available for Windows, macOS, and Linux (x86, amd64, armhf and arm64).
packages using Boards Manager. We have packages available for Windows, macOS, and Linux.
To start the installation process using the Boards Managaer, follow these steps:
@ -61,10 +61,11 @@ To start the installation process using the Boards Managaer, follow these steps:
Windows
-------
Steps to install Arduino ESP32 support on Windows:
.. warning:: Arduino ESP32 core v2.x.x cannot be used on Windows 8.x x86 (32 bits), Windows 7 or earlier. The Windows 32 bits OS is no longer supported by this toolchain.
.. note::
Tested on Windows 10 32 and 64 bit machines.
The Arduino ESP32 v1.0.6 still works on WIN32. You might want to install python 3.8.x because it is the latest release supported by Windows 7.
Steps to install Arduino ESP32 support on Windows:
**Step 1**
@ -166,9 +167,7 @@ Debian/Ubuntu
mkdir -p ~/Arduino/hardware/espressif && \
cd ~/Arduino/hardware/espressif && \
git clone https://github.com/espressif/arduino-esp32.git esp32 && \
cd esp32 && \
git submodule update --init --recursive && \
cd tools && \
cd esp32/tools && \
python3 get.py
- Restart Arduino IDE.
@ -181,9 +180,7 @@ Debian/Ubuntu
mkdir -p espressif && \
cd espressif && \
git clone https://github.com/espressif/arduino-esp32.git esp32 && \
cd esp32 && \
git submodule update --init --recursive && \
cd tools && \
cd esp32/tools && \
python3 get.py
Fedora
@ -203,9 +200,7 @@ Fedora
mkdir -p ~/Arduino/hardware/espressif && \
cd ~/Arduino/hardware/espressif && \
git clone https://github.com/espressif/arduino-esp32.git esp32 && \
cd esp32 && \
git submodule update --init --recursive && \
cd tools && \
cd esp32/tools && \
python get.py
- Restart Arduino IDE.
@ -228,9 +223,7 @@ openSUSE
mkdir -p ~/Arduino/hardware/espressif && \
cd ~/Arduino/hardware/espressif && \
git clone https://github.com/espressif/arduino-esp32.git esp32 && \
cd esp32 && \
git submodule update --init --recursive && \
cd tools && \
cd esp32/tools && \
python get.py
- Restart Arduino IDE.
@ -246,10 +239,8 @@ macOS
mkdir -p ~/Documents/Arduino/hardware/espressif && \
cd ~/Documents/Arduino/hardware/espressif && \
git clone https://github.com/espressif/arduino-esp32.git esp32 --depth 1 && \
cd esp32 && \
git submodule update --init --recursive --depth 1 && \
cd tools && \
git clone https://github.com/espressif/arduino-esp32.git esp32 && \
cd esp32/tools && \
python get.py
Where ``~/Documents/Arduino`` represents your sketch book location as per "Arduino" > "Preferences" > "Sketchbook location" (in the IDE once started). Adjust the command above accordingly.

View File

@ -2,16 +2,89 @@
Libraries
#########
Here is where the Libraries API's descriptions are located.
Here is where the Libraries API's descriptions are located:
Supported Peripherals
---------------------
Currently, the Arduino ESP32 supports the following peripherals with Arduino APIs.
+---------------+---------------+---------------+---------------+-------------------------------+
| Peripheral | ESP32 | ESP32-S2 | ESP32-C3 | Comments |
+===============+===============+===============+===============+===============================+
| ADC | Yes | Yes | Yes | |
+---------------+---------------+---------------+---------------+-------------------------------+
| Bluetooth | Yes | Not Supported | Not Supported | Bluetooth Classic |
+---------------+---------------+---------------+---------------+-------------------------------+
| BLE | Yes | Not Supported | Yes | |
+---------------+---------------+---------------+---------------+-------------------------------+
| DAC | Yes | Yes | Not Supported | |
+---------------+---------------+---------------+---------------+-------------------------------+
| Ethernet | Yes | Not Supported | Not Supported | (*) |
+---------------+---------------+---------------+---------------+-------------------------------+
| GPIO | Yes | Yes | Yes | |
+---------------+---------------+---------------+---------------+-------------------------------+
| Hall Sensor | Yes | Not Supported | Not Supported | |
+---------------+---------------+---------------+---------------+-------------------------------+
| I2C | Yes | Yes | Yes | |
+---------------+---------------+---------------+---------------+-------------------------------+
| I2S | No | No | No | WIP |
+---------------+---------------+---------------+---------------+-------------------------------+
| LEDC | Yes | Yes | Yes | |
+---------------+---------------+---------------+---------------+-------------------------------+
| Motor PWM | No | Not Supported | Not Supported | |
+---------------+---------------+---------------+---------------+-------------------------------+
| Pulse Counter | No | No | No | |
+---------------+---------------+---------------+---------------+-------------------------------+
| RMT | Yes | Yes | Yes | |
+---------------+---------------+---------------+---------------+-------------------------------+
| SDIO | No | No | No | |
+---------------+---------------+---------------+---------------+-------------------------------+
| SPI | Yes | Yes | Yes | |
+---------------+---------------+---------------+---------------+-------------------------------+
| Timer | Yes | Yes | Yes | |
+---------------+---------------+---------------+---------------+-------------------------------+
| Temp. Sensor | Not Supported | Yes | Yes | |
+---------------+---------------+---------------+---------------+-------------------------------+
| Touch | Yes | Yes | Not Supported | |
+---------------+---------------+---------------+---------------+-------------------------------+
| TWAI | No | No | No | |
+---------------+---------------+---------------+---------------+-------------------------------+
| UART | Yes | Yes | Yes | |
+---------------+---------------+---------------+---------------+-------------------------------+
| USB | Not Supported | Yes | Yes | ESP32-C3 only CDC/JTAG |
+---------------+---------------+---------------+---------------+-------------------------------+
| Wi-Fi | Yes | Yes | Yes | |
+---------------+---------------+---------------+---------------+-------------------------------+
Notes
^^^^^
(*) SPI Ethernet is supported by all ESP32 families and RMII only for ESP32.
.. note:: Some peripherals are not available for all ESP32 families. To see more details about it, see the corresponding SoC at `Product Selector <https://products.espressif.com>`_ page.
Datasheet
^^^^^^^^^
* `ESP32 <https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf>`_
* `ESP32-S2 <https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf>`_
* `ESP32-C3 <https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf>`_
APIs
----
The Arduino ESP32 offers some unique APIs, described in this section:
.. toctree::
:maxdepth: 1
:caption: API's:
Bluetooth <api/bluetooth>
Deep Sleep <api/deepsleep>
ESPNOW <api/espnow>
GPIO <api/gpio>
I2C <api/i2c>
RainMaker <api/rainmaker>
Reset Reason <api/reset_reason>
USB <api/usb.rst>
Wi-Fi <api/wifi>

View File

@ -1,5 +1,5 @@
###############
Troubleshotting
Troubleshooting
###############
Common Issues
@ -12,16 +12,71 @@ Here are some of the most common issues around the ESP32 development using Ardui
Installing
----------
Here are the common issues during the installation.
Building
--------
Missing Python: "python": executable file not found in $PATH
************************************************************
You are trying to build your sketch using Ubuntu and this message appears:
.. code-block:: bash
"exec: "python": executable file not found in $PATH
Error compiling for board ESP32 Dev Module"
Solution
^^^^^^^^
To avoid this error, you can install the ``python-is-python3`` package to create the symbolic links.
.. code-block:: bash
sudo apt install python-is-python3
If you are not using Ubuntu, you can check if you have the Python correctly installed or the presence of the symbolic links/environment variables.
Flashing
--------
* The board is not flashing.
Why is my board not flashing/uploading when I try to upload my sketch?
**********************************************************************
To be able to upload the sketch via serial interface, the ESP32 must be in the download mode. The download mode allows you to upload the sketch over the serial port and to get into it, you need to keep the **GPIO0** in LOW while a resetting (**EN** pin) cycle.
If you are trying to upload a new sketch and your board is not responding, there are some possible reasons.
Possible fatal error message from the Arduino IDE:
*A fatal error occurred: Failed to connect to ESP32: Timed out waiting for packet header*
Solution
^^^^^^^^
Here are some steps that you can try to:
* Check your USB cable and try a new one.
* Change the USB port.
* Check your power supply.
* In some instances, you must keep **GPIO0** LOW during the uploading process via the serial interface.
* Hold down the **“BOOT”** button in your ESP32 board while uploading/flashing.
In some development boards, you can try adding the reset delay circuit, as described in the *Power-on Sequence* section on the `ESP32 Hardware Design Guidelines <https://www.espressif.com/sites/default/files/documentation/esp32_hardware_design_guidelines_en.pdf>`_ in order to get into the download mode automatically.
Hardware
--------
* Power Source
* Bad USB cable or charging only cables
Why is my computer not detecting my board?
**************************************************
If your board is not being detected after connecting to the USB, you can try to:
Solution
^^^^^^^^
* Check if the USB driver is missing. - `USB Driver Download Link <https://www.silabs.com/developers/usb-to-uart-bridge-vcp-drivers>`_
* Check your USB cable and try a new one.
* Change the USB port.
* Check your power supply.
* Check if the board is damaged or defective.

View File

@ -0,0 +1,113 @@
##########################
Blink Interactive Tutorial
##########################
Introduction
------------
This is the interactive blink tutorial using `Wokwi`_. For this tutorial, you don't need the ESP32 board or the Arduino toolchain.
.. note:: If you don't want to use this tutorial with the simulation, you can copy and paste the :ref:`blink_example_code` from `Wokwi`_ editor and use it on the `Arduino IDE`_ or `PlatformIO`_.
About this Tutorial
-------------------
This tutorial is the most basic for any get started. In this tutorial, we will show how to set a GPIO pin as an output to drive a LED to blink each 1 second.
Step by step
------------
In order to make this simple blink tutorial, you'll need to do the following steps.
1. **Define the GPIO for the LED.**
.. code-block::
#define LED 2
This ``#define LED 2`` will be used to set the GPIO2 as the ``LED`` output pin.
2. **Setup.**
Inside the ``setup()`` function, we need to add all things we want to run once during the startup.
Here we'll add the ``pinMode`` function to set the pin as output.
.. code-block::
void setup() {
pinMode(LED, OUTPUT);
}
The first argument is the GPIO number, already defined and the second is the mode, here defined as an output.
3. **Main Loop.**
After the ``setup``, the code runs the ``loop`` function infinitely. Here we will handle the GPIO in order to get the LED blinking.
.. code-block::
void loop() {
digitalWrite(LED, HIGH);
delay(100);
digitalWrite(LED, LOW);
delay(100);
}
The first function is the ``digitalWrite()`` with two arguments:
* GPIO: Set the GPIO pin. Here defined by our ``LED`` connected to the GPIO2.
* State: Set the GPIO state as HIGH (ON) or LOW (OFF).
This first ``digitalWrite`` we will set the LED ON.
After the ``digitalWrite``, we will set a ``delay`` function in order to wait for some time, defined in milliseconds.
Now we can set the GPIO to ``LOW`` to turn the LED off and ``delay`` for more few milliseconds to get the LED blinking.
4. **Run the code.**
To run this code, you'll need a development board and the Arduino toolchain installed on your computer. If you don't have both, you can use the simulator to test and edit the code.
Simulation
----------
This simulator is provided by `Wokwi`_ and you can test the blink code and play with some modifications to learn more about this example.
.. raw:: html
<iframe src="https://wokwi.com/arduino/projects/305566932847821378?embed=1" width="100%" height="400" border="0"></iframe>
Change the parameters, like the delay period, to test the code right on your browser. You can add more LEDs, change the GPIO, and more.
.. _blink_example_code:
Example Code
------------
Here is the full blink code.
.. code-block::
#define LED 2
void setup() {
pinMode(LED, OUTPUT);
}
void loop() {
digitalWrite(LED, HIGH);
delay(100);
digitalWrite(LED, LOW);
delay(100);
}
Resources
---------
* `ESP32 Datasheet`_ (Datasheet)
* `Wokwi`_ (Wokwi Website)
.. _ESP32 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf
.. _Wokwi: https://wokwi.com/
.. _PlatformIO: https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html#platformio
.. _Arduino IDE: https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html#installing-using-boards-manager

View File

@ -6,6 +6,7 @@ Tutorials
:maxdepth: 2
:caption: Tutorials:
Blink <blink>
Basic <basic>
DFU <dfu>
GPIO Matrix and Pin Mux <io_mux>

View File

@ -191,7 +191,7 @@ uint8_t* BLECharacteristic::getData() {
* @brief Retrieve the current length of the data of the characteristic.
* @return Amount of databytes of the characteristic.
*/
uint8_t BLECharacteristic::getLength() {
size_t BLECharacteristic::getLength() {
return m_value.getLength();
} // getLength

View File

@ -62,7 +62,7 @@ public:
BLEUUID getUUID();
std::string getValue();
uint8_t* getData();
uint8_t getLength();
size_t getLength();
void indicate();
void notify(bool is_notification = true);

View File

@ -347,7 +347,7 @@ gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
return;
}
#ifndef CLASSIC_BT_ENABLED
#ifndef CONFIG_BT_CLASSIC_ENABLED
esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
#endif
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
@ -357,7 +357,7 @@ gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
return;
}
#ifndef CLASSIC_BT_ENABLED
#ifndef CONFIG_BT_CLASSIC_ENABLED
errRc = esp_bt_controller_enable(ESP_BT_MODE_BLE);
if (errRc != ESP_OK) {
log_e("esp_bt_controller_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));

View File

@ -26,6 +26,7 @@
#define HID_CARD_READER 0x03C6
#define HID_DIGITAL_PEN 0x03C7
#define HID_BARCODE 0x03C8
#define HID_BRAILLE_DISPLAY 0x03C9
class BLEHIDDevice {
public:

View File

@ -157,7 +157,9 @@ void BLEServer::handleGATTServerEvent(esp_gatts_cb_event_t event, esp_gatt_if_t
case ESP_GATTS_MTU_EVT:
updatePeerMTU(param->mtu.conn_id, param->mtu.mtu);
m_pServerCallbacks->onMtuChanged(this, param);
if (m_pServerCallbacks != nullptr) {
m_pServerCallbacks->onMtuChanged(this, param);
}
break;
// ESP_GATTS_CONNECT_EVT

View File

@ -7,7 +7,7 @@
* Author: Thomas M. (ArcticSnowSky)
*/
#include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED)
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BLUEDROID_ENABLED)
#include "BTAddress.h"
#include <string>

View File

@ -10,7 +10,7 @@
#ifndef COMPONENTS_CPP_UTILS_BTADDRESS_H_
#define COMPONENTS_CPP_UTILS_BTADDRESS_H_
#include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED)
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BLUEDROID_ENABLED)
#include <esp_gap_bt_api.h> // ESP32 BT
#include <string>

View File

@ -6,7 +6,7 @@
*/
#include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED)
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BLUEDROID_ENABLED)
//#include <map>

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