Compare commits

..

27 Commits

Author SHA1 Message Date
d011dd7ef5 Missing include in BLE header causes compilation to fail (#3865) 2020-09-30 15:00:22 +03:00
475208e535 IDF release/v4.0 48ea44f3d 2020-07-18 18:14:30 +00:00
2bf655b658 IDF release/v4.0 94d97499a 2020-06-17 12:13:29 +00:00
2fbbae762b IDF release/v4.0 e7ac221b4 2020-06-16 00:23:34 +00:00
d2761a9eab IDF release/v4.0 4c81978a3 2020-05-21 06:09:30 +00:00
8c8d8610f4 IDF release/v4.0 b0f053d82 2020-05-08 12:08:46 +00:00
c2da05050e IDF release/v4.0 fe67bedee 2020-04-16 06:09:39 +00:00
3746ef9df9 IDF release/v4.0 6825d8e0b 2020-04-14 00:14:38 +00:00
92eb1a2264 IDF release/v4.0 acdba0eb4 2020-04-13 12:10:06 +00:00
b47b0dc966 IDF release/v4.0 a3f3c7bdc 2020-04-07 00:12:32 +00:00
2271c7726d Merge branch 'idf-release/v4.0' of https://github.com/espressif/arduino-esp32 into idf-release/v4.0 2020-04-07 01:26:44 +03:00
9afee31462 Fix ETH in 4.0 2020-04-07 01:26:36 +03:00
f15a6ac205 Fix 3.3 compatibility 2020-04-07 01:11:14 +03:00
176077b133 IDF release/v4.0 b6bec84c6 2020-02-13 18:10:22 +00:00
60f20a7869 IDF release/v4.0 230931310 2020-02-13 00:13:59 +00:00
8817e536fd IDF release/v4.0 a61fd1e42 2020-01-29 12:08:12 +00:00
d1e3122d87 Merge branch 'idf-4.0-prep' of https://github.com/espressif/arduino-esp32 into idf-release/v4.0 2020-01-27 18:03:49 +02:00
856e596c79 Pass ethernet events to the main handler 2020-01-27 18:03:03 +02:00
2a88f72c4e Merge branch 'idf-4.0-prep' of https://github.com/espressif/arduino-esp32 into idf-release/v4.0 2020-01-27 17:34:48 +02:00
354e485c4b get smart config to work as well 2020-01-27 17:34:30 +02:00
5d9a22eb3a Merge branch 'idf-4.0-prep' of https://github.com/espressif/arduino-esp32 into idf-release/v4.0 2020-01-27 16:45:02 +02:00
1c4966566c make ETH work 2020-01-27 16:22:07 +02:00
4bb60f68da Update package_esp32_index.template.json 2020-01-27 13:50:33 +02:00
a9fa894f0d Merge branch 'idf-4.0-prep' of https://github.com/espressif/arduino-esp32 into idf-release/v4.0 2020-01-25 22:41:53 +02:00
251d5ef92b Update CMakeLists.txt 2020-01-25 22:41:03 +02:00
41ba143063 IDF release/v4.0 08219f3cf 2020-01-25 14:51:58 +00:00
8c723be135 Initial IDF-4.0 port
SmartConfig and ETH need some work to adapt to the new API
2020-01-25 16:24:19 +02:00
7808 changed files with 300727 additions and 1336852 deletions

View File

@ -1,16 +0,0 @@
----------------------------------------------------------------------------------------------------------------------------------------------------
This entire section can be deleted if all items are checked.
*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..)
----------------------------------------------------------------------------------------------------------------------------------------------------
## Summary
Please describe your proposed PR and what it contains.
## Impact
Please describe impact of your PR and it's function.

View File

