SC-F001 way better logging and parameters. not integrated yet but.
This commit is contained in:
@@ -0,0 +1 @@
|
||||
--ignore-dir=build
|
||||
@@ -0,0 +1,17 @@
|
||||
--align-reference=name
|
||||
--attach-classes
|
||||
--attach-classes
|
||||
--attach-namespaces
|
||||
--convert-tabs
|
||||
--exclude=build
|
||||
--exclude=common
|
||||
--exclude=managed_components
|
||||
--ignore-exclude-errors
|
||||
--indent-switches
|
||||
--indent=spaces=4
|
||||
--keep-one-line-statements
|
||||
--max-continuation-indent=120
|
||||
--pad-header
|
||||
--pad-oper
|
||||
--style=allman
|
||||
--unpad-paren
|
||||
@@ -0,0 +1,66 @@
|
||||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: WebKit
|
||||
AlignConsecutiveMacros: true
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: true
|
||||
AfterControlStatement: Always
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: true
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: true
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: false
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
ColumnLimit: 200
|
||||
CompactNamespaces: true
|
||||
Cpp11BracedListStyle: false
|
||||
FixNamespaceComments: true
|
||||
IndentCaseLabels: true
|
||||
IndentWidth: 4
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: Inner
|
||||
PointerAlignment: Right
|
||||
ReflowComments: true
|
||||
SortIncludes: false
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeInheritanceColon: false
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Auto
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
@@ -0,0 +1 @@
|
||||
a8049b1e609679fb54b2d57b0399dd29c4d1fda09a797edac9926f7810aa5703
|
||||
28
managed_components/esp-idf-lib__esp_idf_lib_helpers/.eil.yml
Normal file
28
managed_components/esp-idf-lib__esp_idf_lib_helpers/.eil.yml
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
name: esp_idf_lib_helpers
|
||||
description: Common support library for esp-idf-lib
|
||||
version: 1.3.10
|
||||
groups:
|
||||
- common
|
||||
code_owners:
|
||||
- trombik
|
||||
- UncleRus
|
||||
depends:
|
||||
- freertos
|
||||
thread_safe: n/a
|
||||
targets:
|
||||
- esp32
|
||||
- esp8266
|
||||
- esp32s2
|
||||
- esp32c3
|
||||
- esp32s3
|
||||
- esp32c2
|
||||
- esp32c6
|
||||
- esp32h2
|
||||
- esp32p4
|
||||
- esp32c5
|
||||
- esp32c61
|
||||
license: ISC
|
||||
copyrights:
|
||||
- name: trombik
|
||||
year: 2019
|
||||
7
managed_components/esp-idf-lib__esp_idf_lib_helpers/.gitignore
vendored
Normal file
7
managed_components/esp-idf-lib__esp_idf_lib_helpers/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
examples/**/sdkconfig
|
||||
examples/**/sdkconfig.old
|
||||
examples/**/build/
|
||||
examples/**/dependencies.lock
|
||||
docs/_*/
|
||||
docs/doxygen.log
|
||||
*.swp
|
||||
3
managed_components/esp-idf-lib__esp_idf_lib_helpers/.gitmodules
vendored
Normal file
3
managed_components/esp-idf-lib__esp_idf_lib_helpers/.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "common"]
|
||||
path = common
|
||||
url = https://github.com/esp-idf-lib/common.git
|
||||
@@ -0,0 +1,12 @@
|
||||
idf_component_register(
|
||||
INCLUDE_DIRS .
|
||||
REQUIRES freertos
|
||||
)
|
||||
|
||||
# include common cmake file for components
|
||||
set(ESP_IDF_LIB_CMAKE ${CMAKE_CURRENT_LIST_DIR}/common/cmake/esp-idf-lib.cmake)
|
||||
if(EXISTS ${ESP_IDF_LIB_CMAKE})
|
||||
include(${ESP_IDF_LIB_CMAKE})
|
||||
else()
|
||||
message(WARNING "${ESP_IDF_LIB_CMAKE} not found")
|
||||
endif()
|
||||
13
managed_components/esp-idf-lib__esp_idf_lib_helpers/LICENSE
Normal file
13
managed_components/esp-idf-lib__esp_idf_lib_helpers/LICENSE
Normal file
@@ -0,0 +1,13 @@
|
||||
Copyright (c) 2019 Tomoyuki Sakurai <y@trombik.org>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
@@ -0,0 +1,30 @@
|
||||
# esp-idf-lib/esp_idf_lib_helpers
|
||||
|
||||
[](https://github.com/esp-idf-lib/esp_idf_lib_helpers/actions/workflows//build.yml)
|
||||
[](https://github.com/esp-idf-lib/esp_idf_lib_helpers/actions/workflows//build-docs.yml)
|
||||
[](https://github.com/esp-idf-lib/esp_idf_lib_helpers/actions/workflows//validate-component.yml)
|
||||
|
||||
Common support library for esp-idf-lib.
|
||||
|
||||
* [Documentation](https://esp-idf-lib.github.io/esp_idf_lib_helpers/)
|
||||
* [Repository](https://github.com/esp-idf-lib/esp_idf_lib_helpers)
|
||||
* [Issues](https://github.com/esp-idf-lib/esp_idf_lib_helpers/issues)
|
||||
* [Discussions and questions](https://github.com/esp-idf-lib/core/discussions)
|
||||
* [Component page at the ESP Component Registry](https://components.espressif.com/components/esp-idf-lib/esp_idf_lib_helpers)
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
idf.py add-dependency esp-idf-lib/esp_idf_lib_helpers
|
||||
```
|
||||
|
||||
## Support
|
||||
|
||||
For questions and discussions about the component, please use
|
||||
[Discussions](https://github.com/esp-idf-lib/core/discussions)
|
||||
at [esp-idf-lib/core](https://github.com/esp-idf-lib/core).
|
||||
|
||||
## Contributing
|
||||
|
||||
Please read [CONTRIBUTING.md](https://github.com/esp-idf-lib/core/blob/main/CONTRIBUTING.md)
|
||||
at [esp-idf-lib/core](https://github.com/esp-idf-lib/core).
|
||||
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require "pathname"
|
||||
require "yaml"
|
||||
|
||||
# A simple CLI to get values in .eil.yml
|
||||
|
||||
key = ARGV.shift
|
||||
project_root = Pathname.new(File.expand_path(__FILE__)).parent.parent
|
||||
eil_file = project_root / ".eil.yml"
|
||||
doc = YAML.safe_load(File.read eil_file)
|
||||
|
||||
case key
|
||||
when "copyright_string"
|
||||
puts doc["copyrights"].map { |e| "#{e['year']}, #{e['name']}" }.join(", ")
|
||||
else
|
||||
puts doc[key]
|
||||
end
|
||||
@@ -0,0 +1,36 @@
|
||||
# Set common build flags but enable them only when the build is in our CI,
|
||||
# making them optional. The idea is, fail when compiled in our CI but just
|
||||
# warn in any other cases. Code that compiles with one toolchain warning-free
|
||||
# may not do so with another toolchain, which creates a project dependency on
|
||||
# specific toolchain vendors and versions.
|
||||
#
|
||||
# Define flags that may cause failures here.
|
||||
if (DEFINED ENV{ESP_IDF_LIB_CI})
|
||||
set(ESP_IDF_LIB_CI_FLAGS
|
||||
-Werror=unused-variable
|
||||
-Werror=unused-function
|
||||
-Werror=write-strings
|
||||
-Werror
|
||||
)
|
||||
endif()
|
||||
|
||||
# Set common build flags. Mandatory.
|
||||
#
|
||||
# Define flags that do not cause failures here.
|
||||
set(ESP_IDF_LIB_FLAGS
|
||||
-Wextra
|
||||
-Wwrite-strings
|
||||
-Wunused-variable
|
||||
-Wunused-function
|
||||
-Wreturn-type
|
||||
)
|
||||
|
||||
# When COMPONENT_LIB is INTERFACE_LIBRARY, or a header-only library, do not
|
||||
# set the flags.
|
||||
get_target_property(COMPONENT_TYPE ${COMPONENT_LIB} TYPE)
|
||||
if(NOT COMPONENT_TYPE STREQUAL "INTERFACE_LIBRARY")
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE
|
||||
${ESP_IDF_LIB_FLAGS}
|
||||
${ESP_IDF_LIB_CI_FLAGS}
|
||||
)
|
||||
endif()
|
||||
@@ -0,0 +1,8 @@
|
||||
COMPONENT_ADD_INCLUDEDIRS = .
|
||||
|
||||
ifdef CONFIG_IDF_TARGET_ESP8266
|
||||
COMPONENT_DEPENDS = esp8266 freertos
|
||||
else
|
||||
COMPONENT_DEPENDS = freertos
|
||||
endif
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Tomoyuki Sakurai <y@trombik.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#if !defined(__ESP_IDF_LIB_HELPERS__H__)
|
||||
#define __ESP_IDF_LIB_HELPERS__H__
|
||||
|
||||
/* XXX this header file does not need to include freertos/FreeRTOS.h.
|
||||
* but without it, ESP8266 RTOS SDK does not include `sdkconfig.h` in correct
|
||||
* order. as this header depends on sdkconfig.h, sdkconfig.h must be included
|
||||
* first. however, the SDK includes this header first, then includes
|
||||
* `sdkconfig.h` when freertos/FreeRTOS.h is not explicitly included. an
|
||||
* evidence can be found in `build/${COMPONENT}/${COMPONENT}.d` in a failed
|
||||
* build.
|
||||
*/
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <esp_idf_version.h>
|
||||
|
||||
#if !defined(ESP_IDF_VERSION) || !defined(ESP_IDF_VERSION_VAL)
|
||||
#error Unknown ESP-IDF/ESP8266 RTOS SDK version
|
||||
#endif
|
||||
|
||||
/* Minimal supported version for ESP32, ESP32S2 */
|
||||
#define HELPER_ESP32_MIN_VER ESP_IDF_VERSION_VAL(3, 3, 5)
|
||||
/* Minimal supported version for ESP8266 */
|
||||
#define HELPER_ESP8266_MIN_VER ESP_IDF_VERSION_VAL(3, 3, 0)
|
||||
|
||||
/* HELPER_TARGET_IS_ESP32
|
||||
* 1 when the target is esp32
|
||||
*/
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32) \
|
||||
|| defined(CONFIG_IDF_TARGET_ESP32S2) \
|
||||
|| defined(CONFIG_IDF_TARGET_ESP32S3) \
|
||||
|| defined(CONFIG_IDF_TARGET_ESP32C2) \
|
||||
|| defined(CONFIG_IDF_TARGET_ESP32C3) \
|
||||
|| defined(CONFIG_IDF_TARGET_ESP32C5) \
|
||||
|| defined(CONFIG_IDF_TARGET_ESP32C6) \
|
||||
|| defined(CONFIG_IDF_TARGET_ESP32P4) \
|
||||
|| defined(CONFIG_IDF_TARGET_ESP32C61) \
|
||||
|| defined(CONFIG_IDF_TARGET_ESP32H2)
|
||||
#define HELPER_TARGET_IS_ESP32 (1)
|
||||
|
||||
/* HELPER_TARGET_IS_ESP8266
|
||||
* 1 when the target is esp8266
|
||||
*/
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP8266)
|
||||
#define HELPER_TARGET_IS_ESP8266 (1)
|
||||
#else
|
||||
#error BUG: cannot determine the target
|
||||
#endif
|
||||
|
||||
#if HELPER_TARGET_IS_ESP32 && ESP_IDF_VERSION < HELPER_ESP32_MIN_VER
|
||||
#error Unsupported ESP-IDF version. Please update!
|
||||
#endif
|
||||
|
||||
#if HELPER_TARGET_IS_ESP8266 && ESP_IDF_VERSION < HELPER_ESP8266_MIN_VER
|
||||
#error Unsupported ESP8266 RTOS SDK version. Please update!
|
||||
#endif
|
||||
|
||||
/* HELPER_SPI_HOST_DEFAULT
|
||||
*
|
||||
* The default SPI_HOST for spi_host_device_t
|
||||
*/
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define HELPER_SPI_HOST_DEFAULT HSPI_HOST
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
|
||||
#define HELPER_SPI_HOST_DEFAULT SPI2_HOST
|
||||
#elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32C61
|
||||
#define HELPER_SPI_HOST_DEFAULT SPI1_HOST
|
||||
#elif CONFIG_IDF_TARGET_ESP32H2
|
||||
#define HELPER_SPI_HOST_DEFAULT SPI1_HOST
|
||||
#elif CONFIG_IDF_TARGET_ESP32P4
|
||||
#define HELPER_SPI_HOST_DEFAULT SPI1_HOST
|
||||
#endif
|
||||
|
||||
/* show the actual values for debugging */
|
||||
#if DEBUG
|
||||
#define VALUE_TO_STRING(x) #x
|
||||
#define VALUE(x) VALUE_TO_STRING(x)
|
||||
#define VAR_NAME_VALUE(var) #var "=" VALUE(var)
|
||||
#pragma message(VAR_NAME_VALUE(CONFIG_IDF_TARGET_ESP32C3))
|
||||
#pragma message(VAR_NAME_VALUE(CONFIG_IDF_TARGET_ESP32H2))
|
||||
#pragma message(VAR_NAME_VALUE(CONFIG_IDF_TARGET_ESP32S2))
|
||||
#pragma message(VAR_NAME_VALUE(CONFIG_IDF_TARGET_ESP32))
|
||||
#pragma message(VAR_NAME_VALUE(CONFIG_IDF_TARGET_ESP8266))
|
||||
#pragma message(VAR_NAME_VALUE(ESP_IDF_VERSION_MAJOR))
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#include <esp32/rom/ets_sys.h>
|
||||
#elif CONFIG_IDF_TARGET_ESP32C2
|
||||
#include <esp32c2/rom/ets_sys.h>
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#include <esp32c3/rom/ets_sys.h>
|
||||
#elif CONFIG_IDF_TARGET_ESP32C5
|
||||
#include <esp32c5/rom/ets_sys.h>
|
||||
#elif CONFIG_IDF_TARGET_ESP32C6
|
||||
#include <esp32c6/rom/ets_sys.h>
|
||||
#elif CONFIG_IDF_TARGET_ESP32C61
|
||||
#include <esp32c61/rom/ets_sys.h>
|
||||
#elif CONFIG_IDF_TARGET_ESP32H2
|
||||
#include <esp32h2/rom/ets_sys.h>
|
||||
#elif CONFIG_IDF_TARGET_ESP32H4
|
||||
#include <esp32h4/rom/ets_sys.h>
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include <esp32s2/rom/ets_sys.h>
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#include <esp32s3/rom/ets_sys.h>
|
||||
#elif CONFIG_IDF_TARGET_ESP32P4
|
||||
#include <esp32p4/rom/ets_sys.h>
|
||||
#elif CONFIG_IDF_TARGET_ESP8266
|
||||
#include <rom/ets_sys.h>
|
||||
#else
|
||||
#error "ets_sys: Unknown target"
|
||||
#endif
|
||||
@@ -0,0 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(example_example)
|
||||
@@ -0,0 +1,5 @@
|
||||
#V := 1
|
||||
PROJECT_NAME := example_example
|
||||
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
@@ -0,0 +1,16 @@
|
||||
# Example application for `example` component
|
||||
|
||||
## What the example does
|
||||
|
||||
The example does nothing but waits in a loop.
|
||||
|
||||
## Configuration
|
||||
|
||||
No configuration is available.
|
||||
|
||||
## Notes
|
||||
|
||||
This is an example application of `example`. It is intended as an example
|
||||
application for new component.
|
||||
|
||||
The code under `main` should conform the code style.
|
||||
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -0,0 +1 @@
|
||||
COMPONENT_ADD_INCLUDEDIRS = .
|
||||
@@ -0,0 +1,5 @@
|
||||
dependencies:
|
||||
esp-idf-lib/esp_idf_lib_helpers:
|
||||
version: '*'
|
||||
description: default
|
||||
version: 1.0.0
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) YYYY YOUR NAME HERE <user@your.dom.ain>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_idf_lib_helpers.h>
|
||||
|
||||
#include "my_local_header.h"
|
||||
|
||||
static char *tag = "main";
|
||||
|
||||
void app_main()
|
||||
{
|
||||
ESP_LOGI(tag, "An example log");
|
||||
#if HELPER_TARGET_IS_ESP32
|
||||
ESP_LOGI(tag, "the target is ESP32");
|
||||
#else
|
||||
ESP_LOGI(tag, "the target is not ESP32");
|
||||
#endif
|
||||
while (1)
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) YYYY YOUR NAME HERE <user@your.dom.ain>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#if !defined(__MY_LOCAL_HEADER__H__)
|
||||
#define __MY_LOCAL_HEADER__H__
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
# add required non-default option for the example if any
|
||||
@@ -0,0 +1,29 @@
|
||||
dependencies: {}
|
||||
description: Common support library for esp-idf-lib
|
||||
discussion: https://github.com/esp-idf-lib/core/discussions
|
||||
documentation: https://esp-idf-lib.github.io/esp_idf_lib_helpers/
|
||||
files:
|
||||
exclude:
|
||||
- docs/**/*
|
||||
issues: https://github.com/esp-idf-lib/esp_idf_lib_helpers/issues
|
||||
license: ISC
|
||||
maintainers:
|
||||
- Tomoyuki Sakurai (@trombik) <y@trombik.org>
|
||||
- Ruslan V. Uss (@UncleRus) <unclerus@gmail.com>
|
||||
repository: git://github.com/esp-idf-lib/esp_idf_lib_helpers.git
|
||||
repository_info:
|
||||
commit_sha: 57bbd8f3cda9c5ad390fc3ea5585e0ad80672584
|
||||
path: .
|
||||
targets:
|
||||
- esp32
|
||||
- esp32c2
|
||||
- esp32c3
|
||||
- esp32c5
|
||||
- esp32c6
|
||||
- esp32c61
|
||||
- esp32h2
|
||||
- esp32p4
|
||||
- esp32s2
|
||||
- esp32s3
|
||||
url: https://github.com/esp-idf-lib/core
|
||||
version: 1.3.10
|
||||
1
managed_components/esp-idf-lib__i2cdev/.ackrc
Normal file
1
managed_components/esp-idf-lib__i2cdev/.ackrc
Normal file
@@ -0,0 +1 @@
|
||||
--ignore-dir=build
|
||||
17
managed_components/esp-idf-lib__i2cdev/.astylerc
Normal file
17
managed_components/esp-idf-lib__i2cdev/.astylerc
Normal file
@@ -0,0 +1,17 @@
|
||||
--align-reference=name
|
||||
--attach-classes
|
||||
--attach-classes
|
||||
--attach-namespaces
|
||||
--convert-tabs
|
||||
--exclude=build
|
||||
--exclude=common
|
||||
--exclude=managed_components
|
||||
--ignore-exclude-errors
|
||||
--indent-switches
|
||||
--indent=spaces=4
|
||||
--keep-one-line-statements
|
||||
--max-continuation-indent=120
|
||||
--pad-header
|
||||
--pad-oper
|
||||
--style=allman
|
||||
--unpad-paren
|
||||
66
managed_components/esp-idf-lib__i2cdev/.clang-format
Normal file
66
managed_components/esp-idf-lib__i2cdev/.clang-format
Normal file
@@ -0,0 +1,66 @@
|
||||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: WebKit
|
||||
AlignConsecutiveMacros: true
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: true
|
||||
AfterControlStatement: Always
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: true
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: true
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: false
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
ColumnLimit: 200
|
||||
CompactNamespaces: true
|
||||
Cpp11BracedListStyle: false
|
||||
FixNamespaceComments: true
|
||||
IndentCaseLabels: true
|
||||
IndentWidth: 4
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: Inner
|
||||
PointerAlignment: Right
|
||||
ReflowComments: true
|
||||
SortIncludes: false
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeInheritanceColon: false
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Auto
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
1
managed_components/esp-idf-lib__i2cdev/.component_hash
Normal file
1
managed_components/esp-idf-lib__i2cdev/.component_hash
Normal file
@@ -0,0 +1 @@
|
||||
11c08f9e1a7d346b5dd763196dc2567cf2209ae49042402c2c2d296624601c14
|
||||
28
managed_components/esp-idf-lib__i2cdev/.eil.yml
Normal file
28
managed_components/esp-idf-lib__i2cdev/.eil.yml
Normal file
@@ -0,0 +1,28 @@
|
||||
name: i2cdev
|
||||
description: ESP-IDF I2C master thread-safe utilities
|
||||
version: 2.0.8
|
||||
groups:
|
||||
- common
|
||||
code_owners:
|
||||
- UncleRus
|
||||
depends:
|
||||
- driver
|
||||
- freertos
|
||||
- esp_idf_lib_helpers
|
||||
thread_safe: yes
|
||||
targets:
|
||||
- esp32
|
||||
- esp8266
|
||||
- esp32s2
|
||||
- esp32c3
|
||||
- esp32s3
|
||||
- esp32c2
|
||||
- esp32c6
|
||||
- esp32h2
|
||||
- esp32p4
|
||||
- esp32c5
|
||||
- esp32c61
|
||||
license: MIT
|
||||
copyrights:
|
||||
- name: UncleRus
|
||||
year: 2018
|
||||
7
managed_components/esp-idf-lib__i2cdev/.gitignore
vendored
Normal file
7
managed_components/esp-idf-lib__i2cdev/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
examples/**/sdkconfig
|
||||
examples/**/sdkconfig.old
|
||||
examples/**/build/
|
||||
examples/**/dependencies.lock
|
||||
docs/_*/
|
||||
docs/doxygen.log
|
||||
*.swp
|
||||
3
managed_components/esp-idf-lib__i2cdev/.gitmodules
vendored
Normal file
3
managed_components/esp-idf-lib__i2cdev/.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "common"]
|
||||
path = common
|
||||
url = https://github.com/esp-idf-lib/common.git
|
||||
45
managed_components/esp-idf-lib__i2cdev/CMakeLists.txt
Normal file
45
managed_components/esp-idf-lib__i2cdev/CMakeLists.txt
Normal file
@@ -0,0 +1,45 @@
|
||||
# ESP-IDF CMake component for i2cdev library
|
||||
set(req driver freertos esp_idf_lib_helpers)
|
||||
|
||||
# ESP-IDF version detection for automatic driver selection
|
||||
# Check for manual override via Kconfig
|
||||
if(CONFIG_I2CDEV_USE_LEGACY_DRIVER)
|
||||
set(USE_LEGACY_DRIVER TRUE)
|
||||
message(STATUS "i2cdev: Manual override - using legacy driver (CONFIG_I2CDEV_USE_LEGACY_DRIVER=y)")
|
||||
elseif(NOT DEFINED IDF_VERSION_MAJOR)
|
||||
# In case older ESP-IDF versions that don't define IDF_VERSION_MAJOR
|
||||
set(USE_LEGACY_DRIVER TRUE)
|
||||
message(STATUS "i2cdev: IDF_VERSION_MAJOR not defined, using legacy driver")
|
||||
elseif(IDF_VERSION_MAJOR LESS 5)
|
||||
set(USE_LEGACY_DRIVER TRUE)
|
||||
message(STATUS "i2cdev: ESP-IDF v${IDF_VERSION_MAJOR}.x detected, using legacy driver")
|
||||
elseif(IDF_VERSION_MAJOR EQUAL 5 AND IDF_VERSION_MINOR LESS 3)
|
||||
set(USE_LEGACY_DRIVER TRUE)
|
||||
message(STATUS "i2cdev: ESP-IDF v${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR} detected, using legacy driver")
|
||||
else()
|
||||
set(USE_LEGACY_DRIVER FALSE)
|
||||
message(STATUS "i2cdev: ESP-IDF v${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR} detected, using new i2c_master driver")
|
||||
endif()
|
||||
|
||||
# Conditionally set the source file based on version detection or Kconfig override
|
||||
if(USE_LEGACY_DRIVER)
|
||||
set(SRCS "i2cdev_legacy.c")
|
||||
message(STATUS "i2cdev: Compiling with legacy I2C driver (i2cdev_legacy.c)")
|
||||
else()
|
||||
set(SRCS "i2cdev.c")
|
||||
message(STATUS "i2cdev: Compiling with new I2C master driver (i2cdev.c)")
|
||||
endif()
|
||||
|
||||
# Register the component
|
||||
idf_component_register(SRCS ${SRCS}
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES ${req})
|
||||
|
||||
|
||||
# include common cmake file for components
|
||||
set(ESP_IDF_LIB_CMAKE ${CMAKE_CURRENT_LIST_DIR}/common/cmake/esp-idf-lib.cmake)
|
||||
if(EXISTS ${ESP_IDF_LIB_CMAKE})
|
||||
include(${ESP_IDF_LIB_CMAKE})
|
||||
else()
|
||||
message(WARNING "${ESP_IDF_LIB_CMAKE} not found")
|
||||
endif()
|
||||
65
managed_components/esp-idf-lib__i2cdev/Kconfig
Normal file
65
managed_components/esp-idf-lib__i2cdev/Kconfig
Normal file
@@ -0,0 +1,65 @@
|
||||
menu "I2C Device Library"
|
||||
|
||||
config I2CDEV_USE_LEGACY_DRIVER
|
||||
bool "Use Legacy I2C Driver API"
|
||||
default n
|
||||
help
|
||||
Select this option to use the older ESP-IDF I2C driver API (driver/i2c.h)
|
||||
instead of the newer driver API (driver/i2c_master.h).
|
||||
|
||||
This is automatically determined by the build system based on your ESP-IDF version.
|
||||
For ESP-IDF versions prior to v5.3, the legacy driver will be used automatically.
|
||||
You can manually override this setting if needed.
|
||||
|
||||
config I2CDEV_AUTO_ENABLE_PULLUPS
|
||||
bool "Automatically enable internal I2C pullups when not configured"
|
||||
default n
|
||||
depends on !IDF_TARGET_ESP8266
|
||||
help
|
||||
When enabled, internal pullup resistors are automatically enabled
|
||||
when both sda_pullup_en and scl_pullup_en are false (default state).
|
||||
|
||||
Useful for development and prototyping. Disable for production
|
||||
systems with external pullups to avoid interference.
|
||||
|
||||
Considerations:
|
||||
- May increase power consumption slightly
|
||||
- Could interfere with carefully tuned external pullups
|
||||
- Not recommended for battery-powered applications
|
||||
|
||||
Note: This option only affects the modern i2cdev driver (ESP32 family).
|
||||
Legacy driver behavior is unchanged for compatibility.
|
||||
|
||||
config I2CDEV_DEFAULT_SDA_PIN
|
||||
int "Default I2C SDA pin"
|
||||
default 21
|
||||
help
|
||||
Default SDA pin for I2C devices.
|
||||
|
||||
config I2CDEV_DEFAULT_SCL_PIN
|
||||
int "Default I2C SCL pin"
|
||||
default 22
|
||||
help
|
||||
Default SCL pin for I2C devices.
|
||||
|
||||
config I2CDEV_MAX_DEVICES_PER_PORT
|
||||
int "Maximum number of devices per I2C port"
|
||||
default 8
|
||||
help
|
||||
Maximum number of devices that can be registered on a single I2C port.
|
||||
|
||||
config I2CDEV_TIMEOUT
|
||||
int "I2C transaction timeout, milliseconds"
|
||||
default 1000
|
||||
range 10 5000
|
||||
|
||||
config I2CDEV_NOLOCK
|
||||
bool "Disable the use of mutexes"
|
||||
default n
|
||||
help
|
||||
Attention! After enabling this option, all I2C device
|
||||
drivers will become non-thread safe.
|
||||
Use this option if you need to access your I2C devices
|
||||
from interrupt handlers.
|
||||
|
||||
endmenu
|
||||
19
managed_components/esp-idf-lib__i2cdev/Kconfig.i2c
Normal file
19
managed_components/esp-idf-lib__i2cdev/Kconfig.i2c
Normal file
@@ -0,0 +1,19 @@
|
||||
config EXAMPLE_I2C_MASTER_SCL
|
||||
int "SCL GPIO Number"
|
||||
default 5 if IDF_TARGET_ESP8266
|
||||
default 6 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C5 || IDF_TARGET_ESP32C6 || IDF_TARGET_ESP32C61
|
||||
default 19 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
||||
default 4 if IDF_TARGET_ESP32H2
|
||||
default 4 if IDF_TARGET_ESP32P4
|
||||
help
|
||||
GPIO number for I2C Master clock line.
|
||||
|
||||
config EXAMPLE_I2C_MASTER_SDA
|
||||
int "SDA GPIO Number"
|
||||
default 4 if IDF_TARGET_ESP8266
|
||||
default 5 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C5 || IDF_TARGET_ESP32C6 || IDF_TARGET_ESP32C61
|
||||
default 18 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
||||
default 3 if IDF_TARGET_ESP32H2
|
||||
default 3 if IDF_TARGET_ESP32P4
|
||||
help
|
||||
GPIO number for I2C Master data line.
|
||||
21
managed_components/esp-idf-lib__i2cdev/LICENSE
Normal file
21
managed_components/esp-idf-lib__i2cdev/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 Ruslan V. Uss (https://github.com/UncleRus)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
30
managed_components/esp-idf-lib__i2cdev/README.md
Normal file
30
managed_components/esp-idf-lib__i2cdev/README.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# esp-idf-lib/i2cdev
|
||||
|
||||
[](https://github.com/esp-idf-lib/i2cdev/actions/workflows//build.yml)
|
||||
[](https://github.com/esp-idf-lib/i2cdev/actions/workflows//build-docs.yml)
|
||||
[](https://github.com/esp-idf-lib/i2cdev/actions/workflows//validate-component.yml)
|
||||
|
||||
ESP-IDF I2C master thread-safe utilities.
|
||||
|
||||
* [Documentation](https://esp-idf-lib.github.io/i2cdev/)
|
||||
* [Repository](https://github.com/esp-idf-lib/i2cdev)
|
||||
* [Issues](https://github.com/esp-idf-lib/i2cdev/issues)
|
||||
* [Discussions and questions](https://github.com/esp-idf-lib/core/discussions)
|
||||
* [Component page at the ESP Component Registry](https://components.espressif.com/components/esp-idf-lib/i2cdev)
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
idf.py add-dependency esp-idf-lib/i2cdev
|
||||
```
|
||||
|
||||
## Support
|
||||
|
||||
For questions and discussions about the component, please use
|
||||
[Discussions](https://github.com/esp-idf-lib/core/discussions)
|
||||
at [esp-idf-lib/core](https://github.com/esp-idf-lib/core).
|
||||
|
||||
## Contributing
|
||||
|
||||
Please read [CONTRIBUTING.md](https://github.com/esp-idf-lib/core/blob/main/CONTRIBUTING.md)
|
||||
at [esp-idf-lib/core](https://github.com/esp-idf-lib/core).
|
||||
18
managed_components/esp-idf-lib__i2cdev/bin/eil-q
Normal file
18
managed_components/esp-idf-lib__i2cdev/bin/eil-q
Normal file
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require "pathname"
|
||||
require "yaml"
|
||||
|
||||
# A simple CLI to get values in .eil.yml
|
||||
|
||||
key = ARGV.shift
|
||||
project_root = Pathname.new(File.expand_path(__FILE__)).parent.parent
|
||||
eil_file = project_root / ".eil.yml"
|
||||
doc = YAML.safe_load(File.read eil_file)
|
||||
|
||||
case key
|
||||
when "copyright_string"
|
||||
puts doc["copyrights"].map { |e| "#{e['year']}, #{e['name']}" }.join(", ")
|
||||
else
|
||||
puts doc[key]
|
||||
end
|
||||
@@ -0,0 +1,36 @@
|
||||
# Set common build flags but enable them only when the build is in our CI,
|
||||
# making them optional. The idea is, fail when compiled in our CI but just
|
||||
# warn in any other cases. Code that compiles with one toolchain warning-free
|
||||
# may not do so with another toolchain, which creates a project dependency on
|
||||
# specific toolchain vendors and versions.
|
||||
#
|
||||
# Define flags that may cause failures here.
|
||||
if (DEFINED ENV{ESP_IDF_LIB_CI})
|
||||
set(ESP_IDF_LIB_CI_FLAGS
|
||||
-Werror=unused-variable
|
||||
-Werror=unused-function
|
||||
-Werror=write-strings
|
||||
-Werror
|
||||
)
|
||||
endif()
|
||||
|
||||
# Set common build flags. Mandatory.
|
||||
#
|
||||
# Define flags that do not cause failures here.
|
||||
set(ESP_IDF_LIB_FLAGS
|
||||
-Wextra
|
||||
-Wwrite-strings
|
||||
-Wunused-variable
|
||||
-Wunused-function
|
||||
-Wreturn-type
|
||||
)
|
||||
|
||||
# When COMPONENT_LIB is INTERFACE_LIBRARY, or a header-only library, do not
|
||||
# set the flags.
|
||||
get_target_property(COMPONENT_TYPE ${COMPONENT_LIB} TYPE)
|
||||
if(NOT COMPONENT_TYPE STREQUAL "INTERFACE_LIBRARY")
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE
|
||||
${ESP_IDF_LIB_FLAGS}
|
||||
${ESP_IDF_LIB_CI_FLAGS}
|
||||
)
|
||||
endif()
|
||||
29
managed_components/esp-idf-lib__i2cdev/component.mk
Normal file
29
managed_components/esp-idf-lib__i2cdev/component.mk
Normal file
@@ -0,0 +1,29 @@
|
||||
COMPONENT_ADD_INCLUDEDIRS = .
|
||||
|
||||
ifdef CONFIG_IDF_TARGET_ESP8266
|
||||
COMPONENT_DEPENDS = esp8266 freertos esp_idf_lib_helpers
|
||||
# ESP8266 RTOS SDK auto-detects all .c files, so use COMPONENT_OBJS to override
|
||||
# This prevents both i2cdev.c and i2cdev_legacy.c from being compiled
|
||||
COMPONENT_OBJS := i2cdev_legacy.o
|
||||
COMPONENT_SRCDIRS := .
|
||||
else
|
||||
COMPONENT_DEPENDS = driver freertos esp_idf_lib_helpers
|
||||
# For ESP32 family, check for manual override first
|
||||
ifdef CONFIG_I2CDEV_USE_LEGACY_DRIVER
|
||||
COMPONENT_SRCS = i2cdev_legacy.c
|
||||
else
|
||||
# Check if version variables are available, fallback to legacy if not
|
||||
ifdef IDF_VERSION_MAJOR
|
||||
ifeq ($(shell test $(IDF_VERSION_MAJOR) -lt 5 && echo 1),1)
|
||||
COMPONENT_SRCS = i2cdev_legacy.c
|
||||
else ifeq ($(shell test $(IDF_VERSION_MAJOR) -eq 5 -a $(IDF_VERSION_MINOR) -lt 3 && echo 1),1)
|
||||
COMPONENT_SRCS = i2cdev_legacy.c
|
||||
else
|
||||
COMPONENT_SRCS = i2cdev.c
|
||||
endif
|
||||
else
|
||||
# Version variables not available - fallback to legacy driver for safety
|
||||
COMPONENT_SRCS = i2cdev_legacy.c
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
@@ -0,0 +1,7 @@
|
||||
# The following four lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(i2c_scanner)
|
||||
@@ -0,0 +1,5 @@
|
||||
#V := 1
|
||||
PROJECT_NAME := i2c_scanner
|
||||
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
@@ -0,0 +1,31 @@
|
||||
# I2C bus scanner
|
||||
|
||||
## What it does
|
||||
|
||||
This example scans the i2c bus in a loop and prints out a table with the addresses of the found i2c devices.
|
||||
|
||||
## Wiring
|
||||
|
||||
Connect `SCL` and `SDA` pins to the following pins with appropriate pull-up
|
||||
resistors.
|
||||
|
||||
| Name | Description | Defaults |
|
||||
|------|-------------|----------|
|
||||
| `CONFIG_EXAMPLE_I2C_MASTER_SCL` | GPIO number for `SCL` | "5" for `esp8266`, "6" for `esp32c3`, "19" for `esp32`, `esp32s2`, and `esp32s3` |
|
||||
| `CONFIG_EXAMPLE_I2C_MASTER_SDA` | GPIO number for `SDA` | "4" for `esp8266`, "5" for `esp32c3`, "18" for `esp32`, `esp32s2`, and `esp32s3` |
|
||||
|
||||
## Example output
|
||||
|
||||
Three devices found on a bus: 0x38, 0x60 and 0x77
|
||||
|
||||
```
|
||||
0 1 2 3 4 5 6 7 8 9 a b c d e f
|
||||
00: -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
30: -- -- -- -- -- -- -- -- 38 -- -- -- -- -- -- --
|
||||
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
60: 60 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
70: -- -- -- -- -- -- -- 77
|
||||
```
|
||||
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -0,0 +1,7 @@
|
||||
menu "I2C scanner configuration"
|
||||
config EXAMPLE_I2C_CLOCK_HZ
|
||||
int "I2C clock frequency, Hz"
|
||||
default 100000
|
||||
|
||||
rsource "../../../Kconfig.i2c"
|
||||
endmenu
|
||||
@@ -0,0 +1 @@
|
||||
COMPONENT_ADD_INCLUDEDIRS = . include/
|
||||
@@ -0,0 +1,7 @@
|
||||
dependencies:
|
||||
esp-idf-lib/esp_idf_lib_helpers:
|
||||
version: '*'
|
||||
esp-idf-lib/i2cdev:
|
||||
version: '*'
|
||||
description: default
|
||||
version: 1.0.0
|
||||
@@ -0,0 +1,43 @@
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <i2cdev.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void task(void *ignore)
|
||||
{
|
||||
i2c_dev_t dev = { 0 };
|
||||
dev.cfg.sda_io_num = CONFIG_EXAMPLE_I2C_MASTER_SDA;
|
||||
dev.cfg.scl_io_num = CONFIG_EXAMPLE_I2C_MASTER_SCL;
|
||||
#if HELPER_TARGET_IS_ESP32
|
||||
dev.cfg.master.clk_speed = CONFIG_EXAMPLE_I2C_CLOCK_HZ; // 100kHz
|
||||
#endif
|
||||
while (1)
|
||||
{
|
||||
esp_err_t res;
|
||||
printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n");
|
||||
printf("00: ");
|
||||
for (uint8_t addr = 3; addr < 0x78; addr++)
|
||||
{
|
||||
if (addr % 16 == 0)
|
||||
printf("\n%.2x:", addr);
|
||||
|
||||
dev.addr = addr;
|
||||
res = i2c_dev_probe(&dev, I2C_DEV_WRITE);
|
||||
|
||||
if (res == 0)
|
||||
printf(" %.2x", addr);
|
||||
else
|
||||
printf(" --");
|
||||
}
|
||||
printf("\n\n");
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
}
|
||||
|
||||
void app_main()
|
||||
{
|
||||
// Init i2cdev library
|
||||
ESP_ERROR_CHECK(i2cdev_init());
|
||||
// Start task
|
||||
xTaskCreate(task, "i2c_scanner", configMINIMAL_STACK_SIZE * 3, NULL, 5, NULL);
|
||||
}
|
||||
897
managed_components/esp-idf-lib__i2cdev/i2cdev.c
Normal file
897
managed_components/esp-idf-lib__i2cdev/i2cdev.c
Normal file
@@ -0,0 +1,897 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 Ruslan V. Uss <unclerus@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file i2cdev.c
|
||||
*
|
||||
* ESP-IDF I2C master thread-safe functions for communication with I2C slave
|
||||
*
|
||||
* Copyright (C) 2018 Ruslan V. Uss <unclerus@gmail.com>
|
||||
* Updated 2025 by quinkq to use newer ESP-IDF I2C master driver API
|
||||
*
|
||||
* MIT Licensed as described in the file LICENSE
|
||||
*/
|
||||
|
||||
#include "i2cdev.h"
|
||||
#include <driver/i2c_master.h>
|
||||
#include <esp_log.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char *TAG = "i2cdev";
|
||||
|
||||
// Fallback definition for platforms without 10-bit address support
|
||||
#ifndef I2C_ADDR_BIT_LEN_10
|
||||
#define I2C_ADDR_BIT_LEN_10 1
|
||||
#endif
|
||||
|
||||
#define I2C_DEFAULT_FREQ_HZ 400000
|
||||
#define I2C_MAX_RETRIES 3
|
||||
#define I2C_RETRY_BASE_DELAY_MS 20
|
||||
#define I2CDEV_MAX_STACK_ALLOC_SIZE 32 // Stack allocation threshold to avoid heap fragmentation for small buffers
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SemaphoreHandle_t lock; // Mutex for exclusive access to this port's state
|
||||
i2c_master_bus_handle_t bus_handle; // Handle to the initialized I2C master bus
|
||||
bool installed; // Flag indicating if the bus for this port has been installed
|
||||
uint32_t ref_count; // Number of devices currently active on this bus port
|
||||
int sda_pin_current; // Actual SDA pin the bus was initialized with
|
||||
int scl_pin_current; // Actual SCL pin the bus was initialized with
|
||||
} i2c_port_state_t;
|
||||
|
||||
static i2c_port_state_t i2c_ports[I2C_NUM_MAX] = { 0 };
|
||||
static i2c_dev_t *active_devices[I2C_NUM_MAX][CONFIG_I2CDEV_MAX_DEVICES_PER_PORT] = { { NULL } };
|
||||
|
||||
// Helper to register a device
|
||||
static esp_err_t register_device(i2c_dev_t *dev)
|
||||
{
|
||||
if (!dev)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
int port = dev->port;
|
||||
if (port >= I2C_NUM_MAX)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
|
||||
// Note: Port mutex should be held by caller
|
||||
for (int i = 0; i < CONFIG_I2CDEV_MAX_DEVICES_PER_PORT; i++)
|
||||
{
|
||||
if (active_devices[port][i] == NULL)
|
||||
{
|
||||
active_devices[port][i] = dev;
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Registered device in slot %d", dev->addr, port, i);
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] No free slots to register device - limit reached", dev->addr, port);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
// Helper to deregister a device
|
||||
static void deregister_device(i2c_dev_t *dev)
|
||||
{
|
||||
if (!dev)
|
||||
return;
|
||||
int port = dev->port;
|
||||
if (port >= I2C_NUM_MAX)
|
||||
return;
|
||||
for (int i = 0; i < CONFIG_I2CDEV_MAX_DEVICES_PER_PORT; i++)
|
||||
{
|
||||
if (active_devices[port][i] == dev)
|
||||
{
|
||||
active_devices[port][i] = NULL;
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Deregistered device from slot %d", dev->addr, port, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t i2cdev_init(void)
|
||||
{
|
||||
ESP_LOGV(TAG, "Initializing I2C subsystem...");
|
||||
memset(active_devices, 0, sizeof(active_devices));
|
||||
for (int i = 0; i < I2C_NUM_MAX; i++)
|
||||
{
|
||||
if (!i2c_ports[i].lock)
|
||||
{
|
||||
i2c_ports[i].lock = xSemaphoreCreateMutex();
|
||||
if (!i2c_ports[i].lock)
|
||||
{
|
||||
ESP_LOGE(TAG, "Could not create port mutex %d", i);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
ESP_LOGV(TAG, "Created port mutex %d", i);
|
||||
}
|
||||
i2c_ports[i].installed = false;
|
||||
i2c_ports[i].ref_count = 0;
|
||||
i2c_ports[i].bus_handle = NULL;
|
||||
i2c_ports[i].sda_pin_current = -1;
|
||||
i2c_ports[i].scl_pin_current = -1;
|
||||
}
|
||||
ESP_LOGV(TAG, "I2C subsystem initialized.");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2c_dev_create_mutex(i2c_dev_t *dev)
|
||||
{
|
||||
#if !CONFIG_I2CDEV_NOLOCK
|
||||
if (!dev)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Creating device mutex...", dev->addr, dev->port);
|
||||
if (dev->mutex)
|
||||
{
|
||||
ESP_LOGW(TAG, "[0x%02x at %d] device mutex already exists (Handle: %p)", dev->addr, dev->port, dev->mutex);
|
||||
return ESP_OK; // Already created
|
||||
}
|
||||
|
||||
dev->mutex = xSemaphoreCreateMutex();
|
||||
if (!dev->mutex)
|
||||
{
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] Could not create device mutex", dev->addr, dev->port);
|
||||
return ESP_ERR_NO_MEM; // Use ESP_ERR_NO_MEM for memory allocation failures
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Device mutex created (Handle: %p)", dev->addr, dev->port, dev->mutex);
|
||||
|
||||
// Register the device for cleanup tracking (under port mutex for consistency)
|
||||
if (dev->port < I2C_NUM_MAX && i2c_ports[dev->port].lock)
|
||||
{
|
||||
if (xSemaphoreTake(i2c_ports[dev->port].lock, pdMS_TO_TICKS(CONFIG_I2CDEV_TIMEOUT)) == pdTRUE)
|
||||
{
|
||||
esp_err_t reg_res = register_device(dev);
|
||||
if (reg_res != ESP_OK)
|
||||
{
|
||||
ESP_LOGW(TAG, "[0x%02x at %d] Failed to register device: %s - device will work but cleanup tracking disabled", dev->addr, dev->port, esp_err_to_name(reg_res));
|
||||
// Continue - device can still function without registration tracking
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Device registered successfully for cleanup tracking", dev->addr, dev->port);
|
||||
}
|
||||
xSemaphoreGive(i2c_ports[dev->port].lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGW(TAG, "[0x%02x at %d] Could not take port mutex for device registration", dev->addr, dev->port);
|
||||
// Continue - device can still function without registration tracking
|
||||
}
|
||||
}
|
||||
|
||||
// Set default address bit length if not explicitly set
|
||||
if (dev->addr_bit_len != I2C_ADDR_BIT_LEN_7 && dev->addr_bit_len != I2C_ADDR_BIT_LEN_10)
|
||||
{
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Setting default 7-bit address format", dev->addr, dev->port);
|
||||
dev->addr_bit_len = I2C_ADDR_BIT_LEN_7;
|
||||
}
|
||||
#else
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Mutex creation skipped (CONFIG_I2CDEV_NOLOCK=1)", dev->addr, dev->port);
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2c_dev_delete_mutex(i2c_dev_t *dev)
|
||||
{
|
||||
#if !CONFIG_I2CDEV_NOLOCK
|
||||
if (!dev)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Deleting device mutex and cleaning up resources", dev->addr, dev->port);
|
||||
|
||||
// Remove device from bus if handle exists
|
||||
if (dev->dev_handle)
|
||||
{
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Removing device handle %p from bus", dev->addr, dev->port, dev->dev_handle);
|
||||
esp_err_t rm_res = i2c_master_bus_rm_device((i2c_master_dev_handle_t)dev->dev_handle);
|
||||
if (rm_res != ESP_OK)
|
||||
{
|
||||
ESP_LOGW(TAG, "[0x%02x at %d] Failed to remove device handle: %s", dev->addr, dev->port, esp_err_to_name(rm_res));
|
||||
// Continue with cleanup despite error
|
||||
}
|
||||
dev->dev_handle = NULL;
|
||||
}
|
||||
|
||||
// Deregister the device
|
||||
deregister_device(dev);
|
||||
|
||||
// Update port reference count if port is valid
|
||||
if (dev->port < I2C_NUM_MAX)
|
||||
{
|
||||
if (xSemaphoreTake(i2c_ports[dev->port].lock, pdMS_TO_TICKS(CONFIG_I2CDEV_TIMEOUT)) == pdTRUE)
|
||||
{
|
||||
if (i2c_ports[dev->port].installed && i2c_ports[dev->port].ref_count > 0)
|
||||
{
|
||||
i2c_ports[dev->port].ref_count--;
|
||||
ESP_LOGV(TAG, "[Port %d] Decremented ref_count to %" PRIu32, dev->port, i2c_ports[dev->port].ref_count);
|
||||
|
||||
// If last device on this port, delete the bus
|
||||
if (i2c_ports[dev->port].ref_count == 0)
|
||||
{
|
||||
ESP_LOGI(TAG, "[Port %d] Last device removed, cleaning up THIS port's bus", dev->port);
|
||||
// Just clean up this port's bus
|
||||
if (i2c_ports[dev->port].bus_handle)
|
||||
{
|
||||
ESP_LOGI(TAG, "[Port %d] Deleting bus handle %p", dev->port, i2c_ports[dev->port].bus_handle);
|
||||
esp_err_t del_bus_res = i2c_del_master_bus(i2c_ports[dev->port].bus_handle);
|
||||
if (del_bus_res != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "[Port %d] Failed to delete master bus: %s", dev->port, esp_err_to_name(del_bus_res));
|
||||
}
|
||||
i2c_ports[dev->port].bus_handle = NULL;
|
||||
}
|
||||
i2c_ports[dev->port].installed = false;
|
||||
i2c_ports[dev->port].sda_pin_current = -1;
|
||||
i2c_ports[dev->port].scl_pin_current = -1;
|
||||
}
|
||||
}
|
||||
xSemaphoreGive(i2c_ports[dev->port].lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGW(TAG, "[0x%02x at %d] Could not take port mutex for ref_count update", dev->addr, dev->port);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the mutex itself last
|
||||
if (dev->mutex)
|
||||
{
|
||||
vSemaphoreDelete(dev->mutex);
|
||||
dev->mutex = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Device mutex was NULL, nothing to delete", dev->addr, dev->port);
|
||||
}
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2c_dev_take_mutex(i2c_dev_t *dev)
|
||||
{
|
||||
#if !CONFIG_I2CDEV_NOLOCK
|
||||
if (!dev)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Attempting to take device mutex (Handle: %p)...", dev->addr, dev->port, dev->mutex);
|
||||
if (!dev->mutex)
|
||||
{
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] Attempt to take NULL device mutex!", dev->addr, dev->port);
|
||||
return ESP_ERR_INVALID_STATE; // Mutex doesn't exist
|
||||
}
|
||||
|
||||
TickType_t timeout_ticks = pdMS_TO_TICKS(CONFIG_I2CDEV_TIMEOUT);
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Taking device mutex with timeout %d ms (%lu ticks)", dev->addr, dev->port, CONFIG_I2CDEV_TIMEOUT, (unsigned long)timeout_ticks);
|
||||
if (!xSemaphoreTake(dev->mutex, timeout_ticks))
|
||||
{
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] Could not take device mutex (Timeout after %d ms)", dev->addr, dev->port, CONFIG_I2CDEV_TIMEOUT);
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Device mutex taken successfully.", dev->addr, dev->port);
|
||||
#else
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Mutex take skipped (CONFIG_I2CDEV_NOLOCK=1)", dev->addr, dev->port);
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2c_dev_give_mutex(i2c_dev_t *dev)
|
||||
{
|
||||
#if !CONFIG_I2CDEV_NOLOCK
|
||||
if (!dev)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Giving device mutex (Handle: %p)...", dev->addr, dev->port, dev->mutex);
|
||||
if (!dev->mutex)
|
||||
{
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] Attempt to give NULL device mutex!", dev->addr, dev->port);
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (!xSemaphoreGive(dev->mutex))
|
||||
{
|
||||
// This case should ideally not happen if the mutex was taken correctly
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] Could not give device mutex (Was it taken?) (Handle: %p)", dev->addr, dev->port, dev->mutex);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Device mutex given successfully.", dev->addr, dev->port);
|
||||
#else
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Mutex give skipped (CONFIG_I2CDEV_NOLOCK=1)", dev->addr, dev->port);
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// i2c_setup_port: Initializes the I2C master bus for a given port if not already done.
|
||||
// It uses pin configurations from dev->cfg.sda_io_num and dev->cfg.scl_io_num.
|
||||
// The pins for a port are fixed after the first device initializes it.
|
||||
static esp_err_t i2c_setup_port(i2c_dev_t *dev) // dev is non-const to update dev->sda_pin, dev->scl_pin
|
||||
{
|
||||
if (!dev)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
if (dev->port >= I2C_NUM_MAX)
|
||||
{
|
||||
ESP_LOGE(TAG, "Invalid I2C port number: %d", dev->port);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_err_t res = ESP_OK;
|
||||
i2c_port_state_t *port_state = &i2c_ports[dev->port];
|
||||
|
||||
ESP_LOGV(TAG, "[Port %d] Setup request for device 0x%02x", dev->port, dev->addr);
|
||||
if (xSemaphoreTake(port_state->lock, pdMS_TO_TICKS(CONFIG_I2CDEV_TIMEOUT)) != pdTRUE)
|
||||
{
|
||||
ESP_LOGE(TAG, "[Port %d] Could not take port mutex for setup", dev->port);
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
if (!port_state->installed)
|
||||
{
|
||||
// Pin Selection Logic: Use device-specified pins, fallback to Kconfig defaults if -1
|
||||
gpio_num_t sda_pin = (dev->cfg.sda_io_num == (gpio_num_t) -1) ? (gpio_num_t)CONFIG_I2CDEV_DEFAULT_SDA_PIN : dev->cfg.sda_io_num;
|
||||
gpio_num_t scl_pin = (dev->cfg.scl_io_num == (gpio_num_t) -1) ? (gpio_num_t)CONFIG_I2CDEV_DEFAULT_SCL_PIN : dev->cfg.scl_io_num;
|
||||
|
||||
// Validate pins (basic check, gpio_is_valid_gpio could be used for more robust check)
|
||||
if (sda_pin < 0 || scl_pin < 0)
|
||||
{
|
||||
ESP_LOGE(TAG, "[Port %d] Invalid SCL/SDA pins: SDA=%d, SCL=%d. Check driver or Kconfig defaults.", dev->port, sda_pin, scl_pin);
|
||||
xSemaphoreGive(port_state->lock);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/*
|
||||
* OPTIONAL I2C PULLUP AUTO-CONFIGURATION
|
||||
*
|
||||
* By default: Uses whatever sda_pullup_en/scl_pullup_en you set (usually false)
|
||||
*
|
||||
* When CONFIG_I2CDEV_AUTO_ENABLE_PULLUPS=y: If both pullup flags are false,
|
||||
* automatically change them to true to enable internal pullups (~45kΩ).
|
||||
*
|
||||
* Manual pullup configuration:
|
||||
* - Set sda_pullup_en=true, scl_pullup_en=true for internal pullups
|
||||
* - Set sda_pullup_en=false, scl_pullup_en=false for external pullups
|
||||
*/
|
||||
|
||||
// Read user's pullup configuration (default false if not set)
|
||||
bool sda_pullup = dev->cfg.sda_pullup_en;
|
||||
bool scl_pullup = dev->cfg.scl_pullup_en;
|
||||
|
||||
#if CONFIG_I2CDEV_AUTO_ENABLE_PULLUPS
|
||||
// CONFIG_I2CDEV_AUTO_ENABLE_PULLUPS=y: If user didn't configure pullups, enable them automatically
|
||||
if (!sda_pullup && !scl_pullup)
|
||||
{
|
||||
sda_pullup = true;
|
||||
scl_pullup = true;
|
||||
ESP_LOGI(TAG, "[Port %d] Auto-enabling internal pullups (CONFIG_I2CDEV_AUTO_ENABLE_PULLUPS=y)", dev->port);
|
||||
}
|
||||
#endif
|
||||
|
||||
ESP_LOGI(TAG,
|
||||
"[Port %d] First initialization. Configuring bus with SDA=%d, SCL=%d (Pullups "
|
||||
"SCL:%d SDA:%d)",
|
||||
dev->port, sda_pin, scl_pin, scl_pullup, sda_pullup);
|
||||
|
||||
i2c_master_bus_config_t bus_config =
|
||||
{
|
||||
.i2c_port = dev->port,
|
||||
.sda_io_num = sda_pin,
|
||||
.scl_io_num = scl_pin,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.glitch_ignore_cnt = 7,
|
||||
.flags.enable_internal_pullup = (sda_pullup || scl_pullup),
|
||||
// Bus speed is not set here. It's per-device or a global target for the bus can be set
|
||||
// if desired, but i2c_master supports per-device speeds.
|
||||
};
|
||||
|
||||
res = i2c_new_master_bus(&bus_config, &port_state->bus_handle);
|
||||
if (res == ESP_OK)
|
||||
{
|
||||
port_state->installed = true;
|
||||
port_state->ref_count = 0; // Will be incremented when a device is successfully added
|
||||
port_state->sda_pin_current = sda_pin;
|
||||
port_state->scl_pin_current = scl_pin;
|
||||
dev->sda_pin = sda_pin; // Update dev struct with actual pins used
|
||||
dev->scl_pin = scl_pin;
|
||||
ESP_LOGI(TAG, "[Port %d] Successfully installed I2C master bus (Handle: %p).", dev->port, port_state->bus_handle);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG, "[Port %d] Failed to create master bus: %d (%s)", dev->port, res, esp_err_to_name(res));
|
||||
port_state->installed = false;
|
||||
port_state->bus_handle = NULL;
|
||||
port_state->sda_pin_current = -1;
|
||||
port_state->scl_pin_current = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGV(TAG, "[Port %d] Port already installed (SDA=%d, SCL=%d, Handle: %p).", dev->port, port_state->sda_pin_current, port_state->scl_pin_current, port_state->bus_handle);
|
||||
// Pin Consistency Check: For subsequent devices, ensure pins match already-configured bus
|
||||
gpio_num_t sda_desired = (dev->cfg.sda_io_num == (gpio_num_t) -1) ? (gpio_num_t)port_state->sda_pin_current : dev->cfg.sda_io_num;
|
||||
gpio_num_t scl_desired = (dev->cfg.scl_io_num == (gpio_num_t) -1) ? (gpio_num_t)port_state->scl_pin_current : dev->cfg.scl_io_num;
|
||||
|
||||
if (sda_desired != port_state->sda_pin_current || scl_desired != port_state->scl_pin_current)
|
||||
{
|
||||
ESP_LOGE(TAG,
|
||||
"[Port %d] Pin mismatch for device 0x%02x! Bus on SDA=%d,SCL=%d. Device wants "
|
||||
"SDA=%d,SCL=%d",
|
||||
dev->port, dev->addr, port_state->sda_pin_current, port_state->scl_pin_current, sda_desired, scl_desired);
|
||||
res = ESP_ERR_INVALID_STATE; // Cannot change pins for an installed bus
|
||||
}
|
||||
else
|
||||
{
|
||||
dev->sda_pin = port_state->sda_pin_current; // Update dev struct with actual pins used
|
||||
dev->scl_pin = port_state->scl_pin_current;
|
||||
}
|
||||
// ref_count is managed by i2c_setup_device when adding/removing device handles
|
||||
}
|
||||
|
||||
xSemaphoreGive(port_state->lock);
|
||||
ESP_LOGV(TAG, "[Port %d] Port setup finished with res %d.", dev->port, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
// i2c_setup_device: Ensures port is set up and adds the device to the bus if not already added.
|
||||
// It also registers the device in active_devices for cleanup purposes.
|
||||
static esp_err_t i2c_setup_device(i2c_dev_t *dev) // dev is non-const - modifies dev->dev_handle, dev->addr_bit_len
|
||||
{
|
||||
if (!dev)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Setting up device context...", dev->addr, dev->port);
|
||||
|
||||
esp_err_t res = i2c_setup_port(dev);
|
||||
if (res != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] Port setup failed during device setup: %d (%s)", dev->addr, dev->port, res, esp_err_to_name(res));
|
||||
return res;
|
||||
}
|
||||
|
||||
// If addr_bit_len is not set (e.g. 0, which is invalid for i2c_addr_bit_len_t enum), default to
|
||||
// 7-bit. Modified to conditionally check for I2C_ADDR_BIT_LEN_10 based on hardware support
|
||||
if (dev->addr_bit_len != I2C_ADDR_BIT_LEN_7
|
||||
#if SOC_I2C_SUPPORT_10BIT_ADDR
|
||||
&& dev->addr_bit_len != I2C_ADDR_BIT_LEN_10
|
||||
#endif
|
||||
)
|
||||
{
|
||||
ESP_LOGD(TAG, "[0x%02x at %d] addr_bit_len not explicitly set, defaulting to 7-bit.", dev->addr, dev->port);
|
||||
dev->addr_bit_len = I2C_ADDR_BIT_LEN_7;
|
||||
}
|
||||
|
||||
// Only warn about address size if the device is actually using 10-bit addressing
|
||||
if (dev->addr_bit_len == I2C_ADDR_BIT_LEN_7 && dev->addr > 0x7F)
|
||||
{
|
||||
ESP_LOGW(TAG,
|
||||
"[0x%02x at %d] Device address > 0x7F but addr_bit_len is 7-bit. Ensure address "
|
||||
"is correct.",
|
||||
dev->addr, dev->port);
|
||||
}
|
||||
|
||||
#if !defined(SOC_I2C_SUPPORT_10BIT_ADDR) || !SOC_I2C_SUPPORT_10BIT_ADDR
|
||||
// On platforms without 10-bit support, force 7-bit addressing regardless of user setting
|
||||
if (dev->addr_bit_len == I2C_ADDR_BIT_LEN_10)
|
||||
{
|
||||
ESP_LOGW(TAG, "[0x%02x at %d] 10-bit addressing not supported on this platform, forcing 7-bit mode", dev->addr, dev->port);
|
||||
dev->addr_bit_len = I2C_ADDR_BIT_LEN_7;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (dev->dev_handle == NULL)
|
||||
{
|
||||
i2c_port_state_t *port_state = &i2c_ports[dev->port];
|
||||
if (xSemaphoreTake(port_state->lock, pdMS_TO_TICKS(CONFIG_I2CDEV_TIMEOUT)) != pdTRUE)
|
||||
{
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] Could not take port mutex for device add", dev->addr, dev->port);
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
if (!port_state->installed || !port_state->bus_handle)
|
||||
{
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] Cannot add device, bus for port %d not ready!", dev->addr, dev->port, dev->port);
|
||||
xSemaphoreGive(port_state->lock);
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Adding device to bus (Bus Handle: %p)...", dev->addr, dev->port, port_state->bus_handle);
|
||||
|
||||
uint32_t effective_dev_speed = dev->cfg.master.clk_speed;
|
||||
if (effective_dev_speed == 0)
|
||||
{
|
||||
ESP_LOGW(TAG,
|
||||
"[0x%02x at %d] Device speed (dev->cfg.master.clk_speed) is 0, using default: "
|
||||
"%" PRIu32 " Hz",
|
||||
dev->addr, dev->port, (uint32_t)I2C_DEFAULT_FREQ_HZ);
|
||||
effective_dev_speed = I2C_DEFAULT_FREQ_HZ;
|
||||
}
|
||||
|
||||
i2c_device_config_t dev_config =
|
||||
{
|
||||
// Use the possibly modified addr_bit_len that respects hardware capabilities
|
||||
.dev_addr_length = dev->addr_bit_len,
|
||||
.device_address = dev->addr,
|
||||
.scl_speed_hz = effective_dev_speed,
|
||||
.flags.disable_ack_check = false,
|
||||
};
|
||||
|
||||
res = i2c_master_bus_add_device(port_state->bus_handle, &dev_config, (i2c_master_dev_handle_t *)&dev->dev_handle);
|
||||
if (res == ESP_OK)
|
||||
{
|
||||
ESP_LOGI(TAG, "[0x%02x at %d] Device added successfully (Device Handle: %p, Speed: %" PRIu32 " Hz).", dev->addr, dev->port, dev->dev_handle, effective_dev_speed);
|
||||
|
||||
// Increment the port reference count for each device successfully added
|
||||
port_state->ref_count++;
|
||||
ESP_LOGV(TAG, "[Port %d] Incremented ref_count to %" PRIu32, dev->port, port_state->ref_count);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] Failed to add device to bus: %d (%s)", dev->addr, dev->port, res, esp_err_to_name(res));
|
||||
dev->dev_handle = NULL;
|
||||
}
|
||||
xSemaphoreGive(port_state->lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Device handle %p already exists. Skipping add.", dev->addr, dev->port, dev->dev_handle);
|
||||
res = ESP_OK;
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Device context setup finished with res %d.", dev->addr, dev->port, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Helper function with retry mechanism for I2C operations
|
||||
static esp_err_t i2c_do_operation_with_retry(i2c_dev_t *dev, esp_err_t (*i2c_func)(i2c_master_dev_handle_t, const void *, size_t, void *, size_t, int), const void *write_buffer, size_t write_size,
|
||||
void *read_buffer, size_t read_size)
|
||||
{
|
||||
if (!dev)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
esp_err_t res = ESP_FAIL;
|
||||
int retry = 0;
|
||||
int timeout_ms = CONFIG_I2CDEV_TIMEOUT;
|
||||
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Performing I2C operation (timeout %d ms)...", dev->addr, dev->port, timeout_ms);
|
||||
|
||||
while (retry <= I2C_MAX_RETRIES)
|
||||
{
|
||||
// Ensure device is set up before each attempt, in case handle became stale or bus was reset
|
||||
// This is more robust if issues like bus errors or device resets occur.
|
||||
res = i2c_setup_device(dev);
|
||||
if (res != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] Device setup failed (Try %d): %d (%s). Retrying setup...", dev->addr, dev->port, retry, res, esp_err_to_name(res));
|
||||
// No point continuing this attempt if setup fails, but the loop will retry setup.
|
||||
vTaskDelay(pdMS_TO_TICKS(I2C_RETRY_BASE_DELAY_MS * (1 << (retry))));
|
||||
retry++;
|
||||
continue;
|
||||
}
|
||||
if (!dev->dev_handle)
|
||||
{
|
||||
ESP_LOGE(TAG,
|
||||
"[0x%02x at %d] Device handle is NULL after setup (Try %d)! Cannot perform "
|
||||
"operation.",
|
||||
dev->addr, dev->port, retry);
|
||||
// This indicates a persistent problem with adding the device to the bus.
|
||||
// No point retrying the i2c_func if handle is null.
|
||||
res = ESP_ERR_INVALID_STATE;
|
||||
vTaskDelay(pdMS_TO_TICKS(I2C_RETRY_BASE_DELAY_MS * (1 << (retry))));
|
||||
retry++;
|
||||
continue;
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Attempting I2C op (Try %d, Handle %p)", dev->addr, dev->port, retry, dev->dev_handle);
|
||||
res = i2c_func(dev->dev_handle, write_buffer, write_size, read_buffer, read_size, timeout_ms);
|
||||
|
||||
if (res == ESP_OK)
|
||||
{
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] I2C operation successful (Try %d).", dev->addr, dev->port, retry);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
ESP_LOGW(TAG, "[0x%02x at %d] I2C op failed (Try %d, Handle %p): %d (%s).", dev->addr, dev->port, retry, dev->dev_handle, res, esp_err_to_name(res));
|
||||
|
||||
// Only remove handle on errors that indicate handle corruption or permanent invalidity
|
||||
// Don't remove on temporary errors like ESP_ERR_TIMEOUT, ESP_FAIL (NACK), etc.
|
||||
bool should_remove_handle = false;
|
||||
switch (res)
|
||||
{
|
||||
case ESP_ERR_INVALID_ARG:
|
||||
// Handle was likely removed by another task or is corrupted
|
||||
should_remove_handle = true;
|
||||
ESP_LOGW(TAG, "[0x%02x at %d] Invalid argument error - handle may be corrupted", dev->addr, dev->port);
|
||||
break;
|
||||
case ESP_ERR_INVALID_STATE:
|
||||
// I2C driver is in invalid state, handle likely needs recreation
|
||||
should_remove_handle = true;
|
||||
ESP_LOGW(TAG, "[0x%02x at %d] Invalid state error - handle may need recreation", dev->addr, dev->port);
|
||||
break;
|
||||
default:
|
||||
// For other errors (timeout, NACK, bus busy, etc.), keep the handle
|
||||
// These are usually temporary and don't require handle recreation
|
||||
should_remove_handle = false;
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Temporary error - keeping handle for retry", dev->addr, dev->port);
|
||||
break;
|
||||
}
|
||||
|
||||
if (should_remove_handle && dev->dev_handle)
|
||||
{
|
||||
ESP_LOGW(TAG, "[0x%02x at %d] Removing potentially corrupted device handle %p after permanent error", dev->addr, dev->port, dev->dev_handle);
|
||||
// Try to remove the handle from the bus before nullifying
|
||||
esp_err_t rm_res = i2c_master_bus_rm_device(dev->dev_handle);
|
||||
if (rm_res != ESP_OK)
|
||||
{
|
||||
ESP_LOGW(TAG, "[0x%02x at %d] Failed to remove corrupted handle (expected): %s", dev->addr, dev->port, esp_err_to_name(rm_res));
|
||||
// This is expected if the handle was already invalid - continue cleanup
|
||||
}
|
||||
dev->dev_handle = NULL;
|
||||
}
|
||||
|
||||
retry++;
|
||||
if (retry <= I2C_MAX_RETRIES)
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(I2C_RETRY_BASE_DELAY_MS * (1 << retry))); // Exponential backoff
|
||||
ESP_LOGW(TAG, "[0x%02x at %d] Retrying operation...", dev->addr, dev->port);
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] I2C operation failed after %d retries. Last error: %d (%s)", dev->addr, dev->port, I2C_MAX_RETRIES + 1, res, esp_err_to_name(res));
|
||||
return res;
|
||||
}
|
||||
|
||||
// Wrapper functions for the I2C master API to use with the retry mechanism
|
||||
// i2c_do_operation_with_retry() needs a unified function signature for all I2C operations
|
||||
static esp_err_t i2c_master_transmit_wrapper(i2c_master_dev_handle_t handle, const void *write_buffer, size_t write_size, void *read_buffer, size_t read_size, int timeout_ms)
|
||||
{
|
||||
return i2c_master_transmit(handle, write_buffer, write_size, timeout_ms);
|
||||
}
|
||||
|
||||
static esp_err_t i2c_master_receive_wrapper(i2c_master_dev_handle_t handle, const void *write_buffer, size_t write_size, void *read_buffer, size_t read_size, int timeout_ms)
|
||||
{
|
||||
return i2c_master_receive(handle, read_buffer, read_size, timeout_ms);
|
||||
}
|
||||
|
||||
static esp_err_t i2c_master_transmit_receive_wrapper(i2c_master_dev_handle_t handle, const void *write_buffer, size_t write_size, void *read_buffer, size_t read_size, int timeout_ms)
|
||||
{
|
||||
return i2c_master_transmit_receive(handle, write_buffer, write_size, read_buffer, read_size, timeout_ms);
|
||||
}
|
||||
|
||||
esp_err_t i2c_dev_read(const i2c_dev_t *dev, const void *out_data, size_t out_size, void *in_data, size_t in_size)
|
||||
{
|
||||
if (!dev || !in_data || !in_size)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] i2c_dev_read called (out_size: %u, in_size: %u)", dev->addr, dev->port, out_size, in_size);
|
||||
|
||||
esp_err_t result = i2c_do_operation_with_retry((i2c_dev_t *)dev, // Cast to non-const for i2c_setup_device internal modifications
|
||||
out_data && out_size ? i2c_master_transmit_receive_wrapper : i2c_master_receive_wrapper, out_data, out_size, in_data, in_size);
|
||||
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] i2c_dev_read result: %s (%d)", dev->addr, dev->port, esp_err_to_name(result), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
esp_err_t i2c_dev_write(const i2c_dev_t *dev, const void *out_reg, size_t out_reg_size, const void *out_data, size_t out_size)
|
||||
{
|
||||
if (!dev)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
if ((!out_reg || !out_reg_size) && (!out_data || !out_size))
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] i2c_dev_write called (reg_size: %u, data_size: %u)", dev->addr, dev->port, out_reg_size, out_size);
|
||||
|
||||
esp_err_t res;
|
||||
if (out_reg && out_reg_size && out_data && out_size)
|
||||
{
|
||||
size_t total_write_size = out_reg_size + out_size;
|
||||
|
||||
// Check for overflow before proceeding
|
||||
if (total_write_size < out_reg_size || total_write_size < out_size)
|
||||
{
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] Write size overflow: reg_size=%u + data_size=%u", dev->addr, dev->port, out_reg_size, out_size);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// Use stack for small buffers to avoid heap fragmentation
|
||||
if (total_write_size <= I2CDEV_MAX_STACK_ALLOC_SIZE)
|
||||
{
|
||||
// Use stack allocation for small buffers
|
||||
uint8_t stack_buf[I2CDEV_MAX_STACK_ALLOC_SIZE];
|
||||
memcpy(stack_buf, out_reg, out_reg_size);
|
||||
memcpy(stack_buf + out_reg_size, out_data, out_size);
|
||||
res = i2c_do_operation_with_retry((i2c_dev_t *)dev, i2c_master_transmit_wrapper, stack_buf, total_write_size, NULL, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t *heap_buf = malloc(total_write_size);
|
||||
if (!heap_buf)
|
||||
{
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] Failed to allocate %u bytes for write", dev->addr, dev->port, total_write_size);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
memcpy(heap_buf, out_reg, out_reg_size);
|
||||
memcpy(heap_buf + out_reg_size, out_data, out_size);
|
||||
res = i2c_do_operation_with_retry((i2c_dev_t *)dev, i2c_master_transmit_wrapper, heap_buf, total_write_size, NULL, 0);
|
||||
free(heap_buf); // Free buffer regardless of operation result
|
||||
}
|
||||
}
|
||||
else if (out_reg && out_reg_size)
|
||||
{
|
||||
res = i2c_do_operation_with_retry((i2c_dev_t *)dev, i2c_master_transmit_wrapper, out_reg, out_reg_size, NULL, 0);
|
||||
}
|
||||
else if (out_data && out_size)
|
||||
{
|
||||
res = i2c_do_operation_with_retry((i2c_dev_t *)dev, i2c_master_transmit_wrapper, out_data, out_size, NULL, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ESP_ERR_INVALID_ARG; // Shouldn't reach here given the earlier check
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] i2c_dev_write result: %s (%d)", dev->addr, dev->port, esp_err_to_name(res), res);
|
||||
return res;
|
||||
}
|
||||
|
||||
esp_err_t i2c_dev_read_reg(const i2c_dev_t *dev, uint8_t reg, void *data, size_t size)
|
||||
{
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] i2c_dev_read_reg called (reg: 0x%02x, size: %u)", dev->addr, dev->port, reg, size);
|
||||
return i2c_dev_read(dev, ®, 1, data, size);
|
||||
}
|
||||
|
||||
esp_err_t i2c_dev_write_reg(const i2c_dev_t *dev, uint8_t reg, const void *data, size_t size)
|
||||
{
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] i2c_dev_write_reg called (reg: 0x%02x, size: %u)", dev->addr, dev->port, reg, size);
|
||||
return i2c_dev_write(dev, ®, 1, data, size);
|
||||
}
|
||||
|
||||
esp_err_t i2c_dev_check_present(const i2c_dev_t *dev_const)
|
||||
{
|
||||
if (!dev_const)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Probing device presence...", dev_const->addr, dev_const->port);
|
||||
|
||||
// Cast to non-const for i2c_setup_port (which may modify internal state)
|
||||
i2c_dev_t *dev = (i2c_dev_t *)dev_const;
|
||||
|
||||
// Ensure the I2C port is set up before probing
|
||||
esp_err_t setup_res = i2c_setup_port(dev);
|
||||
if (setup_res != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] Failed to setup port for probe: %s", dev_const->addr, dev_const->port, esp_err_to_name(setup_res));
|
||||
return setup_res;
|
||||
}
|
||||
|
||||
// Now probe using the initialized bus
|
||||
if (dev_const->port < I2C_NUM_MAX && i2c_ports[dev_const->port].lock)
|
||||
{
|
||||
if (xSemaphoreTake(i2c_ports[dev_const->port].lock, pdMS_TO_TICKS(CONFIG_I2CDEV_TIMEOUT)) == pdTRUE)
|
||||
{
|
||||
if (i2c_ports[dev_const->port].installed && i2c_ports[dev_const->port].bus_handle)
|
||||
{
|
||||
// Use ESP-IDF's built-in probe function - completely non-intrusive
|
||||
esp_err_t probe_res = i2c_master_probe(i2c_ports[dev_const->port].bus_handle, dev_const->addr, CONFIG_I2CDEV_TIMEOUT);
|
||||
xSemaphoreGive(i2c_ports[dev_const->port].lock);
|
||||
|
||||
if (probe_res == ESP_OK)
|
||||
{
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Device probe successful - device present", dev_const->addr, dev_const->port);
|
||||
return ESP_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Device probe failed: %s", dev_const->addr, dev_const->port, esp_err_to_name(probe_res));
|
||||
return probe_res;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
xSemaphoreGive(i2c_ports[dev_const->port].lock);
|
||||
ESP_LOGW(TAG, "[0x%02x at %d] Cannot probe - bus not ready on port %d", dev_const->addr, dev_const->port, dev_const->port);
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] Could not take port mutex for probe", dev_const->addr, dev_const->port);
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] Invalid port or port not initialized", dev_const->addr, dev_const->port);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
// Compatibility wrapper for legacy code that still calls i2c_dev_probe
|
||||
// The new driver implementation uses i2c_master_probe which doesn't need operation_type
|
||||
esp_err_t i2c_dev_probe(const i2c_dev_t *dev, i2c_dev_type_t operation_type)
|
||||
{
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Legacy probe called (operation_type %d), redirecting to new implementation", dev->addr, dev->port, operation_type);
|
||||
|
||||
return i2c_dev_check_present(dev);
|
||||
}
|
||||
|
||||
// Clean up function to be called at application exit
|
||||
esp_err_t i2cdev_done(void)
|
||||
{
|
||||
esp_err_t result = ESP_OK;
|
||||
ESP_LOGV(TAG, "Cleaning up I2C subsystem (i2c_master)...");
|
||||
for (int i = 0; i < I2C_NUM_MAX; i++)
|
||||
{
|
||||
if (i2c_ports[i].lock)
|
||||
{
|
||||
ESP_LOGV(TAG, "[Port %d] Cleaning up port...", i);
|
||||
if (xSemaphoreTake(i2c_ports[i].lock, pdMS_TO_TICKS(CONFIG_I2CDEV_TIMEOUT)) != pdTRUE)
|
||||
{
|
||||
ESP_LOGE(TAG, "[Port %d] Could not take port mutex for cleanup", i);
|
||||
result = ESP_FAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i2c_ports[i].installed)
|
||||
{
|
||||
ESP_LOGV(TAG, "[Port %d] Removing active devices before deleting bus...", i);
|
||||
// Remove all registered devices for this port from the bus
|
||||
for (int j = 0; j < CONFIG_I2CDEV_MAX_DEVICES_PER_PORT; j++)
|
||||
{
|
||||
i2c_dev_t *dev_ptr = active_devices[i][j];
|
||||
if (dev_ptr != NULL && dev_ptr->dev_handle != NULL)
|
||||
{
|
||||
ESP_LOGV(TAG, "[Port %d] Removing device 0x%02x (Handle %p)", i, dev_ptr->addr, dev_ptr->dev_handle);
|
||||
esp_err_t rm_res = i2c_master_bus_rm_device(dev_ptr->dev_handle);
|
||||
if (rm_res != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "[Port %d] Failed to remove device 0x%02x handle: %d", i, dev_ptr->addr, rm_res);
|
||||
// Continue cleanup despite error
|
||||
if (result == ESP_OK)
|
||||
result = rm_res; // Report first error
|
||||
}
|
||||
dev_ptr->dev_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "[Port %d] Deleting master bus handle %p...", i, i2c_ports[i].bus_handle);
|
||||
esp_err_t del_res = i2c_del_master_bus(i2c_ports[i].bus_handle);
|
||||
if (del_res != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "[Port %d] Failed to delete I2C bus during cleanup: %d", i, del_res);
|
||||
if (result == ESP_OK)
|
||||
result = del_res;
|
||||
}
|
||||
i2c_ports[i].installed = false;
|
||||
i2c_ports[i].bus_handle = NULL;
|
||||
i2c_ports[i].ref_count = 0;
|
||||
}
|
||||
xSemaphoreGive(i2c_ports[i].lock);
|
||||
} // End else (mutex taken)
|
||||
|
||||
ESP_LOGV(TAG, "[Port %d] Deleting port mutex...", i);
|
||||
vSemaphoreDelete(i2c_ports[i].lock);
|
||||
i2c_ports[i].lock = NULL;
|
||||
// Clear the active device list for this port
|
||||
memset(active_devices[i], 0, sizeof(active_devices[i]));
|
||||
ESP_LOGV(TAG, "[Port %d] Cleanup complete.", i);
|
||||
|
||||
} // end if lock exists
|
||||
} // end for loop
|
||||
ESP_LOGV(TAG, "I2C subsystem cleanup finished with result: %d", result);
|
||||
return result;
|
||||
}
|
||||
381
managed_components/esp-idf-lib__i2cdev/i2cdev.h
Normal file
381
managed_components/esp-idf-lib__i2cdev/i2cdev.h
Normal file
@@ -0,0 +1,381 @@
|
||||
/**
|
||||
* @file i2cdev.h
|
||||
* @defgroup i2cdev i2cdev
|
||||
* @{
|
||||
*
|
||||
* ESP-IDF I2C master thread-safe functions for communication with I2C slave
|
||||
*
|
||||
* This implementation uses the newer ESP-IDF I2C master driver (v5.0+).
|
||||
* For ESP-IDF versions using the legacy I2C driver, use i2cdev_legacy.c instead.
|
||||
*
|
||||
* Copyright (C) 2018 Ruslan V. Uss <unclerus@gmail.com>
|
||||
* Updated 2025 by quinkq to use newer ESP-IDF I2C master driver API
|
||||
*
|
||||
* MIT Licensed as described in the file LICENSE
|
||||
*
|
||||
* ============================================================================
|
||||
* OPTIONAL I2C PULLUP AUTO-CONFIGURATION
|
||||
* ============================================================================
|
||||
*
|
||||
* This library can optionally enable internal I2C pullups when no explicit
|
||||
* pullup configuration is provided. Feature is DISABLED by default for
|
||||
* backward compatibility (CONFIG_I2CDEV_AUTO_ENABLE_PULLUPS=n).
|
||||
*
|
||||
* Optional auto-pullup (CONFIG_I2CDEV_AUTO_ENABLE_PULLUPS=y):
|
||||
* - If both pullup flags are false (not set/default state), automatically enables internal pullups
|
||||
* - Only available on ESP32 family (modern driver)
|
||||
* - Legacy driver always uses explicit configuration
|
||||
*
|
||||
*
|
||||
* Example - Enable internal pullups:
|
||||
* i2c_dev_t sensor = {
|
||||
* .port = I2C_NUM_0,
|
||||
* .addr = 0x48,
|
||||
* .cfg = {
|
||||
* .sda_io_num = GPIO_NUM_21,
|
||||
* .scl_io_num = GPIO_NUM_22,
|
||||
* .sda_pullup_en = true, // Enable internal pullups
|
||||
* .scl_pullup_en = true, // Enable internal pullups
|
||||
* .master.clk_speed = 400000
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* ============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __I2CDEV_H__
|
||||
#define __I2CDEV_H__
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/i2c.h>
|
||||
#include <esp_err.h>
|
||||
#include <esp_idf_lib_helpers.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
|
||||
// Define missing types for older ESP-IDF versions
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0)
|
||||
typedef enum
|
||||
{
|
||||
I2C_ADDR_BIT_LEN_7 = 0, /*!< I2C 7bit address for slave mode */
|
||||
I2C_ADDR_BIT_LEN_10, /*!< I2C 10bit address for slave mode */
|
||||
} i2c_addr_bit_len_t;
|
||||
#endif
|
||||
|
||||
// Definition for I2CDEV_MAX_STRETCH_TIME
|
||||
#if HELPER_TARGET_IS_ESP8266
|
||||
#define I2CDEV_MAX_STRETCH_TIME 0xffffffff
|
||||
#else
|
||||
#include <soc/i2c_reg.h> // For I2C_TIME_OUT_VALUE_V, etc.
|
||||
#if defined(I2C_TIME_OUT_VALUE_V)
|
||||
#define I2CDEV_MAX_STRETCH_TIME I2C_TIME_OUT_VALUE_V
|
||||
#elif defined(I2C_TIME_OUT_REG_V)
|
||||
#define I2CDEV_MAX_STRETCH_TIME I2C_TIME_OUT_REG_V
|
||||
#else
|
||||
#define I2CDEV_MAX_STRETCH_TIME 0x00ffffff
|
||||
#endif
|
||||
#endif /* HELPER_TARGET_IS_ESP8266 */
|
||||
|
||||
#ifndef CONFIG_I2CDEV_TIMEOUT
|
||||
#define CONFIG_I2CDEV_TIMEOUT 1000 // Default 1 second timeout
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_I2CDEV_NOLOCK
|
||||
#define CONFIG_I2CDEV_NOLOCK 0 // Enable locking by default
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_I2CDEV_MAX_DEVICES_PER_PORT
|
||||
#define CONFIG_I2CDEV_MAX_DEVICES_PER_PORT 8 // Maximum devices per I2C port
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_I2CDEV_DEFAULT_SDA_PIN
|
||||
#define CONFIG_I2CDEV_DEFAULT_SDA_PIN 21 // Default SDA pin
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_I2CDEV_DEFAULT_SCL_PIN
|
||||
#define CONFIG_I2CDEV_DEFAULT_SCL_PIN 22 // Default SCL pin
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_FREERTOS_HZ
|
||||
#define CONFIG_FREERTOS_HZ 100 // Default value in most ESP-IDF configs
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_LOG_MAXIMUM_LEVEL
|
||||
#define CONFIG_LOG_MAXIMUM_LEVEL 3 // INFO level as default
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief I2C transaction type for legacy probe
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
I2C_DEV_WRITE = 0, /**< Write operation for probe */
|
||||
I2C_DEV_READ /**< Read operation for probe */
|
||||
} i2c_dev_type_t;
|
||||
|
||||
/**
|
||||
* I2C device descriptor
|
||||
*
|
||||
* This structure supports both legacy ESP-IDF I2C driver and modern i2c_master driver.
|
||||
*
|
||||
* @note INITIALIZATION CHECKLIST - Set these fields before calling i2c_dev_create_mutex():
|
||||
*
|
||||
* ┌─── REQUIRED (Set by user) ───────────────────────────────────────────┐
|
||||
* │ - dev->port - I2C port number (e.g., I2C_NUM_0) │
|
||||
* │ - dev->addr - Device I2C address (e.g., 0x48) │
|
||||
* │ - dev->cfg.sda_io_num - SDA pin (-1 = use Kconfig default) │
|
||||
* │ - dev->cfg.scl_io_num - SCL pin (-1 = use Kconfig default) │
|
||||
* │ - dev->cfg.master.clk_speed - Clock speed in Hz (e.g., 400000) │
|
||||
* └──────────────────────────────────────────────────────────────────────┘
|
||||
*
|
||||
* ┌─── OPTIONAL (Set by user if needed) ─────────────────────────────────┐
|
||||
* │ - dev->addr_bit_len - Address format (defaults to 7-bit) - NEW │
|
||||
* │ - dev->cfg.sda_pullup_en - Enable internal SDA pullup │
|
||||
* │ - dev->cfg.scl_pullup_en - Enable internal SCL pullup │
|
||||
* │ - dev->timeout_ticks - Legacy driver timeout (legacy only) │
|
||||
* └──────────────────────────────────────────────────────────────────────┘
|
||||
*
|
||||
* ┌─── AUTO-POPULATED (library fills these) ─────────────────────────────┐
|
||||
* │ - dev->mutex - Device mutex handle │
|
||||
* │ - dev->dev_handle - I2C device handle (modern driver) - NEW │
|
||||
* │ - dev->sda_pin - Actual SDA pin used by bus │
|
||||
* │ - dev->scl_pin - Actual SCL pin used by bus │
|
||||
* └──────────────────────────────────────────────────────────────────────┘
|
||||
*
|
||||
* @note BACKWARD COMPATIBILITY DESIGN:
|
||||
* The custom 'cfg' structure mimics ESP-IDF's deprecated i2c_config_t layout
|
||||
* to maintain zero-change compatibility with existing device drivers.
|
||||
* ESP-IDF ≥5.2 deprecated i2c_config_t and split it into separate bus/device
|
||||
* configs, but this library preserves the familiar field paths like:
|
||||
* dev->cfg.sda_io_num, dev->cfg.scl_io_num, dev->cfg.master.clk_speed
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
// ═══ Core Device Identity (REQUIRED) ═══
|
||||
i2c_port_t port; //!< I2C port number (e.g., I2C_NUM_0)
|
||||
uint16_t addr; //!< Device I2C address (e.g., 0x48 for 7-bit)
|
||||
i2c_addr_bit_len_t addr_bit_len; //!< Address format: I2C_ADDR_BIT_LEN_7 (default) or I2C_ADDR_BIT_LEN_10
|
||||
|
||||
// ═══ Library Internal State (AUTO-POPULATED) ═══
|
||||
SemaphoreHandle_t mutex; //!< Device mutex - Created by i2c_dev_create_mutex()
|
||||
void *dev_handle; //!< Device handle - Modern driver only, created lazily (when actual I2C operation is performed)
|
||||
int sda_pin; //!< Actual SDA pin used - Populated after port setup
|
||||
int scl_pin; //!< Actual SCL pin used - Populated after port setup
|
||||
|
||||
// ═══ Legacy Driver Compatibility ═══
|
||||
uint32_t timeout_ticks; //!< Clock stretching timeout - Legacy driver only
|
||||
|
||||
// ═══ User Configuration (REQUIRED) ═══
|
||||
// Configuration structure with i2c_config_t compatible field layout.
|
||||
struct
|
||||
{
|
||||
gpio_num_t sda_io_num; //!< Desired SDA pin (-1 = use Kconfig default)
|
||||
gpio_num_t scl_io_num; //!< Desired SCL pin (-1 = use Kconfig default)
|
||||
uint8_t sda_pullup_en; //!< Enable internal SDA pullup (optional)
|
||||
uint8_t scl_pullup_en; //!< Enable internal SCL pullup (optional)
|
||||
uint32_t clk_flags; //!< Bitwise of ``I2C_SCLK_SRC_FLAG_**FOR_DFS**`` for clk source choice
|
||||
struct
|
||||
{
|
||||
uint32_t clk_speed; //!< Clock speed in Hz
|
||||
} master; //!< Master-specific config (mimics old i2c_config_t.master)
|
||||
} cfg; //!< Configuration set by device drivers (i2c_config_t compatible layout)
|
||||
} i2c_dev_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize I2C subsystem (port mutexes and internal states)
|
||||
*
|
||||
* @note This should be called once at the beginning of your application
|
||||
* before any I2C devices are initialized.
|
||||
*
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
esp_err_t i2cdev_init(void);
|
||||
|
||||
/**
|
||||
* @brief Release I2C subsystem (deletes all devices, buses, and mutexes)
|
||||
*
|
||||
* @note Call this when no more I2C operations will be performed
|
||||
* to clean up resources.
|
||||
*
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
esp_err_t i2cdev_done(void);
|
||||
|
||||
/**
|
||||
* @brief Create mutex for device descriptor and register device
|
||||
*
|
||||
* @note IMPORTANT: Before calling this function, you must properly initialize the i2c_dev_t
|
||||
* structure with device address, port, and pin settings. For ESP-IDF legacy driver,
|
||||
* set pins in dev->cfg.sda_io_num and dev->cfg.scl_io_num. For newer ESP-IDF version,
|
||||
* either method is compatible. See the structure documentation for details.
|
||||
*
|
||||
* @param dev Pointer to device descriptor
|
||||
* @return `ESP_OK` on success
|
||||
*/
|
||||
esp_err_t i2c_dev_create_mutex(i2c_dev_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Delete mutex for device descriptor and perform device cleanup
|
||||
*
|
||||
* @note This function performs cleanup tasks including removing the device from the
|
||||
* I2C bus, deregistering it, and deleting its mutex.
|
||||
*
|
||||
* @param dev Pointer to device descriptor
|
||||
* @return `ESP_OK` on success
|
||||
*/
|
||||
esp_err_t i2c_dev_delete_mutex(i2c_dev_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Take device mutex
|
||||
*
|
||||
* @param dev Pointer to device descriptor
|
||||
* @return `ESP_OK` on success
|
||||
*/
|
||||
esp_err_t i2c_dev_take_mutex(i2c_dev_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Give device mutex
|
||||
*
|
||||
* @param dev Pointer to device descriptor
|
||||
* @return `ESP_OK` on success
|
||||
*/
|
||||
esp_err_t i2c_dev_give_mutex(i2c_dev_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Check the availability of a device on the I2C bus (New Driver) - legacy's i2c_dev_probe function equivalent.
|
||||
*
|
||||
* This function attempts to communicate with the I2C device to see if it ACKs.
|
||||
* It is non-intrusive; if the device is found, any temporary setup for
|
||||
* the check is torn down. Uses the new I2C driver logic.
|
||||
*
|
||||
* @param dev Pointer to the device descriptor. Pins and address must be configured.
|
||||
* @return `ESP_OK` if the device ACKs (is present), an error code otherwise.
|
||||
*/
|
||||
esp_err_t i2c_dev_check_present(const i2c_dev_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Check the availability of a device on the I2C bus (Legacy Driver).
|
||||
*
|
||||
* Issue an operation of `operation_type` to the I2C device then stops.
|
||||
* Primarily for use with the legacy i2cdev_legacy.c implementation.
|
||||
*
|
||||
* @param dev Device descriptor.
|
||||
* @param operation_type Operation type (I2C_DEV_WRITE or I2C_DEV_READ).
|
||||
* @return `ESP_OK` if device is available for the specified operation type.
|
||||
*/
|
||||
esp_err_t i2c_dev_probe(const i2c_dev_t *dev, i2c_dev_type_t operation_type);
|
||||
|
||||
/**
|
||||
* @brief Read from device
|
||||
*
|
||||
* @param dev Pointer to device descriptor
|
||||
* @param[in] out_data Data to write before reading (can be NULL if out_size is 0)
|
||||
* @param out_size Size of data to write
|
||||
* @param[out] in_data Buffer to store data read
|
||||
* @param in_size Number of bytes to read
|
||||
* @return `ESP_OK` on success
|
||||
*/
|
||||
esp_err_t i2c_dev_read(const i2c_dev_t *dev, const void *out_data, size_t out_size, void *in_data, size_t in_size);
|
||||
|
||||
/**
|
||||
* @brief Write to device
|
||||
*
|
||||
* @param dev Pointer to device descriptor
|
||||
* @param[in] out_reg Register address to write to (can be NULL if out_reg_size is 0)
|
||||
* @param out_reg_size Size of register address
|
||||
* @param[in] out_data Data to write (can be NULL if out_size is 0)
|
||||
* @param out_size Size of data to write
|
||||
* @return `ESP_OK` on success
|
||||
*/
|
||||
esp_err_t i2c_dev_write(const i2c_dev_t *dev, const void *out_reg, size_t out_reg_size, const void *out_data, size_t out_size);
|
||||
|
||||
/**
|
||||
* @brief Read from device register (8-bit register address)
|
||||
*
|
||||
* @param dev Pointer to device descriptor
|
||||
* @param reg Command to write before reading
|
||||
* @param[out] data Buffer to store data
|
||||
* @param size Number of bytes to read
|
||||
* @return `ESP_OK` on success
|
||||
*/
|
||||
esp_err_t i2c_dev_read_reg(const i2c_dev_t *dev, uint8_t reg, void *data, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Write to device register (8-bit register address)
|
||||
*
|
||||
* @param dev Pointer to device descriptor
|
||||
* @param reg Command to write before writing data
|
||||
* @param data Buffer with data to write
|
||||
* @param size Number of bytes to write
|
||||
* @return `ESP_OK` on success
|
||||
*/
|
||||
esp_err_t i2c_dev_write_reg(const i2c_dev_t *dev, uint8_t reg, const void *data, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Take device mutex with error checking
|
||||
*/
|
||||
#define I2C_DEV_TAKE_MUTEX(dev) \
|
||||
do \
|
||||
{ \
|
||||
esp_err_t __ = i2c_dev_take_mutex(dev); \
|
||||
if (__ != ESP_OK) \
|
||||
return __; \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/**
|
||||
* @brief Give device mutex with error checking
|
||||
*/
|
||||
#define I2C_DEV_GIVE_MUTEX(dev) \
|
||||
do \
|
||||
{ \
|
||||
esp_err_t __ = i2c_dev_give_mutex(dev); \
|
||||
if (__ != ESP_OK) \
|
||||
return __; \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/**
|
||||
* @brief Execute operation, assuming mutex is held. Gives mutex ONLY on error.
|
||||
*/
|
||||
#define I2C_DEV_CHECK(dev, X) \
|
||||
do \
|
||||
{ \
|
||||
esp_err_t ___ = X; /* Execute operation */ \
|
||||
if (___ != ESP_OK) \
|
||||
{ \
|
||||
/* Give mutex ONLY if error occurred */ \
|
||||
i2c_dev_give_mutex(dev); \
|
||||
return ___; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/**
|
||||
* @brief Execute operation, assuming mutex is held. Gives mutex ONLY on error, logs error.
|
||||
*/
|
||||
#define I2C_DEV_CHECK_LOGE(dev, X, msg, ...) \
|
||||
do \
|
||||
{ \
|
||||
esp_err_t ___ = X; /* Execute operation */ \
|
||||
if (___ != ESP_OK) \
|
||||
{ \
|
||||
/* Give mutex ONLY if error occurred */ \
|
||||
i2c_dev_give_mutex(dev); \
|
||||
ESP_LOGE(TAG, msg, ##__VA_ARGS__); \
|
||||
return ___; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**@}*/
|
||||
|
||||
#endif /* __I2CDEV_H__ */
|
||||
793
managed_components/esp-idf-lib__i2cdev/i2cdev_legacy.c
Normal file
793
managed_components/esp-idf-lib__i2cdev/i2cdev_legacy.c
Normal file
@@ -0,0 +1,793 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 Ruslan V. Uss <unclerus@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file i2cdev.c
|
||||
*
|
||||
* ESP-IDF I2C master thread-safe functions for communication with I2C slave
|
||||
*
|
||||
* Copyright (c) 2018 Ruslan V. Uss <unclerus@gmail.com>
|
||||
* Updated 2025 by quinkq to use newer ESP-IDF I2C master driver API
|
||||
* MIT Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include "esp_idf_lib_helpers.h" // For HELPER_TARGET_IS_ESP32 etc.
|
||||
#include "i2cdev.h" // Common header
|
||||
#include <driver/i2c.h> // Legacy I2C driver
|
||||
#include <esp_log.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <inttypes.h>
|
||||
#include <sdkconfig.h>
|
||||
#if !HELPER_TARGET_IS_ESP8266
|
||||
#include <soc/clk_tree_defs.h> // For APB_CLK_FREQ
|
||||
#endif
|
||||
#include <string.h>
|
||||
|
||||
static const char *TAG = "i2cdev_legacy";
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SemaphoreHandle_t lock;
|
||||
i2c_config_t config; // Use legacy config struct
|
||||
bool installed;
|
||||
uint32_t ref_count;
|
||||
i2c_dev_t *devices[CONFIG_I2CDEV_MAX_DEVICES_PER_PORT]; // Track devices registered on this port
|
||||
} i2c_port_state_t;
|
||||
|
||||
static i2c_port_state_t states[I2C_NUM_MAX] = { 0 };
|
||||
|
||||
#if CONFIG_I2CDEV_NOLOCK
|
||||
#define SEMAPHORE_TAKE(port)
|
||||
#else
|
||||
#define SEMAPHORE_TAKE(port) \
|
||||
do \
|
||||
{ \
|
||||
if (!xSemaphoreTake(states[port].lock, pdMS_TO_TICKS(CONFIG_I2CDEV_TIMEOUT))) \
|
||||
{ \
|
||||
ESP_LOGE(TAG, "Could not take port mutex %d", port); \
|
||||
return ESP_ERR_TIMEOUT; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
#endif
|
||||
|
||||
#if CONFIG_I2CDEV_NOLOCK
|
||||
#define SEMAPHORE_GIVE(port)
|
||||
#else
|
||||
#define SEMAPHORE_GIVE(port) \
|
||||
do \
|
||||
{ \
|
||||
if (!xSemaphoreGive(states[port].lock)) \
|
||||
{ \
|
||||
ESP_LOGE(TAG, "Could not give port mutex %d", port); \
|
||||
return ESP_FAIL; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Register an I2C device for tracking and resource management
|
||||
*
|
||||
* This function adds a device to the port's tracking array, which helps with:
|
||||
* - Monitoring which devices are active on each port
|
||||
* - Proper cleanup when the system shuts down
|
||||
* - Diagnostics and debugging
|
||||
*
|
||||
* Each port can track up to CONFIG_I2CDEV_MAX_DEVICES_PER_PORT devices.
|
||||
*
|
||||
* @param dev Device descriptor to register
|
||||
* @return ESP_OK if registration succeeded, or an error code
|
||||
*/
|
||||
static esp_err_t register_device(i2c_dev_t *dev)
|
||||
{
|
||||
if (!dev || dev->port >= I2C_NUM_MAX)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
if (!states[dev->port].lock)
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
|
||||
esp_err_t ret = ESP_ERR_NO_MEM;
|
||||
|
||||
// Take the mutex directly instead of using the macro
|
||||
if (xSemaphoreTake(states[dev->port].lock, pdMS_TO_TICKS(CONFIG_I2CDEV_TIMEOUT)) != pdTRUE)
|
||||
{
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] Could not take port mutex for registration", dev->addr, dev->port);
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
// Search for an empty slot in the device tracking array
|
||||
for (int i = 0; i < CONFIG_I2CDEV_MAX_DEVICES_PER_PORT; i++)
|
||||
{
|
||||
if (states[dev->port].devices[i] == NULL)
|
||||
{
|
||||
// Found empty slot - register the device here
|
||||
states[dev->port].devices[i] = dev;
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Registered device in slot %d", dev->addr, dev->port, i);
|
||||
ret = ESP_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// All slots full - this will still allow communication but prevents automatic cleanup
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
ESP_LOGW(TAG, "[0x%02x at %d] No free slots to register device", dev->addr, dev->port);
|
||||
}
|
||||
|
||||
// Release the mutex
|
||||
if (!xSemaphoreGive(states[dev->port].lock))
|
||||
{
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] Could not give port mutex after registration", dev->addr, dev->port);
|
||||
// If can't give the mutex, that's a serious error that overrides the registration result
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deregister a device and update reference counting
|
||||
*
|
||||
* This function:
|
||||
* 1. Removes the device from the port's tracking array
|
||||
* 2. Decrements the port's reference count
|
||||
* 3. Cleans up the I2C driver if this was the last device on the port
|
||||
*
|
||||
* This is called during device cleanup to ensure proper resource management.
|
||||
*
|
||||
* @param dev Device descriptor to deregister
|
||||
*/
|
||||
static void deregister_device(i2c_dev_t *dev)
|
||||
{
|
||||
if (!dev || dev->port >= I2C_NUM_MAX)
|
||||
return;
|
||||
|
||||
// Don't use macros that return values since this is a void function
|
||||
if (states[dev->port].lock)
|
||||
{
|
||||
if (xSemaphoreTake(states[dev->port].lock, pdMS_TO_TICKS(CONFIG_I2CDEV_TIMEOUT)) != pdTRUE)
|
||||
{
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] Could not take port mutex for deregistration", dev->addr, dev->port);
|
||||
return; // Cannot proceed without lock
|
||||
}
|
||||
|
||||
// Find the device in the tracking array
|
||||
for (int i = 0; i < CONFIG_I2CDEV_MAX_DEVICES_PER_PORT; i++)
|
||||
{
|
||||
if (states[dev->port].devices[i] == dev)
|
||||
{
|
||||
// Clear this slot
|
||||
states[dev->port].devices[i] = NULL;
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Deregistered device from slot %d", dev->addr, dev->port, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Manage reference counting for this port
|
||||
if (states[dev->port].ref_count > 0)
|
||||
{
|
||||
states[dev->port].ref_count--;
|
||||
ESP_LOGD(TAG, "[Port %d] Decremented ref_count to %" PRIu32, dev->port, states[dev->port].ref_count);
|
||||
|
||||
// If this was the last device using this port, clean up the driver
|
||||
if (states[dev->port].ref_count == 0 && states[dev->port].installed)
|
||||
{
|
||||
ESP_LOGI(TAG, "[Port %d] Last device removed, uninstalling driver", dev->port);
|
||||
i2c_driver_delete(dev->port);
|
||||
states[dev->port].installed = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Release the mutex
|
||||
if (!xSemaphoreGive(states[dev->port].lock))
|
||||
{
|
||||
ESP_LOGE(TAG, "[Port %d] Could not give port mutex after deregistration", dev->port);
|
||||
// Can't do much about this error except log it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t i2cdev_init()
|
||||
{
|
||||
memset(states, 0, sizeof(states));
|
||||
|
||||
#if !CONFIG_I2CDEV_NOLOCK
|
||||
for (int i = 0; i < I2C_NUM_MAX; i++)
|
||||
{
|
||||
states[i].lock = xSemaphoreCreateMutex();
|
||||
if (!states[i].lock)
|
||||
{
|
||||
ESP_LOGE(TAG, "Could not create port mutex %d", i);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2cdev_done()
|
||||
{
|
||||
ESP_LOGV(TAG, "Cleaning up I2C subsystem (legacy)...");
|
||||
for (int i = 0; i < I2C_NUM_MAX; i++)
|
||||
{
|
||||
if (!states[i].lock)
|
||||
continue;
|
||||
|
||||
if (states[i].installed)
|
||||
{
|
||||
SEMAPHORE_TAKE(i);
|
||||
|
||||
// First, clean up any devices still registered on this port
|
||||
for (int j = 0; j < CONFIG_I2CDEV_MAX_DEVICES_PER_PORT; j++)
|
||||
{
|
||||
if (states[i].devices[j] != NULL)
|
||||
{
|
||||
i2c_dev_t *dev = states[i].devices[j];
|
||||
ESP_LOGW(TAG, "[Port %d] Device 0x%02x still registered during cleanup", i, dev->addr);
|
||||
states[i].devices[j] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
i2c_driver_delete(i);
|
||||
states[i].installed = false;
|
||||
states[i].ref_count = 0;
|
||||
|
||||
SEMAPHORE_GIVE(i);
|
||||
}
|
||||
#if !CONFIG_I2CDEV_NOLOCK
|
||||
vSemaphoreDelete(states[i].lock);
|
||||
#endif
|
||||
states[i].lock = NULL;
|
||||
}
|
||||
ESP_LOGV(TAG, "I2C subsystem cleanup finished (legacy).");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2c_dev_create_mutex(i2c_dev_t *dev)
|
||||
{
|
||||
#if !CONFIG_I2CDEV_NOLOCK
|
||||
if (!dev)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Creating device mutex", dev->addr, dev->port);
|
||||
|
||||
// Initialize device pins to -1 to ensure consistent pattern with new driver
|
||||
if (dev->sda_pin == 0 && dev->scl_pin == 0)
|
||||
{
|
||||
dev->sda_pin = -1;
|
||||
dev->scl_pin = -1;
|
||||
ESP_LOGD(TAG, "[0x%02x at %d] Initialized pins to -1", dev->addr, dev->port);
|
||||
}
|
||||
|
||||
if (dev->mutex)
|
||||
{
|
||||
ESP_LOGW(TAG, "[0x%02x at %d] Device mutex already exists", dev->addr, dev->port);
|
||||
return ESP_OK; // Already created
|
||||
}
|
||||
|
||||
dev->mutex = xSemaphoreCreateMutex();
|
||||
if (!dev->mutex)
|
||||
{
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] Could not create device mutex", dev->addr, dev->port);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// Register device for tracking
|
||||
esp_err_t reg_res = register_device(dev);
|
||||
if (reg_res != ESP_OK)
|
||||
{
|
||||
ESP_LOGW(TAG, "[0x%02x at %d] Could not register device: %s", dev->addr, dev->port, esp_err_to_name(reg_res));
|
||||
// Continue anyway since this is not critical
|
||||
}
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2c_dev_delete_mutex(i2c_dev_t *dev)
|
||||
{
|
||||
#if !CONFIG_I2CDEV_NOLOCK
|
||||
if (!dev)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Deleting device mutex and cleaning up", dev->addr, dev->port);
|
||||
|
||||
// Deregister and update ref counts
|
||||
deregister_device(dev);
|
||||
|
||||
// Delete mutex if exists
|
||||
if (dev->mutex)
|
||||
{
|
||||
vSemaphoreDelete(dev->mutex);
|
||||
dev->mutex = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Device mutex was NULL", dev->addr, dev->port);
|
||||
}
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2c_dev_take_mutex(i2c_dev_t *dev)
|
||||
{
|
||||
#if !CONFIG_I2CDEV_NOLOCK
|
||||
if (!dev)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Taking mutex", dev->addr, dev->port);
|
||||
|
||||
if (!dev->mutex)
|
||||
{
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] Attempt to take NULL mutex!", dev->addr, dev->port);
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (!xSemaphoreTake(dev->mutex, pdMS_TO_TICKS(CONFIG_I2CDEV_TIMEOUT)))
|
||||
{
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] Could not take device mutex (timeout %d ms)", dev->addr, dev->port, CONFIG_I2CDEV_TIMEOUT);
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2c_dev_give_mutex(i2c_dev_t *dev)
|
||||
{
|
||||
#if !CONFIG_I2CDEV_NOLOCK
|
||||
if (!dev)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Giving mutex", dev->addr, dev->port);
|
||||
|
||||
if (!dev->mutex)
|
||||
{
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] Attempt to give NULL mutex!", dev->addr, dev->port);
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (!xSemaphoreGive(dev->mutex))
|
||||
{
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] Could not give device mutex", dev->addr, dev->port);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
inline static bool cfg_equal(const i2c_config_t *a, const i2c_config_t *b)
|
||||
{
|
||||
bool clock_equal;
|
||||
#ifdef CONFIG_IDF_TARGET_ESP8266
|
||||
clock_equal = (a->clk_stretch_tick == b->clk_stretch_tick);
|
||||
#else
|
||||
clock_equal = (a->master.clk_speed == b->master.clk_speed);
|
||||
#endif
|
||||
|
||||
return a->mode == b->mode && a->scl_io_num == b->scl_io_num && a->sda_io_num == b->sda_io_num && a->scl_pullup_en == b->scl_pullup_en && a->sda_pullup_en == b->sda_pullup_en && clock_equal;
|
||||
// Note: Ignoring clk_flags for comparison as it might not be consistently set by users
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure and initialize the I2C port for a device
|
||||
*
|
||||
* This function is responsible for:
|
||||
* 1. Determining which pins to use (from device or config)
|
||||
* 2. Validating pin configuration
|
||||
* 3. Installing/configuring the I2C driver if not already done
|
||||
* 4. Managing reference counting for the port
|
||||
* 5. Setting up clock stretching timeout
|
||||
*
|
||||
* This is a critical function that must succeed before any I2C operations
|
||||
* can be performed with a device.
|
||||
*
|
||||
* @param dev Device descriptor with configuration info
|
||||
* @return ESP_OK on success, or an error code on failure
|
||||
*/
|
||||
static esp_err_t i2c_setup_port(i2c_dev_t *dev)
|
||||
{
|
||||
if (!dev)
|
||||
{
|
||||
ESP_LOGE(TAG, "Device is NULL");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (dev->port >= I2C_NUM_MAX)
|
||||
{
|
||||
ESP_LOGE(TAG, "Invalid I2C port number: %d", dev->port);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// Pin Selection Logic:
|
||||
// Pins are taken from dev->cfg.xyz_io_num.
|
||||
// If -1, Kconfig defaults are used.
|
||||
gpio_num_t sda_pin; // Effective SDA pin to be used
|
||||
gpio_num_t scl_pin; // Effective SCL pin to be used
|
||||
|
||||
if (dev->cfg.sda_io_num == (gpio_num_t) -1)
|
||||
{
|
||||
sda_pin = (gpio_num_t)CONFIG_I2CDEV_DEFAULT_SDA_PIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
sda_pin = dev->cfg.sda_io_num;
|
||||
}
|
||||
|
||||
if (dev->cfg.scl_io_num == (gpio_num_t) -1)
|
||||
{
|
||||
scl_pin = (gpio_num_t)CONFIG_I2CDEV_DEFAULT_SCL_PIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
scl_pin = dev->cfg.scl_io_num;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "[0x%02x at %d] Based on cfg: sda_cfg=%d, scl_cfg=%d. Effective pins for setup: SDA=%d, SCL=%d", dev->addr, dev->port, dev->cfg.sda_io_num, dev->cfg.scl_io_num, sda_pin, scl_pin);
|
||||
|
||||
// Perform basic validation of effective pins
|
||||
if (sda_pin < 0 || scl_pin < 0)
|
||||
{
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] Invalid effective SDA/SCL pins (%d, %d). Check Kconfig defaults if cfg pins were -1.", dev->addr, dev->port, sda_pin, scl_pin);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (sda_pin == scl_pin)
|
||||
{
|
||||
ESP_LOGE(TAG, "[0x%02x at %d] Effective SDA and SCL pins cannot be the same (%d).", dev->addr, dev->port, sda_pin);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// Initialize common fields
|
||||
i2c_config_t legacy_cfg = { .mode = I2C_MODE_MASTER,
|
||||
.sda_io_num = sda_pin, // Use locally determined pins
|
||||
.scl_io_num = scl_pin, // Use locally determined pins
|
||||
.sda_pullup_en = dev->cfg.sda_pullup_en ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE,
|
||||
.scl_pullup_en = dev->cfg.scl_pullup_en ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE
|
||||
};
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_ESP8266
|
||||
// ESP8266 uses clk_stretch_tick instead of master.clk_speed
|
||||
// Clock speed will be handled during driver installation
|
||||
uint32_t desired_speed = dev->cfg.master.clk_speed > 0 ? dev->cfg.master.clk_speed : 400000;
|
||||
ESP_LOGD(TAG, "Final I2C config for port %d: SDA=%d, SCL=%d, speed=%lu (ESP8266)", dev->port, legacy_cfg.sda_io_num, legacy_cfg.scl_io_num, (unsigned long)desired_speed);
|
||||
#else
|
||||
// ESP32 family uses master.clk_speed
|
||||
legacy_cfg.master.clk_speed = dev->cfg.master.clk_speed > 0 ? dev->cfg.master.clk_speed : 400000;
|
||||
ESP_LOGD(TAG, "Final I2C config for port %d: SDA=%d, SCL=%d, speed=%lu", dev->port, legacy_cfg.sda_io_num, legacy_cfg.scl_io_num, (unsigned long)legacy_cfg.master.clk_speed);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
legacy_cfg.clk_flags = 0;
|
||||
#endif
|
||||
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
// Part 1: Driver Installation / Reconfiguration
|
||||
if (!cfg_equal(&legacy_cfg, &states[dev->port].config) || !states[dev->port].installed)
|
||||
{
|
||||
ESP_LOGD(TAG, "[0x%02x at %d] Reconfiguring I2C driver", dev->addr, dev->port);
|
||||
|
||||
if (states[dev->port].installed)
|
||||
{
|
||||
ESP_LOGD(TAG, "Uninstalling previous I2C driver configuration for port %d", dev->port);
|
||||
i2c_driver_delete(dev->port);
|
||||
states[dev->port].installed = false;
|
||||
states[dev->port].ref_count = 0;
|
||||
}
|
||||
|
||||
vTaskDelay(1);
|
||||
|
||||
// Target-specific driver installation/configuration sequence
|
||||
#if HELPER_TARGET_IS_ESP32 || HELPER_TARGET_IS_ESP32S2 || HELPER_TARGET_IS_ESP32S3 || HELPER_TARGET_IS_ESP32C3 || HELPER_TARGET_IS_ESP32C6
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0)
|
||||
ESP_LOGD(TAG, "Using IDF >= 5.1.0 driver install order for ESP32 family");
|
||||
err = i2c_driver_install(dev->port, legacy_cfg.mode, 0, 0, 0);
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
err = i2c_param_config(dev->port, &legacy_cfg);
|
||||
}
|
||||
#else
|
||||
ESP_LOGD(TAG, "Using IDF < 5.1.0 driver install order for ESP32 family");
|
||||
err = i2c_param_config(dev->port, &legacy_cfg);
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
err = i2c_driver_install(dev->port, legacy_cfg.mode, 0, 0, 0);
|
||||
}
|
||||
#endif
|
||||
#elif HELPER_TARGET_IS_ESP8266
|
||||
ESP_LOGD(TAG, "Using ESP8266 specific driver installation");
|
||||
legacy_cfg.clk_stretch_tick = dev->timeout_ticks ? dev->timeout_ticks : I2CDEV_MAX_STRETCH_TIME;
|
||||
err = i2c_driver_install(dev->port, legacy_cfg.mode);
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
err = i2c_param_config(dev->port, &legacy_cfg);
|
||||
}
|
||||
// ESP8266 note: Clock speed is not directly configurable through i2c_config_t
|
||||
// The desired speed was: %lu Hz", desired_speed
|
||||
#else
|
||||
// If legacy mode is off, and target detection fails, this avoids a compile error.
|
||||
// The legacy driver just won't support any target in this case.
|
||||
ESP_LOGW(TAG, "i2cdev_legacy.c: No specific target (ESP32/ESP32-S2/ESP32-S3/ESP32-C3/ESP32-C6/ESP8266) detected "
|
||||
"for driver installation. Legacy driver might be inactive or misconfigured.");
|
||||
err = ESP_ERR_NOT_SUPPORTED; // Indicate that setup can't proceed.
|
||||
#endif
|
||||
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to install/configure I2C driver for port %d: %d (%s)", dev->port, err, esp_err_to_name(err));
|
||||
states[dev->port].installed = false; // Ensure state reflects failure
|
||||
return err;
|
||||
}
|
||||
|
||||
memcpy(&states[dev->port].config, &legacy_cfg, sizeof(i2c_config_t));
|
||||
states[dev->port].installed = true;
|
||||
states[dev->port].ref_count++;
|
||||
|
||||
dev->sda_pin = legacy_cfg.sda_io_num;
|
||||
dev->scl_pin = legacy_cfg.scl_io_num;
|
||||
|
||||
ESP_LOGD(TAG, "I2C driver successfully installed/reconfigured on port %d, ref_count=%" PRIu32, dev->port, states[dev->port].ref_count);
|
||||
}
|
||||
else
|
||||
{
|
||||
states[dev->port].ref_count++;
|
||||
ESP_LOGV(TAG, "I2C driver already installed on port %d with matching config, ref_count=%" PRIu32, dev->port, states[dev->port].ref_count);
|
||||
|
||||
dev->sda_pin = states[dev->port].config.sda_io_num;
|
||||
dev->scl_pin = states[dev->port].config.scl_io_num;
|
||||
}
|
||||
|
||||
// Part 2: Timeout Configuration (ESP32 family specific hardware timeout)
|
||||
#if HELPER_TARGET_IS_ESP32 || HELPER_TARGET_IS_ESP32S2 || HELPER_TARGET_IS_ESP32S3 || HELPER_TARGET_IS_ESP32C3 || HELPER_TARGET_IS_ESP32C6
|
||||
int current_timeout_hw;
|
||||
err = i2c_get_timeout(dev->port, ¤t_timeout_hw);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to get HW timeout for port %d: %d (%s)", dev->port, err, esp_err_to_name(err));
|
||||
return err;
|
||||
}
|
||||
uint32_t timeout_ticks_val = dev->timeout_ticks ? dev->timeout_ticks : I2CDEV_MAX_STRETCH_TIME;
|
||||
if (timeout_ticks_val != (uint32_t)current_timeout_hw)
|
||||
{
|
||||
ESP_LOGV(TAG, "Port %d: Updating HW timeout from %d to %" PRIu32 " ticks", dev->port, current_timeout_hw, timeout_ticks_val);
|
||||
err = i2c_set_timeout(dev->port, timeout_ticks_val);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to set HW timeout for port %d: %d (%s)", dev->port, err, esp_err_to_name(err));
|
||||
return err;
|
||||
}
|
||||
ESP_LOGD(TAG, "HW Timeout: ticks = %" PRIu32 " (%" PRIu32 " usec) on port %d", timeout_ticks_val, timeout_ticks_val / 80, dev->port);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2c_dev_probe(const i2c_dev_t *dev, i2c_dev_type_t operation_type)
|
||||
{
|
||||
if (!dev)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
|
||||
SEMAPHORE_TAKE(dev->port);
|
||||
|
||||
esp_err_t res = i2c_setup_port((i2c_dev_t *)dev);
|
||||
if (res == ESP_OK)
|
||||
{
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, dev->addr << 1 | (operation_type == I2C_DEV_READ ? 1 : 0), true);
|
||||
// Alternative Write-style probe for better device compatibility
|
||||
// many devices don't respond well to blind read probes.
|
||||
// i2c_master_write_byte(cmd, dev->addr << 1 | 0, true); // Force write bit (0)
|
||||
i2c_master_stop(cmd);
|
||||
|
||||
res = i2c_master_cmd_begin(dev->port, cmd, pdMS_TO_TICKS(CONFIG_I2CDEV_TIMEOUT));
|
||||
|
||||
i2c_cmd_link_delete(cmd);
|
||||
}
|
||||
|
||||
SEMAPHORE_GIVE(dev->port);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
esp_err_t i2c_dev_read(const i2c_dev_t *dev, const void *out_data, size_t out_size, void *in_data, size_t in_size)
|
||||
{
|
||||
if (!dev || !in_data || !in_size)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
|
||||
SEMAPHORE_TAKE(dev->port);
|
||||
|
||||
// Use a local status variable to track errors
|
||||
esp_err_t err = i2c_setup_port((i2c_dev_t *)dev);
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
// Only create a command handle if setup was successful
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
|
||||
if (out_data && out_size)
|
||||
{
|
||||
// Write phase - typically used to specify a register address
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, dev->addr << 1, true); // Addr + Write bit (0)
|
||||
i2c_master_write(cmd, (void *)out_data, out_size, true);
|
||||
}
|
||||
|
||||
// Read phase - get data from the device
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (dev->addr << 1) | 1, true); // Addr + Read bit (1)
|
||||
i2c_master_read(cmd, in_data, in_size,
|
||||
I2C_MASTER_LAST_NACK); // NACK the last byte to signal end
|
||||
i2c_master_stop(cmd);
|
||||
|
||||
// Execute the command
|
||||
err = i2c_master_cmd_begin(dev->port, cmd, pdMS_TO_TICKS(CONFIG_I2CDEV_TIMEOUT));
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "i2c_master_cmd_begin failed for read: %d (%s)", err, esp_err_to_name(err));
|
||||
}
|
||||
|
||||
// Always delete the command handle
|
||||
i2c_cmd_link_delete(cmd);
|
||||
}
|
||||
|
||||
// Always release the semaphore before returning
|
||||
SEMAPHORE_GIVE(dev->port);
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t i2c_dev_write(const i2c_dev_t *dev, const void *out_reg, size_t out_reg_size, const void *out_data, size_t out_size)
|
||||
{
|
||||
if (!dev)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
if ((!out_reg || !out_reg_size) && (!out_data || !out_size))
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
|
||||
SEMAPHORE_TAKE(dev->port);
|
||||
|
||||
// Use a local status variable to track errors
|
||||
esp_err_t err = i2c_setup_port((i2c_dev_t *)dev);
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
// Only create a command handle if setup was successful
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, dev->addr << 1, true);
|
||||
|
||||
// Write register address/command if provided
|
||||
if (out_reg && out_reg_size)
|
||||
{
|
||||
i2c_master_write(cmd, (void *)out_reg, out_reg_size, true);
|
||||
}
|
||||
|
||||
// Write data if provided
|
||||
if (out_data && out_size)
|
||||
{
|
||||
i2c_master_write(cmd, (void *)out_data, out_size, true);
|
||||
}
|
||||
|
||||
i2c_master_stop(cmd);
|
||||
|
||||
// Execute the command
|
||||
err = i2c_master_cmd_begin(dev->port, cmd, pdMS_TO_TICKS(CONFIG_I2CDEV_TIMEOUT));
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "i2c_master_cmd_begin failed for write: %d (%s)", err, esp_err_to_name(err));
|
||||
}
|
||||
|
||||
// Always delete the command handle
|
||||
i2c_cmd_link_delete(cmd);
|
||||
}
|
||||
|
||||
// Always release the semaphore before returning
|
||||
SEMAPHORE_GIVE(dev->port);
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t i2c_dev_write_reg(const i2c_dev_t *dev, uint8_t reg, const void *out_data, size_t out_size)
|
||||
{
|
||||
if (!dev || !out_data || !out_size)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
|
||||
SEMAPHORE_TAKE(dev->port);
|
||||
|
||||
// Use a local status variable to track errors
|
||||
esp_err_t err = i2c_setup_port((i2c_dev_t *)dev);
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
// Only create a command handle if setup was successful
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (dev->addr << 1) | I2C_MASTER_WRITE, true); // Addr + Write bit
|
||||
i2c_master_write_byte(cmd, reg, true); // Register address
|
||||
if (out_data && out_size)
|
||||
{
|
||||
i2c_master_write(cmd, (void *)out_data, out_size, true); // Data to write
|
||||
}
|
||||
i2c_master_stop(cmd);
|
||||
|
||||
// Execute the command
|
||||
err = i2c_master_cmd_begin(dev->port, cmd, pdMS_TO_TICKS(CONFIG_I2CDEV_TIMEOUT));
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "i2c_master_cmd_begin failed for write_reg: %d (%s)", err, esp_err_to_name(err));
|
||||
}
|
||||
|
||||
// Always delete the command handle
|
||||
i2c_cmd_link_delete(cmd);
|
||||
}
|
||||
|
||||
// Always release the semaphore before returning
|
||||
SEMAPHORE_GIVE(dev->port);
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t i2c_dev_read_reg(const i2c_dev_t *dev, uint8_t reg, void *in_data, size_t in_size)
|
||||
{
|
||||
if (!dev || !in_data || !in_size)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
|
||||
SEMAPHORE_TAKE(dev->port);
|
||||
|
||||
// Use a local status variable to track errors
|
||||
esp_err_t err = i2c_setup_port((i2c_dev_t *)dev);
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
// Only create a command handle if setup was successful
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (dev->addr << 1) | I2C_MASTER_WRITE, true);
|
||||
i2c_master_write_byte(cmd, reg, true);
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (dev->addr << 1) | I2C_MASTER_READ, true);
|
||||
i2c_master_read(cmd, in_data, in_size, I2C_MASTER_LAST_NACK);
|
||||
i2c_master_stop(cmd);
|
||||
|
||||
// Execute the command
|
||||
err = i2c_master_cmd_begin(dev->port, cmd, pdMS_TO_TICKS(CONFIG_I2CDEV_TIMEOUT));
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "i2c_master_cmd_begin failed for read_reg: %d (%s)", err, esp_err_to_name(err));
|
||||
}
|
||||
|
||||
// Always delete the command handle
|
||||
i2c_cmd_link_delete(cmd);
|
||||
}
|
||||
|
||||
// Always release the semaphore before returning
|
||||
SEMAPHORE_GIVE(dev->port);
|
||||
return err;
|
||||
}
|
||||
|
||||
// Implementation of i2c_dev_check_present (updated version of i2c_dev_probe) using legacy I2C driver
|
||||
esp_err_t i2c_dev_check_present(const i2c_dev_t *dev)
|
||||
{
|
||||
if (!dev)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
|
||||
ESP_LOGV(TAG, "[0x%02x at %d] Checking device presence (legacy driver)...", dev->addr, dev->port);
|
||||
|
||||
// Use the exact same pattern as i2c_dev_probe with WRITE operation to ensure consistent behavior
|
||||
return i2c_dev_probe(dev, I2C_DEV_WRITE);
|
||||
}
|
||||
30
managed_components/esp-idf-lib__i2cdev/idf_component.yml
Normal file
30
managed_components/esp-idf-lib__i2cdev/idf_component.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
dependencies:
|
||||
esp-idf-lib/esp_idf_lib_helpers:
|
||||
version: '*'
|
||||
description: ESP-IDF I2C master thread-safe utilities
|
||||
discussion: https://github.com/esp-idf-lib/core/discussions
|
||||
documentation: https://esp-idf-lib.github.io/i2cdev/
|
||||
files:
|
||||
exclude:
|
||||
- docs/**/*
|
||||
issues: https://github.com/esp-idf-lib/i2cdev/issues
|
||||
license: MIT
|
||||
maintainers:
|
||||
- Ruslan V. Uss (@UncleRus) <unclerus@gmail.com>
|
||||
repository: git://github.com/esp-idf-lib/i2cdev.git
|
||||
repository_info:
|
||||
commit_sha: abf0ebc8f0f826373e9a9ee07cf96727a49ed87b
|
||||
path: .
|
||||
targets:
|
||||
- esp32
|
||||
- esp32c2
|
||||
- esp32c3
|
||||
- esp32c5
|
||||
- esp32c6
|
||||
- esp32c61
|
||||
- esp32h2
|
||||
- esp32p4
|
||||
- esp32s2
|
||||
- esp32s3
|
||||
url: https://github.com/esp-idf-lib/core
|
||||
version: 2.0.8
|
||||
1
managed_components/esp-idf-lib__tca95x5/.ackrc
Normal file
1
managed_components/esp-idf-lib__tca95x5/.ackrc
Normal file
@@ -0,0 +1 @@
|
||||
--ignore-dir=build
|
||||
17
managed_components/esp-idf-lib__tca95x5/.astylerc
Normal file
17
managed_components/esp-idf-lib__tca95x5/.astylerc
Normal file
@@ -0,0 +1,17 @@
|
||||
--align-reference=name
|
||||
--attach-classes
|
||||
--attach-classes
|
||||
--attach-namespaces
|
||||
--convert-tabs
|
||||
--exclude=build
|
||||
--exclude=common
|
||||
--exclude=managed_components
|
||||
--ignore-exclude-errors
|
||||
--indent-switches
|
||||
--indent=spaces=4
|
||||
--keep-one-line-statements
|
||||
--max-continuation-indent=120
|
||||
--pad-header
|
||||
--pad-oper
|
||||
--style=allman
|
||||
--unpad-paren
|
||||
66
managed_components/esp-idf-lib__tca95x5/.clang-format
Normal file
66
managed_components/esp-idf-lib__tca95x5/.clang-format
Normal file
@@ -0,0 +1,66 @@
|
||||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: WebKit
|
||||
AlignConsecutiveMacros: true
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: true
|
||||
AfterControlStatement: Always
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: true
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: true
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: false
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
ColumnLimit: 200
|
||||
CompactNamespaces: true
|
||||
Cpp11BracedListStyle: false
|
||||
FixNamespaceComments: true
|
||||
IndentCaseLabels: true
|
||||
IndentWidth: 4
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: Inner
|
||||
PointerAlignment: Right
|
||||
ReflowComments: true
|
||||
SortIncludes: false
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeInheritanceColon: false
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Auto
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
1
managed_components/esp-idf-lib__tca95x5/.component_hash
Normal file
1
managed_components/esp-idf-lib__tca95x5/.component_hash
Normal file
@@ -0,0 +1 @@
|
||||
4bbdbd82828cf1fd5c03fd07e3ea2cb0f36daf16cb3ac7219d1e5decb9ec04ee
|
||||
28
managed_components/esp-idf-lib__tca95x5/.eil.yml
Normal file
28
managed_components/esp-idf-lib__tca95x5/.eil.yml
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
name: tca95x5
|
||||
description: Driver for TCA9535/TCA9555 remote 16-bit I/O expanders for I2C-bus
|
||||
version: 1.0.7
|
||||
groups:
|
||||
- gpio
|
||||
code_owners: UncleRus
|
||||
depends:
|
||||
- i2cdev
|
||||
- log
|
||||
- esp_idf_lib_helpers
|
||||
thread_safe: yes
|
||||
targets:
|
||||
- esp32
|
||||
- esp8266
|
||||
- esp32s2
|
||||
- esp32c3
|
||||
- esp32s3
|
||||
- esp32c2
|
||||
- esp32c6
|
||||
- esp32h2
|
||||
- esp32p4
|
||||
- esp32c5
|
||||
- esp32c61
|
||||
license: BSD-3
|
||||
copyrights:
|
||||
- name: UncleRus
|
||||
year: 2019
|
||||
7
managed_components/esp-idf-lib__tca95x5/.gitignore
vendored
Normal file
7
managed_components/esp-idf-lib__tca95x5/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
examples/**/sdkconfig
|
||||
examples/**/sdkconfig.old
|
||||
examples/**/build/
|
||||
examples/**/dependencies.lock
|
||||
docs/_*/
|
||||
docs/doxygen.log
|
||||
*.swp
|
||||
3
managed_components/esp-idf-lib__tca95x5/.gitmodules
vendored
Normal file
3
managed_components/esp-idf-lib__tca95x5/.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "common"]
|
||||
path = common
|
||||
url = https://github.com/esp-idf-lib/common.git
|
||||
13
managed_components/esp-idf-lib__tca95x5/CMakeLists.txt
Normal file
13
managed_components/esp-idf-lib__tca95x5/CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
idf_component_register(
|
||||
SRCS tca95x5.c
|
||||
INCLUDE_DIRS .
|
||||
REQUIRES i2cdev log esp_idf_lib_helpers
|
||||
)
|
||||
|
||||
# include common cmake file for components
|
||||
set(ESP_IDF_LIB_CMAKE ${CMAKE_CURRENT_LIST_DIR}/common/cmake/esp-idf-lib.cmake)
|
||||
if(EXISTS ${ESP_IDF_LIB_CMAKE})
|
||||
include(${ESP_IDF_LIB_CMAKE})
|
||||
else()
|
||||
message(WARNING "${ESP_IDF_LIB_CMAKE} not found")
|
||||
endif()
|
||||
19
managed_components/esp-idf-lib__tca95x5/Kconfig.i2c
Normal file
19
managed_components/esp-idf-lib__tca95x5/Kconfig.i2c
Normal file
@@ -0,0 +1,19 @@
|
||||
config EXAMPLE_I2C_MASTER_SCL
|
||||
int "SCL GPIO Number"
|
||||
default 5 if IDF_TARGET_ESP8266
|
||||
default 6 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C5 || IDF_TARGET_ESP32C6 || IDF_TARGET_ESP32C61
|
||||
default 19 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
||||
default 4 if IDF_TARGET_ESP32H2
|
||||
default 4 if IDF_TARGET_ESP32P4
|
||||
help
|
||||
GPIO number for I2C Master clock line.
|
||||
|
||||
config EXAMPLE_I2C_MASTER_SDA
|
||||
int "SDA GPIO Number"
|
||||
default 4 if IDF_TARGET_ESP8266
|
||||
default 5 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C5 || IDF_TARGET_ESP32C6 || IDF_TARGET_ESP32C61
|
||||
default 18 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
||||
default 3 if IDF_TARGET_ESP32H2
|
||||
default 3 if IDF_TARGET_ESP32P4
|
||||
help
|
||||
GPIO number for I2C Master data line.
|
||||
26
managed_components/esp-idf-lib__tca95x5/LICENSE
Normal file
26
managed_components/esp-idf-lib__tca95x5/LICENSE
Normal file
@@ -0,0 +1,26 @@
|
||||
Copyright (c) 2019 Ruslan V. Uss <unclerus@gmail.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of itscontributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
30
managed_components/esp-idf-lib__tca95x5/README.md
Normal file
30
managed_components/esp-idf-lib__tca95x5/README.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# esp-idf-lib/tca95x5
|
||||
|
||||
[](https://github.com/esp-idf-lib/tca95x5/actions/workflows//build.yml)
|
||||
[](https://github.com/esp-idf-lib/tca95x5/actions/workflows//build-docs.yml)
|
||||
[](https://github.com/esp-idf-lib/tca95x5/actions/workflows//validate-component.yml)
|
||||
|
||||
Driver for TCA9535/TCA9555 remote 16-bit I/O expanders for I2C-bus.
|
||||
|
||||
* [Documentation](https://esp-idf-lib.github.io/tca95x5/)
|
||||
* [Repository](https://github.com/esp-idf-lib/tca95x5)
|
||||
* [Issues](https://github.com/esp-idf-lib/tca95x5/issues)
|
||||
* [Discussions and questions](https://github.com/esp-idf-lib/core/discussions)
|
||||
* [Component page at the ESP Component Registry](https://components.espressif.com/components/esp-idf-lib/tca95x5)
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
idf.py add-dependency esp-idf-lib/tca95x5
|
||||
```
|
||||
|
||||
## Support
|
||||
|
||||
For questions and discussions about the component, please use
|
||||
[Discussions](https://github.com/esp-idf-lib/core/discussions)
|
||||
at [esp-idf-lib/core](https://github.com/esp-idf-lib/core).
|
||||
|
||||
## Contributing
|
||||
|
||||
Please read [CONTRIBUTING.md](https://github.com/esp-idf-lib/core/blob/main/CONTRIBUTING.md)
|
||||
at [esp-idf-lib/core](https://github.com/esp-idf-lib/core).
|
||||
18
managed_components/esp-idf-lib__tca95x5/bin/eil-q
Normal file
18
managed_components/esp-idf-lib__tca95x5/bin/eil-q
Normal file
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require "pathname"
|
||||
require "yaml"
|
||||
|
||||
# A simple CLI to get values in .eil.yml
|
||||
|
||||
key = ARGV.shift
|
||||
project_root = Pathname.new(File.expand_path(__FILE__)).parent.parent
|
||||
eil_file = project_root / ".eil.yml"
|
||||
doc = YAML.safe_load(File.read eil_file)
|
||||
|
||||
case key
|
||||
when "copyright_string"
|
||||
puts doc["copyrights"].map { |e| "#{e['year']}, #{e['name']}" }.join(", ")
|
||||
else
|
||||
puts doc[key]
|
||||
end
|
||||
@@ -0,0 +1,36 @@
|
||||
# Set common build flags but enable them only when the build is in our CI,
|
||||
# making them optional. The idea is, fail when compiled in our CI but just
|
||||
# warn in any other cases. Code that compiles with one toolchain warning-free
|
||||
# may not do so with another toolchain, which creates a project dependency on
|
||||
# specific toolchain vendors and versions.
|
||||
#
|
||||
# Define flags that may cause failures here.
|
||||
if (DEFINED ENV{ESP_IDF_LIB_CI})
|
||||
set(ESP_IDF_LIB_CI_FLAGS
|
||||
-Werror=unused-variable
|
||||
-Werror=unused-function
|
||||
-Werror=write-strings
|
||||
-Werror
|
||||
)
|
||||
endif()
|
||||
|
||||
# Set common build flags. Mandatory.
|
||||
#
|
||||
# Define flags that do not cause failures here.
|
||||
set(ESP_IDF_LIB_FLAGS
|
||||
-Wextra
|
||||
-Wwrite-strings
|
||||
-Wunused-variable
|
||||
-Wunused-function
|
||||
-Wreturn-type
|
||||
)
|
||||
|
||||
# When COMPONENT_LIB is INTERFACE_LIBRARY, or a header-only library, do not
|
||||
# set the flags.
|
||||
get_target_property(COMPONENT_TYPE ${COMPONENT_LIB} TYPE)
|
||||
if(NOT COMPONENT_TYPE STREQUAL "INTERFACE_LIBRARY")
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE
|
||||
${ESP_IDF_LIB_FLAGS}
|
||||
${ESP_IDF_LIB_CI_FLAGS}
|
||||
)
|
||||
endif()
|
||||
2
managed_components/esp-idf-lib__tca95x5/component.mk
Normal file
2
managed_components/esp-idf-lib__tca95x5/component.mk
Normal file
@@ -0,0 +1,2 @@
|
||||
COMPONENT_ADD_INCLUDEDIRS = .
|
||||
COMPONENT_DEPENDS = i2cdev log esp_idf_lib_helpers
|
||||
@@ -0,0 +1,7 @@
|
||||
# The following four lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(example-tca95x5)
|
||||
@@ -0,0 +1,6 @@
|
||||
#V := 1
|
||||
PROJECT_NAME := example-tca95x5
|
||||
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
## What the example does
|
||||
|
||||
* Initializes the driver
|
||||
* Configure a pin as input
|
||||
* Registers an interrupt that logs port value of the INT pin
|
||||
* Blinks, or toggles, P10 output
|
||||
|
||||
## Wiring
|
||||
|
||||
Connect an LED with an appropriate register to P10.
|
||||
|
||||
Connect a switch that toggle its voltage HIGH or LOW to INT GPIO. The INT GPIO
|
||||
can be set in `menuconfig`. See the defaults in `Kconfig.projbuild`.
|
||||
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -0,0 +1,21 @@
|
||||
menu "Example configuration"
|
||||
|
||||
config EXAMPLE_I2C_ADDR
|
||||
hex "I2C address of TCA9555"
|
||||
default 0x20
|
||||
help
|
||||
I2C address of TCA9555. The default is `TCA95X5_I2C_ADDR_BASE`, or
|
||||
0x20. See available options in datasheet.
|
||||
|
||||
config EXAMPLE_INT_GPIO
|
||||
int "INT GPIO Number"
|
||||
default 14 if IDF_TARGET_ESP8266
|
||||
default 7 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C5 || IDF_TARGET_ESP32C6 || IDF_TARGET_ESP32C61
|
||||
default 5 if IDF_TARGET_ESP32H2
|
||||
default 5 if IDF_TARGET_ESP32P4
|
||||
default 5 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
||||
help
|
||||
GPIO number connected to INT pin.
|
||||
|
||||
rsource "../../../Kconfig.i2c"
|
||||
endmenu
|
||||
@@ -0,0 +1 @@
|
||||
COMPONENT_ADD_INCLUDEDIRS = . include/
|
||||
@@ -0,0 +1,9 @@
|
||||
dependencies:
|
||||
esp-idf-lib/esp_idf_lib_helpers:
|
||||
version: '*'
|
||||
esp-idf-lib/i2cdev:
|
||||
version: '*'
|
||||
esp-idf-lib/tca95x5:
|
||||
version: '*'
|
||||
description: default
|
||||
version: 1.0.0
|
||||
@@ -0,0 +1,80 @@
|
||||
#include <stdio.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <freertos/queue.h>
|
||||
#include <tca95x5.h>
|
||||
#include <driver/gpio.h>
|
||||
#include <esp_log.h>
|
||||
|
||||
static i2c_dev_t tca9555 = { 0 };
|
||||
|
||||
static QueueHandle_t gpio_queue = NULL;
|
||||
|
||||
static const char *TAG = "tca95x5-example";
|
||||
|
||||
// Interrupt handler
|
||||
static void IRAM_ATTR intr_handler(void *arg)
|
||||
{
|
||||
gpio_num_t gpio = (gpio_num_t)arg;
|
||||
xQueueSendFromISR(gpio_queue, &gpio, NULL);
|
||||
}
|
||||
|
||||
// Interrupt event receiver
|
||||
static void gpio_recv_task(void *arg)
|
||||
{
|
||||
gpio_num_t gpio;
|
||||
while (1)
|
||||
{
|
||||
if (xQueueReceive(gpio_queue, &gpio, portMAX_DELAY))
|
||||
{
|
||||
ESP_LOGI(TAG, "GPIO interrupt on pin %d", gpio);
|
||||
if (gpio != CONFIG_EXAMPLE_INT_GPIO) continue;
|
||||
|
||||
uint16_t val;
|
||||
esp_err_t res = tca95x5_port_read(&tca9555, &val);
|
||||
if (res != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Error reading TCA9555: %d (%s)", res, esp_err_to_name(res));
|
||||
continue;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "TCA9555 port value: 0x%04x", val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void main_task(void *pvParameters)
|
||||
{
|
||||
// Init descriptor
|
||||
ESP_ERROR_CHECK(tca95x5_init_desc(&tca9555, CONFIG_EXAMPLE_I2C_ADDR, 0, CONFIG_EXAMPLE_I2C_MASTER_SDA, CONFIG_EXAMPLE_I2C_MASTER_SCL));
|
||||
|
||||
// Setup P00, P01 and P02 as input, others as output
|
||||
ESP_ERROR_CHECK(tca95x5_port_set_mode(&tca9555, 0x0007)); // 0b0000000000000111
|
||||
|
||||
// Create queue
|
||||
gpio_queue = xQueueCreate(5, sizeof(gpio_num_t));
|
||||
|
||||
// Run event receiver
|
||||
xTaskCreate(gpio_recv_task, "gpio_recv_task", 4096, NULL, 5, NULL);
|
||||
|
||||
// Setup GPIO interrupt
|
||||
gpio_set_direction(CONFIG_EXAMPLE_INT_GPIO, GPIO_MODE_INPUT);
|
||||
gpio_set_intr_type(CONFIG_EXAMPLE_INT_GPIO, GPIO_INTR_NEGEDGE);
|
||||
gpio_install_isr_service(0);
|
||||
gpio_isr_handler_add(CONFIG_EXAMPLE_INT_GPIO, intr_handler, (void *)CONFIG_EXAMPLE_INT_GPIO);
|
||||
|
||||
// blink on P10
|
||||
bool on = true;
|
||||
while (1)
|
||||
{
|
||||
ESP_ERROR_CHECK(tca95x5_set_level(&tca9555, 8, on));
|
||||
on = !on;
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
}
|
||||
}
|
||||
|
||||
void app_main()
|
||||
{
|
||||
ESP_ERROR_CHECK(i2cdev_init());
|
||||
xTaskCreate(main_task, "main_task", configMINIMAL_STACK_SIZE * 6, NULL, 5, NULL);
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 96 KiB |
32
managed_components/esp-idf-lib__tca95x5/idf_component.yml
Normal file
32
managed_components/esp-idf-lib__tca95x5/idf_component.yml
Normal file
@@ -0,0 +1,32 @@
|
||||
dependencies:
|
||||
esp-idf-lib/esp_idf_lib_helpers:
|
||||
version: '*'
|
||||
esp-idf-lib/i2cdev:
|
||||
version: '*'
|
||||
description: Driver for TCA9535/TCA9555 remote 16-bit I/O expanders for I2C-bus
|
||||
discussion: https://github.com/esp-idf-lib/core/discussions
|
||||
documentation: https://esp-idf-lib.github.io/tca95x5/
|
||||
files:
|
||||
exclude:
|
||||
- docs/**/*
|
||||
issues: https://github.com/esp-idf-lib/tca95x5/issues
|
||||
license: BSD-3
|
||||
maintainers:
|
||||
- Ruslan V. Uss (@UncleRus) <unclerus@gmail.com>
|
||||
repository: git://github.com/esp-idf-lib/tca95x5.git
|
||||
repository_info:
|
||||
commit_sha: 1334d902c73251c88a70f37c271a335d6a5868e5
|
||||
path: .
|
||||
targets:
|
||||
- esp32
|
||||
- esp32c2
|
||||
- esp32c3
|
||||
- esp32c5
|
||||
- esp32c6
|
||||
- esp32c61
|
||||
- esp32h2
|
||||
- esp32p4
|
||||
- esp32s2
|
||||
- esp32s3
|
||||
url: https://github.com/esp-idf-lib/core
|
||||
version: 1.0.7
|
||||
138
managed_components/esp-idf-lib__tca95x5/tca95x5.c
Normal file
138
managed_components/esp-idf-lib__tca95x5/tca95x5.c
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Ruslan V. Uss <unclerus@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the names of itscontributors
|
||||
* may be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file tca95x5.c
|
||||
*
|
||||
* ESP-IDF driver for TCA9535/TCA9555 remote 16-bit I/O expanders for I2C-bus
|
||||
*
|
||||
* Copyright (c) 2019 Ruslan V. Uss <unclerus@gmail.com>
|
||||
*
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
|
||||
#include <esp_idf_lib_helpers.h>
|
||||
#include "tca95x5.h"
|
||||
|
||||
#define I2C_FREQ_HZ 400000
|
||||
|
||||
#define REG_IN0 0x00
|
||||
#define REG_OUT0 0x02
|
||||
#define REG_CONF0 0x06
|
||||
|
||||
#define CHECK(x) do { esp_err_t __; if ((__ = x) != ESP_OK) return __; } while (0)
|
||||
#define CHECK_ARG(VAL) do { if (!(VAL)) return ESP_ERR_INVALID_ARG; } while (0)
|
||||
#define BV(x) (1 << (x))
|
||||
|
||||
static esp_err_t read_reg_16(i2c_dev_t *dev, uint8_t reg, uint16_t *val)
|
||||
{
|
||||
CHECK_ARG(dev && val);
|
||||
|
||||
I2C_DEV_TAKE_MUTEX(dev);
|
||||
I2C_DEV_CHECK(dev, i2c_dev_read_reg(dev, reg, val, 2));
|
||||
I2C_DEV_GIVE_MUTEX(dev);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t write_reg_16(i2c_dev_t *dev, uint8_t reg, uint16_t val)
|
||||
{
|
||||
CHECK_ARG(dev);
|
||||
|
||||
I2C_DEV_TAKE_MUTEX(dev);
|
||||
I2C_DEV_CHECK(dev, i2c_dev_write_reg(dev, reg, &val, 2));
|
||||
I2C_DEV_GIVE_MUTEX(dev);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
esp_err_t tca95x5_init_desc(i2c_dev_t *dev, uint8_t addr, i2c_port_t port, gpio_num_t sda_gpio, gpio_num_t scl_gpio)
|
||||
{
|
||||
CHECK_ARG(dev && (addr & TCA95X5_I2C_ADDR_BASE));
|
||||
|
||||
dev->port = port;
|
||||
dev->addr = addr;
|
||||
dev->cfg.sda_io_num = sda_gpio;
|
||||
dev->cfg.scl_io_num = scl_gpio;
|
||||
#if HELPER_TARGET_IS_ESP32
|
||||
dev->cfg.master.clk_speed = I2C_FREQ_HZ;
|
||||
#endif
|
||||
|
||||
return i2c_dev_create_mutex(dev);
|
||||
}
|
||||
|
||||
esp_err_t tca95x5_free_desc(i2c_dev_t *dev)
|
||||
{
|
||||
CHECK_ARG(dev);
|
||||
|
||||
return i2c_dev_delete_mutex(dev);
|
||||
}
|
||||
|
||||
esp_err_t tca95x5_port_get_mode(i2c_dev_t *dev, uint16_t *mode)
|
||||
{
|
||||
return read_reg_16(dev, REG_CONF0, mode);
|
||||
}
|
||||
|
||||
esp_err_t tca95x5_port_set_mode(i2c_dev_t *dev, uint16_t mode)
|
||||
{
|
||||
return write_reg_16(dev, REG_CONF0, mode);
|
||||
}
|
||||
|
||||
esp_err_t tca95x5_port_read(i2c_dev_t *dev, uint16_t *val)
|
||||
{
|
||||
return read_reg_16(dev, REG_IN0, val);
|
||||
}
|
||||
|
||||
esp_err_t tca95x5_port_write(i2c_dev_t *dev, uint16_t val)
|
||||
{
|
||||
return write_reg_16(dev, REG_OUT0, val);
|
||||
}
|
||||
|
||||
esp_err_t tca95x5_get_level(i2c_dev_t *dev, uint8_t pin, uint32_t *val)
|
||||
{
|
||||
uint16_t v;
|
||||
CHECK(read_reg_16(dev, REG_IN0, &v));
|
||||
*val = v & BV(pin) ? 1 : 0;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t tca95x5_set_level(i2c_dev_t *dev, uint8_t pin, uint32_t val)
|
||||
{
|
||||
uint16_t v;
|
||||
|
||||
I2C_DEV_TAKE_MUTEX(dev);
|
||||
I2C_DEV_CHECK(dev, i2c_dev_read_reg(dev, REG_OUT0, &v, 2));
|
||||
v = (v & ~BV(pin)) | (val ? BV(pin) : 0);
|
||||
I2C_DEV_CHECK(dev, i2c_dev_write_reg(dev, REG_OUT0, &v, 2));
|
||||
I2C_DEV_GIVE_MUTEX(dev);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
141
managed_components/esp-idf-lib__tca95x5/tca95x5.h
Normal file
141
managed_components/esp-idf-lib__tca95x5/tca95x5.h
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Ruslan V. Uss <unclerus@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the names of itscontributors
|
||||
* may be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file tca95x5.h
|
||||
* @defgroup tca95x5 tca95x5
|
||||
* @{
|
||||
*
|
||||
* ESP-IDF driver for TCA9535/TCA9555 remote 16-bit I/O expanders for I2C-bus
|
||||
*
|
||||
* Copyright (c) 2019 Ruslan V. Uss <unclerus@gmail.com>
|
||||
*
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#ifndef __TCA95X5_H__
|
||||
#define __TCA95X5_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <i2cdev.h>
|
||||
#include <esp_err.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TCA95X5_I2C_ADDR_BASE 0x20
|
||||
|
||||
/**
|
||||
* @brief Initialize device descriptor
|
||||
*
|
||||
* Default SCL frequency is 400kHz
|
||||
*
|
||||
* @param dev Pointer to I2C device descriptor
|
||||
* @param addr I2C address (`0b0100<A2><A1><A0>`)
|
||||
* @param port I2C port number
|
||||
* @param sda_gpio SDA GPIO
|
||||
* @param scl_gpio SCL GPIO
|
||||
* @return `ESP_OK` on success
|
||||
*/
|
||||
esp_err_t tca95x5_init_desc(i2c_dev_t *dev, uint8_t addr, i2c_port_t port, gpio_num_t sda_gpio, gpio_num_t scl_gpio);
|
||||
|
||||
/**
|
||||
* @brief Free device descriptor
|
||||
* @param dev Pointer to I2C device descriptor
|
||||
* @return `ESP_OK` on success
|
||||
*/
|
||||
esp_err_t tca95x5_free_desc(i2c_dev_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Get GPIO pins mode
|
||||
*
|
||||
* 0 - output, 1 - input for each bit in `val`
|
||||
*
|
||||
* @param dev Pointer to device descriptor
|
||||
* @param[out] mode Buffer to store mode, 0 bit for P0.0 .. 15 bit for P1.7
|
||||
* @return `ESP_OK` on success
|
||||
*/
|
||||
esp_err_t tca95x5_port_get_mode(i2c_dev_t *dev, uint16_t *mode);
|
||||
|
||||
/**
|
||||
* @brief Set GPIO pins mode
|
||||
*
|
||||
* 0 - output, 1 - input for each bit in `val`
|
||||
*
|
||||
* @param dev Pointer to device descriptor
|
||||
* @param mode Mode, 0 bit for P0.0 .. 15 bit for P1.7
|
||||
* @return `ESP_OK` on success
|
||||
*/
|
||||
esp_err_t tca95x5_port_set_mode(i2c_dev_t *dev, uint16_t mode);
|
||||
|
||||
/**
|
||||
* @brief Read GPIO port value
|
||||
*
|
||||
* @param dev Pointer to I2C device descriptor
|
||||
* @param val 16-bit GPIO port value, 0 bit for P0.0 .. 15 bit for P1.7
|
||||
* @return `ESP_OK` on success
|
||||
*/
|
||||
esp_err_t tca95x5_port_read(i2c_dev_t *dev, uint16_t *val);
|
||||
|
||||
/**
|
||||
* @brief Write value to GPIO port
|
||||
*
|
||||
* @param dev Pointer to I2C device descriptor
|
||||
* @param val GPIO port value, 0 bit for P0.0 .. 15 bit for P1.7
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
esp_err_t tca95x5_port_write(i2c_dev_t *dev, uint16_t val);
|
||||
|
||||
/**
|
||||
* @brief Read GPIO pin level
|
||||
*
|
||||
* @param dev Pointer to device descriptor
|
||||
* @param pin Pin number, 0 for P0.0 .. 15 for P1.7
|
||||
* @param[out] val `true` if pin currently in high state
|
||||
* @return `ESP_OK` on success
|
||||
*/
|
||||
esp_err_t tca95x5_get_level(i2c_dev_t *dev, uint8_t pin, uint32_t *val);
|
||||
|
||||
/**
|
||||
* @brief Set GPIO pin level
|
||||
*
|
||||
* Pin must be set up as output
|
||||
*
|
||||
* @param dev Pointer to device descriptor
|
||||
* @param pin Pin number, 0 for P0.0 .. 15 for P1.7
|
||||
* @param[out] val `true` if pin currently in high state
|
||||
* @return `ESP_OK` on success
|
||||
*/
|
||||
esp_err_t tca95x5_set_level(i2c_dev_t *dev, uint8_t pin, uint32_t val);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**@}*/
|
||||
|
||||
#endif /* __TCA95X5_H__ */
|
||||
38
managed_components/joltwallet__littlefs/.bumpversion.cfg
Normal file
38
managed_components/joltwallet__littlefs/.bumpversion.cfg
Normal file
@@ -0,0 +1,38 @@
|
||||
[bumpversion]
|
||||
current_version = 1.20.3
|
||||
commit = True
|
||||
tag = True
|
||||
|
||||
[bumpversion:file:README.md]
|
||||
search = littlefs=={current_version}
|
||||
replace = littlefs=={new_version}
|
||||
|
||||
[bumpversion:file:idf_component.yml]
|
||||
search = "{current_version}"
|
||||
replace = "{new_version}"
|
||||
|
||||
[bumpversion:file:library.json]
|
||||
search = "{current_version}"
|
||||
replace = "{new_version}"
|
||||
|
||||
[bumpversion:file(number):include/esp_littlefs.h]
|
||||
search = ESP_LITTLEFS_VERSION_NUMBER "{current_version}"
|
||||
replace = ESP_LITTLEFS_VERSION_NUMBER "{new_version}"
|
||||
|
||||
[bumpversion:file(major):include/esp_littlefs.h]
|
||||
parse = (?P<major>\d+)
|
||||
serialize = {major}
|
||||
search = ESP_LITTLEFS_VERSION_MAJOR {current_version}
|
||||
replace = ESP_LITTLEFS_VERSION_MAJOR {new_version}
|
||||
|
||||
[bumpversion:file(minor):include/esp_littlefs.h]
|
||||
parse = (?P<minor>\d+)
|
||||
serialize = {minor}
|
||||
search = ESP_LITTLEFS_VERSION_MINOR {current_version}
|
||||
replace = ESP_LITTLEFS_VERSION_MINOR {new_version}
|
||||
|
||||
[bumpversion:file(patch):include/esp_littlefs.h]
|
||||
parse = (?P<patch>\d+)
|
||||
serialize = {patch}
|
||||
search = ESP_LITTLEFS_VERSION_PATCH {current_version}
|
||||
replace = ESP_LITTLEFS_VERSION_PATCH {new_version}
|
||||
1
managed_components/joltwallet__littlefs/.component_hash
Normal file
1
managed_components/joltwallet__littlefs/.component_hash
Normal file
@@ -0,0 +1 @@
|
||||
1808d73e99168f6f3c26dd31799a248484762b3a320ec4962dec11a145f4277f
|
||||
11
managed_components/joltwallet__littlefs/.gitignore
vendored
Normal file
11
managed_components/joltwallet__littlefs/.gitignore
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
build/
|
||||
sdkconfig
|
||||
sdkconfig.old
|
||||
|
||||
example/build/
|
||||
example/sdkconfig
|
||||
example/sdkconfig.old
|
||||
example/dependencies.lock
|
||||
|
||||
*.DS_Store
|
||||
*/.cache
|
||||
3
managed_components/joltwallet__littlefs/.gitmodules
vendored
Normal file
3
managed_components/joltwallet__littlefs/.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "main/littlefs"]
|
||||
path = src/littlefs
|
||||
url = https://github.com/littlefs-project/littlefs.git
|
||||
47
managed_components/joltwallet__littlefs/CMakeLists.txt
Normal file
47
managed_components/joltwallet__littlefs/CMakeLists.txt
Normal file
@@ -0,0 +1,47 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
file(GLOB SOURCES src/littlefs/*.c)
|
||||
list(APPEND SOURCES src/esp_littlefs.c src/littlefs_esp_part.c src/lfs_config.c)
|
||||
|
||||
if(IDF_TARGET STREQUAL "esp8266")
|
||||
# ESP8266 configuration here
|
||||
else()
|
||||
# non-ESP8266 configuration
|
||||
list(APPEND pub_requires sdmmc)
|
||||
|
||||
if(CONFIG_LITTLEFS_SDMMC_SUPPORT)
|
||||
list(APPEND SOURCES src/littlefs_sdmmc.c)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
list(APPEND pub_requires esp_partition)
|
||||
list(APPEND priv_requires esptool_py spi_flash vfs)
|
||||
|
||||
idf_component_register(
|
||||
SRCS ${SOURCES}
|
||||
INCLUDE_DIRS include
|
||||
PRIV_INCLUDE_DIRS src
|
||||
REQUIRES ${pub_requires}
|
||||
PRIV_REQUIRES ${priv_requires}
|
||||
)
|
||||
|
||||
set_source_files_properties(
|
||||
${SOURCES}
|
||||
PROPERTIES COMPILE_FLAGS "-DLFS_CONFIG=lfs_config.h"
|
||||
)
|
||||
|
||||
if(CONFIG_LITTLEFS_FCNTL_GET_PATH)
|
||||
target_compile_definitions(${COMPONENT_LIB} PUBLIC -DF_GETPATH=${CONFIG_LITTLEFS_FCNTL_F_GETPATH_VALUE})
|
||||
endif()
|
||||
|
||||
if(CONFIG_LITTLEFS_MULTIVERSION)
|
||||
target_compile_definitions(${COMPONENT_LIB} PUBLIC -DLFS_MULTIVERSION)
|
||||
endif()
|
||||
|
||||
if(CONFIG_LITTLEFS_MALLOC_STRATEGY_DISABLE)
|
||||
target_compile_definitions(${COMPONENT_LIB} PUBLIC -DLFS_NO_MALLOC)
|
||||
endif()
|
||||
|
||||
if(NOT CONFIG_LITTLEFS_ASSERTS)
|
||||
target_compile_definitions(${COMPONENT_LIB} PUBLIC -DLFS_NO_ASSERT)
|
||||
endif()
|
||||
273
managed_components/joltwallet__littlefs/Kconfig
Normal file
273
managed_components/joltwallet__littlefs/Kconfig
Normal file
@@ -0,0 +1,273 @@
|
||||
menu "LittleFS"
|
||||
|
||||
config LITTLEFS_SDMMC_SUPPORT
|
||||
bool "SDMMC support (requires ESP-IDF v5+)"
|
||||
default n
|
||||
help
|
||||
Toggle SD card support
|
||||
This requires IDF v5+ as older ESP-IDF do not support SD card erase.
|
||||
|
||||
config LITTLEFS_MAX_PARTITIONS
|
||||
int "Maximum Number of Partitions"
|
||||
default 3
|
||||
range 1 10
|
||||
help
|
||||
Define maximum number of partitions that can be mounted.
|
||||
|
||||
config LITTLEFS_PAGE_SIZE
|
||||
int "LITTLEFS logical page size"
|
||||
default 256
|
||||
range 256 1024
|
||||
help
|
||||
Logical page size of LITTLEFS partition, in bytes. Must be multiple
|
||||
of flash page size (which is usually 256 bytes).
|
||||
Larger page sizes reduce overhead when storing large files, and
|
||||
improve filesystem performance when reading large files.
|
||||
Smaller page sizes reduce overhead when storing small (< page size)
|
||||
files.
|
||||
|
||||
config LITTLEFS_OBJ_NAME_LEN
|
||||
int "Maximum object name length including NULL terminator."
|
||||
default 64
|
||||
range 16 1022
|
||||
help
|
||||
Includes NULL-terminator. If flashing a prebuilt filesystem image,
|
||||
rebuild the filesystem image if this value changes.
|
||||
mklittlefs, the tool that generates the image will automatically be rebuilt.
|
||||
If downloading a pre-built release of mklittlefs, it was most-likely
|
||||
built with LFS_NAME_MAX=32 and should not be used.
|
||||
|
||||
config LITTLEFS_READ_SIZE
|
||||
int "Minimum size of a block read."
|
||||
default 128
|
||||
help
|
||||
Minimum size of a block read. All read operations will be a
|
||||
multiple of this value.
|
||||
|
||||
config LITTLEFS_WRITE_SIZE
|
||||
int "Minimum size of a block write."
|
||||
default 128
|
||||
help
|
||||
Minimum size of a block program. All write operations will be a
|
||||
multiple of this value.
|
||||
|
||||
config LITTLEFS_LOOKAHEAD_SIZE
|
||||
int "Look ahead size."
|
||||
default 128
|
||||
help
|
||||
Look ahead size. Must be a multiple of 8.
|
||||
|
||||
config LITTLEFS_CACHE_SIZE
|
||||
int "Cache Size"
|
||||
default 512
|
||||
help
|
||||
Size of block caches. Each cache buffers a portion of a block in RAM.
|
||||
The littlefs needs a read cache, a program cache, and one additional
|
||||
cache per file. Larger caches can improve performance by storing more
|
||||
data and reducing the number of disk accesses. Must be a multiple of
|
||||
the read and program sizes, and a factor of the block size (4096).
|
||||
|
||||
config LITTLEFS_BLOCK_CYCLES
|
||||
int "LittleFS wear-leveling block cycles"
|
||||
default 512
|
||||
range -1 1024
|
||||
help
|
||||
Number of erase cycles before littlefs evicts metadata logs and moves
|
||||
the metadata to another block. Suggested values are in the
|
||||
range 100-1000, with large values having better performance at the cost
|
||||
of less consistent wear distribution.
|
||||
Set to -1 to disable block-level wear-leveling.
|
||||
|
||||
config LITTLEFS_USE_MTIME
|
||||
bool "Save file modification time"
|
||||
default "y"
|
||||
help
|
||||
Saves timestamp on modification. Uses an additional 4bytes.
|
||||
|
||||
config LITTLEFS_USE_ONLY_HASH
|
||||
bool "Don't store filepath in the file descriptor"
|
||||
default "n"
|
||||
help
|
||||
Records the filepath only as a 32-bit hash in the file descriptor instead
|
||||
of the entire filepath. Saves approximately `sizeof(filepath)` bytes
|
||||
per file descriptor.
|
||||
If enabled, functionality (like fstat) that requires the file path
|
||||
from the file descriptor will not work.
|
||||
In rare cases, may cause unlinking or renaming issues (unlikely) if
|
||||
there's a hash collision between an open filepath and a filepath
|
||||
to be modified.
|
||||
|
||||
config LITTLEFS_HUMAN_READABLE
|
||||
bool "Make errno human-readable"
|
||||
default "n"
|
||||
help
|
||||
Converts LittleFS error codes into human readable strings.
|
||||
May increase binary size depending on logging level.
|
||||
|
||||
choice LITTLEFS_MTIME
|
||||
prompt "mtime attribute options"
|
||||
depends on LITTLEFS_USE_MTIME
|
||||
default LITTLEFS_MTIME_USE_SECONDS
|
||||
help
|
||||
Save an additional 4-byte attribute. Options listed below.
|
||||
|
||||
config LITTLEFS_MTIME_USE_SECONDS
|
||||
bool "Use Seconds"
|
||||
help
|
||||
Saves timestamp on modification.
|
||||
|
||||
config LITTLEFS_MTIME_USE_NONCE
|
||||
bool "Use Nonce"
|
||||
help
|
||||
Saves nonce on modification; intended for detecting filechanges
|
||||
on systems without access to a RTC.
|
||||
|
||||
A file who's nonce is the same as it was at a previous time has
|
||||
high probability of not having been modified.
|
||||
|
||||
Upon file modification, the nonce is incremented by one. Upon file
|
||||
creation, a random nonce is assigned.
|
||||
|
||||
There is a very slim chance that a file will have the same nonce if
|
||||
it is deleted and created again (approx 1 in 4 billion).
|
||||
|
||||
endchoice
|
||||
|
||||
config LITTLEFS_SPIFFS_COMPAT
|
||||
bool "Improve SPIFFS drop-in compatability"
|
||||
default "n"
|
||||
help
|
||||
Enabling this feature allows for greater drop-in compatability
|
||||
when replacing SPIFFS. Since SPIFFS doesn't have folders, and
|
||||
folders are just considered as part of a file name, enabling this
|
||||
will automatically create folders as necessary to create a file
|
||||
instead of throwing an error. Similarly, upon the deletion of the
|
||||
last file in a folder, the folder will be deleted. It is recommended
|
||||
to only enable this flag as a stop-gap solution.
|
||||
|
||||
config LITTLEFS_FLUSH_FILE_EVERY_WRITE
|
||||
bool "Flush file to flash after each write operation"
|
||||
default "n"
|
||||
help
|
||||
Enabling this feature extends SPIFFS capability.
|
||||
In SPIFFS data is written immediately to the flash storage when fflush() function called.
|
||||
In LittleFS flush() does not write data to the flash, and fsync() call needed after.
|
||||
With this feature fflush() will write data to the storage.
|
||||
|
||||
config LITTLEFS_OPEN_DIR
|
||||
bool "Support opening directory"
|
||||
default "n"
|
||||
depends on !LITTLEFS_USE_ONLY_HASH && LITTLEFS_SPIFFS_COMPAT
|
||||
help
|
||||
Support opening directory by following APIs:
|
||||
|
||||
int fd = open("my_directory", O_DIRECTORY);
|
||||
|
||||
config LITTLEFS_FCNTL_GET_PATH
|
||||
bool "Support get file or directory path"
|
||||
default "n"
|
||||
depends on !LITTLEFS_USE_ONLY_HASH
|
||||
help
|
||||
Support getting directory by following APIs:
|
||||
|
||||
char buffer[MAXPATHLEN];
|
||||
|
||||
int fd = open("my_file", flags);
|
||||
fcntl(fd, F_GETPATH, buffer);
|
||||
|
||||
config LITTLEFS_FCNTL_F_GETPATH_VALUE
|
||||
int "Value of command F_GETPATH"
|
||||
default 20
|
||||
depends on LITTLEFS_FCNTL_GET_PATH
|
||||
help
|
||||
ESP-IDF's header file "fcntl.h" doesn't support macro "F_GETPATH",
|
||||
so we should define this macro here.
|
||||
|
||||
config LITTLEFS_MULTIVERSION
|
||||
bool "Support selecting the LittleFS minor version to write to disk"
|
||||
default "n"
|
||||
help
|
||||
LittleFS 2.6 bumps the on-disk minor version of littlefs from lfs2.0 -> lfs2.1.
|
||||
|
||||
This change is backwards-compatible, but after the first write with the new version,
|
||||
the image on disk will no longer be mountable by older versions of littlefs.
|
||||
|
||||
Enabling LITTLEFS_MULTIVERSION allows to select the On-disk version
|
||||
to use when writing in the form of 16-bit major version
|
||||
+ 16-bit minor version. This limiting metadata to what is supported by
|
||||
older minor versions. Note that some features will be lost. Defaults to
|
||||
to the most recent minor version when zero.
|
||||
|
||||
choice LITTLEFS_DISK_VERSION
|
||||
prompt "LITTLEFS_DISK_VERSION"
|
||||
depends on LITTLEFS_MULTIVERSION
|
||||
default LITTLEFS_DISK_VERSION_MOST_RECENT
|
||||
help
|
||||
See LITTLEFS_MULTIVERSION for details.
|
||||
|
||||
config LITTLEFS_DISK_VERSION_MOST_RECENT
|
||||
bool "Write the most recent LittleFS version"
|
||||
|
||||
config LITTLEFS_DISK_VERSION_2_1
|
||||
bool "Write LittleFS 2.1"
|
||||
|
||||
config LITTLEFS_DISK_VERSION_2_0
|
||||
bool "Write LittleFS 2.0 (no forward-looking erase-state CRCs)"
|
||||
|
||||
endchoice
|
||||
|
||||
choice LITTLEFS_MALLOC_STRATEGY
|
||||
prompt "Buffer allocation strategy"
|
||||
default LITTLEFS_MALLOC_STRATEGY_DEFAULT
|
||||
help
|
||||
Maps lfs_malloc to ESP-IDF capabilities-based memory allocator or
|
||||
disables dynamic allocation in favour of user-provided static buffers.
|
||||
|
||||
config LITTLEFS_MALLOC_STRATEGY_DISABLE
|
||||
bool "Static buffers only"
|
||||
help
|
||||
Disallow dynamic allocation, static buffers must be provided by the calling application.
|
||||
|
||||
config LITTLEFS_MALLOC_STRATEGY_DEFAULT
|
||||
bool "Default heap selection"
|
||||
help
|
||||
Uses an automatic allocation strategy. On systems with heap in SPIRAM, if
|
||||
the allocation size does not exceed SPIRAM_MALLOC_ALWAYSINTERNAL then internal
|
||||
heap allocation if preferred, otherwise allocation will be attempted from SPIRAM
|
||||
heap.
|
||||
|
||||
config LITTLEFS_MALLOC_STRATEGY_INTERNAL
|
||||
bool "Internal heap"
|
||||
help
|
||||
Uses ESP-IDF heap_caps_malloc to allocate from internal heap.
|
||||
|
||||
config LITTLEFS_MALLOC_STRATEGY_SPIRAM
|
||||
bool "SPIRAM heap"
|
||||
depends on SPIRAM_USE_MALLOC || SPIRAM_USE_CAPS_ALLOC
|
||||
help
|
||||
Uses ESP-IDF heap_caps_malloc to allocate from SPIRAM heap.
|
||||
|
||||
endchoice
|
||||
|
||||
config LITTLEFS_ASSERTS
|
||||
bool "Enable asserts"
|
||||
default "y"
|
||||
help
|
||||
Selects whether littlefs performs runtime assert checks.
|
||||
|
||||
config LITTLEFS_MMAP_PARTITION
|
||||
bool "Memory map LITTLEFS partitions"
|
||||
default "n"
|
||||
help
|
||||
Use esp_partition_mmap to map the partitions to memory, which can provide a significant
|
||||
performance boost in some cases. Make sure the chip you're using has enough available address
|
||||
space to map the partition (for the ESP32 there is 4MB available).
|
||||
|
||||
config LITTLEFS_WDT_RESET
|
||||
bool "Reset task watchdog during flash operations"
|
||||
default "n"
|
||||
help
|
||||
Enable calling esp_task_wdt_reset() during flash read/write/erase operations
|
||||
to prevent task watchdog timeouts during long-running filesystem operations.
|
||||
|
||||
endmenu
|
||||
7
managed_components/joltwallet__littlefs/LICENSE
Normal file
7
managed_components/joltwallet__littlefs/LICENSE
Normal file
@@ -0,0 +1,7 @@
|
||||
Copyright 2020 Brian Pugh
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
28
managed_components/joltwallet__littlefs/Makefile
Normal file
28
managed_components/joltwallet__littlefs/Makefile
Normal file
@@ -0,0 +1,28 @@
|
||||
PROJECT_NAME := littlefs
|
||||
|
||||
EXTRA_COMPONENT_DIRS := \
|
||||
$(abspath .) \
|
||||
$(abspath unit_tester) \
|
||||
$(IDF_PATH)/tools/unit-test-app/components/
|
||||
|
||||
CFLAGS += \
|
||||
-Werror
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
||||
.PHONY: tests
|
||||
|
||||
tests-build:
|
||||
$(MAKE) \
|
||||
TEST_COMPONENTS='src'
|
||||
|
||||
tests:
|
||||
$(MAKE) \
|
||||
TEST_COMPONENTS='src' \
|
||||
flash monitor;
|
||||
|
||||
tests-enc:
|
||||
$(MAKE) \
|
||||
TEST_COMPONENTS='src' \
|
||||
encrypted-flash monitor;
|
||||
|
||||
267
managed_components/joltwallet__littlefs/README.md
Normal file
267
managed_components/joltwallet__littlefs/README.md
Normal file
@@ -0,0 +1,267 @@
|
||||
LittleFS for ESP-IDF.
|
||||
|
||||
# What is LittleFS?
|
||||
|
||||
[LittleFS](https://github.com/ARMmbed/littlefs) is a small fail-safe filesystem
|
||||
for microcontrollers. We ported LittleFS to esp-idf (specifically, the ESP32)
|
||||
because SPIFFS was too slow, and FAT was too fragile.
|
||||
|
||||
# How to Use
|
||||
|
||||
## ESP-IDF
|
||||
|
||||
There are two ways to add this component to your project
|
||||
|
||||
1. As a ESP-IDF managed component: In your project directory run
|
||||
|
||||
```
|
||||
idf.py add-dependency joltwallet/littlefs==1.20.3
|
||||
```
|
||||
|
||||
2. As a submodule: In your project, add this as a submodule to your `components/` directory.
|
||||
|
||||
```
|
||||
git submodule add https://github.com/joltwallet/esp_littlefs.git
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
The library can be configured via `idf.py menuconfig` under `Component config->LittleFS`.
|
||||
|
||||
#### Example
|
||||
User @wreyford has kindly provided a [demo repo](https://github.com/wreyford/demo_esp_littlefs) showing the use of `esp_littlefs`. A modified copy exists in the `example/` directory.
|
||||
|
||||
## PlatformIO
|
||||
Add to the following line to your project's `platformio.ini` file:
|
||||
|
||||
```
|
||||
lib_deps = https://github.com/joltwallet/esp_littlefs.git
|
||||
```
|
||||
|
||||
Example `platformio.ini` file:
|
||||
|
||||
```
|
||||
[env]
|
||||
platform = espressif32
|
||||
framework = espidf
|
||||
monitor_speed = 115200
|
||||
|
||||
[common]
|
||||
lib_deps = https://github.com/joltwallet/esp_littlefs.git
|
||||
|
||||
[env:nodemcu-32s]
|
||||
board = nodemcu-32s
|
||||
board_build.filesystem = littlefs
|
||||
board_build.partitions = min_littlefs.csv
|
||||
lib_deps = ${common.lib_deps}
|
||||
```
|
||||
|
||||
Example `min_littlefs.cvs` flash partition layout:
|
||||
```
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x1E0000,
|
||||
app1, app, ota_1, 0x1F0000,0x1E0000,
|
||||
littlefs, data, littlefs, 0x3D0000,0x20000,
|
||||
coredump, data, coredump, 0x3F0000,0x10000,
|
||||
```
|
||||
|
||||
[Currently, it is required](https://github.com/platformio/platform-espressif32/issues/479) to modify `CMakeList.txt`. Add the following 2 lines to the your project's `CMakeList.txt`:
|
||||
|
||||
```
|
||||
get_filename_component(configName "${CMAKE_BINARY_DIR}" NAME)
|
||||
list(APPEND EXTRA_COMPONENT_DIRS "${CMAKE_SOURCE_DIR}/.pio/libdeps/${configName}/esp_littlefs")
|
||||
```
|
||||
|
||||
Example `CMakeList.txt`:
|
||||
|
||||
```
|
||||
cmake_minimum_required(VERSION 3.16.0)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
get_filename_component(configName "${CMAKE_BINARY_DIR}" NAME)
|
||||
list(APPEND EXTRA_COMPONENT_DIRS "${CMAKE_SOURCE_DIR}/.pio/libdeps/${configName}/esp_littlefs")
|
||||
|
||||
project(my_project_name_here)
|
||||
```
|
||||
|
||||
To configure LittleFS from PlatformIO, run the following command:
|
||||
|
||||
```console
|
||||
$ pio run -t menuconfig
|
||||
```
|
||||
An entry `Component config->LittleFS` should be available for configuration. If not, check your `CMakeList.txt` configuration.
|
||||
|
||||
|
||||
# Documentation
|
||||
|
||||
See the official [ESP-IDF SPIFFS documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/storage/spiffs.html), basically all the functionality is the
|
||||
same; just replace `spiffs` with `littlefs` in all function calls.
|
||||
|
||||
Also see the comments in `include/esp_littlefs.h`
|
||||
|
||||
Slight differences between this configuration and SPIFFS's configuration is in the `esp_vfs_littlefs_conf_t`:
|
||||
|
||||
1. `max_files` field doesn't exist since we removed the file limit, thanks to @X-Ryl669
|
||||
2. `grow_on_mount` will expand an existing filesystem to fill the partition. Defaults to `false`.
|
||||
* LittleFS filesystems can only grow, they cannot shrink.
|
||||
|
||||
### Filesystem Image Creation
|
||||
|
||||
At compile time, a filesystem image can be created and flashed to the device by adding the following to your project's `CMakeLists.txt` file:
|
||||
|
||||
```
|
||||
littlefs_create_partition_image(partition_name path_to_folder_containing_files FLASH_IN_PROJECT)
|
||||
```
|
||||
|
||||
If `FLASH_IN_PROJECT` is not specified, the image will still be generated, but you will have to flash it manually using `esptool.py`, `parttool.py`, or a custom build system target.
|
||||
|
||||
For example, if your partition table looks like:
|
||||
|
||||
```
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x6000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
factory, app, factory, 0x10000, 1M,
|
||||
graphics, data, spiffs, , 0xF0000,
|
||||
```
|
||||
|
||||
change it to:
|
||||
|
||||
```
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x6000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
factory, app, factory, 0x10000, 1M,
|
||||
graphics, data, littlefs, , 0xF0000,
|
||||
```
|
||||
|
||||
|
||||
and your project has a folder called `device_graphics/`, your call should be:
|
||||
|
||||
```
|
||||
littlefs_create_partition_image(graphics device_graphics FLASH_IN_PROJECT)
|
||||
```
|
||||
|
||||
|
||||
# Performance
|
||||
|
||||
Here are some naive benchmarks to give a vague indicator on performance.
|
||||
Tests were performed with the following configuration:
|
||||
|
||||
* ESP-IDF: v4.4
|
||||
* Target: ESP32
|
||||
* CPU Clock: 160MHz
|
||||
* Flash SPI Freq: 80MHz
|
||||
* Flash SPI Mode: QIO
|
||||
|
||||
In these tests, FAT has a cache size of 4096, and SPIFFS has a cahce size of 256 bytes.
|
||||
|
||||
#### Formatting a 512KB partition
|
||||
|
||||
```
|
||||
FAT: 549,494 us
|
||||
SPIFFS: 10,715,425 us
|
||||
LittleFS: 110,997 us
|
||||
```
|
||||
|
||||
#### Writing 5 88KB files
|
||||
|
||||
```
|
||||
FAT: 7,124,812 us
|
||||
SPIFFS*: 99,138,905 us
|
||||
LittleFS (cache=128): 8,261,920 us
|
||||
LittleFS (cache=512 default): 6,356,247 us
|
||||
LittleFS (cache=4096): 6,026,592 us
|
||||
*Only wrote 374,784 bytes instead of the benchmark 440,000, so this value is extrapolated
|
||||
```
|
||||
|
||||
In the above test, SPIFFS drastically slows down as the filesystem fills up. Below
|
||||
is the specific breakdown of file write times for SPIFFS. Not sure what happens
|
||||
on the last file write.
|
||||
|
||||
|
||||
```
|
||||
SPIFFS:
|
||||
|
||||
88000 bytes written in 2190635 us
|
||||
88000 bytes written in 2190321 us
|
||||
88000 bytes written in 5133605 us
|
||||
88000 bytes written in 16570667 us
|
||||
22784 bytes written in 73053677 us
|
||||
```
|
||||
|
||||
#### Reading 5 88KB files
|
||||
|
||||
```
|
||||
FAT: 5,685,230 us
|
||||
SPIFFS*: 5,162,289 us
|
||||
LittleFS (cache=128): 6,284,142 us
|
||||
LittleFS (cache=512 default): 5,874,931 us
|
||||
LittleFS (cache=4096): 5,731,385 us
|
||||
*Only read 374,784 bytes instead of the benchmark 440,000, so this value is extrapolated
|
||||
```
|
||||
|
||||
#### Deleting 5 88KB files
|
||||
|
||||
```
|
||||
FAT: 680,358 us
|
||||
SPIFFS*: 1,653,500 us
|
||||
LittleFS (cache=128): 86,090 us
|
||||
LittleFS (cache=512 default): 53,705 us
|
||||
LittleFS (cache=4096): 27,709 us
|
||||
*The 5th file was smaller, did not extrapolate value.
|
||||
```
|
||||
|
||||
|
||||
# Tips, Tricks, and Gotchas
|
||||
|
||||
* LittleFS operates on blocks, and blocks have a size of 4096 bytes on the ESP32.
|
||||
|
||||
* A freshly formatted LittleFS will have 2 blocks in use, making it seem like 8KB are in use.
|
||||
|
||||
* The esp32 has [flash concurrency constraints](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/spi_flash/spi_flash_concurrency.html#concurrency-constraints-for-flash-on-spi1).
|
||||
When using UART (either for data transfer or generic logging) at the same time, you *MUST* enable the following option in KConfig:
|
||||
`menuconfig > Component config > Driver config > UART > UART ISR in IRAM`.
|
||||
|
||||
# Running Unit Tests
|
||||
|
||||
To flash the unit-tester app and the unit-tests, clone or symbolicly link this
|
||||
component to `$IDF_PATH/tools/unit-test-app/components/littlefs`. Make sure the
|
||||
folder name is `littlefs`, not `esp_littlefs`. Then, run the following:
|
||||
|
||||
```
|
||||
cd $IDF_PATH/tools/unit-test-app
|
||||
idf.py menuconfig # See notes
|
||||
idf.py -T littlefs -p YOUR_PORT_HERE flash monitor
|
||||
```
|
||||
|
||||
In `menuconfig`:
|
||||
|
||||
* Set the partition table to `components/littlefs/partition_table_unit_test_app.csv`
|
||||
|
||||
* Double check your crystal frequency `ESP32_XTAL_FREQ_SEL`; my board doesn't work with autodetect.
|
||||
|
||||
To test on an encrypted partition, add the `encrypted` flag to the `flash_test` partition
|
||||
in `partition_table_unit_test_app.csv`. I.e.
|
||||
|
||||
```
|
||||
flash_test, data, spiffs, , 512K, encrypted
|
||||
```
|
||||
|
||||
Also make sure that `CONFIG_SECURE_FLASH_ENC_ENABLED=y` in `menuconfig`.
|
||||
|
||||
The unit tester can then be flashed via the command:
|
||||
|
||||
```
|
||||
idf.py -T littlefs -p YOUR_PORT_HERE encrypted-flash monitor
|
||||
```
|
||||
|
||||
# Breaking Changes
|
||||
|
||||
* July 22, 2020 - Changed attribute type for file timestamp from `0` to `0x74` ('t' ascii value).
|
||||
* May 3, 2023 - All logging tags have been changed to a unified `esp_littlefs`.
|
||||
|
||||
# Acknowledgement
|
||||
|
||||
This code base was heavily modeled after the SPIFFS esp-idf component.
|
||||
24
managed_components/joltwallet__littlefs/component.mk
Normal file
24
managed_components/joltwallet__littlefs/component.mk
Normal file
@@ -0,0 +1,24 @@
|
||||
#
|
||||
# Component Makefile
|
||||
#
|
||||
|
||||
COMPONENT_SRCDIRS := src src/littlefs
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := include
|
||||
|
||||
COMPONENT_PRIV_INCLUDEDIRS := src
|
||||
|
||||
COMPONENT_SUBMODULES := src/littlefs
|
||||
|
||||
CFLAGS += \
|
||||
-DLFS_CONFIG=lfs_config.h
|
||||
|
||||
ifdef CONFIG_LITTLEFS_FCNTL_GET_PATH
|
||||
CFLAGS += \
|
||||
-DF_GETPATH=$(CONFIG_LITTLEFS_FCNTL_F_GETPATH_VALUE)
|
||||
endif
|
||||
|
||||
ifdef CONFIG_LITTLEFS_MULTIVERSION
|
||||
CFLAGS += \
|
||||
-DLFS_MULTIVERSION
|
||||
endif
|
||||
@@ -0,0 +1,9 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
# Add the root of this git repo to the component search path.
|
||||
set(EXTRA_COMPONENT_DIRS "../")
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(demo_esp_littlefs)
|
||||
11
managed_components/joltwallet__littlefs/example/Makefile
Normal file
11
managed_components/joltwallet__littlefs/example/Makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := demo_esp_littlefs
|
||||
|
||||
EXTRA_COMPONENT_DIRS := $(realpath ..)
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
This example is based on [wreyford's](https://github.com/wreyford/demo_esp_littlefs) demo project.
|
||||
|
||||
Modifications were made so that this example project could be built as a part of CI.
|
||||
@@ -0,0 +1 @@
|
||||
Example text to compile into a LittleFS disk image to be flashed to the ESP device.
|
||||
@@ -0,0 +1,7 @@
|
||||
idf_component_register(SRCS "demo_esp_littlefs.c"
|
||||
INCLUDE_DIRS "."
|
||||
)
|
||||
|
||||
# Note: you must have a partition named the first argument (here it's "littlefs")
|
||||
# in your partition table csv file.
|
||||
littlefs_create_partition_image(littlefs ../flash_data FLASH_IN_PROJECT)
|
||||
@@ -0,0 +1,5 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
/* Demo ESP LittleFS Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_system.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "sdkconfig.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include "esp_idf_version.h"
|
||||
#include "esp_flash.h"
|
||||
#include "esp_chip_info.h"
|
||||
#include "spi_flash_mmap.h"
|
||||
|
||||
|
||||
#include "esp_littlefs.h"
|
||||
|
||||
static const char *TAG = "demo_esp_littlefs";
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
printf("Demo LittleFs implementation by esp_littlefs!\n");
|
||||
printf(" https://github.com/joltwallet/esp_littlefs\n");
|
||||
|
||||
/* Print chip information */
|
||||
esp_chip_info_t chip_info;
|
||||
esp_chip_info(&chip_info);
|
||||
printf("This is %s chip with %d CPU cores, WiFi%s%s, ",
|
||||
CONFIG_IDF_TARGET,
|
||||
chip_info.cores,
|
||||
(chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
|
||||
(chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "");
|
||||
|
||||
printf("silicon revision %d, ", chip_info.revision);
|
||||
|
||||
uint32_t size_flash_chip = 0;
|
||||
esp_flash_get_size(NULL, &size_flash_chip);
|
||||
printf("%uMB %s flash\n", (unsigned int)size_flash_chip >> 20,
|
||||
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");
|
||||
|
||||
printf("Free heap: %u\n", (unsigned int) esp_get_free_heap_size());
|
||||
|
||||
printf("Now we are starting the LittleFs Demo ...\n");
|
||||
|
||||
ESP_LOGI(TAG, "Initializing LittleFS");
|
||||
|
||||
esp_vfs_littlefs_conf_t conf = {
|
||||
.base_path = "/littlefs",
|
||||
.partition_label = "littlefs",
|
||||
.format_if_mount_failed = true,
|
||||
.dont_mount = false,
|
||||
};
|
||||
|
||||
// Use settings defined above to initialize and mount LittleFS filesystem.
|
||||
// Note: esp_vfs_littlefs_register is an all-in-one convenience function.
|
||||
esp_err_t ret = esp_vfs_littlefs_register(&conf);
|
||||
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
if (ret == ESP_FAIL)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to mount or format filesystem");
|
||||
}
|
||||
else if (ret == ESP_ERR_NOT_FOUND)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to find LittleFS partition");
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to initialize LittleFS (%s)", esp_err_to_name(ret));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
size_t total = 0, used = 0;
|
||||
ret = esp_littlefs_info(conf.partition_label, &total, &used);
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to get LittleFS partition information (%s)", esp_err_to_name(ret));
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used);
|
||||
}
|
||||
|
||||
// Use POSIX and C standard library functions to work with files.
|
||||
// First create a file.
|
||||
ESP_LOGI(TAG, "Opening file");
|
||||
FILE *f = fopen("/littlefs/hello.txt", "w");
|
||||
if (f == NULL)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to open file for writing");
|
||||
return;
|
||||
}
|
||||
fprintf(f, "LittleFS Rocks!\n");
|
||||
fclose(f);
|
||||
ESP_LOGI(TAG, "File written");
|
||||
|
||||
// Check if destination file exists before renaming
|
||||
struct stat st;
|
||||
if (stat("/littlefs/foo.txt", &st) == 0)
|
||||
{
|
||||
// Delete it if it exists
|
||||
unlink("/littlefs/foo.txt");
|
||||
}
|
||||
|
||||
// Rename original file
|
||||
ESP_LOGI(TAG, "Renaming file");
|
||||
if (rename("/littlefs/hello.txt", "/littlefs/foo.txt") != 0)
|
||||
{
|
||||
ESP_LOGE(TAG, "Rename failed");
|
||||
return;
|
||||
}
|
||||
|
||||
// Open renamed file for reading
|
||||
ESP_LOGI(TAG, "Reading file");
|
||||
f = fopen("/littlefs/foo.txt", "r");
|
||||
if (f == NULL)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to open file for reading");
|
||||
return;
|
||||
}
|
||||
|
||||
char line[128];
|
||||
char *pos;
|
||||
|
||||
fgets(line, sizeof(line), f);
|
||||
fclose(f);
|
||||
// strip newline
|
||||
pos = strchr(line, '\n');
|
||||
if (pos)
|
||||
{
|
||||
*pos = '\0';
|
||||
}
|
||||
ESP_LOGI(TAG, "Read from file: '%s'", line);
|
||||
|
||||
ESP_LOGI(TAG, "Reading from flashed filesystem example.txt");
|
||||
f = fopen("/littlefs/example.txt", "r");
|
||||
if (f == NULL)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to open file for reading");
|
||||
return;
|
||||
}
|
||||
fgets(line, sizeof(line), f);
|
||||
fclose(f);
|
||||
// strip newline
|
||||
pos = strchr(line, '\n');
|
||||
if (pos)
|
||||
{
|
||||
*pos = '\0';
|
||||
}
|
||||
ESP_LOGI(TAG, "Read from file: '%s'", line);
|
||||
|
||||
// All done, unmount partition and disable LittleFS
|
||||
esp_vfs_littlefs_unregister(conf.partition_label);
|
||||
ESP_LOGI(TAG, "LittleFS unmounted");
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
|
||||
nvs, data, nvs, 0x9000, 0x6000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
factory, app, factory, 0x10000, 1M,
|
||||
littlefs, data, littlefs, , 0xF0000,
|
||||
|
@@ -0,0 +1,12 @@
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_demo_esp_littlefs.csv"
|
||||
|
||||
#
|
||||
# Serial flasher config
|
||||
#
|
||||
CONFIG_ESPTOOLPY_BAUD_921600B=y
|
||||
CONFIG_ESPTOOLPY_COMPRESSED=y
|
||||
CONFIG_ESPTOOLPY_MONITOR_BAUD_CONSOLE=y
|
||||
|
||||
# BOOTLOADER
|
||||
CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y
|
||||
@@ -0,0 +1,9 @@
|
||||
dependencies:
|
||||
idf: '>=5.0'
|
||||
description: LittleFS is a small fail-safe filesystem for micro-controllers.
|
||||
repository: git://github.com/joltwallet/esp_littlefs.git
|
||||
repository_info:
|
||||
commit_sha: 8274371dc5912196f66ac3e71dbb6291760cb8b0
|
||||
path: .
|
||||
url: https://github.com/joltwallet/esp_littlefs
|
||||
version: 1.20.3
|
||||
@@ -0,0 +1 @@
|
||||
littlefs-python==0.15.0
|
||||
212
managed_components/joltwallet__littlefs/include/esp_littlefs.h
Normal file
212
managed_components/joltwallet__littlefs/include/esp_littlefs.h
Normal file
@@ -0,0 +1,212 @@
|
||||
#ifndef ESP_LITTLEFS_H__
|
||||
#define ESP_LITTLEFS_H__
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_idf_version.h"
|
||||
#include <stdbool.h>
|
||||
#include "esp_partition.h"
|
||||
|
||||
#ifdef CONFIG_LITTLEFS_SDMMC_SUPPORT
|
||||
#include <sdmmc_cmd.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ESP_LITTLEFS_VERSION_NUMBER "1.20.3"
|
||||
#define ESP_LITTLEFS_VERSION_MAJOR 1
|
||||
#define ESP_LITTLEFS_VERSION_MINOR 20
|
||||
#define ESP_LITTLEFS_VERSION_PATCH 3
|
||||
|
||||
#ifdef ESP8266
|
||||
// ESP8266 RTOS SDK default enables VFS DIR support
|
||||
#define CONFIG_VFS_SUPPORT_DIR 1
|
||||
#endif
|
||||
|
||||
#if CONFIG_VFS_SUPPORT_DIR
|
||||
#define ESP_LITTLEFS_ENABLE_FTRUNCATE
|
||||
#endif // CONFIG_VFS_SUPPORT_DIR
|
||||
|
||||
/**
|
||||
*Configuration structure for esp_vfs_littlefs_register.
|
||||
*/
|
||||
typedef struct {
|
||||
const char *base_path; /**< Mounting point. */
|
||||
const char *partition_label; /**< Label of partition to use. If partition_label, partition, and sdcard are all NULL,
|
||||
then the first partition with data subtype 'littlefs' will be used. */
|
||||
const esp_partition_t* partition; /**< partition to use if partition_label is NULL */
|
||||
|
||||
#ifdef CONFIG_LITTLEFS_SDMMC_SUPPORT
|
||||
sdmmc_card_t *sdcard; /**< SD card handle to use if both esp_partition handle & partition label is NULL */
|
||||
#endif
|
||||
|
||||
uint8_t format_if_mount_failed:1; /**< Format the file system if it fails to mount. */
|
||||
uint8_t read_only : 1; /**< Mount the partition as read-only. */
|
||||
uint8_t dont_mount:1; /**< Don't attempt to mount.*/
|
||||
uint8_t grow_on_mount:1; /**< Grow filesystem to match partition size on mount.*/
|
||||
} esp_vfs_littlefs_conf_t;
|
||||
|
||||
/**
|
||||
* Register and mount (if configured to) littlefs to VFS with given path prefix.
|
||||
*
|
||||
* @param conf Pointer to esp_vfs_littlefs_conf_t configuration structure
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if success
|
||||
* - ESP_ERR_NO_MEM if objects could not be allocated
|
||||
* - ESP_ERR_INVALID_STATE if already mounted or partition is encrypted
|
||||
* - ESP_ERR_NOT_FOUND if partition for littlefs was not found
|
||||
* - ESP_FAIL if mount or format fails
|
||||
*/
|
||||
esp_err_t esp_vfs_littlefs_register(const esp_vfs_littlefs_conf_t * conf);
|
||||
|
||||
/**
|
||||
* Unregister and unmount littlefs from VFS
|
||||
*
|
||||
* @param partition_label Label of the partition to unregister.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if successful
|
||||
* - ESP_ERR_INVALID_STATE already unregistered
|
||||
*/
|
||||
esp_err_t esp_vfs_littlefs_unregister(const char* partition_label);
|
||||
|
||||
#ifdef CONFIG_LITTLEFS_SDMMC_SUPPORT
|
||||
/**
|
||||
* Unregister and unmount LittleFS from VFS for SD card
|
||||
*
|
||||
* @param sdcard SD card to unregister.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if successful
|
||||
* - ESP_ERR_INVALID_STATE already unregistered
|
||||
*/
|
||||
esp_err_t esp_vfs_littlefs_unregister_sdmmc(sdmmc_card_t *sdcard);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Unregister and unmount littlefs from VFS
|
||||
*
|
||||
* @param partition partition to unregister.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if successful
|
||||
* - ESP_ERR_INVALID_STATE already unregistered
|
||||
*/
|
||||
esp_err_t esp_vfs_littlefs_unregister_partition(const esp_partition_t* partition);
|
||||
|
||||
/**
|
||||
* Check if littlefs is mounted
|
||||
*
|
||||
* @param partition_label Label of the partition to check.
|
||||
*
|
||||
* @return
|
||||
* - true if mounted
|
||||
* - false if not mounted
|
||||
*/
|
||||
bool esp_littlefs_mounted(const char* partition_label);
|
||||
|
||||
/**
|
||||
* Check if littlefs is mounted
|
||||
*
|
||||
* @param partition partition to check.
|
||||
*
|
||||
* @return
|
||||
* - true if mounted
|
||||
* - false if not mounted
|
||||
*/
|
||||
bool esp_littlefs_partition_mounted(const esp_partition_t* partition);
|
||||
|
||||
#ifdef CONFIG_LITTLEFS_SDMMC_SUPPORT
|
||||
/**
|
||||
* Check if littlefs is mounted
|
||||
*
|
||||
* @param sdcard SD card to check.
|
||||
*
|
||||
* @return
|
||||
* - true if mounted
|
||||
* - false if not mounted
|
||||
*/
|
||||
bool esp_littlefs_sdmmc_mounted(sdmmc_card_t *sdcard);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Format the littlefs partition
|
||||
*
|
||||
* @param partition_label Label of the partition to format.
|
||||
* @return
|
||||
* - ESP_OK if successful
|
||||
* - ESP_FAIL on error
|
||||
*/
|
||||
esp_err_t esp_littlefs_format(const char* partition_label);
|
||||
|
||||
/**
|
||||
* Format the littlefs partition
|
||||
*
|
||||
* @param partition partition to format.
|
||||
* @return
|
||||
* - ESP_OK if successful
|
||||
* - ESP_FAIL on error
|
||||
*/
|
||||
esp_err_t esp_littlefs_format_partition(const esp_partition_t* partition);
|
||||
|
||||
#ifdef CONFIG_LITTLEFS_SDMMC_SUPPORT
|
||||
/**
|
||||
* Format the LittleFS on a SD card
|
||||
*
|
||||
* @param sdcard SD card to format
|
||||
* @return
|
||||
* - ESP_OK if successful
|
||||
* - ESP_FAIL on error
|
||||
*/
|
||||
esp_err_t esp_littlefs_format_sdmmc(sdmmc_card_t *sdcard);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get information for littlefs
|
||||
*
|
||||
* @param partition_label Optional, label of the partition to get info for.
|
||||
* @param[out] total_bytes Size of the file system
|
||||
* @param[out] used_bytes Current used bytes in the file system
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if success
|
||||
* - ESP_ERR_INVALID_STATE if not mounted
|
||||
*/
|
||||
esp_err_t esp_littlefs_info(const char* partition_label, size_t* total_bytes, size_t* used_bytes);
|
||||
|
||||
/**
|
||||
* Get information for littlefs
|
||||
*
|
||||
* @param parition the partition to get info for.
|
||||
* @param[out] total_bytes Size of the file system
|
||||
* @param[out] used_bytes Current used bytes in the file system
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if success
|
||||
* - ESP_ERR_INVALID_STATE if not mounted
|
||||
*/
|
||||
esp_err_t esp_littlefs_partition_info(const esp_partition_t* partition, size_t *total_bytes, size_t *used_bytes);
|
||||
|
||||
#ifdef CONFIG_LITTLEFS_SDMMC_SUPPORT
|
||||
/**
|
||||
* Get information for littlefs on SD card
|
||||
*
|
||||
* @param[in] sdcard the SD card to get info for.
|
||||
* @param[out] total_bytes Size of the file system
|
||||
* @param[out] used_bytes Current used bytes in the file system
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if success
|
||||
* - ESP_ERR_INVALID_STATE if not mounted
|
||||
*/
|
||||
esp_err_t esp_littlefs_sdmmc_info(sdmmc_card_t *sdcard, size_t *total_bytes, size_t *used_bytes);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user