Merge branch 'develop'

This commit is contained in:
GOB
2026-04-03 11:04:41 +09:00
25 changed files with 696 additions and 423 deletions
@@ -12,28 +12,28 @@ on:
branches:
- '*'
paths:
- 'src/unit/**.cpp'
- 'src/unit/**.hpp'
- 'src/unit/**.h'
- 'src/unit/**.c'
- 'src/**.cpp'
- 'src/**.hpp'
- 'src/**.h'
- 'src/**.c'
- 'examples/UnitUnified/**.ino'
- 'examples/UnitUnified/**.cpp'
- 'examples/UnitUnified/**.hpp'
- 'examples/UnitUnified/**.h'
- 'examples/UnitUnified/**.c'
- '**arduino-esp-v2-build-check.yml'
- '.github/workflows/arduino-esp-v2-build-check.yml'
pull_request:
paths:
- 'src/unit/**.cpp'
- 'src/unit/**.hpp'
- 'src/unit/**.h'
- 'src/unit/**.c'
- 'src/**.cpp'
- 'src/**.hpp'
- 'src/**.h'
- 'src/**.c'
- 'examples/UnitUnified/**.ino'
- 'examples/UnitUnified/**.cpp'
- 'examples/UnitUnified/**.hpp'
- 'examples/UnitUnified/**.h'
- 'examples/UnitUnified/**.c'
- '**arduino-esp-v2-build-check.yml'
- '.github/workflows/arduino-esp-v2-build-check.yml'
workflow_dispatch:
defaults:
@@ -48,11 +48,11 @@ jobs:
build:
name: ${{ matrix.unit }}:${{ matrix.sketch }}:${{matrix.board}}@${{matrix.platform-version}}
runs-on: ubuntu-latest
timeout-minutes: 5
timeout-minutes: 12
strategy:
fail-fast: false
#max-parallel: 1
max-parallel: 20
matrix:
platform-url:
- https://espressif.github.io/arduino-esp32/package_esp32_index.json
@@ -85,19 +85,27 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
# Build
- name: Prepare libraries list
id: libs
run: |
{
echo "yaml<<EOF"
echo "$REQUIRED_LIBRARIES" | tr ',' '\n' | while read -r lib; do
echo "- name: $lib"
done
echo "- source-path: ./"
echo "EOF"
} >> "$GITHUB_OUTPUT"
- name: Compile examples
uses: ArminJo/arduino-test-compile@master
uses: arduino/compile-sketches@v1
with:
arduino-board-fqbn: ${{ matrix.platform }}:${{ matrix.archi }}:${{ matrix.board }}
arduino-platform: ${{ matrix.platform }}:${{ matrix.archi }}@${{ matrix.platform-version }}
platform-url: ${{ matrix.platform-url }}
required-libraries: ${{ env.REQUIRED_LIBRARIES }}
extra-arduino-cli-args: ${{ matrix.cli-args }}
#build-properties: ${{ toJson(matrix.build-properties) }}
sketch-names: ${{ matrix.sketch }}.ino
sketch-names-find-start: ${{ env.SKETCH_NAMES_FIND_START }}/${{ matrix.unit }}
#sketches-exclude: ${{ matrix.sketches-exclude }}
fqbn: ${{ matrix.platform }}:${{ matrix.archi }}:${{ matrix.board }}
platforms: |
- name: ${{ matrix.platform }}:${{ matrix.archi }}
source-url: ${{ matrix.platform-url }}
version: ${{ matrix.platform-version }}
libraries: ${{ steps.libs.outputs.yaml }}
sketch-paths: |
- ${{ env.SKETCH_NAMES_FIND_START }}/${{ matrix.unit }}/${{ matrix.sketch }}
@@ -11,28 +11,28 @@ on:
branches:
- '*'
paths:
- 'src/unit/**.cpp'
- 'src/unit/**.hpp'
- 'src/unit/**.h'
- 'src/unit/**.c'
- 'src/**.cpp'
- 'src/**.hpp'
- 'src/**.h'
- 'src/**.c'
- 'examples/UnitUnified/**.ino'
- 'examples/UnitUnified/**.cpp'
- 'examples/UnitUnified/**.hpp'
- 'examples/UnitUnified/**.h'
- 'examples/UnitUnified/**.c'
- '**arduino-esp-v3-build-check.yml'
- '.github/workflows/arduino-esp-v3-build-check.yml'
pull_request:
paths:
- 'src/unit/**.cpp'
- 'src/unit/**.hpp'
- 'src/unit/**.h'
- 'src/unit/**.c'
- 'src/**.cpp'
- 'src/**.hpp'
- 'src/**.h'
- 'src/**.c'
- 'examples/UnitUnified/**.ino'
- 'examples/UnitUnified/**.cpp'
- 'examples/UnitUnified/**.hpp'
- 'examples/UnitUnified/**.h'
- 'examples/UnitUnified/**.c'
- '**arduino-esp-v3-build-check.yml'
- '.github/workflows/arduino-esp-v3-build-check.yml'
workflow_dispatch:
defaults:
@@ -47,11 +47,11 @@ jobs:
build:
name: ${{ matrix.unit }}:${{ matrix.sketch }}:${{matrix.board}}@${{matrix.platform-version}}
runs-on: ubuntu-latest
timeout-minutes: 5
timeout-minutes: 12
strategy:
fail-fast: false
#max-parallel: 1
max-parallel: 20
matrix:
platform-url:
- https://espressif.github.io/arduino-esp32/package_esp32_index.json
@@ -64,15 +64,17 @@ jobs:
- UnitMiniScales
board:
- arduino_nesso_n1
- m5stack_atom
- m5stack_atoms3
- m5stack_capsule
# - m5stack_cardputer
- m5stack_cardputer
- m5stack_core
- m5stack_core2
- m5stack_coreink
- m5stack_cores3
- m5stack_dial
- m5stack_dinmeter
- m5stack_fire
- m5stack_nanoc6
- m5stack_paper
@@ -84,13 +86,14 @@ jobs:
# - m5stack_stickc
- m5stack_stickc_plus
- m5stack_stickc_plus2
- m5stack_tab5
# - m5stack_timer_cam
# - m5stack_tough
# - m5stack_unit_cam
# - m5stack_unit_cams3
platform-version:
- 3.0.4
- 3.3.6
platform:
- esp32
@@ -101,19 +104,27 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
# Build
- name: Prepare libraries list
id: libs
run: |
{
echo "yaml<<EOF"
echo "$REQUIRED_LIBRARIES" | tr ',' '\n' | while read -r lib; do
echo "- name: $lib"
done
echo "- source-path: ./"
echo "EOF"
} >> "$GITHUB_OUTPUT"
- name: Compile examples
uses: ArminJo/arduino-test-compile@master
uses: arduino/compile-sketches@v1
with:
arduino-board-fqbn: ${{ matrix.platform }}:${{ matrix.archi }}:${{ matrix.board }}
arduino-platform: ${{ matrix.platform }}:${{ matrix.archi }}@${{ matrix.platform-version }}
platform-url: ${{ matrix.platform-url }}
required-libraries: ${{ env.REQUIRED_LIBRARIES }}
extra-arduino-cli-args: ${{ matrix.cli-args }}
#build-properties: ${{ toJson(matrix.build-properties) }}
sketch-names: ${{ matrix.sketch }}.ino
sketch-names-find-start: ${{ env.SKETCH_NAMES_FIND_START }}/${{ matrix.unit }}
#sketches-exclude: ${{ matrix.sketches-exclude }}
fqbn: ${{ matrix.platform }}:${{ matrix.archi }}:${{ matrix.board }}
platforms: |
- name: ${{ matrix.platform }}:${{ matrix.archi }}
source-url: ${{ matrix.platform-url }}
version: ${{ matrix.platform-version }}
libraries: ${{ steps.libs.outputs.yaml }}
sketch-paths: |
- ${{ env.SKETCH_NAMES_FIND_START }}/${{ matrix.unit }}/${{ matrix.sketch }}
+42 -29
View File
@@ -12,28 +12,28 @@ on:
branches:
- '*'
paths:
- 'src/unit/**.cpp'
- 'src/unit/**.hpp'
- 'src/unit/**.h'
- 'src/unit/**.c'
- 'src/**.cpp'
- 'src/**.hpp'
- 'src/**.h'
- 'src/**.c'
- 'examples/UnitUnified/**.ino'
- 'examples/UnitUnified/**.cpp'
- 'examples/UnitUnified/**.hpp'
- 'examples/UnitUnified/**.h'
- 'examples/UnitUnified/**.c'
- '**arduino-m5-build-check.yml'
- '.github/workflows/arduino-m5-build-check.yml'
pull_request:
paths:
- 'src/unit/**.cpp'
- 'src/unit/**.hpp'
- 'src/unit/**.h'
- 'src/unit/**.c'
- 'src/**.cpp'
- 'src/**.hpp'
- 'src/**.h'
- 'src/**.c'
- 'examples/UnitUnified/**.ino'
- 'examples/UnitUnified/**.cpp'
- 'examples/UnitUnified/**.hpp'
- 'examples/UnitUnified/**.h'
- 'examples/UnitUnified/**.c'
- '**arduino-m5-build-check.yml'
- '.github/workflows/arduino-m5-build-check.yml'
workflow_dispatch:
defaults:
@@ -48,11 +48,11 @@ jobs:
build:
name: ${{ matrix.unit }}:${{ matrix.sketch }}:${{matrix.board}}@${{matrix.platform-version}}
runs-on: ubuntu-latest
timeout-minutes: 5
timeout-minutes: 12
strategy:
fail-fast: false
# max-parallel: 1
max-parallel: 20
matrix:
platform-url:
- https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/arduino/package_m5stack_index.json
@@ -65,11 +65,12 @@ jobs:
- UnitMiniScales
board:
- arduino_nesso_n1
- m5stack_atom
- m5stack_atoms3
- m5stack_atoms3r
- m5stack_capsule
# - m5stack_cardputer
- m5stack_cardputer
- m5stack_core
- m5stack_core2
- m5stack_coreink
@@ -77,22 +78,27 @@ jobs:
- m5stack_dial
- m5stack_dinmeter
- m5stack_fire
- m5stack_nano_c6
# - m5stack_nano_h2
- m5stack_paper
- m5stack_papers3
# - m5stack_poe_cam
# - m5stack_stamp_c3
# - m5stack_stamp_pico
- m5stack_stamp_s3
# - m5stack_station
# - m5stack_stickc
- m5stack_stickc
- m5stack_stickc_plus
- m5stack_stickc_plus2
- m5stack_sticks3
- m5stack_tab5
# - m5stack_timer_cam
# - m5stack_tough
# - m5stack_unit_cam
# - m5stack_unit_cams3
platform-version:
- 2.1.2
- 3.2.5
platform:
- m5stack
@@ -103,20 +109,27 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
# Build
- name: Prepare libraries list
id: libs
run: |
{
echo "yaml<<EOF"
echo "$REQUIRED_LIBRARIES" | tr ',' '\n' | while read -r lib; do
echo "- name: $lib"
done
echo "- source-path: ./"
echo "EOF"
} >> "$GITHUB_OUTPUT"
- name: Compile examples
uses: ArminJo/arduino-test-compile@master
uses: arduino/compile-sketches@v1
with:
arduino-board-fqbn: ${{ matrix.platform }}:${{ matrix.archi }}:${{ matrix.board }}
arduino-platform: ${{ matrix.platform }}:${{ matrix.archi }}@${{ matrix.platform-version }}
platform-url: ${{ matrix.platform-url }}
required-libraries: ${{ env.REQUIRED_LIBRARIES }}
extra-arduino-cli-args: ${{ matrix.cli-args }}
#build-properties: ${{ toJson(matrix.build-properties) }}
sketch-names: ${{ matrix.sketch }}.ino
sketch-names-find-start: ${{ env.SKETCH_NAMES_FIND_START }}/${{ matrix.unit }}
#sketches-exclude: ${{ matrix.sketches-exclude }}
fqbn: ${{ matrix.platform }}:${{ matrix.archi }}:${{ matrix.board }}
platforms: |
- name: ${{ matrix.platform }}:${{ matrix.archi }}
source-url: ${{ matrix.platform-url }}
version: ${{ matrix.platform-version }}
libraries: ${{ steps.libs.outputs.yaml }}
sketch-paths: |
- ${{ env.SKETCH_NAMES_FIND_START }}/${{ matrix.unit }}/${{ matrix.sketch }}
+3 -5
View File
@@ -17,7 +17,7 @@ on:
- '**.h'
- '**.c'
- '**.inl'
- '**clang-format-check.yml'
- '.github/workflows/clang-format-check.yml'
- '**.clang-format'
pull_request:
paths:
@@ -27,7 +27,7 @@ on:
- '**.h'
- '**.c'
- '**.inl'
- '**clang-format-check.yml'
- '.github/workflows/clang-format-check.yml'
- '**.clang-format'
workflow_dispatch:
@@ -58,11 +58,9 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Run clang-format style check for C/C++/Protobuf programs.
uses: jidicula/clang-format-action@v4.10.2 # Using include-regex 10.x or later
uses: jidicula/clang-format-action@v4.16.0 # Using include-regex 10.x or later
with:
clang-format-version: '13'
check-path: ${{ matrix.path['check'] }}
+3 -1
View File
@@ -1,8 +1,10 @@
name: Deploy Doxygen docuemnt on GitHub Pages
name: Deploy Doxygen document on GitHub Pages
on: [release, workflow_dispatch]
# branches:
# - main
# - master
permissions:
contents: write
defaults:
run:
shell: bash
+27 -49
View File
@@ -8,30 +8,30 @@ on:
branches:
- '*'
paths:
- 'src/unit/**.cpp'
- 'src/unit/**.hpp'
- 'src/unit/**.h'
- 'src/unit/**.c'
- 'src/**.cpp'
- 'src/**.hpp'
- 'src/**.h'
- 'src/**.c'
- 'examples/UnitUnified/**.ino'
- 'examples/UnitUnified/**.cpp'
- 'examples/UnitUnified/**.hpp'
- 'examples/UnitUnified/**.h'
- 'examples/UnitUnified/**.c'
- '/platformio-build-check.yml'
- '**platformio.ini'
- '.github/workflows/platformio-build-check.yml'
- 'platformio.ini'
pull_request:
paths:
- 'src/unit/**.cpp'
- 'src/unit/**.hpp'
- 'src/unit/**.h'
- 'src/unit/**.c'
- 'src/**.cpp'
- 'src/**.hpp'
- 'src/**.h'
- 'src/**.c'
- 'examples/UnitUnified/**.ino'
- 'examples/UnitUnified/**.cpp'
- 'examples/UnitUnified/**.hpp'
- 'examples/UnitUnified/**.h'
- 'examples/UnitUnified/**.c'
- '**/platformio-build-check.yml'
- '**platformio.ini'
- '.github/workflows/platformio-build-check.yml'
- 'platformio.ini'
workflow_dispatch:
defaults:
@@ -46,12 +46,12 @@ jobs:
build:
name: ${{ matrix.unit }}:${{ matrix.example }}@${{ matrix.board }}:${{ matrix.framework }}:${{ matrix.espressif32 }}
runs-on: ubuntu-latest
timeout-minutes: 5
timeout-minutes: 12
strategy:
fail-fast: false
#max-parallel: 1
max-parallel: 20
matrix:
example:
- PlotToSerial
@@ -67,58 +67,36 @@ jobs:
- Fire
- StampS3
- Dial
- AtomMatrix
- Atom
- AtomS3
- AtomS3R
- NanoC6
- StickCPlus
- StickCPlus2
- StickS3
- Paper
- CoreInk
- Cardputer
- Tab5
- NessoN1
framework:
- Arduino
espressif32:
- latest
# - '5_4_0'
# - '4_4_0'
# exclude:
# - board: CoreS3
# espressif32: '5_4_0'
# - board: CoreS3
# espressif32: '4_4_0'
# - board: StampS3
# espressif32: '5_4_0'
# - board: StampS3
# espressif32: '4_4_0'
# - board: AtomS3
# espressif32: '5_4_0'
# - board: AtomS3
# espressif32: '4_4_0'
# - board: Dial
# espressif32: '5_4_0'
# - board: Dial
# espressif32: '4_4_0'
# - board: NanoC6
# espressif32: '5_4_0'
# - board: NanoC6
# espressif32: '4_4_0'
# - board: StickCPlus
# espressif32: '5_4_0'
# - board: StickCPlus
# espressif32: '4_4_0'
# - board: Paper
# espressif32: '5_4_0'
# - board: Paper
# espressif32: '4_4_0'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
ref: ${{ github.event.pull_request.head.sha }}
python-version: '3.10'
- name: Install intelhex
run: pip install intelhex
- name: Build examples
uses: karniv00l/platformio-run-action@v1
+21
View File
@@ -30,3 +30,24 @@
*.exe
*.out
*.app
# Doxygen
docs/html/
# PlatformIO
.pio/
# IDE
.vscode/
# macOS
.DS_Store
# Temporary
tmp/
# Secrets
.env*
*.pem
*.key
*.cert
+1 -1
View File
@@ -17,7 +17,7 @@ Mini Scales Unit is an integrated mini weighing unit that combines a 5kg weighin
See also examples using conventional methods here.
- [Unit WeightI2C & Datasheet](https://docs.m5stack.com/en/unit/Unit-Weight%20I2C)
- [Unit MiniScales & Datashhet](https://docs.m5stack.com/en/unit/Unit-Mini%20Scales)
- [Unit MiniScales & Datasheet](https://docs.m5stack.com/en/unit/Unit-Mini%20Scales)
### Required Libraries:
- [M5UnitUnified](https://github.com/m5stack/M5UnitUnified)
+1 -1
View File
@@ -42,7 +42,7 @@ DOXYFILE_ENCODING = UTF-8
# title of most generated pages and in a few other places.
# The default value is: My Project.
PROJECT_NAME = M5Unit-WEIGHT
PROJECT_NAME = "M5Unit-WEIGHT"
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
# could be handy for archiving the generated documentation or if some version
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/bash
# Please execute on repositry root
# Please execute on repository root
## Get version from library.properties
## Get git rev of HEAD
@@ -10,6 +10,7 @@
#include <M5UnitUnified.h>
#include <M5UnitUnifiedWEIGHT.h>
#include <M5Utility.h>
#include <M5HAL.hpp>
using m5::unit::weighti2c::Mode;
@@ -21,47 +22,86 @@ m5::unit::UnitMiniScales unit;
uint32_t idx{};
constexpr Mode mode_table[] = {Mode::Float, Mode::Int};
constexpr lgfx::rgb888_t color_table[] = {
{128, 16, 32},
{32, 128, 16},
{16, 32, 128},
{0, 0, 0},
};
constexpr float WEIGHT_MIN{0.0f};
constexpr float WEIGHT_MAX{5000.0f}; // MiniScales: 5kg load cell
bool led_enabled{true};
} // namespace
void setup()
{
m5::utility::delay(2000);
M5.begin();
M5.setTouchButtonHeightByRatio(100);
auto pin_num_sda = M5.getPin(m5::pin_name_t::port_a_sda);
auto pin_num_scl = M5.getPin(m5::pin_name_t::port_a_scl);
M5_LOGI("getPin: SDA:%u SCL:%u", pin_num_sda, pin_num_scl);
Wire.begin(pin_num_sda, pin_num_scl, 100 * 1000U);
// The screen shall be in landscape mode
if (lcd.height() > lcd.width()) {
lcd.setRotation(1);
}
if (!Units.add(unit, Wire) || !Units.begin()) {
auto board = M5.getBoard();
// NessoN1: Arduino Wire (I2C_NUM_0) cannot be used for GROVE port.
// Wire is used by M5Unified In_I2C for internal devices (IOExpander etc.).
// Wire1 exists but is reserved for HatPort — cannot be used for GROVE.
// Reconfiguring Wire to GROVE pins breaks In_I2C, causing ESP_ERR_INVALID_STATE in M5.update().
// Solution: Use SoftwareI2C via M5HAL (bit-banging) for the GROVE port.
// NanoC6: Wire.begin() on GROVE pins conflicts with m5::I2C_Class registered by Ex_I2C.setPort()
// on the same I2C_NUM_0, causing sporadic NACK errors.
// Solution: Use M5.Ex_I2C (m5::I2C_Class) directly instead of Arduino Wire.
bool unit_ready{};
if (board == m5::board_t::board_ArduinoNessoN1) {
// NessoN1: GROVE is on port_b (GPIO 5/4), not port_a (which maps to Wire pins 8/10)
auto pin_num_sda = M5.getPin(m5::pin_name_t::port_b_out);
auto pin_num_scl = M5.getPin(m5::pin_name_t::port_b_in);
M5_LOGI("getPin(M5HAL): SDA:%u SCL:%u", pin_num_sda, pin_num_scl);
m5::hal::bus::I2CBusConfig i2c_cfg;
i2c_cfg.pin_sda = m5::hal::gpio::getPin(pin_num_sda);
i2c_cfg.pin_scl = m5::hal::gpio::getPin(pin_num_scl);
auto i2c_bus = m5::hal::bus::i2c::getBus(i2c_cfg);
M5_LOGI("Bus:%d", i2c_bus.has_value());
unit_ready = Units.add(unit, i2c_bus ? i2c_bus.value() : nullptr) && Units.begin();
} else if (board == m5::board_t::board_M5NanoC6) {
// NanoC6: Use M5.Ex_I2C (m5::I2C_Class, not Arduino Wire)
M5_LOGI("Using M5.Ex_I2C");
unit_ready = Units.add(unit, M5.Ex_I2C) && Units.begin();
} else {
auto pin_num_sda = M5.getPin(m5::pin_name_t::port_a_sda);
auto pin_num_scl = M5.getPin(m5::pin_name_t::port_a_scl);
M5_LOGI("getPin: SDA:%u SCL:%u", pin_num_sda, pin_num_scl);
Wire.end();
Wire.begin(pin_num_sda, pin_num_scl, 100 * 1000U);
unit_ready = Units.add(unit, Wire) && Units.begin();
}
if (!unit_ready) {
M5_LOGE("Failed to begin");
lcd.clear(TFT_RED);
lcd.fillScreen(TFT_RED);
while (true) {
m5::utility::delay(10000);
}
}
float gap{};
unit.readGap(gap);
M5_LOGI("GAP:%f", gap);
#if 0
// Restore factory GAP (enable temporarily if GAP was corrupted)
unit.writeGap(400.0f);
M5_LOGW("Wrote GAP=400.0");
#endif
unit.resetOffset();
M5_LOGI("M5UnitUnified has been begun");
M5_LOGI("%s", Units.debugInfo().c_str());
lcd.clear(TFT_DARKGREEN);
lcd.fillScreen(TFT_DARKGREEN);
}
void loop()
{
M5.update();
auto touch = M5.Touch.getDetail();
Units.update();
if (unit.updated()) {
// Can be checked e.g. by serial plotters
if (!idx) {
@@ -69,19 +109,30 @@ void loop()
} else {
M5.Log.printf(">iWeight:%d\n", unit.iweight());
}
// Update LED color based on weight: Blue(min) -> Red(max)
if (led_enabled) {
float w = unit.weight();
float t = (w - WEIGHT_MIN) / (WEIGHT_MAX - WEIGHT_MIN);
t = std::fmin(1.0f, std::fmax(0.0f, t));
uint8_t r = static_cast<uint8_t>(t * 255);
uint8_t b = static_cast<uint8_t>((1.0f - t) * 255);
unit.writeLEDColor(r, 0, b);
}
}
// Button on MiniScales
// Button on MiniScales: toggle LED ON/OFF
if (unit.wasPressed()) {
static uint32_t cidx{};
unit.writeLEDColor((uint32_t)color_table[cidx]);
cidx = (cidx + 1) % m5::stl::size(color_table);
led_enabled = !led_enabled;
if (!led_enabled) {
unit.writeLEDColor(0, 0, 0);
}
}
// Behavior when BtnA is clicked changes depending on the value.
constexpr int32_t BTN_A_FUNCTION{-1};
constexpr int32_t BTN_A_FUNCTION{0};
if (M5.BtnA.wasClicked() || touch.wasClicked()) {
if (M5.BtnA.wasClicked()) {
switch (BTN_A_FUNCTION) {
case 0: { // Change mode
if (++idx > 1) {
@@ -95,7 +146,7 @@ void loop()
unit.stopPeriodicMeasurement();
char txt[16]{};
if (unit.measureSingleshot(txt)) {
M5.Log.printf(">Singleshort:%s\n", txt);
M5.Log.printf(">Singleshot:%s\n", txt);
} else {
M5_LOGE("Failed to measure");
}
@@ -10,6 +10,7 @@
#include <M5UnitUnified.h>
#include <M5UnitUnifiedWEIGHT.h>
#include <M5Utility.h>
#include <M5HAL.hpp>
using m5::unit::weighti2c::Mode;
@@ -25,34 +26,76 @@ constexpr Mode mode_table[] = {Mode::Float, Mode::Int};
void setup()
{
m5::utility::delay(2000);
M5.begin();
M5.setTouchButtonHeightByRatio(100);
auto pin_num_sda = M5.getPin(m5::pin_name_t::port_a_sda);
auto pin_num_scl = M5.getPin(m5::pin_name_t::port_a_scl);
M5_LOGI("getPin: SDA:%u SCL:%u", pin_num_sda, pin_num_scl);
Wire.begin(pin_num_sda, pin_num_scl, 100 * 1000U);
// The screen shall be in landscape mode
if (lcd.height() > lcd.width()) {
lcd.setRotation(1);
}
if (!Units.add(unit, Wire) || !Units.begin()) {
auto board = M5.getBoard();
// NessoN1: Arduino Wire (I2C_NUM_0) cannot be used for GROVE port.
// Wire is used by M5Unified In_I2C for internal devices (IOExpander etc.).
// Wire1 exists but is reserved for HatPort — cannot be used for GROVE.
// Reconfiguring Wire to GROVE pins breaks In_I2C, causing ESP_ERR_INVALID_STATE in M5.update().
// Solution: Use SoftwareI2C via M5HAL (bit-banging) for the GROVE port.
// NanoC6: Wire.begin() on GROVE pins conflicts with m5::I2C_Class registered by Ex_I2C.setPort()
// on the same I2C_NUM_0, causing sporadic NACK errors.
// Solution: Use M5.Ex_I2C (m5::I2C_Class) directly instead of Arduino Wire.
bool unit_ready{};
if (board == m5::board_t::board_ArduinoNessoN1) {
// NessoN1: GROVE is on port_b (GPIO 5/4), not port_a (which maps to Wire pins 8/10)
auto pin_num_sda = M5.getPin(m5::pin_name_t::port_b_out);
auto pin_num_scl = M5.getPin(m5::pin_name_t::port_b_in);
M5_LOGI("getPin(M5HAL): SDA:%u SCL:%u", pin_num_sda, pin_num_scl);
m5::hal::bus::I2CBusConfig i2c_cfg;
i2c_cfg.pin_sda = m5::hal::gpio::getPin(pin_num_sda);
i2c_cfg.pin_scl = m5::hal::gpio::getPin(pin_num_scl);
auto i2c_bus = m5::hal::bus::i2c::getBus(i2c_cfg);
M5_LOGI("Bus:%d", i2c_bus.has_value());
unit_ready = Units.add(unit, i2c_bus ? i2c_bus.value() : nullptr) && Units.begin();
} else if (board == m5::board_t::board_M5NanoC6) {
// NanoC6: Use M5.Ex_I2C (m5::I2C_Class, not Arduino Wire)
M5_LOGI("Using M5.Ex_I2C");
unit_ready = Units.add(unit, M5.Ex_I2C) && Units.begin();
} else {
auto pin_num_sda = M5.getPin(m5::pin_name_t::port_a_sda);
auto pin_num_scl = M5.getPin(m5::pin_name_t::port_a_scl);
M5_LOGI("getPin: SDA:%u SCL:%u", pin_num_sda, pin_num_scl);
Wire.end();
Wire.begin(pin_num_sda, pin_num_scl, 100 * 1000U);
unit_ready = Units.add(unit, Wire) && Units.begin();
}
if (!unit_ready) {
M5_LOGE("Failed to begin");
lcd.clear(TFT_RED);
lcd.fillScreen(TFT_RED);
while (true) {
m5::utility::delay(10000);
}
}
float gap{};
unit.readGap(gap);
M5_LOGI("GAP:%f", gap);
#if 0
// Restore factory GAP (enable temporarily if GAP was corrupted)
unit.writeGap(400.0f);
M5_LOGW("Wrote GAP=400.0");
#endif
unit.resetOffset();
M5_LOGI("M5UnitUnified has been begun");
M5_LOGI("%s", Units.debugInfo().c_str());
lcd.clear(TFT_DARKGREEN);
lcd.fillScreen(TFT_DARKGREEN);
}
void loop()
{
M5.update();
auto touch = M5.Touch.getDetail();
Units.update();
if (unit.updated()) {
@@ -65,9 +108,9 @@ void loop()
}
// Behavior when BtnA is clicked changes depending on the value.
constexpr int32_t BTN_A_FUNCTION{-1};
constexpr int32_t BTN_A_FUNCTION{0};
if (M5.BtnA.wasClicked() || touch.wasClicked()) {
if (M5.BtnA.wasClicked()) {
switch (BTN_A_FUNCTION) {
case 0: { // Change mode
if (++idx > 1) {
@@ -81,7 +124,7 @@ void loop()
unit.stopPeriodicMeasurement();
char txt[16]{};
if (unit.measureSingleshot(txt)) {
M5.Log.printf(">Singleshort:%s\n", txt);
M5.Log.printf(">Singleshot:%s\n", txt);
} else {
M5_LOGE("Failed to measure");
}
+4 -4
View File
@@ -1,19 +1,19 @@
{
"name": "M5Unit-WEIGHT",
"description": "Library for M5Stack UNIT WEIGHT using M5UnitUnified",
"keywords": "M5Stack UNIT WEIGHT,M5UnitUnified",
"keywords": "m5stack, m5unitunified, weight, weighti2c, miniscales, load-cell, i2c",
"authors": {
"name": "M5Stack",
"url": "http://www.m5stack.com"
"url": "https://www.m5stack.com"
},
"repository": {
"type": "git",
"url": "https://github.com/m5stack/M5Unit-WEIGHT.git"
},
"dependencies": {
"m5stack/M5UnitUnified": ">=0.1.0"
"m5stack/M5UnitUnified": ">=0.4.4"
},
"version": "0.1.0",
"version": "0.1.1",
"frameworks": [
"arduino"
],
+4 -4
View File
@@ -1,11 +1,11 @@
name=M5Unit-WEIGHT
version=0.1.0
version=0.1.1
author=M5Stack
maintainer=M5Stack
sentence=Library for M5Stack UNIT METER using M5UnitUnified
paragraph=See more on http://M5Stack.com
sentence=Library for M5Stack UNIT WEIGHT using M5UnitUnified
paragraph=Supports UnitWeightI2C (SKU:U180) and MiniScales (SKU:U177) for weight measurement with configurable filters and calibration.
category=Device Control
url=https://github.com/m5stack/M5Unit-WEIGHT.git
url=https://github.com/m5stack/M5Unit-WEIGHT
architectures=esp32
includes=M5UnitUnifiedWEIGHT.h
depends=M5UnitUnified,M5Utility,M5HAL
+213 -131
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -5,6 +5,7 @@
*/
/*!
@file M5UnitUnifiedWEIGHT.h
@brief Main header for the M5Unit-WEIGHT library
*/
#ifndef M5_UNIT_UNIFIED_WEIGHT_H
#define M5_UNIT_UNIFIED_WEIGHT_H
+1 -1
View File
@@ -18,7 +18,7 @@
/*!
@namespace m5
@brief Top level namespace of M5stack
@brief Top level namespace of M5Stack
*/
namespace m5 {
+8 -15
View File
@@ -25,7 +25,7 @@ const types::attr_t UnitMiniScales::attr{attribute::AccessI2C};
void UnitMiniScales::update(const bool force)
{
UnitWeightI2C::update(force);
if (_cfg.manage_button_status) {
if (_cfg_mini.manage_button_status) {
_prev_button = _button;
readButtonStatus(_button);
}
@@ -37,7 +37,7 @@ bool UnitMiniScales::readLEDColor(uint32_t& rgb32)
uint8_t r{}, g{}, b{};
if (readLEDColor(r, g, b)) {
rgb32 = (r << 16) | (g << 8) | b;
rgb32 = (static_cast<uint32_t>(r) << 16) | (static_cast<uint32_t>(g) << 8) | static_cast<uint32_t>(b);
return true;
}
return false;
@@ -64,20 +64,13 @@ bool UnitMiniScales::writeLEDColor(const uint8_t r, const uint8_t g, const uint8
bool UnitMiniScales::writeLEDColor(const uint16_t rgb16)
{
// Same as M5GFX colortype rgb565_t
union {
struct {
uint16_t b5 : 5;
uint16_t g6 : 6;
uint16_t r5 : 5;
};
uint16_t raw;
} rgb565{};
rgb565.raw = rgb16;
uint8_t r = (rgb565.r5 << 3) + (rgb565.r5 >> 2);
uint8_t g = (rgb565.g6 << 2) + (rgb565.g6 >> 4);
uint8_t b = (rgb565.b5 << 3) + (rgb565.b5 >> 2);
const uint8_t r5 = static_cast<uint8_t>((rgb16 >> 11) & 0x1F);
const uint8_t g6 = static_cast<uint8_t>((rgb16 >> 5) & 0x3F);
const uint8_t b5 = static_cast<uint8_t>(rgb16 & 0x1F);
M5_LIB_LOGE("%x %u/%u/%u", rgb16, r, g, b);
uint8_t r = static_cast<uint8_t>((r5 << 3) + (r5 >> 2));
uint8_t g = static_cast<uint8_t>((g6 << 2) + (g6 >> 4));
uint8_t b = static_cast<uint8_t>((b5 << 3) + (b5 >> 2));
return writeLEDColor(r, g, b);
}
+13 -9
View File
@@ -39,20 +39,24 @@ public:
{
}
/*!
@brief Update the cached measurement and button state
@param force Force the update even when the normal timing check would skip it
*/
virtual void update(const bool force = false) override;
///@name Settings for begin
///@{
/*! @brief Gets the configration */
/*! @brief Gets the configuration */
inline config_t config()
{
return this->_cfg;
return _cfg_mini;
}
//! @brief Set the configration
//! @brief Set the configuration
inline void config(const config_t& cfg)
{
_cfg = cfg;
UnitWeightI2C::config((UnitWeightI2C::config_t)(this->_cfg));
_cfg_mini = cfg;
UnitWeightI2C::config(static_cast<UnitWeightI2C::config_t>(_cfg_mini));
}
///@}
@@ -97,11 +101,11 @@ public:
bool writeLEDColor(const uint8_t r, const uint8_t g, const uint8_t b);
///@}
////@name Button
///@name Button
///@{
/*!
@brief Read the button status
@param[out] pressse Press if true
@param[out] press Press if true
@return True if successful
*/
bool readButtonStatus(bool& press);
@@ -128,7 +132,7 @@ public:
@return True if released
@note The state is managed by update
*/
inline bool wasReleased()
inline bool wasReleased() const
{
return !_button && (_button != _prev_button);
}
@@ -136,7 +140,7 @@ public:
private:
bool _button{}, _prev_button{};
config_t _cfg{};
config_t _cfg_mini{};
};
namespace miniscales {
+22 -5
View File
@@ -34,8 +34,21 @@ bool UnitWeightI2C::begin()
}
}
// WeightI2C/MiniScales use HX711. Wait for power-up/reset settling (RATE=0: up to about 400ms)
// so the first weight readings are stable.
m5::utility::delay(400);
uint8_t ver{};
if (!read_register8(FIRMWARE_VERSION_REG, ver) || ver == 0) {
bool ready{};
auto timeout_at = m5::utility::millis() + 1500;
do {
ready = read_register8(FIRMWARE_VERSION_REG, ver) && ver != 0;
if (ready) {
break;
}
m5::utility::delay(100);
} while (m5::utility::millis() <= timeout_at);
if (!ready) {
M5_LIB_LOGE("Failed to read firmware version %x", ver);
return false;
}
@@ -103,7 +116,10 @@ bool UnitWeightI2C::measureSingleshot(char* buf)
}
if (buf) {
buf[0] = '\0';
return read_register(WEIGHTX100_STRING_REG, (uint8_t*)buf, 16U);
// Spec: max 15 characters + '\0'
auto ok = read_register(WEIGHTX100_STRING_REG, reinterpret_cast<uint8_t*>(buf), 16U);
buf[15] = '\0'; // Defensive termination even if firmware returns malformed payload
return ok;
}
return false;
}
@@ -112,7 +128,7 @@ bool UnitWeightI2C::readGap(float& gap)
{
uint8_t buf[4]{};
if (read_register(GAP_REG, buf, 4U)) {
gap = *(float*)buf;
std::memcpy(&gap, buf, sizeof(buf));
return true;
}
return false;
@@ -121,7 +137,7 @@ bool UnitWeightI2C::readGap(float& gap)
bool UnitWeightI2C::writeGap(const float gap, const uint32_t duration)
{
uint8_t buf[4]{};
std::memcpy(buf, (uint8_t*)&gap, 4);
std::memcpy(buf, &gap, sizeof(buf));
if (writeRegister(GAP_REG, buf, 4U)) {
m5::utility::delay(duration);
return true;
@@ -138,7 +154,8 @@ bool UnitWeightI2C::readRawADC(int32_t& value)
{
uint8_t buf[4];
if (read_register(RAW_ADC_REG, buf, 4U)) {
value = buf[0] | ((uint32_t)buf[1] << 8) | ((uint32_t)buf[2] << 16) | ((uint32_t)buf[3] << 24);
value = static_cast<int32_t>(static_cast<uint32_t>(buf[0]) | (static_cast<uint32_t>(buf[1]) << 8) |
(static_cast<uint32_t>(buf[2]) << 16) | (static_cast<uint32_t>(buf[3]) << 24));
return true;
}
return false;

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