@ -15,9 +15,9 @@ 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 -P CMakeLists.txt 2>&1 | grep set\(srcs | cut -d'(' -f3 | sed 's/ )//' | sed 's/srcs //' | tr ' ;' '\n' | sort`
CMAKE_SRCS=`cmake --trace-expand -C CMakeLists.txt 2>&1 | grep COMPONENT_SRCS | sed 's/.\+COMPONENT_SRCS //' | sed 's/ )//' | tr ' ;' '\n' | sort`
if ! diff -u0 --label "Repo Files" --label "srcs" <(echo "$REPO_SRCS") <(echo "$CMAKE_SRCS"); then
if ! diff -u0 --label "Repo Files" --label "COMPONENT_SRCS" <(echo "$REPO_SRCS") <(echo "$CMAKE_SRCS"); then
echo "Source files in repo (-) and source files in CMakeLists.txt (+) don't match"
echo "Edit CMakeLists.txt as appropriate to add/remove source files from COMPONENT_SRCS"
exit 1

View File

@ -48,22 +48,16 @@ else
export ARDUINO_USR_PATH="$HOME/Arduino"
fi
# Updated as of Nov 3rd 2020
ARDUINO_IDE_URL="https://github.com/espressif/arduino-esp32/releases/download/1.0.4/arduino-nightly-"
# Currently not working
#ARDUINO_IDE_URL="https://www.arduino.cc/download.php?f=/arduino-nightly-"
if [ ! -d "$ARDUINO_IDE_PATH" ]; then
echo "Installing Arduino IDE on $OS_NAME ..."
echo "Downloading '$ARDUINO_IDE_URL$OS_NAME.$ARCHIVE_FORMAT' to 'arduino.$ARCHIVE_FORMAT' ..."
echo "Downloading 'arduino-nightly-$OS_NAME.$ARCHIVE_FORMAT' to 'arduino.$ARCHIVE_FORMAT' ..."
if [ "$OS_IS_LINUX" == "1" ]; then
wget -O "arduino.$ARCHIVE_FORMAT" "$ARDUINO_IDE_URL$OS_NAME.$ARCHIVE_FORMAT" > /dev/null 2>&1
wget -O "arduino.$ARCHIVE_FORMAT" "https://www.arduino.cc/download.php?f=/arduino-nightly-$OS_NAME.$ARCHIVE_FORMAT" > /dev/null 2>&1
echo "Extracting 'arduino.$ARCHIVE_FORMAT' ..."
tar xf "arduino.$ARCHIVE_FORMAT" > /dev/null
mv arduino-nightly "$ARDUINO_IDE_PATH"
else
curl -o "arduino.$ARCHIVE_FORMAT" -L "$ARDUINO_IDE_URL$OS_NAME.$ARCHIVE_FORMAT" > /dev/null 2>&1
curl -o "arduino.$ARCHIVE_FORMAT" -L "https://www.arduino.cc/download.php?f=/arduino-nightly-$OS_NAME.$ARCHIVE_FORMAT" > /dev/null 2>&1
echo "Extracting 'arduino.$ARCHIVE_FORMAT' ..."
unzip "arduino.$ARCHIVE_FORMAT" > /dev/null
if [ "$OS_IS_MACOS" == "1" ]; then
@ -98,8 +92,8 @@ function build_sketch(){ # build_sketch <fqbn> <path-to-ino> [extra-options]
win_opts="-prefs=runtime.tools.ctags.path=$ARDUINO_IDE_PATH/tools-builder/ctags/$ctags_version -prefs=runtime.tools.arduino-preprocessor.path=$ARDUINO_IDE_PATH/tools-builder/arduino-preprocessor/$preprocessor_version"
fi
#echo ""
#echo "Compiling '"$(basename "$sketch")"' ..."
echo ""
echo "Compiling '"$(basename "$sketch")"' ..."
mkdir -p "$ARDUINO_BUILD_DIR"
mkdir -p "$ARDUINO_CACHE_DIR"
$ARDUINO_IDE_PATH/arduino-builder -compile -logger=human -core-api-version=10810 \
@ -116,10 +110,9 @@ function build_sketch(){ # build_sketch <fqbn> <path-to-ino> [extra-options]
$win_opts $xtra_opts "$sketch"
}
function count_sketches() # count_sketches <examples-path> <target-mcu>
function count_sketches() # count_sketches <examples-path>
{
local examples="$1"
local target="$2"
rm -rf sketches.txt
if [ ! -d "$examples" ]; then
touch sketches.txt
@ -131,50 +124,49 @@ function count_sketches() # count_sketches <examples-path> <target-mcu>
local sketchdir=$(dirname $sketch)
local sketchdirname=$(basename $sketchdir)
local sketchname=$(basename $sketch)
if [[ "$sketchdirname.ino" != "$sketchname" ]]; then
if [[ "${sketchdirname}.ino" != "$sketchname" ]]; then
continue
elif [[ -f "$sketchdir/.skip.$target" ]]; then
fi;
if [[ -f "$sketchdir/.test.skip" ]]; then
continue
else
echo $sketch >> sketches.txt
sketchnum=$(($sketchnum + 1))
fi
echo $sketch >> sketches.txt
sketchnum=$(($sketchnum + 1))
done
return $sketchnum
}
function build_sketches() # build_sketches <fqbn> <target-mcu> <examples-path> <chunk> <total-chunks> [extra-options]
function build_sketches() # build_sketches <fqbn> <examples-path> <chunk> <total-chunks> [extra-options]
{
local fqbn=$1
local target="$2"
local examples=$3
local chunk_idex=$4
local chunks_num=$5
local xtra_opts=$6
local examples=$2
local chunk_idex=$3
local chunks_num=$4
local xtra_opts=$5
if [ "$#" -lt 3 ]; then
if [ "$#" -lt 2 ]; then
echo "ERROR: Illegal number of parameters"
echo "USAGE: build_sketches <fqbn> <target-mcu <examples-path> [<chunk> <total-chunks>] [extra-options]"
echo "USAGE: build_sketches <fqbn> <examples-path> [<chunk> <total-chunks>] [extra-options]"
return 1
fi
if [ "$#" -lt 5 ]; then
if [ "$#" -lt 4 ]; then
chunk_idex="0"
chunks_num="1"
xtra_opts=$4
xtra_opts=$3
fi
if [ "$chunks_num" -le 0 ]; then
echo "ERROR: Chunks count must be positive number"
return 1
fi
if [ "$chunk_idex" -ge "$chunks_num" ] && [ "$chunks_num" -ge 2 ]; then
if [ "$chunk_idex" -ge "$chunks_num" ]; then
echo "ERROR: Chunk index must be less than chunks count"
return 1
fi
set +e
count_sketches "$examples" "$target"
count_sketches "$examples"
local sketchcount=$?
set -e
local sketches=$(cat sketches.txt)
@ -186,27 +178,19 @@ function build_sketches() # build_sketches <fqbn> <target-mcu> <examples-path> <
chunk_size=$(( $chunk_size + 1 ))
fi
local start_index=0
local end_index=0
if [ "$chunk_idex" -ge "$chunks_num" ]; then
start_index=$chunk_idex
end_index=$sketchcount
else
start_index=$(( $chunk_idex * $chunk_size ))
if [ "$sketchcount" -le "$start_index" ]; then
echo "Skipping job"
return 0
fi
local start_index=$(( $chunk_idex * $chunk_size ))
if [ "$sketchcount" -le "$start_index" ]; then
echo "Skipping job"
return 0
fi
end_index=$(( $(( $chunk_idex + 1 )) * $chunk_size ))
if [ "$end_index" -gt "$sketchcount" ]; then
end_index=$sketchcount
fi
fi
local end_index=$(( $(( $chunk_idex + 1 )) * $chunk_size ))
if [ "$end_index" -gt "$sketchcount" ]; then
end_index=$sketchcount
fi
local start_num=$(( $start_index + 1 ))
echo "Found $sketchcount Sketches for target '$target'";
echo "Chunk Index : $chunk_idex"
echo "Found $sketchcount Sketches";
echo "Chunk Count : $chunks_num"
echo "Chunk Size : $chunk_size"
echo "Start Sketch: $start_num"
@ -218,7 +202,7 @@ function build_sketches() # build_sketches <fqbn> <target-mcu> <examples-path> <
local sketchdirname=$(basename $sketchdir)
local sketchname=$(basename $sketch)
if [ "${sketchdirname}.ino" != "$sketchname" ] \
|| [ -f "$sketchdir/.skip.$target" ]; then
|| [ -f "$sketchdir/.test.skip" ]; then
continue
fi
sketchnum=$(($sketchnum + 1))
@ -226,8 +210,6 @@ function build_sketches() # build_sketches <fqbn> <target-mcu> <examples-path> <
|| [ "$sketchnum" -gt "$end_index" ]; then
continue
fi
echo ""
echo "Building Sketch Index $(($sketchnum - 1)) - $sketchdirname"
build_sketch "$fqbn" "$sketch" "$xtra_opts"
local result=$?
if [ $result -ne 0 ]; then

View File

@ -1,69 +1,48 @@
#!/bin/bash
export PLATFORMIO_ESP32_PATH="$HOME/.platformio/packages/framework-arduinoespressif32"
PLATFORMIO_ESP32_URL="https://github.com/platformio/platform-espressif32.git#feature/arduino-idf-master"
XTENSA32_TOOLCHAIN_VERSION="8.4.0+2021r1"
XTENSA32S2_TOOLCHAIN_VERSION="8.4.0+2021r1"
RISCV_TOOLCHAIN_VERSION="8.4.0+2021r1"
ESPTOOLPY_VERSION="~1.30100.0"
ESPRESSIF_ORGANIZATION_NAME="espressif"
echo "Installing Python Wheel ..."
pip install wheel > /dev/null 2>&1
echo "Installing PlatformIO ..."
pip install -U https://github.com/platformio/platformio/archive/master.zip > /dev/null 2>&1
pip install -U https://github.com/platformio/platformio/archive/develop.zip > /dev/null 2>&1
echo "Installing Platform ESP32 ..."
python -m platformio platform install $PLATFORMIO_ESP32_URL > /dev/null 2>&1
python -m platformio platform install https://github.com/platformio/platform-espressif32.git#feature/stage > /dev/null 2>&1
echo "Replacing the package versions ..."
replace_script="import json; import os;"
replace_script+="fp=open(os.path.expanduser('~/.platformio/platforms/espressif32/platform.json'), 'r+');"
replace_script+="data=json.load(fp);"
# Use framework sources from the repository
replace_script+="data['packages']['framework-arduinoespressif32']['version'] = '*';"
replace_script+="del data['packages']['framework-arduinoespressif32']['owner'];"
# Use toolchain packages from the "espressif" organization
replace_script+="data['packages']['toolchain-xtensa-esp32']['owner']='$ESPRESSIF_ORGANIZATION_NAME';"
replace_script+="data['packages']['toolchain-xtensa-esp32s2']['owner']='$ESPRESSIF_ORGANIZATION_NAME';"
replace_script+="data['packages']['toolchain-riscv32-esp']['owner']='$ESPRESSIF_ORGANIZATION_NAME';"
# Update versions to use the upstream
replace_script+="data['packages']['toolchain-xtensa-esp32']['version']='$XTENSA32_TOOLCHAIN_VERSION';"
replace_script+="data['packages']['toolchain-xtensa-esp32s2']['version']='$XTENSA32S2_TOOLCHAIN_VERSION';"
replace_script+="data['packages']['toolchain-riscv32-esp']['version']='$RISCV_TOOLCHAIN_VERSION';"
# esptool.py may require an upstream version (for now platformio is the owner)
replace_script+="data['packages']['tool-esptoolpy']['version']='$ESPTOOLPY_VERSION';"
# Save results
replace_script+="fp.seek(0);fp.truncate();json.dump(data, fp, indent=2);fp.close()"
python -c "$replace_script"
echo "Replacing the framework version ..."
if [[ "$OSTYPE" == "darwin"* ]]; then
sed 's/https:\/\/github\.com\/espressif\/arduino-esp32\.git/*/' "$HOME/.platformio/platforms/espressif32/platform.json" > "platform.json"
mv -f "platform.json" "$HOME/.platformio/platforms/espressif32/platform.json"
else
sed -i 's/https:\/\/github\.com\/espressif\/arduino-esp32\.git/*/' "$HOME/.platformio/platforms/espressif32/platform.json"
fi
if [ "$GITHUB_REPOSITORY" == "espressif/arduino-esp32" ]; then
echo "Linking Core..."
ln -s $GITHUB_WORKSPACE "$PLATFORMIO_ESP32_PATH"
else
echo "Cloning Core Repository ..."
git clone --recursive https://github.com/espressif/arduino-esp32.git "$PLATFORMIO_ESP32_PATH" > /dev/null 2>&1
git clone https://github.com/espressif/arduino-esp32.git "$PLATFORMIO_ESP32_PATH" > /dev/null 2>&1
fi
echo "PlatformIO for ESP32 has been installed"
echo ""
function build_pio_sketch(){ # build_pio_sketch <board> <options> <path-to-ino>
if [ "$#" -lt 3 ]; then
function build_pio_sketch(){ # build_pio_sketch <board> <path-to-ino>
if [ "$#" -lt 2 ]; then
echo "ERROR: Illegal number of parameters"
echo "USAGE: build_pio_sketch <board> <options> <path-to-ino>"
echo "USAGE: build_pio_sketch <board> <path-to-ino>"
return 1
fi
local board="$1"
local options="$2"
local sketch="$3"
local sketch="$2"
local sketch_dir=$(dirname "$sketch")
echo ""
echo "Compiling '"$(basename "$sketch")"' ..."
python -m platformio ci --board "$board" "$sketch_dir" --project-option="$options"
python -m platformio ci --board "$board" "$sketch_dir" --project-option="board_build.partitions = huge_app.csv"
}
function count_sketches() # count_sketches <examples-path>
@ -92,21 +71,20 @@ function count_sketches() # count_sketches <examples-path>
return $sketchnum
}
function build_pio_sketches() # build_pio_sketches <board> <options> <examples-path> <chunk> <total-chunks>
function build_pio_sketches() # build_pio_sketches <board> <examples-path> <chunk> <total-chunks>
{
if [ "$#" -lt 3 ]; then
if [ "$#" -lt 2 ]; then
echo "ERROR: Illegal number of parameters"
echo "USAGE: build_pio_sketches <board> <options> <examples-path> [<chunk> <total-chunks>]"
echo "USAGE: build_pio_sketches <board> <examples-path> [<chunk> <total-chunks>]"
return 1
fi
local board=$1
local options="$2"
local examples=$3
local chunk_idex=$4
local chunks_num=$5
local examples=$2
local chunk_idex=$3
local chunks_num=$4
if [ "$#" -lt 5 ]; then
if [ "$#" -lt 4 ]; then
chunk_idex="0"
chunks_num="1"
fi
@ -165,7 +143,7 @@ function build_pio_sketches() # build_pio_sketches <board> <options> <examples-p
|| [ "$sketchnum" -gt "$end_index" ]; then
continue
fi
build_pio_sketch "$board" "$options" "$sketch"
build_pio_sketch "$board" "$sketch"
local result=$?
if [ $result -ne 0 ]; then
return $result

View File

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

View File

@ -24,7 +24,7 @@ BUILD_PIO=0
if [ "$#" -lt 2 ] || [ "$CHUNKS_CNT" -le 0 ]; then
CHUNK_INDEX=0
CHUNKS_CNT=1
elif [ "$CHUNK_INDEX" -gt "$CHUNKS_CNT" ] && [ "$CHUNKS_CNT" -ge 2 ]; then
elif [ "$CHUNK_INDEX" -gt "$CHUNKS_CNT" ]; then
CHUNK_INDEX=$CHUNKS_CNT
elif [ "$CHUNK_INDEX" -eq "$CHUNKS_CNT" ]; then
BUILD_PIO=1
@ -34,8 +34,7 @@ fi
#git -C "$GITHUB_WORKSPACE" submodule update --init --recursive > /dev/null 2>&1
if [ "$BUILD_PIO" -eq 0 ]; then
# ArduinoIDE ESP32 Test
TARGET="esp32"
# ArduinoIDE Test
FQBN="espressif:esp32:esp32:PSRAM=enabled,PartitionScheme=huge_app"
source ./.github/scripts/install-arduino-ide.sh
source ./.github/scripts/install-arduino-core-esp32.sh
@ -54,51 +53,16 @@ if [ "$BUILD_PIO" -eq 0 ]; then
if [ "$CHUNK_INDEX" -eq 0 ]; then
bash "$ARDUINO_ESP32_PATH/.github/scripts/check-cmakelists.sh"
fi
build_sketches "$FQBN" "$TARGET" "$ARDUINO_ESP32_PATH/libraries" "$CHUNK_INDEX" "$CHUNKS_CNT"
build_sketches "$FQBN" "$ARDUINO_ESP32_PATH/libraries" "$CHUNK_INDEX" "$CHUNKS_CNT"
fi
# ArduinoIDE ESP32S2 Test
TARGET="esp32s2"
FQBN="espressif:esp32:esp32s2:PSRAM=enabled,PartitionScheme=huge_app"
if [ "$OS_IS_WINDOWS" == "1" ]; then
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/WiFi/examples/WiFiClient/WiFiClient.ino" && \
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/WiFiClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino"
elif [ "$OS_IS_MACOS" == "1" ]; then
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/WiFi/examples/WiFiClient/WiFiClient.ino" && \
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/WiFiClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino"
else
build_sketches "$FQBN" "$TARGET" "$ARDUINO_ESP32_PATH/libraries" "$CHUNK_INDEX" "$CHUNKS_CNT"
fi
# ArduinoIDE ESP32C3 Test
TARGET="esp32c3"
FQBN="espressif:esp32:esp32c3:PartitionScheme=huge_app"
if [ "$OS_IS_WINDOWS" == "1" ]; then
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/WiFi/examples/WiFiClient/WiFiClient.ino" && \
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/WiFiClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino"
elif [ "$OS_IS_MACOS" == "1" ]; then
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/WiFi/examples/WiFiClient/WiFiClient.ino" && \
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/WiFiClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino"
else
build_sketches "$FQBN" "$TARGET" "$ARDUINO_ESP32_PATH/libraries" "$CHUNK_INDEX" "$CHUNKS_CNT"
fi
else
# PlatformIO Test
source ./.github/scripts/install-platformio-esp32.sh
# PlatformIO ESP32 Test
BOARD="esp32dev"
OPTIONS="board_build.partitions = huge_app.csv"
build_pio_sketch "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries/WiFi/examples/WiFiClient/WiFiClient.ino" && \
build_pio_sketch "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries/WiFiClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino" && \
build_pio_sketch "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries/BluetoothSerial/examples/SerialToSerialBT/SerialToSerialBT.ino" && \
build_pio_sketch "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries/BLE/examples/BLE_server/BLE_server.ino" && \
build_pio_sketch "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries/ESP32/examples/Camera/CameraWebServer/CameraWebServer.ino"
# PlatformIO ESP32 Test
# OPTIONS="board_build.mcu = esp32s2"
# build_pio_sketch "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries/WiFi/examples/WiFiClient/WiFiClient.ino" && \
# build_pio_sketch "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries/WiFiClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino"
python -m platformio ci --board "$BOARD" "$PLATFORMIO_ESP32_PATH/libraries/WiFi/examples/WiFiClient" --project-option="board_build.mcu = esp32s2" --project-option="board_build.partitions = huge_app.csv"
#build_pio_sketches "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries"
build_pio_sketch "$BOARD" "$PLATFORMIO_ESP32_PATH/libraries/WiFi/examples/WiFiClient/WiFiClient.ino" && \
build_pio_sketch "$BOARD" "$PLATFORMIO_ESP32_PATH/libraries/WiFiClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino" && \
build_pio_sketch "$BOARD" "$PLATFORMIO_ESP32_PATH/libraries/BluetoothSerial/examples/SerialToSerialBT/SerialToSerialBT.ino" && \
build_pio_sketch "$BOARD" "$PLATFORMIO_ESP32_PATH/libraries/BLE/examples/BLE_server/BLE_server.ino" && \
build_pio_sketch "$BOARD" "$PLATFORMIO_ESP32_PATH/libraries/ESP32/examples/Camera/CameraWebServer/CameraWebServer.ino"
#build_pio_sketches esp32dev "$PLATFORMIO_ESP32_PATH/libraries"
fi

View File

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

82
.github/stale.yml vendored
View File

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

View File

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

View File

@ -4,11 +4,9 @@ on:
push:
branches:
- master
- pages
paths:
- 'README.md'
- '.github/scripts/on-pages.sh'
- '.github/workflows/gh-pages.yml'
- 'docs/**'
jobs:

View File

@ -11,8 +11,6 @@ jobs:
steps:
- uses: actions/checkout@master
with:
fetch-depth: 0
- uses: actions/setup-python@v1
with:
python-version: '3.x'

View File

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

14
.gitignore vendored
View File

@ -1,12 +1,9 @@
tools/xtensa-esp32-elf
tools/xtensa-esp32s2-elf
tools/riscv32-esp-elf
tools/dist
tools/esptool
tools/esptool.exe
tools/mkspiffs
tools/mklittlefs
tools/mkfatfs.exe
tools/mkspiffs/mkspiffs
tools/mkspiffs/mkspiffs.exe
.DS_Store
#Ignore files built by Visual Studio/Visual Micro
@ -15,10 +12,3 @@ tools/mkfatfs.exe
.vs/
__vm/
*.vcxproj*
.vscode/
platform.sloeber.txt
boards.sloeber.txt
# Ignore docs build (Sphinx)
docs/build
docs/source/_build

View File

@ -1,27 +1,3 @@
# Check ESP-IDF version and error out if it is not in the supported range.
#
# Note for arduino-esp32 developers: to bypass the version check locally,
# set ARDUINO_SKIP_IDF_VERSION_CHECK environment variable to 1. For example:
# export ARDUINO_SKIP_IDF_VERSION_CHECK=1
# idf.py build
set(min_supported_idf_version "4.4.0")
set(max_supported_idf_version "4.4.99")
set(idf_version "${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}.${IDF_VERSION_PATCH}")
if ("${idf_version}" AND NOT "$ENV{ARDUINO_SKIP_IDF_VERSION_CHECK}")
if (idf_version VERSION_LESS min_supported_idf_version)
message(FATAL_ERROR "Arduino-esp32 can be used with ESP-IDF versions "
"between ${min_supported_idf_version} and ${max_supported_idf_version}, "
"but an older version is detected: ${idf_version}.")
endif()
if (idf_version VERSION_GREATER max_supported_idf_version)
message(FATAL_ERROR "Arduino-esp32 can be used with ESP-IDF versions "
"between ${min_supported_idf_version} and ${max_supported_idf_version}, "
"but a newer version is detected: ${idf_version}.")
endif()
endif()
set(CORE_SRCS
cores/esp32/base64.cpp
cores/esp32/cbuf.cpp
@ -31,7 +7,6 @@ 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
@ -40,7 +15,6 @@ set(CORE_SRCS
cores/esp32/esp32-hal-spi.c
cores/esp32/esp32-hal-time.c
cores/esp32/esp32-hal-timer.c
cores/esp32/esp32-hal-tinyusb.c
cores/esp32/esp32-hal-touch.c
cores/esp32/esp32-hal-uart.c
cores/esp32/esp32-hal-rmt.c
@ -57,12 +31,6 @@ 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
@ -73,26 +41,16 @@ set(LIBRARY_SRCS
libraries/ArduinoOTA/src/ArduinoOTA.cpp
libraries/AsyncUDP/src/AsyncUDP.cpp
libraries/BluetoothSerial/src/BluetoothSerial.cpp
libraries/BluetoothSerial/src/BTAddress.cpp
libraries/BluetoothSerial/src/BTAdvertisedDeviceSet.cpp
libraries/BluetoothSerial/src/BTScanResultsSet.cpp
libraries/DNSServer/src/DNSServer.cpp
libraries/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
libraries/HTTPClient/src/HTTPClient.cpp
libraries/HTTPUpdate/src/HTTPUpdate.cpp
libraries/LittleFS/src/LittleFS.cpp
libraries/NetBIOS/src/NetBIOS.cpp
libraries/Preferences/src/Preferences.cpp
libraries/RainMaker/src/RMaker.cpp
libraries/RainMaker/src/RMakerNode.cpp
libraries/RainMaker/src/RMakerParam.cpp
libraries/RainMaker/src/RMakerDevice.cpp
libraries/RainMaker/src/RMakerType.cpp
libraries/SD_MMC/src/SD_MMC.cpp
libraries/SD/src/SD.cpp
libraries/SD/src/sd_diskio.cpp
@ -102,20 +60,12 @@ set(LIBRARY_SRCS
libraries/SPI/src/SPI.cpp
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
@ -125,7 +75,6 @@ set(LIBRARY_SRCS
libraries/WiFi/src/WiFiServer.cpp
libraries/WiFi/src/WiFiSTA.cpp
libraries/WiFi/src/WiFiUdp.cpp
libraries/WiFiProv/src/WiFiProv.cpp
libraries/Wire/src/Wire.cpp
)
@ -161,9 +110,10 @@ set(BLE_SRCS
libraries/BLE/src/GeneralUtils.cpp
)
set(COMPONENT_SRCS ${CORE_SRCS} ${LIBRARY_SRCS} ${BLE_SRCS})
set(includedirs
variants/${IDF_TARGET}/
set(COMPONENT_ADD_INCLUDEDIRS
variants/esp32/
cores/esp32/
libraries/ArduinoOTA/src
libraries/AsyncUDP/src
@ -177,10 +127,8 @@ set(includedirs
libraries/FS/src
libraries/HTTPClient/src
libraries/HTTPUpdate/src
libraries/LittleFS/src
libraries/NetBIOS/src
libraries/Preferences/src
libraries/RainMaker/src
libraries/SD_MMC/src
libraries/SD/src
libraries/SimpleBLE/src
@ -188,61 +136,15 @@ set(includedirs
libraries/SPI/src
libraries/Ticker/src
libraries/Update/src
libraries/USB/src
libraries/WebServer/src
libraries/WiFiClientSecure/src
libraries/WiFi/src
libraries/WiFiProv/src
libraries/Wire/src
)
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 esp_hid)
set(COMPONENT_PRIV_INCLUDEDIRS cores/esp32/libb64)
idf_component_register(INCLUDE_DIRS ${includedirs} PRIV_INCLUDE_DIRS ${priv_includes} SRCS ${srcs} REQUIRES ${requires} PRIV_REQUIRES ${priv_requires})
set(COMPONENT_REQUIRES spi_flash mbedtls mdns esp_adc_cal)
set(COMPONENT_PRIV_REQUIRES fatfs nvs_flash app_update spiffs bootloader_support openssl bt)
string(TOUPPER ${CONFIG_IDF_TARGET} idf_target_caps)
target_compile_options(${COMPONENT_TARGET} PUBLIC
-DARDUINO=10812
-DARDUINO_${idf_target_caps}_DEV
-DARDUINO_ARCH_ESP32
-DARDUINO_BOARD="${idf_target_caps}_DEV"
-DARDUINO_VARIANT="${CONFIG_IDF_TARGET}"
-DESP32)
if(CONFIG_AUTOSTART_ARDUINO)
# in autostart mode, arduino-esp32 contains app_main() function and needs to
# reference setup() and loop() in the main component. If we add main
# component to priv_requires then we create a large circular dependency
# (arduino-esp32 -> main -> arduino-esp32) and can get linker errors, so
# instead we add setup() and loop() to the undefined symbols list so the
# linker will always include them.
#
# (As they are C++ symbol, we need to add the C++ mangled names.)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u _Z5setupv -u _Z4loopv")
endif()
# This function adds a dependency on the given component if the component is included into the build.
function(maybe_add_component component_name)
idf_build_get_property(components BUILD_COMPONENTS)
if (${component_name} IN_LIST components)
idf_component_get_property(lib_name ${component_name} COMPONENT_LIB)
target_link_libraries(${COMPONENT_LIB} PUBLIC ${lib_name})
endif()
endfunction()
if(IDF_TARGET MATCHES "esp32" AND CONFIG_ESP_RMAKER_TASK_STACK)
maybe_add_component(esp_rainmaker)
maybe_add_component(qrcode)
endif()
if(IDF_TARGET MATCHES "esp32s2|esp32s3" AND CONFIG_TINYUSB_ENABLED)
maybe_add_component(arduino_tinyusb)
endif()
if(NOT CONFIG_ARDUINO_SELECTIVE_COMPILATION OR CONFIG_ARDUINO_SELECTIVE_ArduinoOTA)
maybe_add_component(esp_https_ota)
endif()
if(NOT CONFIG_ARDUINO_SELECTIVE_COMPILATION OR CONFIG_ARDUINO_SELECTIVE_LITTLEFS)
maybe_add_component(esp_littlefs)
endif()
register_component()

View File

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

View File

@ -5,7 +5,7 @@ config ENABLE_ARDUINO_DEPENDS
select LWIP_SO_RCVBUF
select ETHERNET
select WIFI_ENABLED
select ESP32_PHY_CALIBRATION_AND_DATA_STORAGE if IDF_TARGET_ESP32
select ESP32_PHY_CALIBRATION_AND_DATA_STORAGE
select MEMMAP_SMP
default "y"
@ -40,12 +40,6 @@ config ARDUINO_RUNNING_CORE
default 1 if ARDUINO_RUN_CORE1
default -1 if ARDUINO_RUN_NO_AFFINITY
config ARDUINO_LOOP_STACK_SIZE
int "Loop thread stack size"
default 8192
help
Amount of stack available for the Arduino task.
choice ARDUINO_EVENT_RUNNING_CORE
bool "Core on which Arduino's event handler is running"
default ARDUINO_EVENT_RUN_CORE1
@ -82,27 +76,12 @@ choice ARDUINO_UDP_RUNNING_CORE
endchoice
config ARDUINO_UDP_TASK_PRIORITY
int "Priority of the UDP task"
default 3
help
Select at what priority you want the UDP task to run.
config ARDUINO_UDP_RUNNING_CORE
int
default 0 if ARDUINO_UDP_RUN_CORE0
default 1 if ARDUINO_UDP_RUN_CORE1
default -1 if ARDUINO_UDP_RUN_NO_AFFINITY
config ARDUINO_ISR_IRAM
bool "Run interrupts in IRAM"
default "n"
help
Enabling this option will Attach all interrupts with the IRAm flag.
It will also make some HAL function, like, digitalRead/Write and more
be loaded into IRAM for access inside ISRs.
Beware that this is a very dangerous setting. Enable it only if you
are fully aware of the consequences.
config DISABLE_HAL_LOCKS
bool "Disable mutex locks for HAL"
@ -271,12 +250,6 @@ config ARDUINO_SELECTIVE_HTTPClient
select ARDUINO_SELECTIVE_WiFiClientSecure
default y
config ARDUINO_SELECTIVE_LITTLEFS
bool "Enable LITTLEFS"
depends on ARDUINO_SELECTIVE_COMPILATION
select ARDUINO_SELECTIVE_FS
default y
config ARDUINO_SELECTIVE_NetBIOS
bool "Enable NetBIOS"
depends on ARDUINO_SELECTIVE_COMPILATION
@ -343,12 +316,6 @@ config ARDUINO_SELECTIVE_WiFiClientSecure
select ARDUINO_SELECTIVE_WiFi
default y
config ARDUINO_SELECTIVE_WiFiProv
bool "Enable WiFiProv"
depends on ARDUINO_SELECTIVE_COMPILATION
select ARDUINO_SELECTIVE_WiFi
default y
config ARDUINO_SELECTIVE_Wire
bool "Enable Wire"
depends on ARDUINO_SELECTIVE_COMPILATION

View File

@ -1,43 +1,47 @@
# Arduino core for the ESP32, ESP32-S2 and ESP32-C3
![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)
# Arduino core for the ESP32
[![Build Status](https://travis-ci.org/espressif/arduino-esp32.svg?branch=master)](https://travis-ci.org/espressif/arduino-esp32) ![](https://github.com/espressif/arduino-esp32/workflows/ESP32%20Arduino%20CI/badge.svg)
### 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
- [Development Status](#development-status)
- [Installation Instructions](#installation-instructions)
- [Decoding Exceptions](#decoding-exceptions)
- [Issue/Bug report template](#issuebug-report-template)
- [ESP32Dev Board PINMAP](#esp32dev-board-pinmap)
### Development Status
[Latest stable release ![Release Version](https://img.shields.io/github/release/espressif/arduino-esp32.svg?style=plastic) ![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)
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 ![Development Version](https://img.shields.io/github/release/espressif/arduino-esp32/all.svg?style=plastic) ![Development 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)
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
You can use [Arduino-ESP32 Online Documentation](https://docs.espressif.com/projects/arduino-esp32/en/latest/) to get all information about this project.
* [Getting Started](https://docs.espressif.com/projects/arduino-esp32/en/latest/getting_started.html)
* [Installing (Windows, Linux and macOS)](https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html)
* [Libraries](https://docs.espressif.com/projects/arduino-esp32/en/latest/libraries.html)
* [ESP-IDF as Component](https://docs.espressif.com/projects/arduino-esp32/en/latest/esp-idf_component.html)
* [FAQ](https://docs.espressif.com/projects/arduino-esp32/en/latest/faq.html)
* [Troubleshooting](https://docs.espressif.com/projects/arduino-esp32/en/latest/troubleshooting.html)
### Installation Instructions
- Using Arduino IDE Boards Manager (preferred)
+ [Instructions for Boards Manager](docs/arduino-ide/boards_manager.md)
- Using Arduino IDE with the development repository
+ [Instructions for Windows](docs/arduino-ide/windows.md)
+ [Instructions for Mac](docs/arduino-ide/mac.md)
+ [Instructions for Debian/Ubuntu Linux](docs/arduino-ide/debian_ubuntu.md)
+ [Instructions for Fedora](docs/arduino-ide/fedora.md)
+ [Instructions for openSUSE](docs/arduino-ide/opensuse.md)
- [Using PlatformIO](docs/platformio.md)
- [Building with make](docs/make.md)
- [Using as ESP-IDF component](docs/esp-idf_component.md)
- [Using OTAWebUpdater](docs/OTAWebUpdate/OTAWebUpdate.md)
### 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 [Type: For reference](https://github.com/espressif/arduino-esp32/issues?q=is%3Aissue+label%3A%22Type%3A+For+reference%22+).
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).
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](docs/ISSUE_TEMPLATE.md) while reporting any issue.
### Contributing
### ESP32Dev Board PINMAP
We welcome contributions to the Arduino ESP32 project!
![Pin Functions](docs/esp32_pinmap.png)
See [contributing](https://docs.espressif.com/projects/arduino-esp32/en/latest/contributing.html) in the documentation for more information on how to contribute to the project.
### Tip
Sometimes to program ESP32 via serial you must keep GPIO0 LOW during the programming process

6130
boards.txt

File diff suppressed because it is too large Load Diff

View File

@ -29,7 +29,6 @@
#include <string.h>
#include <inttypes.h>
#include "esp_arduino_version.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
@ -79,7 +78,7 @@
#define interrupts() sei()
#define noInterrupts() cli()
#define clockCyclesPerMicrosecond() ( (long int)getCpuFrequencyMhz() )
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )
#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() )
@ -89,7 +88,7 @@
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
#define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet(value, bit) : bitClear(value, bit))
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
// avr-libc defines _NOP() since 1.6.2
#ifndef _NOP
@ -99,23 +98,13 @@
#define bit(b) (1UL << (b))
#define _BV(b) (1UL << (b))
#define digitalPinToTimer(pin) (0)
#define analogInPinToBit(P) (P)
#if SOC_GPIO_PIN_COUNT <= 32
#define digitalPinToPort(pin) (0)
#define digitalPinToBitMask(pin) (1UL << (pin))
#define portOutputRegister(port) ((volatile uint32_t*)GPIO_OUT_REG)
#define portInputRegister(port) ((volatile uint32_t*)GPIO_IN_REG)
#define portModeRegister(port) ((volatile uint32_t*)GPIO_ENABLE_REG)
#elif SOC_GPIO_PIN_COUNT <= 64
#define digitalPinToPort(pin) (((pin)>31)?1:0)
#define digitalPinToBitMask(pin) (1UL << (((pin)>31)?((pin)-32):(pin)))
#define digitalPinToTimer(pin) (0)
#define analogInPinToBit(P) (P)
#define portOutputRegister(port) ((volatile uint32_t*)((port)?GPIO_OUT1_REG:GPIO_OUT_REG))
#define portInputRegister(port) ((volatile uint32_t*)((port)?GPIO_IN1_REG:GPIO_IN_REG))
#define portModeRegister(port) ((volatile uint32_t*)((port)?GPIO_ENABLE1_REG:GPIO_ENABLE_REG))
#else
#error SOC_GPIO_PIN_COUNT > 64 not implemented
#endif
#define NOT_A_PIN -1
#define NOT_A_PORT -1
@ -126,10 +115,10 @@ typedef bool boolean;
typedef uint8_t byte;
typedef unsigned int word;
#ifdef __cplusplus
void setup(void);
void loop(void);
#ifdef __cplusplus
long random(long, long);
#endif
void randomSeed(unsigned long);
@ -175,7 +164,7 @@ using std::min;
using ::round;
uint16_t makeWord(uint16_t w);
uint16_t makeWord(uint8_t h, uint8_t l);
uint16_t makeWord(byte h, byte l);
#define word(...) makeWord(__VA_ARGS__)

View File

@ -23,6 +23,7 @@
#include "esp_spi_flash.h"
#include <memory>
#include <soc/soc.h>
#include <soc/efuse_reg.h>
#include <esp_partition.h>
extern "C" {
#include "esp_ota_ops.h"
@ -34,21 +35,11 @@ extern "C" {
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
#include "esp32/rom/spi_flash.h"
#include "soc/efuse_reg.h"
#define ESP_FLASH_IMAGE_BASE 0x1000 // Flash offset containing flash size and spi mode
#elif CONFIG_IDF_TARGET_ESP32S2
#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"
#define ESP_FLASH_IMAGE_BASE 0x0000 // Esp32c3 is located at 0x0000
#else
#error Target CONFIG_IDF_TARGET is not supported
#endif
#else // ESP32 Before IDF 4.0
#include "rom/spi_flash.h"
#define ESP_FLASH_IMAGE_BASE 0x1000
#endif
/**
@ -140,36 +131,24 @@ uint32_t EspClass::getMaxAllocHeap(void)
uint32_t EspClass::getPsramSize(void)
{
if(psramFound()){
multi_heap_info_t info;
heap_caps_get_info(&info, MALLOC_CAP_SPIRAM);
return info.total_free_bytes + info.total_allocated_bytes;
}
return 0;
multi_heap_info_t info;
heap_caps_get_info(&info, MALLOC_CAP_SPIRAM);
return info.total_free_bytes + info.total_allocated_bytes;
}
uint32_t EspClass::getFreePsram(void)
{
if(psramFound()){
return heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
}
return 0;
return heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
}
uint32_t EspClass::getMinFreePsram(void)
{
if(psramFound()){
return heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM);
}
return 0;
return heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM);
}
uint32_t EspClass::getMaxAllocPsram(void)
{
if(psramFound()){
return heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM);
}
return 0;
return heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM);
}
static uint32_t sketchSize(sketchSize_t response) {
@ -249,53 +228,6 @@ uint8_t EspClass::getChipRevision(void)
return chip_info.revision;
}
const char * EspClass::getChipModel(void)
{
#if CONFIG_IDF_TARGET_ESP32
uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_PKG);
uint32_t pkg_ver = chip_ver & 0x7;
switch (pkg_ver) {
case EFUSE_RD_CHIP_VER_PKG_ESP32D0WDQ6 :
return "ESP32-D0WDQ6";
case EFUSE_RD_CHIP_VER_PKG_ESP32D0WDQ5 :
return "ESP32-D0WDQ5";
case EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5 :
return "ESP32-D2WDQ5";
case EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2 :
return "ESP32-PICO-D2";
case EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4 :
return "ESP32-PICO-D4";
case EFUSE_RD_CHIP_VER_PKG_ESP32PICOV302 :
return "ESP32-PICO-V3-02";
default:
return "Unknown";
}
#elif CONFIG_IDF_TARGET_ESP32S2
uint32_t pkg_ver = REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_3_REG, EFUSE_PKG_VERSION);
switch (pkg_ver) {
case 0:
return "ESP32-S2";
case 1:
return "ESP32-S2FH16";
case 2:
return "ESP32-S2FH32";
default:
return "ESP32-S2 (Unknown)";
}
#elif CONFIG_IDF_TARGET_ESP32S3
return "ESP32-S3";
#elif CONFIG_IDF_TARGET_ESP32C3
return "ESP32-C3";
#endif
}
uint8_t EspClass::getChipCores(void)
{
esp_chip_info_t chip_info;
esp_chip_info(&chip_info);
return chip_info.cores;
}
const char * EspClass::getSdkVersion(void)
{
return esp_get_idf_version();
@ -304,7 +236,7 @@ const char * EspClass::getSdkVersion(void)
uint32_t EspClass::getFlashChipSize(void)
{
esp_image_header_t fhdr;
if(flashRead(ESP_FLASH_IMAGE_BASE, (uint32_t*)&fhdr, sizeof(esp_image_header_t)) && fhdr.magic != ESP_IMAGE_HEADER_MAGIC) {
if(flashRead(0x1000, (uint32_t*)&fhdr, sizeof(esp_image_header_t)) && fhdr.magic != ESP_IMAGE_HEADER_MAGIC) {
return 0;
}
return magicFlashChipSize(fhdr.spi_size);
@ -313,7 +245,7 @@ uint32_t EspClass::getFlashChipSize(void)
uint32_t EspClass::getFlashChipSpeed(void)
{
esp_image_header_t fhdr;
if(flashRead(ESP_FLASH_IMAGE_BASE, (uint32_t*)&fhdr, sizeof(esp_image_header_t)) && fhdr.magic != ESP_IMAGE_HEADER_MAGIC) {
if(flashRead(0x1000, (uint32_t*)&fhdr, sizeof(esp_image_header_t)) && fhdr.magic != ESP_IMAGE_HEADER_MAGIC) {
return 0;
}
return magicFlashChipSpeed(fhdr.spi_speed);
@ -322,7 +254,7 @@ uint32_t EspClass::getFlashChipSpeed(void)
FlashMode_t EspClass::getFlashChipMode(void)
{
esp_image_header_t fhdr;
if(flashRead(ESP_FLASH_IMAGE_BASE, (uint32_t*)&fhdr, sizeof(esp_image_header_t)) && fhdr.magic != ESP_IMAGE_HEADER_MAGIC) {
if(flashRead(0x1000, (uint32_t*)&fhdr, sizeof(esp_image_header_t)) && fhdr.magic != ESP_IMAGE_HEADER_MAGIC) {
return FM_UNKNOWN;
}
return magicFlashChipMode(fhdr.spi_mode);
@ -387,20 +319,6 @@ bool EspClass::flashRead(uint32_t offset, uint32_t *data, size_t size)
return spi_flash_read(offset, (uint32_t*) data, size) == ESP_OK;
}
bool EspClass::partitionEraseRange(const esp_partition_t *partition, uint32_t offset, size_t size)
{
return esp_partition_erase_range(partition, offset, size) == ESP_OK;
}
bool EspClass::partitionWrite(const esp_partition_t *partition, uint32_t offset, uint32_t *data, size_t size)
{
return esp_partition_write(partition, offset, data, size) == ESP_OK;
}
bool EspClass::partitionRead(const esp_partition_t *partition, uint32_t offset, uint32_t *data, size_t size)
{
return esp_partition_read(partition, offset, data, size) == ESP_OK;
}
uint64_t EspClass::getEfuseMac(void)
{

View File

@ -21,8 +21,6 @@
#define ESP_H
#include <Arduino.h>
#include <esp_partition.h>
#include <hal/cpu_hal.h>
/**
* AVR macros for WDT managment
@ -77,8 +75,6 @@ public:
uint32_t getMaxAllocPsram();
uint8_t getChipRevision();
const char * getChipModel();
uint8_t getChipCores();
uint32_t getCpuFreqMHz(){ return getCpuFrequencyMhz(); }
inline uint32_t getCycleCount() __attribute__((always_inline));
const char * getSdkVersion();
@ -101,17 +97,15 @@ public:
bool flashWrite(uint32_t offset, uint32_t *data, size_t size);
bool flashRead(uint32_t offset, uint32_t *data, size_t size);
bool partitionEraseRange(const esp_partition_t *partition, uint32_t offset, size_t size);
bool partitionWrite(const esp_partition_t *partition, uint32_t offset, uint32_t *data, size_t size);
bool partitionRead(const esp_partition_t *partition, uint32_t offset, uint32_t *data, size_t size);
uint64_t getEfuseMac();
};
uint32_t ARDUINO_ISR_ATTR EspClass::getCycleCount()
uint32_t IRAM_ATTR EspClass::getCycleCount()
{
return cpu_hal_get_cycle_count();
uint32_t ccount;
__asm__ __volatile__("esync; rsr %0,ccount":"=a" (ccount));
return ccount;
}
extern EspClass ESP;

View File

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

View File

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

View File

@ -16,7 +16,7 @@ extern "C"
extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type, bool functional);
}
void ARDUINO_ISR_ATTR interruptFunctional(void* arg)
void IRAM_ATTR interruptFunctional(void* arg)
{
InterruptArgStructure* localArg = (InterruptArgStructure*)arg;
if (localArg->interruptFunction)

View File

@ -1,388 +0,0 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "USB.h"
#if CONFIG_IDF_TARGET_ESP32C3
#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 */

View File

@ -1,107 +0,0 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "sdkconfig.h"
#if CONFIG_IDF_TARGET_ESP32C3
#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,141 +5,56 @@
#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
#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_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);
#endif
#if SOC_UART_NUM > 2
HardwareSerial Serial2(2);
#endif
void serialEventRun(void)
HardwareSerial::HardwareSerial(int uart_nr) : _uart_nr(uart_nr), _uart(NULL) {}
void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert, unsigned long timeout_ms)
{
#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC
if(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), _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 >= SOC_UART_NUM) {
log_e("Serial number is invalid, please use numers from 0 to %u", SOC_UART_NUM - 1);
if(0 > _uart_nr || _uart_nr > 2) {
log_e("Serial number is invalid, please use 0, 1 or 2");
return;
}
if(_uart) {
// in this case it is a begin() over a previous begin() - maybe to change baud rate
// thus do not disable debug output
end(false);
end();
}
if(_uart_nr == 0 && rxPin < 0 && txPin < 0) {
rxPin = SOC_RX0;
txPin = SOC_TX0;
rxPin = 3;
txPin = 1;
}
#if SOC_UART_NUM > 1
if(_uart_nr == 1 && rxPin < 0 && txPin < 0) {
rxPin = RX1;
txPin = TX1;
}
#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, _rxBufferSize, invert, rxfifo_full_thrhd);
if (!baud) {
// using baud rate as zero, forces it to try to detect the current baud rate in place
_uart = uartBegin(_uart_nr, baud ? baud : 9600, config, rxPin, txPin, 256, invert);
if(!baud) {
uartStartDetectBaudrate(_uart);
time_t startMillis = millis();
unsigned long detectedBaudRate = 0;
@ -147,11 +62,11 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
yield();
}
end(false);
end();
if(detectedBaudRate) {
delay(100); // Give some time...
_uart = uartBegin(_uart_nr, detectedBaudRate, config, rxPin, txPin, _rxBufferSize, invert, rxfifo_full_thrhd);
_uart = uartBegin(_uart_nr, detectedBaudRate, config, rxPin, txPin, 256, invert);
} 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;
@ -164,16 +79,19 @@ void HardwareSerial::updateBaudRate(unsigned long baud)
uartSetBaudRate(_uart, baud);
}
void HardwareSerial::end(bool turnOffDebug)
void HardwareSerial::end()
{
if(turnOffDebug && uartGetDebug() == _uart_nr) {
if(uartGetDebug() == _uart_nr) {
uartSetDebug(0);
}
delay(10);
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) {
@ -183,7 +101,7 @@ void HardwareSerial::setDebugOutput(bool en)
uartSetDebug(_uart);
} else {
if(uartGetDebug() == _uart_nr) {
uartSetDebug(NULL);
uartSetDebug(0);
}
}
}
@ -259,31 +177,5 @@ uint32_t HardwareSerial::baudRate()
}
HardwareSerial::operator bool() const
{
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;
return true;
}

View File

@ -49,16 +49,14 @@
#include "Stream.h"
#include "esp32-hal.h"
#include "soc/soc_caps.h"
#include "HWCDC.h"
class HardwareSerial: public Stream
{
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(bool turnOffDebug = true);
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);
void end();
void updateBaudRate(unsigned long baud);
int available(void);
int availableForWrite(void);
@ -100,39 +98,20 @@ 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;
size_t _rxBufferSize;
};
extern void serialEventRun(void) __attribute__((weak));
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
#ifndef ARDUINO_USB_CDC_ON_BOOT
#define ARDUINO_USB_CDC_ON_BOOT 0
#endif
#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;
#endif
#if SOC_UART_NUM > 2
extern HardwareSerial Serial2;
#endif
#endif
#endif // HardwareSerial_h

View File

@ -26,10 +26,6 @@
#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

View File

@ -110,37 +110,24 @@ size_t Print::print(unsigned int n, int base)
}
size_t Print::print(long n, int base)
{
int t = 0;
if (base == 10 && n < 0) {
t = print('-');
n = -n;
}
return printNumber(static_cast<unsigned long>(n), base) + t;
}
size_t Print::print(unsigned long n, int base)
{
if(base == 0) {
return write(n);
} else if(base == 10) {
if(n < 0) {
int t = print('-');
n = -n;
return printNumber(n, 10) + t;
}
return printNumber(n, 10);
} else {
return printNumber(n, base);
}
}
size_t Print::print(long long n, int base)
size_t Print::print(unsigned long n, int base)
{
int t = 0;
if (base == 10 && n < 0) {
t = print('-');
n = -n;
}
return printNumber(static_cast<unsigned long long>(n), base) + t;
}
size_t Print::print(unsigned long long n, int base)
{
if (base == 0) {
if(base == 0) {
return write(n);
} else {
return printNumber(n, base);
@ -239,20 +226,6 @@ size_t Print::println(unsigned long num, int base)
return n;
}
size_t Print::println(long long num, int base)
{
size_t n = print(num, base);
n += println();
return n;
}
size_t Print::println(unsigned long long num, int base)
{
size_t n = print(num, base);
n += println();
return n;
}
size_t Print::println(double num, int digits)
{
size_t n = print(num, digits);
@ -278,7 +251,7 @@ size_t Print::println(struct tm * timeinfo, const char * format)
size_t Print::printNumber(unsigned long n, uint8_t base)
{
char buf[8 * sizeof(n) + 1]; // Assumes 8-bit chars plus zero byte.
char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
char *str = &buf[sizeof(buf) - 1];
*str = '\0';
@ -289,34 +262,11 @@ size_t Print::printNumber(unsigned long n, uint8_t base)
}
do {
char c = n % base;
n /= base;
*--str = c < 10 ? c + '0' : c + 'A' - 10;
} while (n);
return write(str);
}
size_t Print::printNumber(unsigned long long n, uint8_t base)
{
char buf[8 * sizeof(n) + 1]; // Assumes 8-bit chars plus zero byte.
char* str = &buf[sizeof(buf) - 1];
*str = '\0';
// prevent crash if called with base == 1
if (base < 2) {
base = 10;
}
do {
auto m = n;
unsigned long m = n;
n /= base;
char c = m - base * n;
*--str = c < 10 ? c + '0' : c + 'A' - 10;
} while (n);
} while(n);
return write(str);
}

View File

@ -36,7 +36,6 @@ class Print
private:
int write_error;
size_t printNumber(unsigned long, uint8_t);
size_t printNumber(unsigned long long, uint8_t);
size_t printFloat(double, uint8_t);
protected:
void setWriteError(int err = 1)
@ -73,11 +72,6 @@ public:
}
size_t printf(const char * format, ...) __attribute__ ((format (printf, 2, 3)));
// add availableForWrite to make compatible with Arduino Print.h
// default to zero, meaning "a single write may block"
// should be overriden by subclasses with buffering
virtual int availableForWrite() { return 0; }
size_t print(const __FlashStringHelper *);
size_t print(const String &);
size_t print(const char[]);
@ -87,8 +81,6 @@ public:
size_t print(unsigned int, int = DEC);
size_t print(long, int = DEC);
size_t print(unsigned long, int = DEC);
size_t print(long long, int = DEC);
size_t print(unsigned long long, int = DEC);
size_t print(double, int = 2);
size_t print(const Printable&);
size_t print(struct tm * timeinfo, const char * format = NULL);
@ -102,8 +94,6 @@ public:
size_t println(unsigned int, int = DEC);
size_t println(long, int = DEC);
size_t println(unsigned long, int = DEC);
size_t println(long long, int = DEC);
size_t println(unsigned long long, int = DEC);
size_t println(double, int = 2);
size_t println(const Printable&);
size_t println(struct tm * timeinfo, const char * format = NULL);

View File

@ -87,22 +87,22 @@ unsigned long Stream::getTimeout(void) {
}
// find returns true if the target string is found
bool Stream::find(const char *target)
bool Stream::find(const char *target)
{
return findUntil(target, strlen(target), NULL, 0);
return findUntil(target, (char*) "");
}
// reads data from the stream until the target string of given length is found
// returns true if target string is found, false if timed out
bool Stream::find(const char *target, size_t length)
{
return findUntil(target, length, NULL, 0);
return findUntil(target, length, NULL, 0);
}
// as find but search ends if the terminator string is found
bool Stream::findUntil(const char *target, const char *terminator)
bool Stream::findUntil(const char *target, const char *terminator)
{
return findUntil(target, strlen(target), terminator, strlen(terminator));
return findUntil(target, strlen(target), terminator, strlen(terminator));
}
// reads data from the stream until the target string of the given length is found
@ -110,78 +110,35 @@ bool Stream::findUntil(const char *target, const char *terminator)
// returns true if target string is found, false if terminated or timed out
bool Stream::findUntil(const char *target, size_t targetLen, const char *terminator, size_t termLen)
{
if (terminator == NULL) {
MultiTarget t[1] = {{target, targetLen, 0}};
return findMulti(t, 1) == 0 ? true : false;
} else {
MultiTarget t[2] = {{target, targetLen, 0}, {terminator, termLen, 0}};
return findMulti(t, 2) == 0 ? true : false;
}
}
size_t index = 0; // maximum target string length is 64k bytes!
size_t termIndex = 0;
int c;
int Stream::findMulti( struct Stream::MultiTarget *targets, int tCount) {
// any zero length target string automatically matches and would make
// a mess of the rest of the algorithm.
for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
if (t->len <= 0)
return t - targets;
}
while (1) {
int c = timedRead();
if (c < 0)
return -1;
for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
// the simple case is if we match, deal with that first.
if (c == t->str[t->index]) {
if (++t->index == t->len)
return t - targets;
else
continue;
}
// if not we need to walk back and see if we could have matched further
// down the stream (ie '1112' doesn't match the first position in '11112'
// but it will match the second position so we can't just reset the current
// index to 0 when we find a mismatch.
if (t->index == 0)
continue;
int origIndex = t->index;
do {
--t->index;
// first check if current char works against the new current index
if (c != t->str[t->index])
continue;
// if it's the only char then we're good, nothing more to check
if (t->index == 0) {
t->index++;
break;
}
// otherwise we need to check the rest of the found string
int diff = origIndex - t->index;
size_t i;
for (i = 0; i < t->index; ++i) {
if (t->str[i] != t->str[i + diff])
break;
}
// if we successfully got through the previous loop then our current
// index is good.
if (i == t->index) {
t->index++;
break;
}
// otherwise we just try the next index
} while (t->index);
if(*target == 0) {
return true; // return true if target is a null string
}
}
// unreachable
return -1;
while((c = timedRead()) > 0) {
if(c != target[index]) {
index = 0; // reset index if any char does not match
}
if(c == target[index]) {
//////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1);
if(++index >= targetLen) { // return true if all chars in the target match
return true;
}
}
if(termLen > 0 && c == terminator[termIndex]) {
if(++termIndex >= termLen) {
return false; // return false if terminate string found before target string
}
} else {
termIndex = 0;
}
}
return false;
}
// returns the first valid (long) integer value from the current position.
@ -256,7 +213,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.1f;
fraction *= 0.1;
}
}
read(); // consume the character we got with peek

View File

@ -60,7 +60,6 @@ public:
void setTimeout(unsigned long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second
unsigned long getTimeout(void);
bool find(const char *target); // reads data from the stream until the target string is found
bool find(uint8_t *target)
{
@ -124,17 +123,6 @@ protected:
// this allows format characters (typically commas) in values to be ignored
float parseFloat(char skipChar); // as above but the given skipChar is ignored
struct MultiTarget {
const char *str; // string you're searching for
size_t len; // length of string you're searching for
size_t index; // index used by the search routine.
};
// This allows you to search for an arbitrary number of strings.
// Returns index of the target that is found first or -1 if timeout occurs.
int findMulti(struct MultiTarget *targets, int tCount);
};
#endif

View File

@ -1,343 +0,0 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "USB.h"
#if CONFIG_TINYUSB_ENABLED
#include "pins_arduino.h"
#include "esp32-hal.h"
#include "esp32-hal-tinyusb.h"
#include "common/tusb_common.h"
#ifndef USB_VID
#define USB_VID USB_ESPRESSIF_VID
#endif
#ifndef USB_PID
#define USB_PID 0x0002
#endif
#ifndef USB_MANUFACTURER
#define USB_MANUFACTURER "Espressif Systems"
#endif
#ifndef USB_PRODUCT
#define USB_PRODUCT ARDUINO_BOARD
#endif
#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_ATTRS (DFU_ATTR_CAN_DOWNLOAD | DFU_ATTR_CAN_UPLOAD | DFU_ATTR_MANIFESTATION_TOLERANT)
uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB DFU_RT");
uint8_t descriptor[TUD_DFU_RT_DESC_LEN] = {
// Interface number, string index, attributes, detach timeout, transfer size */
TUD_DFU_RT_DESCRIPTOR(*itf, str_index, DFU_ATTRS, 700, 64)
};
*itf+=1;
memcpy(dst, descriptor, TUD_DFU_RT_DESC_LEN);
return TUD_DFU_RT_DESC_LEN;
}
// Invoked on DFU_DETACH request to reboot to the bootloader
void tud_dfu_runtime_reboot_to_dfu_cb(void)
{
usb_persist_restart(RESTART_BOOTLOADER_DFU);
}
#endif /* CFG_TUD_DFU_RUNTIME */
ESP_EVENT_DEFINE_BASE(ARDUINO_USB_EVENTS);
static esp_event_loop_handle_t arduino_usb_event_loop_handle = NULL;
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){
if(arduino_usb_event_loop_handle == NULL){
return ESP_FAIL;
}
return esp_event_post_to(arduino_usb_event_loop_handle, event_base, event_id, event_data, event_data_size, 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(arduino_usb_event_loop_handle == NULL){
return ESP_FAIL;
}
return esp_event_handler_register_with(arduino_usb_event_loop_handle, event_base, event_id, event_handler, event_handler_arg);
}
static bool tinyusb_device_mounted = false;
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;
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;
arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY);
}
// Invoked when usb bus is suspended
// 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;
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);
}
// Invoked when usb bus is resumed
void tud_resume_cb(void){
tinyusb_device_suspended = false;
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);
}
ESPUSB::ESPUSB(size_t task_stack_size, uint8_t event_task_priority)
:vid(USB_VID)
,pid(USB_PID)
,product_name(USB_PRODUCT)
,manufacturer_name(USB_MANUFACTURER)
,serial_number(USB_SERIAL)
,fw_version(0x0100)
,usb_version(0x0200)// at least 2.1 or 3.x for BOS & webUSB
,usb_class(TUSB_CLASS_MISC)
,usb_subclass(MISC_SUBCLASS_COMMON)
,usb_protocol(MISC_PROTOCOL_IAD)
,usb_attributes(TUSB_DESC_CONFIG_ATT_SELF_POWERED)
,usb_power_ma(500)
,webusb_enabled(USB_WEBUSB_ENABLED)
,webusb_url(USB_WEBUSB_URL)
,_started(false)
,_task_stack_size(task_stack_size)
,_event_task_priority(event_task_priority)
{
if (!arduino_usb_event_loop_handle) {
esp_event_loop_args_t event_task_args = {
.queue_size = 5,
.task_name = "arduino_usb_events",
.task_priority = _event_task_priority,
.task_stack_size = _task_stack_size,
.task_core_id = tskNO_AFFINITY
};
if (esp_event_loop_create(&event_task_args, &arduino_usb_event_loop_handle) != ESP_OK) {
log_e("esp_event_loop_create failed");
}
}
}
ESPUSB::~ESPUSB(){
if (arduino_usb_event_loop_handle) {
esp_event_loop_delete(arduino_usb_event_loop_handle);
arduino_usb_event_loop_handle = NULL;
}
}
bool ESPUSB::begin(){
if(!_started){
tinyusb_device_config_t tinyusb_device_config = {
.vid = vid,
.pid = pid,
.product_name = product_name.c_str(),
.manufacturer_name = manufacturer_name.c_str(),
.serial_number = serial_number.c_str(),
.fw_version = fw_version,
.usb_version = usb_version,
.usb_class = usb_class,
.usb_subclass = usb_subclass,
.usb_protocol = usb_protocol,
.usb_attributes = usb_attributes,
.usb_power_ma = usb_power_ma,
.webusb_enabled = webusb_enabled,
.webusb_url = webusb_url.c_str()
};
_started = tinyusb_init(&tinyusb_device_config) == ESP_OK;
}
return _started;
}
void ESPUSB::onEvent(esp_event_handler_t callback){
onEvent(ARDUINO_USB_ANY_EVENT, callback);
}
void ESPUSB::onEvent(arduino_usb_event_t event, esp_event_handler_t callback){
arduino_usb_event_handler_register_with(ARDUINO_USB_EVENTS, event, callback, this);
}
ESPUSB::operator bool() const
{
return _started && tinyusb_device_mounted;
}
bool ESPUSB::enableDFU(){
#if CFG_TUD_DFU_RUNTIME
return tinyusb_enable_interface(USB_INTERFACE_DFU, TUD_DFU_RT_DESC_LEN, load_dfu_descriptor) == ESP_OK;
#endif /* CFG_TUD_DFU_RUNTIME */
return false;
}
bool ESPUSB::VID(uint16_t v){
if(!_started){
vid = v;
}
return !_started;
}
uint16_t ESPUSB::VID(void){
return vid;
}
bool ESPUSB::PID(uint16_t p){
if(!_started){
pid = p;
}
return !_started;
}
uint16_t ESPUSB::PID(void){
return pid;
}
bool ESPUSB::firmwareVersion(uint16_t version){
if(!_started){
fw_version = version;
}
return !_started;
}
uint16_t ESPUSB::firmwareVersion(void){
return fw_version;
}
bool ESPUSB::usbVersion(uint16_t version){
if(!_started){
usb_version = version;
}
return !_started;
}
uint16_t ESPUSB::usbVersion(void){
return usb_version;
}
bool ESPUSB::usbPower(uint16_t mA){
if(!_started){
usb_power_ma = mA;
}
return !_started;
}
uint16_t ESPUSB::usbPower(void){
return usb_power_ma;
}
bool ESPUSB::usbClass(uint8_t _class){
if(!_started){
usb_class = _class;
}
return !_started;
}
uint8_t ESPUSB::usbClass(void){
return usb_class;
}
bool ESPUSB::usbSubClass(uint8_t subClass){
if(!_started){
usb_subclass = subClass;
}
return !_started;
}
uint8_t ESPUSB::usbSubClass(void){
return usb_subclass;
}
bool ESPUSB::usbProtocol(uint8_t protocol){
if(!_started){
usb_protocol = protocol;
}
return !_started;
}
uint8_t ESPUSB::usbProtocol(void){
return usb_protocol;
}
bool ESPUSB::usbAttributes(uint8_t attr){
if(!_started){
usb_attributes = attr;
}
return !_started;
}
uint8_t ESPUSB::usbAttributes(void){
return usb_attributes;
}
bool ESPUSB::webUSB(bool enabled){
if(!_started){
webusb_enabled = enabled;
if(enabled && usb_version < 0x0210){
usb_version = 0x0210;
}
}
return !_started;
}
bool ESPUSB::webUSB(void){
return webusb_enabled;
}
bool ESPUSB::productName(const char * name){
if(!_started){
product_name = name;
}
return !_started;
}
const char * ESPUSB::productName(void){
return product_name.c_str();
}
bool ESPUSB::manufacturerName(const char * name){
if(!_started){
manufacturer_name = name;
}
return !_started;
}
const char * ESPUSB::manufacturerName(void){
return manufacturer_name.c_str();
}
bool ESPUSB::serialNumber(const char * name){
if(!_started){
serial_number = name;
}
return !_started;
}
const char * ESPUSB::serialNumber(void){
return serial_number.c_str();
}
bool ESPUSB::webUSBURL(const char * name){
if(!_started){
webusb_url = name;
}
return !_started;
}
const char * ESPUSB::webUSBURL(void){
return webusb_url.c_str();
}
ESPUSB USB;
#endif /* CONFIG_TINYUSB_ENABLED */

View File

@ -1,119 +0,0 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "sdkconfig.h"
#if CONFIG_TINYUSB_ENABLED
#include "esp_event.h"
#include "USBCDC.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);
typedef enum {
ARDUINO_USB_ANY_EVENT = ESP_EVENT_ANY_ID,
ARDUINO_USB_STARTED_EVENT = 0,
ARDUINO_USB_STOPPED_EVENT,
ARDUINO_USB_SUSPEND_EVENT,
ARDUINO_USB_RESUME_EVENT,
ARDUINO_USB_MAX_EVENT,
} arduino_usb_event_t;
typedef union {
struct {
bool remote_wakeup_en;
} suspend;
} arduino_usb_event_data_t;
class ESPUSB {
public:
ESPUSB(size_t event_task_stack_size=2048, uint8_t event_task_priority=5);
~ESPUSB();
void onEvent(esp_event_handler_t callback);
void onEvent(arduino_usb_event_t event, esp_event_handler_t callback);
bool VID(uint16_t v);
uint16_t VID(void);
bool PID(uint16_t p);
uint16_t PID(void);
bool firmwareVersion(uint16_t version);
uint16_t firmwareVersion(void);
bool usbVersion(uint16_t version);
uint16_t usbVersion(void);
bool usbPower(uint16_t mA);
uint16_t usbPower(void);
bool usbClass(uint8_t _class);
uint8_t usbClass(void);
bool usbSubClass(uint8_t subClass);
uint8_t usbSubClass(void);
bool usbProtocol(uint8_t protocol);
uint8_t usbProtocol(void);
bool usbAttributes(uint8_t attr);
uint8_t usbAttributes(void);
bool webUSB(bool enabled);
bool webUSB(void);
bool productName(const char * name);
const char * productName(void);
bool manufacturerName(const char * name);
const char * manufacturerName(void);
bool serialNumber(const char * name);
const char * serialNumber(void);
bool webUSBURL(const char * name);
const char * webUSBURL(void);
bool enableDFU();
bool begin();
operator bool() const;
private:
uint16_t vid;
uint16_t pid;
String product_name;
String manufacturer_name;
String serial_number;
uint16_t fw_version;
uint16_t usb_version;
uint8_t usb_class;
uint8_t usb_subclass;
uint8_t usb_protocol;
uint8_t usb_attributes;
uint16_t usb_power_ma;
bool webusb_enabled;
String webusb_url;
bool _started;
size_t _task_stack_size;
uint8_t _event_task_priority;
};
extern ESPUSB USB;
#endif /* CONFIG_TINYUSB_ENABLED */

View File

@ -1,419 +0,0 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "USB.h"
#if CONFIG_TINYUSB_CDC_ENABLED
#include "USBCDC.h"
#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);
#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");
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)
};
*itf+=2;
memcpy(dst, descriptor, TUD_CDC_DESC_LEN);
return TUD_CDC_DESC_LEN;
}
// Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE
void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
{
if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){
devices[itf]->_onLineState(dtr, 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)
{
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);
}
}
// Invoked when received new data
void tud_cdc_rx_cb(uint8_t itf)
{
if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){
devices[itf]->_onRX();
}
}
// Invoked when received send break
void tud_cdc_send_break_cb(uint8_t itf, uint16_t 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){
if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){
devices[itf]->_onTX();
}
}
static void ARDUINO_ISR_ATTR cdc0_write_char(char c){
if(devices[0] != NULL){
devices[0]->write(c);
}
}
static void usb_unplugged_cb(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data){
((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)
, 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){
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);
}
void USBCDC::onEvent(arduino_usb_cdc_event_t event, esp_event_handler_t callback){
arduino_usb_event_handler_register_with(ARDUINO_USB_CDC_EVENTS, event, callback, this);
}
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));
if(!rx_queue){
return 0;
}
return rx_queue_len;
}
void USBCDC::begin(unsigned long baud)
{
if(tx_lock == NULL) {
tx_lock = xSemaphoreCreateMutex();
}
setRxBufferSize(256);//default if not preset
devices[itf] = this;
}
void USBCDC::end()
{
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;
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_DISCONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
}
}
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;
if(reboot_enable){
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;
}
} else if(dtr && rts){
if(lineState == CDC_LINE_1){
lineState++;
} else {
lineState = CDC_LINE_IDLE;
}
} else if(dtr && !rts){
if(lineState == CDC_LINE_2){
lineState++;
} else {
lineState = CDC_LINE_IDLE;
}
} else if(!dtr && !rts){
if(lineState == CDC_LINE_3){
usb_persist_restart(RESTART_BOOTLOADER);
} else {
lineState = CDC_LINE_IDLE;
}
}
}
if(lineState == CDC_LINE_IDLE){
if(dtr && rts && !connected){
connected = true;
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 && 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);
}
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);
}
}
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(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;
p.line_coding.bit_rate = bit_rate;
p.line_coding.data_bits = data_bits;
p.line_coding.stop_bits = stop_bits;
p.line_coding.parity = parity;
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_LINE_CODING_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
}
}
}
void USBCDC::_onRX(){
uint8_t buf[CONFIG_TINYUSB_CDC_RX_BUFSIZE+1];
uint32_t count = tud_cdc_n_read(itf, buf, CONFIG_TINYUSB_CDC_RX_BUFSIZE);
for(uint32_t i=0; i<count; i++){
if(rx_queue == NULL || !xQueueSend(rx_queue, buf+i, 0)){
return;
}
}
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;
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_TX_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
}
void USBCDC::enableReboot(bool enable){
reboot_enable = enable;
}
bool USBCDC::rebootEnabled(void){
return reboot_enable;
}
int USBCDC::available(void)
{
if(itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL){
return -1;
}
return uxQueueMessagesWaiting(rx_queue);
}
int USBCDC::peek(void)
{
if(itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL){
return -1;
}
uint8_t c;
if(xQueuePeek(rx_queue, &c, 0)) {
return c;
}
return -1;
}
int USBCDC::read(void)
{
if(itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL){
return -1;
}
uint8_t c = 0;
if(xQueueReceive(rx_queue, &c, 0)) {
return c;
}
return -1;
}
size_t USBCDC::read(uint8_t *buffer, size_t size)
{
if(itf >= MAX_USB_CDC_DEVICES || 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;
}
void USBCDC::flush(void)
{
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 || tx_lock == NULL || !tud_cdc_n_connected(itf)){
return 0;
}
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)
{
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)
{
return write(&c, 1);
}
uint32_t USBCDC::baudRate()
{
return bit_rate;
}
void USBCDC::setDebugOutput(bool en)
{
if(en) {
uartSetDebug(NULL);
ets_install_putc1((void (*)(char)) &cdc0_write_char);
} else {
ets_install_putc1(NULL);
}
}
USBCDC::operator bool() const
{
if(itf >= MAX_USB_CDC_DEVICES){
return false;
}
return connected;
}
#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC
USBCDC Serial(0);
#endif
#endif /* CONFIG_TINYUSB_CDC_ENABLED */

View File

@ -1,141 +0,0 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "sdkconfig.h"
#if CONFIG_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);
typedef enum {
ARDUINO_USB_CDC_ANY_EVENT = ESP_EVENT_ANY_ID,
ARDUINO_USB_CDC_CONNECTED_EVENT = 0,
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,
} arduino_usb_cdc_event_t;
typedef union {
struct {
bool dtr;
bool rts;
} line_state;
struct {
uint32_t bit_rate;
uint8_t stop_bits; ///< 0: 1 stop bit - 1: 1.5 stop bits - 2: 2 stop bits
uint8_t parity; ///< 0: None - 1: Odd - 2: Even - 3: Mark - 4: Space
uint8_t data_bits; ///< can be 5, 6, 7, 8 or 16
} line_coding;
struct {
size_t len;
} rx;
} arduino_usb_cdc_event_data_t;
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);
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);
}
uint32_t baudRate();
void setDebugOutput(bool);
operator bool() const;
void enableReboot(bool enable);
bool rebootEnabled(void);
//internal methods
void _onDFU(void);
void _onLineState(bool _dtr, bool _rts);
void _onLineCoding(uint32_t _bit_rate, uint8_t _stop_bits, uint8_t _parity, uint8_t _data_bits);
void _onRX(void);
void _onTX(void);
void _onUnplugged(void);
protected:
uint8_t itf;
uint32_t bit_rate;
uint8_t stop_bits; ///< 0: 1 stop bit - 1: 1.5 stop bits - 2: 2 stop bits
uint8_t parity; ///< 0: None - 1: Odd - 2: Even - 3: Mark - 4: Space
uint8_t data_bits; ///< can be 5, 6, 7, 8 or 16
bool dtr;
bool rts;
bool connected;
bool reboot_enable;
xQueueHandle rx_queue;
xSemaphoreHandle tx_lock;
uint32_t tx_timeout_ms;
};
#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC
extern USBCDC Serial;
#endif
#endif /* CONFIG_TINYUSB_CDC_ENABLED */

View File

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

View File

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

View File

@ -43,7 +43,6 @@ class UDP: public Stream
public:
virtual uint8_t begin(uint16_t) =0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use
virtual uint8_t beginMulticast(IPAddress, uint16_t) { return 0; } // initialize, start listening on specified multicast IP address and port. Returns 1 if successful, 0 on failure
virtual void stop() =0; // Finish with the UDP socket
// Sending UDP packets

View File

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

View File

@ -35,12 +35,6 @@ 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;
@ -65,7 +59,9 @@ String::String(StringSumHelper &&rval) {
String::String(char c) {
init();
char buf[] = { c, '\0' };
char buf[2];
buf[0] = c;
buf[1] = 0;
*this = buf;
}
@ -134,9 +130,9 @@ String::~String() {
inline void String::init(void) {
setSSO(false);
setBuffer(nullptr);
setCapacity(0);
setLen(0);
setBuffer(nullptr);
}
void String::invalidate(void) {
@ -163,7 +159,7 @@ unsigned char String::changeBuffer(unsigned int maxStrLen) {
// Already using SSO, nothing to do
uint16_t oldLen = len();
setSSO(true);
setLen(oldLen);
setLen(oldLen);
return 1;
} else { // if bufptr && !isSSO()
// Using bufptr, need to shrink into sso.buff
@ -172,8 +168,8 @@ unsigned char String::changeBuffer(unsigned int maxStrLen) {
free(wbuffer());
uint16_t oldLen = len();
setSSO(true);
setLen(oldLen);
memcpy(wbuffer(), temp, maxStrLen);
setLen(oldLen);
return 1;
}
}
@ -197,8 +193,8 @@ unsigned char String::changeBuffer(unsigned int maxStrLen) {
}
setSSO(false);
setCapacity(newSize - 1);
setBuffer(newbuffer);
setLen(oldLen); // Needed in case of SSO where len() never existed
setBuffer(newbuffer);
return 1;
}
return 0;
@ -213,8 +209,8 @@ String & String::copy(const char *cstr, unsigned int length) {
invalidate();
return *this;
}
memmove(wbuffer(), cstr, length + 1);
setLen(length);
memmove(wbuffer(), cstr, length + 1);
return *this;
}
@ -223,8 +219,8 @@ String & String::copy(const __FlashStringHelper *pstr, unsigned int length) {
invalidate();
return *this;
}
memcpy_P(wbuffer(), (PGM_P)pstr, length + 1); // We know wbuffer() cannot ever be in PROGMEM, so memcpy safe here
setLen(length);
memcpy_P(wbuffer(), (PGM_P)pstr, length + 1); // We know wbuffer() cannot ever be in PROGMEM, so memcpy safe here
return *this;
}
@ -254,8 +250,8 @@ void String::move(String &rhs) {
setLen(rhs.len());
rhs.setSSO(false);
rhs.setCapacity(0);
rhs.setBuffer(nullptr);
rhs.setLen(0);
rhs.setBuffer(nullptr);
}
#endif
@ -294,11 +290,10 @@ String & String::operator =(const char *cstr) {
return *this;
}
String & String::operator =(const __FlashStringHelper *pstr) {
if(pstr)
copy(pstr, strlen_P((PGM_P)pstr));
else
invalidate();
String & String::operator = (const __FlashStringHelper *pstr)
{
if (pstr) copy(pstr, strlen_P((PGM_P)pstr));
else invalidate();
return *this;
}
@ -352,18 +347,22 @@ unsigned char String::concat(const char *cstr) {
}
unsigned char String::concat(char c) {
char buf[] = { c, '\0' };
char buf[2];
buf[0] = c;
buf[1] = 0;
return concat(buf, 1);
}
unsigned char String::concat(unsigned char num) {
char buf[1 + 3 * sizeof(unsigned char)];
return concat(buf, sprintf(buf, "%d", num));
sprintf(buf, "%d", num);
return concat(buf, strlen(buf));
}
unsigned char String::concat(int num) {
char buf[2 + 3 * sizeof(int)];
return concat(buf, sprintf(buf, "%d", num));
sprintf(buf, "%d", num);
return concat(buf, strlen(buf));
}
unsigned char String::concat(unsigned int num) {
@ -374,7 +373,8 @@ unsigned char String::concat(unsigned int num) {
unsigned char String::concat(long num) {
char buf[2 + 3 * sizeof(long)];
return concat(buf, sprintf(buf, "%ld", num));
sprintf(buf, "%ld", num);
return concat(buf, strlen(buf));
}
unsigned char String::concat(unsigned long num) {
@ -555,7 +555,7 @@ unsigned char String::equalsConstantTime(const String &s2) const {
//at this point lengths are the same
if(len() == 0)
return 1;
//at this point lengths are the same and non-zero
//at this point lenghts are the same and non-zero
const char *p1 = buffer();
const char *p2 = s2.buffer();
unsigned int equalchars = 0;
@ -711,7 +711,10 @@ String String::substring(unsigned int left, unsigned int right) const {
return out;
if(right > len())
right = len();
out.copy(buffer() + left, right - left);
char temp = buffer()[right]; // save the replaced character
wbuffer()[right] = '\0';
out = wbuffer() + left; // pointer arithmetic
wbuffer()[right] = temp; //restore character
return out;
}
@ -741,7 +744,6 @@ void String::replace(const String& find, const String& replace) {
}
} else if(diff < 0) {
char *writeTo = wbuffer();
unsigned int l = len();
while((foundAt = strstr(readFrom, find.buffer())) != NULL) {
unsigned int n = foundAt - readFrom;
memmove(writeTo, readFrom, n);
@ -749,10 +751,9 @@ void String::replace(const String& find, const String& replace) {
memmove(writeTo, replace.buffer(), replace.len());
writeTo += replace.len();
readFrom = foundAt + find.len();
l += diff;
setLen(len() + diff);
}
memmove(writeTo, readFrom, strlen(readFrom)+1);
setLen(l);
} else {
unsigned int size = len(); // compute size needed for result
while((foundAt = strstr(readFrom, find.buffer())) != NULL) {
@ -767,7 +768,7 @@ void String::replace(const String& find, const String& replace) {
while(index >= 0 && (index = lastIndexOf(find, index)) >= 0) {
readFrom = wbuffer() + index + find.len();
memmove(readFrom + diff, readFrom, len() - (readFrom - buffer()));
int newLen = len() + diff;
int newLen = len() + diff;
memmove(wbuffer() + index, replace.buffer(), replace.len());
setLen(newLen);
wbuffer()[newLen] = 0;
@ -795,8 +796,8 @@ void String::remove(unsigned int index, unsigned int count) {
}
char *writeTo = wbuffer() + index;
unsigned int newlen = len() - count;
memmove(writeTo, wbuffer() + index + count, newlen - index);
setLen(newlen);
memmove(writeTo, wbuffer() + index + count, newlen - index);
wbuffer()[newlen] = 0;
}
@ -826,9 +827,9 @@ void String::trim(void) {
while(isspace(*end) && end >= begin)
end--;
unsigned int newlen = end + 1 - begin;
setLen(newlen);
if(begin > buffer())
memmove(wbuffer(), begin, newlen);
setLen(newlen);
wbuffer()[newlen] = 0;
}

View File

@ -55,10 +55,6 @@ 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__
@ -112,8 +108,6 @@ 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);
@ -287,8 +281,8 @@ class String {
// Contains the string info when we're not in SSO mode
struct _ptr {
char * buff;
uint32_t cap;
uint32_t len;
uint16_t cap;
uint16_t len;
};
// This allows strings up up to 11 (10 + \0 termination) without any extra space.
enum { SSOSIZE = sizeof(struct _ptr) + 4 - 1 }; // Characters to allocate space for SSO, must be 12 or more
@ -297,11 +291,7 @@ class String {
unsigned char len : 7; // Ensure only one byte is allocated by GCC for the bitfields
unsigned char isSSO : 1;
} __attribute__((packed)); // Ensure that GCC doesn't expand the flag byte to a 32-bit word for alignment issues
#ifdef BOARD_HAS_PSRAM
enum { CAPACITY_MAX = 3145728 };
#else
enum { CAPACITY_MAX = 65535 };
#endif
enum { CAPACITY_MAX = 65535 }; // If typeof(cap) changed from uint16_t, be sure to update this enum to the max value storable in the type
union {
struct _ptr ptr;
struct _sso sso;
@ -311,19 +301,9 @@ class String {
inline unsigned int len() const { return isSSO() ? sso.len : ptr.len; }
inline unsigned int capacity() const { return isSSO() ? (unsigned int)SSOSIZE - 1 : ptr.cap; } // Size of max string not including terminal NUL
inline void setSSO(bool set) { sso.isSSO = set; }
inline void setLen(int len) {
if (isSSO()) {
sso.len = len;
sso.buff[len] = 0;
} else {
ptr.len = len;
if (ptr.buff) {
ptr.buff[len] = 0;
}
}
}
inline void setLen(int len) { if (isSSO()) sso.len = len; else ptr.len = len; }
inline void setCapacity(int cap) { if (!isSSO()) ptr.cap = cap; }
inline void setBuffer(char *buff) { if (!isSSO()) ptr.buff = buff; }
inline void setBuffer(char *buff) { if (!isSSO()) ptr.buff = buff; }
// Buffer accessor functions
inline const char *buffer() const { return (const char *)(isSSO() ? sso.buff : ptr.buff); }
inline char *wbuffer() const { return isSSO() ? const_cast<char *>(sso.buff) : ptr.buff; } // Writable version of buffer
@ -332,6 +312,7 @@ 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

@ -16,28 +16,19 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_attr.h"
#include "soc/rtc_io_reg.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/sens_reg.h"
#include "driver/adc.h"
#include "esp_adc_cal.h"
#include "esp_system.h"
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
#include "esp_adc_cal.h"
#include "soc/sens_reg.h"
#include "soc/rtc_io_reg.h"
#include "esp32/rom/ets_sys.h"
#include "esp_intr_alloc.h"
#define DEFAULT_VREF 1100
static esp_adc_cal_characteristics_t *__analogCharacteristics[2] = {NULL, NULL};
static uint16_t __analogVRef = 0;
static uint8_t __analogVRefPin = 0;
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/ets_sys.h"
#include "soc/sens_reg.h"
#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
@ -45,40 +36,14 @@ static uint8_t __analogVRefPin = 0;
#include "esp_intr.h"
#endif
#define DEFAULT_VREF 1100
static esp_adc_cal_characteristics_t *__analogCharacteristics[2] = {NULL, NULL};
static uint8_t __analogAttenuation = 3;//11db
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 __analogWidth = 3;//12 bits
static uint8_t __analogClockDiv = 1;
static adc_attenuation_t __pin_attenuation[SOC_GPIO_PIN_COUNT];
static uint16_t __analogVRef = 0;
static uint8_t __analogVRefPin = 0;
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;
}
__analogClockDiv = clockDiv;
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
adc_set_clk_div(__analogClockDiv);
#endif
}
void __analogSetAttenuation(adc_attenuation_t attenuation)
{
__analogAttenuation = attenuation & 3;
}
#if CONFIG_IDF_TARGET_ESP32
void __analogSetWidth(uint8_t bits){
if(bits < 9){
bits = 9;
@ -88,7 +53,19 @@ void __analogSetWidth(uint8_t bits){
__analogWidth = bits - 9;
adc1_config_width(__analogWidth);
}
#endif
void __analogSetClockDiv(uint8_t clockDiv){
if(!clockDiv){
clockDiv = 1;
}
__analogClockDiv = clockDiv;
adc_set_clk_div(__analogClockDiv);
}
void __analogSetAttenuation(adc_attenuation_t attenuation)
{
__analogAttenuation = attenuation & 3;
}
void __analogInit(){
static bool initialized = false;
@ -97,12 +74,7 @@ void __analogInit(){
}
initialized = true;
__analogSetClockDiv(__analogClockDiv);
#if CONFIG_IDF_TARGET_ESP32
__analogSetWidth(__analogWidth + 9);//in bits
#endif
for(int i=0; i<SOC_GPIO_PIN_COUNT; i++){
__pin_attenuation[i] = ADC_ATTENDB_MAX;
}
}
void __analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation)
@ -117,9 +89,6 @@ void __analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation)
adc1_config_channel_atten(channel, attenuation);
}
__analogInit();
if((__pin_attenuation[pin] != ADC_ATTENDB_MAX) || (attenuation != __analogAttenuation)){
__pin_attenuation[pin] = attenuation;
}
}
bool __adcAttachPin(uint8_t pin){
@ -128,10 +97,8 @@ 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
uint32_t touch = READ_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG);
if(touch & (1 << pad)){
touch &= ~((1 << (pad + SENS_TOUCH_PAD_OUTEN2_S))
@ -139,18 +106,14 @@ bool __adcAttachPin(uint8_t pin){
| (1 << (pad + SENS_TOUCH_PAD_WORKEN_S)));
WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG, touch);
}
#endif
}
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
else if(pin == 25){
} else if(pin == 25){
CLEAR_PERI_REG_MASK(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_XPD_DAC | RTC_IO_PDAC1_DAC_XPD_FORCE);//stop dac1
} else if(pin == 26){
CLEAR_PERI_REG_MASK(RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_XPD_DAC | RTC_IO_PDAC2_DAC_XPD_FORCE);//stop dac2
}
#endif
pinMode(pin, ANALOG);
__analogSetPinAttenuation(pin, (__pin_attenuation[pin] != ADC_ATTENDB_MAX)?__pin_attenuation[pin]:__analogAttenuation);
__analogSetPinAttenuation(pin, __analogAttenuation);
return true;
}
@ -159,10 +122,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
}
uint16_t __analogRead(uint8_t pin)
@ -179,19 +139,25 @@ uint16_t __analogRead(uint8_t pin)
channel -= 10;
r = adc2_get_raw( channel, __analogWidth, &value);
if ( r == ESP_OK ) {
return mapResolution(value);
return 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 ) {
log_e("GPIO%u: %s: ADC2 is in use by Wi-Fi. Please see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/adc.html#adc-limitations for more info", pin, esp_err_to_name(r));
log_e("GPIO%u: %s: ADC2 is in use by Wi-Fi.", pin, esp_err_to_name(r));
} else {
log_e("GPIO%u: %s", pin, esp_err_to_name(r));
}
} else {
value = adc1_get_raw(channel);
return mapResolution(value);
return adc1_get_raw(channel);
}
return mapResolution(value);
return value;
}
void __analogSetVRefPin(uint8_t pin){
if(pin <25 || pin > 27){
pin = 0;
}
__analogVRefPin = pin;
}
uint32_t __analogReadMilliVolts(uint8_t pin){
@ -200,7 +166,6 @@ uint32_t __analogReadMilliVolts(uint8_t pin){
log_e("Pin %u is not ADC pin!", pin);
return 0;
}
#if CONFIG_IDF_TARGET_ESP32
if(!__analogVRef){
if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) {
log_d("eFuse Two Point: Supported");
@ -214,7 +179,7 @@ uint32_t __analogReadMilliVolts(uint8_t pin){
__analogVRef = DEFAULT_VREF;
if(__analogVRefPin){
esp_adc_cal_characteristics_t chars;
if(adc_vref_to_gpio(ADC_UNIT_2, __analogVRefPin) == ESP_OK){
if(adc2_vref_to_gpio(__analogVRefPin) == ESP_OK){
__analogVRef = __analogRead(__analogVRefPin);
esp_adc_cal_characterize(1, __analogAttenuation, __analogWidth, DEFAULT_VREF, &chars);
__analogVRef = esp_adc_cal_raw_to_voltage(__analogVRef, &chars);
@ -245,50 +210,41 @@ uint32_t __analogReadMilliVolts(uint8_t pin){
}
}
return esp_adc_cal_raw_to_voltage(adc_reading, __analogCharacteristics[unit - 1]);
#else
uint16_t adc_reading = __analogRead(pin);
uint16_t max_reading = 8191;
uint16_t max_mv = 1100;
switch(__analogAttenuation){
case 3: max_mv = 3900; break;
case 2: max_mv = 2200; break;
case 1: max_mv = 1500; break;
default: break;
}
return (adc_reading * max_mv) / max_reading;
#endif
}
#if CONFIG_IDF_TARGET_ESP32
void __analogSetVRefPin(uint8_t pin){
if(pin <25 || pin > 27){
pin = 0;
}
__analogVRefPin = pin;
}
int __hallRead() //hall sensor using idf read
int __hallRead() //hall sensor without LNA
{
int Sens_Vp0;
int Sens_Vn0;
int Sens_Vp1;
int Sens_Vn1;
pinMode(36, ANALOG);
pinMode(39, ANALOG);
__analogSetWidth(12);
return hall_sensor_read();
SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_XPD_HALL_FORCE_M); // hall sens force enable
SET_PERI_REG_MASK(RTC_IO_HALL_SENS_REG, RTC_IO_XPD_HALL); // xpd hall
SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_HALL_PHASE_FORCE_M); // phase force
CLEAR_PERI_REG_MASK(RTC_IO_HALL_SENS_REG, RTC_IO_HALL_PHASE); // hall phase
Sens_Vp0 = __analogRead(36);
Sens_Vn0 = __analogRead(39);
SET_PERI_REG_MASK(RTC_IO_HALL_SENS_REG, RTC_IO_HALL_PHASE);
Sens_Vp1 = __analogRead(36);
Sens_Vn1 = __analogRead(39);
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR, 0, SENS_FORCE_XPD_SAR_S);
CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_XPD_HALL_FORCE);
CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_HALL_PHASE_FORCE);
return (Sens_Vp1 - Sens_Vp0) - (Sens_Vn1 - Sens_Vn0);
}
#endif
extern uint16_t analogRead(uint8_t pin) __attribute__ ((weak, alias("__analogRead")));
extern uint32_t analogReadMilliVolts(uint8_t pin) __attribute__ ((weak, alias("__analogReadMilliVolts")));
extern void analogReadResolution(uint8_t bits) __attribute__ ((weak, alias("__analogReadResolution")));
extern void analogSetWidth(uint8_t bits) __attribute__ ((weak, alias("__analogSetWidth")));
extern void analogSetClockDiv(uint8_t clockDiv) __attribute__ ((weak, alias("__analogSetClockDiv")));
extern void analogSetAttenuation(adc_attenuation_t attenuation) __attribute__ ((weak, alias("__analogSetAttenuation")));
extern void analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation) __attribute__ ((weak, alias("__analogSetPinAttenuation")));
extern int hallRead() __attribute__ ((weak, alias("__hallRead")));
extern bool adcAttachPin(uint8_t pin) __attribute__ ((weak, alias("__adcAttachPin")));
#if CONFIG_IDF_TARGET_ESP32
extern void analogSetVRefPin(uint8_t pin) __attribute__ ((weak, alias("__analogSetVRefPin")));
extern void analogSetWidth(uint8_t bits) __attribute__ ((weak, alias("__analogSetWidth")));
extern int hallRead() __attribute__ ((weak, alias("__hallRead")));
#endif
extern uint32_t analogReadMilliVolts(uint8_t pin) __attribute__ ((weak, alias("__analogReadMilliVolts")));

View File

@ -30,8 +30,7 @@ typedef enum {
ADC_0db,
ADC_2_5db,
ADC_6db,
ADC_11db,
ADC_ATTENDB_MAX
ADC_11db
} adc_attenuation_t;
/*
@ -39,11 +38,6 @@ typedef enum {
* */
uint16_t analogRead(uint8_t pin);
/*
* Get MilliVolts value for pin
* */
uint32_t analogReadMilliVolts(uint8_t pin);
/*
* Set the resolution of analogRead return values. Default is 12 bits (range from 0 to 4096).
* If between 9 and 12, it will equal the set hardware resolution, else value will be shifted.
@ -53,6 +47,13 @@ uint32_t analogReadMilliVolts(uint8_t pin);
*/
void analogReadResolution(uint8_t bits);
/*
* Sets the sample bits and read resolution
* Default is 12bit (0 - 4095)
* Range is 9 - 12
* */
void analogSetWidth(uint8_t bits);
/*
* Set the divider for the ADC clock.
* Default is 1
@ -72,30 +73,26 @@ void analogSetAttenuation(adc_attenuation_t attenuation);
* */
void analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation);
/*
* Get value for HALL sensor (without LNA)
* connected to pins 36(SVP) and 39(SVN)
* */
int hallRead();
/*
* Attach pin to ADC (will also clear any other analog mode that could be on)
* */
bool adcAttachPin(uint8_t pin);
#if CONFIG_IDF_TARGET_ESP32
/*
* Sets the sample bits and read resolution
* Default is 12bit (0 - 4095)
* Range is 9 - 12
* */
void analogSetWidth(uint8_t bits);
/*
* Set pin to use for ADC calibration if the esp is not already calibrated (25, 26 or 27)
* */
void analogSetVRefPin(uint8_t pin);
/*
* Get value for HALL sensor (without LNA)
* connected to pins 36(SVP) and 39(SVN)
* Get MilliVolts value for pin
* */
int hallRead();
#endif
uint32_t analogReadMilliVolts(uint8_t pin);
#ifdef __cplusplus
}

View File

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

View File

@ -16,6 +16,7 @@
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
#include "freertos/xtensa_timer.h"
#include "esp_attr.h"
#include "esp_log.h"
#include "soc/rtc.h"
@ -28,13 +29,7 @@
#include "esp_system.h"
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
#include "freertos/xtensa_timer.h"
#include "esp32/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "freertos/xtensa_timer.h"
#include "esp32s2/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/rtc.h"
#else
#error Target CONFIG_IDF_TARGET is not supported
#endif
@ -49,6 +44,7 @@ typedef struct apb_change_cb_s {
apb_change_cb_t cb;
} apb_change_t;
const uint32_t MHZ = 1000000;
static apb_change_t * apb_change_callbacks = NULL;
static xSemaphoreHandle apb_change_lock = NULL;
@ -144,14 +140,10 @@ bool removeApbChangeCallback(void * arg, apb_change_cb_t cb){
}
static uint32_t calculateApb(rtc_cpu_freq_config_t * conf){
#if CONFIG_IDF_TARGET_ESP32C3
return APB_CLK_FREQ;
#else
if(conf->freq_mhz >= 80){
return 80 * MHZ;
}
return (conf->source_freq_mhz * MHZ) / conf->div;
#endif
}
void esp_timer_impl_update_apb_freq(uint32_t apb_ticks_per_us); //private in IDF
@ -161,7 +153,6 @@ bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz){
uint32_t capb, apb;
//Get XTAL Frequency and calculate min CPU MHz
rtc_xtal_freq_t xtal = rtc_clk_xtal_freq_get();
#if CONFIG_IDF_TARGET_ESP32
if(xtal > RTC_XTAL_FREQ_AUTO){
if(xtal < RTC_XTAL_FREQ_40M) {
if(cpu_freq_mhz <= xtal && cpu_freq_mhz != xtal && cpu_freq_mhz != (xtal/2)){
@ -173,7 +164,6 @@ bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz){
return false;
}
}
#endif
if(cpu_freq_mhz > xtal && cpu_freq_mhz != 240 && cpu_freq_mhz != 160 && cpu_freq_mhz != 80){
if(xtal >= RTC_XTAL_FREQ_40M){
log_e("Bad frequency: %u MHz! Options are: 240, 160, 80, %u, %u and %u MHz", cpu_freq_mhz, xtal, xtal/2, xtal/4);
@ -182,7 +172,6 @@ bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz){
}
return false;
}
#if CONFIG_IDF_TARGET_ESP32
//check if cpu supports the frequency
if(cpu_freq_mhz == 240){
//Check if ESP32 is rated for a CPU frequency of 160MHz only
@ -192,7 +181,6 @@ bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz){
cpu_freq_mhz = 160;
}
}
#endif
//Get current CPU clock configuration
rtc_clk_cpu_freq_get_config(&cconf);
//return if frequency has not changed
@ -226,12 +214,8 @@ bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz){
esp_timer_impl_update_apb_freq(apb / MHZ);
}
//Update FreeRTOS Tick Divisor
#if CONFIG_IDF_TARGET_ESP32C3
#else
uint32_t fcpu = (conf.freq_mhz >= 80)?(conf.freq_mhz * MHZ):(apb);
_xt_tick_divisor = fcpu / XT_TICK_PER_SEC;
#endif
//Call peripheral functions after the APB change
if(apb_change_callbacks){
triggerApbChangeCallback(APB_AFTER_CHANGE, capb, apb);

View File

@ -12,52 +12,54 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "esp32-hal.h"
#include "esp32-hal-dac.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_attr.h"
#include "soc/rtc_io_reg.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/sens_reg.h"
#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
#define NODAC
#else
#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"
#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
#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"
void ARDUINO_ISR_ATTR __dacWrite(uint8_t pin, uint8_t value)
void IRAM_ATTR __dacWrite(uint8_t pin, uint8_t value)
{
if(pin < DAC1 || pin > DAC2){
if(pin < 25 || pin > 26){
return;//not dac pin
}
pinMode(pin, ANALOG);
uint8_t channel = pin - DAC1;
#if CONFIG_IDF_TARGET_ESP32
uint8_t channel = pin - 25;
//Disable Tone
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;
if (channel) {
//Disable Channel Tone
CLEAR_PERI_REG_MASK(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_CW_EN2_M);
//Set the Dac value
SET_PERI_REG_BITS(RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_DAC, value, RTC_IO_PDAC2_DAC_S); //dac_output
//Channel output enable
SET_PERI_REG_MASK(RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_XPD_DAC | RTC_IO_PDAC2_DAC_XPD_FORCE);
} else {
//Disable Channel Tone
CLEAR_PERI_REG_MASK(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_CW_EN1_M);
//Set the Dac value
SET_PERI_REG_BITS(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_DAC, value, RTC_IO_PDAC1_DAC_S); //dac_output
//Channel output enable
SET_PERI_REG_MASK(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_XPD_DAC | RTC_IO_PDAC1_DAC_XPD_FORCE);
}
RTCIO.pad_dac[channel].dac = value;
}
extern void dacWrite(uint8_t pin, uint8_t value) __attribute__ ((weak, alias("__dacWrite")));
#endif

View File

@ -13,32 +13,22 @@
// limitations under the License.
#include "esp32-hal-gpio.h"
#include "pins_arduino.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_attr.h"
#include "soc/gpio_reg.h"
#include "soc/io_mux_reg.h"
#include "soc/gpio_struct.h"
#include "driver/gpio.h"
#include "esp_system.h"
#include "soc/rtc_io_reg.h"
#include "esp_system.h"
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
#include "esp32/rom/ets_sys.h"
#include "esp32/rom/gpio.h"
#include "esp_intr_alloc.h"
#include "soc/rtc_io_reg.h"
#define GPIO_FUNC 2
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/ets_sys.h"
#include "esp32s2/rom/gpio.h"
#include "esp_intr_alloc.h"
#include "soc/periph_defs.h"
#include "soc/rtc_io_reg.h"
#define GPIO_FUNC 1
#else
#define USE_ESP_IDF_GPIO 1
#error Target CONFIG_IDF_TARGET is not supported
#endif
#else // ESP32 Before IDF 4.0
#include "rom/ets_sys.h"
@ -46,14 +36,9 @@
#include "esp_intr.h"
#endif
#if CONFIG_IDF_TARGET_ESP32
const int8_t esp32_adc2gpio[20] = {36, 37, 38, 39, 32, 33, 34, 35, -1, -1, 4, 0, 2, 15, 13, 12, 14, 27, 25, 26};
#elif CONFIG_IDF_TARGET_ESP32S2
const int8_t esp32_adc2gpio[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
#endif
const DRAM_ATTR esp32_gpioMux_t esp32_gpioMux[SOC_GPIO_PIN_COUNT]={
#if CONFIG_IDF_TARGET_ESP32
const DRAM_ATTR esp32_gpioMux_t esp32_gpioMux[GPIO_PIN_COUNT]={
{0x44, 11, 11, 1},
{0x88, -1, -1, -1},
{0x40, 12, 12, 2},
@ -94,56 +79,6 @@ const DRAM_ATTR esp32_gpioMux_t esp32_gpioMux[SOC_GPIO_PIN_COUNT]={
{0x08, 1, 1, -1},
{0x0c, 2, 2, -1},
{0x10, 3, 3, -1}
#elif CONFIG_IDF_TARGET_ESP32S2
{0x04, 0, -1, -1},
{0x08, 1, 0, 1},
{0x0c, 2, 1, 2},
{0x10, 3, 2, 3},
{0x14, 4, 3, 4},
{0x18, 5, 4, 5},
{0x1c, 6, 5, 6},
{0x20, 7, 6, 7},
{0x24, 8, 7, 8},
{0x28, 9, 8, 9},//FSPI_HD
{0x2c, 10, 9, 10},//FSPI_CS0 / FSPI_D4
{0x30, 11, 10, 11},//FSPI_D / FSPI_D5
{0x34, 12, 11, 12},//FSPI_CLK / FSPI_D6
{0x38, 13, 12, 13},//FSPI_Q / FSPI_D7
{0x3c, 14, 13, 14},//FSPI_WP / FSPI_DQS
{0x40, 15, 14, -1},//32K+ / RTS0
{0x44, 16, 15, -1},//32K- / CTS0
{0x48, 17, 16, -1},//DAC1 / TXD1
{0x4c, 18, 17, -1},//DAC2 / RXD1
{0x50, 19, 18, -1},//USB D- / RTS1
{0x54, 20, 19, -1},//USB D+ / CTS1
{0x58, 21, -1, -1},//SDA?
{ 0, -1, -1, -1},//UNAVAILABLE
{ 0, -1, -1, -1},//UNAVAILABLE
{ 0, -1, -1, -1},//UNAVAILABLE
{ 0, -1, -1, -1},//UNAVAILABLE
{0x6c, -1, -1, -1},//RESERVED SPI_CS1
{0x70, -1, -1, -1},//RESERVED SPI_HD
{0x74, -1, -1, -1},//RESERVED SPI_WP
{0x78, -1, -1, -1},//RESERVED SPI_CS0
{0x7c, -1, -1, -1},//RESERVED SPI_CLK
{0x80, -1, -1, -1},//RESERVED SPI_Q
{0x84, -1, -1, -1},//RESERVED SPI_D
{0x88, -1, -1, -1},//FSPI_HD
{0x8c, -1, -1, -1},//FSPI_CS0
{0x90, -1, -1, -1},//FSPI_D
{0x94, -1, -1, -1},//FSPI_CLK
{0x98, -1, -1, -1},//FSPI_Q
{0x9c, -1, -1, -1},//FSPI_WP
{0xa0, -1, -1, -1},//MTCK
{0xa4, -1, -1, -1},//MTDO
{0xa8, -1, -1, -1},//MTDI
{0xac, -1, -1, -1},//MTMS
{0xb0, -1, -1, -1},//TXD0
{0xb4, -1, -1, -1},//RXD0
{0xb8, -1, -1, -1},//SCL?
{0xbc, -1, -1, -1},//INPUT ONLY
{0, -1, -1, -1}
#endif
};
typedef void (*voidFuncPtr)(void);
@ -153,95 +88,56 @@ typedef struct {
void* arg;
bool functional;
} InterruptHandle_t;
static InterruptHandle_t __pinInterruptHandlers[SOC_GPIO_PIN_COUNT] = {0,};
static InterruptHandle_t __pinInterruptHandlers[GPIO_PIN_COUNT] = {0,};
#include "driver/rtc_io.h"
extern void ARDUINO_ISR_ATTR __pinMode(uint8_t pin, uint8_t mode)
extern void IRAM_ATTR __pinMode(uint8_t pin, uint8_t mode)
{
#if USE_ESP_IDF_GPIO
if (!GPIO_IS_VALID_GPIO(pin)) {
return;
}
gpio_config_t conf = {
.pin_bit_mask = (1ULL<<pin), /*!< GPIO pin: set with bit mask, each bit maps to a GPIO */
.mode = GPIO_MODE_DISABLE, /*!< GPIO mode: set input/output mode */
.pull_up_en = GPIO_PULLUP_DISABLE, /*!< GPIO pull-up */
.pull_down_en = GPIO_PULLDOWN_DISABLE, /*!< GPIO pull-down */
.intr_type = GPIO_INTR_DISABLE /*!< GPIO interrupt type */
};
if (mode < 0x20) {//io
conf.mode = mode & (INPUT | OUTPUT);
if (mode & OPEN_DRAIN) {
conf.mode |= GPIO_MODE_DEF_OD;
}
if (mode & PULLUP) {
conf.pull_up_en = GPIO_PULLUP_ENABLE;
}
if (mode & PULLDOWN) {
conf.pull_down_en = GPIO_PULLDOWN_ENABLE;
}
}
gpio_config(&conf);
if(mode == SPECIAL){
#if CONFIG_IDF_TARGET_ESP32
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[pin], (uint32_t)(((pin)==RX||(pin)==TX)?0:1));
#elif CONFIG_IDF_TARGET_ESP32S2
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[pin], (uint32_t)(((pin)==RX||(pin)==TX)?0:2));
#endif
} else if(mode == ANALOG){
#if !CONFIG_IDF_TARGET_ESP32C3
//adc_gpio_init(ADC_UNIT_1, ADC_CHANNEL_0);
#endif
} else if(mode >= 0x20 && mode < ANALOG) {//function
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[pin], mode >> 5);
}
#else
if(!digitalPinIsValid(pin)) {
return;
}
int8_t rtc_io = esp32_gpioMux[pin].rtc;
uint32_t rtc_reg = (rtc_io != -1)?rtc_io_desc[rtc_io].reg:0;
uint32_t rtc_reg = rtc_gpio_desc[pin].reg;
if(mode == ANALOG) {
if(!rtc_reg) {
return;//not rtc pin
}
#if CONFIG_IDF_TARGET_ESP32S2
SENS.sar_io_mux_conf.iomux_clk_gate_en = 1;
#endif
SET_PERI_REG_MASK(rtc_io_desc[rtc_io].reg, (rtc_io_desc[rtc_io].mux));
SET_PERI_REG_BITS(rtc_io_desc[rtc_io].reg, RTC_IO_TOUCH_PAD1_FUN_SEL_V, 0, rtc_io_desc[rtc_io].func);
RTCIO.pin[rtc_io].pad_driver = 0;//OD = 1
RTCIO.enable_w1tc.w1tc = (1U << rtc_io);
CLEAR_PERI_REG_MASK(rtc_io_desc[rtc_io].reg, rtc_io_desc[rtc_io].ie);
if (rtc_io_desc[rtc_io].pullup) {
CLEAR_PERI_REG_MASK(rtc_io_desc[rtc_io].reg, rtc_io_desc[rtc_io].pullup);
//lock rtc
uint32_t reg_val = ESP_REG(rtc_reg);
if(reg_val & rtc_gpio_desc[pin].mux){
return;//already in adc mode
}
if (rtc_io_desc[rtc_io].pulldown) {
CLEAR_PERI_REG_MASK(rtc_io_desc[rtc_io].reg, rtc_io_desc[rtc_io].pulldown);
}
ESP_REG(DR_REG_IO_MUX_BASE + esp32_gpioMux[pin].reg) = ((uint32_t)GPIO_FUNC << MCU_SEL_S) | ((uint32_t)2 << FUN_DRV_S) | FUN_IE;
reg_val &= ~(
(RTC_IO_TOUCH_PAD1_FUN_SEL_V << rtc_gpio_desc[pin].func)
|rtc_gpio_desc[pin].ie
|rtc_gpio_desc[pin].pullup
|rtc_gpio_desc[pin].pulldown);
ESP_REG(RTC_GPIO_ENABLE_W1TC_REG) = (1 << (rtc_gpio_desc[pin].rtc_num + RTC_GPIO_ENABLE_W1TC_S));
ESP_REG(rtc_reg) = reg_val | rtc_gpio_desc[pin].mux;
//unlock rtc
ESP_REG(DR_REG_IO_MUX_BASE + esp32_gpioMux[pin].reg) = ((uint32_t)2 << MCU_SEL_S) | ((uint32_t)2 << FUN_DRV_S) | FUN_IE;
return;
}
//RTC pins PULL settings
if(rtc_reg) {
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[rtc_io].mux);
//lock rtc
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].mux);
if(mode & PULLUP) {
ESP_REG(rtc_reg) = (ESP_REG(rtc_reg) | rtc_io_desc[rtc_io].pullup) & ~(rtc_io_desc[rtc_io].pulldown);
ESP_REG(rtc_reg) = (ESP_REG(rtc_reg) | rtc_gpio_desc[pin].pullup) & ~(rtc_gpio_desc[pin].pulldown);
} else if(mode & PULLDOWN) {
ESP_REG(rtc_reg) = (ESP_REG(rtc_reg) | rtc_io_desc[rtc_io].pulldown) & ~(rtc_io_desc[rtc_io].pullup);
ESP_REG(rtc_reg) = (ESP_REG(rtc_reg) | rtc_gpio_desc[pin].pulldown) & ~(rtc_gpio_desc[pin].pullup);
} else {
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[rtc_io].pullup | rtc_io_desc[rtc_io].pulldown);
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown);
}
//unlock rtc
}
uint32_t pinFunction = 0, pinControl = 0;
//lock gpio
if(mode & INPUT) {
if(pin < 32) {
GPIO.enable_w1tc = ((uint32_t)1 << pin);
@ -249,8 +145,9 @@ extern void ARDUINO_ISR_ATTR __pinMode(uint8_t pin, uint8_t mode)
GPIO.enable1_w1tc.val = ((uint32_t)1 << (pin - 32));
}
} else if(mode & OUTPUT) {
if(pin >= NUM_OUPUT_PINS){
return;
if(pin > 33){
//unlock gpio
return;//pins above 33 can be only inputs
} else if(pin < 32) {
GPIO.enable_w1ts = ((uint32_t)1 << pin);
} else {
@ -268,13 +165,9 @@ extern void ARDUINO_ISR_ATTR __pinMode(uint8_t pin, uint8_t mode)
pinFunction |= FUN_IE;//input enable but required for output as well?
if(mode & (INPUT | OUTPUT)) {
pinFunction |= ((uint32_t)PIN_FUNC_GPIO << MCU_SEL_S);
pinFunction |= ((uint32_t)2 << MCU_SEL_S);
} else if(mode == SPECIAL) {
#if CONFIG_IDF_TARGET_ESP32
pinFunction |= ((uint32_t)(((pin)==RX||(pin)==TX)?0:1) << MCU_SEL_S);
#elif CONFIG_IDF_TARGET_ESP32S2
pinFunction |= ((uint32_t)(((pin)==RX||(pin)==TX)?0:2) << MCU_SEL_S);
#endif
pinFunction |= ((uint32_t)(((pin)==1||(pin)==3)?0:1) << MCU_SEL_S);
} else {
pinFunction |= ((uint32_t)(mode >> 5) << MCU_SEL_S);
}
@ -286,67 +179,39 @@ extern void ARDUINO_ISR_ATTR __pinMode(uint8_t pin, uint8_t mode)
}
GPIO.pin[pin].val = pinControl;
#endif
//unlock gpio
}
extern void ARDUINO_ISR_ATTR __digitalWrite(uint8_t pin, uint8_t val)
extern void IRAM_ATTR __digitalWrite(uint8_t pin, uint8_t val)
{
#if USE_ESP_IDF_GPIO
gpio_set_level((gpio_num_t)pin, val);
#elif CONFIG_IDF_TARGET_ESP32C3
if (val) {
GPIO.out_w1ts.out_w1ts = (1 << pin);
} else {
GPIO.out_w1tc.out_w1tc = (1 << pin);
}
#else
if(val) {
if(pin < 32) {
GPIO.out_w1ts = ((uint32_t)1 << pin);
} else if(pin < NUM_OUPUT_PINS) {
} else if(pin < 34) {
GPIO.out1_w1ts.val = ((uint32_t)1 << (pin - 32));
}
} else {
if(pin < 32) {
GPIO.out_w1tc = ((uint32_t)1 << pin);
} else if(pin < NUM_OUPUT_PINS) {
} else if(pin < 34) {
GPIO.out1_w1tc.val = ((uint32_t)1 << (pin - 32));
}
}
#endif
}
extern int ARDUINO_ISR_ATTR __digitalRead(uint8_t pin)
extern int IRAM_ATTR __digitalRead(uint8_t pin)
{
#if USE_ESP_IDF_GPIO
return gpio_get_level((gpio_num_t)pin);
#elif CONFIG_IDF_TARGET_ESP32C3
return (GPIO.in.data >> pin) & 0x1;
#else
if(pin < 32) {
return (GPIO.in >> pin) & 0x1;
} else if(pin < GPIO_PIN_COUNT) {
} else if(pin < 40) {
return (GPIO.in1.val >> (pin - 32)) & 0x1;
}
return 0;
#endif
}
#if USE_ESP_IDF_GPIO
static void ARDUINO_ISR_ATTR __onPinInterrupt(void * arg) {
InterruptHandle_t * isr = (InterruptHandle_t*)arg;
if(isr->fn) {
if(isr->arg){
((voidFuncPtrArg)isr->fn)(isr->arg);
} else {
isr->fn();
}
}
}
#else
static intr_handle_t gpio_intr_handle = NULL;
static void ARDUINO_ISR_ATTR __onPinInterrupt()
static void IRAM_ATTR __onPinInterrupt()
{
uint32_t gpio_intr_status_l=0;
uint32_t gpio_intr_status_h=0;
@ -385,7 +250,6 @@ static void ARDUINO_ISR_ATTR __onPinInterrupt()
} while(++pin<GPIO_PIN_COUNT);
}
}
#endif
extern void cleanupFunctional(void* arg);
@ -394,17 +258,8 @@ extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc,
static bool interrupt_initialized = false;
if(!interrupt_initialized) {
#if USE_ESP_IDF_GPIO
esp_err_t err = gpio_install_isr_service((int)ARDUINO_ISR_FLAG);
interrupt_initialized = (err == ESP_OK) || (err == ESP_ERR_INVALID_STATE);
#else
interrupt_initialized = true;
esp_intr_alloc(ETS_GPIO_INTR_SOURCE, (int)ARDUINO_ISR_FLAG, __onPinInterrupt, NULL, &gpio_intr_handle);
#endif
}
if(!interrupt_initialized) {
log_e("GPIO ISR Service Failed To Start");
return;
esp_intr_alloc(ETS_GPIO_INTR_SOURCE, (int)ESP_INTR_FLAG_IRAM, __onPinInterrupt, NULL, &gpio_intr_handle);
}
// if new attach without detach remove old info
@ -416,27 +271,14 @@ extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc,
__pinInterruptHandlers[pin].arg = arg;
__pinInterruptHandlers[pin].functional = functional;
#if USE_ESP_IDF_GPIO
gpio_set_intr_type((gpio_num_t)pin, (gpio_int_type_t)(intr_type & 0x7));
if(intr_type & 0x8){
gpio_wakeup_enable((gpio_num_t)pin, (gpio_int_type_t)(intr_type & 0x7));
}
gpio_isr_handler_add((gpio_num_t)pin, __onPinInterrupt, &__pinInterruptHandlers[pin]);
gpio_intr_enable((gpio_num_t)pin);
#else
esp_intr_disable(gpio_intr_handle);
#if CONFIG_IDF_TARGET_ESP32
if(esp_intr_get_cpu(gpio_intr_handle)) { //APP_CPU
#endif
GPIO.pin[pin].int_ena = 1;
#if CONFIG_IDF_TARGET_ESP32
} else { //PRO_CPU
GPIO.pin[pin].int_ena = 4;
}
#endif
GPIO.pin[pin].int_type = intr_type;
esp_intr_enable(gpio_intr_handle);
#endif
}
extern void __attachInterruptArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type)
@ -450,13 +292,7 @@ extern void __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int intr_type)
extern void __detachInterrupt(uint8_t pin)
{
#if USE_ESP_IDF_GPIO
gpio_intr_disable((gpio_num_t)pin);
gpio_isr_handler_remove((gpio_num_t)pin);
gpio_wakeup_disable((gpio_num_t)pin);
#else
esp_intr_disable(gpio_intr_handle);
#endif
if (__pinInterruptHandlers[pin].functional && __pinInterruptHandlers[pin].arg)
{
cleanupFunctional(__pinInterruptHandlers[pin].arg);
@ -465,13 +301,9 @@ extern void __detachInterrupt(uint8_t pin)
__pinInterruptHandlers[pin].arg = NULL;
__pinInterruptHandlers[pin].functional = false;
#if USE_ESP_IDF_GPIO
gpio_set_intr_type((gpio_num_t)pin, GPIO_INTR_DISABLE);
#else
GPIO.pin[pin].int_ena = 0;
GPIO.pin[pin].int_type = 0;
esp_intr_enable(gpio_intr_handle);
#endif
}

View File

@ -25,17 +25,6 @@ extern "C" {
#endif
#include "esp32-hal.h"
#include "soc/soc_caps.h"
#if (CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3)
#define NUM_OUPUT_PINS 46
#define PIN_DAC1 17
#define PIN_DAC2 18
#else
#define NUM_OUPUT_PINS 34
#define PIN_DAC1 25
#define PIN_DAC2 26
#endif
#define LOW 0x0
#define HIGH 0x1
@ -75,15 +64,15 @@ typedef struct {
int8_t touch; /*!< Touch Channel number (-1 if not Touch pin) */
} esp32_gpioMux_t;
extern const esp32_gpioMux_t esp32_gpioMux[SOC_GPIO_PIN_COUNT];
extern const esp32_gpioMux_t esp32_gpioMux[40];
extern const int8_t esp32_adc2gpio[20];
#define digitalPinIsValid(pin) ((pin) < SOC_GPIO_PIN_COUNT && esp32_gpioMux[(pin)].reg)
#define digitalPinCanOutput(pin) ((pin) < NUM_OUPUT_PINS && esp32_gpioMux[(pin)].reg)
#define digitalPinToRtcPin(pin) (((pin) < SOC_GPIO_PIN_COUNT)?esp32_gpioMux[(pin)].rtc:-1)
#define digitalPinToAnalogChannel(pin) (((pin) < SOC_GPIO_PIN_COUNT)?esp32_gpioMux[(pin)].adc:-1)
#define digitalPinToTouchChannel(pin) (((pin) < SOC_GPIO_PIN_COUNT)?esp32_gpioMux[(pin)].touch:-1)
#define digitalPinToDacChannel(pin) (((pin) == PIN_DAC1)?0:((pin) == PIN_DAC2)?1:-1)
#define digitalPinIsValid(pin) ((pin) < 40 && esp32_gpioMux[(pin)].reg)
#define digitalPinCanOutput(pin) ((pin) < 34 && esp32_gpioMux[(pin)].reg)
#define digitalPinToRtcPin(pin) (((pin) < 40)?esp32_gpioMux[(pin)].rtc:-1)
#define digitalPinToAnalogChannel(pin) (((pin) < 40)?esp32_gpioMux[(pin)].adc:-1)
#define digitalPinToTouchChannel(pin) (((pin) < 40)?esp32_gpioMux[(pin)].touch:-1)
#define digitalPinToDacChannel(pin) (((pin) == 25)?0:((pin) == 26)?1:-1)
void pinMode(uint8_t pin, uint8_t mode);
void digitalWrite(uint8_t pin, uint8_t val);

View File

@ -1,848 +0,0 @@
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <inttypes.h>
#include <string.h>
#include <math.h>
#include "sdkconfig.h"
#include "esp_attr.h"
#include "rom/gpio.h"
#include "soc/gpio_sig_map.h"
#include "hal/gpio_types.h"
#include "driver/gpio.h"
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "freertos/ringbuf.h"
#include "esp_intr_alloc.h"
#include "driver/periph_ctrl.h"
#include "soc/i2c_reg.h"
#include "soc/i2c_struct.h"
#include "hal/i2c_ll.h"
#include "esp32-hal-log.h"
#include "esp32-hal-i2c-slave.h"
#define I2C_SLAVE_USE_RX_QUEUE 0 // 1: Queue, 0: RingBuffer
#if SOC_I2C_NUM > 1
#define I2C_SCL_IDX(p) ((p==0)?I2CEXT0_SCL_OUT_IDX:((p==1)?I2CEXT1_SCL_OUT_IDX:0))
#define I2C_SDA_IDX(p) ((p==0)?I2CEXT0_SDA_OUT_IDX:((p==1)?I2CEXT1_SDA_OUT_IDX:0))
#else
#define I2C_SCL_IDX(p) I2CEXT0_SCL_OUT_IDX
#define I2C_SDA_IDX(p) I2CEXT0_SDA_OUT_IDX
#endif
#if CONFIG_IDF_TARGET_ESP32
#define I2C_TXFIFO_WM_INT_ENA I2C_TXFIFO_EMPTY_INT_ENA
#define I2C_RXFIFO_WM_INT_ENA I2C_RXFIFO_FULL_INT_ENA
#endif
enum {
I2C_SLAVE_EVT_RX, I2C_SLAVE_EVT_TX
};
typedef struct i2c_slave_struct_t {
i2c_dev_t * dev;
uint8_t num;
int8_t sda;
int8_t scl;
i2c_slave_request_cb_t request_callback;
i2c_slave_receive_cb_t receive_callback;
void * arg;
intr_handle_t intr_handle;
TaskHandle_t task_handle;
xQueueHandle event_queue;
#if I2C_SLAVE_USE_RX_QUEUE
xQueueHandle rx_queue;
#else
RingbufHandle_t rx_ring_buf;
#endif
xQueueHandle tx_queue;
uint32_t rx_data_count;
#if !CONFIG_DISABLE_HAL_LOCKS
xSemaphoreHandle lock;
#endif
} i2c_slave_struct_t;
typedef union {
struct {
uint32_t event : 2;
uint32_t stop : 1;
uint32_t param : 29;
};
uint32_t val;
} i2c_slave_queue_event_t;
static i2c_slave_struct_t _i2c_bus_array[SOC_I2C_NUM] = {
{ &I2C0, 0, -1, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0
#if !CONFIG_DISABLE_HAL_LOCKS
, NULL
#endif
},
#if SOC_I2C_NUM > 1
{ &I2C1, 1, -1, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0
#if !CONFIG_DISABLE_HAL_LOCKS
, NULL
#endif
}
#endif
};
#if CONFIG_DISABLE_HAL_LOCKS
#define I2C_SLAVE_MUTEX_LOCK()
#define I2C_SLAVE_MUTEX_UNLOCK()
#else
#define I2C_SLAVE_MUTEX_LOCK() if(i2c->lock){xSemaphoreTake(i2c->lock, portMAX_DELAY);}
#define I2C_SLAVE_MUTEX_UNLOCK() if(i2c->lock){xSemaphoreGive(i2c->lock);}
#endif
//-------------------------------------- HAL_LL (Missing Functions) ------------------------------------------------
typedef enum {
I2C_STRETCH_CAUSE_MASTER_READ,
I2C_STRETCH_CAUSE_TX_FIFO_EMPTY,
I2C_STRETCH_CAUSE_RX_FIFO_FULL,
I2C_STRETCH_CAUSE_MAX
} i2c_stretch_cause_t;
static inline i2c_stretch_cause_t i2c_ll_stretch_cause(i2c_dev_t *hw)
{
#if CONFIG_IDF_TARGET_ESP32C3
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, 32000);
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

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

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// 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_
@ -23,16 +22,58 @@ extern "C" {
#include <stdint.h>
#include <stdbool.h>
#include <esp_err.h>
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
esp_err_t i2cInit(uint8_t i2c_num, int8_t sda, int8_t scl, uint32_t clk_speed);
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);
// 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
#ifdef __cplusplus
}

View File

@ -17,26 +17,14 @@
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp32-hal-matrix.h"
#include "soc/soc_caps.h"
#include "soc/dport_reg.h"
#include "soc/ledc_reg.h"
#include "soc/ledc_struct.h"
#include "driver/periph_ctrl.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
@ -116,13 +104,10 @@ static void _ledcSetupTimer(uint8_t chan, uint32_t div_num, uint8_t bit_num, boo
uint8_t group=(chan/8), timer=((chan/2)%4);
static bool tHasStarted = false;
static uint16_t _activeChannels = 0;
#if CONFIG_IDF_TARGET_ESP32S2
// ESP32-S2 TRM v1.0 on Page 789 -> BIT LEDC_TICK_SEL_TIMERx is 0 for LEDC_PWM_CLK and 1 for REF_TICK
apb_clk = 0;
#endif
if(!tHasStarted) {
tHasStarted = true;
periph_module_enable(PERIPH_LEDC_MODULE);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_LEDC_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_LEDC_RST);
LEDC.conf.apb_clk_sel = 1;//LS use apb clock
addApbChangeCallback((void*)&_activeChannels, _on_apb_change);
@ -134,13 +119,9 @@ static void _ledcSetupTimer(uint8_t chan, uint32_t div_num, uint8_t bit_num, boo
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;
@ -205,21 +186,17 @@ static void _ledcSetupChannel(uint8_t chan, uint8_t idle_level)
LEDC_CHAN(group, channel).duty.duty = 0;
LEDC_CHAN(group, channel).conf0.sig_out_en = 0;//This is the output enable control bit for channel
LEDC_CHAN(group, channel).conf1.duty_start = 0;//When duty_num duty_cycle and duty_scale has been configured. these register won't take effect until set duty_start. this bit is automatically cleared by hardware.
#if CONFIG_IDF_TARGET_ESP32
if(group) {
#endif
LEDC_CHAN(group, channel).conf0.low_speed_update = 1;
#if CONFIG_IDF_TARGET_ESP32
} else {
LEDC_CHAN(group, channel).conf0.clk_en = 0;
}
#endif
LEDC_MUTEX_UNLOCK();
}
double ledcSetup(uint8_t chan, double freq, uint8_t bit_num)
{
if(chan > LAST_CHAN) {
if(chan > 15) {
return 0;
}
double res_freq = _ledcSetupTimerFreq(chan, freq, bit_num);
@ -229,7 +206,7 @@ double ledcSetup(uint8_t chan, double freq, uint8_t bit_num)
void ledcWrite(uint8_t chan, uint32_t duty)
{
if(chan > LAST_CHAN) {
if(chan > 15) {
return;
}
uint8_t group=(chan/8), channel=(chan%8);
@ -238,34 +215,26 @@ void ledcWrite(uint8_t chan, uint32_t duty)
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
}
LEDC_MUTEX_UNLOCK();
}
uint32_t ledcRead(uint8_t chan)
{
if(chan > LAST_CHAN) {
if(chan > 15) {
return 0;
}
return LEDC.channel_group[chan/8].channel[chan%8].duty.duty >> 4;
@ -281,7 +250,7 @@ double ledcReadFreq(uint8_t chan)
double ledcWriteTone(uint8_t chan, double freq)
{
if(chan > LAST_CHAN) {
if(chan > 15) {
return 0;
}
if(!freq) {
@ -308,45 +277,14 @@ 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 > 15) {
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
}
void ledcDetachPin(uint8_t pin)
{
pinMatrixOutDetach(pin, false, false);
}
double ledcChangeFrequency(uint8_t chan, double freq, uint8_t bit_num)
{
if (chan > 15) {
return 0;
}
double res_freq = _ledcSetupTimerFreq(chan, freq, bit_num);
return res_freq;
}
static int8_t pin_to_channel[SOC_GPIO_PIN_COUNT] = { 0 };
static int cnt_channel = SOC_LEDC_CHANNEL_NUM;
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", SOC_LEDC_CHANNEL_NUM);
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

@ -35,7 +35,6 @@ uint32_t ledcRead(uint8_t channel);
double ledcReadFreq(uint8_t channel);
void ledcAttachPin(uint8_t pin, uint8_t channel);
void ledcDetachPin(uint8_t pin);
double ledcChangeFrequency(uint8_t channel, double freq, uint8_t resolution_bits);
#ifdef __cplusplus

View File

@ -20,7 +20,6 @@ extern "C"
#endif
#include "sdkconfig.h"
#include "esp_timer.h"
#define ARDUHAL_LOG_LEVEL_NONE (0)
#define ARDUHAL_LOG_LEVEL_ERROR (1)
@ -37,9 +36,6 @@ extern "C"
#define ARDUHAL_LOG_LEVEL CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL
#else
#define ARDUHAL_LOG_LEVEL CORE_DEBUG_LEVEL
#ifdef USE_ESP_IDF_LOG
#define LOG_LOCAL_LEVEL CORE_DEBUG_LEVEL
#endif
#endif
#ifndef CONFIG_ARDUHAL_LOG_COLORS
@ -66,8 +62,6 @@ 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
@ -75,123 +69,64 @@ 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__
#define ARDUHAL_LOG_FORMAT(letter, format) ARDUHAL_LOG_COLOR_ ## letter "[" #letter "][%s:%u] %s(): " format ARDUHAL_LOG_RESET_COLOR "\r\n", pathToFileName(__FILE__), __LINE__, __FUNCTION__
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
#ifndef USE_ESP_IDF_LOG
#define log_v(format, ...) log_printf(ARDUHAL_LOG_FORMAT(V, format), ##__VA_ARGS__)
#define 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, ...) do {} while(0)
#define isr_log_v(format, ...) do {} while(0)
#define log_buf_v(b,l) do {} while(0)
#define log_v(format, ...)
#define isr_log_v(format, ...)
#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, ...) do {} while(0)
#define isr_log_d(format, ...) do {} while(0)
#define log_buf_d(b,l) do {} while(0)
#define log_d(format, ...)
#define isr_log_d(format, ...)
#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, ...) do {} while(0)
#define isr_log_i(format, ...) do {} while(0)
#define log_buf_i(b,l) do {} while(0)
#define log_i(format, ...)
#define isr_log_i(format, ...)
#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, ...) do {} while(0)
#define isr_log_w(format, ...) do {} while(0)
#define log_buf_w(b,l) do {} while(0)
#define log_w(format, ...)
#define isr_log_w(format, ...)
#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, ...) do {} while(0)
#define isr_log_e(format, ...) do {} while(0)
#define log_buf_e(b,l) do {} while(0)
#define log_e(format, ...)
#define isr_log_e(format, ...)
#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, ...) do {} while(0)
#define isr_log_n(format, ...) do {} while(0)
#define log_buf_n(b,l) do {} while(0)
#define log_n(format, ...)
#define isr_log_n(format, ...)
#endif
#include "esp_log.h"
#ifdef USE_ESP_IDF_LOG
#ifndef TAG
#define TAG "ARDUINO"
#endif
//#define log_n(format, ...) myLog(ESP_LOG_NONE, format, ##__VA_ARGS__)
#else
#ifdef CONFIG_ARDUHAL_ESP_LOG
#undef ESP_LOGE
#undef ESP_LOGW
@ -215,7 +150,6 @@ void log_print_buf(const uint8_t *b, size_t len);
#define ESP_EARLY_LOGD(tag, ...) isr_log_d(__VA_ARGS__)
#define ESP_EARLY_LOGV(tag, ...) isr_log_v(__VA_ARGS__)
#endif
#endif
#ifdef __cplusplus
}

View File

@ -19,10 +19,6 @@
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
#include "esp32/rom/gpio.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/gpio.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/gpio.h"
#else
#error Target CONFIG_IDF_TARGET is not supported
#endif
@ -34,27 +30,27 @@
#define MATRIX_DETACH_IN_LOW_PIN 0x30
#define MATRIX_DETACH_IN_LOW_HIGH 0x38
void ARDUINO_ISR_ATTR pinMatrixOutAttach(uint8_t pin, uint8_t function, bool invertOut, bool invertEnable)
void IRAM_ATTR pinMatrixOutAttach(uint8_t pin, uint8_t function, bool invertOut, bool invertEnable)
{
gpio_matrix_out(pin, function, invertOut, invertEnable);
}
void ARDUINO_ISR_ATTR pinMatrixOutDetach(uint8_t pin, bool invertOut, bool invertEnable)
void IRAM_ATTR pinMatrixOutDetach(uint8_t pin, bool invertOut, bool invertEnable)
{
gpio_matrix_out(pin, MATRIX_DETACH_OUT_SIG, invertOut, invertEnable);
}
void ARDUINO_ISR_ATTR pinMatrixInAttach(uint8_t pin, uint8_t signal, bool inverted)
void IRAM_ATTR pinMatrixInAttach(uint8_t pin, uint8_t signal, bool inverted)
{
gpio_matrix_in(pin, signal, inverted);
}
void ARDUINO_ISR_ATTR pinMatrixInDetach(uint8_t signal, bool high, bool inverted)
void IRAM_ATTR pinMatrixInDetach(uint8_t signal, bool high, bool inverted)
{
gpio_matrix_in(high?MATRIX_DETACH_IN_LOW_HIGH:MATRIX_DETACH_IN_LOW_PIN, signal, inverted);
}
/*
void ARDUINO_ISR_ATTR intrMatrixAttach(uint32_t source, uint32_t inum){
void IRAM_ATTR intrMatrixAttach(uint32_t source, uint32_t inum){
intr_matrix_set(PRO_CPU_NUM, source, inum);
}
*/

View File

@ -38,12 +38,6 @@
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
#include "esp32/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/rtc.h"
#include "driver/temp_sensor.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/rtc.h"
#include "driver/temp_sensor.h"
#else
#error Target CONFIG_IDF_TARGET is not supported
#endif
@ -53,25 +47,12 @@
//Undocumented!!! Get chip temperature in Farenheit
//Source: https://github.com/pcbreflux/espressif/blob/master/esp32/arduino/sketchbook/ESP32_int_temp_sensor/ESP32_int_temp_sensor.ino
#ifdef CONFIG_IDF_TARGET_ESP32
uint8_t temprature_sens_read();
float temperatureRead()
{
return (temprature_sens_read() - 32) / 1.8;
}
#else
float temperatureRead()
{
float result = NAN;
temp_sensor_config_t tsens = TSENS_CONFIG_DEFAULT();
temp_sensor_set_config(tsens);
temp_sensor_start();
temp_sensor_read_celsius(&result);
temp_sensor_stop();
return result;
}
#endif
void __yield()
{
@ -160,12 +141,12 @@ BaseType_t xTaskCreateUniversal( TaskFunction_t pxTaskCode,
#endif
}
unsigned long ARDUINO_ISR_ATTR micros()
unsigned long IRAM_ATTR micros()
{
return (unsigned long) (esp_timer_get_time());
}
unsigned long ARDUINO_ISR_ATTR millis()
unsigned long IRAM_ATTR millis()
{
return (unsigned long) (esp_timer_get_time() / 1000ULL);
}
@ -175,17 +156,17 @@ void delay(uint32_t ms)
vTaskDelay(ms / portTICK_PERIOD_MS);
}
void ARDUINO_ISR_ATTR delayMicroseconds(uint32_t us)
void IRAM_ATTR delayMicroseconds(uint32_t us)
{
uint64_t m = (uint64_t)esp_timer_get_time();
uint32_t m = micros();
if(us){
uint64_t e = (m + us);
uint32_t e = (m + us);
if(m > e){ //overflow
while((uint64_t)esp_timer_get_time() > e){
while(micros() > e){
NOP();
}
}
while((uint64_t)esp_timer_get_time() < e){
while(micros() < e){
NOP();
}
}
@ -227,7 +208,7 @@ void initArduino()
#ifdef F_CPU
setCpuFrequencyMhz(F_CPU/1000000);
#endif
#if CONFIG_SPIRAM_SUPPORT || CONFIG_SPIRAM
#if CONFIG_SPIRAM_SUPPORT
psramInit();
#endif
esp_log_level_set("*", CONFIG_LOG_DEFAULT_LEVEL);
@ -256,7 +237,7 @@ void initArduino()
}
//used by hal log
const char * ARDUINO_ISR_ATTR pathToFileName(const char * path)
const char * IRAM_ATTR pathToFileName(const char * path)
{
size_t i = 0;
size_t pos = 0;

View File

@ -14,7 +14,7 @@
#include "esp32-hal.h"
#if CONFIG_SPIRAM_SUPPORT || CONFIG_SPIRAM
#if CONFIG_SPIRAM_SUPPORT
#include "soc/efuse_reg.h"
#include "esp_heap_caps.h"
@ -22,9 +22,6 @@
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
#include "esp32/spiram.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/spiram.h"
#include "esp32s2/rom/cache.h"
#else
#error Target CONFIG_IDF_TARGET is not supported
#endif
@ -43,7 +40,6 @@ bool psramInit(){
if (spiramFailed) {
return false;
}
#if CONFIG_IDF_TARGET_ESP32
uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_PKG);
uint32_t pkg_ver = chip_ver & 0x7;
if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5 || pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2) {
@ -51,21 +47,14 @@ bool psramInit(){
log_w("PSRAM not supported!");
return false;
}
#elif CONFIG_IDF_TARGET_ESP32S2
extern void esp_config_data_cache_mode(void);
esp_config_data_cache_mode();
Cache_Enable_DCache(0);
#endif
esp_spiram_init_cache();
if (esp_spiram_init() != ESP_OK) {
spiramFailed = true;
log_w("PSRAM init failed!");
#if CONFIG_IDF_TARGET_ESP32
pinMatrixOutDetach(16, false, false);
pinMatrixOutDetach(17, false, false);
#endif
return false;
}
esp_spiram_init_cache();
if (!esp_spiram_test()) {
spiramFailed = true;
log_e("PSRAM test failed!");
@ -76,34 +65,31 @@ bool psramInit(){
log_e("PSRAM could not be added to the heap!");
return false;
}
#if CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL && !CONFIG_ARDUINO_ISR_IRAM
heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL);
#endif
#endif
spiramDetected = true;
log_d("PSRAM enabled");
return true;
}
bool ARDUINO_ISR_ATTR psramFound(){
bool IRAM_ATTR psramFound(){
return spiramDetected;
}
void ARDUINO_ISR_ATTR *ps_malloc(size_t size){
void IRAM_ATTR *ps_malloc(size_t size){
if(!spiramDetected){
return NULL;
}
return heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
}
void ARDUINO_ISR_ATTR *ps_calloc(size_t n, size_t size){
void IRAM_ATTR *ps_calloc(size_t n, size_t size){
if(!spiramDetected){
return NULL;
}
return heap_caps_calloc(n, size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
}
void ARDUINO_ISR_ATTR *ps_realloc(void *ptr, size_t size){
void IRAM_ATTR *ps_realloc(void *ptr, size_t size){
if(!spiramDetected){
return NULL;
}
@ -116,19 +102,19 @@ bool psramInit(){
return false;
}
bool ARDUINO_ISR_ATTR psramFound(){
bool IRAM_ATTR psramFound(){
return false;
}
void ARDUINO_ISR_ATTR *ps_malloc(size_t size){
void IRAM_ATTR *ps_malloc(size_t size){
return NULL;
}
void ARDUINO_ISR_ATTR *ps_calloc(size_t n, size_t size){
void IRAM_ATTR *ps_calloc(size_t n, size_t size){
return NULL;
}
void ARDUINO_ISR_ATTR *ps_realloc(void *ptr, size_t size){
void IRAM_ATTR *ps_realloc(void *ptr, size_t size){
return NULL;
}

View File

@ -19,17 +19,6 @@
extern "C" {
#endif
#include "sdkconfig.h"
#ifndef BOARD_HAS_PSRAM
#ifdef CONFIG_SPIRAM_SUPPORT
#undef CONFIG_SPIRAM_SUPPORT
#endif
#ifdef CONFIG_SPIRAM
#undef CONFIG_SPIRAM
#endif
#endif
bool psramInit();
bool psramFound();

View File

@ -19,36 +19,22 @@
#include "esp32-hal.h"
#include "esp8266-compat.h"
#include "soc/gpio_reg.h"
#include "soc/rmt_struct.h"
#include "soc/gpio_reg.h"
#include "esp32-hal-rmt.h"
#include "driver/periph_ctrl.h"
#include "soc/rmt_struct.h"
#include "esp_intr_alloc.h"
/**
* Internal macros
*/
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
#define MAX_CHANNELS 8
#define MAX_DATA_PER_CHANNEL 64
#define MAX_DATA_PER_ITTERATION 62
#elif CONFIG_IDF_TARGET_ESP32S2
#define MAX_CHANNELS 4
#define MAX_DATA_PER_CHANNEL 64
#define MAX_DATA_PER_ITTERATION 62
#elif CONFIG_IDF_TARGET_ESP32C3
#define MAX_CHANNELS 4
#define MAX_DATA_PER_CHANNEL 48
#define MAX_DATA_PER_ITTERATION 46
#else
#error Target CONFIG_IDF_TARGET is not supported
#endif
#define _ABS(a) (a>0?a:-a)
#define _LIMIT(a,b) (a>b?b:a)
#if CONFIG_IDF_TARGET_ESP32C3
#define _INT_TX_END(channel) (1<<(channel))
#define _INT_RX_END(channel) (4<<(channel))
#define _INT_ERROR(channel) (16<<(channel))
#define _INT_THR_EVNT(channel) (256<<(channel))
#else
#define __INT_TX_END (1)
#define __INT_RX_END (2)
#define __INT_ERROR (4)
@ -58,7 +44,6 @@
#define _INT_RX_END(channel) (__INT_RX_END<<(channel*3))
#define _INT_ERROR(channel) (__INT_ERROR<<(channel*3))
#define _INT_THR_EVNT(channel) ((__INT_THR_EVNT)<<(channel))
#endif
#if CONFIG_DISABLE_HAL_LOCKS
# define RMT_MUTEX_LOCK(channel)
@ -68,7 +53,7 @@
# define RMT_MUTEX_UNLOCK(channel) xSemaphoreGive(g_rmt_objlocks[channel])
#endif /* CONFIG_DISABLE_HAL_LOCKS */
//#define _RMT_INTERNAL_DEBUG
#define _RMT_INTERNAL_DEBUG
#ifdef _RMT_INTERNAL_DEBUG
# define DEBUG_INTERRUPT_START(pin) digitalWrite(pin, 1);
# define DEBUG_INTERRUPT_END(pin) digitalWrite(pin, 0);
@ -109,30 +94,24 @@ struct rmt_obj_s
transaction_state_t tx_state;
rmt_rx_data_cb_t cb;
bool data_alloc;
void * arg;
};
/**
* Internal variables for channel descriptors
*/
static xSemaphoreHandle g_rmt_objlocks[MAX_CHANNELS] = {
NULL, NULL, NULL, NULL,
#if CONFIG_IDF_TARGET_ESP32
NULL, NULL, NULL, NULL
#endif
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
static rmt_obj_t g_rmt_objects[MAX_CHANNELS] = {
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL},
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL},
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL},
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL},
#if CONFIG_IDF_TARGET_ESP32
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL},
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL},
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL},
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL},
#endif
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false},
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false},
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false},
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false},
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false},
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false},
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false},
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false},
};
/**
@ -151,17 +130,17 @@ static void _initPin(int pin, int channel, bool tx_not_rx);
static bool _rmtSendOnce(rmt_obj_t* rmt, rmt_data_t* data, size_t size, bool continuous);
static void ARDUINO_ISR_ATTR _rmt_isr(void* arg);
static void IRAM_ATTR _rmt_isr(void* arg);
static rmt_obj_t* _rmtAllocate(int pin, int from, int size);
static void _initPin(int pin, int channel, bool tx_not_rx);
static int ARDUINO_ISR_ATTR _rmt_get_mem_len(uint8_t channel);
static int IRAM_ATTR _rmt_get_mem_len(uint8_t channel);
static void ARDUINO_ISR_ATTR _rmt_tx_mem_first(uint8_t ch);
static void IRAM_ATTR _rmt_tx_mem_first(uint8_t ch);
static void ARDUINO_ISR_ATTR _rmt_tx_mem_second(uint8_t ch);
static void IRAM_ATTR _rmt_tx_mem_second(uint8_t ch);
/**
@ -175,17 +154,12 @@ bool rmtSetCarrier(rmt_obj_t* rmt, bool carrier_en, bool carrier_level, uint32_t
size_t channel = rmt->channel;
RMT_MUTEX_LOCK(channel);
#if CONFIG_IDF_TARGET_ESP32C3
RMT.tx_carrier[channel].low = low;
RMT.tx_carrier[channel].high = high;
RMT.rx_conf[channel].conf0.carrier_en = carrier_en;
RMT.rx_conf[channel].conf0.carrier_out_lv = carrier_level;
#else
RMT.carrier_duty_ch[channel].low = low;
RMT.carrier_duty_ch[channel].high = high;
RMT.conf_ch[channel].conf0.carrier_en = carrier_en;
RMT.conf_ch[channel].conf0.carrier_out_lv = carrier_level;
#endif
RMT_MUTEX_UNLOCK(channel);
return true;
@ -201,13 +175,8 @@ bool rmtSetFilter(rmt_obj_t* rmt, bool filter_en, uint32_t filter_level)
RMT_MUTEX_LOCK(channel);
#if CONFIG_IDF_TARGET_ESP32C3
RMT.rx_conf[channel].conf1.rx_filter_thres = filter_level;
RMT.rx_conf[channel].conf1.rx_filter_en = filter_en;
#else
RMT.conf_ch[channel].conf1.rx_filter_thres = filter_level;
RMT.conf_ch[channel].conf1.rx_filter_en = filter_en;
#endif
RMT_MUTEX_UNLOCK(channel);
@ -223,11 +192,7 @@ bool rmtSetRxThreshold(rmt_obj_t* rmt, uint32_t value)
size_t channel = rmt->channel;
RMT_MUTEX_LOCK(channel);
#if CONFIG_IDF_TARGET_ESP32C3
RMT.rx_conf[channel].conf0.idle_thres = value;
#else
RMT.conf_ch[channel].conf0.idle_thres = value;
#endif
RMT_MUTEX_UNLOCK(channel);
return true;
@ -292,13 +257,13 @@ bool rmtWrite(rmt_obj_t* rmt, rmt_data_t* data, size_t size)
int channel = rmt->channel;
int allocated_size = MAX_DATA_PER_CHANNEL * rmt->buffers;
if (size > (allocated_size - 1)) {
if (size > allocated_size) {
int half_tx_nr = MAX_DATA_PER_ITTERATION/2;
RMT_MUTEX_LOCK(channel);
// setup interrupt handler if not yet installed for half and full tx
if (!intr_handle) {
esp_intr_alloc(ETS_RMT_INTR_SOURCE, (int)ARDUINO_ISR_FLAG, _rmt_isr, NULL, &intr_handle);
esp_intr_alloc(ETS_RMT_INTR_SOURCE, (int)ESP_INTR_FLAG_IRAM, _rmt_isr, NULL, &intr_handle);
}
rmt->data_size = size - MAX_DATA_PER_ITTERATION;
@ -306,18 +271,6 @@ bool rmtWrite(rmt_obj_t* rmt, rmt_data_t* data, size_t size)
rmt->intr_mode = E_TX_INTR | E_TXTHR_INTR;
rmt->tx_state = E_SET_CONTI | E_FIRST_HALF;
#if CONFIG_IDF_TARGET_ESP32C3
//uint32_t val = RMT.tx_conf[channel].val;
// init the tx limit for interruption
RMT.tx_lim[channel].limit = half_tx_nr+2;
//RMT.tx_conf[channel].val = val;
//RMT.tx_conf[channel].conf_update = 1;
// reset memory pointer
RMT.tx_conf[channel].mem_rst = 1;
//RMT.tx_conf[channel].mem_rst = 0;
RMT.tx_conf[channel].mem_rd_rst = 1;
//RMT.tx_conf[channel].mem_rd_rst = 0;
#else
// init the tx limit for interruption
RMT.tx_lim_ch[channel].limit = half_tx_nr+2;
// reset memory pointer
@ -327,9 +280,9 @@ bool rmtWrite(rmt_obj_t* rmt, rmt_data_t* data, size_t size)
RMT.conf_ch[channel].conf1.mem_rd_rst = 0;
RMT.conf_ch[channel].conf1.mem_wr_rst = 1;
RMT.conf_ch[channel].conf1.mem_wr_rst = 0;
#endif
// set the tx end mark
//RMTMEM.chan[channel].data32[MAX_DATA_PER_ITTERATION].val = 0;
RMTMEM.chan[channel].data32[MAX_DATA_PER_ITTERATION].val = 0;
// clear and enable both Tx completed and half tx event
RMT.int_clr.val = _INT_TX_END(channel);
@ -343,7 +296,6 @@ bool rmtWrite(rmt_obj_t* rmt, rmt_data_t* data, size_t size)
RMT_MUTEX_UNLOCK(channel);
// start the transation
//return _rmtSendOnce(rmt, data, MAX_DATA_PER_ITTERATION, true);
return _rmtSendOnce(rmt, data, MAX_DATA_PER_ITTERATION, false);
} else {
// use one-go mode if data fits one buffer
@ -371,7 +323,6 @@ bool rmtReadData(rmt_obj_t* rmt, uint32_t* data, size_t size)
return true;
}
bool rmtBeginReceive(rmt_obj_t* rmt)
{
if (!rmt) {
@ -382,15 +333,10 @@ bool rmtBeginReceive(rmt_obj_t* rmt)
RMT.int_clr.val = _INT_ERROR(channel);
RMT.int_ena.val |= _INT_ERROR(channel);
#if CONFIG_IDF_TARGET_ESP32C3
RMT.rx_conf[channel].conf1.mem_owner = 1;
RMT.rx_conf[channel].conf1.mem_wr_rst = 1;
RMT.rx_conf[channel].conf1.rx_en = 1;
#else
RMT.conf_ch[channel].conf1.mem_owner = 1;
RMT.conf_ch[channel].conf1.mem_wr_rst = 1;
RMT.conf_ch[channel].conf1.rx_en = 1;
#endif
return true;
}
@ -410,7 +356,7 @@ bool rmtReceiveCompleted(rmt_obj_t* rmt)
}
}
bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb, void * arg)
bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb)
{
if (!rmt && !cb) {
return false;
@ -418,7 +364,6 @@ bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb, void * arg)
int channel = rmt->channel;
RMT_MUTEX_LOCK(channel);
rmt->arg = arg;
rmt->intr_mode = E_RX_INTR;
rmt->tx_state = E_FIRST_HALF;
rmt->cb = cb;
@ -429,48 +374,22 @@ bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb, void * arg)
rmt->data_alloc = true;
}
#if CONFIG_IDF_TARGET_ESP32C3
RMT.rx_conf[channel].conf1.mem_owner = 1;
#else
RMT.conf_ch[channel].conf1.mem_owner = 1;
#endif
RMT.int_clr.val = _INT_RX_END(channel);
RMT.int_clr.val = _INT_ERROR(channel);
RMT.int_ena.val |= _INT_RX_END(channel);
RMT.int_ena.val |= _INT_ERROR(channel);
#if CONFIG_IDF_TARGET_ESP32C3
RMT.rx_conf[channel].conf1.mem_wr_rst = 1;
RMT.rx_conf[channel].conf1.rx_en = 1;
#else
RMT.conf_ch[channel].conf1.mem_wr_rst = 1;
RMT.conf_ch[channel].conf1.rx_en = 1;
#endif
RMT_MUTEX_UNLOCK(channel);
return true;
}
bool rmtEnd(rmt_obj_t* rmt) {
if (!rmt) {
return false;
}
int channel = rmt->channel;
RMT_MUTEX_LOCK(channel);
#if CONFIG_IDF_TARGET_ESP32C3
RMT.rx_conf[channel].conf1.rx_en = 1;
#else
RMT.conf_ch[channel].conf1.rx_en = 1;
#endif
RMT_MUTEX_UNLOCK(channel);
return true;
}
bool rmtReadAsync(rmt_obj_t* rmt, rmt_data_t* data, size_t size, void* eventFlag, bool waitForData, uint32_t timeout)
{
if (!rmt) {
@ -495,11 +414,7 @@ bool rmtReadAsync(rmt_obj_t* rmt, rmt_data_t* data, size_t size, void* eventFlag
RMT_MUTEX_LOCK(channel);
rmt->intr_mode = E_RX_INTR;
#if CONFIG_IDF_TARGET_ESP32C3
RMT.rx_conf[channel].conf1.mem_owner = 1;
#else
RMT.conf_ch[channel].conf1.mem_owner = 1;
#endif
RMT.int_clr.val = _INT_RX_END(channel);
RMT.int_clr.val = _INT_ERROR(channel);
@ -507,15 +422,9 @@ bool rmtReadAsync(rmt_obj_t* rmt, rmt_data_t* data, size_t size, void* eventFlag
RMT.int_ena.val |= _INT_RX_END(channel);
RMT.int_ena.val |= _INT_ERROR(channel);
#if CONFIG_IDF_TARGET_ESP32C3
RMT.rx_conf[channel].conf1.mem_wr_rst = 1;
RMT.rx_conf[channel].conf1.rx_en = 1;
#else
RMT.conf_ch[channel].conf1.mem_wr_rst = 1;
RMT.conf_ch[channel].conf1.rx_en = 1;
#endif
RMT_MUTEX_UNLOCK(channel);
// wait for data if requested so
@ -542,20 +451,14 @@ float rmtSetTick(rmt_obj_t* rmt, float tick)
* rmt tick for 1 MHz -> 1us (1x) div_cnt = 0x01
256us (256x) div_cnt = 0x00
*/
int apb_div = _LIMIT(tick/12.5, 256);
int ref_div = _LIMIT(tick/1000, 256);
float apb_tick = 12.5 * apb_div;
float ref_tick = 1000.0 * ref_div;
size_t channel = rmt->channel;
#if CONFIG_IDF_TARGET_ESP32C3
int apb_div = _LIMIT(tick/25.0f, 256);
float apb_tick = 25.0f * apb_div;
RMT.tx_conf[channel].div_cnt = apb_div & 0xFF;
RMT.tx_conf[channel].conf_update = 1;
return apb_tick;
#else
int apb_div = _LIMIT(tick/12.5f, 256);
int ref_div = _LIMIT(tick/1000, 256);
float apb_tick = 12.5f * apb_div;
float ref_tick = 1000.0f * ref_div;
if (_ABS(apb_tick - tick) < _ABS(ref_tick - tick)) {
RMT.conf_ch[channel].conf0.div_cnt = apb_div & 0xFF;
RMT.conf_ch[channel].conf1.ref_always_on = 1;
@ -565,7 +468,6 @@ float rmtSetTick(rmt_obj_t* rmt, float tick)
RMT.conf_ch[channel].conf1.ref_always_on = 0;
return ref_tick;
}
#endif
}
rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize)
@ -620,76 +522,27 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize)
rmt->tx_not_rx = tx_not_rx;
rmt->buffers =buffers;
rmt->channel = channel;
rmt->arg = NULL;
_initPin(pin, channel, tx_not_rx);
// Initialize the registers in default mode:
// - no carrier, filter
// - timebase tick of 1us
// - idle threshold set to 0x8000 (max pulse width + 1)
#if CONFIG_IDF_TARGET_ESP32C3
RMT.sys_conf.fifo_mask = 1;
if (tx_not_rx) {
RMT.tx_lim[channel].limit = MAX_DATA_PER_ITTERATION/2 + 2;
RMT.tx_conf[channel].val = 0;
// RMT.tx_conf[channel].carrier_en = 0;
// RMT.tx_conf[channel].carrier_out_lv = 0;
// RMT.tx_conf[channel].tx_conti_mode = 0;
// RMT.tx_conf[channel].idle_out_lv = 0; // signal level for idle
// RMT.tx_conf[channel].tx_start = 0;
// RMT.tx_conf[channel].tx_stop = 0;
// RMT.tx_conf[channel].carrier_eff_en = 0;
// RMT.tx_conf[channel].afifo_rst = 0;
// RMT.tx_conf[channel].conf_update = 0;
// RMT.tx_conf[channel].mem_tx_wrap_en = 0;
// RMT.tx_conf[channel].mem_rst = 1;
RMT.tx_conf[channel].idle_out_en = 1; // enable idle
RMT.tx_conf[channel].div_cnt = 1;
RMT.tx_conf[channel].mem_size = buffers;
RMT.tx_conf[channel].mem_rd_rst = 1;
RMT.tx_conf[channel].conf_update = 1;
} else {
RMT.rx_conf[channel].conf0.div_cnt = 1;
RMT.rx_conf[channel].conf0.mem_size = buffers;
RMT.rx_conf[channel].conf0.carrier_en = 0;
RMT.rx_conf[channel].conf0.carrier_out_lv = 0;
RMT.rx_conf[channel].conf0.idle_thres = 0x80;
RMT.rx_conf[channel].conf1.rx_filter_en = 0;
RMT.rx_conf[channel].conf1.rx_filter_thres = 0;
RMT.rx_conf[channel].conf1.mem_rst = 0;
RMT.rx_conf[channel].conf1.mem_rx_wrap_en = 0;
RMT.rx_conf[channel].conf1.afifo_rst = 0;
RMT.rx_conf[channel].conf1.conf_update = 0;
RMT.rx_conf[channel].conf1.rx_en = 1;
RMT.rx_conf[channel].conf1.mem_owner = 1;
RMT.rx_conf[channel].conf1.mem_wr_rst = 1;
}
#else
RMT.conf_ch[channel].conf0.div_cnt = 1;
RMT.conf_ch[channel].conf0.mem_size = buffers;
RMT.conf_ch[channel].conf0.carrier_en = 0;
RMT.conf_ch[channel].conf0.carrier_out_lv = 0;
#if CONFIG_IDF_TARGET_ESP32
RMT.conf_ch[channel].conf0.mem_pd = 0;
#endif
RMT.conf_ch[channel].conf0.idle_thres = 0x80;
RMT.conf_ch[channel].conf1.rx_en = 0;
RMT.conf_ch[channel].conf1.tx_conti_mode = 0;
#if CONFIG_IDF_TARGET_ESP32
RMT.conf_ch[channel].conf1.ref_cnt_rst = 0;
#else
RMT.conf_ch[channel].conf1.chk_rx_carrier_en = 0;
#endif
RMT.conf_ch[channel].conf1.rx_filter_en = 0;
RMT.conf_ch[channel].conf1.rx_filter_thres = 0;
RMT.conf_ch[channel].conf1.idle_out_lv = 0; // signal level for idle
RMT.conf_ch[channel].conf1.idle_out_en = 1; // enable idle
RMT.conf_ch[channel].conf1.ref_always_on = 0; // base clock
RMT.apb_conf.fifo_mask = 1;
if (tx_not_rx) {
@ -701,10 +554,10 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize)
RMT.conf_ch[channel].conf1.mem_owner = 1;
RMT.conf_ch[channel].conf1.mem_wr_rst = 1;
}
#endif
// install interrupt if at least one channel is active
if (!intr_handle) {
esp_intr_alloc(ETS_RMT_INTR_SOURCE, (int)ARDUINO_ISR_FLAG, _rmt_isr, NULL, &intr_handle);
esp_intr_alloc(ETS_RMT_INTR_SOURCE, (int)ESP_INTR_FLAG_IRAM, _rmt_isr, NULL, &intr_handle);
}
RMT_MUTEX_UNLOCK(channel);
@ -720,11 +573,7 @@ bool _rmtSendOnce(rmt_obj_t* rmt, rmt_data_t* data, size_t size, bool continuous
return false;
}
int channel = rmt->channel;
#if CONFIG_IDF_TARGET_ESP32C3
RMT.sys_conf.fifo_mask = 1;
#else
RMT.apb_conf.fifo_mask = 1;
#endif
if (data && size>0) {
size_t i;
volatile uint32_t* rmt_mem_ptr = &(RMTMEM.chan[channel].data32[0].val);
@ -736,15 +585,9 @@ bool _rmtSendOnce(rmt_obj_t* rmt, rmt_data_t* data, size_t size, bool continuous
}
RMT_MUTEX_LOCK(channel);
#if CONFIG_IDF_TARGET_ESP32C3
RMT.tx_conf[channel].tx_conti_mode = continuous;
RMT.tx_conf[channel].mem_rd_rst = 1;
RMT.tx_conf[channel].tx_start = 1;
#else
RMT.conf_ch[channel].conf1.tx_conti_mode = continuous;
RMT.conf_ch[channel].conf1.mem_rd_rst = 1;
RMT.conf_ch[channel].conf1.tx_start = 1;
#endif
RMT_MUTEX_UNLOCK(channel);
return true;
@ -769,7 +612,6 @@ static void _initPin(int pin, int channel, bool tx_not_rx)
{
if (!periph_enabled) {
periph_enabled = true;
periph_module_reset( PERIPH_RMT_MODULE );
periph_module_enable( PERIPH_RMT_MODULE );
}
if (tx_not_rx) {
@ -783,9 +625,8 @@ static void _initPin(int pin, int channel, bool tx_not_rx)
}
static void ARDUINO_ISR_ATTR _rmt_isr(void* arg)
static void IRAM_ATTR _rmt_isr(void* arg)
{
//DEBUG_INTERRUPT_START(4);
int intr_val = RMT.int_st.val;
size_t ch;
for (ch = 0; ch < MAX_CHANNELS; ch++) {
@ -817,18 +658,12 @@ static void ARDUINO_ISR_ATTR _rmt_isr(void* arg)
}
if (g_rmt_objects[ch].cb) {
// actually received data ptr
(g_rmt_objects[ch].cb)(data_received, _rmt_get_mem_len(ch), g_rmt_objects[ch].arg);
(g_rmt_objects[ch].cb)(data_received, _rmt_get_mem_len(ch));
// restart the reception
#if CONFIG_IDF_TARGET_ESP32C3
RMT.rx_conf[ch].conf1.mem_owner = 1;
RMT.rx_conf[ch].conf1.mem_wr_rst = 1;
RMT.rx_conf[ch].conf1.rx_en = 1;
#else
RMT.conf_ch[ch].conf1.mem_owner = 1;
RMT.conf_ch[ch].conf1.mem_wr_rst = 1;
RMT.conf_ch[ch].conf1.rx_en = 1;
#endif
RMT.int_ena.val |= _INT_RX_END(ch);
} else {
// if not callback provide, expect only one Rx
@ -854,17 +689,10 @@ static void ARDUINO_ISR_ATTR _rmt_isr(void* arg)
xEventGroupSetBits(g_rmt_objects[ch].events, RMT_FLAG_ERROR);
}
// reset memory
#if CONFIG_IDF_TARGET_ESP32C3
RMT.tx_conf[ch].mem_rd_rst = 1;
RMT.tx_conf[ch].mem_rd_rst = 0;
RMT.rx_conf[ch].conf1.mem_wr_rst = 1;
RMT.rx_conf[ch].conf1.mem_wr_rst = 0;
#else
RMT.conf_ch[ch].conf1.mem_rd_rst = 1;
RMT.conf_ch[ch].conf1.mem_rd_rst = 0;
RMT.conf_ch[ch].conf1.mem_wr_rst = 1;
RMT.conf_ch[ch].conf1.mem_wr_rst = 0;
#endif
}
if (intr_val & _INT_TX_END(ch)) {
@ -876,50 +704,32 @@ static void ARDUINO_ISR_ATTR _rmt_isr(void* arg)
if (intr_val & _INT_THR_EVNT(ch)) {
// clear the flag
RMT.int_clr.val = _INT_THR_EVNT(ch);
#if CONFIG_IDF_TARGET_ESP32C3
//RMT.int_clr.val = _INT_TX_END(ch);
//RMT.int_ena.val |= _INT_TX_END(ch);
#endif
// initial setup of continuous mode
if (g_rmt_objects[ch].tx_state & E_SET_CONTI) {
#if CONFIG_IDF_TARGET_ESP32C3
RMT.tx_conf[ch].tx_conti_mode = 1;
#else
RMT.conf_ch[ch].conf1.tx_conti_mode = 1;
#endif
g_rmt_objects[ch].intr_mode &= ~E_SET_CONTI;
}
_rmt_tx_mem_first(ch);
}
}
//DEBUG_INTERRUPT_END(4);
}
static void ARDUINO_ISR_ATTR _rmt_tx_mem_second(uint8_t ch)
static void IRAM_ATTR _rmt_tx_mem_second(uint8_t ch)
{
DEBUG_INTERRUPT_START(4)
uint32_t* data = g_rmt_objects[ch].data_ptr;
int half_tx_nr = MAX_DATA_PER_ITTERATION/2;
int i;
#if CONFIG_IDF_TARGET_ESP32C3
RMT.tx_lim[ch].limit = half_tx_nr+2;
#else
RMT.tx_lim_ch[ch].limit = half_tx_nr+2;
#endif
RMT.int_clr.val = _INT_THR_EVNT(ch);
RMT.int_ena.val |= _INT_THR_EVNT(ch);
#if CONFIG_IDF_TARGET_ESP32C3
//RMT.int_clr.val = _INT_TX_END(ch);
//RMT.int_ena.val &= ~_INT_TX_END(ch);
#endif
g_rmt_objects[ch].tx_state |= E_FIRST_HALF;
if (data) {
int remaining_size = g_rmt_objects[ch].data_size;
//ets_printf("RMT Tx[%d] %d\n", ch, remaining_size);
// will the remaining data occupy the entire halfbuffer
if (remaining_size > half_tx_nr) {
for (i = 0; i < half_tx_nr; i++) {
@ -938,30 +748,17 @@ static void ARDUINO_ISR_ATTR _rmt_tx_mem_second(uint8_t ch)
g_rmt_objects[ch].data_ptr = NULL;
}
#if CONFIG_IDF_TARGET_ESP32C3
RMTMEM.chan[ch].data32[half_tx_nr+i].val = 0;
RMT.tx_conf[ch].tx_start = 1;
#endif
} else if ((!(g_rmt_objects[ch].tx_state & E_LAST_DATA)) &&
(!(g_rmt_objects[ch].tx_state & E_END_TRANS))) {
//ets_printf("RMT Tx finishing %d!\n", ch);
for (i = 0; i < half_tx_nr; i++) {
RMTMEM.chan[ch].data32[half_tx_nr+i].val = 0x000F000F;
}
RMTMEM.chan[ch].data32[half_tx_nr+i].val = 0;
g_rmt_objects[ch].tx_state |= E_LAST_DATA;
#if CONFIG_IDF_TARGET_ESP32C3
RMT.tx_conf[ch].tx_conti_mode = 0;
#else
RMT.conf_ch[ch].conf1.tx_conti_mode = 0;
#endif
} else {
//ets_printf("RMT Tx finished %d!\n", ch);
#if CONFIG_IDF_TARGET_ESP32C3
RMT.tx_conf[ch].tx_conti_mode = 0;
#else
log_d("RMT Tx finished %d!\n", ch);
RMT.conf_ch[ch].conf1.tx_conti_mode = 0;
#endif
RMT.int_ena.val &= ~_INT_TX_END(ch);
RMT.int_ena.val &= ~_INT_THR_EVNT(ch);
g_rmt_objects[ch].intr_mode = E_NO_INTR;
@ -970,22 +767,17 @@ static void ARDUINO_ISR_ATTR _rmt_tx_mem_second(uint8_t ch)
DEBUG_INTERRUPT_END(4);
}
static void ARDUINO_ISR_ATTR _rmt_tx_mem_first(uint8_t ch)
static void IRAM_ATTR _rmt_tx_mem_first(uint8_t ch)
{
DEBUG_INTERRUPT_START(2);
uint32_t* data = g_rmt_objects[ch].data_ptr;
int half_tx_nr = MAX_DATA_PER_ITTERATION/2;
int i;
RMT.int_ena.val &= ~_INT_THR_EVNT(ch);
#if CONFIG_IDF_TARGET_ESP32C3
RMT.tx_lim[ch].limit = 0;
#else
RMT.tx_lim_ch[ch].limit = 0;
#endif
if (data) {
int remaining_size = g_rmt_objects[ch].data_size;
//ets_printf("RMT TxF[%d] %d\n", ch, remaining_size);
// will the remaining data occupy the entire halfbuffer
if (remaining_size > half_tx_nr) {
@ -996,11 +788,7 @@ static void ARDUINO_ISR_ATTR _rmt_tx_mem_first(uint8_t ch)
g_rmt_objects[ch].tx_state &= ~E_FIRST_HALF;
// turn off the treshold interrupt
RMT.int_ena.val &= ~_INT_THR_EVNT(ch);
#if CONFIG_IDF_TARGET_ESP32C3
RMT.tx_lim[ch].limit = 0;
#else
RMT.tx_lim_ch[ch].limit = 0;
#endif
g_rmt_objects[ch].data_size -= half_tx_nr;
g_rmt_objects[ch].data_ptr += half_tx_nr;
} else {
@ -1017,37 +805,23 @@ static void ARDUINO_ISR_ATTR _rmt_tx_mem_first(uint8_t ch)
g_rmt_objects[ch].data_ptr = NULL;
}
} else {
//ets_printf("RMT TxF finished %d!\n", ch);
for (i = 0; i < half_tx_nr; i++) {
RMTMEM.chan[ch].data32[i].val = 0x000F000F;
}
RMTMEM.chan[ch].data32[i].val = 0;
g_rmt_objects[ch].tx_state &= ~E_FIRST_HALF;
#if CONFIG_IDF_TARGET_ESP32C3
RMT.tx_lim[ch].limit = 0;
#else
RMT.tx_lim_ch[ch].limit = 0;
#endif
g_rmt_objects[ch].tx_state |= E_LAST_DATA;
#if CONFIG_IDF_TARGET_ESP32C3
RMT.tx_conf[ch].tx_conti_mode = 0;
#else
RMT.conf_ch[ch].conf1.tx_conti_mode = 0;
#endif
}
DEBUG_INTERRUPT_END(2);
}
static int ARDUINO_ISR_ATTR _rmt_get_mem_len(uint8_t channel)
static int IRAM_ATTR _rmt_get_mem_len(uint8_t channel)
{
#if CONFIG_IDF_TARGET_ESP32C3
int block_num = RMT.rx_conf[channel].conf0.mem_size;
int item_block_len = block_num * 48;
#else
int block_num = RMT.conf_ch[channel].conf0.mem_size;
int item_block_len = block_num * 64;
#endif
volatile rmt_item32_t* data = RMTMEM.chan[channel].data32;
int idx;
for(idx = 0; idx < item_block_len; idx++) {

View File

@ -40,7 +40,7 @@ typedef enum {
typedef struct rmt_obj_s rmt_obj_t;
typedef void (*rmt_rx_data_cb_t)(uint32_t *data, size_t len, void *arg);
typedef void (*rmt_rx_data_cb_t)(uint32_t *data, size_t len);
typedef struct {
union {
@ -90,13 +90,8 @@ bool rmtReadAsync(rmt_obj_t* rmt, rmt_data_t* data, size_t size, void* eventFlag
* and callback with data from ISR
*
*/
bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb, void * arg);
bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb);
/***
* Ends async receive started with rmtRead(); but does not
* rmtDeInit().
*/
bool rmtEnd(rmt_obj_t* rmt);
/* Additional interface */

View File

@ -24,10 +24,6 @@
#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
@ -83,9 +79,6 @@ uint32_t sigmaDeltaSetup(uint8_t channel, uint32_t freq) //chan 0-7 freq 1220-31
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;

View File

@ -22,25 +22,15 @@
#include "soc/spi_struct.h"
#include "soc/io_mux_reg.h"
#include "soc/gpio_sig_map.h"
#include "soc/dport_reg.h"
#include "soc/rtc.h"
#include "driver/periph_ctrl.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/gpio.h"
#include "esp_intr_alloc.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "soc/dport_reg.h"
#include "esp32s2/rom/ets_sys.h"
#include "esp32s2/rom/gpio.h"
#include "esp_intr_alloc.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/ets_sys.h"
#include "esp32c3/rom/gpio.h"
#include "esp_intr_alloc.h"
#else
#error Target CONFIG_IDF_TARGET is not supported
#endif
@ -50,6 +40,18 @@
#include "esp_intr.h"
#endif
#define SPI_CLK_IDX(p) ((p==0)?SPICLK_OUT_IDX:((p==1)?SPICLK_OUT_IDX:((p==2)?HSPICLK_OUT_IDX:((p==3)?VSPICLK_OUT_IDX:0))))
#define SPI_MISO_IDX(p) ((p==0)?SPIQ_OUT_IDX:((p==1)?SPIQ_OUT_IDX:((p==2)?HSPIQ_OUT_IDX:((p==3)?VSPIQ_OUT_IDX:0))))
#define SPI_MOSI_IDX(p) ((p==0)?SPID_IN_IDX:((p==1)?SPID_IN_IDX:((p==2)?HSPID_IN_IDX:((p==3)?VSPID_IN_IDX:0))))
#define SPI_SPI_SS_IDX(n) ((n==0)?SPICS0_OUT_IDX:((n==1)?SPICS1_OUT_IDX:((n==2)?SPICS2_OUT_IDX:SPICS0_OUT_IDX)))
#define SPI_HSPI_SS_IDX(n) ((n==0)?HSPICS0_OUT_IDX:((n==1)?HSPICS1_OUT_IDX:((n==2)?HSPICS2_OUT_IDX:HSPICS0_OUT_IDX)))
#define SPI_VSPI_SS_IDX(n) ((n==0)?VSPICS0_OUT_IDX:((n==1)?VSPICS1_OUT_IDX:((n==2)?VSPICS2_OUT_IDX:VSPICS0_OUT_IDX)))
#define SPI_SS_IDX(p, n) ((p==0)?SPI_SPI_SS_IDX(n):((p==1)?SPI_SPI_SS_IDX(n):((p==2)?SPI_HSPI_SS_IDX(n):((p==3)?SPI_VSPI_SS_IDX(n):0))))
#define SPI_INUM(u) (2)
#define SPI_INTR_SOURCE(u) ((u==0)?ETS_SPI0_INTR_SOURCE:((u==1)?ETS_SPI1_INTR_SOURCE:((u==2)?ETS_SPI2_INTR_SOURCE:((p==3)?ETS_SPI3_INTR_SOURCE:0))))
struct spi_struct_t {
spi_dev_t * dev;
#if !CONFIG_DISABLE_HAL_LOCKS
@ -58,84 +60,25 @@ struct spi_struct_t {
uint8_t num;
};
#if CONFIG_IDF_TARGET_ESP32S2
// ESP32S2
#define SPI_COUNT (3)
#define SPI_CLK_IDX(p) ((p==0)?SPICLK_OUT_MUX_IDX:((p==1)?FSPICLK_OUT_MUX_IDX:((p==2)?SPI3_CLK_OUT_MUX_IDX:0)))
#define SPI_MISO_IDX(p) ((p==0)?SPIQ_OUT_IDX:((p==1)?FSPIQ_OUT_IDX:((p==2)?SPI3_Q_OUT_IDX:0)))
#define SPI_MOSI_IDX(p) ((p==0)?SPID_IN_IDX:((p==1)?FSPID_IN_IDX:((p==2)?SPI3_D_IN_IDX:0)))
#define SPI_SPI_SS_IDX(n) ((n==0)?SPICS0_OUT_IDX:((n==1)?SPICS1_OUT_IDX:0))
#define SPI_HSPI_SS_IDX(n) ((n==0)?SPI3_CS0_OUT_IDX:((n==1)?SPI3_CS1_OUT_IDX:((n==2)?SPI3_CS2_OUT_IDX:SPI3_CS0_OUT_IDX)))
#define SPI_FSPI_SS_IDX(n) ((n==0)?FSPICS0_OUT_IDX:((n==1)?FSPICS1_OUT_IDX:((n==2)?FSPICS2_OUT_IDX:FSPICS0_OUT_IDX)))
#define SPI_SS_IDX(p, n) ((p==0)?SPI_SPI_SS_IDX(n):((p==1)?SPI_SPI_SS_IDX(n):((p==2)?SPI_HSPI_SS_IDX(n):0)))
#define SPI_INTR_SOURCE(u) ((u==0)?ETS_SPI1_INTR_SOURCE:((u==1)?ETS_SPI2_INTR_SOURCE:((u==2)?ETS_SPI3_INTR_SOURCE:0)))
#elif CONFIG_IDF_TARGET_ESP32C3
// ESP32S2
#define SPI_COUNT (1)
#define SPI_CLK_IDX(p) FSPICLK_OUT_IDX
#define SPI_MISO_IDX(p) FSPIQ_OUT_IDX
#define SPI_MOSI_IDX(p) FSPID_IN_IDX
#define SPI_SPI_SS_IDX(n) ((n==0)?FSPICS0_OUT_IDX:((n==1)?FSPICS1_OUT_IDX:((n==2)?FSPICS2_OUT_IDX:FSPICS0_OUT_IDX)))
#define SPI_SS_IDX(p, n) SPI_SPI_SS_IDX(n)
#define SPI_INTR_SOURCE(u) ETS_SPI2_INTR_SOURCE
#else
// ESP32
#define SPI_COUNT (4)
#define SPI_CLK_IDX(p) ((p==0)?SPICLK_OUT_IDX:((p==1)?SPICLK_OUT_IDX:((p==2)?HSPICLK_OUT_IDX:((p==3)?VSPICLK_OUT_IDX:0))))
#define SPI_MISO_IDX(p) ((p==0)?SPIQ_OUT_IDX:((p==1)?SPIQ_OUT_IDX:((p==2)?HSPIQ_OUT_IDX:((p==3)?VSPIQ_OUT_IDX:0))))
#define SPI_MOSI_IDX(p) ((p==0)?SPID_IN_IDX:((p==1)?SPID_IN_IDX:((p==2)?HSPID_IN_IDX:((p==3)?VSPID_IN_IDX:0))))
#define SPI_SPI_SS_IDX(n) ((n==0)?SPICS0_OUT_IDX:((n==1)?SPICS1_OUT_IDX:((n==2)?SPICS2_OUT_IDX:SPICS0_OUT_IDX)))
#define SPI_HSPI_SS_IDX(n) ((n==0)?HSPICS0_OUT_IDX:((n==1)?HSPICS1_OUT_IDX:((n==2)?HSPICS2_OUT_IDX:HSPICS0_OUT_IDX)))
#define SPI_VSPI_SS_IDX(n) ((n==0)?VSPICS0_OUT_IDX:((n==1)?VSPICS1_OUT_IDX:((n==2)?VSPICS2_OUT_IDX:VSPICS0_OUT_IDX)))
#define SPI_SS_IDX(p, n) ((p==0)?SPI_SPI_SS_IDX(n):((p==1)?SPI_SPI_SS_IDX(n):((p==2)?SPI_HSPI_SS_IDX(n):((p==3)?SPI_VSPI_SS_IDX(n):0))))
#define SPI_INTR_SOURCE(u) ((u==0)?ETS_SPI0_INTR_SOURCE:((u==1)?ETS_SPI1_INTR_SOURCE:((u==2)?ETS_SPI2_INTR_SOURCE:((p==3)?ETS_SPI3_INTR_SOURCE:0))))
#endif
#if CONFIG_DISABLE_HAL_LOCKS
#define SPI_MUTEX_LOCK()
#define SPI_MUTEX_UNLOCK()
static spi_t _spi_bus_array[] = {
#if CONFIG_IDF_TARGET_ESP32S2
{(volatile spi_dev_t *)(DR_REG_SPI1_BASE), 0},
{(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 1},
{(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 2}
#else
static spi_t _spi_bus_array[4] = {
{(volatile spi_dev_t *)(DR_REG_SPI0_BASE), 0},
{(volatile spi_dev_t *)(DR_REG_SPI1_BASE), 1},
{(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 2},
{(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 3}
#endif
};
#else
#define SPI_MUTEX_LOCK() do {} while (xSemaphoreTake(spi->lock, portMAX_DELAY) != pdPASS)
#define SPI_MUTEX_UNLOCK() xSemaphoreGive(spi->lock)
static spi_t _spi_bus_array[] = {
#if CONFIG_IDF_TARGET_ESP32S2
{(volatile spi_dev_t *)(DR_REG_SPI1_BASE), NULL, 0},
{(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 1},
{(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 2}
#elif CONFIG_IDF_TARGET_ESP32C3
{(volatile spi_dev_t *)(&GPSPI2), NULL, FSPI}
#else
static spi_t _spi_bus_array[4] = {
{(volatile spi_dev_t *)(DR_REG_SPI0_BASE), NULL, 0},
{(volatile spi_dev_t *)(DR_REG_SPI1_BASE), NULL, 1},
{(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 2},
{(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 3}
#endif
};
#endif
@ -145,14 +88,6 @@ void spiAttachSCK(spi_t * spi, int8_t sck)
return;
}
if(sck < 0) {
#if CONFIG_IDF_TARGET_ESP32S2
if(spi->num == FSPI) {
sck = 36;
} else {
log_e("HSPI Does not have default pins on ESP32S2!");
return;
}
#elif CONFIG_IDF_TARGET_ESP32
if(spi->num == HSPI) {
sck = 14;
} else if(spi->num == VSPI) {
@ -160,10 +95,6 @@ void spiAttachSCK(spi_t * spi, int8_t sck)
} else {
sck = 6;
}
#elif CONFIG_IDF_TARGET_ESP32C3
log_e("SPI Does not have default pins on ESP32C3!");
return;
#endif
}
pinMode(sck, OUTPUT);
pinMatrixOutAttach(sck, SPI_CLK_IDX(spi->num), false, false);
@ -175,14 +106,6 @@ void spiAttachMISO(spi_t * spi, int8_t miso)
return;
}
if(miso < 0) {
#if CONFIG_IDF_TARGET_ESP32S2
if(spi->num == FSPI) {
miso = 37;
} else {
log_e("HSPI Does not have default pins on ESP32S2!");
return;
}
#elif CONFIG_IDF_TARGET_ESP32
if(spi->num == HSPI) {
miso = 12;
} else if(spi->num == VSPI) {
@ -190,10 +113,6 @@ void spiAttachMISO(spi_t * spi, int8_t miso)
} else {
miso = 7;
}
#elif CONFIG_IDF_TARGET_ESP32C3
log_e("SPI Does not have default pins on ESP32C3!");
return;
#endif
}
SPI_MUTEX_LOCK();
pinMode(miso, INPUT);
@ -207,14 +126,6 @@ void spiAttachMOSI(spi_t * spi, int8_t mosi)
return;
}
if(mosi < 0) {
#if CONFIG_IDF_TARGET_ESP32S2
if(spi->num == FSPI) {
mosi = 35;
} else {
log_e("HSPI Does not have default pins on ESP32S2!");
return;
}
#elif CONFIG_IDF_TARGET_ESP32
if(spi->num == HSPI) {
mosi = 13;
} else if(spi->num == VSPI) {
@ -222,10 +133,6 @@ void spiAttachMOSI(spi_t * spi, int8_t mosi)
} else {
mosi = 8;
}
#elif CONFIG_IDF_TARGET_ESP32C3
log_e("SPI Does not have default pins on ESP32C3!");
return;
#endif
}
pinMode(mosi, OUTPUT);
pinMatrixOutAttach(mosi, SPI_MOSI_IDX(spi->num), false, false);
@ -237,14 +144,6 @@ void spiDetachSCK(spi_t * spi, int8_t sck)
return;
}
if(sck < 0) {
#if CONFIG_IDF_TARGET_ESP32S2
if(spi->num == FSPI) {
sck = 36;
} else {
log_e("HSPI Does not have default pins on ESP32S2!");
return;
}
#elif CONFIG_IDF_TARGET_ESP32
if(spi->num == HSPI) {
sck = 14;
} else if(spi->num == VSPI) {
@ -252,10 +151,6 @@ void spiDetachSCK(spi_t * spi, int8_t sck)
} else {
sck = 6;
}
#elif CONFIG_IDF_TARGET_ESP32C3
log_e("SPI Does not have default pins on ESP32C3!");
return;
#endif
}
pinMatrixOutDetach(sck, false, false);
pinMode(sck, INPUT);
@ -267,14 +162,6 @@ void spiDetachMISO(spi_t * spi, int8_t miso)
return;
}
if(miso < 0) {
#if CONFIG_IDF_TARGET_ESP32S2
if(spi->num == FSPI) {
miso = 37;
} else {
log_e("HSPI Does not have default pins on ESP32S2!");
return;
}
#elif CONFIG_IDF_TARGET_ESP32
if(spi->num == HSPI) {
miso = 12;
} else if(spi->num == VSPI) {
@ -282,10 +169,6 @@ void spiDetachMISO(spi_t * spi, int8_t miso)
} else {
miso = 7;
}
#elif CONFIG_IDF_TARGET_ESP32C3
log_e("SPI Does not have default pins on ESP32C3!");
return;
#endif
}
pinMatrixInDetach(SPI_MISO_IDX(spi->num), false, false);
pinMode(miso, INPUT);
@ -297,14 +180,6 @@ void spiDetachMOSI(spi_t * spi, int8_t mosi)
return;
}
if(mosi < 0) {
#if CONFIG_IDF_TARGET_ESP32S2
if(spi->num == FSPI) {
mosi = 35;
} else {
log_e("HSPI Does not have default pins on ESP32S2!");
return;
}
#elif CONFIG_IDF_TARGET_ESP32
if(spi->num == HSPI) {
mosi = 13;
} else if(spi->num == VSPI) {
@ -312,10 +187,6 @@ void spiDetachMOSI(spi_t * spi, int8_t mosi)
} else {
mosi = 8;
}
#elif CONFIG_IDF_TARGET_ESP32C3
log_e("SPI Does not have default pins on ESP32C3!");
return;
#endif
}
pinMatrixOutDetach(mosi, false, false);
pinMode(mosi, INPUT);
@ -331,14 +202,6 @@ void spiAttachSS(spi_t * spi, uint8_t cs_num, int8_t ss)
}
if(ss < 0) {
cs_num = 0;
#if CONFIG_IDF_TARGET_ESP32S2
if(spi->num == FSPI) {
ss = 34;
} else {
log_e("HSPI Does not have default pins on ESP32S2!");
return;
}
#elif CONFIG_IDF_TARGET_ESP32
if(spi->num == HSPI) {
ss = 15;
} else if(spi->num == VSPI) {
@ -346,10 +209,6 @@ void spiAttachSS(spi_t * spi, uint8_t cs_num, int8_t ss)
} else {
ss = 11;
}
#elif CONFIG_IDF_TARGET_ESP32C3
log_e("SPI Does not have default pins on ESP32C3!");
return;
#endif
}
pinMode(ss, OUTPUT);
pinMatrixOutAttach(ss, SPI_SS_IDX(spi->num, cs_num), false, false);
@ -362,14 +221,6 @@ void spiDetachSS(spi_t * spi, int8_t ss)
return;
}
if(ss < 0) {
#if CONFIG_IDF_TARGET_ESP32S2
if(spi->num == FSPI) {
ss = 34;
} else {
log_e("HSPI Does not have default pins on ESP32S2!");
return;
}
#elif CONFIG_IDF_TARGET_ESP32
if(spi->num == HSPI) {
ss = 15;
} else if(spi->num == VSPI) {
@ -377,10 +228,6 @@ void spiDetachSS(spi_t * spi, int8_t ss)
} else {
ss = 11;
}
#elif CONFIG_IDF_TARGET_ESP32C3
log_e("SPI Does not have default pins on ESP32C3!");
return;
#endif
}
pinMatrixOutDetach(ss, false, false);
pinMode(ss, INPUT);
@ -392,11 +239,7 @@ void spiEnableSSPins(spi_t * spi, uint8_t cs_mask)
return;
}
SPI_MUTEX_LOCK();
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
spi->dev->misc.val &= ~(cs_mask & SPI_CS_MASK_ALL);
#else
spi->dev->pin.val &= ~(cs_mask & SPI_CS_MASK_ALL);
#endif
SPI_MUTEX_UNLOCK();
}
@ -406,11 +249,7 @@ void spiDisableSSPins(spi_t * spi, uint8_t cs_mask)
return;
}
SPI_MUTEX_LOCK();
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
spi->dev->misc.val |= (cs_mask & SPI_CS_MASK_ALL);
#else
spi->dev->pin.val |= (cs_mask & SPI_CS_MASK_ALL);
#endif
SPI_MUTEX_UNLOCK();
}
@ -442,11 +281,7 @@ void spiSSSet(spi_t * spi)
return;
}
SPI_MUTEX_LOCK();
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
spi->dev->misc.cs_keep_active = 1;
#else
spi->dev->pin.cs_keep_active = 1;
#endif
SPI_MUTEX_UNLOCK();
}
@ -456,11 +291,7 @@ void spiSSClear(spi_t * spi)
return;
}
SPI_MUTEX_LOCK();
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
spi->dev->misc.cs_keep_active = 0;
#else
spi->dev->pin.cs_keep_active = 0;
#endif
SPI_MUTEX_UNLOCK();
}
@ -487,11 +318,7 @@ uint8_t spiGetDataMode(spi_t * spi)
if(!spi) {
return 0;
}
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
bool idleEdge = spi->dev->misc.ck_idle_edge;
#else
bool idleEdge = spi->dev->pin.ck_idle_edge;
#endif
bool outEdge = spi->dev->user.ck_out_edge;
if(idleEdge) {
if(outEdge) {
@ -513,36 +340,20 @@ void spiSetDataMode(spi_t * spi, uint8_t dataMode)
SPI_MUTEX_LOCK();
switch (dataMode) {
case SPI_MODE1:
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
spi->dev->misc.ck_idle_edge = 0;
#else
spi->dev->pin.ck_idle_edge = 0;
#endif
spi->dev->user.ck_out_edge = 1;
break;
case SPI_MODE2:
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
spi->dev->misc.ck_idle_edge = 1;
#else
spi->dev->pin.ck_idle_edge = 1;
#endif
spi->dev->user.ck_out_edge = 1;
break;
case SPI_MODE3:
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
spi->dev->misc.ck_idle_edge = 1;
#else
spi->dev->pin.ck_idle_edge = 1;
#endif
spi->dev->user.ck_out_edge = 0;
break;
case SPI_MODE0:
default:
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
spi->dev->misc.ck_idle_edge = 0;
#else
spi->dev->pin.ck_idle_edge = 0;
#endif
spi->dev->user.ck_out_edge = 0;
break;
}
@ -585,48 +396,28 @@ static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb
}
}
static void spiInitBus(spi_t * spi)
{
#ifndef CONFIG_IDF_TARGET_ESP32C3
spi->dev->slave.trans_done = 0;
#endif
spi->dev->slave.val = 0;
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
spi->dev->misc.val = 0;
#else
spi->dev->pin.val = 0;
#endif
spi->dev->user.val = 0;
spi->dev->user1.val = 0;
spi->dev->ctrl.val = 0;
#ifndef CONFIG_IDF_TARGET_ESP32C3
spi->dev->ctrl1.val = 0;
spi->dev->ctrl2.val = 0;
#else
spi->dev->clk_gate.val = 0;
spi->dev->dma_conf.val = 0;
spi->dev->dma_conf.rx_afifo_rst = 1;
spi->dev->dma_conf.buf_afifo_rst = 1;
#endif
spi->dev->clock.val = 0;
}
void spiStopBus(spi_t * spi)
{
if(!spi) {
return;
}
removeApbChangeCallback(spi, _on_apb_change);
SPI_MUTEX_LOCK();
spiInitBus(spi);
spi->dev->slave.trans_done = 0;
spi->dev->slave.slave_mode = 0;
spi->dev->pin.val = 0;
spi->dev->user.val = 0;
spi->dev->user1.val = 0;
spi->dev->ctrl.val = 0;
spi->dev->ctrl1.val = 0;
spi->dev->ctrl2.val = 0;
spi->dev->clock.val = 0;
SPI_MUTEX_UNLOCK();
removeApbChangeCallback(spi, _on_apb_change);
}
spi_t * spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_t bitOrder)
{
if(spi_num >= SPI_COUNT){
if(spi_num > 3){
return NULL;
}
@ -641,18 +432,6 @@ spi_t * spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_
}
#endif
#if CONFIG_IDF_TARGET_ESP32S2
if(spi_num == FSPI) {
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI2_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI2_RST);
} else if(spi_num == HSPI) {
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI3_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI3_RST);
} else {
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI01_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI01_RST);
}
#elif CONFIG_IDF_TARGET_ESP32
if(spi_num == HSPI) {
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI2_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI2_RST);
@ -663,36 +442,24 @@ spi_t * spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI01_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI01_RST);
}
#elif CONFIG_IDF_TARGET_ESP32C3
periph_module_reset( PERIPH_SPI2_MODULE );
periph_module_enable( PERIPH_SPI2_MODULE );
#endif
spiStopBus(spi);
spiSetDataMode(spi, dataMode);
spiSetBitOrder(spi, bitOrder);
spiSetClockDiv(spi, clockDiv);
SPI_MUTEX_LOCK();
spiInitBus(spi);
#if CONFIG_IDF_TARGET_ESP32C3
spi->dev->clk_gate.clk_en = 1;
spi->dev->clk_gate.mst_clk_sel = 1;
spi->dev->clk_gate.mst_clk_active = 1;
spi->dev->dma_conf.tx_seg_trans_clr_en = 1;
spi->dev->dma_conf.rx_seg_trans_clr_en = 1;
spi->dev->dma_conf.dma_seg_trans_en = 0;
#endif
spi->dev->user.usr_mosi = 1;
spi->dev->user.usr_miso = 1;
spi->dev->user.doutdin = 1;
int i;
for(i=0; i<16; i++) {
spi->dev->data_buf[i] = 0x00000000;
}
SPI_MUTEX_UNLOCK();
spiSetDataMode(spi, dataMode);
spiSetBitOrder(spi, bitOrder);
spiSetClockDiv(spi, clockDiv);
addApbChangeCallback(spi, _on_apb_change);
return spi;
}
@ -704,16 +471,6 @@ void spiWaitReady(spi_t * spi)
while(spi->dev->cmd.usr);
}
#if CONFIG_IDF_TARGET_ESP32S2
#define usr_mosi_dbitlen usr_mosi_bit_len
#define usr_miso_dbitlen usr_miso_bit_len
#elif CONFIG_IDF_TARGET_ESP32C3
#define usr_mosi_dbitlen ms_data_bitlen
#define usr_miso_dbitlen ms_data_bitlen
#define mosi_dlen ms_dlen
#define miso_dlen ms_dlen
#endif
void spiWrite(spi_t * spi, const uint32_t *data, uint8_t len)
{
if(!spi) {
@ -725,16 +482,10 @@ void spiWrite(spi_t * spi, const uint32_t *data, uint8_t len)
}
SPI_MUTEX_LOCK();
spi->dev->mosi_dlen.usr_mosi_dbitlen = (len * 32) - 1;
#ifndef CONFIG_IDF_TARGET_ESP32C3
spi->dev->miso_dlen.usr_miso_dbitlen = 0;
#endif
for(i=0; i<len; i++) {
spi->dev->data_buf[i] = data[i];
}
#if CONFIG_IDF_TARGET_ESP32C3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr);
SPI_MUTEX_UNLOCK();
@ -755,10 +506,6 @@ void spiTransfer(spi_t * spi, uint32_t *data, uint8_t len)
for(i=0; i<len; i++) {
spi->dev->data_buf[i] = data[i];
}
#if CONFIG_IDF_TARGET_ESP32C3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr);
for(i=0; i<len; i++) {
@ -774,14 +521,8 @@ void spiWriteByte(spi_t * spi, uint8_t data)
}
SPI_MUTEX_LOCK();
spi->dev->mosi_dlen.usr_mosi_dbitlen = 7;
#ifndef CONFIG_IDF_TARGET_ESP32C3
spi->dev->miso_dlen.usr_miso_dbitlen = 0;
#endif
spi->dev->data_buf[0] = data;
#if CONFIG_IDF_TARGET_ESP32C3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr);
SPI_MUTEX_UNLOCK();
@ -796,10 +537,6 @@ uint8_t spiTransferByte(spi_t * spi, uint8_t data)
spi->dev->mosi_dlen.usr_mosi_dbitlen = 7;
spi->dev->miso_dlen.usr_miso_dbitlen = 7;
spi->dev->data_buf[0] = data;
#if CONFIG_IDF_TARGET_ESP32C3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr);
data = spi->dev->data_buf[0] & 0xFF;
@ -827,14 +564,8 @@ void spiWriteWord(spi_t * spi, uint16_t data)
}
SPI_MUTEX_LOCK();
spi->dev->mosi_dlen.usr_mosi_dbitlen = 15;
#ifndef CONFIG_IDF_TARGET_ESP32C3
spi->dev->miso_dlen.usr_miso_dbitlen = 0;
#endif
spi->dev->data_buf[0] = data;
#if CONFIG_IDF_TARGET_ESP32C3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr);
SPI_MUTEX_UNLOCK();
@ -852,10 +583,6 @@ uint16_t spiTransferWord(spi_t * spi, uint16_t data)
spi->dev->mosi_dlen.usr_mosi_dbitlen = 15;
spi->dev->miso_dlen.usr_miso_dbitlen = 15;
spi->dev->data_buf[0] = data;
#if CONFIG_IDF_TARGET_ESP32C3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr);
data = spi->dev->data_buf[0];
@ -876,14 +603,8 @@ void spiWriteLong(spi_t * spi, uint32_t data)
}
SPI_MUTEX_LOCK();
spi->dev->mosi_dlen.usr_mosi_dbitlen = 31;
#ifndef CONFIG_IDF_TARGET_ESP32C3
spi->dev->miso_dlen.usr_miso_dbitlen = 0;
#endif
spi->dev->data_buf[0] = data;
#if CONFIG_IDF_TARGET_ESP32C3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr);
SPI_MUTEX_UNLOCK();
@ -901,10 +622,6 @@ uint32_t spiTransferLong(spi_t * spi, uint32_t data)
spi->dev->mosi_dlen.usr_mosi_dbitlen = 31;
spi->dev->miso_dlen.usr_miso_dbitlen = 31;
spi->dev->data_buf[0] = data;
#if CONFIG_IDF_TARGET_ESP32C3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr);
data = spi->dev->data_buf[0];
@ -944,10 +661,6 @@ static void __spiTransferBytes(spi_t * spi, const uint8_t * data, uint8_t * out,
spi->dev->data_buf[i] = wordsBuf[i]; //copy buffer to spi fifo
}
#if CONFIG_IDF_TARGET_ESP32C3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr);
@ -1011,39 +724,23 @@ void spiTransaction(spi_t * spi, uint32_t clockDiv, uint8_t dataMode, uint8_t bi
SPI_MUTEX_LOCK();
spi->dev->clock.val = clockDiv;
switch (dataMode) {
case SPI_MODE1:
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
spi->dev->misc.ck_idle_edge = 0;
#else
spi->dev->pin.ck_idle_edge = 0;
#endif
spi->dev->user.ck_out_edge = 1;
break;
case SPI_MODE2:
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
spi->dev->misc.ck_idle_edge = 1;
#else
spi->dev->pin.ck_idle_edge = 1;
#endif
spi->dev->user.ck_out_edge = 1;
break;
case SPI_MODE3:
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
spi->dev->misc.ck_idle_edge = 1;
#else
spi->dev->pin.ck_idle_edge = 1;
#endif
spi->dev->user.ck_out_edge = 0;
break;
case SPI_MODE0:
default:
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
spi->dev->misc.ck_idle_edge = 0;
#else
spi->dev->pin.ck_idle_edge = 0;
#endif
spi->dev->user.ck_out_edge = 0;
break;
case SPI_MODE1:
spi->dev->pin.ck_idle_edge = 0;
spi->dev->user.ck_out_edge = 1;
break;
case SPI_MODE2:
spi->dev->pin.ck_idle_edge = 1;
spi->dev->user.ck_out_edge = 1;
break;
case SPI_MODE3:
spi->dev->pin.ck_idle_edge = 1;
spi->dev->user.ck_out_edge = 0;
break;
case SPI_MODE0:
default:
spi->dev->pin.ck_idle_edge = 0;
spi->dev->user.ck_out_edge = 0;
break;
}
if (SPI_MSBFIRST == bitOrder) {
spi->dev->ctrl.wr_bit_order = 0;
@ -1070,20 +767,14 @@ void spiEndTransaction(spi_t * spi)
SPI_MUTEX_UNLOCK();
}
void ARDUINO_ISR_ATTR spiWriteByteNL(spi_t * spi, uint8_t data)
void IRAM_ATTR spiWriteByteNL(spi_t * spi, uint8_t data)
{
if(!spi) {
return;
}
spi->dev->mosi_dlen.usr_mosi_dbitlen = 7;
#ifndef CONFIG_IDF_TARGET_ESP32C3
spi->dev->miso_dlen.usr_miso_dbitlen = 0;
#endif
spi->dev->data_buf[0] = data;
#if CONFIG_IDF_TARGET_ESP32C3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr);
}
@ -1096,17 +787,13 @@ uint8_t spiTransferByteNL(spi_t * spi, uint8_t data)
spi->dev->mosi_dlen.usr_mosi_dbitlen = 7;
spi->dev->miso_dlen.usr_miso_dbitlen = 7;
spi->dev->data_buf[0] = data;
#if CONFIG_IDF_TARGET_ESP32C3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr);
data = spi->dev->data_buf[0] & 0xFF;
return data;
}
void ARDUINO_ISR_ATTR spiWriteShortNL(spi_t * spi, uint16_t data)
void IRAM_ATTR spiWriteShortNL(spi_t * spi, uint16_t data)
{
if(!spi) {
return;
@ -1115,14 +802,8 @@ void ARDUINO_ISR_ATTR spiWriteShortNL(spi_t * spi, uint16_t data)
MSB_16_SET(data, data);
}
spi->dev->mosi_dlen.usr_mosi_dbitlen = 15;
#ifndef CONFIG_IDF_TARGET_ESP32C3
spi->dev->miso_dlen.usr_miso_dbitlen = 0;
#endif
spi->dev->data_buf[0] = data;
#if CONFIG_IDF_TARGET_ESP32C3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr);
}
@ -1138,10 +819,6 @@ uint16_t spiTransferShortNL(spi_t * spi, uint16_t data)
spi->dev->mosi_dlen.usr_mosi_dbitlen = 15;
spi->dev->miso_dlen.usr_miso_dbitlen = 15;
spi->dev->data_buf[0] = data;
#if CONFIG_IDF_TARGET_ESP32C3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr);
data = spi->dev->data_buf[0] & 0xFFFF;
@ -1151,7 +828,7 @@ uint16_t spiTransferShortNL(spi_t * spi, uint16_t data)
return data;
}
void ARDUINO_ISR_ATTR spiWriteLongNL(spi_t * spi, uint32_t data)
void IRAM_ATTR spiWriteLongNL(spi_t * spi, uint32_t data)
{
if(!spi) {
return;
@ -1160,14 +837,8 @@ void ARDUINO_ISR_ATTR spiWriteLongNL(spi_t * spi, uint32_t data)
MSB_32_SET(data, data);
}
spi->dev->mosi_dlen.usr_mosi_dbitlen = 31;
#ifndef CONFIG_IDF_TARGET_ESP32C3
spi->dev->miso_dlen.usr_miso_dbitlen = 0;
#endif
spi->dev->data_buf[0] = data;
#if CONFIG_IDF_TARGET_ESP32C3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr);
}
@ -1183,10 +854,6 @@ uint32_t spiTransferLongNL(spi_t * spi, uint32_t data)
spi->dev->mosi_dlen.usr_mosi_dbitlen = 31;
spi->dev->miso_dlen.usr_miso_dbitlen = 31;
spi->dev->data_buf[0] = data;
#if CONFIG_IDF_TARGET_ESP32C3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr);
data = spi->dev->data_buf[0];
@ -1197,9 +864,6 @@ uint32_t spiTransferLongNL(spi_t * spi, uint32_t data)
}
void spiWriteNL(spi_t * spi, const void * data_in, uint32_t len){
if(!spi) {
return;
}
size_t longs = len >> 2;
if(len & 3){
longs++;
@ -1212,16 +876,10 @@ void spiWriteNL(spi_t * spi, const void * data_in, uint32_t len){
c_longs = (longs > 16)?16:longs;
spi->dev->mosi_dlen.usr_mosi_dbitlen = (c_len*8)-1;
#ifndef CONFIG_IDF_TARGET_ESP32C3
spi->dev->miso_dlen.usr_miso_dbitlen = 0;
#endif
spi->dev->miso_dlen.usr_miso_dbitlen = 0;
for (int i=0; i<c_longs; i++) {
spi->dev->data_buf[i] = data[i];
}
#if CONFIG_IDF_TARGET_ESP32C3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr);
@ -1258,27 +916,11 @@ void spiTransferBytesNL(spi_t * spi, const void * data_in, uint8_t * data_out, u
spi->dev->data_buf[i] = 0xFFFFFFFF;
}
}
#if CONFIG_IDF_TARGET_ESP32C3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr);
if(result){
if(c_len & 3){
for (int i=0; i<(c_longs-1); i++) {
result[i] = spi->dev->data_buf[i];
}
uint32_t last_data = spi->dev->data_buf[c_longs-1];
uint8_t * last_out8 = (uint8_t *)&result[c_longs-1];
uint8_t * last_data8 = (uint8_t *)&last_data;
for (int i=0; i<(c_len & 3); i++) {
last_out8[i] = last_data8[i];
}
} else {
for (int i=0; i<c_longs; i++) {
result[i] = spi->dev->data_buf[i];
}
for (int i=0; i<c_longs; i++) {
result[i] = spi->dev->data_buf[i];
}
}
if(data){
@ -1317,10 +959,6 @@ void spiTransferBitsNL(spi_t * spi, uint32_t data, uint32_t * out, uint8_t bits)
spi->dev->mosi_dlen.usr_mosi_dbitlen = (bits - 1);
spi->dev->miso_dlen.usr_miso_dbitlen = (bits - 1);
spi->dev->data_buf[0] = data;
#if CONFIG_IDF_TARGET_ESP32C3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr);
data = spi->dev->data_buf[0];
@ -1338,7 +976,7 @@ void spiTransferBitsNL(spi_t * spi, uint32_t data, uint32_t * out, uint8_t bits)
}
}
void ARDUINO_ISR_ATTR spiWritePixelsNL(spi_t * spi, const void * data_in, uint32_t len){
void IRAM_ATTR spiWritePixelsNL(spi_t * spi, const void * data_in, uint32_t len){
size_t longs = len >> 2;
if(len & 3){
longs++;
@ -1353,9 +991,7 @@ void ARDUINO_ISR_ATTR spiWritePixelsNL(spi_t * spi, const void * data_in, uint32
l_bytes = (c_len & 3);
spi->dev->mosi_dlen.usr_mosi_dbitlen = (c_len*8)-1;
#ifndef CONFIG_IDF_TARGET_ESP32C3
spi->dev->miso_dlen.usr_miso_dbitlen = 0;
#endif
spi->dev->miso_dlen.usr_miso_dbitlen = 0;
for (int i=0; i<c_longs; i++) {
if(msb){
if(l_bytes && i == (c_longs - 1)){
@ -1371,10 +1007,6 @@ void ARDUINO_ISR_ATTR spiWritePixelsNL(spi_t * spi, const void * data_in, uint32
spi->dev->data_buf[i] = data[i];
}
}
#if CONFIG_IDF_TARGET_ESP32C3
spi->dev->cmd.update = 1;
while (spi->dev->cmd.update);
#endif
spi->dev->cmd.usr = 1;
while(spi->dev->cmd.usr);
@ -1397,12 +1029,7 @@ typedef union {
uint32_t clkcnt_l: 6; /*it must be equal to spi_clkcnt_N.*/
uint32_t clkcnt_h: 6; /*it must be floor((spi_clkcnt_N+1)/2-1).*/
uint32_t clkcnt_n: 6; /*it is the divider of spi_clk. So spi_clk frequency is system/(spi_clkdiv_pre+1)/(spi_clkcnt_N+1)*/
#if CONFIG_IDF_TARGET_ESP32C3
uint32_t clkdiv_pre: 4; /*it is pre-divider of spi_clk.*/
uint32_t reserved: 9; /*reserved*/
#else
uint32_t clkdiv_pre: 13; /*it is pre-divider of spi_clk.*/
#endif
uint32_t clk_equ_sysclk: 1; /*1: spi_clk is eqaul to system 0: spi_clk is divided from system clock.*/
};
} spiClk_t;
@ -1444,13 +1071,8 @@ uint32_t spiFrequencyToClockDiv(uint32_t freq)
while(calPreVari++ <= 1) {
calPre = (((apb_freq / (reg.clkcnt_n + 1)) / freq) - 1) + calPreVari;
#if CONFIG_IDF_TARGET_ESP32C3
if(calPre > 0xF) {
reg.clkdiv_pre = 0xF;
#else
if(calPre > 0x1FFF) {
reg.clkdiv_pre = 0x1FFF;
#endif
} else if(calPre <= 0) {
reg.clkdiv_pre = 0;
} else {

View File

@ -19,22 +19,14 @@
extern "C" {
#endif
#include "sdkconfig.h"
#include <stdint.h>
#include <stdbool.h>
#define SPI_HAS_TRANSACTION
#if CONFIG_IDF_TARGET_ESP32C3
#define FSPI 0
#define HSPI 1
#else
#define FSPI 1 //SPI bus attached to the flash (can use the same data lines but different SS)
#define HSPI 2 //SPI bus normally mapped to pins 12 - 15, but can be matrixed to any pins
#if CONFIG_IDF_TARGET_ESP32
#define VSPI 3 //SPI bus normally attached to pins 5, 18, 19 and 23, but can be matrixed to any pins
#endif
#endif
// This defines are not representing the real Divider of the ESP32
// the Defines match to an AVR Arduino on 16MHz for better compatibility
@ -62,7 +54,7 @@ extern "C" {
struct spi_struct_t;
typedef struct spi_struct_t spi_t;
spi_t * spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_t bitOrder);
spi_t * spiStartBus(uint8_t spi_num, uint32_t freq, uint8_t dataMode, uint8_t bitOrder);
void spiStopBus(spi_t * spi);
//Attach/Detach Signal Pins

View File

@ -14,8 +14,7 @@
#include "esp32-hal.h"
#include "lwip/apps/sntp.h"
//#include "tcpip_adapter.h"
#include "esp_netif.h"
#include "tcpip_adapter.h"
static void setTimeZone(long offset, int daylight)
{
@ -44,13 +43,10 @@ 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)
{
//tcpip_adapter_init(); // Should not hurt anything if already inited
esp_netif_init();
tcpip_adapter_init(); // Should not hurt anything if already inited
if(sntp_enabled()){
sntp_stop();
}
@ -65,13 +61,10 @@ 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)
{
//tcpip_adapter_init(); // Should not hurt anything if already inited
esp_netif_init();
tcpip_adapter_init(); // Should not hurt anything if already inited
if(sntp_enabled()){
sntp_stop();
}

View File

@ -14,28 +14,17 @@
#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 "soc/dport_reg.h"
#include "esp_attr.h"
#include "driver/periph_ctrl.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
@ -47,7 +36,7 @@
#define HWTIMER_LOCK() portENTER_CRITICAL(timer->lock)
#define HWTIMER_UNLOCK() portEXIT_CRITICAL(timer->lock)
typedef volatile struct {
typedef struct {
union {
struct {
uint32_t reserved0: 10;
@ -89,7 +78,7 @@ static hw_timer_t hw_timer[4] = {
typedef void (*voidFuncPtr)(void);
static voidFuncPtr __timerInterruptHandlers[4] = {0,0,0,0};
void ARDUINO_ISR_ATTR __timerISR(void * arg){
void IRAM_ATTR __timerISR(void * arg){
uint32_t s0 = TIMERG0.int_st_timers.val;
uint32_t s1 = TIMERG1.int_st_timers.val;
TIMERG0.int_clr_timers.val = s0;
@ -112,9 +101,8 @@ void ARDUINO_ISR_ATTR __timerISR(void * arg){
}
}
uint64_t inline timerRead(hw_timer_t *timer){
uint64_t timerRead(hw_timer_t *timer){
timer->dev->update = 1;
while (timer->dev->update) {};
uint64_t h = timer->dev->cnt_high;
uint64_t l = timer->dev->cnt_low;
return (h << 32) | l;
@ -226,29 +214,15 @@ hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp){
}
hw_timer_t * timer = &hw_timer[num];
if(timer->group) {
periph_module_enable(PERIPH_TIMG1_MODULE);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_TIMERGROUP1_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_TIMERGROUP1_RST);
TIMERG1.int_ena.val &= ~BIT(timer->timer);
} else {
periph_module_enable(PERIPH_TIMG0_MODULE);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_TIMERGROUP_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_TIMERGROUP_RST);
TIMERG0.int_ena.val &= ~BIT(timer->timer);
}
timer->dev->config.enable = 0;
if(timer->group) {
#if CONFIG_IDF_TARGET_ESP32
TIMERG1.int_ena.val &= ~BIT(timer->timer);
#else
TIMERG1.int_ena_timers.val &= ~BIT(timer->timer);
#endif
TIMERG1.int_clr_timers.val |= BIT(timer->timer);
} else {
#if CONFIG_IDF_TARGET_ESP32
TIMERG0.int_ena.val &= ~BIT(timer->timer);
#else
TIMERG0.int_ena_timers.val &= ~BIT(timer->timer);
#endif
TIMERG0.int_clr_timers.val |= BIT(timer->timer);
}
#ifdef TIMER_GROUP_SUPPORTS_XTAL_CLOCK
timer->dev->config.use_xtal = 0;
#endif
timerSetDivider(timer, divider);
timerSetCountUp(timer, countUp);
timerSetAutoReload(timer, false);
@ -266,12 +240,6 @@ void timerEnd(hw_timer_t *timer){
}
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...");
edge = false;
}
#endif
static bool initialized = false;
static intr_handle_t intr_handle = NULL;
if(intr_handle){
@ -282,19 +250,9 @@ void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){
timer->dev->config.edge_int_en = 0;
timer->dev->config.alarm_en = 0;
if(timer->num & 2){
#if CONFIG_IDF_TARGET_ESP32
TIMERG1.int_ena.val &= ~BIT(timer->timer);
#else
TIMERG1.int_ena_timers.val &= ~BIT(timer->timer);
#endif
TIMERG1.int_clr_timers.val |= BIT(timer->timer);
} else {
#if CONFIG_IDF_TARGET_ESP32
TIMERG0.int_ena.val &= ~BIT(timer->timer);
#else
TIMERG0.int_ena_timers.val &= ~BIT(timer->timer);
#endif
TIMERG0.int_clr_timers.val |= BIT(timer->timer);
}
__timerInterruptHandlers[timer->num] = NULL;
} else {
@ -302,15 +260,12 @@ void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){
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;
@ -318,25 +273,16 @@ void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){
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);
esp_intr_alloc(intr_source, (int)(ESP_INTR_FLAG_IRAM|ESP_INTR_FLAG_LOWMED|ESP_INTR_FLAG_EDGE), __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){
#if CONFIG_IDF_TARGET_ESP32
TIMERG1.int_ena.val |= BIT(timer->timer);
#else
TIMERG1.int_ena_timers.val |= BIT(timer->timer);
#endif
} else {
#if CONFIG_IDF_TARGET_ESP32
TIMERG0.int_ena.val |= BIT(timer->timer);
#else
TIMERG0.int_ena_timers.val |= BIT(timer->timer);
#endif
}
}
if(intr_handle){

View File

@ -1,696 +0,0 @@
#include "sdkconfig.h"
#if CONFIG_TINYUSB_ENABLED
#include <stdlib.h>
#include <stdbool.h>
#include "esp_log.h"
#include "soc/soc.h"
#include "soc/efuse_reg.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/usb_struct.h"
#include "soc/usb_reg.h"
#include "soc/usb_wrap_reg.h"
#include "soc/usb_wrap_struct.h"
#include "soc/usb_periph.h"
#include "soc/periph_defs.h"
#include "soc/timer_group_struct.h"
#include "soc/system_reg.h"
#include "hal/usb_hal.h"
#include "hal/gpio_ll.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/periph_ctrl.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "esp_rom_gpio.h"
#include "esp32-hal.h"
#include "esp32-hal-tinyusb.h"
#include "esp32s2/rom/usb/usb_persist.h"
#include "esp32s2/rom/usb/usb_dc.h"
#include "esp32s2/rom/usb/chip_usb_dw_wrapper.h"
typedef enum{
TINYUSB_USBDEV_0,
} tinyusb_usbdev_t;
typedef char *tusb_desc_strarray_device_t[USB_STRING_DESCRIPTOR_ARRAY_SIZE];
typedef struct {
bool external_phy;
} tinyusb_config_t;
static void configure_pins(usb_hal_context_t *usb)
{
for (const usb_iopin_dsc_t *iopin = usb_periph_iopins; iopin->pin != -1; ++iopin) {
if ((usb->use_external_phy) || (iopin->ext_phy_only == 0)) {
esp_rom_gpio_pad_select_gpio(iopin->pin);
if (iopin->is_output) {
esp_rom_gpio_connect_out_signal(iopin->pin, iopin->func, false, false);
} else {
esp_rom_gpio_connect_in_signal(iopin->pin, iopin->func, false);
if ((iopin->pin != GPIO_FUNC_IN_LOW) && (iopin->pin != GPIO_FUNC_IN_HIGH)) {
gpio_ll_input_enable(&GPIO, iopin->pin);
}
}
esp_rom_gpio_pad_unhold(iopin->pin);
}
}
if (!usb->use_external_phy) {
gpio_set_drive_capability(USBPHY_DM_NUM, GPIO_DRIVE_CAP_3);
gpio_set_drive_capability(USBPHY_DP_NUM, GPIO_DRIVE_CAP_3);
}
}
esp_err_t tinyusb_driver_install(const tinyusb_config_t *config)
{
usb_hal_context_t hal = {
.use_external_phy = config->external_phy
};
usb_hal_init(&hal);
configure_pins(&hal);
if (!tusb_init()) {
log_e("Can't initialize the TinyUSB stack.");
return ESP_FAIL;
}
return ESP_OK;
}
typedef char tusb_str_t[127];
static bool WEBUSB_ENABLED = false;
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;
/*
* Device Descriptor
* */
static tusb_desc_device_t tinyusb_device_descriptor = {
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0,
.bDeviceClass = 0,
.bDeviceSubClass = 0,
.bDeviceProtocol = 0,
.bMaxPacketSize0 = CFG_TUD_ENDOINT0_SIZE,
.idVendor = 0,
.idProduct = 0,
.bcdDevice = 0,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01
};
/*
* String Descriptors
* */
#define MAX_STRING_DESCRIPTORS 20
static uint32_t tinyusb_string_descriptor_len = 4;
static char * tinyusb_string_descriptor[MAX_STRING_DESCRIPTORS] = {
// array of pointer to string descriptors
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
};
/* Microsoft OS 2.0 registry property descriptor
Per MS requirements https://msdn.microsoft.com/en-us/library/windows/hardware/hh450799(v=vs.85).aspx
device should create DeviceInterfaceGUIDs. It can be done by driver and
in case of real PnP solution device should expose MS "Microsoft OS 2.0
registry property descriptor". Such descriptor can insert any record
into Windows registry per device/configuration/interface. In our case it
will insert "DeviceInterfaceGUIDs" multistring property.
GUID is freshly generated and should be OK to use.
https://developers.google.com/web/fundamentals/native-hardware/build-for-webusb/
(Section Microsoft OS compatibility descriptors)
*/
#define MS_OS_20_DESC_LEN 0xB2
static uint8_t const tinyusb_ms_os_20_descriptor[] =
{
// Set header: length, type, windows version, total length
U16_TO_U8S_LE(0x000A), U16_TO_U8S_LE(MS_OS_20_SET_HEADER_DESCRIPTOR), U32_TO_U8S_LE(0x06030000), U16_TO_U8S_LE(MS_OS_20_DESC_LEN),
// Configuration subset header: length, type, configuration index, reserved, configuration total length
U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_CONFIGURATION), 0, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A),
// Function Subset header: length, type, first interface, reserved, subset length
U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_FUNCTION), 0, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08),
// MS OS 2.0 Compatible ID descriptor: length, type, compatible ID, sub compatible ID
U16_TO_U8S_LE(0x0014), U16_TO_U8S_LE(MS_OS_20_FEATURE_COMPATBLE_ID), 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sub-compatible
// MS OS 2.0 Registry property descriptor: length, type
U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08-0x08-0x14), U16_TO_U8S_LE(MS_OS_20_FEATURE_REG_PROPERTY),
U16_TO_U8S_LE(0x0007), U16_TO_U8S_LE(0x002A), // wPropertyDataType, wPropertyNameLength and PropertyName "DeviceInterfaceGUIDs\0" in UTF-16
'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00, 't', 0x00, 'e', 0x00,
'r', 0x00, 'f', 0x00, 'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00, 0x00, 0x00,
U16_TO_U8S_LE(0x0050), // wPropertyDataLength
//bPropertyData: “{975F44D9-0D08-43FD-8B3E-127CA8AFFF9D}”.
'{', 0x00, '9', 0x00, '7', 0x00, '5', 0x00, 'F', 0x00, '4', 0x00, '4', 0x00, 'D', 0x00, '9', 0x00, '-', 0x00,
'0', 0x00, 'D', 0x00, '0', 0x00, '8', 0x00, '-', 0x00, '4', 0x00, '3', 0x00, 'F', 0x00, 'D', 0x00, '-', 0x00,
'8', 0x00, 'B', 0x00, '3', 0x00, 'E', 0x00, '-', 0x00, '1', 0x00, '2', 0x00, '7', 0x00, 'C', 0x00, 'A', 0x00,
'8', 0x00, 'A', 0x00, 'F', 0x00, 'F', 0x00, 'F', 0x00, '9', 0x00, 'D', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00
};
TU_VERIFY_STATIC(sizeof(tinyusb_ms_os_20_descriptor) == MS_OS_20_DESC_LEN, "Incorrect size");
/*
* BOS Descriptor (required for webUSB)
* */
#define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN + TUD_BOS_WEBUSB_DESC_LEN + TUD_BOS_MICROSOFT_OS_DESC_LEN)
enum {
VENDOR_REQUEST_WEBUSB = 1,
VENDOR_REQUEST_MICROSOFT = 2
};
static uint8_t const tinyusb_bos_descriptor[] = {
// total length, number of device caps
TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 2),
// Vendor Code, iLandingPage
TUD_BOS_WEBUSB_DESCRIPTOR(VENDOR_REQUEST_WEBUSB, 1),
// Microsoft OS 2.0 descriptor
TUD_BOS_MS_OS_20_DESCRIPTOR(MS_OS_20_DESC_LEN, VENDOR_REQUEST_MICROSOFT)
};
/*
* URL Descriptor (required for webUSB)
* */
typedef struct TU_ATTR_PACKED {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bScheme;
char url[127];
} tinyusb_desc_webusb_url_t;
static tinyusb_desc_webusb_url_t tinyusb_url_descriptor = {
.bLength = 3,
.bDescriptorType = 3, // WEBUSB URL type
.bScheme = 255, // URL Scheme Prefix: 0: "http://", 1: "https://", 255: ""
.url = ""
};
/*
* Configuration Descriptor
* */
static tinyusb_descriptor_cb_t tinyusb_loaded_interfaces_callbacks[USB_INTERFACE_MAX];
static uint32_t tinyusb_loaded_interfaces_mask = 0;
static uint8_t tinyusb_loaded_interfaces_num = 0;
static uint16_t tinyusb_config_descriptor_len = 0;
static uint8_t * tinyusb_config_descriptor = NULL;
/*
* Endpoint Usage Tracking
* */
typedef union {
struct {
uint32_t in:16;
uint32_t out:16;
};
uint32_t val;
} tinyusb_endpoints_usage_t;
static tinyusb_endpoints_usage_t tinyusb_endpoints;
/*
* TinyUSB Callbacks
* */
/**
* @brief Invoked when received GET CONFIGURATION DESCRIPTOR.
*/
__attribute__ ((weak)) uint8_t const *tud_descriptor_configuration_cb(uint8_t index)
{
//log_d("%u", index);
return tinyusb_config_descriptor;
}
/**
* @brief Invoked when received GET DEVICE DESCRIPTOR.
*/
__attribute__ ((weak)) uint8_t const *tud_descriptor_device_cb(void)
{
//log_d("");
return (uint8_t const *)&tinyusb_device_descriptor;
}
/**
* @brief Invoked when received GET STRING DESCRIPTOR request.
*/
__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];
uint8_t chr_count;
if (index == 0) {
memcpy(&_desc_str[1], tinyusb_string_descriptor[0], 2);
chr_count = 1;
} else {
// Convert ASCII string into UTF-16
if (index >= tinyusb_string_descriptor_len) {
return NULL;
}
const char *str = tinyusb_string_descriptor[index];
// Cap at max char
chr_count = strlen(str);
if (chr_count > 126) {
chr_count = 126;
}
for (uint8_t i = 0; i < chr_count; i++) {
_desc_str[1 + i] = str[i];
}
}
// first byte is len, second byte is string type
_desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2);
return _desc_str;
}
/**
* @brief Invoked when received GET BOS DESCRIPTOR request.
*/
uint8_t const * tud_descriptor_bos_cb(void)
{
//log_v("");
return tinyusb_bos_descriptor;
}
__attribute__ ((weak)) bool tinyusb_vendor_control_request_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request){ return false; }
/**
* @brief Handle WebUSB and Vendor requests.
*/
bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
{
if(WEBUSB_ENABLED && (request->bRequest == VENDOR_REQUEST_WEBUSB
|| (request->bRequest == VENDOR_REQUEST_MICROSOFT && request->wIndex == 7))){
// we only care for SETUP stage
if (stage == CONTROL_STAGE_SETUP) {
if(request->bRequest == VENDOR_REQUEST_WEBUSB){
// match vendor request in BOS descriptor
// Get landing page url
tinyusb_url_descriptor.bLength = 3 + strlen(WEBUSB_URL);
snprintf(tinyusb_url_descriptor.url, 127, "%s", WEBUSB_URL);
return tud_control_xfer(rhport, request, (void*) &tinyusb_url_descriptor, tinyusb_url_descriptor.bLength);
}
// Get Microsoft OS 2.0 compatible descriptor
uint16_t total_len;
memcpy(&total_len, tinyusb_ms_os_20_descriptor + 8, 2);
return tud_control_xfer(rhport, request, (void*) tinyusb_ms_os_20_descriptor, total_len);
}
return true;
}
log_v("rhport: %u, stage: %u, type: 0x%x, request: 0x%x", rhport, stage, request->bmRequestType_bit.type, request->bRequest);
return tinyusb_vendor_control_request_cb(rhport, stage, request);
}
/*
* Required Callbacks
* */
#if CFG_TUD_HID
__attribute__ ((weak)) const uint8_t * tud_hid_descriptor_report_cb(uint8_t itf){return NULL;}
__attribute__ ((weak)) uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen){return 0;}
__attribute__ ((weak)) void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, const uint8_t * buffer, uint16_t bufsize){}
#endif
#if CFG_TUD_MSC
__attribute__ ((weak)) bool tud_msc_test_unit_ready_cb(uint8_t lun){return false;}
__attribute__ ((weak)) void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]){}
__attribute__ ((weak)) void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size){}
__attribute__ ((weak)) int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize){return -1;}
__attribute__ ((weak)) int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize){return -1;}
__attribute__ ((weak)) int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize){return -1;}
#endif
/*
* Private API
* */
static bool usb_persist_enabled = false;
static restart_type_t usb_persist_mode = RESTART_NO_PERSIST;
static bool tinyusb_reserve_in_endpoint(uint8_t endpoint){
if(endpoint > 6 || (tinyusb_endpoints.in & BIT(endpoint)) != 0){
return false;
}
tinyusb_endpoints.in |= BIT(endpoint);
return true;
}
static bool tinyusb_reserve_out_endpoint(uint8_t endpoint){
if(endpoint > 6 || (tinyusb_endpoints.out & BIT(endpoint)) != 0){
return false;
}
tinyusb_endpoints.out |= BIT(endpoint);
return true;
}
static bool tinyusb_has_available_fifos(void){
uint8_t max_endpoints = 4, active_endpoints = 0;
if (tinyusb_loaded_interfaces_mask & BIT(USB_INTERFACE_CDC)) {
max_endpoints = 5; //CDC endpoint 0x85 is actually not linked to FIFO and not used
}
for(uint8_t i=1; i<7; i++){
if((tinyusb_endpoints.in & BIT(i)) != 0){
active_endpoints++;
}
}
return active_endpoints < max_endpoints;
}
static uint16_t tinyusb_load_descriptor(tinyusb_interface_t interface, uint8_t * dst, uint8_t * itf)
{
if(tinyusb_loaded_interfaces_callbacks[interface]){
return tinyusb_loaded_interfaces_callbacks[interface](dst, itf);
}
return 0;
}
static bool tinyusb_load_enabled_interfaces(){
tinyusb_config_descriptor_len += TUD_CONFIG_DESC_LEN;
tinyusb_config_descriptor = (uint8_t *)malloc(tinyusb_config_descriptor_len);
if (tinyusb_config_descriptor == NULL) {
log_e("Descriptor Malloc Failed");
return false;
}
uint8_t * dst = tinyusb_config_descriptor + TUD_CONFIG_DESC_LEN;
for(int i=0; i<USB_INTERFACE_MAX; i++){
if (tinyusb_loaded_interfaces_mask & (1U << i)) {
uint16_t len = tinyusb_load_descriptor((tinyusb_interface_t)i, dst, &tinyusb_loaded_interfaces_num);
if (!len) {
log_e("Descriptor Load Failed");
return false;
} else {
dst += len;
}
}
}
uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB Device");
uint8_t descriptor[TUD_CONFIG_DESC_LEN] = {
//num configs, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, tinyusb_loaded_interfaces_num, str_index, tinyusb_config_descriptor_len, USB_DEVICE_ATTRIBUTES, USB_DEVICE_POWER)
};
memcpy(tinyusb_config_descriptor, descriptor, TUD_CONFIG_DESC_LEN);
if ((tinyusb_loaded_interfaces_mask == (BIT(USB_INTERFACE_CDC) | BIT(USB_INTERFACE_DFU))) || (tinyusb_loaded_interfaces_mask == BIT(USB_INTERFACE_CDC))) {
//usb_persist_enabled = true;
//log_d("USB Persist enabled");
}
log_d("Load Done: if_num: %u, descr_len: %u, if_mask: 0x%x", tinyusb_loaded_interfaces_num, tinyusb_config_descriptor_len, tinyusb_loaded_interfaces_mask);
return true;
}
static inline char nibble_to_hex_char(uint8_t b)
{
if (b < 0xa) {
return '0' + b;
} else {
return 'a' + b - 0xa;
}
}
static void set_usb_serial_num(void)
{
/* Get the MAC address */
const uint32_t mac0 = REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_0_REG, EFUSE_MAC_0);
const uint32_t mac1 = REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_1_REG, EFUSE_MAC_1);
uint8_t mac_bytes[6];
memcpy(mac_bytes, &mac0, 4);
memcpy(mac_bytes + 4, &mac1, 2);
/* Convert to UTF16 string */
uint8_t* srl = (uint8_t*)USB_DEVICE_SERIAL;
for (int i = 0; i < 6; ++i) {
uint8_t b = mac_bytes[5 - i]; /* printing from the MSB */
if (i) {
*srl++ = ':';
}
*srl++ = nibble_to_hex_char(b >> 4);
*srl++ = nibble_to_hex_char(b & 0xf);
}
*srl++ = '\0';
}
static void tinyusb_apply_device_config(tinyusb_device_config_t *config){
if(config->product_name){
snprintf(USB_DEVICE_PRODUCT, 126, "%s", config->product_name);
}
if(config->manufacturer_name){
snprintf(USB_DEVICE_MANUFACTURER, 126, "%s", config->manufacturer_name);
}
if(config->serial_number && config->serial_number[0]){
snprintf(USB_DEVICE_SERIAL, 126, "%s", config->serial_number);
} else {
set_usb_serial_num();
}
if(config->webusb_url){
snprintf(WEBUSB_URL, 126, "%s", config->webusb_url);
}
// Windows 10 will not recognize the CDC device if WebUSB is enabled and USB Class is not 2 (CDC)
if(
(tinyusb_loaded_interfaces_mask & BIT(USB_INTERFACE_CDC))
&& config->webusb_enabled
&& (config->usb_class != TUSB_CLASS_CDC)
){
config->usb_class = TUSB_CLASS_CDC;
config->usb_protocol = 0x00;
}
WEBUSB_ENABLED = config->webusb_enabled;
USB_DEVICE_ATTRIBUTES = config->usb_attributes;
USB_DEVICE_POWER = config->usb_power_ma;
tinyusb_device_descriptor.bcdUSB = config->usb_version;
tinyusb_device_descriptor.idVendor = config->vid;
tinyusb_device_descriptor.idProduct = config->pid;
tinyusb_device_descriptor.bcdDevice = config->fw_version;
tinyusb_device_descriptor.bDeviceClass = config->usb_class;
tinyusb_device_descriptor.bDeviceSubClass = config->usb_subclass;
tinyusb_device_descriptor.bDeviceProtocol = config->usb_protocol;
}
static void IRAM_ATTR usb_persist_shutdown_handler(void)
{
if(usb_persist_mode != RESTART_NO_PERSIST){
if (usb_persist_enabled) {
usb_dc_prepare_persist();
}
if (usb_persist_mode == RESTART_BOOTLOADER) {
//USB CDC Download
if (usb_persist_enabled) {
chip_usb_set_persist_flags(USBDC_PERSIST_ENA);
} else {
periph_module_reset(PERIPH_USB_MODULE);
periph_module_enable(PERIPH_USB_MODULE);
}
REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT);
} else if (usb_persist_mode == RESTART_BOOTLOADER_DFU) {
//DFU Download
// Reset USB Core
USB0.grstctl |= USB_CSFTRST;
while ((USB0.grstctl & USB_CSFTRST) == USB_CSFTRST){}
chip_usb_set_persist_flags(USBDC_BOOT_DFU);
REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT);
} else if (usb_persist_enabled) {
//USB Persist reboot
chip_usb_set_persist_flags(USBDC_PERSIST_ENA);
}
}
}
// USB Device Driver task
// This top level thread processes all usb events and invokes callbacks
static void usb_device_task(void *param) {
(void)param;
while(1) tud_task(); // RTOS forever loop
}
/*
* 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(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 %s enabled", tinyusb_interface_names[interface]);
return ESP_OK;
}
esp_err_t tinyusb_init(tinyusb_device_config_t *config) {
if(tinyusb_is_initialized){
return ESP_OK;
}
tinyusb_is_initialized = true;
//tinyusb_endpoints.val = 0;
tinyusb_apply_device_config(config);
if (!tinyusb_load_enabled_interfaces()) {
tinyusb_is_initialized = false;
return ESP_FAIL;
}
bool usb_did_persist = (USB_WRAP.date.val == USBDC_PERSIST_ENA);
//if(usb_did_persist && usb_persist_enabled){
// Enable USB/IO_MUX peripheral reset, if coming from persistent reboot
REG_CLR_BIT(RTC_CNTL_USB_CONF_REG, RTC_CNTL_IO_MUX_RESET_DISABLE);
REG_CLR_BIT(RTC_CNTL_USB_CONF_REG, RTC_CNTL_USB_RESET_DISABLE);
//} else
if(!usb_did_persist || !usb_persist_enabled){
// Reset USB module
periph_module_reset(PERIPH_USB_MODULE);
periph_module_enable(PERIPH_USB_MODULE);
}
if (esp_register_shutdown_handler(usb_persist_shutdown_handler) != ESP_OK) {
tinyusb_is_initialized = false;
return ESP_FAIL;
}
tinyusb_config_t tusb_cfg = {
.external_phy = false // In the most cases you need to use a `false` value
};
esp_err_t err = tinyusb_driver_install(&tusb_cfg);
if (err != ESP_OK) {
tinyusb_is_initialized = false;
return err;
}
xTaskCreate(usb_device_task, "usbd", 4096, NULL, configMAX_PRIORITIES - 1, NULL);
return err;
}
void usb_persist_restart(restart_type_t mode)
{
if (mode < RESTART_TYPE_MAX) {
usb_persist_mode = mode;
esp_restart();
}
}
uint8_t tinyusb_add_string_descriptor(const char * str){
if(str == NULL || tinyusb_string_descriptor_len >= MAX_STRING_DESCRIPTORS){
return 0;
}
uint8_t index = tinyusb_string_descriptor_len;
tinyusb_string_descriptor[tinyusb_string_descriptor_len++] = (char*)str;
return index;
}
uint8_t tinyusb_get_free_duplex_endpoint(void){
if(!tinyusb_has_available_fifos()){
log_e("No available IN endpoints");
return 0;
}
for(uint8_t i=1; i<7; i++){
if((tinyusb_endpoints.in & BIT(i)) == 0 && (tinyusb_endpoints.out & BIT(i)) == 0){
tinyusb_endpoints.in |= BIT(i);
tinyusb_endpoints.out |= BIT(i);
return i;
}
}
log_e("No available duplex endpoints");
return 0;
}
uint8_t tinyusb_get_free_in_endpoint(void){
if(!tinyusb_has_available_fifos()){
log_e("No available IN endpoints");
return 0;
}
for(uint8_t i=1; i<7; i++){
if((tinyusb_endpoints.in & BIT(i)) == 0 && (tinyusb_endpoints.out & BIT(i)) != 0){
tinyusb_endpoints.in |= BIT(i);
return i;
}
}
for(uint8_t i=1; i<7; i++){
if((tinyusb_endpoints.in & BIT(i)) == 0){
tinyusb_endpoints.in |= BIT(i);
return i;
}
}
return 0;
}
uint8_t tinyusb_get_free_out_endpoint(void){
for(uint8_t i=1; i<7; i++){
if((tinyusb_endpoints.out & BIT(i)) == 0 && (tinyusb_endpoints.in & BIT(i)) != 0){
tinyusb_endpoints.out |= BIT(i);
return i;
}
}
for(uint8_t i=1; i<7; i++){
if((tinyusb_endpoints.out & BIT(i)) == 0){
tinyusb_endpoints.out |= BIT(i);
return i;
}
}
return 0;
}
#endif /* CONFIG_TINYUSB_ENABLED */

View File

@ -1,108 +0,0 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "esp32-hal.h"
#if CONFIG_IDF_TARGET_ESP32S2
#if CONFIG_TINYUSB_ENABLED
#ifdef __cplusplus
extern "C" {
#endif
#include "tusb.h"
#include "tusb_option.h"
#include "tusb_config.h"
#define USB_ESPRESSIF_VID 0x303A
#define USB_STRING_DESCRIPTOR_ARRAY_SIZE 10
typedef struct {
uint16_t vid;
uint16_t pid;
const char * product_name;
const char * manufacturer_name;
const char * serial_number;
uint16_t fw_version;
uint16_t usb_version;
uint8_t usb_class;
uint8_t usb_subclass;
uint8_t usb_protocol;
uint8_t usb_attributes;
uint16_t usb_power_ma;
bool webusb_enabled;
const char * webusb_url;
} tinyusb_device_config_t;
#define TINYUSB_CONFIG_DEFAULT() { \
.vid = USB_ESPRESSIF_VID, \
.pid = 0x0002, \
.product_name = CONFIG_TINYUSB_DESC_PRODUCT_STRING, \
.manufacturer_name = CONFIG_TINYUSB_DESC_MANUFACTURER_STRING, \
.serial_number = CONFIG_TINYUSB_DESC_SERIAL_STRING, \
.fw_version = CONFIG_TINYUSB_DESC_BCDDEVICE, \
.usb_version = 0x0200, \
.usb_class = TUSB_CLASS_MISC, \
.usb_subclass = MISC_SUBCLASS_COMMON, \
.usb_protocol = MISC_PROTOCOL_IAD, \
.usb_attributes = TUSB_DESC_CONFIG_ATT_SELF_POWERED, \
.usb_power_ma = 500, \
.webusb_enabled = false, \
.webusb_url = "espressif.github.io/arduino-esp32/webusb.html" \
}
esp_err_t tinyusb_init(tinyusb_device_config_t *config);
/*
* USB Persistence API
* */
typedef enum {
RESTART_NO_PERSIST,
RESTART_PERSIST,
RESTART_BOOTLOADER,
RESTART_BOOTLOADER_DFU,
RESTART_TYPE_MAX
} restart_type_t;
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_MSC,
USB_INTERFACE_DFU,
USB_INTERFACE_HID,
USB_INTERFACE_VENDOR,
USB_INTERFACE_CDC,
USB_INTERFACE_MIDI,
USB_INTERFACE_CUSTOM,
USB_INTERFACE_MAX
} tinyusb_interface_t;
typedef uint16_t (*tinyusb_descriptor_cb_t)(uint8_t * dst, uint8_t * itf);
esp_err_t tinyusb_enable_interface(tinyusb_interface_t interface, uint16_t descriptor_len, tinyusb_descriptor_cb_t cb);
uint8_t tinyusb_add_string_descriptor(const char * str);
uint8_t tinyusb_get_free_duplex_endpoint(void);
uint8_t tinyusb_get_free_in_endpoint(void);
uint8_t tinyusb_get_free_out_endpoint(void);
#ifdef __cplusplus
}
#endif
#endif /* CONFIG_TINYUSB_ENABLED */
#endif /* CONFIG_IDF_TARGET_ESP32S2 */

View File

@ -13,25 +13,18 @@
// limitations under the License.
#include "esp32-hal-touch.h"
#ifndef CONFIG_IDF_TARGET_ESP32C3
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_attr.h"
#include "soc/rtc_io_reg.h"
#include "soc/sens_reg.h"
#include "soc/sens_struct.h"
#include "soc/rtc_cntl_reg.h"
#include "driver/touch_sensor.h"
#include "soc/sens_reg.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"
#else
#error Target CONFIG_IDF_TARGET is not supported
#endif
@ -47,9 +40,8 @@ typedef void (*voidFuncPtr)(void);
static voidFuncPtr __touchInterruptHandlers[10] = {0,};
static intr_handle_t touch_intr_handle = NULL;
void ARDUINO_ISR_ATTR __touchISR(void * arg)
void IRAM_ATTR __touchISR(void * arg)
{
#if CONFIG_IDF_TARGET_ESP32
uint32_t pad_intr = READ_PERI_REG(SENS_SAR_TOUCH_CTRL2_REG) & 0x3ff;
uint32_t rtc_intr = READ_PERI_REG(RTC_CNTL_INT_ST_REG);
uint8_t i = 0;
@ -66,21 +58,16 @@ void ARDUINO_ISR_ATTR __touchISR(void * arg)
}
}
}
#endif
}
void __touchSetCycles(uint16_t measure, uint16_t sleep)
{
__touchSleepCycles = sleep;
__touchMeasureCycles = measure;
#if CONFIG_IDF_TARGET_ESP32
//Touch pad SleepCycle Time
SET_PERI_REG_BITS(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_SLEEP_CYCLES, __touchSleepCycles, SENS_TOUCH_SLEEP_CYCLES_S);
//Touch Pad Measure Time
SET_PERI_REG_BITS(SENS_SAR_TOUCH_CTRL1_REG, SENS_TOUCH_MEAS_DELAY, __touchMeasureCycles, SENS_TOUCH_MEAS_DELAY_S);
#else
touch_pad_set_meas_time(sleep, measure);
#endif
}
void __touchInit()
@ -90,28 +77,15 @@ void __touchInit()
return;
}
initialized = true;
#if CONFIG_IDF_TARGET_ESP32
SET_PERI_REG_BITS(RTC_IO_TOUCH_CFG_REG, RTC_IO_TOUCH_XPD_BIAS, 1, RTC_IO_TOUCH_XPD_BIAS_S);
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
touch_pad_init();
touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_0V5);
touch_pad_set_idle_channel_connect(TOUCH_PAD_CONN_GND);
__touchSetCycles(__touchMeasureCycles, __touchSleepCycles);
touch_pad_denoise_t denoise = {
.grade = TOUCH_PAD_DENOISE_BIT4,
.cap_level = TOUCH_PAD_DENOISE_CAP_L4,
};
touch_pad_denoise_set_config(&denoise);
touch_pad_denoise_enable();
touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);
touch_pad_fsm_start();
#endif
esp_intr_alloc(ETS_RTC_CORE_INTR_SOURCE, (int)ESP_INTR_FLAG_IRAM, __touchISR, NULL, &touch_intr_handle);
}
uint16_t __touchRead(uint8_t pin)
@ -125,7 +99,6 @@ uint16_t __touchRead(uint8_t pin)
__touchInit();
#if CONFIG_IDF_TARGET_ESP32
uint32_t v0 = READ_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG);
//Disable Intr & enable touch pad
WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG,
@ -157,25 +130,6 @@ uint16_t __touchRead(uint8_t pin)
//restore previous value
WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG, v0);
return touch_value;
#else
static uint32_t chan_mask = 0;
uint32_t value = 0;
if((chan_mask & (1 << pad)) == 0){
if(touch_pad_set_thresh((touch_pad_t)pad, TOUCH_PAD_THRESHOLD_MAX) != ESP_OK){
log_e("touch_pad_set_thresh failed");
} else if(touch_pad_config((touch_pad_t)pad) != ESP_OK){
log_e("touch_pad_config failed");
} else {
chan_mask |= (1 << pad);
}
}
if((chan_mask & (1 << pad)) != 0) {
if(touch_pad_read_raw_data((touch_pad_t)pad, &value) != ESP_OK){
log_e("touch_pad_read_raw_data failed");
}
}
return value;
#endif
}
void __touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), uint16_t threshold)
@ -191,7 +145,6 @@ void __touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), uint16_t thresh
__touchInterruptHandlers[pad] = userFunc;
#if CONFIG_IDF_TARGET_ESP32
//clear touch force ,select the Touch mode is Timer
CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_EN_M|SENS_TOUCH_START_FORCE_M);
@ -219,12 +172,8 @@ void __touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), uint16_t thresh
(1 << (pad + SENS_TOUCH_PAD_WORKEN_S)) | \
(1 << (pad + SENS_TOUCH_PAD_OUTEN2_S)) | \
(1 << (pad + SENS_TOUCH_PAD_OUTEN1_S)));
#else
#endif
}
extern uint16_t touchRead(uint8_t pin) __attribute__ ((weak, alias("__touchRead")));
extern void touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), uint16_t threshold) __attribute__ ((weak, alias("__touchAttachInterrupt")));
extern void touchSetCycles(uint16_t measure, uint16_t sleep) __attribute__ ((weak, alias("__touchSetCycles")));
#endif

View File

@ -14,88 +14,166 @@
#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 "driver/uart.h"
#include "hal/uart_ll.h"
#include "soc/soc_caps.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/dport_reg.h"
#include "soc/rtc.h"
#include "esp_intr_alloc.h"
#include "esp_system.h"
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
#include "esp32/rom/ets_sys.h"
#include "esp32/rom/uart.h"
#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
#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)))
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;
bool has_peek;
uint8_t peek_byte;
xQueueHandle queue;
intr_handle_t intr_handle;
};
#if CONFIG_DISABLE_HAL_LOCKS
#define UART_MUTEX_LOCK()
#define UART_MUTEX_UNLOCK()
static uart_t _uart_bus_array[] = {
{0, false, 0},
#if SOC_UART_NUM > 1
{1, false, 0},
#endif
#if SOC_UART_NUM > 2
{2, false, 0},
#endif
static uart_t _uart_bus_array[3] = {
{(volatile uart_dev_t *)(DR_REG_UART_BASE), 0, NULL, NULL},
{(volatile uart_dev_t *)(DR_REG_UART1_BASE), 1, NULL, NULL},
{(volatile uart_dev_t *)(DR_REG_UART2_BASE), 2, NULL, NULL}
};
#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[] = {
{NULL, 0, false, 0},
#if SOC_UART_NUM > 1
{NULL, 1, false, 0},
#endif
#if SOC_UART_NUM > 2
{NULL, 2, false, 0},
#endif
static uart_t _uart_bus_array[3] = {
{(volatile uart_dev_t *)(DR_REG_UART_BASE), NULL, 0, NULL, NULL},
{(volatile uart_dev_t *)(DR_REG_UART1_BASE), NULL, 1, NULL, NULL},
{(volatile uart_dev_t *)(DR_REG_UART2_BASE), NULL, 2, NULL, NULL}
};
#endif
bool uartIsDriverInstalled(uart_t* uart)
static void uart_on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb);
static void IRAM_ATTR _uart_isr(void *arg)
{
uint8_t i, c;
BaseType_t xHigherPriorityTaskWoken;
uart_t* uart;
for(i=0;i<3;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;
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;
if(uart->queue != NULL && !xQueueIsQueueFullFromISR(uart->queue)) {
xQueueSendFromISR(uart->queue, &c, &xHigherPriorityTaskWoken);
}
}
}
if (xHigherPriorityTaskWoken) {
portYIELD_FROM_ISR();
}
}
void uartEnableInterrupt(uart_t* uart)
{
UART_MUTEX_LOCK();
uart->dev->conf1.rxfifo_full_thrhd = 112;
uart->dev->conf1.rx_tout_thrhd = 2;
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)ESP_INTR_FLAG_IRAM, _uart_isr, NULL, &uart->intr_handle);
UART_MUTEX_UNLOCK();
}
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();
}
void uartDetachRx(uart_t* uart)
{
if(uart == NULL) {
return 0;
}
if (uart_is_driver_installed(uart->num)) {
return true;
}
return false;
}
void uartSetPins(uart_t* uart, uint8_t rxPin, uint8_t txPin)
{
if(uart == NULL || rxPin >= SOC_GPIO_PIN_COUNT || txPin >= SOC_GPIO_PIN_COUNT) {
return;
}
UART_MUTEX_LOCK();
ESP_ERROR_CHECK(uart_set_pin(uart->num, txPin, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
UART_MUTEX_UNLOCK();
pinMatrixInDetach(UART_RXD_IDX(uart->num), false, false);
uartDisableInterrupt(uart);
}
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 uartDetachTx(uart_t* uart)
{
if(uart_nr >= SOC_UART_NUM) {
if(uart == NULL) {
return;
}
pinMatrixOutDetach(UART_TXD_IDX(uart->num), false, false);
}
void uartAttachRx(uart_t* uart, uint8_t rxPin, bool inverted)
{
if(uart == NULL || rxPin > 39) {
return;
}
pinMode(rxPin, INPUT);
pinMatrixInAttach(rxPin, UART_RXD_IDX(uart->num), inverted);
uartEnableInterrupt(uart);
}
void uartAttachTx(uart_t* uart, uint8_t txPin, bool inverted)
{
if(uart == NULL || txPin > 39) {
return;
}
pinMode(txPin, OUTPUT);
pinMatrixOutAttach(txPin, UART_TXD_IDX(uart->num), inverted, false);
}
uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t queueLen, bool inverted)
{
if(uart_nr > 2) {
return NULL;
}
@ -105,10 +183,6 @@ 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();
@ -118,31 +192,43 @@ uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rx
}
#endif
UART_MUTEX_LOCK();
uart_config_t uart_config;
uart_config.baud_rate = 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));
if(queueLen && uart->queue == NULL) {
uart->queue = xQueueCreate(queueLen, sizeof(uint8_t)); //initialize the queue
if(uart->queue == NULL) {
return NULL;
}
}
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);
} 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);
} else {
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART_RST);
}
uartFlush(uart);
uartSetBaudRate(uart, baudrate);
UART_MUTEX_LOCK();
uart->dev->conf0.val = config;
#define TWO_STOP_BITS_CONF 0x3
#define ONE_STOP_BITS_CONF 0x1
if ( uart->dev->conf0.stop_bit_num == TWO_STOP_BITS_CONF) {
uart->dev->conf0.stop_bit_num = ONE_STOP_BITS_CONF;
uart->dev->rs485_conf.dl1_en = 1;
}
UART_MUTEX_UNLOCK();
uartFlush(uart);
if(rxPin != -1) {
uartAttachRx(uart, rxPin, inverted);
}
if(txPin != -1) {
uartAttachTx(uart, txPin, inverted);
}
addApbChangeCallback(uart, uart_on_apb_change);
return uart;
}
@ -151,110 +237,78 @@ void uartEnd(uart_t* uart)
if(uart == NULL) {
return;
}
removeApbChangeCallback(uart, uart_on_apb_change);
UART_MUTEX_LOCK();
uart_driver_delete(uart->num);
if(uart->queue != NULL) {
vQueueDelete(uart->queue);
uart->queue = NULL;
}
uart->dev->conf0.val = 0;
UART_MUTEX_UNLOCK();
uartDetachRx(uart);
uartDetachTx(uart);
}
void uartSetRxInvert(uart_t* uart, bool invert)
{
if (uart == NULL)
return;
#if 0
// POTENTIAL ISSUE :: original code only set/reset rxd_inv bit
// IDF or LL set/reset the whole inv_mask!
if (invert)
ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_RXD_INV));
else
ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_INV_DISABLE));
#else
// this implementation is better over IDF API because it only affects RXD
// this is supported in ESP32, ESP32-S2 and ESP32-C3
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
if (invert)
hw->conf0.rxd_inv = 1;
else
hw->conf0.rxd_inv = 0;
#endif
}
uint32_t uartAvailable(uart_t* uart)
{
size_t uartResizeRxBuffer(uart_t * uart, size_t new_size) {
if(uart == NULL) {
return 0;
}
UART_MUTEX_LOCK();
size_t available;
uart_get_buffered_data_len(uart->num, &available);
if (uart->has_peek) available++;
if(uart->queue != NULL) {
vQueueDelete(uart->queue);
uart->queue = xQueueCreate(new_size, sizeof(uint8_t));
if(uart->queue == NULL) {
return 0;
}
}
UART_MUTEX_UNLOCK();
return available;
return new_size;
}
uint32_t uartAvailable(uart_t* uart)
{
if(uart == NULL || uart->queue == NULL) {
return 0;
}
return uxQueueMessagesWaiting(uart->queue);
}
uint32_t uartAvailableForWrite(uart_t* uart)
{
if(uart == NULL) {
return 0;
}
UART_MUTEX_LOCK();
uint32_t available = uart_ll_get_txfifo_len(UART_LL_GET_HW(uart->num));
UART_MUTEX_UNLOCK();
return available;
return 0x7f - uart->dev->status.txfifo_cnt;
}
uint8_t uartRead(uart_t* uart)
{
if(uart == NULL) {
if(uart == NULL || uart->queue == NULL) {
return 0;
}
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;
}
uint8_t c;
if(xQueueReceive(uart->queue, &c, 0)) {
return c;
}
UART_MUTEX_UNLOCK();
return c;
return 0;
}
uint8_t uartPeek(uart_t* uart)
{
if(uart == NULL) {
if(uart == NULL || uart->queue == NULL) {
return 0;
}
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;
}
uint8_t c;
if(xQueuePeek(uart->queue, &c, 0)) {
return c;
}
UART_MUTEX_UNLOCK();
return c;
return 0;
}
void uartWrite(uart_t* uart, uint8_t c)
@ -263,24 +317,28 @@ void uartWrite(uart_t* uart, uint8_t c)
return;
}
UART_MUTEX_LOCK();
uart_write_bytes(uart->num, &c, 1);
while(uart->dev->status.txfifo_cnt == 0x7F);
uart->dev->fifo.rw_byte = c;
UART_MUTEX_UNLOCK();
}
void uartWriteBuf(uart_t* uart, const uint8_t * data, size_t len)
{
if(uart == NULL || data == NULL || !len) {
if(uart == NULL) {
return;
}
UART_MUTEX_LOCK();
uart_write_bytes(uart->num, data, len);
while(len) {
while(uart->dev->status.txfifo_cnt == 0x7F);
uart->dev->fifo.rw_byte = *data++;
len--;
}
UART_MUTEX_UNLOCK();
}
void uartFlush(uart_t* uart)
{
uartFlushTxOnly(uart, true);
uartFlushTxOnly(uart,false);
}
void uartFlushTxOnly(uart_t* uart, bool txOnly)
@ -288,13 +346,22 @@ void uartFlushTxOnly(uart_t* uart, bool txOnly)
if(uart == NULL) {
return;
}
UART_MUTEX_LOCK();
ESP_ERROR_CHECK(uart_wait_tx_done(uart->num, portMAX_DELAY));
if ( !txOnly ) {
ESP_ERROR_CHECK(uart_flush_input(uart->num));
UART_MUTEX_LOCK();
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.
// 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);
}
UART_MUTEX_UNLOCK();
}
@ -304,43 +371,82 @@ void uartSetBaudRate(uart_t* uart, uint32_t baud_rate)
return;
}
UART_MUTEX_LOCK();
uart_ll_set_baudrate(UART_LL_GET_HW(uart->num), baud_rate);
uint32_t clk_div = ((getApbFrequency()<<4)/baud_rate);
uart->dev->clk_div.div_int = clk_div>>4 ;
uart->dev->clk_div.div_frag = clk_div & 0xf;
UART_MUTEX_UNLOCK();
}
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;
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;
if(uart->queue != NULL ) {
xQueueSend(uart->queue, &c, 1); //&xHigherPriorityTaskWoken);
}
}
UART_MUTEX_UNLOCK();
// wait TX empty
while(uart->dev->status.txfifo_cnt || uart->dev->status.st_utx_out);
} 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;
}
UART_MUTEX_LOCK();
uint32_t baud_rate = uart_ll_get_baudrate(UART_LL_GET_HW(uart->num));
UART_MUTEX_UNLOCK();
return baud_rate;
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);
}
static void ARDUINO_ISR_ATTR uart0_write_char(char c)
static void IRAM_ATTR uart0_write_char(char c)
{
while (uart_ll_get_txfifo_len(&UART0) == 0);
uart_ll_write_txfifo(&UART0, (const uint8_t *) &c, 1);
while(((ESP_REG(0x01C+DR_REG_UART_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) == 0x7F);
ESP_REG(DR_REG_UART_BASE) = c;
}
#if SOC_UART_NUM > 1
static void ARDUINO_ISR_ATTR uart1_write_char(char c)
static void IRAM_ATTR uart1_write_char(char c)
{
while (uart_ll_get_txfifo_len(&UART1) == 0);
uart_ll_write_txfifo(&UART1, (const uint8_t *) &c, 1);
while(((ESP_REG(0x01C+DR_REG_UART1_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) == 0x7F);
ESP_REG(DR_REG_UART1_BASE) = c;
}
#endif
#if SOC_UART_NUM > 2
static void ARDUINO_ISR_ATTR uart2_write_char(char c)
static void IRAM_ATTR uart2_write_char(char c)
{
while (uart_ll_get_txfifo_len(&UART2) == 0);
uart_ll_write_txfifo(&UART2, (const uint8_t *) &c, 1);
while(((ESP_REG(0x01C+DR_REG_UART2_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) == 0x7F);
ESP_REG(DR_REG_UART2_BASE) = c;
}
#endif
void uart_install_putc()
{
@ -348,16 +454,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;
#endif
#if SOC_UART_NUM > 2
case 2:
ets_install_putc1((void (*)(char)) &uart2_write_char);
break;
#endif
default:
ets_install_putc1(NULL);
break;
@ -366,11 +468,15 @@ void uart_install_putc()
void uartSetDebug(uart_t* uart)
{
if(uart == NULL || uart->num >= SOC_UART_NUM) {
if(uart == NULL || uart->num > 2) {
s_uart_debug_nr = -1;
} else {
s_uart_debug_nr = uart->num;
}
//ets_install_putc1(NULL);
//return;
} else
if(s_uart_debug_nr == uart->num) {
return;
} else
s_uart_debug_nr = uart->num;
uart_install_putc();
}
@ -381,6 +487,9 @@ int uartGetDebug()
int log_printf(const char *format, ...)
{
if(s_uart_debug_nr < 0){
return 0;
}
static char loc_buf[64];
char * temp = loc_buf;
int len;
@ -396,19 +505,17 @@ int log_printf(const char *format, ...)
return 0;
}
}
#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);
}
#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){
if(_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
ets_printf("%s", temp);
#endif
va_end(arg);
if(len >= sizeof(loc_buf)){
@ -417,126 +524,46 @@ 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)
{
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)
while(uart->dev->rxd_cnt.edge_cnt < 30) { // UART_PULSE_NUM(uart_num)
if(flg) return 0;
ets_delay_us(1000);
}
UART_MUTEX_LOCK();
//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);
unsigned long ret = ((uart->dev->lowpulse.min_cnt + uart->dev->highpulse.min_cnt) >> 1) + 12;
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 == NULL) {
return;
}
if(!uart) 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
uart->dev->auto_baud.glitch_filt = 0x08;
uart->dev->auto_baud.en = 0;
uart->dev->auto_baud.en = 1;
}
unsigned long
uartDetectBaudrate(uart_t *uart)
{
if(uart == NULL) {
return 0;
}
#ifndef CONFIG_IDF_TARGET_ESP32C3 // ESP32-C3 requires further testing - Baud rate detection returns wrong values
static bool uartStateDetectingBaudrate = false;
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
if(!uartStateDetectingBaudrate) {
uartStartDetectBaudrate(uart);
uart->dev->auto_baud.glitch_filt = 0x08;
uart->dev->auto_baud.en = 0;
uart->dev->auto_baud.en = 1;
uartStateDetectingBaudrate = true;
}
@ -544,21 +571,11 @@ 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));
#ifdef CONFIG_IDF_TARGET_ESP32C3
//hw->conf0.autobaud_en = 0;
#else
hw->auto_baud.en = 0;
#endif
uart->dev->auto_baud.en = 0;
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};
@ -575,8 +592,11 @@ uartDetectBaudrate(uart_t *uart)
}
return default_rates[i];
#else
log_e("ESP32-C3 baud rate detection is not supported.");
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) {
return uart->dev->status.st_urx_out != 0;
}

View File

@ -51,7 +51,7 @@ extern "C" {
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);
uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t queueLen, bool inverted);
void uartEnd(uart_t* uart);
uint32_t uartAvailable(uart_t* uart);
@ -68,17 +68,15 @@ void uartFlushTxOnly(uart_t* uart, bool txOnly );
void uartSetBaudRate(uart_t* uart, uint32_t baud_rate);
uint32_t uartGetBaudRate(uart_t* uart);
void uartSetRxInvert(uart_t* uart, bool invert);
size_t uartResizeRxBuffer(uart_t* uart, size_t new_size);
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

@ -20,6 +20,10 @@
#ifndef HAL_ESP32_HAL_H_
#define HAL_ESP32_HAL_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
@ -31,38 +35,9 @@
#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" {
#endif
#ifndef F_CPU
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
#define F_CPU (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ * 1000000U)
#elif CONFIG_IDF_TARGET_ESP32S2
#define F_CPU (CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ * 1000000U)
#endif
#endif
#if CONFIG_ARDUINO_ISR_IRAM
#define ARDUINO_ISR_ATTR IRAM_ATTR
#define ARDUINO_ISR_FLAG ESP_INTR_FLAG_IRAM
#else
#define ARDUINO_ISR_ATTR
#define ARDUINO_ISR_FLAG (0)
#endif
#ifndef ARDUINO_RUNNING_CORE
#define ARDUINO_RUNNING_CORE CONFIG_ARDUINO_RUNNING_CORE
#endif
#ifndef ARDUINO_EVENT_RUNNING_CORE
#define ARDUINO_EVENT_RUNNING_CORE CONFIG_ARDUINO_EVENT_RUNNING_CORE
#endif
//forward declaration from freertos/portmacro.h
@ -90,7 +65,11 @@ void yield(void);
#include "esp32-hal-psram.h"
#include "esp32-hal-cpu.h"
void analogWrite(uint8_t pin, int value);
#ifndef BOARD_HAS_PSRAM
#ifdef CONFIG_SPIRAM_SUPPORT
#undef CONFIG_SPIRAM_SUPPORT
#endif
#endif
//returns chip temperature in Celsius
float temperatureRead();

View File

@ -18,7 +18,7 @@
#define _ESP8266_COMPAT_H_
#define ICACHE_FLASH_ATTR
#define ICACHE_RAM_ATTR ARDUINO_ISR_ATTR
#define ICACHE_RAM_ATTR IRAM_ATTR
#endif /* _ESP8266_COMPAT_H_ */

View File

@ -1,46 +0,0 @@
// Copyright 2019 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
/** Major version number (X.x.x) */
#define ESP_ARDUINO_VERSION_MAJOR 2
/** Minor version number (x.X.x) */
#define ESP_ARDUINO_VERSION_MINOR 0
/** Patch version number (x.x.X) */
#define ESP_ARDUINO_VERSION_PATCH 0
/**
* Macro to convert ARDUINO version number into an integer
*
* To be used in comparisons, such as ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(2, 0, 0)
*/
#define ESP_ARDUINO_VERSION_VAL(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
/**
* Current ARDUINO version, as an integer
*
* To be used in comparisons, such as ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(2, 0, 0)
*/
#define ESP_ARDUINO_VERSION ESP_ARDUINO_VERSION_VAL(ESP_ARDUINO_VERSION_MAJOR, \
ESP_ARDUINO_VERSION_MINOR, \
ESP_ARDUINO_VERSION_PATCH)
#ifdef __cplusplus
}
#endif

View File

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

View File

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

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];
}

View File

@ -2,34 +2,10 @@
#include "freertos/task.h"
#include "esp_task_wdt.h"
#include "Arduino.h"
#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
#ifndef CONFIG_ARDUINO_LOOP_STACK_SIZE
#define ARDUINO_LOOP_STACK_SIZE 8192
#else
#define ARDUINO_LOOP_STACK_SIZE CONFIG_ARDUINO_LOOP_STACK_SIZE
#endif
#endif
TaskHandle_t loopTaskHandle = NULL;
#if CONFIG_AUTOSTART_ARDUINO
#if CONFIG_FREERTOS_UNICORE
void yieldIfNecessary(void){
static uint64_t lastYield = 0;
uint64_t now = millis();
if((now - lastYield) > 2000) {
lastYield = now;
vTaskDelay(5); //delay 1 RTOS tick
}
}
#endif
bool loopTaskWDTEnabled;
@ -37,9 +13,6 @@ void loopTask(void *pvParameters)
{
setup();
for(;;) {
#if CONFIG_FREERTOS_UNICORE
yieldIfNecessary();
#endif
if(loopTaskWDTEnabled){
esp_task_wdt_reset();
}
@ -50,21 +23,9 @@ void loopTask(void *pvParameters)
extern "C" void app_main()
{
#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", 8192, NULL, 1, &loopTaskHandle, CONFIG_ARDUINO_RUNNING_CORE);
}
#endif

View File

@ -53,8 +53,6 @@ typedef unsigned long prog_uint32_t;
*(void * const *)(_addr); \
})
#define pgm_get_far_address(x) ((uint32_t)(&(x)))
#define pgm_read_byte_near(addr) pgm_read_byte(addr)
#define pgm_read_word_near(addr) pgm_read_word(addr)
#define pgm_read_dword_near(addr) pgm_read_dword(addr)

View File

@ -28,9 +28,8 @@
#include <stdint.h>
#include <math.h>
#include "stdlib_noniso.h"
#include "esp_system.h"
static void reverse(char* begin, char* end) {
void reverse(char* begin, char* end) {
char *is = begin;
char *ie = end - 1;
while(is < ie) {

View File

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

View File

@ -16,7 +16,7 @@
Boston, MA 02111-1307 USA
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
*/
#include "esp32-hal.h"
#include "wiring_private.h"

View File

@ -1,122 +0,0 @@
# Arduino-ESP32 Example/Library Name ==(REQUIRED)==
==*Add a brief description about this example/library here!*==
This example/library demonstrates how to create a new example README file.
# Supported Targets ==(REQUIRED)==
==*Add the supported devices here!*==
Currently, this example supports the following targets.
| Supported Targets | ESP32 | ESP32-S2 | ESP32-C3 |
| ----------------- | ----- | -------- | -------- |
## How to Use Example/Library ==(OPTIONAL)==
==*Add a brief description on how to use this example.*==
* How to install the Arduino IDE: [Install Arduino IDE](https://github.com/espressif/arduino-esp32/tree/master/docs/arduino-ide).
### Hardware Connection ==(OPTIONAL)==
==*Add a brief description about wiring or any other hardware specific connection.*==
To use this example, you need to connect the LED to the `GPIOx`.
SDCard GPIO connection scheme:
| SDCard Pin | Function | GPIO |
| ----------- | -------- | ------ |
| 1 | CS | GPIO5 |
| 2 | DI/MOSI | GPIO23 |
| 3 | VSS/GND | GND |
| 4 | VDD/3V3 | 3V3 |
| 5 | SCLK | GPIO18 |
| 6 | VSS/GND | GND |
| 7 | DO/MISO | GPIO19 |
To add images, please create a folder `_asset` inside the example folder to add the relevant images.
### Configure the Project ==(OPTIONAL)==
==*Add a brief description about this example here!*==
Set the LED GPIO by changing the `LED_BUILTIN` value in the function `pinMode(LED_BUILTIN, OUTPUT);`. By default, the GPIO is: `GPIOx`.
#### Example for the GPIO4:
==*Add some code explanation if relevant to the example.*==
```cpp
// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin 4 as an output.
pinMode(4, OUTPUT);
}
```
#### Using Arduino IDE
To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits).
* Before Compile/Verify, select the correct board: `Tools -> Board`.
* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port.
#### Using Platform IO
* Select the COM port: `Devices` or setting the `upload_port` option on the `platformio.ini` file.
## Example/Log Output ==(OPTIONAL)==
==*Add the log/serial output here!*==
```
ets Jul 29 2019 12:21:46
rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1412
load:0x40078000,len:13400
load:0x40080400,len:3672
entry 0x400805f8
ESP32 Chip model = ESP32-D0WDQ5 Rev 3
This chip has 2 cores
Chip ID: 3957392
```
## Troubleshooting ==(REQUIRED)==
==*Add specific issues you may find by using this example here!*==
***Important: Make sure you are using a good quality USB cable and that you have a reliable power source***
* **LED not blinking:** Check the wiring connection and the IO selection.
* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed.
* **COM port not detected:** Check the USB cable and the USB to Serial driver installation.
If the error persist, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute).
## Contribute ==(REQUIRED)==
==*Do not change! Keep as is.*==
To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst)
If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome!
Before creating a new issue, be sure to try the Troubleshooting and to check if the same issue was already created by someone else.
## Resources ==(REQUIRED)==
==*Do not change here! Keep as is or add only relevant documents/info for this example. Do not add any purchase link/marketing stuff*==
* Official ESP32 Forum: [Link](https://esp32.com)
* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32)
* ESP32 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf)
* ESP32-S2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf)
* ESP32-C3 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf)
* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com)

View File

@ -1,28 +1,26 @@
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)
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)
Then if someone is interested and knowledgeable you might get a answer. 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***:
[ExceptionDecoder](https://github.com/me-no-dev/EspExceptionDecoder)
https://github.com/me-no-dev/EspExceptionDecoder
----------------------------- Remove above -----------------------------
### Hardware:
|||||||
|:---|---|---|---|---|---|
|<B>Board</B>|ESP32 Dev Module|node32|ttgo_lora|ESP32-S2-Saola|Custom w/ ESP32-S2-WROVER 16MB|
|<B>Version/Date</B>|1.0.4|2.0.0|0badbeef|11/jul/2017|today's master|
|<B>IDE name</B>|Arduino IDE|Atom + Platform.io|IDF component|VSCode|
|<B>Flash Frequency</B>|40Mhz|80Mhz|
|<B>PSRAM enabled</B>|yes|no|
|<B>Upload Speed</B>|115200|
|<B>Computer OS</B>|Windows 10|Mac OSX|Ubuntu|
Board: ?ESP32 Dev Module? ?node32? ?ttgo_lora?
Core Installation/update date: ?11/jul/2017?
IDE name: ?Arduino IDE? ?Platform.io? ?IDF component?
Flash Frequency: ?40Mhz?
PSRAM enabled: ?no?
Upload Speed: ?115200?
Computer OS: ?Windows 10? ?Mac OSX? ?Ubuntu?
### Description:
Describe your problem here

View File

@ -1,28 +0,0 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = source
BUILDDIR = build
LINKCHECKDIR = build/linkcheck
.PHONY: checklinks
checklinks:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(LINKCHECKDIR)
@echo
@echo "Check finished. Report is in $(LINKCHECKDIR)."
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

View File

@ -0,0 +1,59 @@
# Over the Air through Web browser
OTAWebUpdate is done with a web browser that can be useful in the following typical scenarios:
- Once the application developed and loading directly from Arduino IDE is inconvenient or not possible
- after deployment if user is unable to expose Firmware for OTA from external update server
- provide updates after deployment to small quantity of modules when setting an update server is not practicable
## Requirements
- The ESP and the computer must be connected to the same network
## Implementation
The sample implementation has been done using:
- example sketch OTAWebUpdater.ino
- ESP32 (Dev Module)
You can use another module also if it meets Flash chip size of the sketch
1-Before you begin, please make sure that you have the following software installed:
- Arduino IDE
- Host software depending on O/S you use:
- Avahi http://avahi.org/ for Linux
- Bonjour http://www.apple.com/support/bonjour/ for Windows
- Mac OSX and iOS - support is already built in / no any extra s/w is required
Prepare the sketch and configuration for initial upload with a serial port
- Start Arduino IDE and load sketch OTAWebUpdater.ino available under File > Examples > OTAWebUpdater.ino
- Update ssid and pass in the sketch so the module can join your Wi-Fi network
- Open File > Preferences, look for “Show verbose output during:” and check out “compilation” option
![verbrose](esp32verbose.PNG)
- Upload sketch (Ctrl+U)
- Now open web browser and enter the url, i.e. http://esp32.local. Once entered, browser should display a form
![login](esp32login.PNG)
> username= admin
> password= admin
**Note**-*If entering “http://ESP32.local” does not work, try replacing “ESP32” with modules IP address.This workaround is useful in case the host software installed does not work*.
Now click on Login button and browser will display a upload form
![upload](esp32upload.PNG)
For Uploading the New Firmware you need to provide the Binary File of your Code.
Exporting Binary file of the Firmware (Code)
- Open up the Arduino IDE
- Open up the Code, for Exporting up Binary file
- Now go to Sketch > export compiled Binary
![export](exportTobinary.PNG)
- Binary file is exported to the same Directory where your code is present
Once you are comfortable with this procedure go ahead and modify OTAWebUpdater.ino sketch to print some additional messages, compile it, Export new binary file and upload it using web browser to see entered changes on a Serial Monitor

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -0,0 +1,12 @@
## Installation instructions using Arduino IDE Boards Manager
### ==========================================================
- Stable release link: `https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json`
- Development release link: `https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json`
Starting with 1.6.4, Arduino allows installation of third-party platform packages using Boards Manager. We have packages available for Windows, Mac OS, and Linux (32, 64 bit and ARM).
- Install the current upstream Arduino IDE at the 1.8 level or later. The current version is at the [Arduino website](http://www.arduino.cc/en/main/software).
- Start Arduino and open Preferences window.
- Enter one of the release links above into *Additional Board Manager URLs* field. You can add multiple URLs, separating them with commas.
- Open Boards Manager from Tools > Board menu and install *esp32* platform (and don't forget to select your ESP32 board from Tools > Board menu after installation).

View File

@ -0,0 +1,36 @@
Installation instructions for Debian / Ubuntu OS
=================================================
- Install latest Arduino IDE from [arduino.cc](https://www.arduino.cc/en/Main/Software)
- Open Terminal and execute the following command (copy->paste and hit enter):
```bash
sudo usermod -a -G dialout $USER && \
sudo apt-get install git && \
wget https://bootstrap.pypa.io/get-pip.py && \
sudo python get-pip.py && \
sudo pip install pyserial && \
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 && \
python3 get.py
```
- Restart Arduino IDE
- If you have Arduino installed to ~/, modify the installation as follows, beginning at `mkdir -p ~/Arduino/hardware`:
```bash
cd ~/Arduino/hardware
mkdir -p espressif && \
cd espressif && \
git clone https://github.com/espressif/arduino-esp32.git esp32 && \
cd esp32 && \
git submodule update --init --recursive && \
cd tools && \
python3 get.py
```

View File

@ -0,0 +1,18 @@
Installation instructions for Fedora
=====================================
- Install the latest Arduino IDE from [arduino.cc](https://www.arduino.cc/en/Main/Software). `$ sudo dnf -y install arduino` will most likely install an older release.
- Open Terminal and execute the following command (copy->paste and hit enter):
```bash
sudo usermod -a -G dialout $USER && \
sudo dnf install git python3-pip python3-pyserial && \
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 && \
python get.py
```
- Restart Arduino IDE

29
docs/arduino-ide/mac.md Normal file
View File

@ -0,0 +1,29 @@
Installation instructions for Mac OS
=====================================
- Install latest Arduino IDE from [arduino.cc](https://www.arduino.cc/en/Main/Software)
- Open Terminal and execute the following command (copy->paste and hit enter):
```bash
mkdir -p ~/Documents/Arduino/hardware/espressif && \
cd ~/Documents/Arduino/hardware/espressif && \
git clone https://github.com/espressif/arduino-esp32.git esp32 && \
cd esp32 && \
git submodule update --init --recursive && \
cd 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 if necessary!
 
