├── .clang-format ├── .github ├── ISSUE_TEMPLATE │ └── bug-report.yml ├── actions │ ├── action.yml │ └── arduino-test-compile.sh └── workflows │ ├── Arduino-Lint-Check.yml │ ├── arduino-action-compile.yml │ └── clang-format-check.yml ├── .gitignore ├── LICENSE ├── README.md ├── README_cn.md ├── examples ├── Advanced │ └── i2c_tester │ │ └── i2c_tester.ino ├── Basic │ ├── button │ │ └── button.ino │ ├── camera │ │ └── camera.ino │ ├── display │ │ └── display.ino │ ├── imu │ │ └── imu.ino │ ├── ltr553 │ │ └── ltr553.ino │ ├── mic │ │ └── mic.ino │ ├── mic_wav_record │ │ └── mic_wav_record.ino │ ├── power │ │ └── power.ino │ ├── rtc │ │ └── rtc.ino │ ├── sdcard │ │ └── sdcard.ino │ ├── speaker │ │ ├── audio_file.h │ │ └── speaker.ino │ ├── touch │ │ └── touch.ino │ └── wakeup │ │ └── wakeup.ino ├── Module │ └── 4EncoderMotor │ │ └── 4EncoderMotor.ino └── Unit │ ├── DAC2_GP8413 │ └── DAC2_GP8413.ino │ └── MiniCAN_TJA1051T │ ├── Master │ └── Master.ino │ └── Slave │ └── Slave.ino ├── library.json ├── library.properties ├── platformio.ini └── src ├── M5CoreS3.cpp ├── M5CoreS3.h └── utility ├── GC0308.cpp ├── GC0308.h ├── LTR5XX.cpp └── LTR5XX.h /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | BasedOnStyle: Google 4 | AccessModifierOffset: -1 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveMacros: true 7 | AlignConsecutiveAssignments: true 8 | AlignConsecutiveDeclarations: false 9 | AlignEscapedNewlines: Left 10 | AlignOperands: true 11 | AlignTrailingComments: true 12 | AllowAllArgumentsOnNextLine: true 13 | AllowAllConstructorInitializersOnNextLine: true 14 | AllowAllParametersOfDeclarationOnNextLine: true 15 | AllowShortBlocksOnASingleLine: Never 16 | AllowShortCaseLabelsOnASingleLine: false 17 | AllowShortFunctionsOnASingleLine: false 18 | AllowShortLambdasOnASingleLine: All 19 | AllowShortIfStatementsOnASingleLine: WithoutElse 20 | AllowShortLoopsOnASingleLine: true 21 | AlwaysBreakAfterDefinitionReturnType: None 22 | AlwaysBreakAfterReturnType: None 23 | AlwaysBreakBeforeMultilineStrings: true 24 | AlwaysBreakTemplateDeclarations: Yes 25 | BinPackArguments: true 26 | BinPackParameters: true 27 | BraceWrapping: 28 | AfterCaseLabel: false 29 | AfterClass: false 30 | AfterControlStatement: false 31 | AfterEnum: false 32 | AfterFunction: false 33 | AfterNamespace: false 34 | AfterObjCDeclaration: false 35 | AfterStruct: false 36 | AfterUnion: false 37 | AfterExternBlock: false 38 | BeforeCatch: false 39 | BeforeElse: false 40 | IndentBraces: false 41 | SplitEmptyFunction: true 42 | SplitEmptyRecord: true 43 | SplitEmptyNamespace: true 44 | BreakBeforeBinaryOperators: None 45 | BreakBeforeBraces: Attach 46 | BreakBeforeInheritanceComma: false 47 | BreakInheritanceList: BeforeColon 48 | BreakBeforeTernaryOperators: true 49 | BreakConstructorInitializersBeforeComma: false 50 | BreakConstructorInitializers: BeforeColon 51 | BreakAfterJavaFieldAnnotations: false 52 | BreakStringLiterals: true 53 | ColumnLimit: 80 54 | CommentPragmas: '^ IWYU pragma:' 55 | CompactNamespaces: false 56 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 57 | ConstructorInitializerIndentWidth: 4 58 | ContinuationIndentWidth: 4 59 | Cpp11BracedListStyle: true 60 | DeriveLineEnding: true 61 | DerivePointerAlignment: true 62 | DisableFormat: false 63 | ExperimentalAutoDetectBinPacking: false 64 | FixNamespaceComments: true 65 | ForEachMacros: 66 | - foreach 67 | - Q_FOREACH 68 | - BOOST_FOREACH 69 | IncludeBlocks: Regroup 70 | IncludeCategories: 71 | - Regex: '^' 72 | Priority: 2 73 | SortPriority: 0 74 | - Regex: '^<.*\.h>' 75 | Priority: 1 76 | SortPriority: 0 77 | - Regex: '^<.*' 78 | Priority: 2 79 | SortPriority: 0 80 | - Regex: '.*' 81 | Priority: 3 82 | SortPriority: 0 83 | IncludeIsMainRegex: '([-_](test|unittest))?$' 84 | IncludeIsMainSourceRegex: '' 85 | IndentCaseLabels: true 86 | IndentGotoLabels: true 87 | IndentPPDirectives: None 88 | IndentWidth: 4 89 | IndentWrappedFunctionNames: false 90 | JavaScriptQuotes: Leave 91 | JavaScriptWrapImports: true 92 | KeepEmptyLinesAtTheStartOfBlocks: false 93 | MacroBlockBegin: '' 94 | MacroBlockEnd: '' 95 | MaxEmptyLinesToKeep: 1 96 | NamespaceIndentation: None 97 | ObjCBinPackProtocolList: Never 98 | ObjCBlockIndentWidth: 2 99 | ObjCSpaceAfterProperty: false 100 | ObjCSpaceBeforeProtocolList: true 101 | PenaltyBreakAssignment: 2 102 | PenaltyBreakBeforeFirstCallParameter: 1 103 | PenaltyBreakComment: 300 104 | PenaltyBreakFirstLessLess: 120 105 | PenaltyBreakString: 1000 106 | PenaltyBreakTemplateDeclaration: 10 107 | PenaltyExcessCharacter: 1000000 108 | PenaltyReturnTypeOnItsOwnLine: 200 109 | PointerAlignment: Left 110 | RawStringFormats: 111 | - Language: Cpp 112 | Delimiters: 113 | - cc 114 | - CC 115 | - cpp 116 | - Cpp 117 | - CPP 118 | - 'c++' 119 | - 'C++' 120 | CanonicalDelimiter: '' 121 | BasedOnStyle: google 122 | - Language: TextProto 123 | Delimiters: 124 | - pb 125 | - PB 126 | - proto 127 | - PROTO 128 | EnclosingFunctions: 129 | - EqualsProto 130 | - EquivToProto 131 | - PARSE_PARTIAL_TEXT_PROTO 132 | - PARSE_TEST_PROTO 133 | - PARSE_TEXT_PROTO 134 | - ParseTextOrDie 135 | - ParseTextProtoOrDie 136 | CanonicalDelimiter: '' 137 | BasedOnStyle: google 138 | ReflowComments: true 139 | SortIncludes: false 140 | SortUsingDeclarations: true 141 | SpaceAfterCStyleCast: false 142 | SpaceAfterLogicalNot: false 143 | SpaceAfterTemplateKeyword: true 144 | SpaceBeforeAssignmentOperators: true 145 | SpaceBeforeCpp11BracedList: false 146 | SpaceBeforeCtorInitializerColon: true 147 | SpaceBeforeInheritanceColon: true 148 | SpaceBeforeParens: ControlStatements 149 | SpaceBeforeRangeBasedForLoopColon: true 150 | SpaceInEmptyBlock: false 151 | SpaceInEmptyParentheses: false 152 | SpacesBeforeTrailingComments: 2 153 | SpacesInAngles: false 154 | SpacesInConditionalStatement: false 155 | SpacesInContainerLiterals: true 156 | SpacesInCStyleCastParentheses: false 157 | SpacesInParentheses: false 158 | SpacesInSquareBrackets: false 159 | SpaceBeforeSquareBrackets: false 160 | Standard: Auto 161 | StatementMacros: 162 | - Q_UNUSED 163 | - QT_REQUIRE_VERSION 164 | TabWidth: 4 165 | UseCRLF: false 166 | UseTab: Never 167 | ... 168 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.yml: -------------------------------------------------------------------------------- 1 | # Source: 2 | # https://github.com/Tinyu-Zhao/M5-Depends/blob/main/.github/ISSUE_TEMPLATE/bug-report.yml 3 | # See: 4 | # https://docs.github.com/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-issue-forms 5 | 6 | name: Bug report 7 | description: Report a problem with the code in this repository. 8 | labels: 9 | - "type: bug" 10 | body: 11 | - type: markdown 12 | attributes: 13 | value: "Thank you for opening an issue on an M5Stack Arduino library repository.\n\ 14 | To improve the speed of resolution please review the following guidelines and common troubleshooting steps below before creating the issue:\n\ 15 | If you have any UIFLOW questions you can ask in the [special board](https://community.m5stack.com/category/5/uiflow), there will be many enthusiastic friends to help you.\n\ 16 | Do not use GitHub issues for troubleshooting projects and issues. Instead use the forums at https://community.m5stack.com to ask questions and troubleshoot why something isn't working as expected. In many cases the problem is a common issue that you will more quickly receive help from the forum community. GitHub issues are meant for known defects in the code. If you don't know if there is a defect in the code then start with troubleshooting on the forum first." 17 | - type: textarea 18 | id: description 19 | attributes: 20 | label: Describe the bug 21 | description: A clear and concise description of what the bug is. 22 | validations: 23 | required: true 24 | - type: textarea 25 | id: reproduce 26 | attributes: 27 | label: To reproduce 28 | description: Provide the specific set of steps we can follow to reproduce the problem. 29 | placeholder: | 30 | 1. In this environment... 31 | 2. With this config... 32 | 3. Run '...' 33 | 4. See error... 34 | validations: 35 | required: true 36 | - type: textarea 37 | id: expected 38 | attributes: 39 | label: Expected behavior 40 | description: What would you expect to happen after following those instructions? 41 | validations: 42 | required: true 43 | - type: textarea 44 | id: screenshots 45 | attributes: 46 | label: Screenshots 47 | description: If applicable, add screenshots to help explain your problem. 48 | validations: 49 | required: false 50 | - type: textarea 51 | id: information 52 | attributes: 53 | label: Environment 54 | description: | 55 | If applicable, add screenshots to help explain your problem. 56 | examples: 57 | - **OS**: Ubuntu 20.04 58 | - **IDE & IDE Version**: Arduino 1.8.19 Or Platform IO v2.5.0 59 | - **Repository Version**: 0.4.0 60 | value: | 61 | - OS: 62 | - IDE &IDE Version: 63 | - Repository Version: 64 | validations: 65 | required: false 66 | - type: textarea 67 | id: additional 68 | attributes: 69 | label: Additional context 70 | description: Add any additional information here. 71 | validations: 72 | required: false 73 | - type: checkboxes 74 | id: checklist 75 | attributes: 76 | label: Issue checklist 77 | description: Please double-check that you have done each of the following things before submitting the issue. 78 | options: 79 | - label: I searched for previous reports in [the issue tracker](https://github.com/m5stack/M5Stack/issues?q=) 80 | required: true 81 | - label: My report contains all necessary details 82 | required: true 83 | -------------------------------------------------------------------------------- /.github/actions/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Test compile for Arduino' 2 | description: 'Compile sketches or Arduino library examples for one board type using arduino-cli and check for errors' 3 | author: 'Armin Joachimsmeyer' 4 | inputs: 5 | cli-version: 6 | description: 'Version of arduino-cli to use when building. Current (8/2022) one is 0.26.0.' 7 | default: 'latest' 8 | required: false 9 | 10 | sketch-names: 11 | description: 'Comma sepatated list of patterns or filenames (without path) of the sketch(es) to test compile. Useful if the sketch is a *.cpp or *.c file or only one sketch in the repository should be compiled.' 12 | default: '*.ino' 13 | required: false 14 | 15 | sketch-names-find-start: 16 | description: 'The start directory to look for the sketch-names to test compile. Can be a path like "digistump-avr/libraries/*/examples/C*/" .' 17 | default: '.' 18 | required: false 19 | 20 | arduino-board-fqbn: 21 | #In the Arduino IDE, the fqbn is printed in the first line of the verbose output for compilation as parameter -fqbn=... for the "arduino-builder -dump-prefs" command 22 | description: 'Fully Qualified Board Name of the Arduino board. You may add a suffix behind the fqbn with "|" to specify one board for e.g. different compile options like arduino:avr:uno|trace.' 23 | default: 'arduino:avr:uno' 24 | required: false 25 | 26 | arduino-platform: 27 | description: 'Comma separated list of platform specifiers, if you require a fixed version like "arduino:avr@1.8.2" or do not want the specifier derived from the 2 first elements of the arduino-board-fqbn or need more than one core. The suffix "@latest" is always removed.' 28 | default: '' 29 | required: false 30 | 31 | platform-default-url: 32 | description: 'The platform URL for the required board description if arduino-board-fqbn does not start with "arduino:" and not explicitly specified by platform-url.' 33 | default: '' 34 | required: false 35 | 36 | platform-url: 37 | description: 'The platform URL for the required board description if arduino-board-fqbn does not start with "arduino:".' 38 | default: '' 39 | required: false 40 | 41 | required-libraries: 42 | description: 'Comma separated list of arduino library names required for compiling the sketches / examples for this board.' 43 | default: '' 44 | required: false 45 | 46 | sketches-exclude: 47 | description: 'Comma or space separated list of complete names of all sketches / examples to be excluded in the build for this board.' 48 | default: '' 49 | required: false 50 | 51 | build-properties: 52 | description: | 53 | Build parameter like -DDEBUG for each example specified or for all examples, if example name is "All". In json format. 54 | For example: build-properties: '{ "WhistleSwitch": "-DDEBUG -DFREQUENCY_RANGE_LOW", "SimpleFrequencyDetector": "-DINFO" }' 55 | default: '' 56 | required: false 57 | 58 | extra-arduino-cli-args: 59 | description: | 60 | This string is passed verbatim without double quotes to the arduino-cli compile commandline as last argument before the filename. 61 | See https://arduino.github.io/arduino-cli/commands/arduino-cli_compile/ for compile parameters. 62 | default: '' 63 | required: false 64 | 65 | extra-arduino-lib-install-args: 66 | description: | 67 | This string is passed verbatim without double quotes to the arduino-cli lib install commandline as last argument before the library names. 68 | It can be used e.g. to suppress dependency resolving for libraries by using --no-deps as argument string. 69 | default: '' 70 | required: false 71 | 72 | set-build-path: 73 | description: 'Flag to set the build directory (arduino-cli paramer --build-path) to /build subdirectory of compiled sketches.' 74 | default: 'false' 75 | required: false 76 | 77 | debug-compile: 78 | description: 'If set to "true" the action logs verbose compile output even during successful builds' 79 | default: '' 80 | required: false 81 | 82 | debug-install: 83 | description: 'If set to "true" the action logs verbose arduino-cli output during installation' 84 | default: '' 85 | required: false 86 | 87 | runs: 88 | using: 'composite' 89 | steps: 90 | - name: Compile all sketches / examples using the bash script arduino-test-compile.sh 91 | env: 92 | # Passing parameters to the script by setting the appropriate ENV_* variables. 93 | # Direct passing as arguments is not possible because of blanks in the arguments. 94 | ENV_CLI_VERSION: ${{ inputs.cli-version }} 95 | ENV_SKETCH_NAMES: ${{ inputs.sketch-names }} 96 | ENV_SKETCH_NAMES_FIND_START: ${{ inputs.sketch-names-find-start }} 97 | ENV_ARDUINO_BOARD_FQBN: ${{ inputs.arduino-board-fqbn }} 98 | ENV_ARDUINO_PLATFORM: ${{ inputs.arduino-platform }} 99 | ENV_PLATFORM_DEFAULT_URL: ${{ inputs.platform-default-url }} 100 | ENV_PLATFORM_URL: ${{ inputs.platform-url }} 101 | ENV_REQUIRED_LIBRARIES: ${{ inputs.required-libraries }} 102 | ENV_SKETCHES_EXCLUDE: ${{ inputs.sketches-exclude }} 103 | ENV_BUILD_PROPERTIES: ${{ inputs.build-properties }} 104 | ENV_EXTRA_ARDUINO_CLI_ARGS: ${{ inputs.extra-arduino-cli-args }} 105 | ENV_EXTRA_ARDUINO_LIB_INSTALL_ARGS: ${{ inputs.extra-arduino-lib-install-args }} 106 | ENV_SET_BUILD_PATH: ${{ inputs.set-build-path }} 107 | ENV_DEBUG_COMPILE: ${{ inputs.debug-compile }} 108 | ENV_DEBUG_INSTALL: ${{ inputs.debug-install }} 109 | 110 | run: ${{ github.action_path }}/arduino-test-compile.sh 111 | shell: bash 112 | 113 | branding: 114 | icon: 'eye' 115 | color: 'red' -------------------------------------------------------------------------------- /.github/actions/arduino-test-compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # arduino-test-compile.sh 4 | # Bash script to do a test-compile of one or more Arduino programs in a repository each with different compile parameters. 5 | # 6 | # Copyright (C) 2020-2022 Armin Joachimsmeyer 7 | # https://github.com/ArminJo/Github-Actions 8 | # License: MIT 9 | # 10 | 11 | # Input parameter, which is normally not used for Githup actions 12 | CLI_VERSION="$1" 13 | SKETCH_NAMES="$2" 14 | SKETCH_NAMES_FIND_START="$3" 15 | ARDUINO_BOARD_FQBN="$4" 16 | ARDUINO_PLATFORM="$5" 17 | PLATFORM_DEFAULT_URL="$6" 18 | PLATFORM_URL="$7" 19 | REQUIRED_LIBRARIES="$8" 20 | SKETCHES_EXCLUDE="$9" 21 | EXAMPLES_EXCLUDE="${10}" 22 | BUILD_PROPERTIES="${11}" 23 | EXAMPLES_BUILD_PROPERTIES="${12}" 24 | EXTRA_ARDUINO_CLI_ARGS="${13}" 25 | EXTRA_ARDUINO_LIB_INSTALL_ARGS="${14}" 26 | SET_BUILD_PATH="${15}" 27 | DEBUG_COMPILE="${16}" 28 | DEBUG_INSTALL="${17}" 29 | 30 | readonly RED='\033[0;31m' 31 | readonly GREEN='\033[0;32m' 32 | readonly YELLOW='\033[1;33m' 33 | readonly BLUE='\033[0;34m' 34 | 35 | # 36 | # Get env parameter from action run with higher priority, which enables the script to run directly in a step 37 | # 38 | if [[ -n $ENV_CLI_VERSION ]]; then CLI_VERSION=$ENV_CLI_VERSION; fi 39 | if [[ -n $ENV_SKETCH_NAMES ]]; then SKETCH_NAMES=$ENV_SKETCH_NAMES; fi 40 | if [[ -n $ENV_SKETCH_NAMES_FIND_START ]]; then SKETCH_NAMES_FIND_START=$ENV_SKETCH_NAMES_FIND_START; fi 41 | if [[ -n $ENV_ARDUINO_BOARD_FQBN ]]; then ARDUINO_BOARD_FQBN=$ENV_ARDUINO_BOARD_FQBN; fi 42 | if [[ -n $ENV_ARDUINO_PLATFORM ]]; then ARDUINO_PLATFORM=$ENV_ARDUINO_PLATFORM; fi 43 | if [[ -n $ENV_PLATFORM_DEFAULT_URL ]]; then PLATFORM_DEFAULT_URL=$ENV_PLATFORM_DEFAULT_URL; fi 44 | if [[ -n $ENV_PLATFORM_URL ]]; then PLATFORM_URL=$ENV_PLATFORM_URL; fi 45 | if [[ -n $ENV_REQUIRED_LIBRARIES ]]; then REQUIRED_LIBRARIES=$ENV_REQUIRED_LIBRARIES; fi 46 | if [[ -n $ENV_SKETCHES_EXCLUDE ]]; then SKETCHES_EXCLUDE=$ENV_SKETCHES_EXCLUDE; fi 47 | if [[ -n $ENV_EXAMPLES_EXCLUDE ]]; then EXAMPLES_EXCLUDE=$ENV_EXAMPLES_EXCLUDE; fi #deprecated 48 | if [[ -n $ENV_BUILD_PROPERTIES ]]; then BUILD_PROPERTIES=$ENV_BUILD_PROPERTIES; fi 49 | if [[ -n $ENV_EXAMPLES_BUILD_PROPERTIES ]]; then EXAMPLES_BUILD_PROPERTIES=$ENV_EXAMPLES_BUILD_PROPERTIES; fi #deprecated 50 | if [[ -n $ENV_EXTRA_ARDUINO_CLI_ARGS ]]; then EXTRA_ARDUINO_CLI_ARGS=$ENV_EXTRA_ARDUINO_CLI_ARGS; fi 51 | if [[ -n $ENV_EXTRA_ARDUINO_LIB_INSTALL_ARGS ]]; then EXTRA_ARDUINO_LIB_INSTALL_ARGS=$ENV_EXTRA_ARDUINO_LIB_INSTALL_ARGS; fi 52 | if [[ -n $ENV_SET_BUILD_PATH ]]; then SET_BUILD_PATH=$ENV_SET_BUILD_PATH; fi 53 | 54 | if [[ -n $ENV_DEBUG_COMPILE ]]; then DEBUG_COMPILE=$ENV_DEBUG_COMPILE; fi 55 | if [[ -n $ENV_DEBUG_INSTALL ]]; then DEBUG_INSTALL=$ENV_DEBUG_INSTALL; fi 56 | 57 | # 58 | # Handle deprecated names 59 | # 60 | if [[ -z $SKETCHES_EXCLUDE && -n $EXAMPLES_EXCLUDE ]]; then 61 | echo "Please change parameter name from \"examples-exclude\" to \"sketches-exclude\"" 62 | SKETCHES_EXCLUDE=${EXAMPLES_EXCLUDE} 63 | fi 64 | if [[ -z $BUILD_PROPERTIES && -n $EXAMPLES_BUILD_PROPERTIES ]]; then 65 | echo "Please change parameter name from \"examples-build-properties\" to \"build-properties\"" 66 | BUILD_PROPERTIES=${EXAMPLES_BUILD_PROPERTIES} 67 | fi 68 | 69 | # 70 | # Enforce defaults. Required at least for script version. !!! MUST be equal the defaults in action.yml !!! 71 | # 72 | echo -e "\r\n${YELLOW}Set defaults" 73 | if [[ -z $ARDUINO_BOARD_FQBN ]]; then 74 | echo "Set ARDUINO_BOARD_FQBN to default value: \"arduino:avr:uno\"" 75 | ARDUINO_BOARD_FQBN='arduino:avr:uno' 76 | fi 77 | if [[ -z $PLATFORM_URL && -n $PLATFORM_DEFAULT_URL ]]; then 78 | echo -e "Set PLATFORM_URL to default value: \"${PLATFORM_DEFAULT_URL}\"" 79 | PLATFORM_URL=$PLATFORM_DEFAULT_URL 80 | fi 81 | if [[ -z $CLI_VERSION ]]; then 82 | echo "Set CLI_VERSION to default value: \"latest\"" 83 | CLI_VERSION='latest' 84 | fi 85 | if [[ -z $SKETCH_NAMES ]]; then 86 | echo -e "Set SKETCH_NAMES to default value: \"*.ino\"" 87 | SKETCH_NAMES='*.ino' 88 | fi 89 | if [[ -z $SKETCH_NAMES_FIND_START ]]; then 90 | echo -e "Set SKETCH_NAMES_FIND_START to default value: \".\" (root of repository)" 91 | SKETCH_NAMES_FIND_START='.' 92 | fi 93 | if [[ -z $SET_BUILD_PATH ]]; then 94 | echo -e "Set SET_BUILD_PATH to default value: \"false\"" 95 | SET_BUILD_PATH='false' 96 | fi 97 | 98 | # 99 | # Echo input parameter 100 | # 101 | echo -e "\r\n${YELLOW}Echo input parameter" 102 | echo CLI_VERSION=$CLI_VERSION 103 | echo SKETCH_NAMES=$SKETCH_NAMES 104 | echo SKETCH_NAMES_FIND_START=$SKETCH_NAMES_FIND_START 105 | echo ARDUINO_BOARD_FQBN=$ARDUINO_BOARD_FQBN 106 | echo ARDUINO_PLATFORM=$ARDUINO_PLATFORM 107 | echo PLATFORM_DEFAULT_URL=$PLATFORM_DEFAULT_URL 108 | echo PLATFORM_URL=$PLATFORM_URL 109 | echo REQUIRED_LIBRARIES=$REQUIRED_LIBRARIES 110 | echo SKETCHES_EXCLUDE=$SKETCHES_EXCLUDE 111 | echo BUILD_PROPERTIES=$BUILD_PROPERTIES 112 | echo EXTRA_ARDUINO_CLI_ARGS=$EXTRA_ARDUINO_CLI_ARGS 113 | echo EXTRA_ARDUINO_LIB_INSTALL_ARGS=$EXTRA_ARDUINO_LIB_INSTALL_ARGS 114 | echo SET_BUILD_PATH=$SET_BUILD_PATH 115 | 116 | echo DEBUG_COMPILE=$DEBUG_COMPILE 117 | echo DEBUG_INSTALL=$DEBUG_INSTALL 118 | 119 | VERBOSE_PARAMETER= 120 | if [[ $DEBUG_INSTALL == true ]]; then 121 | VERBOSE_PARAMETER=--verbose 122 | echo 123 | echo HOME=$HOME # /home/runner 124 | echo PWD=$PWD # *** 125 | echo GITHUB_WORKSPACE=$GITHUB_WORKSPACE # /home/runner/work// 126 | #set 127 | #ls -lR $GITHUB_WORKSPACE 128 | fi 129 | 130 | # Show calling parameters 131 | declare -p BASH_ARGV 132 | 133 | # 134 | # Download and install arduino IDE, if not already cached 135 | # 136 | echo -n -e "\r\n${YELLOW}arduino-cli " 137 | if [[ -f $HOME/arduino_ide/arduino-cli ]]; then 138 | echo -e "cached: ${GREEN}\xe2\x9c\x93" # never seen :-( 139 | else 140 | echo -n "downloading: " 141 | wget --quiet https://downloads.arduino.cc/arduino-cli/arduino-cli_${CLI_VERSION}_Linux_64bit.tar.gz 142 | if [[ $? -ne 0 ]]; then 143 | echo -e "${RED}\xe2\x9c\x96" 144 | echo "::error:: Unable to download arduino-cli_${CLI_VERSION}_Linux_64bit.tar.gz" 145 | exit 3 146 | else 147 | echo -e "${GREEN}\xe2\x9c\x93" 148 | fi 149 | echo -n "Upacking arduino-cli to ${HOME}/arduino_ide: " 150 | if [[ ! -d $HOME/arduino_ide/ ]]; then 151 | mkdir $HOME/arduino_ide 152 | fi 153 | tar xf arduino-cli_${CLI_VERSION}_Linux_64bit.tar.gz -C $HOME/arduino_ide/ 154 | if [[ $? -ne 0 ]]; then 155 | echo -e "${RED}\xe2\x9c\x96" 156 | else 157 | echo -e "${GREEN}\xe2\x9c\x93" 158 | fi 159 | # ls -l $HOME/arduino_ide/* # LICENSE.txt + arduino-cli 160 | # ls -l $HOME # only arduino_ide 161 | fi 162 | 163 | # add the arduino CLI to our PATH 164 | export PATH="$HOME/arduino_ide:$PATH" 165 | 166 | #print version 167 | arduino-cli version 168 | 169 | # 170 | # Add *Custom* directories to Arduino library directory 171 | # 172 | # if ls $GITHUB_WORKSPACE/*Custom* >/dev/null 2>&1; then 173 | # echo -e "\r\n${YELLOW}Add *Custom* as Arduino library" 174 | # mkdir --parents $HOME/Arduino/libraries 175 | # rm --force --recursive $GITHUB_WORKSPACE/*Custom*/.git # do not want to move the whole .git directory 176 | # # mv to avoid the library examples to be test compiled 177 | # echo mv --no-clobber $VERBOSE_PARAMETER $GITHUB_WORKSPACE/\*Custom\* $HOME/Arduino/libraries/ 178 | # mv --no-clobber $VERBOSE_PARAMETER $GITHUB_WORKSPACE/*Custom* $HOME/Arduino/libraries/ 179 | # fi 180 | 181 | echo "Download Depends Arduino library" 182 | mkdir --parents $HOME/Arduino/libraries 183 | 184 | if [[ -f $GITHUB_WORKSPACE/library.properties ]]; then 185 | OLD_IFS="$IFS" 186 | IFS=$'\n' 187 | for line in $(cat $GITHUB_WORKSPACE/library.properties); do 188 | result=$(echo $line | grep "depends=") 189 | if [[ "$result" != "" ]]; then 190 | depends_str=${line##*depends=} 191 | IFS="," 192 | for lib in ${depends_str[@]}; do 193 | echo "download $lib" 194 | arduino-cli lib install $lib 195 | done 196 | fi 197 | done 198 | IFS="$OLD_IFS" 199 | fi 200 | 201 | echo "Check Arduino library" 202 | repo_name="${GITHUB_WORKSPACE##*/}" 203 | if [[ -d $HOME/Arduino/libraries/$repo_name ]]; then 204 | rm -r $HOME/Arduino/libraries/$repo_name 205 | echo "Same Arduino library: ${repo_name}, replace this repository" 206 | fi 207 | 208 | cp -r $GITHUB_WORKSPACE $HOME/Arduino/libraries/ 209 | ls $HOME/Arduino/libraries/$repo_name 210 | 211 | # Link this repository as Arduino library 212 | # 213 | # Check if repo is an Arduino library 214 | # if [[ -f $GITHUB_WORKSPACE/library.properties ]]; then 215 | # echo -e "\r\n${YELLOW}Link this repository as Arduino library" 216 | # mkdir --parents $HOME/Arduino/libraries 217 | # repo_name="${GITHUB_WORKSPACE##*/}" 218 | # if [[ -d $HOME/Arduino/libraries/$repo_name ]]; then 219 | # rm -r $HOME/Arduino/libraries/$repo_name 220 | # echo -e "\r\nSame Arduino library: ${repo_name}, replace this repository" 221 | # fi 222 | # ln --symbolic $GITHUB_WORKSPACE $HOME/Arduino/libraries/. 223 | # if [[ $DEBUG_INSTALL == true ]]; then 224 | # echo ln --symbolic $GITHUB_WORKSPACE $HOME/Arduino/libraries/. 225 | # rm --force --recursive $HOME/Arduino/libraries/*/.git # do not want to list the whole .git directory 226 | # echo ls -l --dereference --recursive --all $HOME/Arduino/libraries/ 227 | # ls -l --dereference --recursive --all $HOME/Arduino/libraries/ 228 | # fi 229 | # fi 230 | 231 | # 232 | # Update index and install the required board platform 233 | # 234 | echo -e "\r\n${YELLOW}Update index and install the required board platform" 235 | if [[ -z $ARDUINO_PLATFORM ]]; then 236 | # ARDUINO_PLATFORM is empty -> derive platform from the 2 first elements of the arduino-board-fqbn 237 | remainder=${ARDUINO_BOARD_FQBN#*:} 238 | provider=${ARDUINO_BOARD_FQBN%%:*} 239 | PLATFORM=${provider}:${remainder%%:*} 240 | else 241 | # Remove @latest from specified platform 242 | PLATFORM=${ARDUINO_PLATFORM%@latest} 243 | fi 244 | echo PLATFORM=${PLATFORM} # e.g. digistump:avr 245 | if [[ ${PLATFORM} != *arduino* && -z $PLATFORM_URL ]]; then 246 | # check if the requested platform is manually installed 247 | if [[ ! -d $HOME/.arduino15/packages/${provider} ]]; then 248 | echo -e "::error::Non Arduino platform $PLATFORM requested, but \"platform-url\" parameter is missing." 249 | exit 1 250 | fi 251 | fi 252 | 253 | if [[ -n $PLATFORM_URL ]]; then 254 | PLATFORM_URL=${PLATFORM_URL// /,} # replace space by comma to enable multiple urls which are space separated 255 | PLATFORM_URL_COMMAND="--additional-urls" 256 | fi 257 | 258 | PLATFORM=${PLATFORM//,/ } # replace all comma by space to enable multiple platforms which are comma separated 259 | declare -a PLATFORM_ARRAY=($PLATFORM) 260 | if [[ $DEBUG_INSTALL == true ]]; then 261 | declare -p PLATFORM_ARRAY # print properties of PLATFORM_ARRAY 262 | fi 263 | for single_platform in "${PLATFORM_ARRAY[@]}"; do # Loop over all platforms specified 264 | if [[ $DEBUG_INSTALL == true ]]; then 265 | echo -e "arduino-cli core update-index $PLATFORM_URL_COMMAND $PLATFORM_URL --verbose" 266 | arduino-cli core update-index $PLATFORM_URL_COMMAND $PLATFORM_URL --verbose # must specify --additional-urls here 267 | if [[ $? -ne 0 ]]; then 268 | echo "::error::Updating index of $PLATFORM_URL failed" 269 | exit 1 270 | fi 271 | echo -e "arduino-cli core install $single_platform $PLATFORM_URL_COMMAND $PLATFORM_URL -v" 272 | arduino-cli core install $single_platform $PLATFORM_URL_COMMAND $PLATFORM_URL --verbose 273 | else 274 | echo -e "arduino-cli core update-index $PLATFORM_URL_COMMAND $PLATFORM_URL > /dev/null" 275 | arduino-cli core update-index $PLATFORM_URL_COMMAND $PLATFORM_URL >/dev/null # must specify --additional-urls here 276 | if [[ $? -ne 0 ]]; then 277 | echo "::error::Updating index of $PLATFORM_URL failed" 278 | exit 1 279 | fi 280 | echo -e "arduino-cli core install $single_platform $PLATFORM_URL_COMMAND $PLATFORM_URL > /dev/null" 281 | arduino-cli core install $single_platform $PLATFORM_URL_COMMAND $PLATFORM_URL >/dev/null 282 | fi 283 | if [[ $? -ne 0 ]]; then 284 | echo "::error::Install core for $single_platform failed" 285 | exit 1 286 | fi 287 | done 288 | 289 | # 290 | # Special esp8266 and esp32 platform handling 291 | # 292 | echo -e "\r\n${YELLOW}Special esp8266 and esp32 platform handling" 293 | if [[ ${PLATFORM} == esp8266:esp8266 && ! -f /usr/bin/python3 ]]; then 294 | # python3 is a link in the esp8266 package: /github/home/.arduino15/packages/esp8266/tools/python3/3.7.2-post1/python3 -> /usr/bin/python3 295 | echo -e "\r\n${YELLOW}install python3 for ESP8266" 296 | apt-get install -qq python3 >/dev/null 297 | fi 298 | 299 | if [[ $PLATFORM == esp32:esp32 ]]; then 300 | if [[ ! -f /usr/bin/pip && ! -f /usr/bin/python ]]; then 301 | echo -e "\r\n${YELLOW}install python and pip for ESP32" 302 | # Here we would get the warning: The directory '/github/home/.cache/pip/http' or its parent directory is not owned by the current user and the cache has been disabled. 303 | # Please check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag. 304 | apt-get install -qq python-pip >/dev/null 2>&1 # this installs also python 305 | fi 306 | pip install pyserial 307 | fi 308 | 309 | # 310 | # List installed boards with their FQBN 311 | # 312 | echo -e "\r\n${YELLOW}List installed boards with their FQBN" 313 | if [[ $DEBUG_INSTALL == true ]]; then 314 | echo arduino-cli board listall --verbose 315 | arduino-cli board listall --verbose 316 | else 317 | echo arduino-cli board listall 318 | arduino-cli board listall 319 | fi 320 | 321 | # 322 | # Install required libraries 323 | # 324 | echo -e "\n${YELLOW}Install required libraries" 325 | if [[ -z $REQUIRED_LIBRARIES ]]; then 326 | echo No additional libraries to install 327 | else 328 | echo Install libraries $REQUIRED_LIBRARIES 329 | BACKUP_IFS="$IFS" 330 | # Split comma separated library list 331 | IFS=$',' 332 | declare -a REQUIRED_LIBRARIES_ARRAY=($REQUIRED_LIBRARIES) 333 | IFS="$BACKUP_IFS" 334 | if [[ $DEBUG_INSTALL == true ]]; then 335 | arduino-cli lib install "${REQUIRED_LIBRARIES_ARRAY[@]}" $EXTRA_ARDUINO_LIB_INSTALL_ARGS 336 | else 337 | arduino-cli lib install "${REQUIRED_LIBRARIES_ARRAY[@]}" $EXTRA_ARDUINO_LIB_INSTALL_ARGS >/dev/null 2>&1 338 | fi 339 | if [[ $? -ne 0 ]]; then 340 | echo "::error::Installation of $REQUIRED_LIBRARIES failed" 341 | exit 1 342 | fi 343 | fi 344 | 345 | # Save generated files to the build subfolder of the sketch 346 | export ARDUINO_SKETCH_ALWAYS_EXPORT_BINARIES=true 347 | 348 | # 349 | # Get the build property map 350 | # 351 | echo -e "\n${YELLOW}Compiling sketches / examples for board $ARDUINO_BOARD_FQBN\n" 352 | 353 | # If matrix.build-properties are specified, create an associative shell array 354 | # Input example: { "WhistleSwitch": "-DINFO -DFREQUENCY_RANGE_LOW", "SimpleFrequencyDetector": "-DINFO" } 355 | # Converted to: [All]="-DDEBUG -DINFO" [WhistleSwitch]="-DDEBUG -DINFO" 356 | if [[ -n $BUILD_PROPERTIES && $BUILD_PROPERTIES != "null" ]]; then # contains "null", if passed as environment variable 357 | echo BUILD_PROPERTIES=$BUILD_PROPERTIES 358 | BUILD_PROPERTIES=${BUILD_PROPERTIES#\{} # remove the "{". The "}" is required as end token 359 | # (\w*): * first token before the colon and spaces, ([^,}]*) token after colon and spaces up to "," or "}", [,}] trailing characters 360 | if [[ $DEBUG_COMPILE == true ]]; then 361 | echo BUILD_PROPERTIES is converted to:$(echo $BUILD_PROPERTIES | sed -E 's/"(\w*)": *([^,}]*)[,}]/\[\1\]=\2/g') 362 | fi 363 | declare -A PROP_MAP="( $(echo $BUILD_PROPERTIES | sed -E 's/"(\w*)": *([^,}]*)[,}]/\[\1\]=\2/g') )" 364 | declare -p PROP_MAP # print properties of PROP_MAP 365 | else 366 | declare -A PROP_MAP=([dummy]=dummy) # declare an accociative array 367 | fi 368 | 369 | # 370 | # Finally, we compile all examples 371 | # 372 | # Split comma separated sketch name list 373 | BACKUP_IFS="$IFS" 374 | IFS=$',' 375 | SKETCH_NAMES=${SKETCH_NAMES// /} # replace all spaces 376 | GLOBIGNORE=*:?:[ # Disable filename expansion (globbing) of *.ino to abc.ino if abc.ino is a file in the directory 377 | declare -a SKETCH_NAMES_ARRAY=($SKETCH_NAMES) # declare an indexed array 378 | GLOBIGNORE= # Enable it for cp command below 379 | if [[ $DEBUG_COMPILE == true ]]; then 380 | declare -p SKETCH_NAMES_ARRAY # print properties of SKETCH_NAMES_ARRAY 381 | fi 382 | IFS="$BACKUP_IFS" 383 | COMPILED_SKETCHES= 384 | for sketch_name in "${SKETCH_NAMES_ARRAY[@]}"; do # Loop over all sketch names 385 | if [[ $SET_BUILD_PATH == true ]]; then 386 | # must use $GITHUB_WORKSPACE/$SKETCH_NAMES_FIND_START, since arduino-cli does not support relative path for --build-path 387 | declare -a SKETCHES=($(find ${GITHUB_WORKSPACE}/${SKETCH_NAMES_FIND_START} -type f -name "$sketch_name")) # only search for files 388 | else 389 | declare -a SKETCHES=($(find ${SKETCH_NAMES_FIND_START} -type f -name "$sketch_name")) # only search for files 390 | fi 391 | if [[ $DEBUG_COMPILE == true ]]; then 392 | declare -p SKETCHES 393 | fi 394 | 395 | # Check if find command found a file 396 | if [[ -z ${SKETCHES[0]} ]]; then 397 | GLOBIGNORE=*:?:[ # Disable filename expansion (globbing) of *.ino to abc.ino if abc.ino is a file in the directory 398 | echo -e "::error::\nNo files found to compile with sketch_name=${sketch_name}." 399 | echo "sketch-names=${SKETCH_NAMES} and sketch-names-find-start=${SKETCH_NAMES_FIND_START}" 400 | GLOBIGNORE= 401 | # No files found -> list start directory and execute find command to see what we did 402 | echo -e "find command is: find ${GITHUB_WORKSPACE}/${SKETCH_NAMES_FIND_START} -type f -name \"$sketch_name\"" 403 | echo "\"sketch-names-find-start\" directory content listing with: ls -l ${GITHUB_WORKSPACE}/${SKETCH_NAMES_FIND_START}" 404 | ls -l ${GITHUB_WORKSPACE}/${SKETCH_NAMES_FIND_START} 405 | echo 406 | fi 407 | 408 | for sketch in "${SKETCHES[@]}"; do # Loop over all sketch files 409 | SKETCH_PATH=$(dirname $sketch) # complete path to sketch 410 | SKETCH_DIR=${SKETCH_PATH##*/} # directory of sketch, must match sketch basename 411 | SKETCH_FILENAME=$(basename $sketch) # complete name of sketch 412 | SKETCH_EXTENSION=${SKETCH_FILENAME##*.} # extension of sketch 413 | SKETCH_BASENAME=${SKETCH_FILENAME%%.$SKETCH_EXTENSION} # name without extension / basename of sketch, must match directory name 414 | if [[ $DEBUG_COMPILE == true ]]; then 415 | echo -n "Process $sketch with filename $SKETCH_FILENAME and extension $SKETCH_EXTENSION" 416 | fi 417 | echo -e "\n" 418 | if [[ $SKETCHES_EXCLUDE == *"$SKETCH_BASENAME"* ]]; then 419 | echo -e "Skipping $SKETCH_PATH \xe2\x9e\x9e" # Right arrow 420 | else 421 | # If sketch name does not end with .ino, rename it locally 422 | if [[ $SKETCH_EXTENSION != ino ]]; then 423 | echo "Rename ${SKETCH_PATH}/${SKETCH_FILENAME} to ${SKETCH_PATH}/${SKETCH_BASENAME}.ino" 424 | mv ${SKETCH_PATH}/${SKETCH_FILENAME} ${SKETCH_PATH}/${SKETCH_BASENAME}.ino 425 | fi 426 | # If directory name does not match sketch name, create an appropriate directory, copy the files recursively and compile 427 | if [[ $SKETCH_DIR != $SKETCH_BASENAME ]]; then 428 | mkdir $HOME/$SKETCH_BASENAME 429 | echo "Creating directory $HOME/$SKETCH_BASENAME and copy ${SKETCH_PATH}/* to it" 430 | cp --recursive ${SKETCH_PATH}/* $HOME/$SKETCH_BASENAME 431 | SKETCH_PATH=$HOME/$SKETCH_BASENAME 432 | fi 433 | if [[ $SET_BUILD_PATH == true ]]; then 434 | BUILD_PATH_PARAMETER="--build-path $SKETCH_PATH/build/" 435 | fi 436 | # Check if there is an entry in the associative array and create compile parameter to put in compiler.*.extra_flags 437 | # This flags are also defined in platform.txt as empty, to be overwritten by a platform.local.txt definition. 438 | # But I never saw a distribution using this fature, so we can go on here :-) 439 | echo -n "Compiling $SKETCH_BASENAME " 440 | if [[ -n ${PROP_MAP[$SKETCH_BASENAME]} ]]; then 441 | GCC_EXTRA_FLAGS=${PROP_MAP[$SKETCH_BASENAME]} 442 | echo -n "with $GCC_EXTRA_FLAGS " 443 | elif [[ -n ${PROP_MAP[All]} ]]; then 444 | GCC_EXTRA_FLAGS=${PROP_MAP[All]} 445 | echo -n "with $GCC_EXTRA_FLAGS " 446 | else 447 | GCC_EXTRA_FLAGS= 448 | fi 449 | if [[ -z $GCC_EXTRA_FLAGS ]]; then 450 | build_stdout=$(arduino-cli compile -e --verbose --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH 2>&1) 451 | # build_stdout=$(arduino-cli compile -e --verbose --warnings all --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH 2>&1) 452 | # build_stdout=$(arduino-cli compile -e --log-level error --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH 2>&1) 453 | else 454 | build_stdout=$(arduino-cli compile -e --verbose --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER --build-property compiler.cpp.extra_flags="${GCC_EXTRA_FLAGS}" --build-property compiler.c.extra_flags="${GCC_EXTRA_FLAGS}" --build-property compiler.S.extra_flags="${GCC_EXTRA_FLAGS}" $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH 2>&1) 455 | # build_stdout=$(arduino-cli compile -e --verbose --warnings all --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER --build-property compiler.cpp.extra_flags="${GCC_EXTRA_FLAGS}" --build-property compiler.c.extra_flags="${GCC_EXTRA_FLAGS}" --build-property compiler.S.extra_flags="${GCC_EXTRA_FLAGS}" $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH 2>&1) 456 | # build_stdout=$(arduino-cli compile -e --log-level error --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER --build-property compiler.cpp.extra_flags="${GCC_EXTRA_FLAGS}" --build-property compiler.c.extra_flags="${GCC_EXTRA_FLAGS}" --build-property compiler.S.extra_flags="${GCC_EXTRA_FLAGS}" $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH 2>&1) 457 | fi 458 | if [[ $? -ne 0 ]]; then 459 | echo -e ""${RED}"\xe2\x9c\x96" # If ok output a green checkmark else a red X and the command output. 460 | if [[ -z $GCC_EXTRA_FLAGS ]]; then 461 | echo "arduino-cli compile -e --verbose --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH" 462 | # echo "arduino-cli compile -e --verbose --warnings all --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH" 463 | # echo "arduino-cli compile -e --log-level error --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH" 464 | else 465 | echo "arduino-cli compile -e --verbose --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER --build-property compiler.cpp.extra_flags=\"${GCC_EXTRA_FLAGS}\" --build-property compiler.c.extra_flags=\"${GCC_EXTRA_FLAGS}\" --build-property compiler.S.extra_flags=\"${GCC_EXTRA_FLAGS}\" $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH" 466 | # echo "arduino-cli compile -e --verbose --warnings all --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER --build-property compiler.cpp.extra_flags=\"${GCC_EXTRA_FLAGS}\" --build-property compiler.c.extra_flags=\"${GCC_EXTRA_FLAGS}\" --build-property compiler.S.extra_flags=\"${GCC_EXTRA_FLAGS}\" $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH" 467 | # echo "arduino-cli compile -e --log-level error --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER --build-property compiler.cpp.extra_flags=\"${GCC_EXTRA_FLAGS}\" --build-property compiler.c.extra_flags=\"${GCC_EXTRA_FLAGS}\" --build-property compiler.S.extra_flags=\"${GCC_EXTRA_FLAGS}\" $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH" 468 | fi 469 | echo "::error::Compile of $SKETCH_BASENAME ${GCC_EXTRA_FLAGS} failed" 470 | echo -e "$build_stdout \n" 471 | # repeat the info after hundred lines of output :-) 472 | echo "Compile of $SKETCH_BASENAME ${GCC_EXTRA_FLAGS} failed" 473 | exit_code=1 474 | else 475 | echo -e "${GREEN}\xe2\x9c\x93" 476 | if [[ -z $GCC_EXTRA_FLAGS ]]; then 477 | echo "arduino-cli compile -e --verbose --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH" 478 | # echo "arduino-cli compile -e --verbose --warnings all --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH" 479 | # echo "arduino-cli compile -e --log-level error --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH" 480 | else 481 | echo "arduino-cli compile -e --verbose --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER --build-property compiler.cpp.extra_flags=\"${GCC_EXTRA_FLAGS}\" --build-property compiler.c.extra_flags=\"${GCC_EXTRA_FLAGS}\" --build-property compiler.S.extra_flags=\"${GCC_EXTRA_FLAGS}\" $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH" 482 | # echo "arduino-cli compile -e --verbose --warnings all --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER --build-property compiler.cpp.extra_flags=\"${GCC_EXTRA_FLAGS}\" --build-property compiler.c.extra_flags=\"${GCC_EXTRA_FLAGS}\" --build-property compiler.S.extra_flags=\"${GCC_EXTRA_FLAGS}\" $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH" 483 | # echo "arduino-cli compile -e --log-level error --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER --build-property compiler.cpp.extra_flags=\"${GCC_EXTRA_FLAGS}\" --build-property compiler.c.extra_flags=\"${GCC_EXTRA_FLAGS}\" --build-property compiler.S.extra_flags=\"${GCC_EXTRA_FLAGS}\" $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH" 484 | fi 485 | if [[ $DEBUG_COMPILE == true || $SET_BUILD_PATH == true ]]; then 486 | echo "Debug mode enabled => compile output will be printed also for successful compilation and sketch directory is listed after compilation" 487 | echo -e "$build_stdout \n" 488 | echo -e "\nls -l --recursive $SKETCH_PATH/build/" 489 | ls -l --recursive $SKETCH_PATH/build/ 490 | echo -e "\r\n" 491 | fi 492 | fi 493 | COMPILED_SKETCHES="$COMPILED_SKETCHES $SKETCH_NAME" 494 | fi 495 | done 496 | done 497 | if [ -z "$COMPILED_SKETCHES" ]; then 498 | echo "::error::Did not find any sketches to compile, probably misconfigured or used checkout twice without \"path:\" parameter?" 499 | exit_code=2 500 | fi 501 | 502 | echo "compiled all example, export bin file..." 503 | pwd 504 | find . -name "*.bin" 505 | 506 | exit $exit_code 507 | -------------------------------------------------------------------------------- /.github/workflows/Arduino-Lint-Check.yml: -------------------------------------------------------------------------------- 1 | name: Arduino Lint Check 2 | on: 3 | push: 4 | pull_request: 5 | jobs: 6 | lint: 7 | name: Lint Check 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | - uses: arduino/arduino-lint-action@v1 12 | with: 13 | library-manager: update 14 | compliance: strict 15 | project-type: all -------------------------------------------------------------------------------- /.github/workflows/arduino-action-compile.yml: -------------------------------------------------------------------------------- 1 | # arduino-test-compile-ActionTest.yml 2 | # Github workflow script for testing the arduino-test-compile action development. 3 | # 4 | # Copyright (C) 2020 Armin Joachimsmeyer 5 | # https://github.com/ArminJo/Github-Actions 6 | # License: MIT 7 | # 8 | 9 | # This is the name of the workflow, visible on GitHub UI. 10 | name: Arduino Compile 11 | on: 12 | push: # see: https://help.github.com/en/actions/reference/events-that-trigger-workflows#pull-request-event-pull_request 13 | paths: 14 | - '**.ino' 15 | - '**.cpp' 16 | - '**.h' 17 | - 'arduino-test-compile.sh' 18 | - '*.yml' 19 | workflow_dispatch: 20 | jobs: 21 | build: 22 | name: ${{ matrix.arduino-boards-fqbn }} - test compiling examples 23 | 24 | runs-on: ubuntu-latest # ubuntu-latest # I picked Ubuntu to use shell scripts. 25 | 26 | env: 27 | # Comma separated list without double quotes around the list. 28 | CLI_VERSION: latest 29 | 30 | strategy: 31 | matrix: 32 | # The matrix will produce one job for each configuration parameter of type `arduino-boards-fqbn` 33 | # In the Arduino IDE, the fqbn is printed in the first line of the verbose output for compilation as parameter -fqbn=... for the "arduino-builder -dump-prefs" command 34 | # 35 | # Examples: arduino:avr:uno, arduino:avr:leonardo, arduino:avr:nano, arduino:avr:mega 36 | # arduino:sam:arduino_due_x, arduino:samd:arduino_zero_native" 37 | # ATTinyCore:avr:attinyx5:chip=85,clock=1internal, digistump:avr:digispark-tiny, digistump:avr:digispark-pro 38 | # STMicroelectronics:stm32:GenF1:pnum=BLUEPILL_F103C8 39 | # esp8266:esp8266:huzzah:eesz=4M3M,xtal=80, esp32:esp32:featheresp32:FlashFreq=80 40 | # You may add a suffix behind the fqbn with "|" to specify one board for e.g. different compile options like arduino:avr:uno|trace 41 | ############################################################################################################# 42 | arduino-boards-fqbn: 43 | - m5stack:esp32:m5stack_cores3 44 | 45 | # Specify parameters for each board. 46 | ############################################################################################################# 47 | include: 48 | - arduino-boards-fqbn: m5stack:esp32:m5stack_cores3 49 | platform-url: https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/arduino/package_m5stack_index.json 50 | sketches-exclude: WhistleSwitch,50Hz,SimpleFrequencyDetector 51 | 52 | # Do not cancel all jobs / architectures if one job fails 53 | fail-fast: false 54 | 55 | steps: 56 | - name: Checkout 57 | uses: actions/checkout@v3 58 | 59 | - name: Checkout custom library 60 | uses: actions/checkout@v3 61 | with: 62 | repository: ArminJo/ATtinySerialOut 63 | ref: master 64 | path: CustomLibrary # must match the pattern *Custom* 65 | 66 | # Test of the arduino-test-compile action 67 | - name: Compile all examples using the arduino-test-compile action 68 | # uses: ArminJo/arduino-test-compile@master 69 | uses: ./.github/actions 70 | with: 71 | arduino-board-fqbn: ${{ matrix.arduino-boards-fqbn }} 72 | arduino-platform: ${{ matrix.arduino-platform }} 73 | platform-url: ${{ matrix.platform-url }} 74 | required-libraries: ${{ env.REQUIRED_LIBRARIES }} 75 | sketches-exclude: ${{ matrix.sketches-exclude }} 76 | build-properties: ${{ toJson(matrix.build-properties) }} 77 | sketch-names: "*.ino" 78 | sketch-names-find-start: "examples/*" 79 | debug-compile: true 80 | debug-install: true 81 | -------------------------------------------------------------------------------- /.github/workflows/clang-format-check.yml: -------------------------------------------------------------------------------- 1 | name: clang-format Check 2 | on: [push, pull_request] 3 | jobs: 4 | formatting-check: 5 | name: Formatting Check 6 | runs-on: ubuntu-latest 7 | strategy: 8 | matrix: 9 | path: 10 | - check: "./" # path to include 11 | exclude: "(FactoryTest)" # path to exclude 12 | # - check: 'src' 13 | # exclude: '(Fonts)' # Exclude file paths containing "Fonts" 14 | # - check: 'examples' 15 | # exclude: '' 16 | steps: 17 | - uses: actions/checkout@v3.1.0 18 | - name: Run clang-format style check for C/C++/Protobuf programs. 19 | uses: jidicula/clang-format-action@v4.9.0 20 | with: 21 | clang-format-version: "13" 22 | check-path: ${{ matrix.path['check'] }} 23 | exclude-regex: ${{ matrix.path['exclude'] }} 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | .vscode 35 | .pio -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 M5Stack 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # M5CoreS3 Library 2 | 3 | [![Arduino Compile](https://github.com/m5stack/M5CoreS3/actions/workflows/arduino-action-compile.yml/badge.svg)](https://github.com/m5stack/M5CoreS3/actions/workflows/arduino-action-compile.yml) 4 | [![Arduino Lint](https://github.com/m5stack/M5CoreS3/actions/workflows/Arduino-Lint-Check.yml/badge.svg)](https://github.com/m5stack/M5CoreS3/actions/workflows/Arduino-Lint-Check.yml) 5 | [![Clang Format](https://github.com/m5stack/M5CoreS3/actions/workflows/clang-format-check.yml/badge.svg)](https://github.com/m5stack/M5CoreS3/actions/workflows/clang-format-check.yml) 6 | 7 | 8 | English | [中文](README_cn.md) 9 | 10 | M5CoreS3 11 | 12 | * **For the Detailed documentation of CoreS3, please [Click here](https://docs.m5stack.com/en/core/CoreS3)** 13 | 14 | ## Depend Libraries: 15 | 16 | - [M5GFX](https://github.com/m5stack/m5gfx) 17 | - [M5Unified](https://github.com/m5stack/M5unified) 18 | 19 | ## Description 20 | 21 | `CoreS3` is the third generation of the M5Stack development kit series, its core master adopts the `ESP32-S3` solution, `dual-core Xtensa LX7` processor, the main frequency is`240MHz`, comes with '`WiFi`function, and the onboard `16MFLASH`and `8M-PSRAM`; It can `download the program`through the `TYPE-C` interface, support `OTG and CDC`functions, and facilitate external USB devices and flashing firmware; The front is equipped with a `2.0-inch capacitive touch IPS screen`, and the panel is made of `high-strength glass material`; A `30w pixel camera GC0308` is built into the bottom of the screen, with `proximity sensor LTR-553ALS-WA`; The power supply part adopts `AXP2101 power management core`chip and `4-way power flow control loop`, and the overall adopts `low power consumption` design; On-board `6-axis attitude sensor BMI270 and magnetometer BMM150`; On-board `TF-card (microSD)` card slot; On-board BM8563 `RTC` chip, providing accurate timing and `sleep-timer wake-up` function; In terms of sound output, it adopts high-fidelity `16bits-I2S` power amplifier chip AW88298, and the fuselage has a built-in `1w speaker`; In terms of sound input, ES7210 `audio decoding chip + dual microphone input` is adopted; On the side of the fuselage, there is a `independent power button and restart (RST) button`, self-built delay circuit, `long press the reset button to enter the program download mode`. The CoreS3 set comes with a `DinBase Base` by default, which is convenient for `Din rail, wall and screw fixing`; It can be powered by external `DC 12V (support 9~24V)` or internal `500mAh lithium battery`; DinBase reserves multiple `proto` locations for users to `DIY`. This finished product is suitable for scenarios such as `Internet of Things development, various DIY project development, smart home control system and industrial automation control system`. 22 | 23 | **Power on and off operation:**
Power on: Click the left power button
shut down: Long press the left power button for 6 seconds
reset: Click the bottom RST button 24 | 25 | 26 | ## Features 27 | 28 | - Developed based on ESP32, support WiFi @16M Flash, 8M PSRAM 29 | - Built-in camera, proximity sensor, speaker, power indicator, RTC, I2S amplifier, dual microphone, condenser touch screen, power button, reset button, gyroscope 30 | - TF card slot 31 | - High-strength glass 32 | - Support OTG and CDC functions 33 | - AXP2101 power management, low power design 34 | - Supported programming platforms: Arduino, UIFlow 35 | 36 | ## PlatformIO Compilation 37 | 38 | [Compilation File](https://github.com/m5stack/M5CoreS3/blob/main/platformio.ini) 39 | 40 | ## Start with Board Support Package 41 | 42 | To speed up prototyping on some development boards, you can use [Board Support Packages](https://github.com/espressif/esp-bsp) (BSPs), which makes initialization of a particular board as easy as few function calls. 43 | 44 | A BSP typically supports all of the hardware components provided on development board. Apart from the pinout definition and initialization functions, a BSP ships with drivers for the external components such as sensors, displays, audio codecs etc. 45 | 46 | The BSPs are distributed via IDF Component Manager, so they can be found in IDF Component Registry. 47 | 48 | Here is an example of how to add M5CoreS3 BSP to your project: 49 | 50 | `idf.py add-dependency m5stack_core_s3` 51 | 52 | More examples of BSP usage can be found in [BSP examples folder](https://github.com/espressif/esp-bsp/tree/master/examples). 53 | 54 | 55 | ## M5CoreS3 M-BUS Schematic diagram 56 | 57 | 58 | 59 | ## Schematic 60 | 61 | schematics 62 | 63 | 64 | - [Complete schematic pdf](https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/datasheet/core/K128%20CoreS3/Sch_M5_CoreS3_v1.0.pdf) 65 | 66 | 67 | ## More Information 68 | 69 | **Arduino IDE Development**: [Click Here](https://docs.m5stack.com/en/quick_start/cores3/arduino) -------------------------------------------------------------------------------- /README_cn.md: -------------------------------------------------------------------------------- 1 | # M5CoreS3 Library 2 | 3 | [![Arduino Compile](https://github.com/m5stack/M5CoreS3/actions/workflows/arduino-action-compile.yml/badge.svg)](https://github.com/m5stack/M5CoreS3/actions/workflows/arduino-action-compile.yml) 4 | [![Arduino Lint](https://github.com/m5stack/M5CoreS3/actions/workflows/Arduino-Lint-Check.yml/badge.svg)](https://github.com/m5stack/M5CoreS3/actions/workflows/Arduino-Lint-Check.yml) 5 | [![Clang Format](https://github.com/m5stack/M5CoreS3/actions/workflows/clang-format-check.yml/badge.svg)](https://github.com/m5stack/M5CoreS3/actions/workflows/clang-format-check.yml) 6 | 7 | 中文 | [English](README_cn.md) 8 | 9 | 10 | 11 | * **如果查看 CoreS3 的详细介绍文档,[点击这里](https://docs.m5stack.com/zh_CN/core/CoreS3)** 12 | 13 | ## 依赖库: 14 | 15 | - [M5GFX](https://github.com/m5stack/m5gfx) 16 | - [M5Unified](https://github.com/m5stack/M5unified) 17 | 18 | ## 描述 19 | 20 | `CoreS3`是M5Stack开发套件系列的第三代主机,其核心主控采用`ESP32-S3`方案,`双核Xtensa LX7`处理器,主频`240MHz`,自带`WiFi`功能,板载`16MFLASH`和`8M-PSRAM`;可通过`TYPE-C`接口`下载程序`,支持`OTG和CDC`功能,方便外接usb设备和烧录固件;正面搭载一块`2.0寸电容触摸IPS屏`,面板采用`高强度玻璃材质`;屏幕下方内置一个`30w像素的摄像头GC0308`,附带`接近传感器LTR-553ALS-WA`;电源部分采用`AXP2101电源管理芯`片及`4路电源流向控制回路`,整体采用`低功耗`设计;板载`六轴姿态传感器BMI270和磁力计BMM150`;板载`TF-card(microSD)`卡槽;板载BM8563 `RTC`芯片,提供精确计时及`休眠-定时唤醒`功能;声音输出方面采用高保真`16bits-I2S`功放芯片AW88298,机身内置`1w扬声器`;声音输入方面采用ES7210`音频解码芯片+双麦克风输入`;在机身侧边配有`独立电源按键与重启(RST)按键`,自建延时电路,`长按复位键便可进入程序下载模式`。CoreS3套装默认附带`DinBase底座`,方便实现`Din导轨、挂墙以及螺丝固定`;可外部`DC 12V(支持9~24V)`或者内部`500mAh锂电池`供电;DinBase预留多处`proto`的位置,方便用户`DIY`。本成品适用于`物联网开发、各种DIY项目开发、智能家居控制系统和工业自动化控制系统`等场景。 21 | 22 | ## 产品特性 23 | 24 | - 基于 ESP32 开发,支持WiFi @16M Flash,8M PSRAM 25 | - 内置摄像头、接近传感器、扬声器,电源指示灯,RTC,I2S功放,双麦克风,电容式触摸屏幕,电源键,复位按键,陀螺仪 26 | - TF卡插槽 27 | - 高强度玻璃材质 28 | - 支持OTG和CDC功能 29 | - 采用AXP2101电源管理,低功耗设计 30 | - 支持编程平台:Arduino、UIFlow 31 | 32 | ## PlatformIO 编译 33 | 34 | [编译文件](https://github.com/m5stack/M5CoreS3/blob/main/platformio.ini) 35 | 36 | 37 | ## 上手板级支持包 38 | 39 | 可以使用 [板级支持包](https://github.com/espressif/esp-bsp) (BSP),协助在开发板上的原型开发。仅需要调用几个函数,便可以完成对特定开发板的初始化。 40 | 41 | 一般来说,BSP 支持开发板上所有硬件组件。除了管脚定义和初始化功能外,BSP 还附带如传感器、显示器、音频编解码器等外部元件的驱动程序。 42 | 43 | BSP 通过 IDF 组件管理器 发布,可以前往 IDF 组件注册器 进行下载。 44 | 45 | 以下示例演示了如何将 M5CoreS3 BSP 添加到项目中: 46 | 47 | `idf.py add-dependency m5stack_core_s3` 48 | 49 | 更多有关使用 BSP 的示例,请前往 [BSP 示例文件夹](https://github.com/espressif/esp-bsp/tree/master/examples)。 50 | 51 | ## M5CoreS3 M-BUS示意图 52 | 53 | 54 | 55 | ## 原理图 56 | 57 | schematics 58 | 59 | - [完整原理图pdf](https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/datasheet/core/K128%20CoreS3/Sch_M5_CoreS3_v1.0.pdf) 60 | 61 | ## 更多信息 62 | 63 | **Arduino IDE 环境搭建**: [点击这里](https://docs.m5stack.com/zh_CN/quick_start/cores3/arduino) -------------------------------------------------------------------------------- /examples/Advanced/i2c_tester/i2c_tester.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD 3 | * 4 | * SPDX-License-Identifier: MIT 5 | */ 6 | 7 | #include 8 | 9 | void setup() 10 | { 11 | CoreS3.begin(); 12 | CoreS3.Display.setTextColor(YELLOW); // Set the font color to yellow. 13 | CoreS3.Display.setTextSize(2); // Set the font size to 2. 14 | CoreS3.Display.println("M5CoreS3 I2C Tester"); // Print a string on the screen. 15 | CoreS3.Ex_I2C.begin(); 16 | CoreS3.In_I2C.begin(); 17 | } 18 | 19 | int textColor = YELLOW; 20 | 21 | void runScan(m5::I2C_Class &i2c) 22 | { 23 | int address; 24 | for (address = 8; address < 0x78; address++) { 25 | if (i2c.start(address, false, 400000) && i2c.stop()) { 26 | CoreS3.Display.print(address, HEX); 27 | CoreS3.Display.print(" "); 28 | Serial.print(address, HEX); 29 | Serial.print(" "); 30 | } else { 31 | CoreS3.Display.print("."); 32 | Serial.print("."); 33 | } 34 | 35 | delay(10); 36 | } 37 | if (textColor == YELLOW) { 38 | textColor = CYAN; 39 | } else { 40 | textColor = YELLOW; 41 | } 42 | CoreS3.Display.setTextColor(textColor, BLACK); 43 | } 44 | 45 | void loop() 46 | { 47 | int count = 5; 48 | CoreS3.Display.clear(); 49 | while (count--) { 50 | CoreS3.Display.setCursor(0, 0); 51 | CoreS3.Display.println("Ex I2C Address [HEX]"); 52 | runScan(CoreS3.Ex_I2C); 53 | } 54 | count = 5; 55 | CoreS3.Display.clear(); 56 | 57 | while (count--) { 58 | CoreS3.Display.setCursor(0, 0); 59 | CoreS3.Display.println("In I2C Address [HEX]"); 60 | runScan(CoreS3.In_I2C); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /examples/Basic/button/button.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD 3 | * 4 | * SPDX-License-Identifier: MIT 5 | */ 6 | 7 | /* 8 | * @file button.ino 9 | * @author tinyu (tinyu@m5stack.com) 10 | * @brief M5CoreS3 Touch Button / PWR Button Test 11 | * @version 0.2 12 | * @date 2025-03-07 13 | * 14 | * 15 | * @Hardwares: M5CoreS3 16 | * @Platform Version: Arduino M5Stack Board Manager v2.1.3 17 | * @Dependent Library: 18 | * M5GFX: https://github.com/m5stack/M5GFX 19 | * M5Unified: https://github.com/m5stack/M5Unified 20 | * M5CoreS3: https://github.com/m5stack/M5CoreS3 21 | */ 22 | 23 | #include 24 | 25 | static m5::touch_state_t prev_state; 26 | 27 | void setup(void) 28 | { 29 | auto cfg = M5.config(); 30 | CoreS3.begin(cfg); 31 | 32 | CoreS3.Display.setTextColor(RED); 33 | CoreS3.Display.setTextDatum(middle_center); 34 | CoreS3.Display.setFont(&fonts::Orbitron_Light_24); 35 | CoreS3.Display.setTextSize(1); 36 | 37 | CoreS3.Display.drawString("Touch Button Test", CoreS3.Display.width() / 2, 15); 38 | CoreS3.Display.fillRect(0, CoreS3.Display.height() - 40, CoreS3.Display.width() / 3, 40, WHITE); 39 | CoreS3.Display.fillRect(CoreS3.Display.width() / 3, CoreS3.Display.height() - 40, CoreS3.Display.width() / 3, 40, 40 | GREEN); 41 | CoreS3.Display.fillRect((CoreS3.Display.width() / 3) * 2, CoreS3.Display.height() - 40, CoreS3.Display.width() / 3, 42 | 40, YELLOW); 43 | CoreS3.Display.drawString("Btn A Btn B Btn C", CoreS3.Display.width() / 2, CoreS3.Display.height() - 20); 44 | } 45 | 46 | void loop(void) 47 | { 48 | CoreS3.update(); 49 | auto touchPoint = CoreS3.Touch.getDetail(); 50 | if (prev_state != touchPoint.state) { 51 | prev_state = touchPoint.state; 52 | } 53 | if ((CoreS3.Display.height() > touchPoint.y && touchPoint.y > CoreS3.Display.height() - 40) && 54 | touchPoint.state == m5::touch_state_t::touch_begin) { 55 | CoreS3.Display.fillRect(0, 40, CoreS3.Display.width(), 70, BLACK); 56 | if (CoreS3.Display.width() / 3 > touchPoint.x && touchPoint.x > 0) 57 | CoreS3.Display.drawString("Btn A", CoreS3.Display.width() / 2, CoreS3.Display.height() / 2 - 30); 58 | if ((CoreS3.Display.width() / 3) * 2 > touchPoint.x && touchPoint.x > CoreS3.Display.width() / 3) 59 | CoreS3.Display.drawString("Btn B", CoreS3.Display.width() / 2, CoreS3.Display.height() / 2 - 30); 60 | if (CoreS3.Display.width() > touchPoint.x && touchPoint.x > (CoreS3.Display.width() / 3) * 2) 61 | CoreS3.Display.drawString("Btn C", CoreS3.Display.width() / 2, CoreS3.Display.height() / 2 - 30); 62 | Serial.printf("x:%d ,y:%d", touchPoint.x, touchPoint.y); 63 | } 64 | int state = CoreS3.BtnPWR.wasClicked(); 65 | if (state) { 66 | CoreS3.Display.fillRect(0, 40, CoreS3.Display.width(), 70, BLACK); 67 | CoreS3.Display.drawString("Btn PWR", CoreS3.Display.width() / 2, CoreS3.Display.height() / 2 - 30); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /examples/Basic/camera/camera.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD 3 | * 4 | * SPDX-License-Identifier: MIT 5 | */ 6 | 7 | /* 8 | * @file camera.ino 9 | * @author SeanKwok (shaoxiang@m5stack.com) 10 | * @brief M5CoreS3 Camera Test 11 | * @version 0.1 12 | * @date 2023-12-25 13 | * 14 | * 15 | * @Hardwares: M5CoreS3 16 | * @Platform Version: Arduino M5Stack Board Manager v2.0.9 17 | * @Dependent Library: 18 | * M5GFX: https://github.com/m5stack/M5GFX 19 | * M5Unified: https://github.com/m5stack/M5Unified 20 | * M5CoreS3: https://github.com/m5stack/M5CoreS3 21 | */ 22 | #include "M5CoreS3.h" 23 | 24 | #include "esp_camera.h" 25 | 26 | // #define CONVERT_TO_JPEG 27 | 28 | void setup() 29 | { 30 | auto cfg = M5.config(); 31 | CoreS3.begin(cfg); 32 | CoreS3.Display.setTextColor(GREEN); 33 | CoreS3.Display.setTextDatum(middle_center); 34 | CoreS3.Display.setFont(&fonts::Orbitron_Light_24); 35 | CoreS3.Display.setTextSize(1); 36 | 37 | if (!CoreS3.Camera.begin()) { 38 | CoreS3.Display.drawString("Camera Init Fail", CoreS3.Display.width() / 2, CoreS3.Display.height() / 2); 39 | } 40 | CoreS3.Display.drawString("Camera Init Success", CoreS3.Display.width() / 2, CoreS3.Display.height() / 2); 41 | } 42 | 43 | void loop() 44 | { 45 | if (CoreS3.Camera.get()) { 46 | #ifdef CONVERT_TO_JPEG 47 | uint8_t *out_jpg = NULL; 48 | size_t out_jpg_len = 0; 49 | frame2jpg(CoreS3.Camera.fb, 255, &out_jpg, &out_jpg_len); 50 | CoreS3.Display.drawJpg(out_jpg, out_jpg_len, 0, 0, CoreS3.Display.width(), CoreS3.Display.height()); 51 | free(out_jpg); 52 | #else 53 | CoreS3.Display.pushImage(0, 0, CoreS3.Display.width(), CoreS3.Display.height(), 54 | (uint16_t *)CoreS3.Camera.fb->buf); 55 | #endif 56 | 57 | CoreS3.Camera.free(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /examples/Basic/display/display.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD 3 | * 4 | * SPDX-License-Identifier: MIT 5 | */ 6 | 7 | /* 8 | * @file display.ino 9 | * @author SeanKwok (shaoxiang@m5stack.com) 10 | * @brief M5CoreS3 Display Test 11 | * @version 0.1 12 | * @date 2023-12-18 13 | * 14 | * 15 | * @Hardwares: M5CoreS3 16 | * @Platform Version: Arduino M5Stack Board Manager v2.0.7 17 | * @Dependent Library: 18 | * M5GFX: https://github.com/m5stack/M5GFX 19 | * M5Unified: https://github.com/m5stack/M5Unified 20 | * M5CoreS3: https://github.com/m5stack/M5CoreS3 21 | */ 22 | #include "M5CoreS3.h" 23 | 24 | void draw_function(LovyanGFX* gfx) { 25 | int x = rand() % gfx->width(); 26 | int y = rand() % gfx->height(); 27 | int r = (gfx->width() >> 4) + 2; 28 | uint16_t c = rand(); 29 | gfx->fillRect(x - r, y - r, r * 2, r * 2, c); 30 | } 31 | 32 | void setup() { 33 | auto cfg = M5.config(); 34 | CoreS3.begin(cfg); 35 | int textsize = CoreS3.Display.height() / 60; 36 | if (textsize == 0) { 37 | textsize = 1; 38 | } 39 | CoreS3.Display.setTextSize(textsize); 40 | } 41 | 42 | void loop() { 43 | int x = rand() % CoreS3.Display.width(); 44 | int y = rand() % CoreS3.Display.height(); 45 | int r = (CoreS3.Display.width() >> 4) + 2; 46 | uint16_t c = rand(); 47 | CoreS3.Display.fillCircle(x, y, r, c); 48 | draw_function(&CoreS3.Display); 49 | } -------------------------------------------------------------------------------- /examples/Basic/imu/imu.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD 3 | * 4 | * SPDX-License-Identifier: MIT 5 | */ 6 | 7 | #include 8 | 9 | void setup() { 10 | auto cfg = M5.config(); 11 | CoreS3.begin(cfg); 12 | CoreS3.Display.setTextSize(2); // Set text size. 13 | CoreS3.Display.setCursor(0, 0); // Set the cursor. 14 | delay(200); // Delay 200ms. 15 | CoreS3.Imu.begin(); // Init IMU. 16 | } 17 | 18 | void loop() { 19 | auto imu_update = M5.Imu.update(); 20 | if (imu_update) { 21 | auto data = M5.Imu.getImuData(); 22 | 23 | // The data obtained by getImuData can be used as follows. 24 | data.accel.x; // accel x-axis value. 25 | data.accel.y; // accel y-axis value. 26 | data.accel.z; // accel z-axis value. 27 | data.accel.value; // accel 3values array [0]=x / [1]=y / [2]=z. 28 | 29 | data.gyro.x; // gyro x-axis value. 30 | data.gyro.y; // gyro y-axis value. 31 | data.gyro.z; // gyro z-axis value. 32 | data.gyro.value; // gyro 3values array [0]=x / [1]=y / [2]=z. 33 | 34 | data.mag.x; // mag x-axis value. 35 | data.mag.y; // mag y-axis value. 36 | data.mag.z; // mag z-axis value. 37 | data.mag.value; // mag 3values array [0]=x / [1]=y / [2]=z. 38 | 39 | data.value; // all sensor 9values array [0~2]=accel / [3~5]=gyro / 40 | // [6~8]=mag 41 | 42 | // gyroscope output related. 43 | CoreS3.Display.setCursor(0, 20); 44 | CoreS3.Display.printf( 45 | "gyroX, gyroY, gyroZ"); // Screen printingformatted string. 46 | CoreS3.Display.setCursor(0, 42); 47 | CoreS3.Display.fillRect(0, 42, 320, 20, BLACK); 48 | CoreS3.Display.printf("%2.2f\t %2.2f\t %2.2f", data.gyro.x, 49 | data.gyro.y, data.gyro.z); 50 | 51 | // Accelerometer output is related 52 | CoreS3.Display.setCursor(0, 70); 53 | CoreS3.Display.printf("accX, accY, accZ"); 54 | CoreS3.Display.setCursor(0, 92); 55 | CoreS3.Display.fillRect(0, 92, 320, 20, BLACK); 56 | CoreS3.Display.printf("%2.2f\t %2.2f\t %2.2f", data.accel.x, 57 | data.accel.y, data.accel.z); 58 | 59 | // Pose output is related 60 | CoreS3.Display.setCursor(0, 120); 61 | CoreS3.Display.printf("pitch, roll, yaw"); 62 | CoreS3.Display.setCursor(0, 142); 63 | CoreS3.Display.fillRect(0, 142, 320, 20, BLACK); 64 | CoreS3.Display.printf("%2.1f %2.1f %2.1f", data.mag.x, data.mag.y, 65 | data.mag.z); 66 | 67 | delay(10); 68 | } 69 | } -------------------------------------------------------------------------------- /examples/Basic/ltr553/ltr553.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD 3 | * 4 | * SPDX-License-Identifier: MIT 5 | */ 6 | 7 | /* 8 | * @file ltr553.ino 9 | * @author SeanKwok (shaoxiang@m5stack.com) 10 | * @brief M5CoreS3 LTR553 Test 11 | * @version 0.1 12 | * @date 2023-12-25 13 | * 14 | * 15 | * @Hardwares: M5CoreS3 16 | * @Platform Version: Arduino M5Stack Board Manager v2.0.9 17 | * @Dependent Library: 18 | * M5GFX: https://github.com/m5stack/M5GFX 19 | * M5Unified: https://github.com/m5stack/M5Unified 20 | * M5CoreS3: https://github.com/m5stack/M5CoreS3 21 | */ 22 | #include 23 | 24 | Ltr5xx_Init_Basic_Para device_init_base_para = LTR5XX_BASE_PARA_CONFIG_DEFAULT; 25 | 26 | uint16_t read_ps_value; 27 | uint16_t read_als_value; 28 | 29 | void setup() { 30 | auto cfg = M5.config(); 31 | CoreS3.begin(cfg); 32 | CoreS3.Display.setTextColor(GREEN); 33 | CoreS3.Display.setTextDatum(middle_center); 34 | CoreS3.Display.setFont(&fonts::Orbitron_Light_24); 35 | CoreS3.Display.setTextSize(1); 36 | 37 | device_init_base_para.ps_led_pulse_freq = LTR5XX_LED_PULSE_FREQ_40KHZ; 38 | device_init_base_para.ps_measurement_rate = LTR5XX_PS_MEASUREMENT_RATE_50MS; 39 | device_init_base_para.als_gain = LTR5XX_ALS_GAIN_48X; 40 | 41 | if (!CoreS3.Ltr553.begin(&device_init_base_para)) { 42 | CoreS3.Display.drawString("Ltr553 Init Fail", 43 | CoreS3.Display.width() / 2, 44 | CoreS3.Display.height() / 2); 45 | while (1) { 46 | delay(10); 47 | } 48 | } 49 | 50 | CoreS3.Display.drawString("Ltr553 Init Success", CoreS3.Display.width() / 2, 51 | CoreS3.Display.height() / 2); 52 | // active ps 53 | CoreS3.Ltr553.setPsMode(LTR5XX_PS_ACTIVE_MODE); 54 | 55 | // active als 56 | CoreS3.Ltr553.setAlsMode(LTR5XX_ALS_ACTIVE_MODE); 57 | // not active ps 58 | // CoreS3.Ltr553.setPsMode(LTR5XX_PS_STAND_BY_MODE); 59 | 60 | // not active als 61 | // CoreS3.Ltr553.setAlsMode(LTR5XX_ALS_STAND_BY_MODE); 62 | } 63 | 64 | void loop() { 65 | CoreS3.Display.clear(); 66 | read_ps_value = CoreS3.Ltr553.getPsValue(); 67 | read_als_value = CoreS3.Ltr553.getAlsValue(); 68 | 69 | CoreS3.Display.drawString( 70 | "PS:" + String(read_ps_value) + " / " + "ALS:" + String(read_als_value), 71 | CoreS3.Display.width() / 2, CoreS3.Display.height() / 2); 72 | 73 | Serial.printf("ps value = %d\r\n", read_ps_value); 74 | Serial.printf("als value = %d\r\n", read_als_value); 75 | delay(100); 76 | } 77 | -------------------------------------------------------------------------------- /examples/Basic/mic/mic.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD 3 | * 4 | * SPDX-License-Identifier: MIT 5 | * 6 | * @Hardwares: M5CoreS3 7 | * @Platform Version: Arduino M5Stack Board Manager v2.0.9 8 | * @Dependent Library: 9 | * M5GFX: https://github.com/m5stack/M5GFX 10 | * M5Unified: https://github.com/m5stack/M5Unified 11 | * M5CoreS3: https://github.com/m5stack/M5CoreS3 12 | */ 13 | 14 | #include 15 | 16 | static constexpr const size_t record_number = 256; 17 | static constexpr const size_t record_length = 320; 18 | static constexpr const size_t record_size = record_number * record_length; 19 | static constexpr const size_t record_samplerate = 17000; 20 | static int16_t prev_y[record_length]; 21 | static int16_t prev_h[record_length]; 22 | static size_t rec_record_idx = 2; 23 | static size_t draw_record_idx = 0; 24 | static int16_t *rec_data; 25 | 26 | void setup(void) { 27 | auto cfg = M5.config(); 28 | 29 | CoreS3.begin(cfg); 30 | 31 | CoreS3.Display.startWrite(); 32 | CoreS3.Display.setRotation(1); 33 | CoreS3.Display.setTextDatum(top_center); 34 | CoreS3.Display.setTextColor(WHITE); 35 | CoreS3.Display.setFont(&fonts::FreeSansBoldOblique12pt7b); 36 | 37 | rec_data = (typeof(rec_data))heap_caps_malloc(record_size * 38 | 39 | sizeof(int16_t), 40 | MALLOC_CAP_8BIT); 41 | memset(rec_data, 0, record_size * sizeof(int16_t)); 42 | CoreS3.Speaker.setVolume(255); 43 | 44 | /// Since the microphone and speaker cannot be used at the same time, 45 | // turn 46 | /// off the speaker here. 47 | CoreS3.Speaker.end(); 48 | CoreS3.Mic.begin(); 49 | CoreS3.Display.fillCircle(130, 15, 8, RED); 50 | CoreS3.Display.drawString("REC", 180, 3); 51 | } 52 | 53 | void loop(void) { 54 | CoreS3.update(); 55 | 56 | if (CoreS3.Mic.isEnabled()) { 57 | static constexpr int shift = 6; 58 | auto data = &rec_data[rec_record_idx * record_length]; 59 | if (CoreS3.Mic.record(data, record_length, record_samplerate)) { 60 | data = &rec_data[draw_record_idx * record_length]; 61 | 62 | int32_t w = CoreS3.Display.width(); 63 | if (w > record_length - 1) { 64 | w = record_length - 1; 65 | } 66 | for (int32_t x = 0; x < w; ++x) { 67 | CoreS3.Display.writeFastVLine(x, prev_y[x], prev_h[x], 68 | TFT_BLACK); 69 | int32_t y1 = (data[x] >> shift); 70 | int32_t y2 = (data[x + 1] >> shift); 71 | if (y1 > y2) { 72 | int32_t tmp = y1; 73 | y1 = y2; 74 | y2 = tmp; 75 | } 76 | int32_t y = ((CoreS3.Display.height()) >> 1) + y1; 77 | int32_t h = ((CoreS3.Display.height()) >> 1) + y2 + 1 - y; 78 | prev_y[x] = y; 79 | prev_h[x] = h; 80 | CoreS3.Display.writeFastVLine(x, prev_y[x], prev_h[x], WHITE); 81 | } 82 | 83 | CoreS3.Display.display(); 84 | CoreS3.Display.fillCircle(130, 15, 8, RED); 85 | CoreS3.Display.drawString("REC", 180, 3); 86 | if (++draw_record_idx >= record_number) { 87 | draw_record_idx = 0; 88 | } 89 | if (++rec_record_idx >= record_number) { 90 | rec_record_idx = 0; 91 | } 92 | } 93 | } 94 | int state = M5.BtnPWR.wasClicked(); 95 | if (state) { 96 | auto cfg = CoreS3.Mic.config(); 97 | cfg.noise_filter_level = (cfg.noise_filter_level + 8) & 255; 98 | CoreS3.Mic.config(cfg); 99 | CoreS3.Display.clear(); 100 | CoreS3.Display.fillCircle(130, 15, 8, GREEN); 101 | CoreS3.Display.drawString("NF:" + String(cfg.noise_filter_level), 180, 102 | 3); 103 | delay(2000); 104 | CoreS3.Display.clear(); 105 | 106 | } else if (M5.Touch.getCount() && M5.Touch.getDetail(0).wasClicked()) { 107 | if (CoreS3.Speaker.isEnabled()) { 108 | CoreS3.Display.clear(); 109 | while (CoreS3.Mic.isRecording()) { 110 | delay(1); 111 | } 112 | /// Since the microphone and speaker cannot be used at the same 113 | /// time, turn off the microphone here. 114 | CoreS3.Mic.end(); 115 | CoreS3.Speaker.begin(); 116 | 117 | CoreS3.Display.fillTriangle(130 - 8, 15 - 8, 130 - 8, 15 + 8, 118 | 130 + 8, 15, 0x1c9f); 119 | CoreS3.Display.drawString("PLAY", 180, 3); 120 | int start_pos = rec_record_idx * record_length; 121 | if (start_pos < record_size) { 122 | CoreS3.Speaker.playRaw(&rec_data[start_pos], 123 | record_size - start_pos, 124 | record_samplerate, false, 1, 0); 125 | } 126 | if (start_pos > 0) { 127 | CoreS3.Speaker.playRaw(rec_data, start_pos, record_samplerate, 128 | false, 1, 0); 129 | } 130 | do { 131 | delay(1); 132 | CoreS3.update(); 133 | } while (CoreS3.Speaker.isPlaying()); 134 | 135 | /// Since the microphone and speaker cannot be used at the same 136 | /// time, turn off the speaker here. 137 | CoreS3.Speaker.end(); 138 | CoreS3.Mic.begin(); 139 | 140 | CoreS3.Display.clear(); 141 | CoreS3.Display.fillCircle(130, 15, 8, RED); 142 | CoreS3.Display.drawString("REC", 180, 3); 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /examples/Basic/mic_wav_record/mic_wav_record.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD 3 | * 4 | * SPDX-License-Identifier: MIT 5 | * 6 | * @Hardwares: M5CoreS3 7 | * @Platform Version: Arduino M5Stack Board Manager v2.0.9 8 | * @Dependent Library: 9 | * M5GFX: https://github.com/m5stack/M5GFX 10 | * M5Unified: https://github.com/m5stack/M5Unified 11 | * M5CoreS3: https://github.com/m5stack/M5CoreS3 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | // Btn A is to record audio. Btn A 是录音音频 19 | // Btn B is to play audio. Btn B是播放音频 20 | // Btn C is to delete file. Btn C是删除文件 21 | // PWR is to select a file. PWR是选择文件 22 | // The selected file is yellow, the unselected file is white, and the playing 23 | // file is the selected file. 24 | // 选中的文件是黄色的,未选中的文件是白色的,播放的文件是选中的文件. 25 | 26 | #define SD_SPI_SCK_PIN (36) 27 | #define SD_SPI_MISO_PIN (35) 28 | #define SD_SPI_MOSI_PIN (37) 29 | #define SD_SPI_CS_PIN (4) 30 | 31 | static constexpr const size_t record_number = 256; 32 | static constexpr const size_t record_length = 320; 33 | static constexpr const size_t record_size = record_number * record_length; 34 | static constexpr const size_t record_samplerate = 17000; 35 | static int16_t prev_y[record_length]; 36 | static int16_t prev_h[record_length]; 37 | static size_t rec_record_idx = 2; 38 | static size_t draw_record_idx = 0; 39 | static int16_t* rec_data; 40 | 41 | static uint32_t file_counter = 0; 42 | static uint8_t selectedFileIndex = 0; 43 | static std::vector wavFiles; 44 | 45 | static m5::touch_state_t prev_state; 46 | 47 | // AV file header definition 48 | struct WAVHeader { 49 | char riff[4] = {'R', 'I', 'F', 'F'}; 50 | uint32_t fileSize = 0; 51 | char wave[4] = {'W', 'A', 'V', 'E'}; 52 | char fmt[4] = {'f', 'm', 't', ' '}; 53 | uint32_t fmtSize = 16; 54 | uint16_t audioFormat = 1; 55 | uint16_t numChannels = 1; 56 | uint32_t sampleRate = record_samplerate; 57 | uint32_t byteRate = record_samplerate * sizeof(int16_t); 58 | uint16_t blockAlign = sizeof(int16_t); 59 | uint16_t bitsPerSample = 16; 60 | char data[4] = {'d', 'a', 't', 'a'}; 61 | uint32_t dataSize = 0; 62 | }; 63 | 64 | void micRecord(void); // Record audio. 65 | void viewBtn(void); // Display button 66 | bool saveWAVToSD(int16_t* data, 67 | size_t dataSize); // Save the WAV file to the SD card. 68 | void scanAndDisplayWAVFiles( 69 | void); // Scan and display the WAV files on the SD card on the screen. 70 | bool playSelectedWAVFile( 71 | const String& fileName); // Play the selected WAV file. 72 | void playWAV(uint32_t sampleRate); // Play the WAV file. 73 | void updateDisplay( 74 | std::vector wavFiles, 75 | uint8_t selectedFileIndex); // Update the displayed information. 76 | void setup(void) { 77 | CoreS3.begin(); 78 | Serial.begin(115200); 79 | 80 | CoreS3.Display.startWrite(); 81 | CoreS3.Display.setRotation(1); 82 | CoreS3.Display.setTextDatum(top_center); 83 | CoreS3.Display.setTextColor(WHITE); 84 | CoreS3.Display.setFont(&fonts::FreeSansBoldOblique12pt7b); 85 | CoreS3.Display.endWrite(); 86 | 87 | // SD Card Initialization 88 | SPI.begin(SD_SPI_SCK_PIN, SD_SPI_MISO_PIN, SD_SPI_MOSI_PIN, SD_SPI_CS_PIN); 89 | 90 | if (!SD.begin(SD_SPI_CS_PIN, SPI, 25000000)) { 91 | printf("Card failed, or not present\r\n"); 92 | while (1); 93 | } 94 | uint8_t cardType = SD.cardType(); 95 | if (cardType == CARD_NONE) { 96 | printf("No SD card attached\r\n"); 97 | return; 98 | } 99 | printf("SD Card Type: "); 100 | if (cardType == CARD_MMC) { 101 | printf("MMC\r\n"); 102 | } else if (cardType == CARD_SD) { 103 | printf("SDSC\r\n"); 104 | } else if (cardType == CARD_SDHC) { 105 | printf("SDHC\r\n"); 106 | } else { 107 | printf("UNKNOWN\r\n"); 108 | } 109 | uint64_t cardSize = SD.cardSize() / (1024 * 1024); 110 | printf("SD Card Size: %lluMB\r\n", cardSize); 111 | 112 | rec_data = (typeof(rec_data))heap_caps_malloc(record_size * sizeof(int16_t), 113 | MALLOC_CAP_8BIT); 114 | memset(rec_data, 0, record_size * sizeof(int16_t)); 115 | CoreS3.Speaker.setVolume(255); 116 | 117 | /// Since the microphone and speaker cannot be used at the same time, 118 | // turn 119 | /// off the speaker here. 120 | CoreS3.Speaker.end(); 121 | CoreS3.Mic.begin(); 122 | viewBtn(); 123 | scanAndDisplayWAVFiles(); 124 | updateDisplay(wavFiles, selectedFileIndex); 125 | } 126 | 127 | void loop(void) { 128 | CoreS3.update(); 129 | auto touchPoint = CoreS3.Touch.getDetail(); 130 | if (prev_state != touchPoint.state) { 131 | prev_state = touchPoint.state; 132 | } 133 | if ((CoreS3.Display.height() > touchPoint.y && 134 | touchPoint.y > CoreS3.Display.height() - 40) && 135 | touchPoint.state == m5::touch_state_t::touch_begin) { 136 | if (CoreS3.Display.width() / 3 > touchPoint.x && 137 | touchPoint.x > 0) { // Record an audio file. 138 | micRecord(); 139 | if (saveWAVToSD(rec_data, record_size)) { 140 | printf("WAV file saved successfully.\n"); 141 | } else { 142 | printf("Failed to save WAV file.\n"); 143 | } 144 | viewBtn(); 145 | scanAndDisplayWAVFiles(); 146 | } 147 | if ((CoreS3.Display.width() / 3) * 2 > touchPoint.x && 148 | touchPoint.x > CoreS3.Display.width() / 3) { // Play an audio file. 149 | playSelectedWAVFile(wavFiles[selectedFileIndex]); 150 | viewBtn(); 151 | } 152 | if (CoreS3.Display.width() > touchPoint.x && 153 | touchPoint.x > (CoreS3.Display.width() / 3) * 2) { // 删除音频文件 154 | String filePath = "/" + wavFiles[selectedFileIndex]; 155 | if (SD.remove(filePath.c_str())) { 156 | printf("Deleted file: %s\n", filePath.c_str()); 157 | wavFiles.erase(wavFiles.begin() + selectedFileIndex); 158 | if (selectedFileIndex >= wavFiles.size() && !wavFiles.empty()) { 159 | selectedFileIndex--; 160 | } 161 | } else { 162 | printf("Failed to delete file: %s\n", filePath.c_str()); 163 | } 164 | scanAndDisplayWAVFiles(); 165 | } 166 | } 167 | int state = M5.BtnPWR.wasClicked(); // Delete an audio file. 168 | if (state) { 169 | selectedFileIndex = (++selectedFileIndex) % wavFiles.size(); 170 | updateDisplay(wavFiles, selectedFileIndex); 171 | } 172 | } 173 | 174 | void micRecord(void) { 175 | CoreS3.Display.startWrite(); 176 | CoreS3.Display.clear(); 177 | CoreS3.Display.setTextColor(WHITE); 178 | // Record 179 | if (CoreS3.Mic.isEnabled()) { 180 | CoreS3.Display.fillCircle(130, 15, 8, RED); 181 | CoreS3.Display.drawString("REC", 180, 15); 182 | static constexpr int shift = 6; 183 | for (uint16_t i = 0; i < record_number; i++) { 184 | auto data = &rec_data[i * record_length]; 185 | if (CoreS3.Mic.record(data, record_length, record_samplerate)) { 186 | if (i >= 2) { 187 | data = &rec_data[(i - 2) * record_length]; 188 | int32_t w = CoreS3.Display.width(); 189 | if (w > record_length - 1) { 190 | w = record_length - 1; 191 | } 192 | for (int32_t x = 0; x < w; ++x) { 193 | CoreS3.Display.writeFastVLine(x, prev_y[x], prev_h[x], 194 | TFT_BLACK); 195 | int32_t y1 = (data[x] >> shift); 196 | int32_t y2 = (data[x + 1] >> shift); 197 | if (y1 > y2) { 198 | int32_t tmp = y1; 199 | y1 = y2; 200 | y2 = tmp; 201 | } 202 | int32_t y = ((CoreS3.Display.height()) >> 1) + y1; 203 | int32_t h = 204 | ((CoreS3.Display.height()) >> 1) + y2 + 1 - y; 205 | prev_y[x] = y; 206 | prev_h[x] = h; 207 | CoreS3.Display.writeFastVLine(x, prev_y[x], prev_h[x], 208 | WHITE); 209 | } 210 | } 211 | } 212 | CoreS3.Display.display(); 213 | CoreS3.Display.fillCircle(130, 15, 8, RED); 214 | CoreS3.Display.drawString("REC", 180, 15); 215 | } 216 | CoreS3.Display.clear(); 217 | } 218 | CoreS3.Display.endWrite(); 219 | } 220 | 221 | void viewBtn(void) { 222 | CoreS3.Display.startWrite(); 223 | CoreS3.Display.setTextColor(RED); 224 | CoreS3.Display.setTextDatum(middle_center); 225 | CoreS3.Display.setFont(&fonts::Orbitron_Light_24); 226 | CoreS3.Display.setTextSize(1); 227 | CoreS3.Display.fillRect(0, CoreS3.Display.height() - 40, 228 | CoreS3.Display.width() / 3, 40, WHITE); 229 | CoreS3.Display.fillRect(CoreS3.Display.width() / 3, 230 | CoreS3.Display.height() - 40, 231 | CoreS3.Display.width() / 3, 40, GREEN); 232 | CoreS3.Display.fillRect((CoreS3.Display.width() / 3) * 2, 233 | CoreS3.Display.height() - 40, 234 | CoreS3.Display.width() / 3, 40, YELLOW); 235 | CoreS3.Display.drawString("Btn A Btn B Btn C", 236 | CoreS3.Display.width() / 2, 237 | CoreS3.Display.height() - 20); 238 | CoreS3.Display.endWrite(); 239 | } 240 | 241 | void scanAndDisplayWAVFiles() { 242 | static std::vector previousWavFiles; 243 | 244 | // Scan the WAV files on the SD card and store them in wavFiles. 245 | File dir = SD.open("/"); 246 | if (!dir) { 247 | printf("Failed to open directory.\n"); 248 | return; 249 | } 250 | wavFiles.clear(); 251 | while (File entry = dir.openNextFile()) { 252 | if (!entry.isDirectory() && String(entry.name()).endsWith(".wav")) { 253 | wavFiles.push_back( 254 | String(entry.name())); // Only add .wav files to the list. 255 | } 256 | entry.close(); 257 | } 258 | dir.close(); 259 | 260 | // If wavFiles changes, clear the interface and update the display. 261 | if (wavFiles != previousWavFiles) { 262 | previousWavFiles = wavFiles; // Update the previous file list. 263 | updateDisplay(wavFiles, selectedFileIndex); 264 | } 265 | } 266 | 267 | void updateDisplay(std::vector wavFiles, uint8_t selectedFileIndex) { 268 | CoreS3.Display.startWrite(); 269 | if (wavFiles.empty()) { 270 | printf("No WAV files found on SD card.\n"); 271 | CoreS3.Display.fillRect(0, 0, 320, 200, BLACK); 272 | CoreS3.Display.setTextColor(RED); 273 | int xPos = (CoreS3.Display.width()) / 2; 274 | int yPos = CoreS3.Display.height() / 2 - 20; 275 | CoreS3.Display.drawString("No WAV files found", xPos, yPos); 276 | CoreS3.Display.endWrite(); 277 | return; 278 | } 279 | const uint8_t maxVisibleFiles = 7; 280 | uint8_t startIndex = 0; 281 | 282 | // Ensure the selected file is within the visible area. 283 | if (selectedFileIndex >= maxVisibleFiles) { 284 | startIndex = selectedFileIndex - (maxVisibleFiles - 1); 285 | } 286 | CoreS3.Display.fillRect(0, 0, 320, 200, BLACK); 287 | 288 | // Display the list of WAV files, centered. The selected file's font will be 289 | // yellow, and the unselected files' font will be white. 290 | for (size_t i = startIndex; 291 | i < startIndex + maxVisibleFiles && i < wavFiles.size(); i++) { 292 | uint16_t color = (i == selectedFileIndex) ? YELLOW : WHITE; 293 | CoreS3.Display.setTextColor(color); 294 | CoreS3.Display.drawString(wavFiles[i], CoreS3.Display.width() / 2, 295 | 25 + (i - startIndex) * 25); 296 | } 297 | CoreS3.Display.endWrite(); 298 | } 299 | bool saveWAVToSD(int16_t* data, size_t dataSize) { 300 | // Validate input data. 301 | if (!data || dataSize == 0) { 302 | printf("Invalid data or dataSize.\n"); 303 | return false; // Invalid data or size, return false. 304 | } 305 | 306 | // Generate the filename using the counter. 307 | char filename[32]; 308 | snprintf(filename, sizeof(filename), "/recorded%lu.wav", file_counter); 309 | file_counter++; // Increment the counter for the next file. 310 | 311 | // Open the file for writing (it will overwrite the file if it exists). 312 | File file = SD.open(filename, FILE_WRITE); 313 | if (!file) { 314 | printf("Failed to open file for writing: %s\n", filename); 315 | return false; // Failed to open the file, return false. 316 | } 317 | 318 | // Initialize WAV header. 319 | WAVHeader header; 320 | header.fileSize = 321 | 36 + 322 | dataSize * sizeof(int16_t); // Calculate file size (including header). 323 | header.dataSize = dataSize * sizeof(int16_t); // Calculate data size. 324 | 325 | // Write the WAV header to the file. 326 | if (file.write((uint8_t*)&header, sizeof(WAVHeader)) != sizeof(WAVHeader)) { 327 | printf("Failed to write WAV header.\n"); 328 | file.close(); 329 | return false; // Failed to write header, close file and return false. 330 | } 331 | 332 | // Write the audio data to the file. 333 | if (file.write((uint8_t*)data, dataSize * sizeof(int16_t)) != 334 | dataSize * sizeof(int16_t)) { 335 | printf("Failed to write WAV data.\n"); 336 | file.close(); 337 | return false; // Failed to write data, close file and return false. 338 | } 339 | 340 | // Close the file after writing. 341 | file.close(); 342 | printf("WAV file saved successfully: %s\n", filename); 343 | return true; // Successfully saved the file, return true. 344 | } 345 | 346 | bool playSelectedWAVFile(const String& fileName) { 347 | String filePath = "/" + fileName; 348 | printf("Playing WAV file: %s\n", filePath.c_str()); 349 | 350 | // Open the WAV file 351 | File file = SD.open(filePath.c_str()); 352 | if (!file) { 353 | printf("Failed to open WAV file: %s\n", filePath.c_str()); 354 | return false; // Return false if the file cannot be opened 355 | } 356 | 357 | // Read the WAV file header to extract relevant information (e.g., sample 358 | // rate) 359 | WAVHeader header; 360 | file.read((uint8_t*)&header, sizeof(WAVHeader)); 361 | 362 | // Validate the WAV file header 363 | if (header.riff[0] != 'R' || header.riff[1] != 'I' || 364 | header.riff[2] != 'F' || header.riff[3] != 'F') { 365 | printf("Invalid WAV file: 'RIFF' header not found.\n"); 366 | file.close(); 367 | return false; // Return false if the header is invalid 368 | } 369 | if (header.wave[0] != 'W' || header.wave[1] != 'A' || 370 | header.wave[2] != 'V' || header.wave[3] != 'E') { 371 | printf("Invalid WAV file: 'WAVE' header not found.\n"); 372 | file.close(); 373 | return false; // Return false if the header is invalid 374 | } 375 | 376 | // Extract sample rate from the header (bytes 24-27) 377 | printf("Sample Rate from WAV header: %lu\n", header.sampleRate); 378 | 379 | // Skip the rest of the WAV file header (typically 44 bytes) 380 | file.seek(44); // Skip to the data section 381 | 382 | // Read audio data into the buffer 383 | size_t bytesRead = 384 | file.read((uint8_t*)rec_data, record_size * sizeof(int16_t)); 385 | file.close(); 386 | 387 | if (bytesRead == 0) { 388 | printf("Failed to read WAV file data.\n"); 389 | return false; // Return false if no data was read 390 | } 391 | 392 | // Play the WAV data 393 | playWAV(header.sampleRate); 394 | printf("Playback finished.\n"); 395 | return true; 396 | } 397 | 398 | void playWAV(uint32_t sampleRate) { 399 | CoreS3.Display.startWrite(); 400 | CoreS3.Display.clear(); 401 | CoreS3.Mic.end(); // Disable the microphone 402 | CoreS3.Speaker.begin(); // Enable the speaker for playback 403 | CoreS3.Display.setTextColor(WHITE); 404 | CoreS3.Display.fillTriangle(120 - 8, 15 - 8, 120 - 8, 15 + 8, 120 + 8, 15, 405 | 0x1c9f); 406 | CoreS3.Display.drawString("PLAY", 180, 407 | 15); // Display "PLAY" text on the screen 408 | static constexpr int shift = 6; 409 | 410 | // Loop through all the data blocks and play them 411 | for (uint16_t i = 0; i < record_number; i++) { 412 | auto data = &rec_data[i * record_length]; 413 | 414 | // Play the data block using the sample rate extracted from the WAV 415 | // header 416 | CoreS3.Speaker.playRaw(&rec_data[i * record_length], record_length, 417 | sampleRate); 418 | 419 | // Wait until playback finishes 420 | do { 421 | delay(1); 422 | CoreS3.update(); 423 | } while (CoreS3.Speaker.isPlaying()); 424 | 425 | // If more than two data blocks have been played, display the waveform 426 | if (i >= 2) { 427 | data = &rec_data[(i - 2) * record_length]; 428 | int32_t w = CoreS3.Display.width(); 429 | if (w > record_length - 1) { 430 | w = record_length - 1; 431 | } 432 | for (int32_t x = 0; x < w; ++x) { 433 | CoreS3.Display.writeFastVLine( 434 | x, prev_y[x], prev_h[x], 435 | TFT_BLACK); // Erase previous lines 436 | int32_t y1 = (data[x] >> shift); 437 | int32_t y2 = (data[x + 1] >> shift); 438 | if (y1 > y2) { 439 | int32_t tmp = y1; 440 | y1 = y2; 441 | y2 = tmp; // Ensure y1 is less than y2 442 | } 443 | int32_t y = ((CoreS3.Display.height()) >> 1) + y1; 444 | int32_t h = ((CoreS3.Display.height()) >> 1) + y2 + 1 - y; 445 | prev_y[x] = y; 446 | prev_h[x] = h; 447 | CoreS3.Display.writeFastVLine(x, prev_y[x], prev_h[x], 448 | WHITE); // Draw new lines 449 | } 450 | } 451 | 452 | // Continuously update the "PLAY" text and triangle icon during playback 453 | CoreS3.Display.fillTriangle(120 - 8, 15 - 8, 120 - 8, 15 + 8, 120 + 8, 454 | 15, 0x1c9f); 455 | CoreS3.Display.drawString("PLAY", 180, 15); 456 | } 457 | 458 | // End the playback 459 | CoreS3.Speaker.end(); 460 | CoreS3.Mic.begin(); // Re-enable the microphone 461 | CoreS3.Display.clear(); // Clear the display 462 | updateDisplay(wavFiles, selectedFileIndex); // Update the file display 463 | CoreS3.Display.endWrite(); 464 | } 465 | -------------------------------------------------------------------------------- /examples/Basic/power/power.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD 3 | * 4 | * SPDX-License-Identifier: MIT 5 | */ 6 | 7 | #include "M5CoreS3.h" 8 | 9 | void setup() 10 | { 11 | auto cfg = M5.config(); 12 | // if using ext power input(Grove Port or DC input power supply) needs to be set to false. 13 | // cfg.output_power = false; 14 | CoreS3.begin(cfg); 15 | CoreS3.Display.setTextSize(2); 16 | 17 | CoreS3.Power.setChargeCurrent(200); 18 | } 19 | 20 | void loop() 21 | { 22 | CoreS3.Display.clear(); 23 | 24 | bool bat_ischarging = CoreS3.Power.isCharging(); 25 | CoreS3.Display.setCursor(10, 30); 26 | CoreS3.Display.printf("Bat Charging: %d", bat_ischarging); 27 | 28 | int bat_vol = CoreS3.Power.getBatteryVoltage(); 29 | CoreS3.Display.setCursor(10, 50); 30 | CoreS3.Display.printf("Bat Voltage: %dmv", bat_vol); 31 | 32 | int bat_level = CoreS3.Power.getBatteryLevel(); 33 | CoreS3.Display.setCursor(10, 70); 34 | CoreS3.Display.printf("Bat Level: %d", bat_level); 35 | 36 | int vbus_vol = CoreS3.Power.getVBUSVoltage(); 37 | CoreS3.Display.setCursor(10, 90); 38 | CoreS3.Display.printf("VBus Voltage: %dmv", vbus_vol); 39 | delay(1000); 40 | } 41 | -------------------------------------------------------------------------------- /examples/Basic/rtc/rtc.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD 3 | * 4 | * SPDX-License-Identifier: MIT 5 | */ 6 | 7 | /* 8 | * @file rtc.ino 9 | * @author SeanKwok (shaoxiang@m5stack.com) 10 | * @brief M5CoreS3 RTC SNTP Test 11 | * @version 0.1 12 | * @date 2023-12-25 13 | * 14 | * 15 | * @Hardwares: M5CoreS3 16 | * @Platform Version: Arduino M5Stack Board Manager v2.0.9 17 | * @Dependent Library: 18 | * M5GFX: https://github.com/m5stack/M5GFX 19 | * M5Unified: https://github.com/m5stack/M5Unified 20 | * M5CoreS3: https://github.com/m5stack/M5CoreS3 21 | */ 22 | 23 | #if defined(ARDUINO) 24 | 25 | #define WIFI_SSID "YOUR WIFI SSID NAME" 26 | #define WIFI_PASSWORD "YOUR WIFI PASSWORD" 27 | #define NTP_TIMEZONE "UTC-8" 28 | #define NTP_SERVER1 "0.pool.ntp.org" 29 | #define NTP_SERVER2 "1.pool.ntp.org" 30 | #define NTP_SERVER3 "2.pool.ntp.org" 31 | 32 | #include 33 | 34 | // Different versions of the framework have different SNTP header file names and 35 | // availability. 36 | #if __has_include() 37 | #include 38 | #define SNTP_ENABLED 1 39 | #elif __has_include() 40 | #include 41 | #define SNTP_ENABLED 1 42 | #endif 43 | 44 | #endif 45 | 46 | #ifndef SNTP_ENABLED 47 | #define SNTP_ENABLED 0 48 | #endif 49 | 50 | #include 51 | 52 | void setup(void) { 53 | CoreS3.begin(); 54 | 55 | if (!CoreS3.Rtc.isEnabled()) { 56 | Serial.println("RTC not found."); 57 | for (;;) { 58 | vTaskDelay(500); 59 | } 60 | } 61 | 62 | Serial.println("RTC found."); 63 | 64 | // It is recommended to set UTC for the RTC and ESP32 internal clocks. 65 | /* /// setup RTC ( direct setting ) 66 | // YYYY MM DD hh mm ss 67 | CoreS3.Rtc.setDateTime( { { 2021, 12, 31 }, { 12, 34, 56 } } ); 68 | 69 | //*/ 70 | 71 | /// setup RTC ( NTP auto setting ) 72 | 73 | CoreS3.Display.println("WiFi Connecting..."); 74 | 75 | WiFi.begin(WIFI_SSID, WIFI_PASSWORD); 76 | while (WiFi.status() != WL_CONNECTED) { 77 | Serial.print('.'); 78 | delay(500); 79 | } 80 | CoreS3.Display.println("WiFi Connected."); 81 | Serial.println("\r\n WiFi Connected."); 82 | 83 | configTzTime(NTP_TIMEZONE, NTP_SERVER1, NTP_SERVER2, NTP_SERVER3); 84 | 85 | #if SNTP_ENABLED 86 | while (sntp_get_sync_status() != SNTP_SYNC_STATUS_COMPLETED) { 87 | Serial.print('.'); 88 | delay(1000); 89 | } 90 | Serial.println("\r\n NTP Connected."); 91 | CoreS3.Display.println("NTP Connected"); 92 | #else 93 | delay(1600); 94 | struct tm timeInfo; 95 | while (!getLocalTime(&timeInfo, 1000)) { 96 | Serial.print('.'); 97 | }; 98 | #endif 99 | 100 | time_t t = time(nullptr) + 1; // Advance one second. 101 | while (t > time(nullptr)); /// Synchronization in seconds 102 | CoreS3.Rtc.setDateTime(gmtime(&t)); 103 | CoreS3.Display.clear(); 104 | } 105 | 106 | void loop(void) { 107 | static constexpr const char* const wd[7] = {"Sun", "Mon", "Tue", "Wed", 108 | "Thr", "Fri", "Sat"}; 109 | 110 | delay(500); 111 | 112 | auto dt = CoreS3.Rtc.getDateTime(); 113 | Serial.printf("RTC UTC :%04d/%02d/%02d (%s) %02d:%02d:%02d\r\n", 114 | dt.date.year, dt.date.month, dt.date.date, 115 | wd[dt.date.weekDay], dt.time.hours, dt.time.minutes, 116 | dt.time.seconds); 117 | CoreS3.Display.setCursor(0, 0); 118 | CoreS3.Display.printf("RTC UTC :%04d/%02d/%02d (%s) %02d:%02d:%02d", 119 | dt.date.year, dt.date.month, dt.date.date, 120 | wd[dt.date.weekDay], dt.time.hours, dt.time.minutes, 121 | dt.time.seconds); 122 | 123 | /// ESP32 internal timer 124 | auto t = time(nullptr); 125 | { 126 | auto tm = gmtime(&t); // for UTC. 127 | Serial.printf("ESP32 UTC :%04d/%02d/%02d (%s) %02d:%02d:%02d\r\n", 128 | tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, 129 | wd[tm->tm_wday], tm->tm_hour, tm->tm_min, tm->tm_sec); 130 | CoreS3.Display.setCursor(0, 20); 131 | CoreS3.Display.printf("ESP32 UTC :%04d/%02d/%02d (%s) %02d:%02d:%02d", 132 | tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, 133 | wd[tm->tm_wday], tm->tm_hour, tm->tm_min, 134 | tm->tm_sec); 135 | } 136 | 137 | { 138 | auto tm = localtime(&t); // for local timezone. 139 | Serial.printf("ESP32 %s:%04d/%02d/%02d (%s) %02d:%02d:%02d\r\n", 140 | NTP_TIMEZONE, tm->tm_year + 1900, tm->tm_mon + 1, 141 | tm->tm_mday, wd[tm->tm_wday], tm->tm_hour, tm->tm_min, 142 | tm->tm_sec); 143 | CoreS3.Display.setCursor(0, 40); 144 | CoreS3.Display.printf("ESP32 %s:%04d/%02d/%02d (%s) %02d:%02d:%02d", 145 | NTP_TIMEZONE, tm->tm_year + 1900, tm->tm_mon + 1, 146 | tm->tm_mday, wd[tm->tm_wday], tm->tm_hour, 147 | tm->tm_min, tm->tm_sec); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /examples/Basic/sdcard/sdcard.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD 3 | * 4 | * SPDX-License-Identifier: MIT 5 | */ 6 | 7 | /* 8 | * @file sdcard.ino 9 | * @author SeanKwok (shaoxiang@m5stack.com) 10 | * @brief M5CoreS3 MicroSD Card Test 11 | * @version 0.1 12 | * @date 2023-12-25 13 | * 14 | * 15 | * @Hardwares: M5CoreS3 16 | * @Platform Version: Arduino M5Stack Board Manager v2.0.9 17 | * @Dependent Library: 18 | * M5GFX: https://github.com/m5stack/M5GFX 19 | * M5Unified: https://github.com/m5stack/M5Unified 20 | * M5CoreS3: https://github.com/m5stack/M5CoreS3 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #define SD_SPI_SCK_PIN 36 28 | #define SD_SPI_MISO_PIN 35 29 | #define SD_SPI_MOSI_PIN 37 30 | #define SD_SPI_CS_PIN 4 31 | 32 | void listDir(fs::FS &fs, const char *dirname, uint8_t levels); 33 | void createDir(fs::FS &fs, const char *path); 34 | void removeDir(fs::FS &fs, const char *path); 35 | void readFile(fs::FS &fs, const char *path); 36 | void writeFile(fs::FS &fs, const char *path, const char *message); 37 | void appendFile(fs::FS &fs, const char *path, const char *message); 38 | void renameFile(fs::FS &fs, const char *path1, const char *path2); 39 | void deleteFile(fs::FS &fs, const char *path); 40 | void testFileIO(fs::FS &fs, const char *path); 41 | 42 | M5Canvas canvas(&CoreS3.Display); 43 | 44 | void printf_log(const char *format, ...); 45 | void println_log(const char *str); 46 | 47 | void setup() { 48 | CoreS3.begin(); 49 | 50 | canvas.setColorDepth(1); // mono color 51 | canvas.createSprite(CoreS3.Display.width(), CoreS3.Display.height()); 52 | canvas.setPaletteColor(1, GREEN); 53 | canvas.setTextSize((float)canvas.width() / 160); 54 | canvas.setTextScroll(true); 55 | 56 | // SD Card Initialization 57 | SPI.begin(SD_SPI_SCK_PIN, SD_SPI_MISO_PIN, SD_SPI_MOSI_PIN, SD_SPI_CS_PIN); 58 | 59 | if (!SD.begin(SD_SPI_CS_PIN, SPI, 25000000)) { 60 | // Print a message if the SD card initialization 61 | // fails orif the SD card does not exist. 62 | // 如果SD卡初始化失败或者SD卡不存在,则打印消息. 63 | println_log("Card failed, or not present"); 64 | while (1); 65 | } 66 | 67 | uint8_t cardType = SD.cardType(); 68 | 69 | if (cardType == CARD_NONE) { 70 | println_log("No SD card attached"); 71 | return; 72 | } 73 | 74 | Serial.print("SD Card Type: "); 75 | if (cardType == CARD_MMC) { 76 | println_log("MMC"); 77 | } else if (cardType == CARD_SD) { 78 | println_log("SDSC"); 79 | } else if (cardType == CARD_SDHC) { 80 | println_log("SDHC"); 81 | } else { 82 | println_log("UNKNOWN"); 83 | } 84 | 85 | uint64_t cardSize = SD.cardSize() / (1024 * 1024); 86 | printf_log("SD Card Size: %lluMB\n", cardSize); 87 | 88 | listDir(SD, "/", 0); 89 | createDir(SD, "/mydir"); 90 | listDir(SD, "/", 0); 91 | removeDir(SD, "/mydir"); 92 | listDir(SD, "/", 2); 93 | writeFile(SD, "/hello.txt", "Hello "); 94 | appendFile(SD, "/hello.txt", "World!\n"); 95 | readFile(SD, "/hello.txt"); 96 | deleteFile(SD, "/foo.txt"); 97 | renameFile(SD, "/hello.txt", "/foo.txt"); 98 | readFile(SD, "/foo.txt"); 99 | testFileIO(SD, "/test.txt"); 100 | printf_log("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024)); 101 | printf_log("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024)); 102 | } 103 | void loop() { 104 | } 105 | 106 | void listDir(fs::FS &fs, const char *dirname, uint8_t levels) { 107 | printf_log("Listing directory: %s\n", dirname); 108 | 109 | File root = fs.open(dirname); 110 | if (!root) { 111 | println_log("Failed to open directory"); 112 | return; 113 | } 114 | if (!root.isDirectory()) { 115 | println_log("Not a directory"); 116 | return; 117 | } 118 | 119 | File file = root.openNextFile(); 120 | while (file) { 121 | if (file.isDirectory()) { 122 | Serial.print(" DIR : "); 123 | println_log(file.name()); 124 | if (levels) { 125 | listDir(fs, file.path(), levels - 1); 126 | } 127 | } else { 128 | Serial.print(" FILE: "); 129 | Serial.print(file.name()); 130 | Serial.print(" SIZE: "); 131 | println_log(String(file.size()).c_str()); 132 | } 133 | file = root.openNextFile(); 134 | } 135 | } 136 | 137 | void createDir(fs::FS &fs, const char *path) { 138 | printf_log("Creating Dir: %s\n", path); 139 | if (fs.mkdir(path)) { 140 | println_log("Dir created"); 141 | } else { 142 | println_log("mkdir failed"); 143 | } 144 | } 145 | 146 | void removeDir(fs::FS &fs, const char *path) { 147 | printf_log("Removing Dir: %s\n", path); 148 | if (fs.rmdir(path)) { 149 | println_log("Dir removed"); 150 | } else { 151 | println_log("rmdir failed"); 152 | } 153 | } 154 | 155 | void readFile(fs::FS &fs, const char *path) { 156 | printf_log("Reading file: %s\n", path); 157 | 158 | File file = fs.open(path); 159 | if (!file) { 160 | println_log("Failed to open file for reading"); 161 | return; 162 | } 163 | 164 | Serial.print("Read from file: "); 165 | while (file.available()) { 166 | Serial.write(file.read()); 167 | } 168 | file.close(); 169 | } 170 | 171 | void writeFile(fs::FS &fs, const char *path, const char *message) { 172 | printf_log("Writing file: %s\n", path); 173 | 174 | File file = fs.open(path, FILE_WRITE); 175 | if (!file) { 176 | println_log("Failed to open file for writing"); 177 | return; 178 | } 179 | if (file.print(message)) { 180 | println_log("File written"); 181 | } else { 182 | println_log("Write failed"); 183 | } 184 | file.close(); 185 | } 186 | 187 | void appendFile(fs::FS &fs, const char *path, const char *message) { 188 | printf_log("Appending to file: %s\n", path); 189 | 190 | File file = fs.open(path, FILE_APPEND); 191 | if (!file) { 192 | println_log("Failed to open file for appending"); 193 | return; 194 | } 195 | if (file.print(message)) { 196 | println_log("Message appended"); 197 | } else { 198 | println_log("Append failed"); 199 | } 200 | file.close(); 201 | } 202 | 203 | void renameFile(fs::FS &fs, const char *path1, const char *path2) { 204 | printf_log("Renaming file %s to %s\n", path1, path2); 205 | if (fs.rename(path1, path2)) { 206 | println_log("File renamed"); 207 | } else { 208 | println_log("Rename failed"); 209 | } 210 | } 211 | 212 | void deleteFile(fs::FS &fs, const char *path) { 213 | printf_log("Deleting file: %s\n", path); 214 | if (fs.remove(path)) { 215 | println_log("File deleted"); 216 | } else { 217 | println_log("Delete failed"); 218 | } 219 | } 220 | 221 | void testFileIO(fs::FS &fs, const char *path) { 222 | File file = fs.open(path); 223 | static uint8_t buf[512]; 224 | size_t len = 0; 225 | uint32_t start = millis(); 226 | uint32_t end = start; 227 | if (file) { 228 | len = file.size(); 229 | size_t flen = len; 230 | start = millis(); 231 | while (len) { 232 | size_t toRead = len; 233 | if (toRead > 512) { 234 | toRead = 512; 235 | } 236 | file.read(buf, toRead); 237 | len -= toRead; 238 | } 239 | end = millis() - start; 240 | printf_log("%u bytes read for %lu ms\n", flen, end); 241 | file.close(); 242 | } else { 243 | println_log("Failed to open file for reading"); 244 | } 245 | 246 | file = fs.open(path, FILE_WRITE); 247 | if (!file) { 248 | println_log("Failed to open file for writing"); 249 | return; 250 | } 251 | 252 | size_t i; 253 | start = millis(); 254 | for (i = 0; i < 2048; i++) { 255 | file.write(buf, 512); 256 | } 257 | end = millis() - start; 258 | printf_log("%u bytes written for %lu ms\n", 2048 * 512, end); 259 | file.close(); 260 | } 261 | 262 | void printf_log(const char *format, ...) { 263 | char buf[256]; 264 | va_list args; 265 | va_start(args, format); 266 | vsnprintf(buf, 256, format, args); 267 | va_end(args); 268 | Serial.print(buf); 269 | canvas.printf(buf); 270 | canvas.pushSprite(0, 0); 271 | } 272 | 273 | void println_log(const char *str) { 274 | Serial.println(str); 275 | canvas.println(str); 276 | canvas.pushSprite(0, 0); 277 | } 278 | -------------------------------------------------------------------------------- /examples/Basic/speaker/speaker.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD 3 | * 4 | * SPDX-License-Identifier: MIT 5 | */ 6 | 7 | /* 8 | * @file speaker.ino 9 | * @author SeanKwok (shaoxiang@m5stack.com) 10 | * @brief M5CoreS3 Speaker Test 11 | * @version 0.1 12 | * @date 2023-12-25 13 | * 14 | * 15 | * @Hardwares: M5CoreS3 16 | * @Platform Version: Arduino M5Stack Board Manager v2.0.9 17 | * @Dependent Library: 18 | * M5GFX: https://github.com/m5stack/M5GFX 19 | * M5Unified: https://github.com/m5stack/M5Unified 20 | * M5CoreS3: https://github.com/m5stack/M5CoreS3 21 | */ 22 | 23 | #include 24 | #include "audio_file.h" 25 | 26 | //---------------------------------------------------------------- 27 | 28 | /// 8bit unsigned 44.1kHz mono (exclude wav header) 29 | extern const uint8_t wav_unsigned_8bit_click[46000]; 30 | 31 | /// wav data (include wav header) 32 | extern const uint8_t wav_with_header[230432]; 33 | 34 | static int menu_x = 2; 35 | static int menu_y = 20; 36 | static int menu_w = 120; 37 | static int menu_h = 30; 38 | static int menu_padding = 36; 39 | 40 | static void tone_up(bool holding) { 41 | static int tone_hz; 42 | if (!holding) { 43 | tone_hz = 100; 44 | } 45 | CoreS3.Speaker.tone(++tone_hz, 1000, 1); 46 | } 47 | 48 | static void bgm_play_stop(bool holding = false) { 49 | if (holding) { 50 | return; 51 | } 52 | if (CoreS3.Speaker.isPlaying(0)) { 53 | CoreS3.Speaker.stop(0); 54 | } else { 55 | CoreS3.Speaker.playWav(wav_with_header, sizeof(wav_with_header), ~0u, 0, 56 | true); 57 | } 58 | } 59 | 60 | static void m_volume_up(bool) { 61 | int v = CoreS3.Speaker.getVolume() + 1; 62 | if (v < 256) { 63 | CoreS3.Speaker.setVolume(v); 64 | } 65 | } 66 | 67 | static void m_volume_down(bool) { 68 | int v = CoreS3.Speaker.getVolume() - 1; 69 | if (v >= 0) { 70 | CoreS3.Speaker.setVolume(v); 71 | } 72 | } 73 | 74 | static void c_volume_up(bool) { 75 | int v = CoreS3.Speaker.getChannelVolume(0) + 1; 76 | if (v < 256) { 77 | CoreS3.Speaker.setChannelVolume(0, v); 78 | } 79 | } 80 | 81 | static void c_volume_down(bool) { 82 | int v = CoreS3.Speaker.getChannelVolume(0) - 1; 83 | if (v >= 0) { 84 | CoreS3.Speaker.setChannelVolume(0, v); 85 | } 86 | } 87 | 88 | struct menu_item_t { 89 | const char* title; 90 | void (*func)(bool); 91 | }; 92 | 93 | static const menu_item_t menus[] = { 94 | {"tone", tone_up}, {"play/stop", bgm_play_stop}, 95 | {"ms vol u", m_volume_up}, {"ms vol d", m_volume_down}, 96 | {"ch vol u", c_volume_up}, {"ch vol d", c_volume_down}, 97 | }; 98 | static constexpr const size_t menu_count = sizeof(menus) / sizeof(menus[0]); 99 | 100 | size_t cursor_index = 0; 101 | 102 | void draw_menu(size_t index, bool focus) { 103 | CoreS3.Display.startWrite(); 104 | auto baseColor = CoreS3.Display.getBaseColor(); 105 | CoreS3.Display.setColor(focus ? baseColor : ~baseColor); 106 | CoreS3.Display.drawRect(menu_x, menu_y + index * menu_padding, menu_w, 107 | menu_h); 108 | CoreS3.Display.drawRect(menu_x + 1, menu_y + index * menu_padding + 1, 109 | menu_w - 2, menu_h - 2); 110 | CoreS3.Display.setColor(focus ? ~baseColor : baseColor); 111 | CoreS3.Display.fillRect(menu_x + 2, menu_y + index * menu_padding + 2, 112 | menu_w - 4, menu_h - 4); 113 | CoreS3.Display.setTextDatum(textdatum_t::middle_center); 114 | CoreS3.Display.setTextColor(focus ? baseColor : ~baseColor, 115 | focus ? ~baseColor : baseColor); 116 | CoreS3.Display.drawString(menus[index].title, menu_x + (menu_w >> 1), 117 | menu_y + index * menu_padding + (menu_h >> 1)); 118 | CoreS3.Display.endWrite(); 119 | } 120 | 121 | void select_menu(size_t index) { 122 | CoreS3.Speaker.playRaw( 123 | wav_unsigned_8bit_click, 124 | sizeof(wav_unsigned_8bit_click) / sizeof(wav_unsigned_8bit_click[0]), 125 | 44100, false); 126 | CoreS3.Display.startWrite(); 127 | draw_menu(cursor_index, false); 128 | cursor_index = index; 129 | draw_menu(cursor_index, true); 130 | CoreS3.Display.endWrite(); 131 | } 132 | 133 | void move_menu(bool back = false) { 134 | if (back) { 135 | select_menu((cursor_index ? cursor_index : menu_count) - 1); 136 | } else { 137 | select_menu((cursor_index + 1) % menu_count); 138 | } 139 | } 140 | 141 | void hold_menu(bool holding) { 142 | if (menus[cursor_index].func != nullptr) { 143 | menus[cursor_index].func(holding); 144 | } 145 | } 146 | 147 | void setup(void) { 148 | auto cfg = M5.config(); 149 | 150 | CoreS3.begin(cfg); 151 | 152 | { /// I2S Custom configurations are available if you desire. 153 | auto spk_cfg = CoreS3.Speaker.config(); 154 | 155 | if (spk_cfg.use_dac || spk_cfg.buzzer) { 156 | /// Increasing the sample_rate will improve the sound quality 157 | /// instead of increasing the CPU load. 158 | spk_cfg.sample_rate = 159 | 192000; // default:64000 (64kHz) e.g. 48000 , 50000 , 80000 , 160 | // 96000 , 100000 , 128000 , 144000 , 192000 , 200000 161 | } 162 | /* 163 | spk_cfg.pin_data_out=8; 164 | spk_cfg.pin_bck=7; 165 | spk_cfg.pin_ws=10; // LRCK 166 | 167 | /// use single gpio buzzer, ( need only pin_data_out ) 168 | spk_cfg.buzzer = false; 169 | 170 | /// use DAC speaker, ( need only pin_data_out ) ( only GPIO_NUM_25 171 | or GPIO_NUM_26 ) spk_cfg.use_dac = false; 172 | // spk_cfg.dac_zero_level = 64; // for Unit buzzer with DAC. 173 | 174 | /// Volume Multiplier 175 | spk_cfg.magnification = 16; 176 | //*/ 177 | CoreS3.Speaker.config(spk_cfg); 178 | } 179 | CoreS3.Speaker.begin(); 180 | 181 | if (CoreS3.Display.width() > CoreS3.Display.height()) { 182 | CoreS3.Display.setRotation(CoreS3.Display.getRotation() ^ 1); 183 | } 184 | 185 | if (CoreS3.Display.width() < 100) { 186 | menu_x = 0; 187 | menu_y = 10; 188 | menu_w = CoreS3.Display.width() - 8; 189 | } else { 190 | CoreS3.Display.setFont(&fonts::DejaVu18); 191 | } 192 | menu_padding = (CoreS3.Display.height() - menu_y) / menu_count; 193 | menu_h = menu_padding - 2; 194 | 195 | if (!CoreS3.Speaker.isEnabled()) { 196 | CoreS3.Display.print("Speaker not found..."); 197 | for (;;) { 198 | CoreS3.delay(1); 199 | } 200 | } 201 | 202 | CoreS3.Display.setEpdMode(epd_mode_t::epd_fastest); 203 | CoreS3.Display.fillScreen(TFT_DARKGRAY); 204 | CoreS3.Display.print("SOUND TEST"); 205 | 206 | /// The setVolume function can be set the master volume in the range of 207 | /// 0-255. (default : 64) 208 | CoreS3.Speaker.setVolume(64); 209 | 210 | /// The setAllChannelVolume function can be set the all virtual channel 211 | /// volume in the range of 0-255. (default : 255) 212 | CoreS3.Speaker.setAllChannelVolume(255); 213 | 214 | /// The setChannelVolume function can be set the specified virtual channel 215 | /// volume in the range of 0-255. (default : 255) 216 | CoreS3.Speaker.setChannelVolume(0, 255); 217 | 218 | /// play 2000Hz tone sound, 100 msec. 219 | CoreS3.Speaker.tone(2000, 100); 220 | 221 | CoreS3.delay(100); 222 | 223 | /// play 1000Hz tone sound, 100 msec. 224 | CoreS3.Speaker.tone(1000, 100); 225 | 226 | CoreS3.delay(100); 227 | 228 | /// stop output sound. 229 | CoreS3.Speaker.stop(); 230 | 231 | CoreS3.delay(500); 232 | 233 | /// The playRaw function can play raw wave data. 234 | /// 1st argument : data pointer, (supported int8_t / uint8_t / int16_t) 235 | /// 2nd argument : Number of data array elements. 236 | /// 3rd argument : the sampling rate (Hz) (default = 44100) 237 | /// 4th argument : true=stereo / false=monaural (default = false) 238 | /// 5th argument : repeat count (default = 1) 239 | /// 6th argument : virtual channel number (If omitted, use an available 240 | /// channel.) 241 | CoreS3.Speaker.playRaw( 242 | wav_unsigned_8bit_click, 243 | sizeof(wav_unsigned_8bit_click) / sizeof(wav_unsigned_8bit_click[0]), 244 | 44100, false); 245 | 246 | while (CoreS3.Speaker.isPlaying()) { 247 | CoreS3.delay(1); 248 | } // Wait for the output to finish. 249 | 250 | CoreS3.delay(500); 251 | 252 | // The 2nd argument of the tone function can be used to specify the output 253 | // time (milliseconds). 254 | CoreS3.Speaker.tone(440, 1000); // 440Hz sound output for 1 seconds. 255 | 256 | while (CoreS3.Speaker.isPlaying()) { 257 | CoreS3.delay(1); 258 | } // Wait for the output to finish. 259 | 260 | CoreS3.delay(500); 261 | 262 | CoreS3.Speaker.setVolume(0); 263 | CoreS3.Speaker.tone( 264 | 880); // tone 880Hz sound output. (Keeps output until it stops.) 265 | for (int i = 0; i <= 64; i++) { 266 | CoreS3.Speaker.setVolume( 267 | i); // Volume can be changed during sound output. 268 | CoreS3.delay(25); 269 | } 270 | CoreS3.Speaker.stop(); // stop sound output. 271 | 272 | CoreS3.delay(500); 273 | 274 | // The tone function can specify a virtual channel number as its 3rd 275 | // argument. If the tone function is used on the same channel number, the 276 | // previous tone will be stopped and a new tone will be played. 277 | CoreS3.Speaker.tone( 278 | 261.626, 1000, 279 | 1); // tone 261.626Hz output for 1 seconds, use channel 1 280 | CoreS3.delay(200); 281 | CoreS3.Speaker.tone( 282 | 329.628, 1000, 283 | 1); // tone 329.628Hz output for 1 seconds, use channel 1 284 | CoreS3.delay(200); 285 | CoreS3.Speaker.tone( 286 | 391.995, 1000, 287 | 1); // tone 391.995Hz output for 1 seconds, use channel 1 288 | 289 | while (CoreS3.Speaker.isPlaying()) { 290 | CoreS3.delay(1); 291 | } // Wait for the output to finish. 292 | 293 | CoreS3.delay(500); 294 | 295 | // By specifying different channels, multiple sounds can be output 296 | // simultaneously. 297 | CoreS3.Speaker.tone( 298 | 261.626, 1000, 299 | 1); // tone 261.626Hz output for 1 seconds, use channel 1 300 | CoreS3.delay(200); 301 | CoreS3.Speaker.tone( 302 | 329.628, 1000, 303 | 2); // tone 329.628Hz output for 1 seconds, use channel 2 304 | CoreS3.delay(200); 305 | CoreS3.Speaker.tone( 306 | 391.995, 1000, 307 | 3); // tone 391.995Hz output for 1 seconds, use channel 3 308 | 309 | while (CoreS3.Speaker.isPlaying()) { 310 | CoreS3.delay(1); 311 | } // Wait for the output to finish. 312 | 313 | CoreS3.delay(500); 314 | 315 | /// tone data (8bit unsigned wav) 316 | const uint8_t wavdata[64] = { 317 | 132, 138, 143, 154, 151, 139, 138, 140, 144, 147, 147, 147, 151, 318 | 159, 184, 194, 203, 222, 228, 227, 210, 202, 197, 181, 172, 169, 319 | 177, 178, 172, 151, 141, 131, 107, 96, 87, 77, 73, 66, 42, 320 | 28, 17, 10, 15, 25, 55, 68, 76, 82, 80, 74, 61, 66, 321 | 79, 107, 109, 103, 81, 73, 86, 94, 99, 112, 121, 129}; 322 | 323 | /// Using a single wave of data, you can change the tone. 324 | CoreS3.Speaker.tone(261.626, 1000, 1, true, wavdata, sizeof(wavdata)); 325 | CoreS3.delay(200); 326 | CoreS3.Speaker.tone(329.628, 1000, 2, true, wavdata, sizeof(wavdata)); 327 | CoreS3.delay(200); 328 | CoreS3.Speaker.tone(391.995, 1000, 3, true, wavdata, sizeof(wavdata)); 329 | CoreS3.delay(200); 330 | 331 | while (CoreS3.Speaker.isPlaying()) { 332 | CoreS3.delay(1); 333 | } // Wait for the output to finish. 334 | 335 | CoreS3.Display.startWrite(); 336 | for (size_t i = 0; i < menu_count; i++) { 337 | draw_menu(i, i == cursor_index); 338 | } 339 | CoreS3.Display.endWrite(); 340 | 341 | bgm_play_stop(false); 342 | } 343 | 344 | void loop(void) { 345 | if (!CoreS3.Display.displayBusy()) { 346 | static int32_t prev_channelvolume; 347 | static int32_t prev_mastervolume; 348 | int32_t m_vol = 349 | (CoreS3.Speaker.getVolume() * (CoreS3.Display.height() - menu_y)) >> 350 | 8; 351 | int32_t c_vol = (CoreS3.Speaker.getChannelVolume(0) * 352 | (CoreS3.Display.height() - menu_y)) >> 353 | 8; 354 | if (prev_mastervolume != m_vol || prev_channelvolume != c_vol) { 355 | int32_t b = (255 * (CoreS3.Display.height() - menu_y)) >> 8; 356 | prev_mastervolume = m_vol; 357 | prev_channelvolume = c_vol; 358 | CoreS3.Display.startWrite(); 359 | CoreS3.Display.fillRect(menu_x + menu_w + 1, menu_y, 3, b - m_vol, 360 | CoreS3.Display.getBaseColor()); 361 | CoreS3.Display.fillRect(menu_x + menu_w + 5, menu_y, 3, b - c_vol, 362 | CoreS3.Display.getBaseColor()); 363 | CoreS3.Display.fillRect(menu_x + menu_w + 1, menu_y + b, 3, -m_vol, 364 | ~CoreS3.Display.getBaseColor()); 365 | CoreS3.Display.fillRect(menu_x + menu_w + 5, menu_y + b, 3, -c_vol, 366 | ~CoreS3.Display.getBaseColor()); 367 | CoreS3.Display.endWrite(); 368 | } 369 | } 370 | 371 | CoreS3.delay(5); 372 | CoreS3.update(); 373 | 374 | auto touch_count = CoreS3.Touch.getCount(); 375 | for (size_t i = 0; i < touch_count; i++) { 376 | auto detail = CoreS3.Touch.getDetail(i); 377 | if (((size_t)detail.x - menu_x) < menu_w) { 378 | size_t index = (detail.y - menu_y) / menu_padding; 379 | if (index < menu_count) { 380 | if (detail.wasPressed()) { 381 | select_menu(index); 382 | } else if (index == cursor_index) { 383 | if (detail.wasClicked()) { 384 | hold_menu(false); 385 | } else if (detail.isHolding()) { 386 | hold_menu(true); 387 | } 388 | } 389 | } 390 | } 391 | } 392 | } 393 | -------------------------------------------------------------------------------- /examples/Basic/touch/touch.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD 3 | * 4 | * SPDX-License-Identifier: MIT 5 | */ 6 | 7 | /* 8 | * @file touch.ino 9 | * @author SeanKwok (shaoxiang@m5stack.com) 10 | * @brief M5CoreS3 Touch Test 11 | * @version 0.1 12 | * @date 2023-12-25 13 | * 14 | * 15 | * @Hardwares: M5CoreS3 16 | * @Platform Version: Arduino M5Stack Board Manager v2.0.9 17 | * @Dependent Library: 18 | * M5GFX: https://github.com/m5stack/M5GFX 19 | * M5Unified: https://github.com/m5stack/M5Unified 20 | * M5CoreS3: https://github.com/m5stack/M5CoreS3 21 | */ 22 | 23 | #include 24 | 25 | void setup(void) { 26 | auto cfg = M5.config(); 27 | CoreS3.begin(cfg); 28 | 29 | CoreS3.Display.setTextColor(GREEN); 30 | CoreS3.Display.setTextDatum(middle_center); 31 | CoreS3.Display.setFont(&fonts::Orbitron_Light_24); 32 | CoreS3.Display.setTextSize(1); 33 | 34 | CoreS3.Display.drawString("Touch Test", CoreS3.Display.width() / 2, 35 | CoreS3.Display.height() / 2); 36 | } 37 | 38 | int prev_x = -1; 39 | int prev_y = -1; 40 | 41 | static m5::touch_state_t prev_state; 42 | 43 | void loop(void) { 44 | CoreS3.update(); 45 | 46 | auto t = CoreS3.Touch.getDetail(); 47 | if (prev_state != t.state) { 48 | prev_state = t.state; 49 | static constexpr const char* state_name[16] = { 50 | "none", "touch", "touch_end", "touch_begin", 51 | "___", "hold", "hold_end", "hold_begin", 52 | "___", "flick", "flick_end", "flick_begin", 53 | "___", "drag", "drag_end", "drag_begin"}; 54 | M5_LOGI("%s", state_name[t.state]); 55 | CoreS3.Display.fillRect(0, 0, CoreS3.Display.width(), 140, BLACK); 56 | 57 | CoreS3.Display.drawString(state_name[t.state], 58 | CoreS3.Display.width() / 2, 59 | CoreS3.Display.height() / 2 - 30); 60 | } 61 | if (prev_x != t.x || prev_y != t.y) { 62 | CoreS3.Display.fillRect(0, 140, CoreS3.Display.width(), 100, BLACK); 63 | CoreS3.Display.drawString( 64 | "X:" + String(t.x) + " / " + "Y:" + String(t.y), 65 | CoreS3.Display.width() / 2, 200); 66 | prev_x = t.x; 67 | prev_y = t.y; 68 | CoreS3.Display.fillCircle(prev_x, prev_y, 4, GREEN); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /examples/Basic/wakeup/wakeup.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD 3 | * 4 | * SPDX-License-Identifier: MIT 5 | */ 6 | 7 | /* 8 | * @file wakeup.ino 9 | * @author SeanKwok (shaoxiang@m5stack.com) 10 | * @brief M5CoreS3 Timer Wakeup Test 11 | * @version 0.1 12 | * @date 2023-12-25 13 | * 14 | * 15 | * @Hardwares: M5CoreS3 16 | * @Platform Version: Arduino M5Stack Board Manager v2.0.9 17 | * @Dependent Library: 18 | * M5GFX: https://github.com/m5stack/M5GFX 19 | * M5Unified: https://github.com/m5stack/M5Unified 20 | * M5CoreS3: https://github.com/m5stack/M5CoreS3 21 | */ 22 | 23 | #include 24 | 25 | void setup(void) { 26 | auto cfg = M5.config(); 27 | CoreS3.begin(cfg); 28 | 29 | CoreS3.Display.setTextColor(GREEN); 30 | CoreS3.Display.setTextDatum(middle_center); 31 | CoreS3.Display.setFont(&fonts::FreeSerifItalic18pt7b); 32 | CoreS3.Display.setTextSize(1); 33 | 34 | CoreS3.Display.drawString("Touch", CoreS3.Display.width() / 2, 35 | CoreS3.Display.height() / 2 - 60); 36 | CoreS3.Display.drawString("to sleep", CoreS3.Display.width() / 2, 37 | CoreS3.Display.height() / 2 - 20); 38 | CoreS3.Display.drawString("After 5s", CoreS3.Display.width() / 2, 39 | CoreS3.Display.height() / 2 + 20); 40 | CoreS3.Display.drawString("Wakeup", CoreS3.Display.width() / 2, 41 | CoreS3.Display.height() / 2 + 60); 42 | } 43 | 44 | void loop(void) { 45 | CoreS3.update(); 46 | 47 | if (CoreS3.Touch.getCount() && CoreS3.Touch.getDetail(0).wasClicked()) { 48 | CoreS3.Power.timerSleep(5); 49 | // CoreS3.Power.timerSleep(const rtc_time_t& time); 50 | // CoreS3.Power.timerSleep(const rtc_date_t& date, const rtc_time_t& 51 | // time); 52 | // CoreS3.Power.powerOff(); shutdown 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /examples/Module/4EncoderMotor/4EncoderMotor.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * @file DriverSample.ino 3 | * @author SeanKwok (shaoxiang@m5stack.com) 4 | * @brief Module 4EncoderMotor Test Demo. 5 | * @version 0.1 6 | * @date 2024-01-19 7 | * 8 | * 9 | * @Hardwares: M5CoreS3 + Module 4EncoderMotor 10 | * @Platform Version: Arduino M5Stack Board Manager v2.1.0 11 | * @Dependent Library: 12 | * M5Unified: https://github.com/m5stack/M5Unified 13 | * M5GFX: https://github.com/m5stack/M5GFX 14 | * M5Module4EncoderMotor: https://github.com/m5stack/M5Module-4EncoderMotor 15 | */ 16 | 17 | #include "M5Unified.h" 18 | #include "M5GFX.h" 19 | #include "M5Module4EncoderMotor.h" 20 | 21 | M5Module4EncoderMotor driver; 22 | 23 | #define MAX_RECORD_SIZE 256 24 | 25 | float amp_record[MAX_RECORD_SIZE] = {0}; 26 | uint8_t record_index = 0; 27 | float amp_value = 0.0f; 28 | 29 | uint8_t avg_filter_level = 20; 30 | 31 | float avg_filter(float *data, int len) { 32 | float sum = 0; 33 | float min = data[0]; 34 | float max = data[0]; 35 | for (int i = 0; i < len; i++) { 36 | if (data[i] < min) { 37 | min = data[i]; 38 | } 39 | if (data[i] > max) { 40 | max = data[i]; 41 | } 42 | sum += data[i]; 43 | } 44 | sum -= min; 45 | sum -= max; 46 | return sum / (len - 2); 47 | } 48 | 49 | void setup() { 50 | M5.begin(); 51 | M5.Display.begin(); 52 | 53 | M5.Display.setTextColor(WHITE); 54 | M5.Display.setTextDatum(top_center); 55 | M5.Display.setFont(&fonts::FreeSansBold12pt7b); 56 | M5.Display.setTextSize(1); 57 | 58 | while (!driver.begin(&Wire1, MODULE_4ENCODERMOTOR_ADDR, 11, 12)) { 59 | Serial.println("Driver Init faild!"); 60 | M5.Display.drawString("Driver Init faild!", 160, 7); 61 | delay(1000); 62 | } 63 | 64 | Serial.println("Driver Init success!"); 65 | M5.Display.clear(); 66 | M5.Display.fillRect(0, 0, 320, 35, 0x27f); 67 | M5.Display.drawString("4Encoder Motor", 160, 7); 68 | M5.Display.setTextDatum(top_left); 69 | 70 | // motor channel 0 -3 71 | for (uint8_t i = 0; i < 4; i++) { 72 | driver.setMode(i, NORMAL_MODE); 73 | driver.setMotorSpeed(i, 127); 74 | } 75 | M5.Display.drawString("NORMAL MODE", 20, 40 + 35 * 5); 76 | } 77 | 78 | bool direction = true; 79 | int mode = NORMAL_MODE; 80 | 81 | void loop() { 82 | M5.update(); 83 | for (uint8_t i = 0; i < 4; i++) { 84 | M5.Display.fillRect(20, 40 + 35 * i, 300, 35, BLACK); 85 | int32_t encoder_value = driver.getEncoderValue(i); 86 | M5.Display.drawString("CH" + String(i) + ": " + String(encoder_value), 87 | 20, 40 + 35 * i); 88 | } 89 | 90 | if (avg_filter_level != 0) { 91 | amp_record[record_index] = driver.getMotorCurrent(); 92 | record_index++; 93 | if (record_index >= avg_filter_level) { 94 | record_index = 0; 95 | } 96 | amp_value = avg_filter(amp_record, avg_filter_level); 97 | } 98 | 99 | float voltage = driver.getAnalogInput(_8bit) / 255.0 * 3.3 / 0.16; 100 | float current = amp_value; 101 | 102 | M5.Display.fillRect(20, 40 + 35 * 4, 300, 35, BLACK); 103 | M5.Display.drawString( 104 | "POWER: " + String(voltage) + "V/" + String(current) + "A", 20, 105 | 40 + 35 * 4); 106 | 107 | if (M5.BtnA.wasClicked() || 108 | (M5.Touch.getCount() && M5.Touch.getDetail(0).wasClicked())) { 109 | mode++; 110 | if (mode > SPEED_MODE) { 111 | mode = NORMAL_MODE; 112 | } 113 | M5.Display.fillRect(20, 40 + 35 * 5, 300, 35, BLACK); 114 | 115 | switch (mode) { 116 | case NORMAL_MODE: { 117 | M5.Display.drawString("NORMAL MODE", 20, 40 + 35 * 5); 118 | // motor channel 0 -3 NORMAL_MODE 119 | for (uint8_t i = 0; i < 4; i++) { 120 | driver.setMode(i, NORMAL_MODE); 121 | driver.setMotorSpeed(i, 127); 122 | } 123 | break; 124 | } 125 | case POSITION_MODE: { 126 | M5.Display.drawString("POSITION MODE", 20, 40 + 35 * 5); 127 | // motor channel 0 -3 POSITION_MODE 128 | 129 | for (uint8_t i = 0; i < 4; i++) { 130 | driver.setMode(i, POSITION_MODE); 131 | driver.setEncoderValue(i, 0); 132 | driver.setPostionPIDMaxSpeed(i, 127); 133 | driver.setPositionPoint(i, 1000); 134 | } 135 | break; 136 | } 137 | case SPEED_MODE: { 138 | M5.Display.drawString("SPEED MODE", 20, 40 + 35 * 5); 139 | // motor channel 0 -3 SPEED_MODE 140 | for (uint8_t i = 0; i < 4; i++) { 141 | driver.setMode(i, SPEED_MODE); 142 | driver.setSpeedPoint(i, 127); 143 | } 144 | break; 145 | } 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /examples/Unit/DAC2_GP8413/DAC2_GP8413.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * @file DAC2_GP8413.ino 3 | * @author SeanKwok (shaoxiang@m5stack.com) 4 | * @brief CoreS3 Unit DAC2 Test 5 | * @version 0.1 6 | * @date 2024-01-09 7 | * 8 | * 9 | * @Hardwares: CoreS3 + Unit DAC2(GP8413) 10 | * @Platform Version: Arduino M5Stack Board Manager v2.0.9 11 | * @Dependent Library: 12 | * M5GFX: https://github.com/m5stack/M5GFX 13 | * M5Unified: https://github.com/m5stack/M5Unified 14 | * DFRobot_GP8XXX: https://github.com/DFRobot/DFRobot_GP8XXX 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | DFRobot_GP8XXX_IIC GP8413(RESOLUTION_15_BIT, 0x59, &Wire); 21 | 22 | // range is 0~10000mv 23 | void setDacVoltage(uint16_t vol, uint8_t ch) { 24 | uint16_t setting_vol = 0; 25 | if (vol > 10000) { 26 | vol = 10000; 27 | } 28 | if (ch > 1) ch = 1; 29 | setting_vol = (int16_t)((float)vol / 10000.0f * 32767.0f); 30 | if (setting_vol > 32767) { 31 | setting_vol = 32767; 32 | } 33 | GP8413.setDACOutVoltage(setting_vol, ch); 34 | } 35 | 36 | void AllOutputCtl(uint16_t vol) { 37 | CoreS3.Display.fillRect(0, 0, CoreS3.Display.width(), 30, 38 | vol > 0 ? GREEN : ORANGE); 39 | CoreS3.Display.drawString("OUTPUT " + String(vol) + "mv", 40 | CoreS3.Display.width() / 2, 0); 41 | // set channel0 42 | setDacVoltage(vol, 0); 43 | // set channel1 44 | setDacVoltage(vol, 1); 45 | } 46 | 47 | void setup(void) { 48 | auto cfg = M5.config(); 49 | 50 | CoreS3.begin(cfg); 51 | CoreS3.Display.setRotation(1); 52 | CoreS3.Display.setTextDatum(top_center); 53 | CoreS3.Display.setTextColor(WHITE); 54 | CoreS3.Display.setFont(&fonts::FreeSansBoldOblique12pt7b); 55 | CoreS3.Display.setTextSize(1); 56 | CoreS3.Display.drawString("DAC2", CoreS3.Display.width() / 2, 57 | CoreS3.Display.height() / 2 - 20); 58 | Wire.end(); 59 | Wire.begin(2, 1); 60 | 61 | while (GP8413.begin() != 0) { 62 | Serial.println("Init Fail!"); 63 | CoreS3.Display.drawString("Init Fail!", CoreS3.Display.width() / 2, 64 | CoreS3.Display.height() / 2); 65 | delay(1000); 66 | } 67 | CoreS3.Display.clear(); 68 | CoreS3.Display.drawString("DAC2", CoreS3.Display.width() / 2, 69 | CoreS3.Display.height() / 2 - 20); 70 | GP8413.setDACOutRange(GP8413.eOutputRange10V); 71 | CoreS3.Display.drawString("BtnA En/Dis Output", CoreS3.Display.width() / 2, 72 | CoreS3.Display.height() / 2 + 20); 73 | 74 | AllOutputCtl(0); 75 | } 76 | 77 | bool output = false; 78 | 79 | void loop(void) { 80 | CoreS3.update(); 81 | if (CoreS3.Touch.getCount() && CoreS3.Touch.getDetail().wasPressed()) { 82 | output = !output; 83 | if (output) { 84 | AllOutputCtl(3300); 85 | // AllOutputCtl(10000); 86 | } else { 87 | AllOutputCtl(0); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /examples/Unit/MiniCAN_TJA1051T/Master/Master.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Slave.ino 3 | * @author SeanKwok (shaoxiang@m5stack.com) 4 | * @brief Unit Mini CAN Test Master 5 | * @version 0.1 6 | * @date 2024-02-01 7 | * 8 | * 9 | * @Hardwares: M5CoreS3 + Unit Mini CAN 10 | * @Platform Version: Arduino M5Stack Board Manager v2.0.9 11 | * @Dependent Library: 12 | * M5GFX: https://github.com/m5stack/M5GFX 13 | * M5Unified: https://github.com/m5stack/M5Unified 14 | * M5CoreS3: https://github.com/m5stack/M5CoreS3 15 | */ 16 | 17 | #include 18 | #include 19 | #include "freertos/FreeRTOS.h" 20 | #include "freertos/task.h" 21 | #include "freertos/queue.h" 22 | #include "freertos/semphr.h" 23 | #include "esp_err.h" 24 | #include "esp_log.h" 25 | #include "driver/twai.h" 26 | #include "esp_err.h" 27 | 28 | #include "M5CoreS3.h" 29 | 30 | M5Canvas canvas(&CoreS3.Display); 31 | 32 | /* --------------------- Definitions and static variables ------------------ */ 33 | 34 | #define TX_TASK_PRIO 8 // Receiving task priority 35 | #define TX_GPIO_NUM gpio_num_t(9) 36 | #define RX_GPIO_NUM gpio_num_t(8) 37 | 38 | static const twai_general_config_t g_config = 39 | TWAI_GENERAL_CONFIG_DEFAULT(TX_GPIO_NUM, RX_GPIO_NUM, TWAI_MODE_NORMAL); 40 | static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_25KBITS(); 41 | static const twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL(); 42 | 43 | #define ID_SLAVE_1 0x0B1 44 | 45 | static const twai_message_t slave_1_on = {.identifier = ID_SLAVE_1, 46 | .data_length_code = 8, 47 | .data = {1, 2, 3, 4, 5, 6, 7, 8}}; 48 | 49 | static const twai_message_t slave_1_off = {.identifier = ID_SLAVE_1, 50 | .data_length_code = 8, 51 | .data = {0, 0, 0, 0, 0, 0, 0, 0}}; 52 | 53 | static void twai_transmit_task(void *arg) { 54 | while (1) { 55 | twai_transmit(&slave_1_on, portMAX_DELAY); 56 | 57 | Serial.printf("send cmd on to 0x%02X\r\n", ID_SLAVE_1); 58 | Serial.print("send data: "); 59 | canvas.printf("send cmd on to 0x%02X\r\n", ID_SLAVE_1); 60 | canvas.print("send data: "); 61 | for (int i = 0; i < slave_1_on.data_length_code; i++) { 62 | Serial.printf("0x%02X ", slave_1_on.data[i]); 63 | canvas.printf("0x%02X ", slave_1_on.data[i]); 64 | } 65 | Serial.println(); 66 | canvas.println("\r\n"); 67 | canvas.pushSprite(0, 0); 68 | vTaskDelay(pdMS_TO_TICKS(1000)); 69 | 70 | twai_transmit(&slave_1_off, portMAX_DELAY); 71 | Serial.printf("send cmd off to 0x%02X\r\n", ID_SLAVE_1); 72 | Serial.print("send data: "); 73 | canvas.printf("send cmd off to 0x%02X\r\n", ID_SLAVE_1); 74 | canvas.print("send data: "); 75 | for (int i = 0; i < slave_1_off.data_length_code; i++) { 76 | Serial.printf("0x%02X ", slave_1_off.data[i]); 77 | canvas.printf("0x%02X ", slave_1_on.data[i]); 78 | } 79 | Serial.println(); 80 | canvas.println("\r\n"); 81 | canvas.pushSprite(0, 0); 82 | vTaskDelay(pdMS_TO_TICKS(1000)); 83 | } 84 | vTaskDelete(NULL); 85 | } 86 | 87 | void setup() { 88 | auto cfg = M5.config(); 89 | CoreS3.begin(cfg); 90 | 91 | canvas.setColorDepth(1); // mono color 92 | canvas.createSprite(CoreS3.Display.width(), CoreS3.Display.height()); 93 | canvas.setPaletteColor(1, GREEN); 94 | canvas.setTextScroll(true); 95 | 96 | canvas.println("CAN Master"); 97 | 98 | canvas.pushSprite(0, 0); 99 | 100 | ESP_ERROR_CHECK(twai_driver_install(&g_config, &t_config, &f_config)); 101 | Serial.println("Driver installed"); 102 | ESP_ERROR_CHECK(twai_start()); 103 | xTaskCreatePinnedToCore(twai_transmit_task, "twai_transmit_task", 4096, 104 | NULL, TX_TASK_PRIO, NULL, tskNO_AFFINITY); 105 | } 106 | 107 | void loop() { 108 | } -------------------------------------------------------------------------------- /examples/Unit/MiniCAN_TJA1051T/Slave/Slave.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Slave.ino 3 | * @author SeanKwok (shaoxiang@m5stack.com) 4 | * @brief Unit Mini CAN Test Slave 5 | * @version 0.1 6 | * @date 2024-02-01 7 | * 8 | * 9 | * @Hardwares: M5CoreS3 + Unit Mini CAN 10 | * @Platform Version: Arduino M5Stack Board Manager v2.0.9 11 | * @Dependent Library: 12 | * M5GFX: https://github.com/m5stack/M5GFX 13 | * M5Unified: https://github.com/m5stack/M5Unified 14 | * M5CoreS3: https://github.com/m5stack/M5CoreS3 15 | */ 16 | 17 | #include 18 | #include 19 | #include "freertos/FreeRTOS.h" 20 | #include "freertos/task.h" 21 | #include "freertos/queue.h" 22 | #include "freertos/semphr.h" 23 | #include "esp_err.h" 24 | #include "esp_log.h" 25 | #include "driver/twai.h" 26 | #include "esp_err.h" 27 | 28 | #include "M5CoreS3.h" 29 | M5Canvas canvas(&CoreS3.Display); 30 | 31 | /* --------------------- Definitions and static variables ------------------ */ 32 | 33 | #define RX_TASK_PRIO 8 // Receiving task priority 34 | #define TX_GPIO_NUM gpio_num_t(9) 35 | #define RX_GPIO_NUM gpio_num_t(8) 36 | 37 | static const twai_general_config_t g_config = 38 | TWAI_GENERAL_CONFIG_DEFAULT(TX_GPIO_NUM, RX_GPIO_NUM, TWAI_MODE_NORMAL); 39 | static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_25KBITS(); 40 | static const twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL(); 41 | 42 | static void twai_receive_task(void *arg) { 43 | twai_message_t rx_msg; 44 | while (1) { 45 | twai_receive(&rx_msg, portMAX_DELAY); 46 | Serial.printf("received identifier: 0x%02X\r\n", rx_msg.identifier); 47 | canvas.printf("received identifier: 0x%02X\r\n", rx_msg.identifier); 48 | // rx_msg.data 49 | Serial.print("received data: "); 50 | canvas.print("received data: "); 51 | for (int i = 0; i < rx_msg.data_length_code; i++) { 52 | Serial.printf("0x%02X ", rx_msg.data[i]); 53 | canvas.printf("0x%02X ", rx_msg.data[i]); 54 | } 55 | Serial.println(); 56 | canvas.println("\r\n"); 57 | canvas.pushSprite(0, 0); 58 | vTaskDelay(pdMS_TO_TICKS(100)); 59 | } 60 | vTaskDelete(NULL); 61 | } 62 | 63 | void setup() { 64 | auto cfg = M5.config(); 65 | CoreS3.begin(cfg); 66 | 67 | canvas.setColorDepth(1); // mono color 68 | canvas.createSprite(CoreS3.Display.width(), CoreS3.Display.height()); 69 | canvas.setPaletteColor(1, GREEN); 70 | canvas.setTextScroll(true); 71 | 72 | canvas.println("CAN Slave"); 73 | 74 | canvas.pushSprite(0, 0); 75 | 76 | ESP_ERROR_CHECK(twai_driver_install(&g_config, &t_config, &f_config)); 77 | Serial.println("Driver installed"); 78 | ESP_ERROR_CHECK(twai_start()); 79 | xTaskCreatePinnedToCore(twai_receive_task, "twai_receive_task", 4096, NULL, 80 | RX_TASK_PRIO, NULL, tskNO_AFFINITY); 81 | } 82 | 83 | void loop() { 84 | } -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "M5CoreS3", 3 | "description": "An ESP32 Arduino board", 4 | "keywords": "M5CoreS3", 5 | "authors": { 6 | "name": "Tinyu-Zhao,M5Stack", 7 | "url": "http://www.m5stack.com" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/m5stack/M5CoreS3.git" 12 | }, 13 | "version": "1.0.1", 14 | "frameworks": "arduino", 15 | "platforms": "espressif32", 16 | "headers": "M5CoreS3.h" 17 | } -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=M5CoreS3 2 | version=1.0.1 3 | author=Tinyu-Zhao,M5Stack 4 | maintainer=Tinyu-Zhao,M5Stack 5 | sentence=Library for M5CoreS3 Core development kit 6 | paragraph=See more on http://M5Stack.com 7 | category=Device Control 8 | url=https://github.com/m5stack/M5CoreS3 9 | architectures=esp32 10 | includes=M5CoreS3.h 11 | depends=M5GFX,M5Unified,M5Family 12 | -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | ; 11 | ; Example tester by @hpsaturn from CanAirIO Sensorlib pio ini schema 12 | 13 | [platformio] 14 | src_dir = ./examples/PlatformIO/ 15 | lib_dir = ./ 16 | 17 | [env] 18 | framework = arduino 19 | upload_speed = 1500000 20 | monitor_speed = 115200 21 | monitor_filters = time 22 | build_flags = 23 | -DESP32S3 24 | -DBOARD_HAS_PSRAM 25 | -mfix-esp32-psram-cache-issue 26 | -DCORE_DEBUG_LEVEL=5 27 | -DARDUINO_USB_CDC_ON_BOOT=1 28 | -DARDUINO_USB_MODE=1 29 | lib_deps = 30 | m5stack/M5Unified@^0.1.6 31 | 32 | [common] 33 | framework = ${env.framework} 34 | upload_speed = ${env.upload_speed} 35 | monitor_speed = ${env.monitor_speed} 36 | build_flags = ${env.build_flags} 37 | lib_deps = ${env.lib_deps} 38 | 39 | [env:M5CoreS3] 40 | extends = common 41 | platform = espressif32 42 | board = esp32-s3-devkitc-1 43 | build_src_filter = -<*> + 44 | 45 | -------------------------------------------------------------------------------- /src/M5CoreS3.cpp: -------------------------------------------------------------------------------- 1 | #include "M5CoreS3.h" 2 | 3 | using namespace m5; 4 | 5 | M5CoreS3 CoreS3; 6 | 7 | void M5CoreS3::begin() { 8 | M5.begin(); 9 | } 10 | 11 | void M5CoreS3::begin(m5::M5Unified::config_t cfg) { 12 | M5.begin(cfg); 13 | } 14 | 15 | void M5CoreS3::update() { 16 | M5.update(); 17 | } 18 | 19 | void M5CoreS3::delay(uint32_t msec) { 20 | M5.delay(msec); 21 | } 22 | -------------------------------------------------------------------------------- /src/M5CoreS3.h: -------------------------------------------------------------------------------- 1 | #ifndef _M5_CORES3_H_ 2 | #define _M5_CORES3_H_ 3 | 4 | #include "M5Unified.h" 5 | #include "M5GFX.h" 6 | #include "./utility/GC0308.h" 7 | #include "./utility/LTR5XX.h" 8 | 9 | namespace m5 { 10 | class M5CoreS3 { 11 | private: 12 | /* data */ 13 | public: 14 | void begin(); 15 | void begin(m5::M5Unified::config_t cfg); 16 | 17 | M5GFX &Display = M5.Display; 18 | M5GFX &Lcd = Display; 19 | 20 | IMU_Class &Imu = M5.Imu; 21 | Power_Class &Power = M5.Power; 22 | RTC8563_Class &Rtc = M5.Rtc; 23 | Touch_Class &Touch = M5.Touch; 24 | 25 | Speaker_Class &Speaker = M5.Speaker; 26 | 27 | Mic_Class &Mic = M5.Mic; 28 | 29 | Button_Class &BtnPWR = M5.getButton(4); 30 | 31 | /// for internal I2C device 32 | I2C_Class &In_I2C = m5::In_I2C; 33 | 34 | /// for external I2C device (Port.A) 35 | I2C_Class &Ex_I2C = m5::Ex_I2C; 36 | 37 | GC0308 Camera; 38 | LTR5XX Ltr553; 39 | 40 | void update(void); 41 | void delay(uint32_t msec); 42 | }; 43 | } // namespace m5 44 | 45 | extern m5::M5CoreS3 CoreS3; 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /src/utility/GC0308.cpp: -------------------------------------------------------------------------------- 1 | #include "GC0308.h" 2 | 3 | static camera_config_t camera_config = { 4 | .pin_pwdn = -1, 5 | .pin_reset = -1, 6 | .pin_xclk = -1, 7 | .pin_sscb_sda = 12, 8 | .pin_sscb_scl = 11, 9 | .pin_d7 = 47, 10 | .pin_d6 = 48, 11 | .pin_d5 = 16, 12 | .pin_d4 = 15, 13 | .pin_d3 = 42, 14 | .pin_d2 = 41, 15 | .pin_d1 = 40, 16 | .pin_d0 = 39, 17 | 18 | .pin_vsync = 46, 19 | .pin_href = 38, 20 | .pin_pclk = 45, 21 | 22 | .xclk_freq_hz = 20000000, 23 | .ledc_timer = LEDC_TIMER_0, 24 | .ledc_channel = LEDC_CHANNEL_0, 25 | 26 | .pixel_format = PIXFORMAT_RGB565, 27 | .frame_size = FRAMESIZE_QVGA, 28 | .jpeg_quality = 0, 29 | .fb_count = 2, 30 | .fb_location = CAMERA_FB_IN_PSRAM, 31 | .grab_mode = CAMERA_GRAB_WHEN_EMPTY, 32 | .sccb_i2c_port = -1, 33 | }; 34 | 35 | bool GC0308::begin() 36 | { 37 | M5.In_I2C.release(); 38 | esp_err_t err = esp_camera_init(&camera_config); 39 | if (err != ESP_OK) { 40 | return false; 41 | } 42 | sensor = esp_camera_sensor_get(); 43 | return true; 44 | } 45 | 46 | bool GC0308::get() 47 | { 48 | fb = esp_camera_fb_get(); 49 | if (!fb) { 50 | return false; 51 | } 52 | return true; 53 | } 54 | 55 | bool GC0308::free() 56 | { 57 | if (fb) { 58 | esp_camera_fb_return(fb); 59 | return true; 60 | } 61 | return false; 62 | } 63 | -------------------------------------------------------------------------------- /src/utility/GC0308.h: -------------------------------------------------------------------------------- 1 | #ifndef GC0308_H 2 | #define GC0308_H 3 | 4 | #include "M5Unified.h" 5 | #include "esp_camera.h" 6 | 7 | class GC0308 { 8 | private: 9 | public: 10 | camera_fb_t* fb; 11 | sensor_t* sensor; 12 | camera_config_t* config; 13 | bool begin(); 14 | bool get(); 15 | bool free(); 16 | }; 17 | 18 | #endif -------------------------------------------------------------------------------- /src/utility/LTR5XX.cpp: -------------------------------------------------------------------------------- 1 | #include "LTR5XX.h" 2 | 3 | /*===========================================================================*/ 4 | /* LTR5XX Registers address*/ 5 | #define LTR5XX_ALS_CONTR_REG 0x80 6 | #define LTR5XX_PS_CONTR_REG 0x81 7 | #define LTR5XX_PS_LED_REG 0x82 8 | #define LTR5XX_PS_N_PULSES_REG 0x83 9 | #define LTR5XX_PS_MEAS_RATE_REG 0x84 10 | #define LTR5XX_ALS_MEAS_PATE_REG 0x85 11 | 12 | #ifdef LTR507 13 | #define LTR5XX_ALS_DATA_0_REG 0x88 14 | #define LTR5XX_ALS_DATA_1_REG 0x89 15 | #define LTR5XX_ALS_PS_STATUS_REG 0x8A 16 | #define LTR5XX_PS_DATA_LOW_REG 0x8B 17 | #define LTR5XX_PS_DATA_HIGH_REG 0x8C 18 | #define LTR5XX_ALS_DATA_CH1_0_REG 0x8D 19 | #define LTR5XX_ALS_DATA_CH1_1_REG 0x8E 20 | #define LTR5XX_ALS_DATA_CH1_2_REG 0x8F 21 | #define LTR5XX_ALS_DATA_CH2_0_REG 0x90 22 | #define LTR5XX_ALS_DATA_CH2_1_REG 0x91 23 | #define LTR5XX_ALS_DATA_CH2_2_REG 0x92 24 | #define LTR5XX_INTERRUPT_REG 0x98 25 | #define LTR5XX_PS_THRES_UP_0_REG 0x99 26 | #define LTR5XX_PS_THRES_UP_1_REG 0x9A 27 | #define LTR5XX_PS_THRES_LOW_0_REG 0x9B 28 | #define LTR5XX_PS_THRES_LOW_1_REG 0x9C 29 | #define LTR5XX_ALS_THRES_UP_0_REG 0x9E 30 | #define LTR5XX_ALS_THRES_UP_1_REG 0x9F 31 | #define LTR5XX_ALS_THRES_LOW_0_REG 0xA0 32 | #define LTR5XX_ALS_THRES_LOW_1_REG 0xA1 33 | #define LTR5XX_INTERRUPT_PERSIST_REG 0xA4 34 | #endif 35 | 36 | #ifdef LTR55X 37 | #define LTR5XX_ALS_PS_STATUS_REG 0x8C 38 | #define LTR5XX_PS_DATA_LOW_REG 0x8D 39 | #define LTR5XX_PS_DATA_HIGH_REG 0x8E 40 | #define LTR5XX_ALS_DATA_CH1_0_REG 0x88 41 | #define LTR5XX_ALS_DATA_CH1_1_REG 0x89 42 | #define LTR5XX_ALS_DATA_CH0_0_REG 0x8A 43 | #define LTR5XX_ALS_DATA_CH0_1_REG 0x8B 44 | #define LTR5XX_INTERRUPT_REG 0x8F 45 | #define LTR5XX_PS_THRES_UP_0_REG 0x90 46 | #define LTR5XX_PS_THRES_UP_1_REG 0x91 47 | #define LTR5XX_PS_THRES_LOW_0_REG 0x92 48 | #define LTR5XX_PS_THRES_LOW_1_REG 0x93 49 | #define LTR5XX_ALS_THRES_UP_0_REG 0x97 50 | #define LTR5XX_ALS_THRES_UP_1_REG 0x98 51 | #define LTR5XX_ALS_THRES_LOW_0_REG 0x99 52 | #define LTR5XX_ALS_THRES_LOW_1_REG 0x9A 53 | #define LTR5XX_INTERRUPT_PERSIST_REG 0x9E 54 | #endif 55 | /*===========================================================================*/ 56 | 57 | /*===========================================================================*/ 58 | /*LTR55X Registers operating parameters*/ 59 | #ifdef LTR55X 60 | #define LTR5XX_ALS_MODE_MASK 0x01 61 | #define LTR5XX_ALS_MODE_SHIFT 0 62 | 63 | #define LTR5XX_ALS_GAIN_MASK 0x1C 64 | #define LTR5XX_ALS_GAIN_SHIFT 2 65 | 66 | #define LTR5XX_ALS_INTEGRATION_TIME_MASK 0x38 67 | #define LTR5XX_ALS_INTEGRATION_TIME_SHIFT 3 68 | 69 | #define LTR5XX_ALS_MEASURE_RATE_MASK 0x07 70 | #define LTR5XX_ALS_MEASURE_RATE_SHIFT 0 71 | 72 | #define LTR5XX_ALS_DATA_LOW_MASK 0xFF 73 | #define LTR5XX_ALS_DATA_HIGH_MASK 0xFF 74 | 75 | #define LTR5XX_PS_PULSES_MASK 0x0F 76 | 77 | #define LTR5XX_PS_MEAS_RATE_MASK 0x0F 78 | 79 | #define LTR5XX_VALID_PS_DATA_MASK 0x80 80 | #define LTR5XX_VALID_PS_DATA_SHIFT 7 81 | #endif 82 | 83 | /*LTR507 Registers operating parameters*/ 84 | #ifdef LTR507 85 | #define LTR5XX_ALS_MODE_MASK 0x02 86 | #define LTR5XX_ALS_MODE_SHIFT 0 87 | 88 | #define LTR5XX_ALS_GAIN_MASK 0x18 89 | #define LTR5XX_ALS_GAIN_SHIFT 3 90 | 91 | #define LTR5XX_ALS_ADC_BIT_WIDTH_MASK 0xE0 92 | #define LTR5XX_ALS_ADC_BIT_WIDTH_SHIFT 5 93 | 94 | #define LTR5XX_ALS_MEASURE_RATE_MASK 0x07 95 | #define LTR5XX_ALS_MEASURE_RATE_SHIFT 0 96 | 97 | #define LTR5XX_ALS_DATA_LOW_MASK 0xF0 98 | #define LTR5XX_ALS_DATA_MID_MASK 0xFF 99 | #define LTR5XX_ALS_DATA_HIGH_MASK 0xFF 100 | 101 | #define LTR5XX_PS_PULSES_MASK 0xFF 102 | 103 | #define LTR5XX_PS_MEAS_RATE_MASK 0x07 104 | 105 | #define LTR5XX_VALID_PS_DATA_MASK 0x10 106 | #define LTR5XX_VALID_PS_DATA_SHIFT 4 107 | #endif 108 | 109 | /*LTR55X and LTR507 common Registers operating parameters*/ 110 | #define LTR5XX_PS_MODE_MASK 0x02 111 | #define LTR5XX_PS_MODE_SHIFT 1 112 | 113 | #define LTR5XX_LED_PULSE_FREQ_MASK 0xE0 114 | #define LTR5XX_LED_PULSE_FREQ_SHIFT 5 115 | 116 | #define LTR5XX_LED_DUTY_CYCLE_MASK 0x18 117 | #define LTR5XX_LED_DUTY_CYCLE_SHIFT 3 118 | 119 | #define LTR5XX_LED_PEAK_CURRENT_MASK 0x07 120 | 121 | #define LTR5XX_PS_DATA_LOW_MASK 0xFF 122 | #define LTR5XX_PS_DATA_HIGH_MASK 0x07 123 | 124 | #define LTR5XX_ALS_INTERRUPT_STATUS_MASK 0x08 125 | #define LTR5XX_ALS_INTERRUPT_STATUS_SHIFT 3 126 | 127 | #define LTR5XX_PS_INTERRUPT_STATUS_MASK 0x02 128 | #define LTR5XX_PS_INTERRUPT_STATUS_SHIFT 1 129 | 130 | #define LTR5XX_INTERRUPT_POLARITY_MASK 0x04 131 | #define LTR5XX_INTERRUPT_POLARITY_SHIFT 2 132 | 133 | #define LTR5XX_INTERRUPT_MODE_MASK 0x03 134 | 135 | #define LTR5XX_PS_THRES_UP_1_MASK 0x07 136 | #define LTR5XX_PS_THRES_LOW_1_MASK 0x07 137 | 138 | #define LTR5XX_PS_INTERRUPT_PERSIST_MASK 0xF0 139 | #define LTR5XX_PS_INTERRUPT_PERSIST_SHIFT 4 140 | 141 | #define LTR5XX_ALS_INTERRUPT_PERSIST_MASK 0x0F 142 | 143 | bool LTR5XX::ltr5xx_read(uint8_t start_reg_addr, uint8_t *pdata, uint8_t size) { 144 | return M5.In_I2C.readRegister(_address, start_reg_addr, pdata, size, 145 | 100000L); 146 | } 147 | 148 | bool LTR5XX::ltr5xx_write(uint8_t start_reg_addr, uint8_t *pdata, 149 | uint8_t size) { 150 | return M5.In_I2C.writeRegister(_address, start_reg_addr, pdata, size, 151 | 100000L); 152 | } 153 | 154 | bool LTR5XX::ps_set_led_pulse_freq(uint8_t value) { 155 | uint8_t read_reg, write_reg, tmp_value; 156 | ltr5xx_read(LTR5XX_PS_LED_REG, &read_reg, 1); 157 | read_reg &= (~LTR5XX_LED_PULSE_FREQ_MASK); 158 | tmp_value = 159 | (value << LTR5XX_LED_PULSE_FREQ_SHIFT) & LTR5XX_LED_PULSE_FREQ_MASK; 160 | write_reg = read_reg | tmp_value; 161 | return ltr5xx_write(LTR5XX_PS_LED_REG, &write_reg, 1); 162 | } 163 | 164 | bool LTR5XX::ps_set_led_duty_cycle(uint8_t value) { 165 | uint8_t read_reg, write_reg, tmp_value; 166 | ltr5xx_read(LTR5XX_PS_LED_REG, &read_reg, 1); 167 | read_reg &= (~LTR5XX_LED_DUTY_CYCLE_MASK); 168 | tmp_value = 169 | (value << LTR5XX_LED_DUTY_CYCLE_SHIFT) & LTR5XX_LED_DUTY_CYCLE_MASK; 170 | write_reg = read_reg | tmp_value; 171 | return ltr5xx_write(LTR5XX_PS_LED_REG, &write_reg, 1); 172 | } 173 | 174 | bool LTR5XX::ps_set_led_peak_current(uint8_t value) { 175 | uint8_t read_reg, write_reg, tmp_value; 176 | ltr5xx_read(LTR5XX_PS_LED_REG, &read_reg, 1); 177 | read_reg &= (~LTR5XX_LED_PEAK_CURRENT_MASK); 178 | tmp_value = value & LTR5XX_LED_PEAK_CURRENT_MASK; 179 | write_reg = read_reg | tmp_value; 180 | return ltr5xx_write(LTR5XX_PS_LED_REG, &write_reg, 1); 181 | } 182 | 183 | bool LTR5XX::ps_set_n_pulses(uint8_t value) { 184 | uint8_t tmp_value; 185 | tmp_value = value & LTR5XX_PS_PULSES_MASK; 186 | return ltr5xx_write(LTR5XX_PS_N_PULSES_REG, &tmp_value, 1); 187 | } 188 | 189 | bool LTR5XX::ps_set_meas_rate(uint8_t value) { 190 | uint8_t tmp_value; 191 | tmp_value = value & LTR5XX_PS_MEAS_RATE_MASK; 192 | return ltr5xx_write(LTR5XX_PS_MEAS_RATE_REG, &tmp_value, 1); 193 | } 194 | 195 | bool LTR5XX::als_set_gain(uint8_t value) { 196 | uint8_t read_reg, write_reg, tmp_value; 197 | ltr5xx_read(LTR5XX_ALS_CONTR_REG, &read_reg, 1); 198 | read_reg &= (~LTR5XX_ALS_GAIN_MASK); 199 | tmp_value = (value << LTR5XX_ALS_GAIN_SHIFT) & LTR5XX_ALS_GAIN_MASK; 200 | write_reg = read_reg | tmp_value; 201 | return ltr5xx_write(LTR5XX_ALS_CONTR_REG, &write_reg, 1); 202 | } 203 | 204 | // LTR507 default integration time is 75ms,only use default values 205 | #ifdef LTR55X 206 | bool LTR5XX::als_set_integration_time(uint8_t value) { 207 | uint8_t read_reg, write_reg, tmp_value; 208 | ltr5xx_read(LTR5XX_ALS_MEAS_PATE_REG, &read_reg, 1); 209 | read_reg &= (~LTR5XX_ALS_INTEGRATION_TIME_MASK); 210 | tmp_value = (value << LTR5XX_ALS_INTEGRATION_TIME_SHIFT) & 211 | LTR5XX_ALS_INTEGRATION_TIME_MASK; 212 | write_reg = read_reg | tmp_value; 213 | return ltr5xx_write(LTR5XX_ALS_MEAS_PATE_REG, &write_reg, 1); 214 | } 215 | #endif 216 | 217 | // LTR507 can chose als adc bit width 218 | #ifdef LTR507 219 | bool void LTR5XX::als_set_adc_bit_width(uint8_t value) { 220 | uint8_t read_reg, write_reg, tmp_value; 221 | ltr5xx_read(LTR5XX_ALS_MEAS_PATE_REG, &read_reg, 1); 222 | read_reg &= (~LTR5XX_ALS_ADC_BIT_WIDTH_MASK); 223 | tmp_value = (value << LTR5XX_ALS_ADC_BIT_WIDTH_SHIFT) & 224 | LTR5XX_ALS_ADC_BIT_WIDTH_MASK; 225 | write_reg = read_reg | tmp_value; 226 | return ltr5xx_write(LTR5XX_ALS_MEAS_PATE_REG, &write_reg, 1); 227 | } 228 | #endif 229 | 230 | bool LTR5XX::als_set_measure_rate(uint8_t value) { 231 | uint8_t read_reg, write_reg, tmp_value; 232 | ltr5xx_read(LTR5XX_ALS_MEAS_PATE_REG, &read_reg, 1); 233 | read_reg &= (~LTR5XX_ALS_MEASURE_RATE_MASK); 234 | tmp_value = 235 | (value << LTR5XX_ALS_MEASURE_RATE_SHIFT) & LTR5XX_ALS_MEASURE_RATE_MASK; 236 | write_reg = read_reg | tmp_value; 237 | return ltr5xx_write(LTR5XX_ALS_MEAS_PATE_REG, &write_reg, 1); 238 | } 239 | 240 | bool LTR5XX::ltr5xx_set_interrupt_polarity(uint8_t polarity) { 241 | uint8_t read_reg, write_reg, tmp_value; 242 | ltr5xx_read(LTR5XX_INTERRUPT_REG, &read_reg, 1); 243 | read_reg &= (~LTR5XX_INTERRUPT_POLARITY_MASK); 244 | tmp_value = (polarity << LTR5XX_INTERRUPT_POLARITY_SHIFT) & 245 | LTR5XX_INTERRUPT_POLARITY_MASK; 246 | write_reg = read_reg | tmp_value; 247 | return ltr5xx_write(LTR5XX_INTERRUPT_REG, &write_reg, 1); 248 | } 249 | 250 | bool LTR5XX::ltr5xx_set_interrupt_mode(uint8_t mode) { 251 | uint8_t read_reg, write_reg, tmp_value; 252 | ltr5xx_read(LTR5XX_INTERRUPT_REG, &read_reg, 1); 253 | read_reg &= (~LTR5XX_INTERRUPT_MODE_MASK); 254 | tmp_value = mode & LTR5XX_INTERRUPT_MODE_MASK; 255 | write_reg = read_reg | tmp_value; 256 | return ltr5xx_write(LTR5XX_INTERRUPT_REG, &write_reg, 1); 257 | } 258 | 259 | bool LTR5XX::ps_set_threshold(uint16_t ps_upper_threshold, 260 | uint16_t ps_lower_threshold) { 261 | uint8_t buffer[4]; 262 | 263 | buffer[0] = ps_upper_threshold & 0xFF; // up_reg_0 264 | buffer[1] = 265 | (ps_upper_threshold >> 8) & LTR5XX_PS_THRES_UP_1_MASK; // up_reg_1 266 | buffer[2] = ps_lower_threshold & 0xFF; // low_reg_0 267 | buffer[3] = 268 | (ps_lower_threshold >> 8) & LTR5XX_PS_THRES_LOW_1_MASK; // low_reg_1; 269 | 270 | return ltr5xx_write(LTR5XX_PS_THRES_UP_0_REG, &buffer[0], 4); 271 | } 272 | 273 | bool LTR5XX::als_set_threshold(uint16_t als_upper_threshold, 274 | uint16_t als_lower_threshold) { 275 | uint8_t buffer[4]; 276 | 277 | buffer[0] = als_upper_threshold & 0xFF; // up_reg_0 278 | buffer[1] = (als_upper_threshold >> 8) & 0xFF; // up_reg_1 279 | buffer[2] = als_lower_threshold & 0xFF; // low_reg_0 280 | buffer[3] = (als_lower_threshold >> 8) & 0xFF; // low_reg_1; 281 | 282 | return ltr5xx_write(LTR5XX_ALS_THRES_UP_0_REG, &buffer[0], 4); 283 | } 284 | 285 | bool LTR5XX::ltr5xx_set_n_values_outside_trigger_interrupt( 286 | uint8_t ps_n_values_outside_trigger, uint8_t als_n_values_outside_trigger) { 287 | uint8_t temp_value; 288 | 289 | temp_value = 290 | (ps_n_values_outside_trigger << LTR5XX_PS_INTERRUPT_PERSIST_SHIFT) & 291 | LTR5XX_PS_INTERRUPT_PERSIST_MASK; 292 | temp_value |= 293 | als_n_values_outside_trigger & LTR5XX_ALS_INTERRUPT_PERSIST_MASK; 294 | 295 | return ltr5xx_write(LTR5XX_INTERRUPT_PERSIST_REG, &temp_value, 1); 296 | } 297 | 298 | LTR5XX::LTR5XX(uint8_t sda, uint8_t scl, uint8_t address) { 299 | _sda = sda; 300 | _scl = scl; 301 | _address = address; 302 | } 303 | 304 | bool LTR5XX::begin(Ltr5xx_Init_Basic_Para *init_base_para) { 305 | return (setPsMode(LTR5XX_PS_STAND_BY_MODE) && 306 | setAlsMode(LTR5XX_ALS_STAND_BY_MODE) && 307 | ps_set_led_pulse_freq(init_base_para->ps_led_pulse_freq) && 308 | ps_set_led_duty_cycle(init_base_para->ps_led_duty_cycle) && 309 | ps_set_meas_rate(init_base_para->ps_measurement_rate) && 310 | ps_set_led_peak_current(init_base_para->ps_led_peak_current) && 311 | ps_set_n_pulses(init_base_para->ps_led_n_pulses) && 312 | als_set_gain(init_base_para->als_gain) && 313 | #ifdef LTR55X 314 | als_set_integration_time(init_base_para->als_integration_time) && 315 | #endif 316 | #ifdef LTR507 317 | als_set_adc_bit_width(init_base_para->als_adc_bit_width) && 318 | #endif 319 | 320 | als_set_measure_rate(init_base_para->als_measurement_rate)); 321 | } 322 | 323 | bool LTR5XX::begin(Ltr5xx_Init_Interrupt_Para *init_interrupt_para) { 324 | return (ltr5xx_set_interrupt_polarity( 325 | init_interrupt_para->interrupt_polarity) && 326 | ltr5xx_set_interrupt_mode(init_interrupt_para->interrupt_mode) && 327 | ps_set_threshold(init_interrupt_para->ps_upper_threshold, 328 | init_interrupt_para->ps_lower_threshold) && 329 | als_set_threshold(init_interrupt_para->als_upper_threshold, 330 | init_interrupt_para->als_lower_threshold) && 331 | ltr5xx_set_n_values_outside_trigger_interrupt( 332 | init_interrupt_para->ps_n_values_outside_trigger, 333 | init_interrupt_para->als_n_values_outside_trigger)); 334 | } 335 | 336 | bool LTR5XX::setPsMode(uint8_t mode) { 337 | uint8_t read_reg, write_reg, tmp_value; 338 | ltr5xx_read(LTR5XX_PS_CONTR_REG, &read_reg, 1); 339 | read_reg &= (~LTR5XX_PS_MODE_MASK); 340 | tmp_value = (mode << LTR5XX_PS_MODE_SHIFT) & LTR5XX_PS_MODE_MASK; 341 | write_reg = read_reg | tmp_value; 342 | return ltr5xx_write(LTR5XX_PS_CONTR_REG, &write_reg, 1); 343 | } 344 | 345 | uint16_t LTR5XX::getPsValue(void) { 346 | uint8_t buffer[2]; 347 | uint16_t result; 348 | ltr5xx_read(LTR5XX_PS_DATA_LOW_REG, &buffer[0], 2); 349 | buffer[0] &= LTR5XX_PS_DATA_LOW_MASK; 350 | buffer[1] &= LTR5XX_PS_DATA_HIGH_MASK; 351 | result = (buffer[1] << 8) | buffer[0]; 352 | return result; 353 | } 354 | 355 | bool LTR5XX::setAlsMode(uint8_t mode) { 356 | uint8_t read_reg, write_reg, tmp_value; 357 | ltr5xx_read(LTR5XX_ALS_CONTR_REG, &read_reg, 1); 358 | read_reg &= (~LTR5XX_ALS_MODE_MASK); 359 | tmp_value = (mode << LTR5XX_ALS_MODE_SHIFT) & LTR5XX_ALS_MODE_MASK; 360 | write_reg = read_reg | tmp_value; 361 | return ltr5xx_write(LTR5XX_ALS_CONTR_REG, &write_reg, 1); 362 | } 363 | 364 | uint16_t LTR5XX::getAlsValue() { 365 | uint8_t buffer[4]; 366 | uint16_t result; 367 | 368 | #ifdef LTR507 369 | ltr5xx_read(LTR5XX_ALS_DATA_0_REG, &buffer[0], 2); 370 | result = (buffer[1] << 8) | buffer[0]; 371 | #endif 372 | 373 | #ifdef LTR55X 374 | uint16_t ch1_value, ch0_value; 375 | ltr5xx_read(LTR5XX_ALS_DATA_CH1_0_REG, &buffer[0], 4); 376 | ch1_value = (buffer[1] << 8) | buffer[0]; 377 | ch0_value = (buffer[3] << 8) | buffer[2]; 378 | result = (ch1_value + ch0_value) >> 1; 379 | #endif 380 | return result; 381 | } 382 | 383 | uint8_t LTR5XX::getPsIRQ() { 384 | uint8_t read_reg, int_status; 385 | ltr5xx_read(LTR5XX_ALS_PS_STATUS_REG, &read_reg, 1); 386 | int_status = (read_reg & LTR5XX_PS_INTERRUPT_STATUS_MASK) >> 387 | LTR5XX_PS_INTERRUPT_STATUS_SHIFT; 388 | return int_status; 389 | } 390 | 391 | uint8_t LTR5XX::getAlsIRQ() { 392 | uint8_t read_reg, int_status; 393 | ltr5xx_read(LTR5XX_ALS_PS_STATUS_REG, &read_reg, 1); 394 | int_status = (read_reg & LTR5XX_ALS_INTERRUPT_STATUS_MASK) >> 395 | LTR5XX_ALS_INTERRUPT_STATUS_SHIFT; 396 | return int_status; 397 | } -------------------------------------------------------------------------------- /src/utility/LTR5XX.h: -------------------------------------------------------------------------------- 1 | #ifndef __LTR5XX_H__ 2 | #define __LTR5XX_H__ 3 | 4 | #include "M5Unified.h" 5 | #include 6 | 7 | /*you can only choose one device LTR553,LTR556,or LTR507*/ 8 | /*LTR553 and LTR556 only infrared wavelengths are different*/ 9 | /*if use LTR553 or LTR556*/ 10 | #ifndef LTR55X 11 | #define LTR55X 12 | #endif 13 | 14 | /*if use LTR507*/ 15 | // #ifndef LTR507 16 | // #define LTR507 17 | // #endif 18 | 19 | /*LTR-55x address is can't change*/ 20 | #define LTR55X_ADDR 0x23 21 | /*LTR-507 SEL pin is "Float"*/ 22 | #define LTR507_SEL_FLOAT_ADDR 0x23 23 | /*LTR-507 SEL pin is "VDD"*/ 24 | #define LTR507_SEL_VDD_ADDR 0x3B 25 | /*LTR-507 SEL pin is "GND"*/ 26 | #define LTR507_SEL_GND_ADDR 0x3A 27 | 28 | /*===========================================================================*/ 29 | /*LTR55X Registers operating parameters*/ 30 | #ifdef LTR55X 31 | #define LTR5XX_ALS_STAND_BY_MODE 0 32 | #define LTR5XX_ALS_ACTIVE_MODE 1 33 | 34 | #define LTR5XX_ALS_GAIN_1X 0x00 // default 35 | #define LTR5XX_ALS_GAIN_2X 0x01 36 | #define LTR5XX_ALS_GAIN_4X 0x02 37 | #define LTR5XX_ALS_GAIN_8X 0x03 38 | #define LTR5XX_ALS_GAIN_48X 0x06 39 | #define LTR5XX_ALS_GAIN_96X 0x07 40 | 41 | // als measurement time must be set to be equal or larger than integration time 42 | #define LTR5XX_ALS_INTEGRATION_TIME_50MS 0x01 43 | #define LTR5XX_ALS_INTEGRATION_TIME_100MS 0x00 // default 44 | #define LTR5XX_ALS_INTEGRATION_TIME_150MS 0x04 45 | #define LTR5XX_ALS_INTEGRATION_TIME_200MS 0x02 46 | #define LTR5XX_ALS_INTEGRATION_TIME_250MS 0x05 47 | #define LTR5XX_ALS_INTEGRATION_TIME_300MS 0x06 48 | #define LTR5XX_ALS_INTEGRATION_TIME_350MS 0x07 49 | #define LTR5XX_ALS_INTEGRATION_TIME_400MS 0x03 50 | 51 | #define LTR5XX_ALS_MEASUREMENT_RATE_50MS 0x00 52 | #define LTR5XX_ALS_MEASUREMENT_RATE_100MS 0x01 53 | #define LTR5XX_ALS_MEASUREMENT_RATE_200MS 0x02 54 | #define LTR5XX_ALS_MEASUREMENT_RATE_500MS 0x03 // default 55 | #define LTR5XX_ALS_MEASUREMENT_RATE_1000MS 0x04 56 | #define LTR5XX_ALS_MEASUREMENT_RATE_2000MS 0x05 57 | 58 | #define LTR5XX_LED_CURRENT_DUTY_PER25 0x00 59 | #define LTR5XX_LED_CURRENT_DUTY_PER50 0x01 60 | #define LTR5XX_LED_CURRENT_DUTY_PER75 0x02 61 | #define LTR5XX_LED_CURRENT_DUTY_PER100 0x03 // default 62 | 63 | #define LTR5XX_PS_MEASUREMENT_RATE_10MS 0x08 64 | #define LTR5XX_PS_MEASUREMENT_RATE_50MS 0x00 65 | #define LTR5XX_PS_MEASUREMENT_RATE_70MS 0x01 66 | #define LTR5XX_PS_MEASUREMENT_RATE_100MS 0x02 // default 67 | #define LTR5XX_PS_MEASUREMENT_RATE_200MS 0x03 68 | #define LTR5XX_PS_MEASUREMENT_RATE_500MS 0x04 69 | #define LTR5XX_PS_MEASUREMENT_RATE_1000MS 0x05 70 | #define LTR5XX_PS_MEASUREMENT_RATE_2000MS 0x06 71 | #endif 72 | 73 | /*LTR507 Registers operating parameters*/ 74 | #ifdef LTR507 75 | #define LTR5XX_ALS_STAND_BY_MODE 0 76 | #define LTR5XX_ALS_ACTIVE_MODE 2 77 | 78 | #define LTR5XX_ALS_GAIN_RANGE1 0x00 // default 79 | #define LTR5XX_ALS_GAIN_RANGE2 0x01 80 | #define LTR5XX_ALS_GAIN_RANGE3 0x02 81 | #define LTR5XX_ALS_GAIN_RANGE4 0x03 82 | 83 | #define LTR5XX_ALS_ADC_BIT_WIDTH_20BIT 0x00 // integration time = 1200ms 84 | #define LTR5XX_ALS_ADC_BIT_WIDTH_19BIT 0x01 // integration time = 600ms 85 | #define LTR5XX_ALS_ADC_BIT_WIDTH_18BIT 0x02 // integration time = 300ms 86 | #define LTR5XX_ALS_ADC_BIT_WIDTH_17BIT 0x03 // integration time = 150ms 87 | #define LTR5XX_ALS_ADC_BIT_WIDTH_16BIT 0x04 // integration time = 75ms default 88 | #define LTR5XX_ALS_ADC_BIT_WIDTH_12BIT 0x05 // integration time = 4.685ms 89 | #define LTR5XX_ALS_ADC_BIT_WIDTH_8BIT 0x06 // integration time = 292us 90 | #define LTR5XX_ALS_ADC_BIT_WIDTH_4BIT 0x07 // integration time = 18us 91 | 92 | // als measurement time must be set to be equal or larger than integration time 93 | #define LTR5XX_ALS_MEASUREMENT_RATE_100MS 0x00 94 | #define LTR5XX_ALS_MEASUREMENT_RATE_200MS 0x01 95 | #define LTR5XX_ALS_MEASUREMENT_RATE_500MS 0x02 // default 96 | #define LTR5XX_ALS_MEASUREMENT_RATE_1000MS 0x03 97 | #define LTR5XX_ALS_MEASUREMENT_RATE_2000MS 0x04 98 | 99 | #define LTR5XX_LED_CURRENT_DUTY_DEFAULT \ 100 | 0x01 // LTR507 led duty cycle must write as 01 101 | 102 | #define LTR5XX_PS_MEASUREMENT_RATE_12_5MS 0x00 103 | #define LTR5XX_PS_MEASUREMENT_RATE_50MS 0x01 104 | #define LTR5XX_PS_MEASUREMENT_RATE_70MS 0x02 105 | #define LTR5XX_PS_MEASUREMENT_RATE_100MS 0x03 // default 106 | #define LTR5XX_PS_MEASUREMENT_RATE_200MS 0x04 107 | #define LTR5XX_PS_MEASUREMENT_RATE_500MS 0x05 108 | #define LTR5XX_PS_MEASUREMENT_RATE_1000MS 0x06 109 | #define LTR5XX_PS_MEASUREMENT_RATE_2000MS 0x07 110 | #endif 111 | 112 | /*LTR55X and LTR507 common Registers operating parameters*/ 113 | #define LTR5XX_PS_STAND_BY_MODE 0 114 | #define LTR5XX_PS_ACTIVE_MODE 1 115 | 116 | #define LTR5XX_LED_PULSE_FREQ_30KHZ 0x00 117 | #define LTR5XX_LED_PULSE_FREQ_40KHZ 0x01 118 | #define LTR5XX_LED_PULSE_FREQ_50KHZ 0x02 119 | #define LTR5XX_LED_PULSE_FREQ_60KHZ 0x03 // default 120 | #define LTR5XX_LED_PULSE_FREQ_70KHZ 0x04 121 | #define LTR5XX_LED_PULSE_FREQ_80KHZ 0x05 122 | #define LTR5XX_LED_PULSE_FREQ_90KHZ 0x06 123 | #define LTR5XX_LED_PULSE_FREQ_100KHZ 0x07 124 | 125 | #define LTR5XX_LED_PEAK_CURRENT_5MA 0x00 126 | #define LTR5XX_LED_PEAK_CURRENT_10MA 0x01 127 | #define LTR5XX_LED_PEAK_CURRENT_20MA 0x02 128 | #define LTR5XX_LED_PEAK_CURRENT_50MA 0x03 // LTR507 default 129 | #define LTR5XX_LED_PEAK_CURRENT_100MA 0x04 // LTR55X default 130 | 131 | #define LTR5XX_INTERRUPT_TRIGGER 1 132 | 133 | #define LTR5XX_INTERRUPT_POLARITY_LOGIC_0 \ 134 | 0 // interrupt tigger INT PIN is low level(INT PIN must Connect pull-up 135 | // resistor to VDD) default 136 | #define LTR5XX_INTERRUPT_POLARITY_LOGIC_1 \ 137 | 1 // interrupt tigger INT PIN is high level(INT PIN must Connect pull-down 138 | // resistor to GND) 139 | 140 | #define LTR5XX_INTERRUPT_MODE_INACTIVE \ 141 | 0 // interrupt pin is inactive/high impedance state (default) 142 | #define LTR5XX_INTERRUPT_MODE_PS_TRIGGER 1 // only ps can tigger interrupt 143 | #define LTR5XX_INTERRUPT_MODE_ALS_TRIGGER 2 // only als can tigger interrupt 144 | #define LTR5XX_INTERRUPT_MODE_PS_ALS_TRIGGER \ 145 | 3 // both ps and als can tigger interrupt 146 | 147 | #define LTR5XX_EVERY_VALUE_OUTSIDE_TIGGER_INTERRUPT \ 148 | 0 // every ps value outside threshold range 149 | #define LTR5XX_2_VALUES_OUTSIDE_TIGGER_INTERRUPT 1 150 | #define LTR5XX_3_VALUES_OUTSIDE_TIGGER_INTERRUPT 2 151 | #define LTR5XX_4_VALUES_OUTSIDE_TIGGER_INTERRUPT 3 152 | #define LTR5XX_5_VALUES_OUTSIDE_TIGGER_INTERRUPT 4 153 | #define LTR5XX_6_VALUES_OUTSIDE_TIGGER_INTERRUPT 5 154 | #define LTR5XX_7_VALUES_OUTSIDE_TIGGER_INTERRUPT 6 155 | #define LTR5XX_8_VALUES_OUTSIDE_TIGGER_INTERRUPT 7 156 | #define LTR5XX_9_VALUES_OUTSIDE_TIGGER_INTERRUPT 8 157 | #define LTR5XX_10_VALUES_OUTSIDE_TIGGER_INTERRUPT 9 158 | #define LTR5XX_11_VALUES_OUTSIDE_TIGGER_INTERRUPT 10 159 | #define LTR5XX_12_VALUES_OUTSIDE_TIGGER_INTERRUPT 11 160 | #define LTR5XX_13_VALUES_OUTSIDE_TIGGER_INTERRUPT 12 161 | #define LTR5XX_14_VALUES_OUTSIDE_TIGGER_INTERRUPT 13 162 | #define LTR5XX_15_VALUES_OUTSIDE_TIGGER_INTERRUPT 14 163 | #define LTR5XX_16_VALUES_OUTSIDE_TIGGER_INTERRUPT 15 164 | /*===========================================================================*/ 165 | 166 | // sensor base initialization parameters 167 | #ifdef LTR55X 168 | typedef struct _Ltr5xx_Init_Basic_Para { 169 | uint8_t ps_led_pulse_freq; 170 | uint8_t ps_led_duty_cycle; 171 | uint8_t ps_measurement_rate; 172 | uint8_t ps_led_peak_current; 173 | uint8_t ps_led_n_pulses; 174 | 175 | uint8_t als_gain; 176 | uint8_t als_integration_time; 177 | uint8_t als_measurement_rate; 178 | } Ltr5xx_Init_Basic_Para; 179 | 180 | /* Default config for sensor base initialization parameters */ 181 | #define LTR5XX_BASE_PARA_CONFIG_DEFAULT \ 182 | { \ 183 | LTR5XX_LED_PULSE_FREQ_60KHZ, LTR5XX_LED_CURRENT_DUTY_PER100, \ 184 | LTR5XX_PS_MEASUREMENT_RATE_100MS, LTR5XX_LED_PEAK_CURRENT_100MA, \ 185 | 1, /*ps_led_n_pulses:1~15 default:1*/ \ 186 | LTR5XX_ALS_GAIN_1X, LTR5XX_ALS_INTEGRATION_TIME_100MS, \ 187 | LTR5XX_ALS_MEASUREMENT_RATE_500MS \ 188 | } 189 | #endif 190 | 191 | #ifdef LTR507 192 | typedef struct _Ltr5xx_Init_Basic_Para { 193 | uint8_t ps_led_pulse_freq; 194 | uint8_t ps_led_duty_cycle; 195 | uint8_t ps_measurement_rate; 196 | uint8_t ps_led_peak_current; 197 | uint8_t ps_led_n_pulses; 198 | 199 | uint8_t als_gain; 200 | uint8_t als_adc_bit_width; 201 | uint8_t als_measurement_rate; 202 | } Ltr5xx_Init_Basic_Para; 203 | 204 | /* Default config for sensor base initialization parameters */ 205 | #define LTR5XX_BASE_PARA_CONFIG_DEFAULT \ 206 | { \ 207 | LTR5XX_LED_PULSE_FREQ_60KHZ, LTR5XX_LED_CURRENT_DUTY_DEFAULT, \ 208 | LTR5XX_PS_MEASUREMENT_RATE_100MS, LTR5XX_LED_PEAK_CURRENT_50MA, \ 209 | 127, /*ps_led_n_pulses:1~255 default:127*/ \ 210 | LTR5XX_ALS_GAIN_RANGE1, LTR5XX_ALS_ADC_BIT_WIDTH_16BIT, \ 211 | LTR5XX_ALS_MEASUREMENT_RATE_500MS \ 212 | } 213 | #endif 214 | 215 | // sensor interrupt initialization parameters 216 | typedef struct _Ltr5xx_Init_Interrupt_Para { 217 | uint8_t interrupt_polarity; 218 | uint8_t interrupt_mode; 219 | uint16_t ps_upper_threshold; 220 | uint16_t ps_lower_threshold; 221 | uint16_t als_upper_threshold; 222 | uint16_t als_lower_threshold; 223 | uint8_t ps_n_values_outside_trigger; 224 | uint8_t als_n_values_outside_trigger; 225 | } Ltr5xx_Init_Interrupt_Para; 226 | 227 | /* Default config for sensor interrupt initialization parameters */ 228 | #define LTR5XX_INTERRUPT_PARA_CONFIG_DEFAULT \ 229 | { \ 230 | LTR5XX_INTERRUPT_POLARITY_LOGIC_0, /*interrupt tigger INT PIN is low \ 231 | level(INT PIN must Connect \ 232 | pull-up resistor to VDD) default \ 233 | */ \ 234 | LTR5XX_INTERRUPT_MODE_INACTIVE, /*interrupt pin is inactive/high \ 235 | impedance state (default)*/ \ 236 | 0x07FF, /*ps_upper_threshold default*/ \ 237 | 0x0000, /*ps_lower_threshold default*/ \ 238 | 0xFFFF, /*als_upper_threshold default*/ \ 239 | 0x0000, /*als_lower_threshold default*/ \ 240 | LTR5XX_EVERY_VALUE_OUTSIDE_TIGGER_INTERRUPT, /*ps_n_values_outside_trigger \ 241 | default*/ \ 242 | LTR5XX_EVERY_VALUE_OUTSIDE_TIGGER_INTERRUPT /*als_n_values_outside_trigger \ 243 | default*/ \ 244 | } 245 | 246 | class LTR5XX { 247 | public: 248 | #ifdef LTR55X 249 | LTR5XX(uint8_t sda = -1, uint8_t scl = -1, uint8_t address = LTR55X_ADDR); 250 | #else 251 | LTR5XX(uint8_t sda, uint8_t scl, uint8_t address); 252 | #endif 253 | bool begin(Ltr5xx_Init_Basic_Para *init_base_para); 254 | bool begin(Ltr5xx_Init_Interrupt_Para *init_interrupt_para); 255 | bool setPsMode(uint8_t mode); 256 | uint16_t getPsValue(void); 257 | bool setAlsMode(uint8_t mode); 258 | uint16_t getAlsValue(void); 259 | uint8_t getPsIRQ(void); 260 | uint8_t getAlsIRQ(void); 261 | 262 | private: 263 | uint8_t _sda, _scl, _address; 264 | bool ltr5xx_read(uint8_t start_reg_addr, uint8_t *pdata, uint8_t size); 265 | bool ltr5xx_write(uint8_t start_reg_addr, uint8_t *pdata, uint8_t size); 266 | bool ps_set_led_pulse_freq(uint8_t value); 267 | bool ps_set_led_duty_cycle(uint8_t value); 268 | bool ps_set_led_peak_current(uint8_t value); 269 | bool ps_set_n_pulses(uint8_t value); 270 | bool ps_set_meas_rate(uint8_t value); 271 | bool als_set_gain(uint8_t value); 272 | #ifdef LTR55X 273 | bool als_set_integration_time(uint8_t value); 274 | #endif 275 | #ifdef LTR507 276 | bool als_set_adc_bit_width(uint8_t value); 277 | #endif 278 | bool als_set_measure_rate(uint8_t value); 279 | bool ltr5xx_set_interrupt_polarity(uint8_t polarity); 280 | bool ltr5xx_set_interrupt_mode(uint8_t mode); 281 | bool ps_set_threshold(uint16_t ps_upper_threshold, 282 | uint16_t ps_lower_threshold); 283 | bool als_set_threshold(uint16_t als_upper_threshold, 284 | uint16_t als_lower_threshold); 285 | bool ltr5xx_set_n_values_outside_trigger_interrupt( 286 | uint8_t ps_n_values_outside_trigger, 287 | uint8_t als_n_values_outside_trigger); 288 | }; 289 | 290 | #endif 291 | --------------------------------------------------------------------------------