Compare commits
287 Commits
Author | SHA1 | Date | |
---|---|---|---|
15bbd0a187 | |||
02c3ec01cc | |||
cb5a490616 | |||
f257d6f126 | |||
aabbed0bbc | |||
a418058a66 | |||
96ad341451 | |||
2673b88582 | |||
67c99142d2 | |||
951c8bece5 | |||
4413dbbd87 | |||
ed53b6c8d4 | |||
2e53300da5 | |||
64c7f746fd | |||
1049be7d56 | |||
34c81be93b | |||
2fb2ef54ce | |||
49f525c91d | |||
b145e65975 | |||
951c32056a | |||
7a7bd37e51 | |||
a75602dc68 | |||
88789cd817 | |||
335cedf4f7 | |||
f9f70d2f73 | |||
5b207104aa | |||
1706af4656 | |||
bd54ee442b | |||
00214d5c2a | |||
381e88ec75 | |||
f87107dedb | |||
ce85cf03cc | |||
f2a20e8a38 | |||
c5bb8334d7 | |||
6de7f16f28 | |||
1688b7c179 | |||
36ff442698 | |||
93f10609f4 | |||
67583e84d6 | |||
108e467164 | |||
91bca6c074 | |||
204f360dce | |||
3f06a38f69 | |||
2f6f251400 | |||
e4acfbc54a | |||
79d53bdc4c | |||
f3f6dad14a | |||
317be68cef | |||
1f4dd7f131 | |||
8be2f7b1cc | |||
9f827a66d5 | |||
e1cdbd7816 | |||
7a35be3e7e | |||
078671d273 | |||
541cef9149 | |||
6dfaf6cdd4 | |||
92ce408f4c | |||
453af3800c | |||
44c11981d2 | |||
9eea85f9ff | |||
24b76cbb14 | |||
4a55ff970d | |||
a62979d8a0 | |||
1f59c5abec | |||
0730e0ec93 | |||
c45cff5f83 | |||
b1d072df9f | |||
929cf2c2d5 | |||
87853353db | |||
e265bd0d7c | |||
94809ce38b | |||
29455a0447 | |||
78499c459b | |||
ce680708ec | |||
90c01dab77 | |||
000d967db3 | |||
44dd99f5a5 | |||
b580bb23fd | |||
a7ea737f30 | |||
2af8cc3485 | |||
e5bd18d6aa | |||
a4118ea889 | |||
c4fcab28e4 | |||
0acbe781f5 | |||
0b0dfab3cf | |||
5fd737925f | |||
5bb8177aa1 | |||
be84c8219c | |||
31127f4260 | |||
4365a45401 | |||
023ae75b97 | |||
c5a1f3efd7 | |||
9406f8e464 | |||
65eafd16b5 | |||
d5a98f9a39 | |||
3780b5c924 | |||
1775dd1faa | |||
6972695d95 | |||
e0e5c88658 | |||
6e47e18a1b | |||
34125cee1d | |||
ee24736042 | |||
5458df0a54 | |||
e12d8c8ff1 | |||
4ada3f5804 | |||
268595c743 | |||
4a0305a05e | |||
6393dbc91b | |||
49df8778f9 | |||
f79411f3d3 | |||
db4e7667af | |||
f64ca2e084 | |||
1effae46ea | |||
d9833f9b6d | |||
0aafa05e8f | |||
16f4b0f5ba | |||
780588dce3 | |||
eac8b2def3 | |||
a9bd39de66 | |||
5eda278177 | |||
c8a4010fa6 | |||
dd25e2b9d6 | |||
cf6ab9c8a3 | |||
676f5cfe30 | |||
f4f1c8956b | |||
cbcba53dff | |||
c37557c711 | |||
8f46bade7a | |||
21947ebe76 | |||
c7bdb234bf | |||
cf43d174b7 | |||
b1bcec08f8 | |||
46d888eb68 | |||
1f4f2b6e97 | |||
ea236e28e5 | |||
5ae3e836f9 | |||
eca328e576 | |||
5b5cbb4926 | |||
aec2635b07 | |||
e7e94ea247 | |||
b5ee7ddeed | |||
10602939cc | |||
23820874ec | |||
4f9e583b29 | |||
7f87d0fc3a | |||
90fc68d83f | |||
4f8e5b54b7 | |||
483a424d0a | |||
e7d0ad2efd | |||
77f504453f | |||
67de199bac | |||
39155e70a6 | |||
f385ee4219 | |||
e30b821be1 | |||
cb7aef1e88 | |||
fb513c79fa | |||
90d3ae25af | |||
a618fc1361 | |||
0db9e2f45b | |||
a1d8b959b0 | |||
de66c39f04 | |||
1b5696a534 | |||
955675e712 | |||
2082945d36 | |||
0d6b142228 | |||
7c3a82a525 | |||
dadc101506 | |||
1b2f34b0d6 | |||
76f0a80fe7 | |||
5bfbcfc91c | |||
7a53c2d371 | |||
cb2fbe445d | |||
48becf8966 | |||
15f8853819 | |||
7856de7a57 | |||
e62ff6dc37 | |||
182499071a | |||
cdd48e4ee4 | |||
0c3597f8d7 | |||
82161bebe3 | |||
55b8f67d80 | |||
9c20f1bdd0 | |||
b45cf11ff1 | |||
fb0d63b576 | |||
5d9b98c9b0 | |||
11f89cddf6 | |||
01c8cae0dc | |||
57cf2fb9f5 | |||
41c372c143 | |||
223acb3511 | |||
f6c9faf4da | |||
89e7893b1a | |||
7a4e7066f9 | |||
f3dca15a6f | |||
9f1330c70c | |||
ec7aeb4903 | |||
9a518cd3d7 | |||
81b7c47203 | |||
e6ba8c7ac9 | |||
72eb3f32fe | |||
66b11ff2a4 | |||
404a31f445 | |||
371f382db7 | |||
425619dfea | |||
aeb4a13aad | |||
8645971981 | |||
5502879a5b | |||
46d5afb17f | |||
66746750a4 | |||
e7a2759b65 | |||
2ee66b54f0 | |||
2d3c57635d | |||
a299ddc99e | |||
93bcf5f250 | |||
bd41334265 | |||
9a0762ad2a | |||
a451c9ef0d | |||
d362e1ee1a | |||
33d9f4aa19 | |||
63c51d51fb | |||
5b845272ed | |||
5da4a47bdf | |||
3253de8792 | |||
a31f30529d | |||
35643bdd9b | |||
8dc70e0add | |||
b42739dfa4 | |||
93d5b8c672 | |||
f815a7c636 | |||
23f6e81d52 | |||
e8311b00ae | |||
4d95e3a7ea | |||
7dc769d81c | |||
4204d1e60a | |||
d7fda910fb | |||
f7fc8ab377 | |||
dd834b3372 | |||
0e55f775d3 | |||
22a488cf23 | |||
6e7cc5210d | |||
7a6900a1f2 | |||
0e0a7565e8 | |||
bd3addeb8e | |||
1cf1c8eb79 | |||
3fe7c2e8cd | |||
5d00b6eb16 | |||
419ba32432 | |||
a0ddd8a16e | |||
b8dab5ed1a | |||
2141313148 | |||
44aaf13225 | |||
560c0f45f5 | |||
4b3f5c8ed4 | |||
c282cd8f5f | |||
7e59971d2f | |||
f4b17b3033 | |||
1ab550f6f2 | |||
9be784f69b | |||
7cdfb8bc7c | |||
8134a42162 | |||
f13ff65691 | |||
e831680a41 | |||
d964873840 | |||
7e8993fc83 | |||
15bae92a72 | |||
6f23cd5988 | |||
ad4cf1461b | |||
5de03a3918 | |||
4b385690bc | |||
dd513df124 | |||
cee659563d | |||
55442a05a4 | |||
c9b3e512dd | |||
8d0e68db4f | |||
d2530850a3 | |||
7ecbb483da | |||
b0e896e9ae | |||
08f4665775 | |||
2452c1fb53 | |||
5f98370707 | |||
81b9130d8d | |||
434d02c49f | |||
15db297130 | |||
fe093a5e35 | |||
a0ef17a9dd | |||
be77bd4e27 | |||
ef99cd7fe7 |
16
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
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.
|
4
.github/scripts/check-cmakelists.sh
vendored
@ -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 -C CMakeLists.txt 2>&1 | grep COMPONENT_SRCS | sed 's/.\+COMPONENT_SRCS //' | sed 's/ )//' | tr ' ;' '\n' | sort`
|
||||
CMAKE_SRCS=`cmake --trace-expand -C CMakeLists.txt 2>&1 | grep set\(srcs | cut -d'(' -f3 | sed 's/ )//' | sed 's/srcs //' | tr ' ;' '\n' | sort`
|
||||
|
||||
if ! diff -u0 --label "Repo Files" --label "COMPONENT_SRCS" <(echo "$REPO_SRCS") <(echo "$CMAKE_SRCS"); then
|
||||
if ! diff -u0 --label "Repo Files" --label "srcs" <(echo "$REPO_SRCS") <(echo "$CMAKE_SRCS"); then
|
||||
echo "Source files in repo (-) and source files in CMakeLists.txt (+) don't match"
|
||||
echo "Edit CMakeLists.txt as appropriate to add/remove source files from COMPONENT_SRCS"
|
||||
exit 1
|
||||
|
@ -23,9 +23,9 @@ if [ ! -d "$ARDUINO_ESP32_PATH" ]; then
|
||||
git clone https://github.com/espressif/arduino-esp32.git esp32 > /dev/null 2>&1
|
||||
fi
|
||||
|
||||
echo "Updating Submodules ..."
|
||||
#echo "Updating Submodules ..."
|
||||
cd esp32
|
||||
git submodule update --init --recursive > /dev/null 2>&1
|
||||
#git submodule update --init --recursive > /dev/null 2>&1
|
||||
|
||||
echo "Installing Platform Tools ..."
|
||||
cd tools && python get.py
|
||||
|
72
.github/scripts/install-arduino-ide.sh
vendored
@ -98,8 +98,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,9 +116,10 @@ function build_sketch(){ # build_sketch <fqbn> <path-to-ino> [extra-options]
|
||||
$win_opts $xtra_opts "$sketch"
|
||||
}
|
||||
|
||||
function count_sketches() # count_sketches <examples-path>
|
||||
function count_sketches() # count_sketches <examples-path> <target-mcu>
|
||||
{
|
||||
local examples="$1"
|
||||
local target="$2"
|
||||
rm -rf sketches.txt
|
||||
if [ ! -d "$examples" ]; then
|
||||
touch sketches.txt
|
||||
@ -130,49 +131,50 @@ function count_sketches() # count_sketches <examples-path>
|
||||
local sketchdir=$(dirname $sketch)
|
||||
local sketchdirname=$(basename $sketchdir)
|
||||
local sketchname=$(basename $sketch)
|
||||
if [[ "${sketchdirname}.ino" != "$sketchname" ]]; then
|
||||
if [[ "$sketchdirname.ino" != "$sketchname" ]]; then
|
||||
continue
|
||||
fi;
|
||||
if [[ -f "$sketchdir/.test.skip" ]]; then
|
||||
elif [[ -f "$sketchdir/.skip.$target" ]]; 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> <examples-path> <chunk> <total-chunks> [extra-options]
|
||||
function build_sketches() # build_sketches <fqbn> <target-mcu> <examples-path> <chunk> <total-chunks> [extra-options]
|
||||
{
|
||||
local fqbn=$1
|
||||
local examples=$2
|
||||
local chunk_idex=$3
|
||||
local chunks_num=$4
|
||||
local xtra_opts=$5
|
||||
local target="$2"
|
||||
local examples=$3
|
||||
local chunk_idex=$4
|
||||
local chunks_num=$5
|
||||
local xtra_opts=$6
|
||||
|
||||
if [ "$#" -lt 2 ]; then
|
||||
if [ "$#" -lt 3 ]; then
|
||||
echo "ERROR: Illegal number of parameters"
|
||||
echo "USAGE: build_sketches <fqbn> <examples-path> [<chunk> <total-chunks>] [extra-options]"
|
||||
echo "USAGE: build_sketches <fqbn> <target-mcu <examples-path> [<chunk> <total-chunks>] [extra-options]"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$#" -lt 4 ]; then
|
||||
if [ "$#" -lt 5 ]; then
|
||||
chunk_idex="0"
|
||||
chunks_num="1"
|
||||
xtra_opts=$3
|
||||
xtra_opts=$4
|
||||
fi
|
||||
|
||||
if [ "$chunks_num" -le 0 ]; then
|
||||
echo "ERROR: Chunks count must be positive number"
|
||||
return 1
|
||||
fi
|
||||
if [ "$chunk_idex" -ge "$chunks_num" ]; then
|
||||
if [ "$chunk_idex" -ge "$chunks_num" ] && [ "$chunks_num" -ge 2 ]; then
|
||||
echo "ERROR: Chunk index must be less than chunks count"
|
||||
return 1
|
||||
fi
|
||||
|
||||
set +e
|
||||
count_sketches "$examples"
|
||||
count_sketches "$examples" "$target"
|
||||
local sketchcount=$?
|
||||
set -e
|
||||
local sketches=$(cat sketches.txt)
|
||||
@ -184,19 +186,27 @@ function build_sketches() # build_sketches <fqbn> <examples-path> <chunk> <total
|
||||
chunk_size=$(( $chunk_size + 1 ))
|
||||
fi
|
||||
|
||||
local start_index=$(( $chunk_idex * $chunk_size ))
|
||||
if [ "$sketchcount" -le "$start_index" ]; then
|
||||
echo "Skipping job"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local end_index=$(( $(( $chunk_idex + 1 )) * $chunk_size ))
|
||||
if [ "$end_index" -gt "$sketchcount" ]; then
|
||||
local start_index=0
|
||||
local end_index=0
|
||||
if [ "$chunk_idex" -ge "$chunks_num" ]; then
|
||||
start_index=$chunk_idex
|
||||
end_index=$sketchcount
|
||||
fi
|
||||
else
|
||||
start_index=$(( $chunk_idex * $chunk_size ))
|
||||
if [ "$sketchcount" -le "$start_index" ]; then
|
||||
echo "Skipping job"
|
||||
return 0
|
||||
fi
|
||||
|
||||
end_index=$(( $(( $chunk_idex + 1 )) * $chunk_size ))
|
||||
if [ "$end_index" -gt "$sketchcount" ]; then
|
||||
end_index=$sketchcount
|
||||
fi
|
||||
fi
|
||||
|
||||
local start_num=$(( $start_index + 1 ))
|
||||
echo "Found $sketchcount Sketches";
|
||||
echo "Found $sketchcount Sketches for target '$target'";
|
||||
echo "Chunk Index : $chunk_idex"
|
||||
echo "Chunk Count : $chunks_num"
|
||||
echo "Chunk Size : $chunk_size"
|
||||
echo "Start Sketch: $start_num"
|
||||
@ -208,7 +218,7 @@ function build_sketches() # build_sketches <fqbn> <examples-path> <chunk> <total
|
||||
local sketchdirname=$(basename $sketchdir)
|
||||
local sketchname=$(basename $sketch)
|
||||
if [ "${sketchdirname}.ino" != "$sketchname" ] \
|
||||
|| [ -f "$sketchdir/.test.skip" ]; then
|
||||
|| [ -f "$sketchdir/.skip.$target" ]; then
|
||||
continue
|
||||
fi
|
||||
sketchnum=$(($sketchnum + 1))
|
||||
@ -216,6 +226,8 @@ function build_sketches() # build_sketches <fqbn> <examples-path> <chunk> <total
|
||||
|| [ "$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
|
||||
|
61
.github/scripts/install-platformio-esp32.sh
vendored
@ -1,18 +1,43 @@
|
||||
#!/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/develop.zip > /dev/null 2>&1
|
||||
pip install -U https://github.com/platformio/platformio/archive/master.zip > /dev/null 2>&1
|
||||
|
||||
echo "Installing Platform ESP32 ..."
|
||||
python -m platformio platform install https://github.com/platformio/platform-espressif32.git > /dev/null 2>&1
|
||||
python -m platformio platform install $PLATFORMIO_ESP32_URL > /dev/null 2>&1
|
||||
|
||||
echo "Replacing the framework version ..."
|
||||
python -c "import json; import os; fp=open(os.path.expanduser('~/.platformio/platforms/espressif32/platform.json'), 'r+'); data=json.load(fp); data['packages']['framework-arduinoespressif32']['version'] = '*'; del data['packages']['framework-arduinoespressif32']['owner']; fp.seek(0); fp.truncate(); json.dump(data, fp); fp.close()"
|
||||
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"
|
||||
|
||||
if [ "$GITHUB_REPOSITORY" == "espressif/arduino-esp32" ]; then
|
||||
echo "Linking Core..."
|
||||
@ -25,19 +50,20 @@ fi
|
||||
echo "PlatformIO for ESP32 has been installed"
|
||||
echo ""
|
||||
|
||||
function build_pio_sketch(){ # build_pio_sketch <board> <path-to-ino>
|
||||
if [ "$#" -lt 2 ]; then
|
||||
function build_pio_sketch(){ # build_pio_sketch <board> <options> <path-to-ino>
|
||||
if [ "$#" -lt 3 ]; then
|
||||
echo "ERROR: Illegal number of parameters"
|
||||
echo "USAGE: build_pio_sketch <board> <path-to-ino>"
|
||||
echo "USAGE: build_pio_sketch <board> <options> <path-to-ino>"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local board="$1"
|
||||
local sketch="$2"
|
||||
local options="$2"
|
||||
local sketch="$3"
|
||||
local sketch_dir=$(dirname "$sketch")
|
||||
echo ""
|
||||
echo "Compiling '"$(basename "$sketch")"' ..."
|
||||
python -m platformio ci --board "$board" "$sketch_dir" --project-option="board_build.partitions = huge_app.csv"
|
||||
python -m platformio ci --board "$board" "$sketch_dir" --project-option="$options"
|
||||
}
|
||||
|
||||
function count_sketches() # count_sketches <examples-path>
|
||||
@ -66,20 +92,21 @@ function count_sketches() # count_sketches <examples-path>
|
||||
return $sketchnum
|
||||
}
|
||||
|
||||
function build_pio_sketches() # build_pio_sketches <board> <examples-path> <chunk> <total-chunks>
|
||||
function build_pio_sketches() # build_pio_sketches <board> <options> <examples-path> <chunk> <total-chunks>
|
||||
{
|
||||
if [ "$#" -lt 2 ]; then
|
||||
if [ "$#" -lt 3 ]; then
|
||||
echo "ERROR: Illegal number of parameters"
|
||||
echo "USAGE: build_pio_sketches <board> <examples-path> [<chunk> <total-chunks>]"
|
||||
echo "USAGE: build_pio_sketches <board> <options> <examples-path> [<chunk> <total-chunks>]"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local board=$1
|
||||
local examples=$2
|
||||
local chunk_idex=$3
|
||||
local chunks_num=$4
|
||||
local options="$2"
|
||||
local examples=$3
|
||||
local chunk_idex=$4
|
||||
local chunks_num=$5
|
||||
|
||||
if [ "$#" -lt 4 ]; then
|
||||
if [ "$#" -lt 5 ]; then
|
||||
chunk_idex="0"
|
||||
chunks_num="1"
|
||||
fi
|
||||
@ -138,7 +165,7 @@ function build_pio_sketches() # build_pio_sketches <board> <examples-path> <chun
|
||||
|| [ "$sketchnum" -gt "$end_index" ]; then
|
||||
continue
|
||||
fi
|
||||
build_pio_sketch "$board" "$sketch"
|
||||
build_pio_sketch "$board" "$options" "$sketch"
|
||||
local result=$?
|
||||
if [ $result -ne 0 ]; then
|
||||
return $result
|
||||
|
86
.github/scripts/on-pages.sh
vendored
@ -85,47 +85,59 @@ function git_safe_upload_to_pages(){
|
||||
return $?
|
||||
}
|
||||
|
||||
EVENT_JSON=`cat $GITHUB_EVENT_PATH`
|
||||
git_safe_upload_to_pages "index.md" "README.md"
|
||||
|
||||
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[]'`
|
||||
# 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
|
||||
|
||||
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
|
||||
# EVENT_JSON=`cat $GITHUB_EVENT_PATH`
|
||||
|
||||
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
|
||||
# echo "GITHUB_EVENT_PATH: $GITHUB_EVENT_PATH"
|
||||
# echo "EVENT_JSON: $EVENT_JSON"
|
||||
|
||||
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
|
||||
# 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
|
||||
|
||||
echo
|
||||
echo "DONE!"
|
||||
|
63
.github/scripts/on-push.sh
vendored
@ -24,48 +24,81 @@ BUILD_PIO=0
|
||||
if [ "$#" -lt 2 ] || [ "$CHUNKS_CNT" -le 0 ]; then
|
||||
CHUNK_INDEX=0
|
||||
CHUNKS_CNT=1
|
||||
elif [ "$CHUNK_INDEX" -gt "$CHUNKS_CNT" ]; then
|
||||
elif [ "$CHUNK_INDEX" -gt "$CHUNKS_CNT" ] && [ "$CHUNKS_CNT" -ge 2 ]; then
|
||||
CHUNK_INDEX=$CHUNKS_CNT
|
||||
elif [ "$CHUNK_INDEX" -eq "$CHUNKS_CNT" ]; then
|
||||
BUILD_PIO=1
|
||||
fi
|
||||
|
||||
echo "Updating submodules ..."
|
||||
git -C "$GITHUB_WORKSPACE" submodule update --init --recursive > /dev/null 2>&1
|
||||
#echo "Updating submodules ..."
|
||||
#git -C "$GITHUB_WORKSPACE" submodule update --init --recursive > /dev/null 2>&1
|
||||
|
||||
if [ "$BUILD_PIO" -eq 0 ]; then
|
||||
# ArduinoIDE Test
|
||||
# ArduinoIDE ESP32 Test
|
||||
TARGET="esp32"
|
||||
FQBN="espressif:esp32:esp32:PSRAM=enabled,PartitionScheme=huge_app"
|
||||
source ./.github/scripts/install-arduino-ide.sh
|
||||
source ./.github/scripts/install-arduino-core-esp32.sh
|
||||
if [ "$OS_IS_WINDOWS" == "1" ]; then
|
||||
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/WiFiClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino" && \
|
||||
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/BLE/examples/BLE_server/BLE_server.ino" && \
|
||||
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/AzureIoT/examples/GetStarted/GetStarted.ino" && \
|
||||
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/ESP32/examples/Camera/CameraWebServer/CameraWebServer.ino"
|
||||
elif [ "$OS_IS_MACOS" == "1" ]; then
|
||||
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/WiFi/examples/WiFiClient/WiFiClient.ino" && \
|
||||
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/WiFiClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino" && \
|
||||
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/BluetoothSerial/examples/SerialToSerialBT/SerialToSerialBT.ino" && \
|
||||
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/BLE/examples/BLE_server/BLE_server.ino" && \
|
||||
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/AzureIoT/examples/GetStarted/GetStarted.ino" && \
|
||||
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/ESP32/examples/Camera/CameraWebServer/CameraWebServer.ino"
|
||||
else
|
||||
# CMake Test
|
||||
if [ "$CHUNK_INDEX" -eq 0 ]; then
|
||||
bash "$ARDUINO_ESP32_PATH/.github/scripts/check-cmakelists.sh"
|
||||
fi
|
||||
build_sketches "$FQBN" "$ARDUINO_ESP32_PATH/libraries" "$CHUNK_INDEX" "$CHUNKS_CNT"
|
||||
build_sketches "$FQBN" "$TARGET" "$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"
|
||||
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/AzureIoT/examples/GetStarted/GetStarted.ino" && \
|
||||
build_pio_sketch "$BOARD" "$PLATFORMIO_ESP32_PATH/libraries/ESP32/examples/Camera/CameraWebServer/CameraWebServer.ino"
|
||||
#build_pio_sketches esp32dev "$PLATFORMIO_ESP32_PATH/libraries"
|
||||
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"
|
||||
fi
|
||||
|
70
.github/scripts/on-release.sh
vendored
@ -183,6 +183,7 @@ 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 ..."
|
||||
@ -194,6 +195,7 @@ 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"
|
||||
|
||||
@ -254,17 +256,30 @@ 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(.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')
|
||||
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")
|
||||
shopt -s nocasematch
|
||||
if [ "$prev_any_release" == "$RELEASE_TAG" ]; then
|
||||
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')
|
||||
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")
|
||||
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 ..."
|
||||
@ -272,17 +287,12 @@ 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"`
|
||||
@ -327,21 +337,35 @@ 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 ..."
|
||||
commitFile=$OUTPUT_DIR/commits.txt
|
||||
git -C "$GITHUB_WORKSPACE" log --oneline "$COMMITS_SINCE_RELEASE..HEAD" > "$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
|
||||
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"
|
||||
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
|
||||
|
11
.github/stale.yml
vendored
@ -12,12 +12,9 @@ onlyLabels: []
|
||||
|
||||
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
|
||||
exemptLabels:
|
||||
- pinned
|
||||
- security
|
||||
- "to be implemented"
|
||||
- "for reference"
|
||||
- "move to PR"
|
||||
- "enhancement"
|
||||
- "Type: For reference"
|
||||
- "Type: To be implemented"
|
||||
- "Type: Feature request"
|
||||
|
||||
# Set to true to ignore issues in a project (defaults to false)
|
||||
exemptProjects: false
|
||||
@ -29,7 +26,7 @@ exemptMilestones: false
|
||||
exemptAssignees: false
|
||||
|
||||
# Label to use when marking as stale
|
||||
staleLabel: stale
|
||||
staleLabel: "Status: Stale"
|
||||
|
||||
# Comment to post when marking as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
|
38
.github/workflows/docs.yml
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
name: ReadTheDocs CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- release/*
|
||||
paths:
|
||||
- 'docs/**'
|
||||
- '.github/workflows/docs.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'docs/**'
|
||||
- '.github/workflows/docs.yml'
|
||||
|
||||
jobs:
|
||||
|
||||
build-docs:
|
||||
name: Build ReadTheDocs
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Build
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install python3-pip python3-setuptools
|
||||
# GitHub CI installs pip3 and setuptools outside the path.
|
||||
# Update the path to include them and run.
|
||||
PATH=/home/runner/.local/bin:$PATH pip3 install --user -r ./docs/requirements.txt
|
||||
cd ./docs && PATH=/home/runner/.local/bin:$PATH SPHINXOPTS="-W" make html
|
4
.github/workflows/gh-pages.yml
vendored
@ -4,9 +4,11 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- pages
|
||||
paths:
|
||||
- 'README.md'
|
||||
- 'docs/**'
|
||||
- '.github/scripts/on-pages.sh'
|
||||
- '.github/workflows/gh-pages.yml'
|
||||
|
||||
jobs:
|
||||
|
||||
|
2
.github/workflows/release.yml
vendored
@ -11,6 +11,8 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
27
.github/workflows/test_selfhosted_runner.yml
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
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
|
7
.gitignore
vendored
@ -1,10 +1,12 @@
|
||||
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
|
||||
.DS_Store
|
||||
|
||||
#Ignore files built by Visual Studio/Visual Micro
|
||||
@ -14,3 +16,8 @@ tools/mklittlefs
|
||||
__vm/
|
||||
*.vcxproj*
|
||||
.vscode/
|
||||
platform.sloeber.txt
|
||||
boards.sloeber.txt
|
||||
|
||||
# Ignore docs build (Sphinx)
|
||||
docs/build
|
||||
|
3
.gitmodules
vendored
@ -1,3 +0,0 @@
|
||||
[submodule "libraries/AzureIoT"]
|
||||
path = libraries/AzureIoT
|
||||
url = https://github.com/VSChina/ESP32_AzureIoT_Arduino
|
||||
|
149
CMakeLists.txt
@ -7,6 +7,7 @@ set(CORE_SRCS
|
||||
cores/esp32/esp32-hal-dac.c
|
||||
cores/esp32/esp32-hal-gpio.c
|
||||
cores/esp32/esp32-hal-i2c.c
|
||||
cores/esp32/esp32-hal-i2c-slave.c
|
||||
cores/esp32/esp32-hal-ledc.c
|
||||
cores/esp32/esp32-hal-matrix.c
|
||||
cores/esp32/esp32-hal-misc.c
|
||||
@ -15,6 +16,7 @@ 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
|
||||
@ -31,6 +33,12 @@ set(CORE_SRCS
|
||||
cores/esp32/stdlib_noniso.c
|
||||
cores/esp32/Stream.cpp
|
||||
cores/esp32/StreamString.cpp
|
||||
cores/esp32/HWCDC.cpp
|
||||
cores/esp32/USB.cpp
|
||||
cores/esp32/USBCDC.cpp
|
||||
cores/esp32/USBMSC.cpp
|
||||
cores/esp32/FirmwareMSC.cpp
|
||||
cores/esp32/firmware_msc_fat.c
|
||||
cores/esp32/wiring_pulse.c
|
||||
cores/esp32/wiring_shift.c
|
||||
cores/esp32/WMath.cpp
|
||||
@ -41,6 +49,9 @@ 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
|
||||
@ -49,8 +60,14 @@ set(LIBRARY_SRCS
|
||||
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
|
||||
@ -61,6 +78,14 @@ set(LIBRARY_SRCS
|
||||
libraries/Ticker/src/Ticker.cpp
|
||||
libraries/Update/src/Updater.cpp
|
||||
libraries/Update/src/HttpsOTAUpdate.cpp
|
||||
libraries/USB/src/USBHID.cpp
|
||||
libraries/USB/src/USBHIDMouse.cpp
|
||||
libraries/USB/src/USBHIDKeyboard.cpp
|
||||
libraries/USB/src/USBHIDGamepad.cpp
|
||||
libraries/USB/src/USBHIDConsumerControl.cpp
|
||||
libraries/USB/src/USBHIDSystemControl.cpp
|
||||
libraries/USB/src/USBHIDVendor.cpp
|
||||
libraries/USB/src/USBVendor.cpp
|
||||
libraries/WebServer/src/WebServer.cpp
|
||||
libraries/WebServer/src/Parsing.cpp
|
||||
libraries/WebServer/src/detail/mimetable.cpp
|
||||
@ -80,66 +105,6 @@ set(LIBRARY_SRCS
|
||||
libraries/Wire/src/Wire.cpp
|
||||
)
|
||||
|
||||
set(AZURE_SRCS
|
||||
libraries/AzureIoT/src/az_iot/azureiotcerts.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/pal/agenttime.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/pal/dns_async.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/pal/freertos/lock.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/pal/freertos/threadapi.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/pal/freertos/tickcounter.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/pal/lwip/sntp_lwip.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/pal/socket_async.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/pal/src/platform_openssl_compact.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/pal/src/tlsio_openssl_compact.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/pal/tlsio_options.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/base64.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/buffer.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/connection_string_parser.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/consolelogger.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/constbuffer.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/constmap.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/crt_abstractions.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/doublylinkedlist.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/gballoc.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/gb_stdio.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/gb_time.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/hmac.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/hmacsha256.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/httpapiex.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/httpapiexsas.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/httpheaders.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/http_proxy_io.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/map.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/optionhandler.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/sastoken.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/sha1.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/sha224.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/sha384-512.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/singlylinkedlist.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/strings.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/string_tokenizer.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/urlencode.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/usha.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/vector.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/xio.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/xlogging.c
|
||||
libraries/AzureIoT/src/az_iot/iothub_client/src/blob.c
|
||||
libraries/AzureIoT/src/az_iot/iothub_client/src/iothub_client_authorization.c
|
||||
libraries/AzureIoT/src/az_iot/iothub_client/src/iothub_client.c
|
||||
libraries/AzureIoT/src/az_iot/iothub_client/src/iothub_client_ll.c
|
||||
libraries/AzureIoT/src/az_iot/iothub_client/src/iothub_client_retry_control.c
|
||||
libraries/AzureIoT/src/az_iot/iothub_client/src/iothub_message.c
|
||||
libraries/AzureIoT/src/az_iot/iothub_client/src/iothubtransport.c
|
||||
libraries/AzureIoT/src/az_iot/iothub_client/src/iothubtransportmqtt.c
|
||||
libraries/AzureIoT/src/az_iot/iothub_client/src/iothubtransport_mqtt_common.c
|
||||
libraries/AzureIoT/src/az_iot/iothub_client/src/version.c
|
||||
libraries/AzureIoT/src/az_iot/umqtt/src/mqtt_client.c
|
||||
libraries/AzureIoT/src/az_iot/umqtt/src/mqtt_codec.c
|
||||
libraries/AzureIoT/src/az_iot/umqtt/src/mqtt_message.c
|
||||
libraries/AzureIoT/src/AzureIotHub.cpp
|
||||
libraries/AzureIoT/src/Esp32MQTTClient.cpp
|
||||
)
|
||||
|
||||
set(BLE_SRCS
|
||||
libraries/BLE/src/BLE2902.cpp
|
||||
libraries/BLE/src/BLE2904.cpp
|
||||
@ -172,14 +137,12 @@ set(BLE_SRCS
|
||||
libraries/BLE/src/GeneralUtils.cpp
|
||||
)
|
||||
|
||||
set(COMPONENT_SRCS ${CORE_SRCS} ${LIBRARY_SRCS} ${AZURE_SRCS} ${BLE_SRCS})
|
||||
|
||||
set(COMPONENT_ADD_INCLUDEDIRS
|
||||
variants/esp32/
|
||||
set(includedirs
|
||||
variants/${IDF_TARGET}/
|
||||
cores/esp32/
|
||||
libraries/ArduinoOTA/src
|
||||
libraries/AsyncUDP/src
|
||||
libraries/AzureIoT/src
|
||||
libraries/BLE/src
|
||||
libraries/BluetoothSerial/src
|
||||
libraries/DNSServer/src
|
||||
@ -190,8 +153,10 @@ set(COMPONENT_ADD_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
|
||||
@ -199,6 +164,7 @@ set(COMPONENT_ADD_INCLUDEDIRS
|
||||
libraries/SPI/src
|
||||
libraries/Ticker/src
|
||||
libraries/Update/src
|
||||
libraries/USB/src
|
||||
libraries/WebServer/src
|
||||
libraries/WiFiClientSecure/src
|
||||
libraries/WiFi/src
|
||||
@ -206,14 +172,53 @@ set(COMPONENT_ADD_INCLUDEDIRS
|
||||
libraries/Wire/src
|
||||
)
|
||||
|
||||
set(COMPONENT_PRIV_INCLUDEDIRS cores/esp32/libb64)
|
||||
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_REQUIRES spi_flash mbedtls mdns ethernet esp_adc_cal wifi_provisioning)
|
||||
set(COMPONENT_PRIV_REQUIRES fatfs nvs_flash app_update spiffs bootloader_support openssl bt esp_http_client esp_https_ota)
|
||||
idf_component_register(INCLUDE_DIRS ${includedirs} PRIV_INCLUDE_DIRS ${priv_includes} SRCS ${srcs} REQUIRES ${requires} PRIV_REQUIRES ${priv_requires})
|
||||
|
||||
register_component()
|
||||
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)
|
||||
|
||||
set_source_files_properties(libraries/AzureIoT/src/az_iot/iothub_client/src/iothubtransport_mqtt_common.c
|
||||
PROPERTIES COMPILE_FLAGS
|
||||
-Wno-maybe-uninitialized
|
||||
)
|
||||
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()
|
||||
|
50
CONTRIBUTING.rst
Normal file
@ -0,0 +1,50 @@
|
||||
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
|
@ -5,7 +5,7 @@ config ENABLE_ARDUINO_DEPENDS
|
||||
select LWIP_SO_RCVBUF
|
||||
select ETHERNET
|
||||
select WIFI_ENABLED
|
||||
select ESP32_PHY_CALIBRATION_AND_DATA_STORAGE
|
||||
select ESP32_PHY_CALIBRATION_AND_DATA_STORAGE if IDF_TARGET_ESP32
|
||||
select MEMMAP_SMP
|
||||
default "y"
|
||||
|
||||
@ -94,6 +94,16 @@ config ARDUINO_UDP_RUNNING_CORE
|
||||
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"
|
||||
default "n"
|
||||
@ -261,6 +271,12 @@ 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
|
||||
@ -327,6 +343,12 @@ 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
|
||||
|
53
README.md
@ -1,49 +1,54 @@
|
||||
# Arduino core for the ESP32
|
||||
[](https://travis-ci.org/espressif/arduino-esp32) 
|
||||
|
||||
[](https://travis-ci.org/espressif/arduino-esp32)  [](https://docs.espressif.com/projects/arduino-esp32/en/latest/?badge=latest)
|
||||
|
||||
### Need help or have a question? Join the chat at [](https://gitter.im/espressif/arduino-esp32?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
## Contents
|
||||
|
||||
- [ESP32-S2 and ESP32-C3 Support](#esp32-s2-and-esp32-c3-support)
|
||||
- [Development Status](#development-status)
|
||||
- [Installation Instructions](#installation-instructions)
|
||||
- [Decoding Exceptions](#decoding-exceptions)
|
||||
- [Issue/Bug report template](#issuebug-report-template)
|
||||
- [ESP32Dev Board PINMAP](#esp32dev-board-pinmap)
|
||||
|
||||
### ESP32-S2 and ESP32-C3 Support
|
||||
|
||||
If you want to test ESP32-S2 and/or ESP32-C3 through the board manager, please use the development release link:
|
||||
|
||||
```
|
||||
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json
|
||||
```
|
||||
|
||||
Now you can install the latest 2.0.0 version from the boards manager.
|
||||
|
||||
### Development Status
|
||||
|
||||
Latest Stable Release [](https://github.com/espressif/arduino-esp32/releases/latest/) [](https://github.com/espressif/arduino-esp32/releases/latest/) [](https://github.com/espressif/arduino-esp32/releases/latest/)
|
||||
|
||||
Latest Development Release [](https://github.com/espressif/arduino-esp32/releases/latest/) [](https://github.com/espressif/arduino-esp32/releases/latest/) [](https://github.com/espressif/arduino-esp32/releases/latest/)
|
||||
Latest Development Release [](https://github.com/espressif/arduino-esp32/releases/) [](https://github.com/espressif/arduino-esp32/releases/) [](https://github.com/espressif/arduino-esp32/releases/)
|
||||
|
||||
### Documentation
|
||||
|
||||
### 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)
|
||||
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)
|
||||
|
||||
### Decoding exceptions
|
||||
|
||||
You can use [EspExceptionDecoder](https://github.com/me-no-dev/EspExceptionDecoder) to get meaningful call trace.
|
||||
|
||||
### Issue/Bug report template
|
||||
Before reporting an issue, make sure you've searched for similar one that was already created. Also make sure to go through all the issues labelled as [for reference](https://github.com/espressif/arduino-esp32/issues?utf8=%E2%9C%93&q=is%3Aissue%20label%3A%22for%20reference%22%20).
|
||||
Before reporting an issue, make sure you've searched for similar one that was already created. Also make sure to go through all the issues labelled as [Type: For reference](https://github.com/espressif/arduino-esp32/issues?q=is%3Aissue+label%3A%22Type%3A+For+reference%22+).
|
||||
|
||||
Finally, if you are sure no one else had the issue, follow the [ISSUE_TEMPLATE](docs/ISSUE_TEMPLATE.md) while reporting any issue.
|
||||
Finally, if you are sure no one else had the issue, follow the [issue template](docs/ISSUE_TEMPLATE.md) while reporting any issue.
|
||||
|
||||
### ESP32Dev Board PINMAP
|
||||
### Contributing
|
||||
|
||||

|
||||
We welcome contributions to the Arduino ESP32 project!
|
||||
|
||||
### Tip
|
||||
|
||||
Sometimes to program ESP32 via serial you must keep GPIO0 LOW during the programming process
|
||||
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.
|
||||
|
4501
boards.txt
@ -29,6 +29,7 @@
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "esp_arduino_version.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
@ -98,13 +99,23 @@
|
||||
#define bit(b) (1UL << (b))
|
||||
#define _BV(b) (1UL << (b))
|
||||
|
||||
#define digitalPinToPort(pin) (((pin)>31)?1:0)
|
||||
#define digitalPinToBitMask(pin) (1UL << (((pin)>31)?((pin)-32):(pin)))
|
||||
#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 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
|
||||
@ -115,10 +126,12 @@ typedef bool boolean;
|
||||
typedef uint8_t byte;
|
||||
typedef unsigned int word;
|
||||
|
||||
#ifdef __cplusplus
|
||||
void setup(void);
|
||||
void loop(void);
|
||||
|
||||
long random(long, long);
|
||||
#endif
|
||||
void randomSeed(unsigned long);
|
||||
long map(long, long, long, long, long);
|
||||
|
||||
@ -162,7 +175,7 @@ using std::min;
|
||||
using ::round;
|
||||
|
||||
uint16_t makeWord(uint16_t w);
|
||||
uint16_t makeWord(byte h, byte l);
|
||||
uint16_t makeWord(uint8_t h, uint8_t l);
|
||||
|
||||
#define word(...) makeWord(__VA_ARGS__)
|
||||
|
||||
|
@ -19,12 +19,10 @@
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "Esp.h"
|
||||
#include "rom/spi_flash.h"
|
||||
#include "esp_sleep.h"
|
||||
#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"
|
||||
@ -32,6 +30,27 @@ extern "C" {
|
||||
}
|
||||
#include <MD5Builder.h>
|
||||
|
||||
#include "esp_system.h"
|
||||
#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
|
||||
|
||||
/**
|
||||
* User-defined Literals
|
||||
* usage:
|
||||
@ -121,24 +140,36 @@ uint32_t EspClass::getMaxAllocHeap(void)
|
||||
|
||||
uint32_t EspClass::getPsramSize(void)
|
||||
{
|
||||
multi_heap_info_t info;
|
||||
heap_caps_get_info(&info, MALLOC_CAP_SPIRAM);
|
||||
return info.total_free_bytes + info.total_allocated_bytes;
|
||||
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;
|
||||
}
|
||||
|
||||
uint32_t EspClass::getFreePsram(void)
|
||||
{
|
||||
return heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
|
||||
if(psramFound()){
|
||||
return heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t EspClass::getMinFreePsram(void)
|
||||
{
|
||||
return heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM);
|
||||
if(psramFound()){
|
||||
return heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t EspClass::getMaxAllocPsram(void)
|
||||
{
|
||||
return heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM);
|
||||
if(psramFound()){
|
||||
return heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t sketchSize(sketchSize_t response) {
|
||||
@ -220,6 +251,7 @@ uint8_t EspClass::getChipRevision(void)
|
||||
|
||||
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) {
|
||||
@ -233,9 +265,28 @@ const char * EspClass::getChipModel(void)
|
||||
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)
|
||||
@ -253,7 +304,7 @@ const char * EspClass::getSdkVersion(void)
|
||||
uint32_t EspClass::getFlashChipSize(void)
|
||||
{
|
||||
esp_image_header_t fhdr;
|
||||
if(flashRead(0x1000, (uint32_t*)&fhdr, sizeof(esp_image_header_t)) && fhdr.magic != ESP_IMAGE_HEADER_MAGIC) {
|
||||
if(flashRead(ESP_FLASH_IMAGE_BASE, (uint32_t*)&fhdr, sizeof(esp_image_header_t)) && fhdr.magic != ESP_IMAGE_HEADER_MAGIC) {
|
||||
return 0;
|
||||
}
|
||||
return magicFlashChipSize(fhdr.spi_size);
|
||||
@ -262,7 +313,7 @@ uint32_t EspClass::getFlashChipSize(void)
|
||||
uint32_t EspClass::getFlashChipSpeed(void)
|
||||
{
|
||||
esp_image_header_t fhdr;
|
||||
if(flashRead(0x1000, (uint32_t*)&fhdr, sizeof(esp_image_header_t)) && fhdr.magic != ESP_IMAGE_HEADER_MAGIC) {
|
||||
if(flashRead(ESP_FLASH_IMAGE_BASE, (uint32_t*)&fhdr, sizeof(esp_image_header_t)) && fhdr.magic != ESP_IMAGE_HEADER_MAGIC) {
|
||||
return 0;
|
||||
}
|
||||
return magicFlashChipSpeed(fhdr.spi_speed);
|
||||
@ -271,7 +322,7 @@ uint32_t EspClass::getFlashChipSpeed(void)
|
||||
FlashMode_t EspClass::getFlashChipMode(void)
|
||||
{
|
||||
esp_image_header_t fhdr;
|
||||
if(flashRead(0x1000, (uint32_t*)&fhdr, sizeof(esp_image_header_t)) && fhdr.magic != ESP_IMAGE_HEADER_MAGIC) {
|
||||
if(flashRead(ESP_FLASH_IMAGE_BASE, (uint32_t*)&fhdr, sizeof(esp_image_header_t)) && fhdr.magic != ESP_IMAGE_HEADER_MAGIC) {
|
||||
return FM_UNKNOWN;
|
||||
}
|
||||
return magicFlashChipMode(fhdr.spi_mode);
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <esp_partition.h>
|
||||
#include <hal/cpu_hal.h>
|
||||
|
||||
/**
|
||||
* AVR macros for WDT managment
|
||||
@ -108,11 +109,9 @@ public:
|
||||
|
||||
};
|
||||
|
||||
uint32_t IRAM_ATTR EspClass::getCycleCount()
|
||||
uint32_t ARDUINO_ISR_ATTR EspClass::getCycleCount()
|
||||
{
|
||||
uint32_t ccount;
|
||||
__asm__ __volatile__("esync; rsr %0,ccount":"=a" (ccount));
|
||||
return ccount;
|
||||
return cpu_hal_get_cycle_count();
|
||||
}
|
||||
|
||||
extern EspClass ESP;
|
||||
|
424
cores/esp32/FirmwareMSC.cpp
Normal file
@ -0,0 +1,424 @@
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "FirmwareMSC.h"
|
||||
|
||||
#if CONFIG_TINYUSB_MSC_ENABLED
|
||||
|
||||
#include <cstring>
|
||||
#include "esp_partition.h"
|
||||
#include "esp_ota_ops.h"
|
||||
#include "esp32-hal.h"
|
||||
#include "pins_arduino.h"
|
||||
#include "firmware_msc_fat.h"
|
||||
|
||||
#ifndef USB_FW_MSC_VENDOR_ID
|
||||
#define USB_FW_MSC_VENDOR_ID "ESP32" //max 8 chars
|
||||
#endif
|
||||
#ifndef USB_FW_MSC_PRODUCT_ID
|
||||
#define USB_FW_MSC_PRODUCT_ID "Firmware MSC"//max 16 chars
|
||||
#endif
|
||||
#ifndef USB_FW_MSC_PRODUCT_REVISION
|
||||
#define USB_FW_MSC_PRODUCT_REVISION "1.0" //max 4 chars
|
||||
#endif
|
||||
#ifndef USB_FW_MSC_VOLUME_NAME
|
||||
#define USB_FW_MSC_VOLUME_NAME "ESP32-FWMSC" //max 11 chars
|
||||
#endif
|
||||
#ifndef USB_FW_MSC_SERIAL_NUMBER
|
||||
#define USB_FW_MSC_SERIAL_NUMBER 0x00000000
|
||||
#endif
|
||||
|
||||
ESP_EVENT_DEFINE_BASE(ARDUINO_FIRMWARE_MSC_EVENTS);
|
||||
esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait);
|
||||
esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg);
|
||||
|
||||
//General Variables
|
||||
static uint8_t * msc_ram_disk = NULL;
|
||||
static fat_boot_sector_t * msc_boot = NULL;
|
||||
static uint8_t * msc_table = NULL;
|
||||
static uint16_t msc_table_sectors = 0;
|
||||
static uint16_t msc_total_sectors = 0;
|
||||
static bool mcs_is_fat16 = false;
|
||||
|
||||
//Firmware Read
|
||||
static const esp_partition_t* msc_run_partition = NULL;
|
||||
static uint16_t fw_start_sector = 0;
|
||||
static uint16_t fw_end_sector = 0;
|
||||
static size_t fw_size = 0;
|
||||
static fat_dir_entry_t * fw_entry = NULL;
|
||||
|
||||
//Firmware Write
|
||||
typedef enum {
|
||||
MSC_UPDATE_IDLE,
|
||||
MSC_UPDATE_STARTING,
|
||||
MSC_UPDATE_RUNNING,
|
||||
MSC_UPDATE_END
|
||||
} msc_update_state_t;
|
||||
|
||||
static const esp_partition_t* msc_ota_partition = NULL;
|
||||
static msc_update_state_t msc_update_state = MSC_UPDATE_IDLE;
|
||||
static uint16_t msc_update_start_sector = 0;
|
||||
static uint32_t msc_update_bytes_written = 0;
|
||||
static fat_dir_entry_t * msc_update_entry = NULL;
|
||||
|
||||
static uint32_t get_firmware_size(const esp_partition_t* partition){
|
||||
esp_image_metadata_t data;
|
||||
const esp_partition_pos_t running_pos = {
|
||||
.offset = partition->address,
|
||||
.size = partition->size,
|
||||
};
|
||||
data.start_addr = running_pos.offset;
|
||||
esp_image_verify(ESP_IMAGE_VERIFY, &running_pos, &data);
|
||||
return data.image_len;
|
||||
}
|
||||
|
||||
//Get number of sectors required based on the size of the firmware and OTA partition
|
||||
static size_t msc_update_get_required_disk_sectors(){
|
||||
size_t data_sectors = 16;
|
||||
size_t total_sectors = 0;
|
||||
msc_run_partition = esp_ota_get_running_partition();
|
||||
msc_ota_partition = esp_ota_get_next_update_partition(NULL);
|
||||
if(msc_run_partition){
|
||||
fw_size = get_firmware_size(msc_run_partition);
|
||||
data_sectors += FAT_SIZE_TO_SECTORS(fw_size);
|
||||
log_d("APP size: %u (%u sectors)", fw_size, FAT_SIZE_TO_SECTORS(fw_size));
|
||||
} else {
|
||||
log_w("APP partition not found. Reading disabled");
|
||||
}
|
||||
if(msc_ota_partition){
|
||||
data_sectors += FAT_SIZE_TO_SECTORS(msc_ota_partition->size);
|
||||
log_d("OTA size: %u (%u sectors)", msc_ota_partition->size, FAT_SIZE_TO_SECTORS(msc_ota_partition->size));
|
||||
} else {
|
||||
log_w("OTA partition not found. Writing disabled");
|
||||
}
|
||||
msc_table_sectors = fat_sectors_per_alloc_table(data_sectors, false);
|
||||
total_sectors = data_sectors + msc_table_sectors + 2;
|
||||
if(total_sectors > 0xFF4){
|
||||
log_d("USING FAT16");
|
||||
mcs_is_fat16 = true;
|
||||
total_sectors -= msc_table_sectors;
|
||||
msc_table_sectors = fat_sectors_per_alloc_table(data_sectors, true);
|
||||
total_sectors += msc_table_sectors;
|
||||
} else {
|
||||
log_d("USING FAT12");
|
||||
mcs_is_fat16 = false;
|
||||
}
|
||||
log_d("FAT sector size: %u", DISK_SECTOR_SIZE);
|
||||
log_d("FAT data sectors: %u", data_sectors);
|
||||
log_d("FAT table sectors: %u", msc_table_sectors);
|
||||
log_d("FAT total sectors: %u (%uKB)", total_sectors, (total_sectors * DISK_SECTOR_SIZE) / 1024);
|
||||
return total_sectors;
|
||||
}
|
||||
|
||||
//setup the ramdisk and add the firmware download file
|
||||
static bool msc_update_setup_disk(const char * volume_label, uint32_t serial_number){
|
||||
msc_total_sectors = msc_update_get_required_disk_sectors();
|
||||
uint8_t ram_sectors = msc_table_sectors + 2;
|
||||
msc_ram_disk = (uint8_t*)calloc(ram_sectors, DISK_SECTOR_SIZE);
|
||||
if(!msc_ram_disk){
|
||||
log_e("Failed to allocate RAM Disk: %u bytes", ram_sectors * DISK_SECTOR_SIZE);
|
||||
return false;
|
||||
}
|
||||
fw_start_sector = ram_sectors;
|
||||
fw_end_sector = fw_start_sector;
|
||||
msc_boot = fat_add_boot_sector(msc_ram_disk, msc_total_sectors, msc_table_sectors, fat_file_system_type(mcs_is_fat16), volume_label, serial_number);
|
||||
msc_table = fat_add_table(msc_ram_disk, msc_boot, mcs_is_fat16);
|
||||
//fat_dir_entry_t * label = fat_add_label(msc_ram_disk, volume_label);
|
||||
if(msc_run_partition){
|
||||
fw_entry = fat_add_root_file(msc_ram_disk, 0, "FIRMWARE", "BIN", fw_size, 2, mcs_is_fat16);
|
||||
fw_end_sector = FAT_SIZE_TO_SECTORS(fw_size) + fw_start_sector;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void msc_update_delete_disk(){
|
||||
fw_entry = NULL;
|
||||
fw_size = 0;
|
||||
fw_end_sector = 0;
|
||||
fw_start_sector = 0;
|
||||
msc_table = NULL;
|
||||
msc_boot = NULL;
|
||||
msc_table_sectors = 0;
|
||||
msc_total_sectors = 0;
|
||||
msc_run_partition = NULL;
|
||||
msc_ota_partition = NULL;
|
||||
msc_update_state = MSC_UPDATE_IDLE;
|
||||
msc_update_start_sector = 0;
|
||||
msc_update_bytes_written = 0;
|
||||
msc_update_entry = NULL;
|
||||
free(msc_ram_disk);
|
||||
msc_ram_disk = NULL;
|
||||
}
|
||||
|
||||
//filter out entries to only include BINs in the root folder
|
||||
static fat_dir_entry_t * msc_update_get_root_bin_entry(uint8_t index){
|
||||
fat_dir_entry_t * entry = (fat_dir_entry_t *)(msc_ram_disk + ((msc_boot->sectors_per_alloc_table+1) * DISK_SECTOR_SIZE) + (index * sizeof(fat_dir_entry_t)));
|
||||
fat_lfn_entry_t * lfn = (fat_lfn_entry_t*)entry;
|
||||
|
||||
//empty entry
|
||||
if(entry->file_magic == 0){
|
||||
return NULL;
|
||||
}
|
||||
//long file name
|
||||
if(lfn->attr == 0x0F && lfn->type == 0x00 && lfn->first_cluster == 0x0000){
|
||||
return NULL;
|
||||
}
|
||||
//only files marked as archives
|
||||
if(entry->file_attr != FAT_FILE_ATTR_ARCHIVE){
|
||||
return NULL;
|
||||
}
|
||||
//deleted
|
||||
if(entry->file_magic == 0xE5 || entry->file_magic == 0x05){
|
||||
return NULL;
|
||||
}
|
||||
//not bins
|
||||
if(memcmp("BIN", entry->file_extension, 3)){
|
||||
return NULL;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
//get an empty bin (the host will add an entry for file about to be written with size of zero)
|
||||
static fat_dir_entry_t * msc_update_find_new_bin(){
|
||||
for(uint8_t i=16; i;){
|
||||
i--;
|
||||
fat_dir_entry_t * entry = msc_update_get_root_bin_entry(i);
|
||||
if(entry && entry->file_size == 0){
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//get a bin starting from particular sector
|
||||
static fat_dir_entry_t * msc_update_find_bin(uint16_t sector){
|
||||
for(uint8_t i=16; i; ){
|
||||
i--;
|
||||
fat_dir_entry_t * entry = msc_update_get_root_bin_entry(i);
|
||||
if(entry && entry->data_start_sector == (sector - msc_boot->sectors_per_alloc_table)){
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//write the new data and erase the flash blocks when necessary
|
||||
static esp_err_t msc_update_write(const esp_partition_t *partition, uint32_t offset, void *data, size_t size){
|
||||
esp_err_t err = ESP_OK;
|
||||
if((offset & (SPI_FLASH_SEC_SIZE-1)) == 0){
|
||||
err = esp_partition_erase_range(partition, offset, SPI_FLASH_SEC_SIZE);
|
||||
log_v("ERASE[0x%08X]: %s", offset, (err != ESP_OK)?"FAIL":"OK");
|
||||
if(err != ESP_OK){
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return esp_partition_write(partition, offset, data, size);
|
||||
}
|
||||
|
||||
//called when error was encountered while updating
|
||||
static void msc_update_error(){
|
||||
log_e("UPDATE_ERROR: %u", msc_update_bytes_written);
|
||||
arduino_firmware_msc_event_data_t p;
|
||||
p.error.size = msc_update_bytes_written;
|
||||
arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_ERROR_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY);
|
||||
msc_update_state = MSC_UPDATE_IDLE;
|
||||
msc_update_entry = NULL;
|
||||
msc_update_bytes_written = 0;
|
||||
msc_update_start_sector = 0;
|
||||
}
|
||||
|
||||
//called when all firmware bytes have been received
|
||||
static void msc_update_end(){
|
||||
log_d("UPDATE_END: %u", msc_update_entry->file_size);
|
||||
msc_update_state = MSC_UPDATE_END;
|
||||
size_t ota_size = get_firmware_size(msc_ota_partition);
|
||||
if(ota_size != msc_update_entry->file_size){
|
||||
log_e("OTA SIZE MISMATCH %u != %u", ota_size, msc_update_entry->file_size);
|
||||
msc_update_error();
|
||||
return;
|
||||
}
|
||||
if(!ota_size || esp_ota_set_boot_partition(msc_ota_partition) != ESP_OK){
|
||||
log_e("ENABLING OTA PARTITION FAILED");
|
||||
msc_update_error();
|
||||
return;
|
||||
}
|
||||
arduino_firmware_msc_event_data_t p;
|
||||
p.end.size = msc_update_entry->file_size;
|
||||
arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_END_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
|
||||
static int32_t msc_write(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize){
|
||||
//log_d("lba: %u, offset: %u, bufsize: %u", lba, offset, bufsize);
|
||||
if(lba < fw_start_sector){
|
||||
//write to sectors that are in RAM
|
||||
memcpy(msc_ram_disk + (lba * DISK_SECTOR_SIZE) + offset, buffer, bufsize);
|
||||
if(msc_ota_partition && lba == (fw_start_sector - 1)){
|
||||
//monitor the root folder table
|
||||
if(msc_update_state <= MSC_UPDATE_RUNNING){
|
||||
fat_dir_entry_t * update_entry = msc_update_find_new_bin();
|
||||
if(update_entry) {
|
||||
if(msc_update_entry) {
|
||||
log_v("REPLACING ENTRY");
|
||||
} else {
|
||||
log_v("ASSIGNING ENTRY");
|
||||
}
|
||||
if(msc_update_state <= MSC_UPDATE_STARTING){
|
||||
msc_update_state = MSC_UPDATE_STARTING;
|
||||
msc_update_bytes_written = 0;
|
||||
msc_update_start_sector = 0;
|
||||
}
|
||||
msc_update_entry = update_entry;
|
||||
} else if(msc_update_state == MSC_UPDATE_RUNNING){
|
||||
if(!msc_update_entry && msc_update_start_sector){
|
||||
msc_update_entry = msc_update_find_bin(msc_update_start_sector);
|
||||
}
|
||||
if(msc_update_entry && msc_update_bytes_written >= msc_update_entry->file_size){
|
||||
msc_update_end();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(msc_ota_partition && lba >= msc_update_start_sector){
|
||||
//handle writes to the region where the new firmware will be uploaded
|
||||
arduino_firmware_msc_event_data_t p;
|
||||
if(msc_update_state <= MSC_UPDATE_STARTING && buffer[0] == 0xE9){
|
||||
msc_update_state = MSC_UPDATE_RUNNING;
|
||||
msc_update_start_sector = lba;
|
||||
msc_update_bytes_written = 0;
|
||||
log_d("UPDATE_START: %u (0x%02X)", lba, lba - msc_boot->sectors_per_alloc_table);
|
||||
arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_START_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY);
|
||||
if(msc_update_write(msc_ota_partition, ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset, buffer, bufsize) == ESP_OK){
|
||||
log_v("UPDATE_WRITE: %u %u", ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset, bufsize);
|
||||
msc_update_bytes_written = ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset + bufsize;
|
||||
p.write.offset = ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset;
|
||||
p.write.size = bufsize;
|
||||
arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_WRITE_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY);
|
||||
} else {
|
||||
msc_update_error();
|
||||
return 0;
|
||||
}
|
||||
} else if(msc_update_state == MSC_UPDATE_RUNNING){
|
||||
if(msc_update_entry && msc_update_entry->file_size && msc_update_bytes_written < msc_update_entry->file_size && (msc_update_bytes_written + bufsize) >= msc_update_entry->file_size){
|
||||
bufsize = msc_update_entry->file_size - msc_update_bytes_written;
|
||||
}
|
||||
if(msc_update_write(msc_ota_partition, ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset, buffer, bufsize) == ESP_OK){
|
||||
log_v("UPDATE_WRITE: %u %u", ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset, bufsize);
|
||||
msc_update_bytes_written = ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset + bufsize;
|
||||
p.write.offset = ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset;
|
||||
p.write.size = bufsize;
|
||||
arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_WRITE_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY);
|
||||
if(msc_update_entry && msc_update_entry->file_size && msc_update_bytes_written >= msc_update_entry->file_size){
|
||||
msc_update_end();
|
||||
}
|
||||
} else {
|
||||
msc_update_error();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return bufsize;
|
||||
}
|
||||
|
||||
static int32_t msc_read(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize){
|
||||
//log_d("lba: %u, offset: %u, bufsize: %u", lba, offset, bufsize);
|
||||
if(lba < fw_start_sector){
|
||||
memcpy(buffer, msc_ram_disk + (lba * DISK_SECTOR_SIZE) + offset, bufsize);
|
||||
} else if(msc_run_partition && lba < fw_end_sector){
|
||||
//read the currently running firmware
|
||||
if(esp_partition_read(msc_run_partition, ((lba - fw_start_sector) * DISK_SECTOR_SIZE) + offset, buffer, bufsize) != ESP_OK){
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
memset(buffer, 0, bufsize);
|
||||
}
|
||||
return bufsize;
|
||||
}
|
||||
|
||||
static bool msc_start_stop(uint8_t power_condition, bool start, bool load_eject){
|
||||
//log_d("power: %u, start: %u, eject: %u", power_condition, start, load_eject);
|
||||
arduino_firmware_msc_event_data_t p;
|
||||
p.power.power_condition = power_condition;
|
||||
p.power.start = start;
|
||||
p.power.load_eject = load_eject;
|
||||
arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_POWER_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY);
|
||||
return true;
|
||||
}
|
||||
|
||||
static volatile TaskHandle_t msc_task_handle = NULL;
|
||||
static void msc_task(void *pvParameters){
|
||||
for (;;) {
|
||||
if(msc_update_state == MSC_UPDATE_END){
|
||||
delay(100);
|
||||
esp_restart();
|
||||
}
|
||||
delay(100);
|
||||
}
|
||||
msc_task_handle = NULL;
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
FirmwareMSC::FirmwareMSC():msc(){}
|
||||
|
||||
FirmwareMSC::~FirmwareMSC(){
|
||||
end();
|
||||
}
|
||||
|
||||
bool FirmwareMSC::begin(){
|
||||
if(msc_ram_disk){
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!msc_update_setup_disk(USB_FW_MSC_VOLUME_NAME, USB_FW_MSC_SERIAL_NUMBER)){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!msc_task_handle){
|
||||
xTaskCreateUniversal(msc_task, "msc_disk", 1024, NULL, 2, (TaskHandle_t*)&msc_task_handle, 0);
|
||||
if(!msc_task_handle){
|
||||
msc_update_delete_disk();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
msc.vendorID(USB_FW_MSC_VENDOR_ID);
|
||||
msc.productID(USB_FW_MSC_PRODUCT_ID);
|
||||
msc.productRevision(USB_FW_MSC_PRODUCT_REVISION);
|
||||
msc.onStartStop(msc_start_stop);
|
||||
msc.onRead(msc_read);
|
||||
msc.onWrite(msc_write);
|
||||
msc.mediaPresent(true);
|
||||
msc.begin(msc_boot->fat12_sector_num, DISK_SECTOR_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
void FirmwareMSC::end(){
|
||||
msc.end();
|
||||
if(msc_task_handle){
|
||||
vTaskDelete(msc_task_handle);
|
||||
msc_task_handle = NULL;
|
||||
}
|
||||
msc_update_delete_disk();
|
||||
}
|
||||
|
||||
void FirmwareMSC::onEvent(esp_event_handler_t callback){
|
||||
onEvent(ARDUINO_FIRMWARE_MSC_ANY_EVENT, callback);
|
||||
}
|
||||
void FirmwareMSC::onEvent(arduino_firmware_msc_event_t event, esp_event_handler_t callback){
|
||||
arduino_usb_event_handler_register_with(ARDUINO_FIRMWARE_MSC_EVENTS, event, callback, this);
|
||||
}
|
||||
|
||||
#if ARDUINO_USB_MSC_ON_BOOT
|
||||
FirmwareMSC MSC_Update;
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_USB_MSC_ENABLED */
|
70
cores/esp32/FirmwareMSC.h
Normal file
@ -0,0 +1,70 @@
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
#include <stdbool.h>
|
||||
#include "USBMSC.h"
|
||||
|
||||
#if CONFIG_TINYUSB_MSC_ENABLED
|
||||
|
||||
#include "esp_event.h"
|
||||
|
||||
ESP_EVENT_DECLARE_BASE(ARDUINO_FIRMWARE_MSC_EVENTS);
|
||||
|
||||
typedef enum {
|
||||
ARDUINO_FIRMWARE_MSC_ANY_EVENT = ESP_EVENT_ANY_ID,
|
||||
ARDUINO_FIRMWARE_MSC_START_EVENT = 0,
|
||||
ARDUINO_FIRMWARE_MSC_WRITE_EVENT,
|
||||
ARDUINO_FIRMWARE_MSC_END_EVENT,
|
||||
ARDUINO_FIRMWARE_MSC_ERROR_EVENT,
|
||||
ARDUINO_FIRMWARE_MSC_POWER_EVENT,
|
||||
ARDUINO_FIRMWARE_MSC_MAX_EVENT,
|
||||
} arduino_firmware_msc_event_t;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
size_t offset;
|
||||
size_t size;
|
||||
} write;
|
||||
struct {
|
||||
uint8_t power_condition;
|
||||
bool start;
|
||||
bool load_eject;
|
||||
} power;
|
||||
struct {
|
||||
size_t size;
|
||||
} end;
|
||||
struct {
|
||||
size_t size;
|
||||
} error;
|
||||
} arduino_firmware_msc_event_data_t;
|
||||
|
||||
class FirmwareMSC {
|
||||
private:
|
||||
USBMSC msc;
|
||||
|
||||
public:
|
||||
FirmwareMSC();
|
||||
~FirmwareMSC();
|
||||
bool begin();
|
||||
void end();
|
||||
void onEvent(esp_event_handler_t callback);
|
||||
void onEvent(arduino_firmware_msc_event_t event, esp_event_handler_t callback);
|
||||
};
|
||||
|
||||
#if ARDUINO_USB_MSC_ON_BOOT
|
||||
extern FirmwareMSC MSC_Update;
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_TINYUSB_MSC_ENABLED */
|
@ -16,7 +16,7 @@ extern "C"
|
||||
extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type, bool functional);
|
||||
}
|
||||
|
||||
void IRAM_ATTR interruptFunctional(void* arg)
|
||||
void ARDUINO_ISR_ATTR interruptFunctional(void* arg)
|
||||
{
|
||||
InterruptArgStructure* localArg = (InterruptArgStructure*)arg;
|
||||
if (localArg->interruptFunction)
|
||||
|
388
cores/esp32/HWCDC.cpp
Normal file
@ -0,0 +1,388 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "USB.h"
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
|
||||
#include "esp32-hal.h"
|
||||
#include "HWCDC.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/ringbuf.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "soc/periph_defs.h"
|
||||
#include "hal/usb_serial_jtag_ll.h"
|
||||
|
||||
ESP_EVENT_DEFINE_BASE(ARDUINO_HW_CDC_EVENTS);
|
||||
|
||||
static RingbufHandle_t tx_ring_buf = NULL;
|
||||
static xQueueHandle rx_queue = NULL;
|
||||
static uint8_t rx_data_buf[64];
|
||||
static intr_handle_t intr_handle = NULL;
|
||||
static volatile bool initial_empty = false;
|
||||
static xSemaphoreHandle tx_lock = NULL;
|
||||
static uint32_t tx_timeout_ms = 200;
|
||||
static esp_event_loop_handle_t arduino_hw_cdc_event_loop_handle = NULL;
|
||||
|
||||
static esp_err_t arduino_hw_cdc_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, BaseType_t *task_unblocked){
|
||||
if(arduino_hw_cdc_event_loop_handle == NULL){
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return esp_event_isr_post_to(arduino_hw_cdc_event_loop_handle, event_base, event_id, event_data, event_data_size, task_unblocked);
|
||||
}
|
||||
|
||||
static esp_err_t arduino_hw_cdc_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg){
|
||||
if (!arduino_hw_cdc_event_loop_handle) {
|
||||
esp_event_loop_args_t event_task_args = {
|
||||
.queue_size = 5,
|
||||
.task_name = "arduino_hw_cdc_events",
|
||||
.task_priority = 5,
|
||||
.task_stack_size = 2048,
|
||||
.task_core_id = tskNO_AFFINITY
|
||||
};
|
||||
if (esp_event_loop_create(&event_task_args, &arduino_hw_cdc_event_loop_handle) != ESP_OK) {
|
||||
log_e("esp_event_loop_create failed");
|
||||
}
|
||||
}
|
||||
if(arduino_hw_cdc_event_loop_handle == NULL){
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return esp_event_handler_register_with(arduino_hw_cdc_event_loop_handle, event_base, event_id, event_handler, event_handler_arg);
|
||||
}
|
||||
|
||||
static void hw_cdc_isr_handler(void *arg) {
|
||||
portBASE_TYPE xTaskWoken = 0;
|
||||
uint32_t usbjtag_intr_status = 0;
|
||||
arduino_hw_cdc_event_data_t event = {0};
|
||||
usbjtag_intr_status = usb_serial_jtag_ll_get_intsts_mask();
|
||||
|
||||
if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY) {
|
||||
// Interrupt tells us the host picked up the data we sent.
|
||||
if (usb_serial_jtag_ll_txfifo_writable() == 1) {
|
||||
// We disable the interrupt here so that the interrupt won't be triggered if there is no data to send.
|
||||
usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
|
||||
|
||||
if(!initial_empty){
|
||||
initial_empty = true;
|
||||
//send event?
|
||||
//ets_printf("CONNECTED\n");
|
||||
arduino_hw_cdc_event_post(ARDUINO_HW_CDC_EVENTS, ARDUINO_HW_CDC_CONNECTED_EVENT, &event, sizeof(arduino_hw_cdc_event_data_t), &xTaskWoken);
|
||||
}
|
||||
size_t queued_size;
|
||||
uint8_t *queued_buff = (uint8_t *)xRingbufferReceiveUpToFromISR(tx_ring_buf, &queued_size, 64);
|
||||
// If the hardware fifo is avaliable, write in it. Otherwise, do nothing.
|
||||
if (queued_buff != NULL) { //Although tx_queued_bytes may be larger than 0. We may have interrupt before xRingbufferSend() was called.
|
||||
//Copy the queued buffer into the TX FIFO
|
||||
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
|
||||
usb_serial_jtag_ll_write_txfifo(queued_buff, queued_size);
|
||||
usb_serial_jtag_ll_txfifo_flush();
|
||||
vRingbufferReturnItemFromISR(tx_ring_buf, queued_buff, &xTaskWoken);
|
||||
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
|
||||
//send event?
|
||||
//ets_printf("TX:%u\n", queued_size);
|
||||
event.tx.len = queued_size;
|
||||
arduino_hw_cdc_event_post(ARDUINO_HW_CDC_EVENTS, ARDUINO_HW_CDC_TX_EVENT, &event, sizeof(arduino_hw_cdc_event_data_t), &xTaskWoken);
|
||||
}
|
||||
} else {
|
||||
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT) {
|
||||
// read rx buffer(max length is 64), and send avaliable data to ringbuffer.
|
||||
// Ensure the rx buffer size is larger than RX_MAX_SIZE.
|
||||
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT);
|
||||
uint32_t rx_fifo_len = usb_serial_jtag_ll_read_rxfifo(rx_data_buf, 64);
|
||||
uint32_t i=0;
|
||||
for(i=0; i<rx_fifo_len; i++){
|
||||
if(rx_queue == NULL || !xQueueSendFromISR(rx_queue, rx_data_buf+i, &xTaskWoken)){
|
||||
break;
|
||||
}
|
||||
}
|
||||
//send event?
|
||||
//ets_printf("RX:%u/%u\n", i, rx_fifo_len);
|
||||
event.rx.len = i;
|
||||
arduino_hw_cdc_event_post(ARDUINO_HW_CDC_EVENTS, ARDUINO_HW_CDC_RX_EVENT, &event, sizeof(arduino_hw_cdc_event_data_t), &xTaskWoken);
|
||||
}
|
||||
|
||||
if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_BUS_RESET) {
|
||||
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_BUS_RESET);
|
||||
initial_empty = false;
|
||||
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
|
||||
//ets_printf("BUS_RESET\n");
|
||||
arduino_hw_cdc_event_post(ARDUINO_HW_CDC_EVENTS, ARDUINO_HW_CDC_BUS_RESET_EVENT, &event, sizeof(arduino_hw_cdc_event_data_t), &xTaskWoken);
|
||||
}
|
||||
|
||||
if (xTaskWoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
static void ARDUINO_ISR_ATTR cdc0_write_char(char c) {
|
||||
if(xPortInIsrContext()){
|
||||
xRingbufferSendFromISR(tx_ring_buf, (void*) (&c), 1, NULL);
|
||||
} else {
|
||||
xRingbufferSend(tx_ring_buf, (void*) (&c), 1, tx_timeout_ms / portTICK_PERIOD_MS);
|
||||
}
|
||||
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
|
||||
}
|
||||
|
||||
HWCDC::HWCDC() {
|
||||
|
||||
}
|
||||
|
||||
HWCDC::~HWCDC(){
|
||||
end();
|
||||
}
|
||||
|
||||
HWCDC::operator bool() const
|
||||
{
|
||||
return initial_empty;
|
||||
}
|
||||
|
||||
void HWCDC::onEvent(esp_event_handler_t callback){
|
||||
onEvent(ARDUINO_HW_CDC_ANY_EVENT, callback);
|
||||
}
|
||||
|
||||
void HWCDC::onEvent(arduino_hw_cdc_event_t event, esp_event_handler_t callback){
|
||||
arduino_hw_cdc_event_handler_register_with(ARDUINO_HW_CDC_EVENTS, event, callback, this);
|
||||
}
|
||||
|
||||
void HWCDC::begin(unsigned long baud)
|
||||
{
|
||||
if(tx_lock == NULL) {
|
||||
tx_lock = xSemaphoreCreateMutex();
|
||||
}
|
||||
setRxBufferSize(256);//default if not preset
|
||||
setTxBufferSize(256);//default if not preset
|
||||
|
||||
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY | USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT | USB_SERIAL_JTAG_INTR_BUS_RESET);
|
||||
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY | USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT | USB_SERIAL_JTAG_INTR_BUS_RESET);
|
||||
if(!intr_handle && esp_intr_alloc(ETS_USB_SERIAL_JTAG_INTR_SOURCE, 0, hw_cdc_isr_handler, NULL, &intr_handle) != ESP_OK){
|
||||
isr_log_e("HW USB CDC failed to init interrupts");
|
||||
end();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void HWCDC::end()
|
||||
{
|
||||
//Disable tx/rx interrupt.
|
||||
usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY | USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT | USB_SERIAL_JTAG_INTR_BUS_RESET);
|
||||
esp_intr_free(intr_handle);
|
||||
intr_handle = NULL;
|
||||
if(tx_lock != NULL) {
|
||||
vSemaphoreDelete(tx_lock);
|
||||
}
|
||||
setRxBufferSize(0);
|
||||
setTxBufferSize(0);
|
||||
if (arduino_hw_cdc_event_loop_handle) {
|
||||
esp_event_loop_delete(arduino_hw_cdc_event_loop_handle);
|
||||
arduino_hw_cdc_event_loop_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void HWCDC::setTxTimeoutMs(uint32_t timeout){
|
||||
tx_timeout_ms = timeout;
|
||||
}
|
||||
|
||||
/*
|
||||
* WRITING
|
||||
*/
|
||||
|
||||
size_t HWCDC::setTxBufferSize(size_t tx_queue_len){
|
||||
if(tx_ring_buf){
|
||||
if(!tx_queue_len){
|
||||
vRingbufferDelete(tx_ring_buf);
|
||||
tx_ring_buf = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
tx_ring_buf = xRingbufferCreate(tx_queue_len, RINGBUF_TYPE_BYTEBUF);
|
||||
if(!tx_ring_buf){
|
||||
return 0;
|
||||
}
|
||||
return tx_queue_len;
|
||||
}
|
||||
|
||||
int HWCDC::availableForWrite(void)
|
||||
{
|
||||
if(tx_ring_buf == NULL || tx_lock == NULL){
|
||||
return 0;
|
||||
}
|
||||
if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){
|
||||
return 0;
|
||||
}
|
||||
size_t a = xRingbufferGetCurFreeSize(tx_ring_buf);
|
||||
xSemaphoreGive(tx_lock);
|
||||
return a;
|
||||
}
|
||||
|
||||
size_t HWCDC::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
if(buffer == NULL || size == 0 || tx_ring_buf == NULL || tx_lock == NULL){
|
||||
return 0;
|
||||
}
|
||||
if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){
|
||||
return 0;
|
||||
}
|
||||
size_t max_size = xRingbufferGetMaxItemSize(tx_ring_buf);
|
||||
size_t space = xRingbufferGetCurFreeSize(tx_ring_buf);
|
||||
size_t to_send = size, so_far = 0;
|
||||
|
||||
if(space > size){
|
||||
space = size;
|
||||
}
|
||||
// Non-Blocking method, Sending data to ringbuffer, and handle the data in ISR.
|
||||
if(xRingbufferSend(tx_ring_buf, (void*) (buffer), space, 0) != pdTRUE){
|
||||
size = 0;
|
||||
} else {
|
||||
to_send -= space;
|
||||
so_far += space;
|
||||
// Now trigger the ISR to read data from the ring buffer.
|
||||
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
|
||||
|
||||
while(to_send){
|
||||
if(max_size > to_send){
|
||||
max_size = to_send;
|
||||
}
|
||||
// Blocking method, Sending data to ringbuffer, and handle the data in ISR.
|
||||
if(xRingbufferSend(tx_ring_buf, (void*) (buffer+so_far), max_size, tx_timeout_ms / portTICK_PERIOD_MS) != pdTRUE){
|
||||
size = so_far;
|
||||
break;
|
||||
}
|
||||
so_far += max_size;
|
||||
to_send -= max_size;
|
||||
// Now trigger the ISR to read data from the ring buffer.
|
||||
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
|
||||
}
|
||||
}
|
||||
xSemaphoreGive(tx_lock);
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t HWCDC::write(uint8_t c)
|
||||
{
|
||||
return write(&c, 1);
|
||||
}
|
||||
|
||||
void HWCDC::flush(void)
|
||||
{
|
||||
if(tx_ring_buf == NULL || tx_lock == NULL){
|
||||
return;
|
||||
}
|
||||
if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){
|
||||
return;
|
||||
}
|
||||
UBaseType_t uxItemsWaiting = 0;
|
||||
vRingbufferGetInfo(tx_ring_buf, NULL, NULL, NULL, NULL, &uxItemsWaiting);
|
||||
if(uxItemsWaiting){
|
||||
// Now trigger the ISR to read data from the ring buffer.
|
||||
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
|
||||
}
|
||||
while(uxItemsWaiting){
|
||||
delay(5);
|
||||
vRingbufferGetInfo(tx_ring_buf, NULL, NULL, NULL, NULL, &uxItemsWaiting);
|
||||
}
|
||||
xSemaphoreGive(tx_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* READING
|
||||
*/
|
||||
|
||||
size_t HWCDC::setRxBufferSize(size_t rx_queue_len){
|
||||
if(rx_queue){
|
||||
if(!rx_queue_len){
|
||||
vQueueDelete(rx_queue);
|
||||
rx_queue = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
rx_queue = xQueueCreate(rx_queue_len, sizeof(uint8_t));
|
||||
if(!rx_queue){
|
||||
return 0;
|
||||
}
|
||||
if(!tx_ring_buf){
|
||||
tx_ring_buf = xRingbufferCreate(rx_queue_len, RINGBUF_TYPE_BYTEBUF);
|
||||
}
|
||||
return rx_queue_len;
|
||||
}
|
||||
|
||||
int HWCDC::available(void)
|
||||
{
|
||||
if(rx_queue == NULL){
|
||||
return -1;
|
||||
}
|
||||
return uxQueueMessagesWaiting(rx_queue);
|
||||
}
|
||||
|
||||
int HWCDC::peek(void)
|
||||
{
|
||||
if(rx_queue == NULL){
|
||||
return -1;
|
||||
}
|
||||
uint8_t c;
|
||||
if(xQueuePeek(rx_queue, &c, 0)) {
|
||||
return c;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int HWCDC::read(void)
|
||||
{
|
||||
if(rx_queue == NULL){
|
||||
return -1;
|
||||
}
|
||||
uint8_t c = 0;
|
||||
if(xQueueReceive(rx_queue, &c, 0)) {
|
||||
return c;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t HWCDC::read(uint8_t *buffer, size_t size)
|
||||
{
|
||||
if(rx_queue == NULL){
|
||||
return -1;
|
||||
}
|
||||
uint8_t c = 0;
|
||||
size_t count = 0;
|
||||
while(count < size && xQueueReceive(rx_queue, &c, 0)){
|
||||
buffer[count++] = c;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* DEBUG
|
||||
*/
|
||||
|
||||
void HWCDC::setDebugOutput(bool en)
|
||||
{
|
||||
if(en) {
|
||||
uartSetDebug(NULL);
|
||||
ets_install_putc1((void (*)(char)) &cdc0_write_char);
|
||||
} else {
|
||||
ets_install_putc1(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#if ARDUINO_HW_CDC_ON_BOOT //Serial used for USB CDC
|
||||
HWCDC Serial;
|
||||
#else
|
||||
HWCDC USBSerial;
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_TINYUSB_CDC_ENABLED */
|
107
cores/esp32/HWCDC.h
Normal file
@ -0,0 +1,107 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "esp_event.h"
|
||||
#include "Stream.h"
|
||||
|
||||
ESP_EVENT_DECLARE_BASE(ARDUINO_HW_CDC_EVENTS);
|
||||
|
||||
typedef enum {
|
||||
ARDUINO_HW_CDC_ANY_EVENT = ESP_EVENT_ANY_ID,
|
||||
ARDUINO_HW_CDC_CONNECTED_EVENT = 0,
|
||||
ARDUINO_HW_CDC_BUS_RESET_EVENT,
|
||||
ARDUINO_HW_CDC_RX_EVENT,
|
||||
ARDUINO_HW_CDC_TX_EVENT,
|
||||
ARDUINO_HW_CDC_MAX_EVENT,
|
||||
} arduino_hw_cdc_event_t;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
size_t len;
|
||||
} rx;
|
||||
struct {
|
||||
size_t len;
|
||||
} tx;
|
||||
} arduino_hw_cdc_event_data_t;
|
||||
|
||||
class HWCDC: public Stream
|
||||
{
|
||||
public:
|
||||
HWCDC();
|
||||
~HWCDC();
|
||||
|
||||
void onEvent(esp_event_handler_t callback);
|
||||
void onEvent(arduino_hw_cdc_event_t event, esp_event_handler_t callback);
|
||||
|
||||
size_t setRxBufferSize(size_t);
|
||||
size_t setTxBufferSize(size_t);
|
||||
void setTxTimeoutMs(uint32_t timeout);
|
||||
void begin(unsigned long baud=0);
|
||||
void end();
|
||||
|
||||
int available(void);
|
||||
int availableForWrite(void);
|
||||
int peek(void);
|
||||
int read(void);
|
||||
size_t read(uint8_t *buffer, size_t size);
|
||||
size_t write(uint8_t);
|
||||
size_t write(const uint8_t *buffer, size_t size);
|
||||
void flush(void);
|
||||
|
||||
inline size_t read(char * buffer, size_t size)
|
||||
{
|
||||
return read((uint8_t*) buffer, size);
|
||||
}
|
||||
inline size_t write(const char * buffer, size_t size)
|
||||
{
|
||||
return write((uint8_t*) buffer, size);
|
||||
}
|
||||
inline size_t write(const char * s)
|
||||
{
|
||||
return write((uint8_t*) s, strlen(s));
|
||||
}
|
||||
inline size_t write(unsigned long n)
|
||||
{
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
inline size_t write(long n)
|
||||
{
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
inline size_t write(unsigned int n)
|
||||
{
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
inline size_t write(int n)
|
||||
{
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
operator bool() const;
|
||||
void setDebugOutput(bool);
|
||||
uint32_t baudRate(){return 115200;}
|
||||
|
||||
};
|
||||
|
||||
#if ARDUINO_HW_CDC_ON_BOOT //Serial used for USB CDC
|
||||
extern HWCDC Serial;
|
||||
#else
|
||||
extern HWCDC USBSerial;
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_IDF_TARGET_ESP32C3 */
|
@ -5,58 +5,141 @@
|
||||
|
||||
#include "pins_arduino.h"
|
||||
#include "HardwareSerial.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#ifndef SOC_RX0
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define SOC_RX0 3
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#define SOC_RX0 44
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#define SOC_RX0 20
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SOC_TX0
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define SOC_TX0 1
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#define SOC_TX0 43
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#define SOC_TX0 21
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void serialEvent(void) __attribute__((weak));
|
||||
void serialEvent(void) {}
|
||||
|
||||
#if SOC_UART_NUM > 1
|
||||
|
||||
#ifndef RX1
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define RX1 9
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#define RX1 18
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#define RX1 18
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef TX1
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define TX1 10
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#define TX1 17
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#define TX1 19
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void serialEvent1(void) __attribute__((weak));
|
||||
void serialEvent1(void) {}
|
||||
#endif /* SOC_UART_NUM > 1 */
|
||||
|
||||
#if SOC_UART_NUM > 2
|
||||
#ifndef RX2
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define RX2 16
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef TX2
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define TX2 17
|
||||
#endif
|
||||
#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
|
||||
|
||||
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)
|
||||
void serialEventRun(void)
|
||||
{
|
||||
if(0 > _uart_nr || _uart_nr > 2) {
|
||||
log_e("Serial number is invalid, please use 0, 1 or 2");
|
||||
#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);
|
||||
return;
|
||||
}
|
||||
if(_uart) {
|
||||
end();
|
||||
// in this case it is a begin() over a previous begin() - maybe to change baud rate
|
||||
// thus do not disable debug output
|
||||
end(false);
|
||||
}
|
||||
if(_uart_nr == 0 && rxPin < 0 && txPin < 0) {
|
||||
rxPin = 3;
|
||||
txPin = 1;
|
||||
rxPin = SOC_RX0;
|
||||
txPin = SOC_TX0;
|
||||
}
|
||||
#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, 256, invert);
|
||||
_tx_pin = txPin;
|
||||
_rx_pin = rxPin;
|
||||
|
||||
if(!baud) {
|
||||
_uart = uartBegin(_uart_nr, baud ? baud : 9600, config, rxPin, txPin, _rxBufferSize, invert, rxfifo_full_thrhd);
|
||||
if (!baud) {
|
||||
// using baud rate as zero, forces it to try to detect the current baud rate in place
|
||||
uartStartDetectBaudrate(_uart);
|
||||
time_t startMillis = millis();
|
||||
unsigned long detectedBaudRate = 0;
|
||||
@ -64,16 +147,14 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
|
||||
yield();
|
||||
}
|
||||
|
||||
end();
|
||||
end(false);
|
||||
|
||||
if(detectedBaudRate) {
|
||||
delay(100); // Give some time...
|
||||
_uart = uartBegin(_uart_nr, detectedBaudRate, config, rxPin, txPin, 256, invert);
|
||||
_uart = uartBegin(_uart_nr, detectedBaudRate, config, rxPin, txPin, _rxBufferSize, invert, rxfifo_full_thrhd);
|
||||
} else {
|
||||
log_e("Could not detect baudrate. Serial data at the port must be present within the timeout for detection to be possible");
|
||||
_uart = NULL;
|
||||
_tx_pin = 255;
|
||||
_rx_pin = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -83,20 +164,16 @@ void HardwareSerial::updateBaudRate(unsigned long baud)
|
||||
uartSetBaudRate(_uart, baud);
|
||||
}
|
||||
|
||||
void HardwareSerial::end()
|
||||
void HardwareSerial::end(bool turnOffDebug)
|
||||
{
|
||||
if(uartGetDebug() == _uart_nr) {
|
||||
if(turnOffDebug && uartGetDebug() == _uart_nr) {
|
||||
uartSetDebug(0);
|
||||
}
|
||||
log_v("pins %d %d",_tx_pin, _rx_pin);
|
||||
uartEnd(_uart, _tx_pin, _rx_pin);
|
||||
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) {
|
||||
@ -106,7 +183,7 @@ void HardwareSerial::setDebugOutput(bool en)
|
||||
uartSetDebug(_uart);
|
||||
} else {
|
||||
if(uartGetDebug() == _uart_nr) {
|
||||
uartSetDebug(0);
|
||||
uartSetDebug(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -182,10 +259,31 @@ uint32_t HardwareSerial::baudRate()
|
||||
}
|
||||
HardwareSerial::operator bool() const
|
||||
{
|
||||
return true;
|
||||
return uartIsDriverInstalled(_uart);
|
||||
}
|
||||
|
||||
void HardwareSerial::setRxInvert(bool invert)
|
||||
{
|
||||
uartSetRxInvert(_uart, invert);
|
||||
}
|
||||
|
||||
void HardwareSerial::setPins(uint8_t rxPin, uint8_t txPin)
|
||||
{
|
||||
uartSetPins(_uart, rxPin, txPin);
|
||||
}
|
||||
|
||||
size_t HardwareSerial::setRxBufferSize(size_t new_size) {
|
||||
|
||||
if (_uart) {
|
||||
log_e("RX Buffer can't be resized when Serial is already running.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (new_size <= SOC_UART_FIFO_LEN) {
|
||||
log_e("RX Buffer must be higher than %d.\n", SOC_UART_FIFO_LEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_rxBufferSize = new_size;
|
||||
return _rxBufferSize;
|
||||
}
|
||||
|
@ -49,14 +49,16 @@
|
||||
|
||||
#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);
|
||||
void end();
|
||||
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 updateBaudRate(unsigned long baud);
|
||||
int available(void);
|
||||
int availableForWrite(void);
|
||||
@ -98,24 +100,39 @@ public:
|
||||
uint32_t baudRate();
|
||||
operator bool() const;
|
||||
|
||||
size_t setRxBufferSize(size_t);
|
||||
void setDebugOutput(bool);
|
||||
|
||||
void setRxInvert(bool);
|
||||
void setPins(uint8_t rxPin, uint8_t txPin);
|
||||
size_t setRxBufferSize(size_t new_size);
|
||||
|
||||
protected:
|
||||
int _uart_nr;
|
||||
uart_t* _uart;
|
||||
uint8_t _tx_pin;
|
||||
uint8_t _rx_pin;
|
||||
size_t _rxBufferSize;
|
||||
};
|
||||
|
||||
extern void serialEventRun(void) __attribute__((weak));
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
|
||||
#ifndef ARDUINO_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
|
||||
|
@ -21,7 +21,21 @@
|
||||
|
||||
#include <WString.h>
|
||||
#include <Stream.h>
|
||||
|
||||
#include "esp_system.h"
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/md5_hash.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/md5_hash.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#include "esp32c3/rom/md5_hash.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/md5_hash.h"
|
||||
#endif
|
||||
|
||||
class MD5Builder
|
||||
{
|
||||
|
@ -73,6 +73,11 @@ 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[]);
|
||||
|
343
cores/esp32/USB.cpp
Normal file
@ -0,0 +1,343 @@
|
||||
// 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 */
|
119
cores/esp32/USB.h
Normal file
@ -0,0 +1,119 @@
|
||||
// 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 */
|
419
cores/esp32/USBCDC.cpp
Normal file
@ -0,0 +1,419 @@
|
||||
// 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 */
|
141
cores/esp32/USBCDC.h
Normal file
@ -0,0 +1,141 @@
|
||||
// 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 */
|
260
cores/esp32/USBMSC.cpp
Normal file
@ -0,0 +1,260 @@
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "USBMSC.h"
|
||||
|
||||
#if CONFIG_TINYUSB_MSC_ENABLED
|
||||
|
||||
#include "esp32-hal-tinyusb.h"
|
||||
|
||||
extern "C" uint16_t tusb_msc_load_descriptor(uint8_t * dst, uint8_t * itf)
|
||||
{
|
||||
uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB MSC");
|
||||
uint8_t ep_num = tinyusb_get_free_duplex_endpoint();
|
||||
TU_VERIFY (ep_num != 0);
|
||||
uint8_t descriptor[TUD_MSC_DESC_LEN] = {
|
||||
// Interface number, string index, EP Out & EP In address, EP size
|
||||
TUD_MSC_DESCRIPTOR(*itf, str_index, ep_num, (uint8_t)(0x80 | ep_num), 64)
|
||||
};
|
||||
*itf+=1;
|
||||
memcpy(dst, descriptor, TUD_MSC_DESC_LEN);
|
||||
return TUD_MSC_DESC_LEN;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
bool media_present;
|
||||
uint8_t vendor_id[8];
|
||||
uint8_t product_id[16];
|
||||
uint8_t product_rev[4];
|
||||
uint16_t block_size;
|
||||
uint32_t block_count;
|
||||
bool (*start_stop)(uint8_t power_condition, bool start, bool load_eject);
|
||||
int32_t (*read)(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize);
|
||||
int32_t (*write)(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize);
|
||||
} msc_lun_t;
|
||||
|
||||
static const uint8_t MSC_MAX_LUN = 3;
|
||||
static uint8_t MSC_ACTIVE_LUN = 0;
|
||||
static msc_lun_t msc_luns[MSC_MAX_LUN];
|
||||
|
||||
static void cplstr(void *dst, const void * src, size_t max_len){
|
||||
if(!src || !dst || !max_len){
|
||||
return;
|
||||
}
|
||||
size_t l = strlen((const char *)src);
|
||||
if(l > max_len){
|
||||
l = max_len;
|
||||
}
|
||||
memcpy(dst, src, l);
|
||||
}
|
||||
|
||||
// Invoked when received GET_MAX_LUN request, required for multiple LUNs implementation
|
||||
uint8_t tud_msc_get_maxlun_cb(void)
|
||||
{
|
||||
log_v("%u", MSC_ACTIVE_LUN);
|
||||
return MSC_ACTIVE_LUN;
|
||||
}
|
||||
|
||||
// Invoked when received SCSI_CMD_INQUIRY
|
||||
// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
|
||||
void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4])
|
||||
{
|
||||
log_v("[%u]", lun);
|
||||
cplstr(vendor_id , msc_luns[lun].vendor_id, 8);
|
||||
cplstr(product_id , msc_luns[lun].product_id, 16);
|
||||
cplstr(product_rev, msc_luns[lun].product_rev, 4);
|
||||
}
|
||||
|
||||
// Invoked when received Test Unit Ready command.
|
||||
// return true allowing host to read/write this LUN e.g SD card inserted
|
||||
bool tud_msc_test_unit_ready_cb(uint8_t lun)
|
||||
{
|
||||
log_v("[%u]: %u", lun, msc_luns[lun].media_present);
|
||||
return msc_luns[lun].media_present; // RAM disk is always ready
|
||||
}
|
||||
|
||||
// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
|
||||
// Application update block count and block size
|
||||
void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size)
|
||||
{
|
||||
log_v("[%u]", lun);
|
||||
if(!msc_luns[lun].media_present){
|
||||
*block_count = 0;
|
||||
*block_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
*block_count = msc_luns[lun].block_count;
|
||||
*block_size = msc_luns[lun].block_size;
|
||||
}
|
||||
|
||||
// Invoked when received Start Stop Unit command
|
||||
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
|
||||
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
|
||||
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject)
|
||||
{
|
||||
log_v("[%u] power: %u, start: %u, eject: %u", lun, power_condition, start, load_eject);
|
||||
if(msc_luns[lun].start_stop){
|
||||
return msc_luns[lun].start_stop(power_condition, start, load_eject);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Callback invoked when received READ10 command.
|
||||
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
|
||||
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
log_v("[%u], lba: %u, offset: %u, bufsize: %u", lun, lba, offset, bufsize);
|
||||
if(!msc_luns[lun].media_present){
|
||||
return 0;
|
||||
}
|
||||
if(msc_luns[lun].read){
|
||||
return msc_luns[lun].read(lba, offset, buffer, bufsize);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Callback invoked when received WRITE10 command.
|
||||
// Process data in buffer to disk's storage and return number of written bytes
|
||||
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize)
|
||||
{
|
||||
log_v("[%u], lba: %u, offset: %u, bufsize: %u", lun, lba, offset, bufsize);
|
||||
if(!msc_luns[lun].media_present){
|
||||
return 0;
|
||||
}
|
||||
if(msc_luns[lun].write){
|
||||
return msc_luns[lun].write(lba, offset, buffer, bufsize);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Callback invoked when received an SCSI command not in built-in list below
|
||||
// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
|
||||
// - READ10 and WRITE10 has their own callbacks
|
||||
int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize)
|
||||
{
|
||||
// read10 & write10 has their own callback and MUST not be handled here
|
||||
log_v("[%u] cmd: %u, bufsize: %u", lun, scsi_cmd[0], bufsize);
|
||||
|
||||
void const* response = NULL;
|
||||
uint16_t resplen = 0;
|
||||
|
||||
// most scsi handled is input
|
||||
bool in_xfer = true;
|
||||
|
||||
if(!msc_luns[lun].media_present){
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (scsi_cmd[0]) {
|
||||
case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
|
||||
// Host is about to read/write etc ... better not to disconnect disk
|
||||
resplen = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Set Sense = Invalid Command Operation
|
||||
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
|
||||
|
||||
// negative means error -> tinyusb could stall and/or response with failed status
|
||||
resplen = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
// return resplen must not larger than bufsize
|
||||
if (resplen > bufsize) resplen = bufsize;
|
||||
|
||||
if (response && (resplen > 0)) {
|
||||
if (in_xfer) {
|
||||
memcpy(buffer, response, resplen);
|
||||
} else {
|
||||
// SCSI output
|
||||
}
|
||||
}
|
||||
|
||||
return resplen;
|
||||
}
|
||||
|
||||
USBMSC::USBMSC(){
|
||||
if(MSC_ACTIVE_LUN < MSC_MAX_LUN){
|
||||
_lun = MSC_ACTIVE_LUN;
|
||||
MSC_ACTIVE_LUN++;
|
||||
msc_luns[_lun].media_present = false;
|
||||
msc_luns[_lun].vendor_id[0] = 0;
|
||||
msc_luns[_lun].product_id[0] = 0;
|
||||
msc_luns[_lun].product_rev[0] = 0;
|
||||
msc_luns[_lun].block_size = 0;
|
||||
msc_luns[_lun].block_count = 0;
|
||||
msc_luns[_lun].start_stop = NULL;
|
||||
msc_luns[_lun].read = NULL;
|
||||
msc_luns[_lun].write = NULL;
|
||||
}
|
||||
if(_lun == 0){
|
||||
tinyusb_enable_interface(USB_INTERFACE_MSC, TUD_MSC_DESC_LEN, tusb_msc_load_descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
USBMSC::~USBMSC(){
|
||||
end();
|
||||
}
|
||||
|
||||
bool USBMSC::begin(uint32_t block_count, uint16_t block_size){
|
||||
msc_luns[_lun].block_size = block_size;
|
||||
msc_luns[_lun].block_count = block_count;
|
||||
if(!msc_luns[_lun].block_size || !msc_luns[_lun].block_count || !msc_luns[_lun].read || !msc_luns[_lun].write){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void USBMSC::end(){
|
||||
msc_luns[_lun].media_present = false;
|
||||
msc_luns[_lun].vendor_id[0] = 0;
|
||||
msc_luns[_lun].product_id[0] = 0;
|
||||
msc_luns[_lun].product_rev[0] = 0;
|
||||
msc_luns[_lun].block_size = 0;
|
||||
msc_luns[_lun].block_count = 0;
|
||||
msc_luns[_lun].start_stop = NULL;
|
||||
msc_luns[_lun].read = NULL;
|
||||
msc_luns[_lun].write = NULL;
|
||||
}
|
||||
|
||||
void USBMSC::vendorID(const char * vid){
|
||||
cplstr(msc_luns[_lun].vendor_id, vid, 8);
|
||||
}
|
||||
|
||||
void USBMSC::productID(const char * pid){
|
||||
cplstr(msc_luns[_lun].product_id, pid, 16);
|
||||
}
|
||||
|
||||
void USBMSC::productRevision(const char * rev){
|
||||
cplstr(msc_luns[_lun].product_rev, rev, 4);
|
||||
}
|
||||
|
||||
void USBMSC::onStartStop(msc_start_stop_cb cb){
|
||||
msc_luns[_lun].start_stop = cb;
|
||||
}
|
||||
|
||||
void USBMSC::onRead(msc_read_cb cb){
|
||||
msc_luns[_lun].read = cb;
|
||||
}
|
||||
|
||||
void USBMSC::onWrite(msc_write_cb cb){
|
||||
msc_luns[_lun].write = cb;
|
||||
}
|
||||
|
||||
void USBMSC::mediaPresent(bool media_present){
|
||||
msc_luns[_lun].media_present = media_present;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_TINYUSB_MSC_ENABLED */
|
51
cores/esp32/USBMSC.h
Normal file
@ -0,0 +1,51 @@
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_TINYUSB_MSC_ENABLED
|
||||
|
||||
// Invoked when received Start Stop Unit command
|
||||
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
|
||||
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
|
||||
typedef bool (*msc_start_stop_cb)(uint8_t power_condition, bool start, bool load_eject);
|
||||
|
||||
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
|
||||
typedef int32_t (*msc_read_cb)(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize);
|
||||
|
||||
// Process data in buffer to disk's storage and return number of written bytes
|
||||
typedef int32_t (*msc_write_cb)(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize);
|
||||
|
||||
class USBMSC
|
||||
{
|
||||
public:
|
||||
USBMSC();
|
||||
~USBMSC();
|
||||
bool begin(uint32_t block_count, uint16_t block_size);
|
||||
void end();
|
||||
void vendorID(const char * vid);//max 8 chars
|
||||
void productID(const char * pid);//max 16 chars
|
||||
void productRevision(const char * ver);//max 4 chars
|
||||
void mediaPresent(bool media_present);
|
||||
void onStartStop(msc_start_stop_cb cb);
|
||||
void onRead(msc_read_cb cb);
|
||||
void onWrite(msc_write_cb cb);
|
||||
private:
|
||||
uint8_t _lun;
|
||||
};
|
||||
|
||||
#endif /* CONFIG_TINYUSB_MSC_ENABLED */
|
@ -27,6 +27,7 @@ extern "C" {
|
||||
#include <stdlib.h>
|
||||
#include "esp_system.h"
|
||||
}
|
||||
#include "esp32-hal-log.h"
|
||||
|
||||
void randomSeed(unsigned long seed)
|
||||
{
|
||||
@ -69,16 +70,19 @@ 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
unsigned int makeWord(unsigned int w)
|
||||
uint16_t makeWord(uint16_t w)
|
||||
{
|
||||
return w;
|
||||
}
|
||||
|
||||
unsigned int makeWord(unsigned char h, unsigned char l)
|
||||
uint16_t makeWord(uint8_t h, uint8_t l)
|
||||
{
|
||||
return (h << 8) | l;
|
||||
}
|
||||
|
@ -35,6 +35,12 @@ String::String(const char *cstr) {
|
||||
copy(cstr, strlen(cstr));
|
||||
}
|
||||
|
||||
String::String(const char *cstr, unsigned int length) {
|
||||
init();
|
||||
if (cstr)
|
||||
copy(cstr, length);
|
||||
}
|
||||
|
||||
String::String(const String &value) {
|
||||
init();
|
||||
*this = value;
|
||||
@ -59,9 +65,7 @@ String::String(StringSumHelper &&rval) {
|
||||
|
||||
String::String(char c) {
|
||||
init();
|
||||
char buf[2];
|
||||
buf[0] = c;
|
||||
buf[1] = 0;
|
||||
char buf[] = { c, '\0' };
|
||||
*this = buf;
|
||||
}
|
||||
|
||||
@ -130,9 +134,9 @@ String::~String() {
|
||||
|
||||
inline void String::init(void) {
|
||||
setSSO(false);
|
||||
setBuffer(nullptr);
|
||||
setCapacity(0);
|
||||
setLen(0);
|
||||
setBuffer(nullptr);
|
||||
}
|
||||
|
||||
void String::invalidate(void) {
|
||||
@ -159,7 +163,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
|
||||
@ -168,8 +172,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;
|
||||
}
|
||||
}
|
||||
@ -193,8 +197,8 @@ unsigned char String::changeBuffer(unsigned int maxStrLen) {
|
||||
}
|
||||
setSSO(false);
|
||||
setCapacity(newSize - 1);
|
||||
setLen(oldLen); // Needed in case of SSO where len() never existed
|
||||
setBuffer(newbuffer);
|
||||
setLen(oldLen); // Needed in case of SSO where len() never existed
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@ -209,8 +213,8 @@ String & String::copy(const char *cstr, unsigned int length) {
|
||||
invalidate();
|
||||
return *this;
|
||||
}
|
||||
setLen(length);
|
||||
memmove(wbuffer(), cstr, length + 1);
|
||||
setLen(length);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -219,8 +223,8 @@ String & String::copy(const __FlashStringHelper *pstr, unsigned int length) {
|
||||
invalidate();
|
||||
return *this;
|
||||
}
|
||||
setLen(length);
|
||||
memcpy_P(wbuffer(), (PGM_P)pstr, length + 1); // We know wbuffer() cannot ever be in PROGMEM, so memcpy safe here
|
||||
setLen(length);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -250,8 +254,8 @@ void String::move(String &rhs) {
|
||||
setLen(rhs.len());
|
||||
rhs.setSSO(false);
|
||||
rhs.setCapacity(0);
|
||||
rhs.setLen(0);
|
||||
rhs.setBuffer(nullptr);
|
||||
rhs.setLen(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -290,10 +294,11 @@ 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;
|
||||
}
|
||||
@ -347,22 +352,18 @@ unsigned char String::concat(const char *cstr) {
|
||||
}
|
||||
|
||||
unsigned char String::concat(char c) {
|
||||
char buf[2];
|
||||
buf[0] = c;
|
||||
buf[1] = 0;
|
||||
char buf[] = { c, '\0' };
|
||||
return concat(buf, 1);
|
||||
}
|
||||
|
||||
unsigned char String::concat(unsigned char num) {
|
||||
char buf[1 + 3 * sizeof(unsigned char)];
|
||||
sprintf(buf, "%d", num);
|
||||
return concat(buf, strlen(buf));
|
||||
return concat(buf, sprintf(buf, "%d", num));
|
||||
}
|
||||
|
||||
unsigned char String::concat(int num) {
|
||||
char buf[2 + 3 * sizeof(int)];
|
||||
sprintf(buf, "%d", num);
|
||||
return concat(buf, strlen(buf));
|
||||
return concat(buf, sprintf(buf, "%d", num));
|
||||
}
|
||||
|
||||
unsigned char String::concat(unsigned int num) {
|
||||
@ -373,8 +374,7 @@ unsigned char String::concat(unsigned int num) {
|
||||
|
||||
unsigned char String::concat(long num) {
|
||||
char buf[2 + 3 * sizeof(long)];
|
||||
sprintf(buf, "%ld", num);
|
||||
return concat(buf, strlen(buf));
|
||||
return concat(buf, sprintf(buf, "%ld", num));
|
||||
}
|
||||
|
||||
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 lenghts are the same and non-zero
|
||||
//at this point lengths are the same and non-zero
|
||||
const char *p1 = buffer();
|
||||
const char *p2 = s2.buffer();
|
||||
unsigned int equalchars = 0;
|
||||
@ -711,10 +711,7 @@ String String::substring(unsigned int left, unsigned int right) const {
|
||||
return out;
|
||||
if(right > len())
|
||||
right = len();
|
||||
char temp = buffer()[right]; // save the replaced character
|
||||
wbuffer()[right] = '\0';
|
||||
out = wbuffer() + left; // pointer arithmetic
|
||||
wbuffer()[right] = temp; //restore character
|
||||
out.copy(buffer() + left, right - left);
|
||||
return out;
|
||||
}
|
||||
|
||||
@ -744,6 +741,7 @@ 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);
|
||||
@ -751,9 +749,10 @@ void String::replace(const String& find, const String& replace) {
|
||||
memmove(writeTo, replace.buffer(), replace.len());
|
||||
writeTo += replace.len();
|
||||
readFrom = foundAt + find.len();
|
||||
setLen(len() + diff);
|
||||
l += 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) {
|
||||
@ -768,7 +767,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;
|
||||
@ -796,8 +795,8 @@ void String::remove(unsigned int index, unsigned int count) {
|
||||
}
|
||||
char *writeTo = wbuffer() + index;
|
||||
unsigned int newlen = len() - count;
|
||||
setLen(newlen);
|
||||
memmove(writeTo, wbuffer() + index + count, newlen - index);
|
||||
setLen(newlen);
|
||||
wbuffer()[newlen] = 0;
|
||||
}
|
||||
|
||||
@ -827,9 +826,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;
|
||||
}
|
||||
|
||||
|
@ -55,6 +55,10 @@ class String {
|
||||
// fails, the string will be marked as invalid (i.e. "if (s)" will
|
||||
// be false).
|
||||
String(const char *cstr = "");
|
||||
String(const char *cstr, unsigned int length);
|
||||
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
||||
String(const uint8_t *cstr, unsigned int length) : String((const char*)cstr, length) {}
|
||||
#endif
|
||||
String(const String &str);
|
||||
String(const __FlashStringHelper *str);
|
||||
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
||||
@ -108,6 +112,8 @@ class String {
|
||||
// concatenation is considered unsuccessful.
|
||||
unsigned char concat(const String &str);
|
||||
unsigned char concat(const char *cstr);
|
||||
unsigned char concat(const char *cstr, unsigned int length);
|
||||
unsigned char concat(const uint8_t *cstr, unsigned int length) {return concat((const char*)cstr, length);}
|
||||
unsigned char concat(char c);
|
||||
unsigned char concat(unsigned char c);
|
||||
unsigned char concat(int num);
|
||||
@ -281,8 +287,8 @@ class String {
|
||||
// Contains the string info when we're not in SSO mode
|
||||
struct _ptr {
|
||||
char * buff;
|
||||
uint16_t cap;
|
||||
uint16_t len;
|
||||
uint32_t cap;
|
||||
uint32_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
|
||||
@ -291,7 +297,11 @@ 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
|
||||
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
|
||||
#ifdef BOARD_HAS_PSRAM
|
||||
enum { CAPACITY_MAX = 3145728 };
|
||||
#else
|
||||
enum { CAPACITY_MAX = 65535 };
|
||||
#endif
|
||||
union {
|
||||
struct _ptr ptr;
|
||||
struct _sso sso;
|
||||
@ -301,9 +311,19 @@ 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; else ptr.len = len; }
|
||||
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 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
|
||||
@ -312,7 +332,6 @@ class String {
|
||||
void init(void);
|
||||
void invalidate(void);
|
||||
unsigned char changeBuffer(unsigned int maxStrLen);
|
||||
unsigned char concat(const char *cstr, unsigned int length);
|
||||
|
||||
// copy and move
|
||||
String & copy(const char *cstr, unsigned int length);
|
||||
|
@ -15,24 +15,70 @@
|
||||
#include "esp32-hal-adc.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_intr.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 uint8_t __analogAttenuation = 3;//11db
|
||||
static uint8_t __analogWidth = 3;//12 bits
|
||||
static uint8_t __analogClockDiv = 1;
|
||||
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
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_intr.h"
|
||||
#endif
|
||||
|
||||
static uint8_t __analogAttenuation = 3;//11db
|
||||
static uint8_t __analogWidth = ADC_WIDTH_MAX - 1; //3 for ESP32/ESP32C3; 4 for ESP32S2
|
||||
static uint8_t __analogReturnedWidth = SOC_ADC_MAX_BITWIDTH; //12 for ESP32/ESP32C3; 13 for ESP32S2
|
||||
static uint8_t __analogClockDiv = 1;
|
||||
static adc_attenuation_t __pin_attenuation[SOC_GPIO_PIN_COUNT];
|
||||
|
||||
static inline uint16_t mapResolution(uint16_t value)
|
||||
{
|
||||
uint8_t from = __analogWidth + 9;
|
||||
if (from == __analogReturnedWidth) {
|
||||
return value;
|
||||
}
|
||||
if (from > __analogReturnedWidth) {
|
||||
return value >> (from - __analogReturnedWidth);
|
||||
}
|
||||
return value << (__analogReturnedWidth - from);
|
||||
}
|
||||
|
||||
void __analogSetClockDiv(uint8_t clockDiv){
|
||||
if(!clockDiv){
|
||||
clockDiv = 1;
|
||||
}
|
||||
__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;
|
||||
@ -42,19 +88,7 @@ void __analogSetWidth(uint8_t bits){
|
||||
__analogWidth = bits - 9;
|
||||
adc1_config_width(__analogWidth);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
void __analogInit(){
|
||||
static bool initialized = false;
|
||||
@ -63,7 +97,12 @@ 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)
|
||||
@ -78,6 +117,9 @@ 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){
|
||||
@ -86,8 +128,10 @@ 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))
|
||||
@ -95,14 +139,18 @@ bool __adcAttachPin(uint8_t pin){
|
||||
| (1 << (pad + SENS_TOUCH_PAD_WORKEN_S)));
|
||||
WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG, touch);
|
||||
}
|
||||
} else if(pin == 25){
|
||||
#endif
|
||||
}
|
||||
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
|
||||
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, __analogAttenuation);
|
||||
__analogSetPinAttenuation(pin, (__pin_attenuation[pin] != ADC_ATTENDB_MAX)?__pin_attenuation[pin]:__analogAttenuation);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -111,7 +159,10 @@ 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)
|
||||
@ -128,25 +179,19 @@ uint16_t __analogRead(uint8_t pin)
|
||||
channel -= 10;
|
||||
r = adc2_get_raw( channel, __analogWidth, &value);
|
||||
if ( r == ESP_OK ) {
|
||||
return value;
|
||||
return mapResolution(value);
|
||||
} else if ( r == ESP_ERR_INVALID_STATE ) {
|
||||
log_e("GPIO%u: %s: ADC2 not initialized yet.", pin, esp_err_to_name(r));
|
||||
} else if ( r == ESP_ERR_TIMEOUT ) {
|
||||
log_e("GPIO%u: %s: ADC2 is in use by Wi-Fi.", pin, esp_err_to_name(r));
|
||||
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));
|
||||
} else {
|
||||
log_e("GPIO%u: %s", pin, esp_err_to_name(r));
|
||||
}
|
||||
} else {
|
||||
return adc1_get_raw(channel);
|
||||
value = adc1_get_raw(channel);
|
||||
return mapResolution(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void __analogSetVRefPin(uint8_t pin){
|
||||
if(pin <25 || pin > 27){
|
||||
pin = 0;
|
||||
}
|
||||
__analogVRefPin = pin;
|
||||
return mapResolution(value);
|
||||
}
|
||||
|
||||
uint32_t __analogReadMilliVolts(uint8_t pin){
|
||||
@ -155,6 +200,7 @@ 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");
|
||||
@ -168,7 +214,7 @@ uint32_t __analogReadMilliVolts(uint8_t pin){
|
||||
__analogVRef = DEFAULT_VREF;
|
||||
if(__analogVRefPin){
|
||||
esp_adc_cal_characteristics_t chars;
|
||||
if(adc2_vref_to_gpio(__analogVRefPin) == ESP_OK){
|
||||
if(adc_vref_to_gpio(ADC_UNIT_2, __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);
|
||||
@ -199,41 +245,50 @@ 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
|
||||
}
|
||||
|
||||
int __hallRead() //hall sensor without LNA
|
||||
{
|
||||
int Sens_Vp0;
|
||||
int Sens_Vn0;
|
||||
int Sens_Vp1;
|
||||
int Sens_Vn1;
|
||||
#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
|
||||
{
|
||||
pinMode(36, ANALOG);
|
||||
pinMode(39, ANALOG);
|
||||
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);
|
||||
__analogSetWidth(12);
|
||||
return hall_sensor_read();
|
||||
}
|
||||
#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 uint32_t analogReadMilliVolts(uint8_t pin) __attribute__ ((weak, alias("__analogReadMilliVolts")));
|
||||
extern void analogSetWidth(uint8_t bits) __attribute__ ((weak, alias("__analogSetWidth")));
|
||||
extern int hallRead() __attribute__ ((weak, alias("__hallRead")));
|
||||
#endif
|
||||
|
||||
|
@ -30,7 +30,8 @@ typedef enum {
|
||||
ADC_0db,
|
||||
ADC_2_5db,
|
||||
ADC_6db,
|
||||
ADC_11db
|
||||
ADC_11db,
|
||||
ADC_ATTENDB_MAX
|
||||
} adc_attenuation_t;
|
||||
|
||||
/*
|
||||
@ -38,6 +39,11 @@ 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.
|
||||
@ -47,13 +53,6 @@ uint16_t analogRead(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
|
||||
@ -73,26 +72,30 @@ 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 MilliVolts value for pin
|
||||
* Get value for HALL sensor (without LNA)
|
||||
* connected to pins 36(SVP) and 39(SVN)
|
||||
* */
|
||||
uint32_t analogReadMilliVolts(uint8_t pin);
|
||||
int hallRead();
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -18,11 +18,12 @@
|
||||
|
||||
bool btInUse(){ return true; }
|
||||
|
||||
#ifdef CONFIG_BLUEDROID_ENABLED
|
||||
#include "esp_bt.h"
|
||||
|
||||
#ifdef CONFIG_CLASSIC_BT_ENABLED
|
||||
#ifdef CONFIG_BTDM_CONTROLLER_MODE_BTDM
|
||||
#define BT_MODE ESP_BT_MODE_BTDM
|
||||
#elif defined(CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY)
|
||||
#define BT_MODE ESP_BT_MODE_CLASSIC_BT
|
||||
#else
|
||||
#define BT_MODE ESP_BT_MODE_BLE
|
||||
#endif
|
||||
@ -79,7 +80,7 @@ bool btStop(){
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
#else // CONFIG_BT_ENABLED
|
||||
bool btStarted()
|
||||
{
|
||||
return false;
|
||||
@ -94,6 +95,6 @@ bool btStop()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
|
||||
|
@ -16,17 +16,32 @@
|
||||
#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"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "rom/rtc.h"
|
||||
#include "soc/apb_ctrl_reg.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "esp32-hal.h"
|
||||
#include "esp32-hal-cpu.h"
|
||||
|
||||
#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
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/rtc.h"
|
||||
#endif
|
||||
|
||||
typedef struct apb_change_cb_s {
|
||||
struct apb_change_cb_s * prev;
|
||||
struct apb_change_cb_s * next;
|
||||
@ -34,7 +49,6 @@ 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;
|
||||
@ -130,10 +144,14 @@ 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
|
||||
@ -143,6 +161,7 @@ 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)){
|
||||
@ -154,6 +173,7 @@ 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);
|
||||
@ -162,6 +182,7 @@ 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
|
||||
@ -171,6 +192,7 @@ 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
|
||||
@ -204,8 +226,12 @@ 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);
|
||||
|
@ -12,43 +12,52 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "esp32-hal-dac.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_intr.h"
|
||||
#include "soc/rtc_io_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/sens_reg.h"
|
||||
#include "esp32-hal.h"
|
||||
|
||||
void IRAM_ATTR __dacWrite(uint8_t pin, uint8_t value)
|
||||
#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
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
|
||||
#ifndef NODAC
|
||||
#include "esp_attr.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/rtc_io_periph.h"
|
||||
#include "soc/sens_reg.h"
|
||||
#include "soc/sens_struct.h"
|
||||
#include "driver/dac.h"
|
||||
|
||||
void ARDUINO_ISR_ATTR __dacWrite(uint8_t pin, uint8_t value)
|
||||
{
|
||||
if(pin < 25 || pin > 26){
|
||||
if(pin < DAC1 || pin > DAC2){
|
||||
return;//not dac pin
|
||||
}
|
||||
pinMode(pin, ANALOG);
|
||||
uint8_t channel = pin - 25;
|
||||
|
||||
|
||||
//Disable Tone
|
||||
uint8_t channel = pin - DAC1;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_DAC_CTRL1_REG, SENS_SW_TONE_EN);
|
||||
|
||||
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);
|
||||
#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;
|
||||
}
|
||||
RTCIO.pad_dac[channel].dac = value;
|
||||
}
|
||||
|
||||
extern void dacWrite(uint8_t pin, uint8_t value) __attribute__ ((weak, alias("__dacWrite")));
|
||||
|
||||
#endif
|
||||
|
@ -13,20 +13,47 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include "esp32-hal-gpio.h"
|
||||
#include "pins_arduino.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_intr.h"
|
||||
#include "rom/gpio.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"
|
||||
|
||||
#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
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/ets_sys.h"
|
||||
#include "rom/gpio.h"
|
||||
#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[GPIO_PIN_COUNT]={
|
||||
const DRAM_ATTR esp32_gpioMux_t esp32_gpioMux[SOC_GPIO_PIN_COUNT]={
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
{0x44, 11, 11, 1},
|
||||
{0x88, -1, -1, -1},
|
||||
{0x40, 12, 12, 2},
|
||||
@ -67,6 +94,56 @@ const DRAM_ATTR esp32_gpioMux_t esp32_gpioMux[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);
|
||||
@ -76,56 +153,95 @@ typedef struct {
|
||||
void* arg;
|
||||
bool functional;
|
||||
} InterruptHandle_t;
|
||||
static InterruptHandle_t __pinInterruptHandlers[GPIO_PIN_COUNT] = {0,};
|
||||
static InterruptHandle_t __pinInterruptHandlers[SOC_GPIO_PIN_COUNT] = {0,};
|
||||
|
||||
#include "driver/rtc_io.h"
|
||||
|
||||
extern void IRAM_ATTR __pinMode(uint8_t pin, uint8_t mode)
|
||||
extern void ARDUINO_ISR_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;
|
||||
}
|
||||
|
||||
uint32_t rtc_reg = rtc_gpio_desc[pin].reg;
|
||||
int8_t rtc_io = esp32_gpioMux[pin].rtc;
|
||||
uint32_t rtc_reg = (rtc_io != -1)?rtc_io_desc[rtc_io].reg:0;
|
||||
if(mode == ANALOG) {
|
||||
if(!rtc_reg) {
|
||||
return;//not rtc pin
|
||||
}
|
||||
//lock rtc
|
||||
uint32_t reg_val = ESP_REG(rtc_reg);
|
||||
if(reg_val & rtc_gpio_desc[pin].mux){
|
||||
return;//already in adc mode
|
||||
#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);
|
||||
}
|
||||
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;
|
||||
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;
|
||||
return;
|
||||
}
|
||||
|
||||
//RTC pins PULL settings
|
||||
if(rtc_reg) {
|
||||
//lock rtc
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].mux);
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[rtc_io].mux);
|
||||
if(mode & PULLUP) {
|
||||
ESP_REG(rtc_reg) = (ESP_REG(rtc_reg) | rtc_gpio_desc[pin].pullup) & ~(rtc_gpio_desc[pin].pulldown);
|
||||
ESP_REG(rtc_reg) = (ESP_REG(rtc_reg) | rtc_io_desc[rtc_io].pullup) & ~(rtc_io_desc[rtc_io].pulldown);
|
||||
} else if(mode & PULLDOWN) {
|
||||
ESP_REG(rtc_reg) = (ESP_REG(rtc_reg) | rtc_gpio_desc[pin].pulldown) & ~(rtc_gpio_desc[pin].pullup);
|
||||
ESP_REG(rtc_reg) = (ESP_REG(rtc_reg) | rtc_io_desc[rtc_io].pulldown) & ~(rtc_io_desc[rtc_io].pullup);
|
||||
} else {
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown);
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[rtc_io].pullup | rtc_io_desc[rtc_io].pulldown);
|
||||
}
|
||||
//unlock rtc
|
||||
}
|
||||
|
||||
uint32_t pinFunction = 0, pinControl = 0;
|
||||
|
||||
//lock gpio
|
||||
if(mode & INPUT) {
|
||||
if(pin < 32) {
|
||||
GPIO.enable_w1tc = ((uint32_t)1 << pin);
|
||||
@ -133,9 +249,8 @@ extern void IRAM_ATTR __pinMode(uint8_t pin, uint8_t mode)
|
||||
GPIO.enable1_w1tc.val = ((uint32_t)1 << (pin - 32));
|
||||
}
|
||||
} else if(mode & OUTPUT) {
|
||||
if(pin > 33){
|
||||
//unlock gpio
|
||||
return;//pins above 33 can be only inputs
|
||||
if(pin >= NUM_OUPUT_PINS){
|
||||
return;
|
||||
} else if(pin < 32) {
|
||||
GPIO.enable_w1ts = ((uint32_t)1 << pin);
|
||||
} else {
|
||||
@ -153,9 +268,13 @@ extern void IRAM_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)2 << MCU_SEL_S);
|
||||
pinFunction |= ((uint32_t)PIN_FUNC_GPIO << MCU_SEL_S);
|
||||
} else if(mode == SPECIAL) {
|
||||
pinFunction |= ((uint32_t)(((pin)==1||(pin)==3)?0:1) << MCU_SEL_S);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
pinFunction |= ((uint32_t)(((pin)==RX||(pin)==TX)?0:1) << MCU_SEL_S);
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
pinFunction |= ((uint32_t)(((pin)==RX||(pin)==TX)?0:2) << MCU_SEL_S);
|
||||
#endif
|
||||
} else {
|
||||
pinFunction |= ((uint32_t)(mode >> 5) << MCU_SEL_S);
|
||||
}
|
||||
@ -167,39 +286,67 @@ extern void IRAM_ATTR __pinMode(uint8_t pin, uint8_t mode)
|
||||
}
|
||||
|
||||
GPIO.pin[pin].val = pinControl;
|
||||
//unlock gpio
|
||||
#endif
|
||||
}
|
||||
|
||||
extern void IRAM_ATTR __digitalWrite(uint8_t pin, uint8_t val)
|
||||
extern void ARDUINO_ISR_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 < 34) {
|
||||
} else if(pin < NUM_OUPUT_PINS) {
|
||||
GPIO.out1_w1ts.val = ((uint32_t)1 << (pin - 32));
|
||||
}
|
||||
} else {
|
||||
if(pin < 32) {
|
||||
GPIO.out_w1tc = ((uint32_t)1 << pin);
|
||||
} else if(pin < 34) {
|
||||
} else if(pin < NUM_OUPUT_PINS) {
|
||||
GPIO.out1_w1tc.val = ((uint32_t)1 << (pin - 32));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
extern int IRAM_ATTR __digitalRead(uint8_t pin)
|
||||
extern int ARDUINO_ISR_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 < 40) {
|
||||
} else if(pin < GPIO_PIN_COUNT) {
|
||||
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 IRAM_ATTR __onPinInterrupt()
|
||||
static void ARDUINO_ISR_ATTR __onPinInterrupt()
|
||||
{
|
||||
uint32_t gpio_intr_status_l=0;
|
||||
uint32_t gpio_intr_status_h=0;
|
||||
@ -238,6 +385,7 @@ static void IRAM_ATTR __onPinInterrupt()
|
||||
} while(++pin<GPIO_PIN_COUNT);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
extern void cleanupFunctional(void* arg);
|
||||
|
||||
@ -246,8 +394,17 @@ 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)ESP_INTR_FLAG_IRAM, __onPinInterrupt, NULL, &gpio_intr_handle);
|
||||
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;
|
||||
}
|
||||
|
||||
// if new attach without detach remove old info
|
||||
@ -259,14 +416,27 @@ 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)
|
||||
@ -280,7 +450,13 @@ 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);
|
||||
@ -289,9 +465,13 @@ 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
|
||||
}
|
||||
|
||||
|
||||
|
@ -25,6 +25,17 @@ 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
|
||||
@ -64,15 +75,15 @@ typedef struct {
|
||||
int8_t touch; /*!< Touch Channel number (-1 if not Touch pin) */
|
||||
} esp32_gpioMux_t;
|
||||
|
||||
extern const esp32_gpioMux_t esp32_gpioMux[40];
|
||||
extern const esp32_gpioMux_t esp32_gpioMux[SOC_GPIO_PIN_COUNT];
|
||||
extern const int8_t esp32_adc2gpio[20];
|
||||
|
||||
#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)
|
||||
#define digitalPinIsValid(pin) ((pin) < SOC_GPIO_PIN_COUNT && esp32_gpioMux[(pin)].reg)
|
||||
#define digitalPinCanOutput(pin) ((pin) < NUM_OUPUT_PINS && esp32_gpioMux[(pin)].reg)
|
||||
#define digitalPinToRtcPin(pin) (((pin) < SOC_GPIO_PIN_COUNT)?esp32_gpioMux[(pin)].rtc:-1)
|
||||
#define digitalPinToAnalogChannel(pin) (((pin) < SOC_GPIO_PIN_COUNT)?esp32_gpioMux[(pin)].adc:-1)
|
||||
#define digitalPinToTouchChannel(pin) (((pin) < SOC_GPIO_PIN_COUNT)?esp32_gpioMux[(pin)].touch:-1)
|
||||
#define digitalPinToDacChannel(pin) (((pin) == PIN_DAC1)?0:((pin) == PIN_DAC2)?1:-1)
|
||||
|
||||
void pinMode(uint8_t pin, uint8_t mode);
|
||||
void digitalWrite(uint8_t pin, uint8_t val);
|
||||
|
848
cores/esp32/esp32-hal-i2c-slave.c
Executable file
@ -0,0 +1,848 @@
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_attr.h"
|
||||
#include "rom/gpio.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "hal/gpio_types.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/ringbuf.h"
|
||||
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "soc/i2c_reg.h"
|
||||
#include "soc/i2c_struct.h"
|
||||
#include "hal/i2c_ll.h"
|
||||
#include "esp32-hal-log.h"
|
||||
#include "esp32-hal-i2c-slave.h"
|
||||
|
||||
#define I2C_SLAVE_USE_RX_QUEUE 0 // 1: Queue, 0: RingBuffer
|
||||
|
||||
#if SOC_I2C_NUM > 1
|
||||
#define I2C_SCL_IDX(p) ((p==0)?I2CEXT0_SCL_OUT_IDX:((p==1)?I2CEXT1_SCL_OUT_IDX:0))
|
||||
#define I2C_SDA_IDX(p) ((p==0)?I2CEXT0_SDA_OUT_IDX:((p==1)?I2CEXT1_SDA_OUT_IDX:0))
|
||||
#else
|
||||
#define I2C_SCL_IDX(p) I2CEXT0_SCL_OUT_IDX
|
||||
#define I2C_SDA_IDX(p) I2CEXT0_SDA_OUT_IDX
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define I2C_TXFIFO_WM_INT_ENA I2C_TXFIFO_EMPTY_INT_ENA
|
||||
#define I2C_RXFIFO_WM_INT_ENA I2C_RXFIFO_FULL_INT_ENA
|
||||
#endif
|
||||
|
||||
enum {
|
||||
I2C_SLAVE_EVT_RX, I2C_SLAVE_EVT_TX
|
||||
};
|
||||
|
||||
typedef struct i2c_slave_struct_t {
|
||||
i2c_dev_t * dev;
|
||||
uint8_t num;
|
||||
int8_t sda;
|
||||
int8_t scl;
|
||||
i2c_slave_request_cb_t request_callback;
|
||||
i2c_slave_receive_cb_t receive_callback;
|
||||
void * arg;
|
||||
intr_handle_t intr_handle;
|
||||
TaskHandle_t task_handle;
|
||||
xQueueHandle event_queue;
|
||||
#if I2C_SLAVE_USE_RX_QUEUE
|
||||
xQueueHandle rx_queue;
|
||||
#else
|
||||
RingbufHandle_t rx_ring_buf;
|
||||
#endif
|
||||
xQueueHandle tx_queue;
|
||||
uint32_t rx_data_count;
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
xSemaphoreHandle lock;
|
||||
#endif
|
||||
} i2c_slave_struct_t;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t event : 2;
|
||||
uint32_t stop : 1;
|
||||
uint32_t param : 29;
|
||||
};
|
||||
uint32_t val;
|
||||
} i2c_slave_queue_event_t;
|
||||
|
||||
static i2c_slave_struct_t _i2c_bus_array[SOC_I2C_NUM] = {
|
||||
{ &I2C0, 0, -1, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
, NULL
|
||||
#endif
|
||||
},
|
||||
#if SOC_I2C_NUM > 1
|
||||
{ &I2C1, 1, -1, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
, NULL
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#if CONFIG_DISABLE_HAL_LOCKS
|
||||
#define I2C_SLAVE_MUTEX_LOCK()
|
||||
#define I2C_SLAVE_MUTEX_UNLOCK()
|
||||
#else
|
||||
#define I2C_SLAVE_MUTEX_LOCK() if(i2c->lock){xSemaphoreTake(i2c->lock, portMAX_DELAY);}
|
||||
#define I2C_SLAVE_MUTEX_UNLOCK() if(i2c->lock){xSemaphoreGive(i2c->lock);}
|
||||
#endif
|
||||
|
||||
//-------------------------------------- HAL_LL (Missing Functions) ------------------------------------------------
|
||||
typedef enum {
|
||||
I2C_STRETCH_CAUSE_MASTER_READ,
|
||||
I2C_STRETCH_CAUSE_TX_FIFO_EMPTY,
|
||||
I2C_STRETCH_CAUSE_RX_FIFO_FULL,
|
||||
I2C_STRETCH_CAUSE_MAX
|
||||
} i2c_stretch_cause_t;
|
||||
|
||||
static inline i2c_stretch_cause_t i2c_ll_stretch_cause(i2c_dev_t *hw)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
return hw->sr.stretch_cause;
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
return hw->status_reg.stretch_cause;
|
||||
#else
|
||||
return I2C_STRETCH_CAUSE_MAX;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void i2c_ll_set_stretch(i2c_dev_t *hw, uint16_t time)
|
||||
{
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32
|
||||
typeof(hw->scl_stretch_conf) scl_stretch_conf;
|
||||
scl_stretch_conf.val = 0;
|
||||
scl_stretch_conf.slave_scl_stretch_en = (time > 0);
|
||||
scl_stretch_conf.stretch_protect_num = time;
|
||||
scl_stretch_conf.slave_scl_stretch_clr = 1;
|
||||
hw->scl_stretch_conf.val = scl_stretch_conf.val;
|
||||
if(time > 0){
|
||||
//enable interrupt
|
||||
hw->int_ena.val |= I2C_SLAVE_STRETCH_INT_ENA;
|
||||
} else {
|
||||
//disable interrupt
|
||||
hw->int_ena.val &= (~I2C_SLAVE_STRETCH_INT_ENA);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void i2c_ll_stretch_clr(i2c_dev_t *hw)
|
||||
{
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32
|
||||
hw->scl_stretch_conf.slave_scl_stretch_clr = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool i2c_ll_slave_addressed(i2c_dev_t *hw)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
return hw->sr.slave_addressed;
|
||||
#else
|
||||
return hw->status_reg.slave_addressed;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool i2c_ll_slave_rw(i2c_dev_t *hw)//not exposed by hal_ll
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
return hw->sr.slave_rw;
|
||||
#else
|
||||
return hw->status_reg.slave_rw;
|
||||
#endif
|
||||
}
|
||||
|
||||
//-------------------------------------- PRIVATE (Function Prototypes) ------------------------------------------------
|
||||
static void i2c_slave_free_resources(i2c_slave_struct_t * i2c);
|
||||
static void i2c_slave_delay_us(uint64_t us);
|
||||
static void i2c_slave_gpio_mode(int8_t pin, gpio_mode_t mode);
|
||||
static bool i2c_slave_check_line_state(int8_t sda, int8_t scl);
|
||||
static bool i2c_slave_attach_gpio(i2c_slave_struct_t * i2c, int8_t sda, int8_t scl);
|
||||
static bool i2c_slave_detach_gpio(i2c_slave_struct_t * i2c);
|
||||
static bool i2c_slave_set_frequency(i2c_slave_struct_t * i2c, uint32_t clk_speed);
|
||||
static bool i2c_slave_send_event(i2c_slave_struct_t * i2c, i2c_slave_queue_event_t* event);
|
||||
static bool i2c_slave_handle_tx_fifo_empty(i2c_slave_struct_t * i2c);
|
||||
static bool i2c_slave_handle_rx_fifo_full(i2c_slave_struct_t * i2c, uint32_t len);
|
||||
static size_t i2c_slave_read_rx(i2c_slave_struct_t * i2c, uint8_t * data, size_t len);
|
||||
static void i2c_slave_isr_handler(void* arg);
|
||||
static void i2c_slave_task(void *pv_args);
|
||||
|
||||
|
||||
//=====================================================================================================================
|
||||
//-------------------------------------- Public Functions -------------------------------------------------------------
|
||||
//=====================================================================================================================
|
||||
|
||||
esp_err_t i2cSlaveAttachCallbacks(uint8_t num, i2c_slave_request_cb_t request_callback, i2c_slave_receive_cb_t receive_callback, void * arg){
|
||||
if(num >= SOC_I2C_NUM){
|
||||
log_e("Invalid port num: %u", num);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
i2c_slave_struct_t * i2c = &_i2c_bus_array[num];
|
||||
I2C_SLAVE_MUTEX_LOCK();
|
||||
i2c->request_callback = request_callback;
|
||||
i2c->receive_callback = receive_callback;
|
||||
i2c->arg = arg;
|
||||
I2C_SLAVE_MUTEX_UNLOCK();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t frequency, size_t rx_len, size_t tx_len) {
|
||||
if(num >= SOC_I2C_NUM){
|
||||
log_e("Invalid port num: %u", num);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (sda < 0 || scl < 0) {
|
||||
log_e("invalid pins sda=%d, scl=%d", sda, scl);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if(!frequency){
|
||||
frequency = 100000;
|
||||
} else if(frequency > 1000000){
|
||||
frequency = 1000000;
|
||||
}
|
||||
|
||||
log_i("Initialising I2C Slave: sda=%d scl=%d freq=%d, addr=0x%x", sda, scl, frequency, slaveID);
|
||||
|
||||
i2c_slave_struct_t * i2c = &_i2c_bus_array[num];
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
if(!i2c->lock){
|
||||
i2c->lock = xSemaphoreCreateMutex();
|
||||
if (i2c->lock == NULL) {
|
||||
log_e("RX queue create failed");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
I2C_SLAVE_MUTEX_LOCK();
|
||||
i2c_slave_free_resources(i2c);
|
||||
|
||||
#if I2C_SLAVE_USE_RX_QUEUE
|
||||
i2c->rx_queue = xQueueCreate(rx_len, sizeof(uint8_t));
|
||||
if (i2c->rx_queue == NULL) {
|
||||
log_e("RX queue create failed");
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto fail;
|
||||
}
|
||||
#else
|
||||
i2c->rx_ring_buf = xRingbufferCreate(rx_len, RINGBUF_TYPE_BYTEBUF);
|
||||
if (i2c->rx_ring_buf == NULL) {
|
||||
log_e("RX RingBuf create failed");
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
|
||||
i2c->tx_queue = xQueueCreate(tx_len, sizeof(uint8_t));
|
||||
if (i2c->tx_queue == NULL) {
|
||||
log_e("TX queue create failed");
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
i2c->event_queue = xQueueCreate(16, sizeof(i2c_slave_queue_event_t));
|
||||
if (i2c->event_queue == NULL) {
|
||||
log_e("Event queue create failed");
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
xTaskCreate(i2c_slave_task, "i2c_slave_task", 4096, i2c, 20, &i2c->task_handle);
|
||||
if(i2c->task_handle == NULL){
|
||||
log_e("Event thread create failed");
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (frequency == 0) {
|
||||
frequency = 100000L;
|
||||
}
|
||||
frequency = (frequency * 5) / 4;
|
||||
|
||||
if (i2c->num == 0) {
|
||||
periph_module_enable(PERIPH_I2C0_MODULE);
|
||||
#if SOC_I2C_NUM > 1
|
||||
} else {
|
||||
periph_module_enable(PERIPH_I2C1_MODULE);
|
||||
#endif
|
||||
}
|
||||
|
||||
i2c_ll_slave_init(i2c->dev);
|
||||
i2c_ll_set_fifo_mode(i2c->dev, true);
|
||||
i2c_ll_set_slave_addr(i2c->dev, slaveID, false);
|
||||
i2c_ll_set_tout(i2c->dev, 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);
|
||||
}
|
35
cores/esp32/esp32-hal-i2c-slave.h
Executable file
@ -0,0 +1,35 @@
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "stdint.h"
|
||||
#include "stddef.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
typedef void (*i2c_slave_request_cb_t) (uint8_t num, void * arg);
|
||||
typedef void (*i2c_slave_receive_cb_t) (uint8_t num, uint8_t * data, size_t len, bool stop, void * arg);
|
||||
esp_err_t i2cSlaveAttachCallbacks(uint8_t num, i2c_slave_request_cb_t request_callback, i2c_slave_receive_cb_t receive_callback, void * arg);
|
||||
|
||||
esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t frequency, size_t rx_len, size_t tx_len);
|
||||
esp_err_t i2cSlaveDeinit(uint8_t num);
|
||||
size_t i2cSlaveWrite(uint8_t num, const uint8_t *buf, uint32_t len, uint32_t timeout_ms);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -12,6 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// modified Nov 2017 by Chuck Todd <StickBreaker> to support Interrupt Driven I/O
|
||||
// modified Nov 2021 by Hristo Gochkov <Me-No-Dev> to support ESP-IDF API
|
||||
|
||||
#ifndef _ESP32_HAL_I2C_H_
|
||||
#define _ESP32_HAL_I2C_H_
|
||||
@ -22,58 +23,16 @@ extern "C" {
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include <esp_err.h>
|
||||
|
||||
// External Wire.h equivalent error Codes
|
||||
typedef enum {
|
||||
I2C_ERROR_OK=0,
|
||||
I2C_ERROR_DEV,
|
||||
I2C_ERROR_ACK,
|
||||
I2C_ERROR_TIMEOUT,
|
||||
I2C_ERROR_BUS,
|
||||
I2C_ERROR_BUSY,
|
||||
I2C_ERROR_MEMORY,
|
||||
I2C_ERROR_CONTINUE,
|
||||
I2C_ERROR_NO_BEGIN
|
||||
} i2c_err_t;
|
||||
|
||||
struct i2c_struct_t;
|
||||
typedef struct i2c_struct_t i2c_t;
|
||||
|
||||
i2c_t * i2cInit(uint8_t i2c_num, int8_t sda, int8_t scl, uint32_t clk_speed);
|
||||
void i2cRelease(i2c_t *i2c); // free ISR, Free DQ, Power off peripheral clock. Must call i2cInit() to recover
|
||||
i2c_err_t i2cWrite(i2c_t * i2c, uint16_t address, uint8_t* buff, uint16_t size, bool sendStop, uint16_t timeOutMillis);
|
||||
i2c_err_t i2cRead(i2c_t * i2c, uint16_t address, uint8_t* buff, uint16_t size, bool sendStop, uint16_t timeOutMillis, uint32_t *readCount);
|
||||
i2c_err_t i2cFlush(i2c_t *i2c);
|
||||
i2c_err_t i2cSetFrequency(i2c_t * i2c, uint32_t clk_speed);
|
||||
uint32_t i2cGetFrequency(i2c_t * i2c);
|
||||
uint32_t i2cGetStatus(i2c_t * i2c); // Status register of peripheral
|
||||
|
||||
//Functions below should be used only if well understood
|
||||
//Might be deprecated and removed in future
|
||||
i2c_err_t i2cAttachSCL(i2c_t * i2c, int8_t scl);
|
||||
i2c_err_t i2cDetachSCL(i2c_t * i2c, int8_t scl);
|
||||
i2c_err_t i2cAttachSDA(i2c_t * i2c, int8_t sda);
|
||||
i2c_err_t i2cDetachSDA(i2c_t * i2c, int8_t sda);
|
||||
|
||||
//Stickbreakers ISR Support
|
||||
i2c_err_t i2cProcQueue(i2c_t *i2c, uint32_t *readCount, uint16_t timeOutMillis);
|
||||
i2c_err_t i2cAddQueueWrite(i2c_t *i2c, uint16_t i2cDeviceAddr, uint8_t *dataPtr, uint16_t dataLen, bool SendStop, EventGroupHandle_t event);
|
||||
i2c_err_t i2cAddQueueRead(i2c_t *i2c, uint16_t i2cDeviceAddr, uint8_t *dataPtr, uint16_t dataLen, bool SendStop, EventGroupHandle_t event);
|
||||
|
||||
//stickbreaker debug support
|
||||
uint32_t i2cDebug(i2c_t *, uint32_t setBits, uint32_t resetBits);
|
||||
// Debug actions have 3 currently defined locus
|
||||
// 0xXX------ : at entry of ProcQueue
|
||||
// 0x--XX---- : at exit of ProcQueue
|
||||
// 0x------XX : at entry of Flush
|
||||
//
|
||||
// bit 0 causes DumpI2c to execute
|
||||
// bit 1 causes DumpInts to execute
|
||||
// bit 2 causes DumpCmdqueue to execute
|
||||
// bit 3 causes DumpStatus to execute
|
||||
// bit 4 causes DumpFifo to execute
|
||||
esp_err_t i2cInit(uint8_t i2c_num, int8_t sda, int8_t scl, uint32_t clk_speed);
|
||||
esp_err_t i2cDeinit(uint8_t i2c_num);
|
||||
esp_err_t i2cSetClock(uint8_t i2c_num, uint32_t frequency);
|
||||
esp_err_t i2cGetClock(uint8_t i2c_num, uint32_t * frequency);
|
||||
esp_err_t i2cWrite(uint8_t i2c_num, uint16_t address, const uint8_t* buff, size_t size, uint32_t timeOutMillis);
|
||||
esp_err_t i2cRead(uint8_t i2c_num, uint16_t address, uint8_t* buff, size_t size, uint32_t timeOutMillis, size_t *readCount);
|
||||
esp_err_t i2cWriteReadNonStop(uint8_t i2c_num, uint16_t address, const uint8_t* wbuff, size_t wsize, uint8_t* rbuff, size_t rsize, uint32_t timeOutMillis, size_t *readCount);
|
||||
bool i2cIsInit(uint8_t i2c_num);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -16,11 +16,32 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp32-hal-matrix.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
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/ets_sys.h"
|
||||
#endif
|
||||
|
||||
#if CONFIG_DISABLE_HAL_LOCKS
|
||||
#define LEDC_MUTEX_LOCK()
|
||||
@ -94,10 +115,13 @@ 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;
|
||||
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);
|
||||
periph_module_enable(PERIPH_LEDC_MODULE);
|
||||
LEDC.conf.apb_clk_sel = 1;//LS use apb clock
|
||||
addApbChangeCallback((void*)&_activeChannels, _on_apb_change);
|
||||
|
||||
@ -109,9 +133,13 @@ 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;
|
||||
@ -176,17 +204,21 @@ 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 > 15) {
|
||||
if(chan > LAST_CHAN) {
|
||||
return 0;
|
||||
}
|
||||
double res_freq = _ledcSetupTimerFreq(chan, freq, bit_num);
|
||||
@ -196,7 +228,7 @@ double ledcSetup(uint8_t chan, double freq, uint8_t bit_num)
|
||||
|
||||
void ledcWrite(uint8_t chan, uint32_t duty)
|
||||
{
|
||||
if(chan > 15) {
|
||||
if(chan > LAST_CHAN) {
|
||||
return;
|
||||
}
|
||||
uint8_t group=(chan/8), channel=(chan%8);
|
||||
@ -205,26 +237,34 @@ 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 > 15) {
|
||||
if(chan > LAST_CHAN) {
|
||||
return 0;
|
||||
}
|
||||
return LEDC.channel_group[chan/8].channel[chan%8].duty.duty >> 4;
|
||||
@ -240,7 +280,7 @@ double ledcReadFreq(uint8_t chan)
|
||||
|
||||
double ledcWriteTone(uint8_t chan, double freq)
|
||||
{
|
||||
if(chan > 15) {
|
||||
if(chan > LAST_CHAN) {
|
||||
return 0;
|
||||
}
|
||||
if(!freq) {
|
||||
@ -267,14 +307,27 @@ double ledcWriteNote(uint8_t chan, note_t note, uint8_t octave){
|
||||
|
||||
void ledcAttachPin(uint8_t pin, uint8_t chan)
|
||||
{
|
||||
if(chan > 15) {
|
||||
if(chan > LAST_CHAN) {
|
||||
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;
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ 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
|
||||
|
@ -20,6 +20,7 @@ extern "C"
|
||||
#endif
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_timer.h"
|
||||
|
||||
#define ARDUHAL_LOG_LEVEL_NONE (0)
|
||||
#define ARDUHAL_LOG_LEVEL_ERROR (1)
|
||||
@ -36,6 +37,9 @@ 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
|
||||
@ -62,6 +66,8 @@ extern "C"
|
||||
#define ARDUHAL_LOG_COLOR_I ARDUHAL_LOG_COLOR(ARDUHAL_LOG_COLOR_GREEN)
|
||||
#define ARDUHAL_LOG_COLOR_D ARDUHAL_LOG_COLOR(ARDUHAL_LOG_COLOR_CYAN)
|
||||
#define ARDUHAL_LOG_COLOR_V ARDUHAL_LOG_COLOR(ARDUHAL_LOG_COLOR_GRAY)
|
||||
#define ARDUHAL_LOG_COLOR_PRINT(letter) log_printf(ARDUHAL_LOG_COLOR_ ## letter)
|
||||
#define ARDUHAL_LOG_COLOR_PRINT_END log_printf(ARDUHAL_LOG_RESET_COLOR)
|
||||
#else
|
||||
#define ARDUHAL_LOG_COLOR_E
|
||||
#define ARDUHAL_LOG_COLOR_W
|
||||
@ -69,64 +75,123 @@ 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 "[" #letter "][%s:%u] %s(): " format ARDUHAL_LOG_RESET_COLOR "\r\n", pathToFileName(__FILE__), __LINE__, __FUNCTION__
|
||||
#define ARDUHAL_LOG_FORMAT(letter, format) ARDUHAL_LOG_COLOR_ ## letter "[%6u][" #letter "][%s:%u] %s(): " format ARDUHAL_LOG_RESET_COLOR "\r\n", (unsigned long) (esp_timer_get_time() / 1000ULL), pathToFileName(__FILE__), __LINE__, __FUNCTION__
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
|
||||
#ifndef USE_ESP_IDF_LOG
|
||||
#define log_v(format, ...) log_printf(ARDUHAL_LOG_FORMAT(V, format), ##__VA_ARGS__)
|
||||
#define isr_log_v(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(V, format), ##__VA_ARGS__)
|
||||
#define log_buf_v(b,l) do{ARDUHAL_LOG_COLOR_PRINT(V);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0)
|
||||
#else
|
||||
#define log_v(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_VERBOSE, TAG, format, ##__VA_ARGS__);}while(0)
|
||||
#define isr_log_v(format, ...) do {ets_printf(LOG_FORMAT(V, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0)
|
||||
#define log_buf_v(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_VERBOSE);}while(0)
|
||||
#endif
|
||||
#else
|
||||
#define log_v(format, ...)
|
||||
#define isr_log_v(format, ...)
|
||||
#define log_buf_v(b,l)
|
||||
#endif
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
|
||||
#ifndef USE_ESP_IDF_LOG
|
||||
#define log_d(format, ...) log_printf(ARDUHAL_LOG_FORMAT(D, format), ##__VA_ARGS__)
|
||||
#define isr_log_d(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(D, format), ##__VA_ARGS__)
|
||||
#define log_buf_d(b,l) do{ARDUHAL_LOG_COLOR_PRINT(D);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0)
|
||||
#else
|
||||
#define log_d(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_DEBUG, TAG, format, ##__VA_ARGS__);}while(0)
|
||||
#define isr_log_d(format, ...) do {ets_printf(LOG_FORMAT(D, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0)
|
||||
#define log_buf_d(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_DEBUG);}while(0)
|
||||
#endif
|
||||
#else
|
||||
#define log_d(format, ...)
|
||||
#define isr_log_d(format, ...)
|
||||
#define log_buf_d(b,l)
|
||||
#endif
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
#ifndef USE_ESP_IDF_LOG
|
||||
#define log_i(format, ...) log_printf(ARDUHAL_LOG_FORMAT(I, format), ##__VA_ARGS__)
|
||||
#define isr_log_i(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(I, format), ##__VA_ARGS__)
|
||||
#define log_buf_i(b,l) do{ARDUHAL_LOG_COLOR_PRINT(I);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0)
|
||||
#else
|
||||
#define log_i(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_INFO, TAG, format, ##__VA_ARGS__);}while(0)
|
||||
#define isr_log_i(format, ...) do {ets_printf(LOG_FORMAT(I, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0)
|
||||
#define log_buf_i(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_INFO);}while(0)
|
||||
#endif
|
||||
#else
|
||||
#define log_i(format, ...)
|
||||
#define isr_log_i(format, ...)
|
||||
#define log_buf_i(b,l)
|
||||
#endif
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_WARN
|
||||
#ifndef USE_ESP_IDF_LOG
|
||||
#define log_w(format, ...) log_printf(ARDUHAL_LOG_FORMAT(W, format), ##__VA_ARGS__)
|
||||
#define isr_log_w(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(W, format), ##__VA_ARGS__)
|
||||
#define log_buf_w(b,l) do{ARDUHAL_LOG_COLOR_PRINT(W);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0)
|
||||
#else
|
||||
#define log_w(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_WARN, TAG, format, ##__VA_ARGS__);}while(0)
|
||||
#define isr_log_w(format, ...) do {ets_printf(LOG_FORMAT(W, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0)
|
||||
#define log_buf_w(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_WARN);}while(0)
|
||||
#endif
|
||||
#else
|
||||
#define log_w(format, ...)
|
||||
#define isr_log_w(format, ...)
|
||||
#define log_buf_w(b,l)
|
||||
#endif
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
|
||||
#ifndef USE_ESP_IDF_LOG
|
||||
#define log_e(format, ...) log_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__)
|
||||
#define isr_log_e(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__)
|
||||
#define log_buf_e(b,l) do{ARDUHAL_LOG_COLOR_PRINT(E);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0)
|
||||
#else
|
||||
#define log_e(format, ...) do {log_to_esp(TAG, ESP_LOG_ERROR, format, ##__VA_ARGS__);}while(0)
|
||||
#define isr_log_e(format, ...) do {ets_printf(LOG_FORMAT(E, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0)
|
||||
#define log_buf_e(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_ERROR);}while(0)
|
||||
#endif
|
||||
#else
|
||||
#define log_e(format, ...)
|
||||
#define isr_log_e(format, ...)
|
||||
#define log_buf_e(b,l)
|
||||
#endif
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_NONE
|
||||
#ifndef USE_ESP_IDF_LOG
|
||||
#define log_n(format, ...) log_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__)
|
||||
#define isr_log_n(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__)
|
||||
#define log_buf_n(b,l) do{ARDUHAL_LOG_COLOR_PRINT(E);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0)
|
||||
#else
|
||||
#define log_n(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_ERROR, TAG, format, ##__VA_ARGS__);}while(0)
|
||||
#define isr_log_n(format, ...) do {ets_printf(LOG_FORMAT(E, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0)
|
||||
#define log_buf_n(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_ERROR);}while(0)
|
||||
#endif
|
||||
#else
|
||||
#define log_n(format, ...)
|
||||
#define isr_log_n(format, ...)
|
||||
#define log_buf_n(b,l)
|
||||
#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
|
||||
@ -150,6 +215,7 @@ int log_printf(const char *fmt, ...);
|
||||
#define ESP_EARLY_LOGD(tag, ...) isr_log_d(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGV(tag, ...) isr_log_v(__VA_ARGS__)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -14,33 +14,47 @@
|
||||
|
||||
#include "esp32-hal-matrix.h"
|
||||
#include "esp_attr.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#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
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/gpio.h"
|
||||
#endif
|
||||
|
||||
#define MATRIX_DETACH_OUT_SIG 0x100
|
||||
#define MATRIX_DETACH_IN_LOW_PIN 0x30
|
||||
#define MATRIX_DETACH_IN_LOW_HIGH 0x38
|
||||
|
||||
void IRAM_ATTR pinMatrixOutAttach(uint8_t pin, uint8_t function, bool invertOut, bool invertEnable)
|
||||
void ARDUINO_ISR_ATTR pinMatrixOutAttach(uint8_t pin, uint8_t function, bool invertOut, bool invertEnable)
|
||||
{
|
||||
gpio_matrix_out(pin, function, invertOut, invertEnable);
|
||||
}
|
||||
|
||||
void IRAM_ATTR pinMatrixOutDetach(uint8_t pin, bool invertOut, bool invertEnable)
|
||||
void ARDUINO_ISR_ATTR pinMatrixOutDetach(uint8_t pin, bool invertOut, bool invertEnable)
|
||||
{
|
||||
gpio_matrix_out(pin, MATRIX_DETACH_OUT_SIG, invertOut, invertEnable);
|
||||
}
|
||||
|
||||
void IRAM_ATTR pinMatrixInAttach(uint8_t pin, uint8_t signal, bool inverted)
|
||||
void ARDUINO_ISR_ATTR pinMatrixInAttach(uint8_t pin, uint8_t signal, bool inverted)
|
||||
{
|
||||
gpio_matrix_in(pin, signal, inverted);
|
||||
}
|
||||
|
||||
void IRAM_ATTR pinMatrixInDetach(uint8_t signal, bool high, bool inverted)
|
||||
void ARDUINO_ISR_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 IRAM_ATTR intrMatrixAttach(uint32_t source, uint32_t inum){
|
||||
void ARDUINO_ISR_ATTR intrMatrixAttach(uint32_t source, uint32_t inum){
|
||||
intr_matrix_set(PRO_CPU_NUM, source, inum);
|
||||
}
|
||||
*/
|
||||
|
@ -31,18 +31,47 @@
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/apb_ctrl_reg.h"
|
||||
#include "rom/rtc.h"
|
||||
#include "esp_task_wdt.h"
|
||||
#include "esp32-hal.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#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
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/rtc.h"
|
||||
#endif
|
||||
|
||||
//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()
|
||||
{
|
||||
@ -131,12 +160,12 @@ BaseType_t xTaskCreateUniversal( TaskFunction_t pxTaskCode,
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned long IRAM_ATTR micros()
|
||||
unsigned long ARDUINO_ISR_ATTR micros()
|
||||
{
|
||||
return (unsigned long) (esp_timer_get_time());
|
||||
}
|
||||
|
||||
unsigned long IRAM_ATTR millis()
|
||||
unsigned long ARDUINO_ISR_ATTR millis()
|
||||
{
|
||||
return (unsigned long) (esp_timer_get_time() / 1000ULL);
|
||||
}
|
||||
@ -146,17 +175,17 @@ void delay(uint32_t ms)
|
||||
vTaskDelay(ms / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
void IRAM_ATTR delayMicroseconds(uint32_t us)
|
||||
void ARDUINO_ISR_ATTR delayMicroseconds(uint32_t us)
|
||||
{
|
||||
uint32_t m = micros();
|
||||
uint64_t m = (uint64_t)esp_timer_get_time();
|
||||
if(us){
|
||||
uint32_t e = (m + us);
|
||||
uint64_t e = (m + us);
|
||||
if(m > e){ //overflow
|
||||
while(micros() > e){
|
||||
while((uint64_t)esp_timer_get_time() > e){
|
||||
NOP();
|
||||
}
|
||||
}
|
||||
while(micros() < e){
|
||||
while((uint64_t)esp_timer_get_time() < e){
|
||||
NOP();
|
||||
}
|
||||
}
|
||||
@ -198,7 +227,7 @@ void initArduino()
|
||||
#ifdef F_CPU
|
||||
setCpuFrequencyMhz(F_CPU/1000000);
|
||||
#endif
|
||||
#if CONFIG_SPIRAM_SUPPORT
|
||||
#if CONFIG_SPIRAM_SUPPORT || CONFIG_SPIRAM
|
||||
psramInit();
|
||||
#endif
|
||||
esp_log_level_set("*", CONFIG_LOG_DEFAULT_LEVEL);
|
||||
@ -227,7 +256,7 @@ void initArduino()
|
||||
}
|
||||
|
||||
//used by hal log
|
||||
const char * IRAM_ATTR pathToFileName(const char * path)
|
||||
const char * ARDUINO_ISR_ATTR pathToFileName(const char * path)
|
||||
{
|
||||
size_t i = 0;
|
||||
size_t pos = 0;
|
||||
|
@ -1,11 +1,37 @@
|
||||
// Copyright 2015-2016 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 "esp32-hal.h"
|
||||
|
||||
#if CONFIG_SPIRAM_SUPPORT
|
||||
#include "esp_spiram.h"
|
||||
#if CONFIG_SPIRAM_SUPPORT || CONFIG_SPIRAM
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#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
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "esp_spiram.h"
|
||||
#endif
|
||||
|
||||
static volatile bool spiramDetected = false;
|
||||
static volatile bool spiramFailed = false;
|
||||
|
||||
@ -17,6 +43,7 @@ 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) {
|
||||
@ -24,14 +51,21 @@ bool psramInit(){
|
||||
log_w("PSRAM not supported!");
|
||||
return false;
|
||||
}
|
||||
esp_spiram_init_cache();
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
extern void esp_config_data_cache_mode(void);
|
||||
esp_config_data_cache_mode();
|
||||
Cache_Enable_DCache(0);
|
||||
#endif
|
||||
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!");
|
||||
@ -42,31 +76,34 @@ 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 IRAM_ATTR psramFound(){
|
||||
bool ARDUINO_ISR_ATTR psramFound(){
|
||||
return spiramDetected;
|
||||
}
|
||||
|
||||
void IRAM_ATTR *ps_malloc(size_t size){
|
||||
void ARDUINO_ISR_ATTR *ps_malloc(size_t size){
|
||||
if(!spiramDetected){
|
||||
return NULL;
|
||||
}
|
||||
return heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
}
|
||||
|
||||
void IRAM_ATTR *ps_calloc(size_t n, size_t size){
|
||||
void ARDUINO_ISR_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 IRAM_ATTR *ps_realloc(void *ptr, size_t size){
|
||||
void ARDUINO_ISR_ATTR *ps_realloc(void *ptr, size_t size){
|
||||
if(!spiramDetected){
|
||||
return NULL;
|
||||
}
|
||||
@ -79,19 +116,19 @@ bool psramInit(){
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IRAM_ATTR psramFound(){
|
||||
bool ARDUINO_ISR_ATTR psramFound(){
|
||||
return false;
|
||||
}
|
||||
|
||||
void IRAM_ATTR *ps_malloc(size_t size){
|
||||
void ARDUINO_ISR_ATTR *ps_malloc(size_t size){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void IRAM_ATTR *ps_calloc(size_t n, size_t size){
|
||||
void ARDUINO_ISR_ATTR *ps_calloc(size_t n, size_t size){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void IRAM_ATTR *ps_realloc(void *ptr, size_t size){
|
||||
void ARDUINO_ISR_ATTR *ps_realloc(void *ptr, size_t size){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,17 @@
|
||||
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();
|
||||
|
||||
|
@ -19,22 +19,36 @@
|
||||
#include "esp32-hal.h"
|
||||
#include "esp8266-compat.h"
|
||||
#include "soc/gpio_reg.h"
|
||||
#include "soc/gpio_reg.h"
|
||||
|
||||
#include "esp32-hal-rmt.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
|
||||
#include "soc/rmt_struct.h"
|
||||
#include "driver/periph_ctrl.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)
|
||||
@ -44,6 +58,7 @@
|
||||
#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)
|
||||
@ -53,7 +68,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);
|
||||
@ -101,7 +116,10 @@ struct rmt_obj_s
|
||||
* Internal variables for channel descriptors
|
||||
*/
|
||||
static xSemaphoreHandle g_rmt_objlocks[MAX_CHANNELS] = {
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
|
||||
NULL, NULL, NULL, NULL,
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
NULL, NULL, NULL, NULL
|
||||
#endif
|
||||
};
|
||||
|
||||
static rmt_obj_t g_rmt_objects[MAX_CHANNELS] = {
|
||||
@ -109,10 +127,12 @@ 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},
|
||||
#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
|
||||
};
|
||||
|
||||
/**
|
||||
@ -131,17 +151,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 IRAM_ATTR _rmt_isr(void* arg);
|
||||
static void ARDUINO_ISR_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 IRAM_ATTR _rmt_get_mem_len(uint8_t channel);
|
||||
static int ARDUINO_ISR_ATTR _rmt_get_mem_len(uint8_t channel);
|
||||
|
||||
static void IRAM_ATTR _rmt_tx_mem_first(uint8_t ch);
|
||||
static void ARDUINO_ISR_ATTR _rmt_tx_mem_first(uint8_t ch);
|
||||
|
||||
static void IRAM_ATTR _rmt_tx_mem_second(uint8_t ch);
|
||||
static void ARDUINO_ISR_ATTR _rmt_tx_mem_second(uint8_t ch);
|
||||
|
||||
|
||||
/**
|
||||
@ -155,12 +175,17 @@ 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;
|
||||
@ -176,8 +201,13 @@ 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);
|
||||
|
||||
@ -193,7 +223,11 @@ 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;
|
||||
@ -241,7 +275,6 @@ bool rmtLoop(rmt_obj_t* rmt, rmt_data_t* data, size_t size)
|
||||
return false;
|
||||
}
|
||||
|
||||
int channel = rmt->channel;
|
||||
int allocated_size = MAX_DATA_PER_CHANNEL * rmt->buffers;
|
||||
|
||||
if (size > allocated_size) {
|
||||
@ -259,13 +292,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) {
|
||||
if (size > (allocated_size - 1)) {
|
||||
|
||||
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)ESP_INTR_FLAG_IRAM, _rmt_isr, NULL, &intr_handle);
|
||||
esp_intr_alloc(ETS_RMT_INTR_SOURCE, (int)ARDUINO_ISR_FLAG, _rmt_isr, NULL, &intr_handle);
|
||||
}
|
||||
|
||||
rmt->data_size = size - MAX_DATA_PER_ITTERATION;
|
||||
@ -273,6 +306,18 @@ 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
|
||||
@ -282,9 +327,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);
|
||||
@ -298,6 +343,7 @@ 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
|
||||
@ -336,10 +382,15 @@ 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;
|
||||
}
|
||||
|
||||
@ -378,17 +429,26 @@ 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;
|
||||
@ -401,7 +461,11 @@ bool rmtEnd(rmt_obj_t* rmt) {
|
||||
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;
|
||||
@ -431,7 +495,11 @@ 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);
|
||||
@ -439,9 +507,15 @@ 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
|
||||
@ -468,14 +542,20 @@ 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.0, 256);
|
||||
float apb_tick = 25.0 * 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.5, 256);
|
||||
int ref_div = _LIMIT(tick/1000, 256);
|
||||
float apb_tick = 12.5 * apb_div;
|
||||
float ref_tick = 1000.0 * 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;
|
||||
@ -485,6 +565,7 @@ 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)
|
||||
@ -547,16 +628,62 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize)
|
||||
// - 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
|
||||
@ -574,10 +701,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)ESP_INTR_FLAG_IRAM, _rmt_isr, NULL, &intr_handle);
|
||||
esp_intr_alloc(ETS_RMT_INTR_SOURCE, (int)ARDUINO_ISR_FLAG, _rmt_isr, NULL, &intr_handle);
|
||||
}
|
||||
RMT_MUTEX_UNLOCK(channel);
|
||||
|
||||
@ -593,7 +720,11 @@ 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);
|
||||
@ -605,9 +736,15 @@ 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;
|
||||
@ -632,6 +769,7 @@ 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) {
|
||||
@ -645,8 +783,9 @@ static void _initPin(int pin, int channel, bool tx_not_rx)
|
||||
}
|
||||
|
||||
|
||||
static void IRAM_ATTR _rmt_isr(void* arg)
|
||||
static void ARDUINO_ISR_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++) {
|
||||
@ -681,9 +820,15 @@ static void IRAM_ATTR _rmt_isr(void* arg)
|
||||
(g_rmt_objects[ch].cb)(data_received, _rmt_get_mem_len(ch), g_rmt_objects[ch].arg);
|
||||
|
||||
// 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
|
||||
@ -709,10 +854,17 @@ static void IRAM_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)) {
|
||||
@ -724,32 +876,50 @@ static void IRAM_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 IRAM_ATTR _rmt_tx_mem_second(uint8_t ch)
|
||||
static void ARDUINO_ISR_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++) {
|
||||
@ -768,17 +938,30 @@ static void IRAM_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 {
|
||||
log_d("RMT Tx finished %d!\n", ch);
|
||||
//ets_printf("RMT Tx finished %d!\n", ch);
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
RMT.tx_conf[ch].tx_conti_mode = 0;
|
||||
#else
|
||||
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;
|
||||
@ -787,17 +970,22 @@ static void IRAM_ATTR _rmt_tx_mem_second(uint8_t ch)
|
||||
DEBUG_INTERRUPT_END(4);
|
||||
}
|
||||
|
||||
static void IRAM_ATTR _rmt_tx_mem_first(uint8_t ch)
|
||||
static void ARDUINO_ISR_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) {
|
||||
@ -808,7 +996,11 @@ static void IRAM_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 {
|
||||
@ -825,23 +1017,37 @@ static void IRAM_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 IRAM_ATTR _rmt_get_mem_len(uint8_t channel)
|
||||
static int ARDUINO_ISR_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++) {
|
||||
|
@ -16,11 +16,25 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp32-hal-matrix.h"
|
||||
#include "soc/gpio_sd_reg.h"
|
||||
#include "soc/gpio_sd_struct.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/ets_sys.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/ets_sys.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#include "esp32c3/rom/ets_sys.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/ets_sys.h"
|
||||
#endif
|
||||
|
||||
|
||||
#if CONFIG_DISABLE_HAL_LOCKS
|
||||
#define SD_MUTEX_LOCK()
|
||||
@ -69,6 +83,9 @@ 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;
|
||||
|
@ -17,28 +17,38 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_intr.h"
|
||||
#include "rom/gpio.h"
|
||||
#include "soc/spi_reg.h"
|
||||
#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"
|
||||
|
||||
#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))))
|
||||
#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
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/ets_sys.h"
|
||||
#include "rom/gpio.h"
|
||||
#include "esp_intr.h"
|
||||
#endif
|
||||
|
||||
struct spi_struct_t {
|
||||
spi_dev_t * dev;
|
||||
@ -48,25 +58,84 @@ 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[4] = {
|
||||
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
|
||||
{(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[4] = {
|
||||
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
|
||||
{(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
|
||||
|
||||
@ -76,6 +145,14 @@ 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) {
|
||||
@ -83,6 +160,10 @@ 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);
|
||||
@ -94,6 +175,14 @@ 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) {
|
||||
@ -101,6 +190,10 @@ 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);
|
||||
@ -114,6 +207,14 @@ 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) {
|
||||
@ -121,6 +222,10 @@ 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);
|
||||
@ -132,6 +237,14 @@ 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) {
|
||||
@ -139,6 +252,10 @@ 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);
|
||||
@ -150,6 +267,14 @@ 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) {
|
||||
@ -157,6 +282,10 @@ 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);
|
||||
@ -168,6 +297,14 @@ 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) {
|
||||
@ -175,6 +312,10 @@ 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);
|
||||
@ -190,6 +331,14 @@ 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) {
|
||||
@ -197,6 +346,10 @@ 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);
|
||||
@ -209,6 +362,14 @@ 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) {
|
||||
@ -216,6 +377,10 @@ 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);
|
||||
@ -227,7 +392,11 @@ 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();
|
||||
}
|
||||
|
||||
@ -237,7 +406,11 @@ 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();
|
||||
}
|
||||
|
||||
@ -269,7 +442,11 @@ 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();
|
||||
}
|
||||
|
||||
@ -279,7 +456,11 @@ 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();
|
||||
}
|
||||
|
||||
@ -306,7 +487,11 @@ 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) {
|
||||
@ -328,20 +513,36 @@ 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;
|
||||
}
|
||||
@ -386,14 +587,27 @@ 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;
|
||||
spi->dev->slave.slave_mode = 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;
|
||||
}
|
||||
|
||||
@ -402,9 +616,9 @@ void spiStopBus(spi_t * spi)
|
||||
if(!spi) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
removeApbChangeCallback(spi, _on_apb_change);
|
||||
|
||||
|
||||
SPI_MUTEX_LOCK();
|
||||
spiInitBus(spi);
|
||||
SPI_MUTEX_UNLOCK();
|
||||
@ -412,7 +626,7 @@ void spiStopBus(spi_t * spi)
|
||||
|
||||
spi_t * spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_t bitOrder)
|
||||
{
|
||||
if(spi_num > 3){
|
||||
if(spi_num >= SPI_COUNT){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -427,23 +641,46 @@ spi_t * spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_
|
||||
}
|
||||
#endif
|
||||
|
||||
if(spi_num == HSPI) {
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST);
|
||||
} else if(spi_num == VSPI) {
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_2);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST_2);
|
||||
#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_SPI_CLK_EN_1);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST_1);
|
||||
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);
|
||||
} else if(spi_num == VSPI) {
|
||||
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_ESP32C3
|
||||
periph_module_reset( PERIPH_SPI2_MODULE );
|
||||
periph_module_enable( PERIPH_SPI2_MODULE );
|
||||
#endif
|
||||
|
||||
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;
|
||||
@ -455,6 +692,7 @@ spi_t * spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_
|
||||
spiSetClockDiv(spi, clockDiv);
|
||||
|
||||
addApbChangeCallback(spi, _on_apb_change);
|
||||
|
||||
return spi;
|
||||
}
|
||||
|
||||
@ -466,6 +704,16 @@ 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) {
|
||||
@ -477,10 +725,16 @@ 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();
|
||||
@ -501,6 +755,10 @@ 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++) {
|
||||
@ -516,8 +774,14 @@ 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();
|
||||
@ -532,6 +796,10 @@ 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;
|
||||
@ -559,8 +827,14 @@ 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();
|
||||
@ -578,6 +852,10 @@ 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];
|
||||
@ -598,8 +876,14 @@ 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();
|
||||
@ -617,6 +901,10 @@ 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];
|
||||
@ -656,6 +944,10 @@ 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);
|
||||
@ -719,23 +1011,39 @@ 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:
|
||||
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;
|
||||
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;
|
||||
}
|
||||
if (SPI_MSBFIRST == bitOrder) {
|
||||
spi->dev->ctrl.wr_bit_order = 0;
|
||||
@ -762,14 +1070,20 @@ void spiEndTransaction(spi_t * spi)
|
||||
SPI_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
void IRAM_ATTR spiWriteByteNL(spi_t * spi, uint8_t data)
|
||||
void ARDUINO_ISR_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);
|
||||
}
|
||||
@ -782,13 +1096,17 @@ 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 IRAM_ATTR spiWriteShortNL(spi_t * spi, uint16_t data)
|
||||
void ARDUINO_ISR_ATTR spiWriteShortNL(spi_t * spi, uint16_t data)
|
||||
{
|
||||
if(!spi) {
|
||||
return;
|
||||
@ -797,8 +1115,14 @@ void IRAM_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);
|
||||
}
|
||||
@ -814,6 +1138,10 @@ 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;
|
||||
@ -823,7 +1151,7 @@ uint16_t spiTransferShortNL(spi_t * spi, uint16_t data)
|
||||
return data;
|
||||
}
|
||||
|
||||
void IRAM_ATTR spiWriteLongNL(spi_t * spi, uint32_t data)
|
||||
void ARDUINO_ISR_ATTR spiWriteLongNL(spi_t * spi, uint32_t data)
|
||||
{
|
||||
if(!spi) {
|
||||
return;
|
||||
@ -832,8 +1160,14 @@ void IRAM_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);
|
||||
}
|
||||
@ -849,6 +1183,10 @@ 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];
|
||||
@ -859,6 +1197,9 @@ 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++;
|
||||
@ -871,10 +1212,16 @@ 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;
|
||||
spi->dev->miso_dlen.usr_miso_dbitlen = 0;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
spi->dev->miso_dlen.usr_miso_dbitlen = 0;
|
||||
#endif
|
||||
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);
|
||||
|
||||
@ -911,11 +1258,27 @@ 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){
|
||||
for (int i=0; i<c_longs; i++) {
|
||||
result[i] = spi->dev->data_buf[i];
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
if(data){
|
||||
@ -954,6 +1317,10 @@ 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];
|
||||
@ -971,7 +1338,7 @@ void spiTransferBitsNL(spi_t * spi, uint32_t data, uint32_t * out, uint8_t bits)
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR spiWritePixelsNL(spi_t * spi, const void * data_in, uint32_t len){
|
||||
void ARDUINO_ISR_ATTR spiWritePixelsNL(spi_t * spi, const void * data_in, uint32_t len){
|
||||
size_t longs = len >> 2;
|
||||
if(len & 3){
|
||||
longs++;
|
||||
@ -986,7 +1353,9 @@ void IRAM_ATTR spiWritePixelsNL(spi_t * spi, const void * data_in, uint32_t len)
|
||||
l_bytes = (c_len & 3);
|
||||
|
||||
spi->dev->mosi_dlen.usr_mosi_dbitlen = (c_len*8)-1;
|
||||
spi->dev->miso_dlen.usr_miso_dbitlen = 0;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
spi->dev->miso_dlen.usr_miso_dbitlen = 0;
|
||||
#endif
|
||||
for (int i=0; i<c_longs; i++) {
|
||||
if(msb){
|
||||
if(l_bytes && i == (c_longs - 1)){
|
||||
@ -1002,6 +1371,10 @@ void IRAM_ATTR spiWritePixelsNL(spi_t * spi, const void * data_in, uint32_t len)
|
||||
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);
|
||||
|
||||
@ -1024,7 +1397,12 @@ 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;
|
||||
@ -1066,8 +1444,13 @@ 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 {
|
||||
|
@ -19,14 +19,22 @@
|
||||
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
|
||||
|
@ -14,7 +14,8 @@
|
||||
|
||||
#include "esp32-hal.h"
|
||||
#include "lwip/apps/sntp.h"
|
||||
#include "tcpip_adapter.h"
|
||||
//#include "tcpip_adapter.h"
|
||||
#include "esp_netif.h"
|
||||
|
||||
static void setTimeZone(long offset, int daylight)
|
||||
{
|
||||
@ -43,10 +44,13 @@ 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
|
||||
//tcpip_adapter_init(); // Should not hurt anything if already inited
|
||||
esp_netif_init();
|
||||
if(sntp_enabled()){
|
||||
sntp_stop();
|
||||
}
|
||||
@ -61,10 +65,13 @@ 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
|
||||
//tcpip_adapter_init(); // Should not hurt anything if already inited
|
||||
esp_netif_init();
|
||||
if(sntp_enabled()){
|
||||
sntp_stop();
|
||||
}
|
||||
|
@ -14,18 +14,40 @@
|
||||
|
||||
#include "esp32-hal-timer.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "freertos/task.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "soc/timer_group_struct.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#endif
|
||||
#include "freertos/task.h"
|
||||
#include "soc/timer_group_struct.h"
|
||||
#include "esp_attr.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/ets_sys.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/ets_sys.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "soc/periph_defs.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#include "esp32c3/rom/ets_sys.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "soc/periph_defs.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_intr.h"
|
||||
#endif
|
||||
|
||||
#define HWTIMER_LOCK() portENTER_CRITICAL(timer->lock)
|
||||
#define HWTIMER_UNLOCK() portEXIT_CRITICAL(timer->lock)
|
||||
|
||||
typedef struct {
|
||||
typedef volatile struct {
|
||||
union {
|
||||
struct {
|
||||
uint32_t reserved0: 10;
|
||||
@ -67,7 +89,7 @@ static hw_timer_t hw_timer[4] = {
|
||||
typedef void (*voidFuncPtr)(void);
|
||||
static voidFuncPtr __timerInterruptHandlers[4] = {0,0,0,0};
|
||||
|
||||
void IRAM_ATTR __timerISR(void * arg){
|
||||
void ARDUINO_ISR_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;
|
||||
@ -90,8 +112,9 @@ void IRAM_ATTR __timerISR(void * arg){
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t timerRead(hw_timer_t *timer){
|
||||
uint64_t inline 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;
|
||||
@ -203,15 +226,29 @@ hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp){
|
||||
}
|
||||
hw_timer_t * timer = &hw_timer[num];
|
||||
if(timer->group) {
|
||||
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);
|
||||
periph_module_enable(PERIPH_TIMG1_MODULE);
|
||||
} else {
|
||||
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);
|
||||
periph_module_enable(PERIPH_TIMG0_MODULE);
|
||||
}
|
||||
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);
|
||||
@ -229,6 +266,12 @@ 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){
|
||||
@ -239,9 +282,19 @@ 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 {
|
||||
@ -249,12 +302,15 @@ 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;
|
||||
@ -262,16 +318,25 @@ 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)(ESP_INTR_FLAG_IRAM|ESP_INTR_FLAG_LOWMED|ESP_INTR_FLAG_EDGE), __timerISR, NULL, &intr_handle);
|
||||
esp_intr_alloc(intr_source, (int)(ARDUINO_ISR_FLAG|ESP_INTR_FLAG_LOWMED), __timerISR, NULL, &intr_handle);
|
||||
} else {
|
||||
intr_matrix_set(esp_intr_get_cpu(intr_handle), intr_source, esp_intr_get_intno(intr_handle));
|
||||
}
|
||||
if(timer->group){
|
||||
#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){
|
||||
|
696
cores/esp32/esp32-hal-tinyusb.c
Normal file
@ -0,0 +1,696 @@
|
||||
|
||||
#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 */
|
108
cores/esp32/esp32-hal-tinyusb.h
Normal file
@ -0,0 +1,108 @@
|
||||
// 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 */
|
@ -13,14 +13,32 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include "esp32-hal-touch.h"
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_intr.h"
|
||||
#include "soc/rtc_io_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/sens_reg.h"
|
||||
#include "soc/sens_struct.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "driver/touch_sensor.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
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_intr.h"
|
||||
#endif
|
||||
|
||||
static uint16_t __touchSleepCycles = 0x1000;
|
||||
static uint16_t __touchMeasureCycles = 0x1000;
|
||||
@ -29,8 +47,9 @@ typedef void (*voidFuncPtr)(void);
|
||||
static voidFuncPtr __touchInterruptHandlers[10] = {0,};
|
||||
static intr_handle_t touch_intr_handle = NULL;
|
||||
|
||||
void IRAM_ATTR __touchISR(void * arg)
|
||||
void ARDUINO_ISR_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;
|
||||
@ -47,16 +66,21 @@ void IRAM_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()
|
||||
@ -66,15 +90,28 @@ 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)ESP_INTR_FLAG_IRAM, __touchISR, NULL, &touch_intr_handle);
|
||||
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
|
||||
}
|
||||
|
||||
uint16_t __touchRead(uint8_t pin)
|
||||
@ -88,6 +125,7 @@ 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,
|
||||
@ -119,6 +157,25 @@ 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)
|
||||
@ -134,6 +191,7 @@ 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);
|
||||
|
||||
@ -161,8 +219,12 @@ 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
|
||||
|
@ -14,155 +14,88 @@
|
||||
|
||||
#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 "rom/ets_sys.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_intr.h"
|
||||
#include "rom/uart.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"
|
||||
|
||||
#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)))
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#include "driver/uart.h"
|
||||
#include "hal/uart_ll.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/uart_struct.h"
|
||||
|
||||
static int s_uart_debug_nr = 0;
|
||||
|
||||
struct uart_struct_t {
|
||||
uart_dev_t * dev;
|
||||
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
xSemaphoreHandle lock;
|
||||
#endif
|
||||
|
||||
uint8_t num;
|
||||
xQueueHandle queue;
|
||||
intr_handle_t intr_handle;
|
||||
bool has_peek;
|
||||
uint8_t peek_byte;
|
||||
|
||||
};
|
||||
|
||||
#if CONFIG_DISABLE_HAL_LOCKS
|
||||
|
||||
#define UART_MUTEX_LOCK()
|
||||
#define UART_MUTEX_UNLOCK()
|
||||
|
||||
static uart_t _uart_bus_array[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}
|
||||
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
|
||||
};
|
||||
|
||||
#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[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}
|
||||
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
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
static void uart_on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb);
|
||||
|
||||
static void 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) {
|
||||
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, uint8_t rxPin)
|
||||
bool uartIsDriverInstalled(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL) {
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
pinMatrixInDetach(rxPin, false, false);
|
||||
uartDisableInterrupt(uart);
|
||||
|
||||
if (uart_is_driver_installed(uart->num)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void uartDetachTx(uart_t* uart, uint8_t txPin)
|
||||
void uartSetPins(uart_t* uart, uint8_t rxPin, uint8_t txPin)
|
||||
{
|
||||
if(uart == NULL) {
|
||||
if(uart == NULL || rxPin >= SOC_GPIO_PIN_COUNT || txPin >= SOC_GPIO_PIN_COUNT) {
|
||||
return;
|
||||
}
|
||||
pinMatrixOutDetach(txPin, false, false);
|
||||
UART_MUTEX_LOCK();
|
||||
ESP_ERROR_CHECK(uart_set_pin(uart->num, txPin, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||
UART_MUTEX_UNLOCK();
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t queueLen, bool inverted, uint8_t rxfifo_full_thrhd)
|
||||
{
|
||||
if(uart == 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) {
|
||||
if(uart_nr >= SOC_UART_NUM) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -172,6 +105,10 @@ uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rx
|
||||
|
||||
uart_t* uart = &_uart_bus_array[uart_nr];
|
||||
|
||||
if (uart_is_driver_installed(uart_nr)) {
|
||||
uartEnd(uart);
|
||||
}
|
||||
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
if(uart->lock == NULL) {
|
||||
uart->lock = xSemaphoreCreateMutex();
|
||||
@ -181,167 +118,143 @@ uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rx
|
||||
}
|
||||
#endif
|
||||
|
||||
if(queueLen && uart->queue == NULL) {
|
||||
uart->queue = xQueueCreate(queueLen, sizeof(uint8_t)); //initialize the queue
|
||||
if(uart->queue == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if(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_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));
|
||||
}
|
||||
|
||||
// tx_idle_num : idle interval after tx FIFO is empty(unit: the time it takes to send one bit under current baudrate)
|
||||
// Setting it to 0 prevents line idle time/delays when sending messages with small intervals
|
||||
uart->dev->idle_conf.tx_idle_num = 0; //
|
||||
|
||||
UART_MUTEX_UNLOCK();
|
||||
|
||||
if(rxPin != -1) {
|
||||
uartAttachRx(uart, rxPin, inverted);
|
||||
}
|
||||
|
||||
if(txPin != -1) {
|
||||
uartAttachTx(uart, txPin, inverted);
|
||||
}
|
||||
addApbChangeCallback(uart, uart_on_apb_change);
|
||||
uartFlush(uart);
|
||||
return uart;
|
||||
}
|
||||
|
||||
void uartEnd(uart_t* uart, uint8_t txPin, uint8_t rxPin)
|
||||
void uartEnd(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL) {
|
||||
return;
|
||||
}
|
||||
removeApbChangeCallback(uart, uart_on_apb_change);
|
||||
|
||||
|
||||
UART_MUTEX_LOCK();
|
||||
if(uart->queue != NULL) {
|
||||
vQueueDelete(uart->queue);
|
||||
uart->queue = NULL;
|
||||
}
|
||||
|
||||
uart->dev->conf0.val = 0;
|
||||
|
||||
uart_driver_delete(uart->num);
|
||||
UART_MUTEX_UNLOCK();
|
||||
|
||||
uartDetachRx(uart, rxPin);
|
||||
uartDetachTx(uart, txPin);
|
||||
}
|
||||
|
||||
size_t uartResizeRxBuffer(uart_t * uart, size_t new_size) {
|
||||
if(uart == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
UART_MUTEX_LOCK();
|
||||
if(uart->queue != NULL) {
|
||||
vQueueDelete(uart->queue);
|
||||
uart->queue = xQueueCreate(new_size, sizeof(uint8_t));
|
||||
if(uart->queue == NULL) {
|
||||
UART_MUTEX_UNLOCK();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
UART_MUTEX_UNLOCK();
|
||||
|
||||
return new_size;
|
||||
}
|
||||
|
||||
void uartSetRxInvert(uart_t* uart, bool invert)
|
||||
{
|
||||
if (uart == NULL)
|
||||
return;
|
||||
|
||||
#if 0
|
||||
// POTENTIAL ISSUE :: original code only set/reset rxd_inv bit
|
||||
// IDF or LL set/reset the whole inv_mask!
|
||||
if (invert)
|
||||
uart->dev->conf0.rxd_inv = 1;
|
||||
ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_RXD_INV));
|
||||
else
|
||||
uart->dev->conf0.rxd_inv = 0;
|
||||
ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_INV_DISABLE));
|
||||
|
||||
#else
|
||||
// this implementation is better over IDF API because it only affects RXD
|
||||
// this is supported in ESP32, ESP32-S2 and ESP32-C3
|
||||
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
|
||||
if (invert)
|
||||
hw->conf0.rxd_inv = 1;
|
||||
else
|
||||
hw->conf0.rxd_inv = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
uint32_t uartAvailable(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL || uart->queue == NULL) {
|
||||
|
||||
if(uart == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return (uxQueueMessagesWaiting(uart->queue) + uart->dev->status.rxfifo_cnt) ;
|
||||
|
||||
UART_MUTEX_LOCK();
|
||||
size_t available;
|
||||
uart_get_buffered_data_len(uart->num, &available);
|
||||
if (uart->has_peek) available++;
|
||||
UART_MUTEX_UNLOCK();
|
||||
return available;
|
||||
}
|
||||
|
||||
|
||||
uint32_t uartAvailableForWrite(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return 0x7f - uart->dev->status.txfifo_cnt;
|
||||
UART_MUTEX_LOCK();
|
||||
uint32_t available = uart_ll_get_txfifo_len(UART_LL_GET_HW(uart->num));
|
||||
UART_MUTEX_UNLOCK();
|
||||
return available;
|
||||
}
|
||||
|
||||
void uartRxFifoToQueue(uart_t* uart)
|
||||
{
|
||||
uint8_t c;
|
||||
UART_MUTEX_LOCK();
|
||||
//disable interrupts
|
||||
uart->dev->int_ena.val = 0;
|
||||
uart->dev->int_clr.val = 0xffffffff;
|
||||
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;
|
||||
xQueueSend(uart->queue, &c, 0);
|
||||
}
|
||||
//enable interrupts
|
||||
uart->dev->int_ena.rxfifo_full = 1;
|
||||
uart->dev->int_ena.frm_err = 1;
|
||||
uart->dev->int_ena.rxfifo_tout = 1;
|
||||
uart->dev->int_clr.val = 0xffffffff;
|
||||
UART_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
uint8_t uartRead(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL || uart->queue == NULL) {
|
||||
if(uart == NULL) {
|
||||
return 0;
|
||||
}
|
||||
uint8_t c;
|
||||
if ((uxQueueMessagesWaiting(uart->queue) == 0) && (uart->dev->status.rxfifo_cnt > 0))
|
||||
{
|
||||
uartRxFifoToQueue(uart);
|
||||
uint8_t c = 0;
|
||||
|
||||
UART_MUTEX_LOCK();
|
||||
|
||||
if (uart->has_peek) {
|
||||
uart->has_peek = false;
|
||||
c = uart->peek_byte;
|
||||
} else {
|
||||
|
||||
int len = uart_read_bytes(uart->num, &c, 1, 20 / portTICK_RATE_MS);
|
||||
if (len == 0) {
|
||||
c = 0;
|
||||
}
|
||||
}
|
||||
if(xQueueReceive(uart->queue, &c, 0)) {
|
||||
return c;
|
||||
}
|
||||
return 0;
|
||||
UART_MUTEX_UNLOCK();
|
||||
return c;
|
||||
}
|
||||
|
||||
uint8_t uartPeek(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL || uart->queue == NULL) {
|
||||
if(uart == NULL) {
|
||||
return 0;
|
||||
}
|
||||
uint8_t c;
|
||||
if ((uxQueueMessagesWaiting(uart->queue) == 0) && (uart->dev->status.rxfifo_cnt > 0))
|
||||
{
|
||||
uartRxFifoToQueue(uart);
|
||||
uint8_t c = 0;
|
||||
|
||||
UART_MUTEX_LOCK();
|
||||
|
||||
if (uart->has_peek) {
|
||||
c = uart->peek_byte;
|
||||
} else {
|
||||
int len = uart_read_bytes(uart->num, &c, 1, 20 / portTICK_RATE_MS);
|
||||
if (len == 0) {
|
||||
c = 0;
|
||||
} else {
|
||||
uart->has_peek = true;
|
||||
uart->peek_byte = c;
|
||||
}
|
||||
}
|
||||
if(xQueuePeek(uart->queue, &c, 0)) {
|
||||
return c;
|
||||
}
|
||||
return 0;
|
||||
UART_MUTEX_UNLOCK();
|
||||
return c;
|
||||
}
|
||||
|
||||
void uartWrite(uart_t* uart, uint8_t c)
|
||||
@ -350,28 +263,24 @@ void uartWrite(uart_t* uart, uint8_t c)
|
||||
return;
|
||||
}
|
||||
UART_MUTEX_LOCK();
|
||||
while(uart->dev->status.txfifo_cnt == 0x7F);
|
||||
uart->dev->fifo.rw_byte = c;
|
||||
uart_write_bytes(uart->num, &c, 1);
|
||||
UART_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
void uartWriteBuf(uart_t* uart, const uint8_t * data, size_t len)
|
||||
{
|
||||
if(uart == NULL) {
|
||||
if(uart == NULL || data == NULL || !len) {
|
||||
return;
|
||||
}
|
||||
|
||||
UART_MUTEX_LOCK();
|
||||
while(len) {
|
||||
while(uart->dev->status.txfifo_cnt == 0x7F);
|
||||
uart->dev->fifo.rw_byte = *data++;
|
||||
len--;
|
||||
}
|
||||
uart_write_bytes(uart->num, data, len);
|
||||
UART_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
void uartFlush(uart_t* uart)
|
||||
{
|
||||
uartFlushTxOnly(uart,true);
|
||||
uartFlushTxOnly(uart, true);
|
||||
}
|
||||
|
||||
void uartFlushTxOnly(uart_t* uart, bool txOnly)
|
||||
@ -379,22 +288,13 @@ void uartFlushTxOnly(uart_t* uart, bool txOnly)
|
||||
if(uart == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
ESP_ERROR_CHECK(uart_wait_tx_done(uart->num, portMAX_DELAY));
|
||||
|
||||
// we read the data out and make `fifo_len == 0 && rd_addr == wr_addr`.
|
||||
while(uart->dev->status.rxfifo_cnt != 0 || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) {
|
||||
READ_PERI_REG(UART_FIFO_REG(uart->num));
|
||||
}
|
||||
|
||||
xQueueReset(uart->queue);
|
||||
if ( !txOnly ) {
|
||||
ESP_ERROR_CHECK(uart_flush_input(uart->num));
|
||||
}
|
||||
|
||||
UART_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
@ -404,82 +304,43 @@ void uartSetBaudRate(uart_t* uart, uint32_t baud_rate)
|
||||
return;
|
||||
}
|
||||
UART_MUTEX_LOCK();
|
||||
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_ll_set_baudrate(UART_LL_GET_HW(uart->num), baud_rate);
|
||||
UART_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
static void uart_on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb)
|
||||
{
|
||||
uart_t* uart = (uart_t*)arg;
|
||||
if(ev_type == APB_BEFORE_CHANGE){
|
||||
UART_MUTEX_LOCK();
|
||||
//disabple interrupt
|
||||
uart->dev->int_ena.val = 0;
|
||||
uart->dev->int_clr.val = 0xffffffff;
|
||||
// read RX fifo
|
||||
uint8_t c;
|
||||
// BaseType_t xHigherPriorityTaskWoken;
|
||||
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;
|
||||
}
|
||||
|
||||
uint32_t clk_div = (uart->dev->clk_div.div_int << 4) | (uart->dev->clk_div.div_frag & 0x0F);
|
||||
if(!clk_div) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ((getApbFrequency()<<4)/clk_div);
|
||||
UART_MUTEX_LOCK();
|
||||
uint32_t baud_rate = uart_ll_get_baudrate(UART_LL_GET_HW(uart->num));
|
||||
UART_MUTEX_UNLOCK();
|
||||
return baud_rate;
|
||||
}
|
||||
|
||||
static void IRAM_ATTR uart0_write_char(char c)
|
||||
static void ARDUINO_ISR_ATTR uart0_write_char(char c)
|
||||
{
|
||||
while(((ESP_REG(0x01C+DR_REG_UART_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) == 0x7F);
|
||||
ESP_REG(DR_REG_UART_BASE) = c;
|
||||
while (uart_ll_get_txfifo_len(&UART0) == 0);
|
||||
uart_ll_write_txfifo(&UART0, (const uint8_t *) &c, 1);
|
||||
}
|
||||
|
||||
static void IRAM_ATTR uart1_write_char(char c)
|
||||
#if SOC_UART_NUM > 1
|
||||
static void ARDUINO_ISR_ATTR uart1_write_char(char c)
|
||||
{
|
||||
while(((ESP_REG(0x01C+DR_REG_UART1_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) == 0x7F);
|
||||
ESP_REG(DR_REG_UART1_BASE) = c;
|
||||
while (uart_ll_get_txfifo_len(&UART1) == 0);
|
||||
uart_ll_write_txfifo(&UART1, (const uint8_t *) &c, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void IRAM_ATTR uart2_write_char(char c)
|
||||
#if SOC_UART_NUM > 2
|
||||
static void ARDUINO_ISR_ATTR uart2_write_char(char c)
|
||||
{
|
||||
while(((ESP_REG(0x01C+DR_REG_UART2_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) == 0x7F);
|
||||
ESP_REG(DR_REG_UART2_BASE) = c;
|
||||
while (uart_ll_get_txfifo_len(&UART2) == 0);
|
||||
uart_ll_write_txfifo(&UART2, (const uint8_t *) &c, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
void uart_install_putc()
|
||||
{
|
||||
@ -487,12 +348,16 @@ 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;
|
||||
@ -501,15 +366,11 @@ void uart_install_putc()
|
||||
|
||||
void uartSetDebug(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL || uart->num > 2) {
|
||||
if(uart == NULL || uart->num >= SOC_UART_NUM) {
|
||||
s_uart_debug_nr = -1;
|
||||
//ets_install_putc1(NULL);
|
||||
//return;
|
||||
} else
|
||||
if(s_uart_debug_nr == uart->num) {
|
||||
return;
|
||||
} else
|
||||
s_uart_debug_nr = uart->num;
|
||||
} else {
|
||||
s_uart_debug_nr = uart->num;
|
||||
}
|
||||
uart_install_putc();
|
||||
}
|
||||
|
||||
@ -520,9 +381,6 @@ 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;
|
||||
@ -538,17 +396,19 @@ int log_printf(const char *format, ...)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
vsnprintf(temp, len+1, format, arg);
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
if(_uart_bus_array[s_uart_debug_nr].lock){
|
||||
if(s_uart_debug_nr != -1 && _uart_bus_array[s_uart_debug_nr].lock){
|
||||
xSemaphoreTake(_uart_bus_array[s_uart_debug_nr].lock, portMAX_DELAY);
|
||||
ets_printf("%s", temp);
|
||||
xSemaphoreGive(_uart_bus_array[s_uart_debug_nr].lock);
|
||||
} else {
|
||||
ets_printf("%s", temp);
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
|
||||
vsnprintf(temp, len+1, format, arg);
|
||||
ets_printf("%s", temp);
|
||||
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
if(s_uart_debug_nr != -1 && _uart_bus_array[s_uart_debug_nr].lock){
|
||||
xSemaphoreGive(_uart_bus_array[s_uart_debug_nr].lock);
|
||||
}
|
||||
#endif
|
||||
va_end(arg);
|
||||
if(len >= sizeof(loc_buf)){
|
||||
@ -557,46 +417,126 @@ int log_printf(const char *format, ...)
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static void log_print_buf_line(const uint8_t *b, size_t len, size_t total_len){
|
||||
for(size_t i = 0; i<len; i++){
|
||||
log_printf("%s0x%02x,",i?" ":"", b[i]);
|
||||
}
|
||||
if(total_len > 16){
|
||||
for(size_t i = len; i<16; i++){
|
||||
log_printf(" ");
|
||||
}
|
||||
log_printf(" // ");
|
||||
} else {
|
||||
log_printf(" // ");
|
||||
}
|
||||
for(size_t i = 0; i<len; i++){
|
||||
log_printf("%c",((b[i] >= 0x20) && (b[i] < 0x80))?b[i]:'.');
|
||||
}
|
||||
log_printf("\n");
|
||||
}
|
||||
|
||||
void log_print_buf(const uint8_t *b, size_t len){
|
||||
if(!len || !b){
|
||||
return;
|
||||
}
|
||||
for(size_t i = 0; i<len; i+=16){
|
||||
if(len > 16){
|
||||
log_printf("/* 0x%04X */ ", i);
|
||||
}
|
||||
log_print_buf_line(b+i, ((len-i)<16)?(len - i):16, len);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* if enough pulses are detected return the minimum high pulse duration + minimum low pulse duration divided by two.
|
||||
* This equals one bit period. If flag is true the function return inmediately, otherwise it waits for enough pulses.
|
||||
*/
|
||||
unsigned long uartBaudrateDetect(uart_t *uart, bool flg)
|
||||
{
|
||||
while(uart->dev->rxd_cnt.edge_cnt < 30) { // UART_PULSE_NUM(uart_num)
|
||||
if(uart == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
|
||||
|
||||
while(hw->rxd_cnt.edge_cnt < 30) { // UART_PULSE_NUM(uart_num)
|
||||
if(flg) return 0;
|
||||
ets_delay_us(1000);
|
||||
}
|
||||
|
||||
UART_MUTEX_LOCK();
|
||||
unsigned long ret = ((uart->dev->lowpulse.min_cnt + uart->dev->highpulse.min_cnt) >> 1) + 12;
|
||||
//log_i("lowpulse_min_cnt = %d hightpulse_min_cnt = %d", hw->lowpulse.min_cnt, hw->highpulse.min_cnt);
|
||||
unsigned long ret = ((hw->lowpulse.min_cnt + hw->highpulse.min_cnt) >> 1);
|
||||
UART_MUTEX_UNLOCK();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* To start detection of baud rate with the uart the auto_baud.en bit needs to be cleared and set. The bit period is
|
||||
* detected calling uartBadrateDetect(). The raw baudrate is computed using the UART_CLK_FREQ. The raw baudrate is
|
||||
* rounded to the closed real baudrate.
|
||||
*
|
||||
* ESP32-C3 reports wrong baud rate detection as shown below:
|
||||
*
|
||||
* This will help in a future recall for the C3.
|
||||
* Baud Sent: Baud Read:
|
||||
* 300 --> 19536
|
||||
* 2400 --> 19536
|
||||
* 4800 --> 19536
|
||||
* 9600 --> 28818
|
||||
* 19200 --> 57678
|
||||
* 38400 --> 115440
|
||||
* 57600 --> 173535
|
||||
* 115200 --> 347826
|
||||
* 230400 --> 701754
|
||||
*
|
||||
*
|
||||
*/
|
||||
void uartStartDetectBaudrate(uart_t *uart) {
|
||||
if(!uart) return;
|
||||
if(uart == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
uart->dev->auto_baud.glitch_filt = 0x08;
|
||||
uart->dev->auto_baud.en = 0;
|
||||
uart->dev->auto_baud.en = 1;
|
||||
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32C3
|
||||
|
||||
// ESP32-C3 requires further testing
|
||||
// Baud rate detection returns wrong values
|
||||
|
||||
log_e("ESP32-C3 baud rate detection is not supported.");
|
||||
return;
|
||||
|
||||
// Code bellow for C3 kept for future recall
|
||||
//hw->rx_filt.glitch_filt = 0x08;
|
||||
//hw->rx_filt.glitch_filt_en = 1;
|
||||
//hw->conf0.autobaud_en = 0;
|
||||
//hw->conf0.autobaud_en = 1;
|
||||
|
||||
#else
|
||||
hw->auto_baud.glitch_filt = 0x08;
|
||||
hw->auto_baud.en = 0;
|
||||
hw->auto_baud.en = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
unsigned long
|
||||
uartDetectBaudrate(uart_t *uart)
|
||||
{
|
||||
if(uart == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3 // ESP32-C3 requires further testing - Baud rate detection returns wrong values
|
||||
|
||||
static bool uartStateDetectingBaudrate = false;
|
||||
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
|
||||
|
||||
if(!uartStateDetectingBaudrate) {
|
||||
uart->dev->auto_baud.glitch_filt = 0x08;
|
||||
uart->dev->auto_baud.en = 0;
|
||||
uart->dev->auto_baud.en = 1;
|
||||
uartStartDetectBaudrate(uart);
|
||||
uartStateDetectingBaudrate = true;
|
||||
}
|
||||
|
||||
@ -604,11 +544,21 @@ uartDetectBaudrate(uart_t *uart)
|
||||
if (!divisor) {
|
||||
return 0;
|
||||
}
|
||||
// log_i(...) below has been used to check C3 baud rate detection results
|
||||
//log_i("Divisor = %d\n", divisor);
|
||||
//log_i("BAUD RATE based on Positive Pulse %d\n", getApbFrequency()/((hw->pospulse.min_cnt + 1)/2));
|
||||
//log_i("BAUD RATE based on Negative Pulse %d\n", getApbFrequency()/((hw->negpulse.min_cnt + 1)/2));
|
||||
|
||||
uart->dev->auto_baud.en = 0;
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32C3
|
||||
//hw->conf0.autobaud_en = 0;
|
||||
#else
|
||||
hw->auto_baud.en = 0;
|
||||
#endif
|
||||
uartStateDetectingBaudrate = false; // Initialize for the next round
|
||||
|
||||
unsigned long baudrate = getApbFrequency() / divisor;
|
||||
//log_i("APB_FREQ = %d\nraw baudrate detected = %d", getApbFrequency(), baudrate);
|
||||
|
||||
static const unsigned long default_rates[] = {300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 74880, 115200, 230400, 256000, 460800, 921600, 1843200, 3686400};
|
||||
|
||||
@ -625,11 +575,8 @@ uartDetectBaudrate(uart_t *uart)
|
||||
}
|
||||
|
||||
return default_rates[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the status of the RX state machine, if the value is non-zero the state machine is active.
|
||||
*/
|
||||
bool uartRxActive(uart_t* uart) {
|
||||
return uart->dev->status.st_urx_out != 0;
|
||||
#else
|
||||
log_e("ESP32-C3 baud rate detection is not supported.");
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
@ -51,8 +51,8 @@ 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);
|
||||
void uartEnd(uart_t* uart, uint8_t rxPin, uint8_t txPin);
|
||||
uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t queueLen, bool inverted, uint8_t rxfifo_full_thrhd);
|
||||
void uartEnd(uart_t* uart);
|
||||
|
||||
uint32_t uartAvailable(uart_t* uart);
|
||||
uint32_t uartAvailableForWrite(uart_t* uart);
|
||||
@ -68,17 +68,17 @@ void uartFlushTxOnly(uart_t* uart, bool txOnly );
|
||||
void uartSetBaudRate(uart_t* uart, uint32_t baud_rate);
|
||||
uint32_t uartGetBaudRate(uart_t* uart);
|
||||
|
||||
size_t uartResizeRxBuffer(uart_t* uart, size_t new_size);
|
||||
|
||||
void uartSetRxInvert(uart_t* uart, bool invert);
|
||||
|
||||
void uartSetDebug(uart_t* uart);
|
||||
int uartGetDebug();
|
||||
|
||||
bool uartIsDriverInstalled(uart_t* uart);
|
||||
void uartSetPins(uart_t* uart, uint8_t rxPin, uint8_t txPin);
|
||||
|
||||
void uartStartDetectBaudrate(uart_t *uart);
|
||||
unsigned long uartDetectBaudrate(uart_t *uart);
|
||||
|
||||
bool uartRxActive(uart_t* uart);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -20,10 +20,6 @@
|
||||
#ifndef HAL_ESP32_HAL_H_
|
||||
#define HAL_ESP32_HAL_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
@ -34,9 +30,39 @@ extern "C" {
|
||||
#include <math.h>
|
||||
#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
|
||||
@ -64,12 +90,6 @@ void yield(void);
|
||||
#include "esp32-hal-psram.h"
|
||||
#include "esp32-hal-cpu.h"
|
||||
|
||||
#ifndef BOARD_HAS_PSRAM
|
||||
#ifdef CONFIG_SPIRAM_SUPPORT
|
||||
#undef CONFIG_SPIRAM_SUPPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//returns chip temperature in Celsius
|
||||
float temperatureRead();
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
#define _ESP8266_COMPAT_H_
|
||||
|
||||
#define ICACHE_FLASH_ATTR
|
||||
#define ICACHE_RAM_ATTR IRAM_ATTR
|
||||
#define ICACHE_RAM_ATTR ARDUINO_ISR_ATTR
|
||||
|
||||
|
||||
#endif /* _ESP8266_COMPAT_H_ */
|
46
cores/esp32/esp_arduino_version.h
Normal file
@ -0,0 +1,46 @@
|
||||
// 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
|
204
cores/esp32/firmware_msc_fat.c
Normal file
@ -0,0 +1,204 @@
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "firmware_msc_fat.h"
|
||||
//copy up to max_len chars from src to dst and do not terminate
|
||||
static size_t cplstr(void *dst, const void * src, size_t max_len){
|
||||
if(!src || !dst || !max_len){
|
||||
return 0;
|
||||
}
|
||||
size_t l = strlen((const char *)src);
|
||||
if(l > max_len){
|
||||
l = max_len;
|
||||
}
|
||||
memcpy(dst, src, l);
|
||||
return l;
|
||||
}
|
||||
|
||||
//copy up to max_len chars from src to dst, adding spaces up to max_len. do not terminate
|
||||
static void cplstrsp(void *dst, const void * src, size_t max_len){
|
||||
size_t l = cplstr(dst, src, max_len);
|
||||
for(; l < max_len; l++){
|
||||
((uint8_t*)dst)[l] = 0x20;
|
||||
}
|
||||
}
|
||||
|
||||
// FAT12
|
||||
static const char * FAT12_FILE_SYSTEM_TYPE = "FAT12";
|
||||
|
||||
static uint16_t fat12_sectors_per_alloc_table(uint32_t sector_num){
|
||||
uint32_t required_bytes = (((sector_num * 3)+1)/2);
|
||||
return (required_bytes / DISK_SECTOR_SIZE) + ((required_bytes & (DISK_SECTOR_SIZE - 1))?1:0);
|
||||
}
|
||||
|
||||
static uint8_t * fat12_add_table(uint8_t * dst, fat_boot_sector_t * boot){
|
||||
memset(dst+DISK_SECTOR_SIZE, 0, boot->sectors_per_alloc_table * DISK_SECTOR_SIZE);
|
||||
uint8_t * d = dst + DISK_SECTOR_SIZE;
|
||||
d[0] = 0xF8;
|
||||
d[1] = 0xFF;
|
||||
d[2] = 0xFF;
|
||||
return d;
|
||||
}
|
||||
|
||||
static void fat12_set_table_index(uint8_t * table, uint16_t index, uint16_t value){
|
||||
uint16_t offset = (index >> 1) * 3;
|
||||
uint8_t * data = table + offset;
|
||||
if(index & 1){
|
||||
data[2] = (value >> 4) & 0xFF;
|
||||
data[1] = (data[1] & 0xF) | ((value & 0xF) << 4);
|
||||
} else {
|
||||
data[0] = value & 0xFF;
|
||||
data[1] = (data[1] & 0xF0) | ((value >> 8) & 0xF);
|
||||
}
|
||||
}
|
||||
|
||||
//FAT16
|
||||
static const char * FAT16_FILE_SYSTEM_TYPE = "FAT16";
|
||||
|
||||
static uint16_t fat16_sectors_per_alloc_table(uint32_t sector_num){
|
||||
uint32_t required_bytes = sector_num * 2;
|
||||
return (required_bytes / DISK_SECTOR_SIZE) + ((required_bytes & (DISK_SECTOR_SIZE - 1))?1:0);
|
||||
}
|
||||
|
||||
static uint8_t * fat16_add_table(uint8_t * dst, fat_boot_sector_t * boot){
|
||||
memset(dst+DISK_SECTOR_SIZE, 0, boot->sectors_per_alloc_table * DISK_SECTOR_SIZE);
|
||||
uint16_t * d = (uint16_t *)(dst + DISK_SECTOR_SIZE);
|
||||
d[0] = 0xFFF8;
|
||||
d[1] = 0xFFFF;
|
||||
return (uint8_t *)d;
|
||||
}
|
||||
|
||||
static void fat16_set_table_index(uint8_t * table, uint16_t index, uint16_t value){
|
||||
uint16_t offset = index * 2;
|
||||
*(uint16_t *)(table + offset) = value;
|
||||
}
|
||||
|
||||
//Interface
|
||||
const char * fat_file_system_type(bool fat16) {
|
||||
return ((fat16)?FAT16_FILE_SYSTEM_TYPE:FAT12_FILE_SYSTEM_TYPE);
|
||||
}
|
||||
|
||||
uint16_t fat_sectors_per_alloc_table(uint32_t sector_num, bool fat16){
|
||||
if(fat16){
|
||||
return fat16_sectors_per_alloc_table(sector_num);
|
||||
}
|
||||
return fat12_sectors_per_alloc_table(sector_num);
|
||||
}
|
||||
|
||||
uint8_t * fat_add_table(uint8_t * dst, fat_boot_sector_t * boot, bool fat16){
|
||||
if(fat16){
|
||||
return fat16_add_table(dst, boot);
|
||||
}
|
||||
return fat12_add_table(dst, boot);
|
||||
}
|
||||
|
||||
void fat_set_table_index(uint8_t * table, uint16_t index, uint16_t value, bool fat16){
|
||||
if(fat16){
|
||||
fat16_set_table_index(table, index, value);
|
||||
} else {
|
||||
fat12_set_table_index(table, index, value);
|
||||
}
|
||||
}
|
||||
|
||||
fat_boot_sector_t * fat_add_boot_sector(uint8_t * dst, uint16_t sector_num, uint16_t table_sectors, const char * file_system_type, const char * volume_label, uint32_t serial_number){
|
||||
fat_boot_sector_t *boot = (fat_boot_sector_t*)dst;
|
||||
boot->jump_instruction[0] = 0xEB;
|
||||
boot->jump_instruction[1] = 0x3C;
|
||||
boot->jump_instruction[2] = 0x90;
|
||||
cplstr(boot->oem_name, "MSDOS5.0", 8);
|
||||
boot->bytes_per_sector = DISK_SECTOR_SIZE;
|
||||
boot->sectors_per_cluster = 1;
|
||||
boot->reserved_sectors_count = 1;
|
||||
boot->file_alloc_tables_num = 1;
|
||||
boot->max_root_dir_entries = 16;
|
||||
boot->fat12_sector_num = sector_num;
|
||||
boot->media_descriptor = 0xF8;
|
||||
boot->sectors_per_alloc_table = table_sectors;
|
||||
boot->sectors_per_track = 1;
|
||||
boot->num_heads = 1;
|
||||
boot->hidden_sectors_count = 0;
|
||||
boot->total_sectors_32 = 0;
|
||||
boot->physical_drive_number = 0x80;
|
||||
boot->reserved0 = 0x00;
|
||||
boot->extended_boot_signature = 0x29;
|
||||
boot->serial_number = serial_number;
|
||||
cplstrsp(boot->volume_label, volume_label, 11);
|
||||
memset(boot->reserved, 0, 448);
|
||||
cplstrsp(boot->file_system_type, file_system_type, 8);
|
||||
boot->signature = 0xAA55;
|
||||
return boot;
|
||||
}
|
||||
|
||||
fat_dir_entry_t * fat_add_label(uint8_t * dst, const char * volume_label){
|
||||
fat_boot_sector_t * boot = (fat_boot_sector_t *)dst;
|
||||
fat_dir_entry_t * entry = (fat_dir_entry_t *)(dst + ((boot->sectors_per_alloc_table+1) * DISK_SECTOR_SIZE));
|
||||
memset(entry, 0, sizeof(fat_dir_entry_t));
|
||||
cplstrsp(entry->volume_label, volume_label, 11);
|
||||
entry->file_attr = FAT_FILE_ATTR_VOLUME_LABEL;
|
||||
return entry;
|
||||
}
|
||||
|
||||
fat_dir_entry_t * fat_add_root_file(uint8_t * dst, uint8_t index, const char * file_name, const char * file_extension, size_t file_size, uint16_t data_start_sector, bool is_fat16){
|
||||
fat_boot_sector_t * boot = (fat_boot_sector_t *)dst;
|
||||
uint8_t * table = dst + DISK_SECTOR_SIZE;
|
||||
fat_dir_entry_t * entry = (fat_dir_entry_t *)(dst + ((boot->sectors_per_alloc_table+1) * DISK_SECTOR_SIZE) + (index * sizeof(fat_dir_entry_t)));
|
||||
memset(entry, 0, sizeof(fat_dir_entry_t));
|
||||
cplstrsp(entry->file_name, file_name, 8);
|
||||
cplstrsp(entry->file_extension, file_extension, 3);
|
||||
entry->file_attr = FAT_FILE_ATTR_ARCHIVE;
|
||||
entry->file_size = file_size;
|
||||
entry->data_start_sector = data_start_sector;
|
||||
entry->extended_attr = 0;
|
||||
|
||||
uint16_t file_sectors = file_size / DISK_SECTOR_SIZE;
|
||||
if(file_size % DISK_SECTOR_SIZE){
|
||||
file_sectors++;
|
||||
}
|
||||
|
||||
uint16_t data_end_sector = data_start_sector + file_sectors;
|
||||
for(uint16_t i=data_start_sector; i<(data_end_sector-1); i++){
|
||||
fat_set_table_index(table, i, i+1, is_fat16);
|
||||
}
|
||||
fat_set_table_index(table, data_end_sector-1, 0xFFFF, is_fat16);
|
||||
|
||||
//Set Firmware Date based on the build time
|
||||
static const char * month_names_short[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
|
||||
char mstr[8] = {'\0',};
|
||||
const char *str = __DATE__ " " __TIME__;
|
||||
int ms=0, seconds=0, minutes=0, hours=0, year=0, date=0, month=0;
|
||||
int r = sscanf(str,"%s %d %d %d:%d:%d", mstr, &date, &year, &hours, &minutes, &seconds);
|
||||
if(r >= 0){
|
||||
for(int i=0; i<12; i++){
|
||||
if(!strcmp(mstr, month_names_short[i])){
|
||||
month = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
entry->creation_time_ms = FAT_MS2V(seconds, ms);
|
||||
entry->creation_time_hms = FAT_HMS2V(hours, minutes, seconds);
|
||||
entry->creation_time_ymd = FAT_YMD2V(year, month, date);
|
||||
entry->last_access_ymd = entry->creation_time_ymd;
|
||||
entry->last_modified_hms = entry->creation_time_hms;
|
||||
entry->last_modified_ymd = entry->creation_time_ymd;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
uint8_t fat_lfn_checksum(const uint8_t *short_filename){
|
||||
uint8_t sum = 0;
|
||||
for (uint8_t i = 11; i; i--) {
|
||||
sum = ((sum & 1) << 7) + (sum >> 1) + *short_filename++;
|
||||
}
|
||||
return sum;
|
||||
}
|
141
cores/esp32/firmware_msc_fat.h
Normal file
@ -0,0 +1,141 @@
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define FAT_U8(v) ((v) & 0xFF)
|
||||
#define FAT_U16(v) FAT_U8(v), FAT_U8((v) >> 8)
|
||||
#define FAT_U32(v) FAT_U8(v), FAT_U8((v) >> 8), FAT_U8((v) >> 16), FAT_U8((v) >> 24)
|
||||
|
||||
#define FAT12_TBL2B(l,h) FAT_U8(l), FAT_U8(((l >> 8) & 0xF) | ((h << 4) & 0xF0)), FAT_U8(h >> 4)
|
||||
|
||||
#define FAT_MS2B(s,ms) FAT_U8(((((s) & 0x1) * 1000) + (ms)) / 10)
|
||||
#define FAT_HMS2B(h,m,s) FAT_U8(((s) >> 1)|(((m) & 0x7) << 5)), FAT_U8((((m) >> 3) & 0x7)|((h) << 3))
|
||||
#define FAT_YMD2B(y,m,d) FAT_U8(((d) & 0x1F)|(((m) & 0x7) << 5)), FAT_U8((((m) >> 3) & 0x1)|((((y) - 1980) & 0x7F) << 1))
|
||||
|
||||
#define FAT_MS2V(s,ms) FAT_U8(((((s) & 0x1) * 1000) + (ms)) / 10)
|
||||
#define FAT_HMS2V(h,m,s) (FAT_U8(((s) >> 1)|(((m) & 0x7) << 5)) | (FAT_U8((((m) >> 3) & 0x7)|((h) << 3)) << 8))
|
||||
#define FAT_YMD2V(y,m,d) (FAT_U8(((d) & 0x1F)|(((m) & 0x7) << 5)) | (FAT_U8((((m) >> 3) & 0x1)|((((y) - 1980) & 0x7F) << 1)) << 8))
|
||||
|
||||
#define FAT_B2HMS(hms) ((hms >> 11) & 0x1F), ((hms >> 5) & 0x3F), ((hms & 0x1F) << 1)
|
||||
#define FAT_B2YMD(ymd) (((ymd >> 9) & 0x7F) + 1980), ((ymd >> 5) & 0x0F), (ymd & 0x1F)
|
||||
|
||||
#define FAT_FILE_ATTR_READ_ONLY 0x01
|
||||
#define FAT_FILE_ATTR_HIDDEN 0x02
|
||||
#define FAT_FILE_ATTR_SYSTEM 0x04
|
||||
#define FAT_FILE_ATTR_VOLUME_LABEL 0x08
|
||||
#define FAT_FILE_ATTR_SUBDIRECTORY 0x10
|
||||
#define FAT_FILE_ATTR_ARCHIVE 0x20
|
||||
#define FAT_FILE_ATTR_DEVICE 0x40
|
||||
|
||||
static const uint16_t DISK_SECTOR_SIZE = 512;
|
||||
|
||||
#define FAT_SIZE_TO_SECTORS(bytes) ((bytes) / DISK_SECTOR_SIZE) + (((bytes) % DISK_SECTOR_SIZE)?1:0)
|
||||
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint8_t jump_instruction[3];
|
||||
char oem_name[8];//padded with spaces (0x20)
|
||||
uint16_t bytes_per_sector;//DISK_SECTOR_SIZE usually 512
|
||||
uint8_t sectors_per_cluster;//Allowed values are 1, 2, 4, 8, 16, 32, 64, and 128
|
||||
uint16_t reserved_sectors_count;//At least 1 for this sector, usually 32 for FAT32
|
||||
uint8_t file_alloc_tables_num;//Almost always 2; RAM disks might use 1
|
||||
uint16_t max_root_dir_entries;//FAT12 and FAT16
|
||||
uint16_t fat12_sector_num;//DISK_SECTOR_NUM FAT12 and FAT16
|
||||
uint8_t media_descriptor;
|
||||
uint16_t sectors_per_alloc_table;//FAT12 and FAT16
|
||||
uint16_t sectors_per_track;//A value of 0 may indicate LBA-only access
|
||||
uint16_t num_heads;
|
||||
uint32_t hidden_sectors_count;
|
||||
uint32_t total_sectors_32;
|
||||
uint8_t physical_drive_number;//0x00 for (first) removable media, 0x80 for (first) fixed disk
|
||||
uint8_t reserved0;
|
||||
uint8_t extended_boot_signature;//should be 0x29
|
||||
uint32_t serial_number;//0x1234 => 1234
|
||||
char volume_label[11];//padded with spaces (0x20)
|
||||
char file_system_type[8];//padded with spaces (0x20)
|
||||
uint8_t reserved[448];
|
||||
uint16_t signature;//should be 0xAA55
|
||||
} fat_boot_sector_t;
|
||||
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
union {
|
||||
struct {
|
||||
char file_name[8];//padded with spaces (0x20)
|
||||
char file_extension[3];//padded with spaces (0x20)
|
||||
};
|
||||
struct {
|
||||
uint8_t file_magic;// 0xE5:deleted, 0x05:will_be_deleted, 0x00:end_marker, 0x2E:dot_marker(. or ..)
|
||||
char file_magic_data[10];
|
||||
};
|
||||
char volume_label[11];//padded with spaces (0x20)
|
||||
};
|
||||
uint8_t file_attr;//mask of FAT_FILE_ATTR_*
|
||||
uint8_t reserved;//always 0
|
||||
uint8_t creation_time_ms;//ms * 10; max 1990 (1s 990ms)
|
||||
uint16_t creation_time_hms; // [5:6:5] => h:m:(s/2)
|
||||
uint16_t creation_time_ymd; // [7:4:5] => (y+1980):m:d
|
||||
uint16_t last_access_ymd;
|
||||
uint16_t extended_attr;
|
||||
uint16_t last_modified_hms;
|
||||
uint16_t last_modified_ymd;
|
||||
uint16_t data_start_sector;
|
||||
uint32_t file_size;
|
||||
} fat_dir_entry_t;
|
||||
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
union {
|
||||
struct {
|
||||
uint8_t number:5;
|
||||
uint8_t reserved0:1;
|
||||
uint8_t llfp:1;
|
||||
uint8_t reserved1:1;
|
||||
} seq;
|
||||
uint8_t seq_num; //0xE5: Deleted Entry
|
||||
};
|
||||
uint16_t name0[5];
|
||||
uint8_t attr; //ALWAYS 0x0F
|
||||
uint8_t type; //ALWAYS 0x00
|
||||
uint8_t dos_checksum;
|
||||
uint16_t name1[6];
|
||||
uint16_t first_cluster; //ALWAYS 0x0000
|
||||
uint16_t name2[2];
|
||||
} fat_lfn_entry_t;
|
||||
|
||||
typedef union {
|
||||
fat_dir_entry_t dir;
|
||||
fat_lfn_entry_t lfn;
|
||||
} fat_entry_t;
|
||||
|
||||
const char * fat_file_system_type(bool fat16);
|
||||
uint16_t fat_sectors_per_alloc_table(uint32_t sector_num, bool fat16);
|
||||
uint8_t * fat_add_table(uint8_t * dst, fat_boot_sector_t * boot, bool fat16);
|
||||
void fat_set_table_index(uint8_t * table, uint16_t index, uint16_t value, bool fat16);
|
||||
fat_boot_sector_t * fat_add_boot_sector(uint8_t * dst, uint16_t sector_num, uint16_t table_sectors, const char * file_system_type, const char * volume_label, uint32_t serial_number);
|
||||
fat_dir_entry_t * fat_add_label(uint8_t * dst, const char * volume_label);
|
||||
fat_dir_entry_t * fat_add_root_file(uint8_t * dst, uint8_t index, const char * file_name, const char * file_extension, size_t file_size, uint16_t data_start_sector, bool is_fat16);
|
||||
uint8_t fat_lfn_checksum(const uint8_t *short_filename);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -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];
|
||||
}
|
||||
|
||||
|
@ -2,14 +2,34 @@
|
||||
#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 CONFIG_ARDUINO_LOOP_STACK_SIZE 8192
|
||||
#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;
|
||||
|
||||
@ -17,6 +37,9 @@ void loopTask(void *pvParameters)
|
||||
{
|
||||
setup();
|
||||
for(;;) {
|
||||
#if CONFIG_FREERTOS_UNICORE
|
||||
yieldIfNecessary();
|
||||
#endif
|
||||
if(loopTaskWDTEnabled){
|
||||
esp_task_wdt_reset();
|
||||
}
|
||||
@ -27,9 +50,21 @@ 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", CONFIG_ARDUINO_LOOP_STACK_SIZE, NULL, 1, &loopTaskHandle, CONFIG_ARDUINO_RUNNING_CORE);
|
||||
xTaskCreateUniversal(loopTask, "loopTask", ARDUINO_LOOP_STACK_SIZE, NULL, 1, &loopTaskHandle, ARDUINO_RUNNING_CORE);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -28,8 +28,9 @@
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
#include "stdlib_noniso.h"
|
||||
#include "esp_system.h"
|
||||
|
||||
void reverse(char* begin, char* end) {
|
||||
static void reverse(char* begin, char* end) {
|
||||
char *is = begin;
|
||||
char *ie = end - 1;
|
||||
while(is < ie) {
|
||||
|
@ -17,13 +17,11 @@
|
||||
//#include <limits.h>
|
||||
#include "wiring_private.h"
|
||||
#include "pins_arduino.h"
|
||||
|
||||
|
||||
extern uint32_t xthal_get_ccount();
|
||||
#include <hal/cpu_hal.h>
|
||||
|
||||
#define WAIT_FOR_PIN_STATE(state) \
|
||||
while (digitalRead(pin) != (state)) { \
|
||||
if (xthal_get_ccount() - start_cycle_count > timeout_cycles) { \
|
||||
if (cpu_hal_get_cycle_count() - start_cycle_count > timeout_cycles) { \
|
||||
return 0; \
|
||||
} \
|
||||
}
|
||||
@ -36,12 +34,12 @@ unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
|
||||
timeout = max_timeout_us;
|
||||
}
|
||||
const uint32_t timeout_cycles = microsecondsToClockCycles(timeout);
|
||||
const uint32_t start_cycle_count = xthal_get_ccount();
|
||||
const uint32_t start_cycle_count = cpu_hal_get_cycle_count();
|
||||
WAIT_FOR_PIN_STATE(!state);
|
||||
WAIT_FOR_PIN_STATE(state);
|
||||
const uint32_t pulse_start_cycle_count = xthal_get_ccount();
|
||||
const uint32_t pulse_start_cycle_count = cpu_hal_get_cycle_count();
|
||||
WAIT_FOR_PIN_STATE(!state);
|
||||
return clockCyclesToMicroseconds(xthal_get_ccount() - pulse_start_cycle_count);
|
||||
return clockCyclesToMicroseconds(cpu_hal_get_cycle_count() - pulse_start_cycle_count);
|
||||
}
|
||||
|
||||
unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout)
|
||||
|
122
docs/EXAMPLE_README_TEMPLATE.md
Normal file
@ -0,0 +1,122 @@
|
||||
# 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)
|
28
docs/Makefile
Normal file
@ -0,0 +1,28 @@
|
||||
# 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)
|
@ -1,59 +0,0 @@
|
||||
# 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
|
||||
|
||||

|
||||
|
||||
- Upload sketch (Ctrl+U)
|
||||
- Now open web browser and enter the url, i.e. http://esp32.local. Once entered, browser should display a form
|
||||
|
||||

|
||||
|
||||
> username= admin
|
||||
|
||||
> password= admin
|
||||
|
||||
**Note**-*If entering “http://ESP32.local” does not work, try replacing “ESP32” with module’s 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
|
||||
|
||||

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

|
||||
|
||||
- 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
|
||||
|
||||
|
||||
|
@ -1,12 +0,0 @@
|
||||
## 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 (x86, amd64, armhf and arm64).
|
||||
|
||||
- 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).
|
@ -1,36 +0,0 @@
|
||||
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
|
||||
```
|
@ -1,18 +0,0 @@
|
||||
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
|
@ -1,29 +0,0 @@
|
||||
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 --depth 1 && \
|
||||
cd esp32 && \
|
||||
git submodule update --init --recursive --depth 1 && \
|
||||
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
|
||||
|
@ -1,22 +0,0 @@
|
||||
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
|
@ -1,49 +0,0 @@
|
||||
## Steps to install Arduino ESP32 support on Windows
|
||||
### Tested on 32 and 64 bit Windows 10 machines
|
||||
|
||||
1. Download and install the latest Arduino IDE ```Windows Installer``` from [arduino.cc](https://www.arduino.cc/en/Main/Software)
|
||||
2. Download and install Git from [git-scm.com](https://git-scm.com/download/win)
|
||||
3. Start ```Git GUI``` and run through the following steps:
|
||||
- Select ```Clone Existing Repository```
|
||||
|
||||

|
||||
|
||||
- Select source and destination
|
||||
- Sketchbook Directory: Usually ```C:/Users/[YOUR_USER_NAME]/Documents/Arduino``` and is listed underneath the "Sketchbook location" in Arduino preferences.
|
||||
- Source Location: ```https://github.com/espressif/arduino-esp32.git```
|
||||
- Target Directory: ```[ARDUINO_SKETCHBOOK_DIR]/hardware/espressif/esp32```
|
||||
- Click ```Clone``` to start cloning the repository
|
||||
|
||||

|
||||

|
||||
- open a `Git Bash` session pointing to ```[ARDUINO_SKETCHBOOK_DIR]/hardware/espressif/esp32``` and execute ```git submodule update --init --recursive```
|
||||
- Open ```[ARDUINO_SKETCHBOOK_DIR]/hardware/espressif/esp32/tools``` and double-click ```get.exe```
|
||||
|
||||

|
||||
|
||||
- When ```get.exe``` finishes, you should see the following files in the directory
|
||||
|
||||

|
||||
|
||||
4. Plug your ESP32 board and wait for the drivers to install (or install manually any that might be required)
|
||||
5. Start Arduino IDE
|
||||
6. Select your board in ```Tools > Board``` menu
|
||||
7. Select the COM port that the board is attached to
|
||||
8. Compile and upload (You might need to hold the boot button while uploading)
|
||||
|
||||

|
||||
|
||||
### How to update to the latest code
|
||||
|
||||
1. Start ```Git GUI``` and you should see the repository under ```Open Recent Repository```. Click on it!
|
||||
|
||||

|
||||
|
||||
2. From menu ```Remote``` select ```Fetch from``` > ```origin```
|
||||
|
||||

|
||||
|
||||
3. Wait for git to pull any changes and close ```Git GUI```
|
||||
4. Open ```[ARDUINO_SKETCHBOOK_DIR]/hardware/espressif/esp32/tools``` and double-click ```get.exe```
|
||||
|
||||

|
@ -1,82 +0,0 @@
|
||||
To use as a component of ESP-IDF
|
||||
=================================================
|
||||
|
||||
## esp32-arduino-lib-builder
|
||||
|
||||
For a simplified method, see [lib-builder](lib_builder.md)
|
||||
|
||||
## Installation
|
||||
|
||||
- Download and install [esp-idf](https://github.com/espressif/esp-idf)
|
||||
- Create blank idf project (from one of the examples)
|
||||
- in the project folder, create a folder called components and clone this repository inside
|
||||
|
||||
```bash
|
||||
mkdir -p components && \
|
||||
cd components && \
|
||||
git clone https://github.com/espressif/arduino-esp32.git arduino && \
|
||||
cd arduino && \
|
||||
git submodule update --init --recursive && \
|
||||
cd ../.. && \
|
||||
make menuconfig
|
||||
```
|
||||
- ```make menuconfig``` has some Arduino options
|
||||
- "Autostart Arduino setup and loop on boot"
|
||||
- If you enable this options, your main.cpp should be formated like any other sketch
|
||||
|
||||
```arduino
|
||||
//file: main.cpp
|
||||
#include "Arduino.h"
|
||||
|
||||
void setup(){
|
||||
Serial.begin(115200);
|
||||
}
|
||||
|
||||
void loop(){
|
||||
Serial.println("loop");
|
||||
delay(1000);
|
||||
}
|
||||
```
|
||||
|
||||
- Else you need to implement ```app_main()``` and call ```initArduino();``` in it.
|
||||
|
||||
Keep in mind that setup() and loop() will not be called in this case.
|
||||
If you plan to base your code on examples provided in [esp-idf](https://github.com/espressif/esp-idf/tree/master/examples), please make sure move the app_main() function in main.cpp from the files in the example.
|
||||
|
||||
```arduino
|
||||
//file: main.cpp
|
||||
#include "Arduino.h"
|
||||
|
||||
extern "C" void app_main()
|
||||
{
|
||||
initArduino();
|
||||
pinMode(4, OUTPUT);
|
||||
digitalWrite(4, HIGH);
|
||||
//do your own thing
|
||||
}
|
||||
```
|
||||
- "Disable mutex locks for HAL"
|
||||
- If enabled, there will be no protection on the drivers from concurently accessing them from another thread/interrupt/core
|
||||
- "Autoconnect WiFi on boot"
|
||||
- If enabled, WiFi will start with the last known configuration
|
||||
- Else it will wait for WiFi.begin
|
||||
- ```make flash monitor``` will build, upload and open serial monitor to your board
|
||||
|
||||
## Logging To Serial
|
||||
|
||||
If you are writing code that does not require Arduino to compile and you want your `ESP_LOGx` macros to work in Arduino IDE, you can enable the compatibility by adding the following lines after your includes:
|
||||
|
||||
```cpp
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "esp32-hal-log.h"
|
||||
#endif
|
||||
```
|
||||
|
||||
## FreeRTOS Tick Rate (Hz)
|
||||
|
||||
You might notice that Arduino-esp32's `delay()` function will only work in multiples of 10ms. That is because, by default, esp-idf handles task events 100 times per second.
|
||||
To fix that behavior you need to set FreeRTOS tick rate to 1000Hz in `make menuconfig` -> `Component config` -> `FreeRTOS` -> `Tick rate`.
|
||||
|
||||
## Compilation Errors
|
||||
|
||||
As commits are made to esp-idf and submodules, the codebases can develop incompatibilities which cause compilation errors. If you have problems compiling, follow the instructions in [Issue #1142](https://github.com/espressif/arduino-esp32/issues/1142) to roll esp-idf back to a known good version.
|
Before Width: | Height: | Size: 510 KiB |
@ -1,14 +0,0 @@
|
||||
## Using esp32-arduino-lib-builder to compile custom libraries
|
||||
|
||||
Espressif has provided a [tool](https://github.com/espressif/esp32-arduino-lib-builder) to simplify building your own compiled libraries for use in Arduino IDE (or your favorite IDE).
|
||||
To use it to generate custom libraries, follow these steps:
|
||||
1. `git clone https://github.com/espressif/esp32-arduino-lib-builder`
|
||||
2. `cd esp32-arduino-lib-builder`
|
||||
3. `./tools/update-components.sh`
|
||||
4. `./tools/install-esp-idf.sh` (if you already have an $IDF_PATH defined, it will use your local copy of the repository)
|
||||
5. `make menuconfig` or directly edit sdkconfig.
|
||||
6. `./build.sh`
|
||||
|
||||
The script automates the process of building [arduino as an ESP-IDF component](https://github.com/espressif/arduino-esp32/blob/master/docs/esp-idf_component.md).
|
||||
Once it is complete, you can cherry pick the needed libraries from `out/tools/sdk/lib`, or run `tools/copy-to-arduino.sh` to copy the entire built system.
|
||||
`tools/config.sh` contains a number of variables that control the process, particularly the $IDF_BRANCH variable. You can adjust this to try building against newer versions, but there are absolutely no guarantees that any components will work or even successfully compile against a newer IDF.
|
35
docs/make.bat
Normal file
@ -0,0 +1,35 @@
|
||||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=source
|
||||
set BUILDDIR=build
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
|
||||
:end
|
||||
popd
|
@ -1,4 +0,0 @@
|
||||
To use make
|
||||
============
|
||||
|
||||
[makeEspArduino](https://github.com/plerup/makeEspArduino) is a generic makefile for any ESP8266/ESP32 Arduino project.Using make instead of the Arduino IDE makes it easier to do automated and production builds.
|
@ -1,11 +0,0 @@
|
||||
Installation instructions for using PlatformIO
|
||||
=================================================
|
||||
|
||||
- [What is PlatformIO?](https://docs.platformio.org/en/latest/what-is-platformio.html?utm_source=github&utm_medium=arduino-esp32)
|
||||
- [PlatformIO IDE](https://platformio.org/platformio-ide?utm_source=github&utm_medium=arduino-esp32)
|
||||
- [PlatformIO Core](https://docs.platformio.org/en/latest/core.html?utm_source=github&utm_medium=arduino-esp32) (command line tool)
|
||||
- [Advanced usage](https://docs.platformio.org/en/latest/platforms/espressif32.html?utm_source=github&utm_medium=arduino-esp32) -
|
||||
custom settings, uploading to SPIFFS, Over-the-Air (OTA), staging version
|
||||
- [Integration with Cloud and Standalone IDEs](https://docs.platformio.org/en/latest/ide.html?utm_source=github&utm_medium=arduino-esp32) -
|
||||
Cloud9, Codeanywhere, Eclipse Che (Codenvy), Atom, CLion, Eclipse, Emacs, NetBeans, Qt Creator, Sublime Text, VIM, Visual Studio, and VSCode
|
||||
- [Project Examples](https://docs.platformio.org/en/latest/platforms/espressif32.html?utm_source=github&utm_medium=arduino-esp32#examples)
|
5
docs/requirements.txt
Normal file
@ -0,0 +1,5 @@
|
||||
# This is a list of python packages used to generate documentation. This file is used with pip:
|
||||
# pip install --user -r requirements.txt
|
||||
#
|
||||
# matplotlib is currently required only by the script generate_chart.py
|
||||
sphinx-copybutton==0.3.0
|
Before Width: | Height: | Size: 186 KiB After Width: | Height: | Size: 186 KiB |
BIN
docs/source/_static/esp32-c3_devkitM-1_pinlayout.png
Normal file
After Width: | Height: | Size: 1.1 MiB |
BIN
docs/source/_static/esp32-s2_saola1_pinlayout.png
Normal file
After Width: | Height: | Size: 1.7 MiB |
BIN
docs/source/_static/esp32_devkitC_pinlayout.png
Normal file
After Width: | Height: | Size: 1.5 MiB |
BIN
docs/source/_static/install_guide_boards_manager_esp32.png
Normal file
After Width: | Height: | Size: 22 KiB |