- If you get the error below. Install the command line dev tools with xcode-select --install and try the command above again:
```xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun```
```xcode-select --install```
- Try `python3` instead of `python` if you get the error: `IOError: [Errno socket error] [SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version (_ssl.c:590)` when running `python get.py`
- If you get the following error when running `python get.py` urllib.error.URLError: <urlopen error SSL: CERTIFICATE_VERIFY_FAILED, go to Macintosh HD > Applications > Python3.6 folder (or any other python version), and run the following scripts: Install Certificates.command and Update Shell Profile.command
- Restart Arduino IDE

View File

@ -0,0 +1,22 @@
Installation instructions for openSUSE
======================================
- Install the latest Arduino IDE from [arduino.cc](https://www.arduino.cc/en/Main/Software).
- Open Terminal and execute the following command (copy->paste and hit enter):
```bash
sudo usermod -a -G dialout $USER && \
if [ `python --version 2>&1 | grep '2.7' | wc -l` = "1" ]; then \
sudo zypper install git python-pip python-pyserial; \
else \
sudo zypper install git python3-pip python3-pyserial; \
fi && \
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 && \
python get.py
```
- Restart Arduino IDE

View File

Before

Width:  |  Height:  |  Size: 186 KiB

After

Width:  |  Height:  |  Size: 186 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

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