Compare commits
10 Commits
main
...
adc-testin
| Author | SHA1 | Date |
|---|---|---|
|
|
84e7d02db8 | |
|
|
cc6b4488ee | |
|
|
928a176e7c | |
|
|
8255b2a672 | |
|
|
d48281436e | |
|
|
dcb73c0a25 | |
|
|
2c21f1f9cb | |
|
|
a2afec52e2 | |
|
|
2cc258e8e2 | |
|
|
a77298b3a6 |
|
|
@ -1,65 +1 @@
|
||||||
**/build
|
**/build
|
||||||
|
|
||||||
# Zephyr build directories
|
|
||||||
build/
|
|
||||||
build-*/
|
|
||||||
*/build/
|
|
||||||
**/build/
|
|
||||||
|
|
||||||
# Zephyr out-of-tree build directories
|
|
||||||
out-of-tree-build/
|
|
||||||
|
|
||||||
# Files generated by the build system
|
|
||||||
zephyr.elf
|
|
||||||
zephyr.bin
|
|
||||||
zephyr.hex
|
|
||||||
zephyr.map
|
|
||||||
zephyr.strip
|
|
||||||
zephyr.lst
|
|
||||||
zephyr.asm
|
|
||||||
zephyr.stat
|
|
||||||
zephyr.a
|
|
||||||
zephyr.o
|
|
||||||
*.o
|
|
||||||
*.a
|
|
||||||
*.so
|
|
||||||
*.so.*
|
|
||||||
*.dll
|
|
||||||
*.exe
|
|
||||||
|
|
||||||
# Cmake
|
|
||||||
CMakeCache.txt
|
|
||||||
CMakeFiles/
|
|
||||||
cmake_install.cmake
|
|
||||||
CTestTestfile.cmake
|
|
||||||
compile_commands.json
|
|
||||||
|
|
||||||
# Kconfig generated files
|
|
||||||
.config
|
|
||||||
.config.old
|
|
||||||
autoconf.h
|
|
||||||
|
|
||||||
# Doxygen
|
|
||||||
doxygen/
|
|
||||||
|
|
||||||
# west
|
|
||||||
.west/
|
|
||||||
west.yml.bak
|
|
||||||
|
|
||||||
# Editor-specific files
|
|
||||||
.vscode/
|
|
||||||
.idea/
|
|
||||||
*.swp
|
|
||||||
*~
|
|
||||||
*.bak
|
|
||||||
*.orig
|
|
||||||
|
|
||||||
# Python
|
|
||||||
__pycache__/
|
|
||||||
*.pyc
|
|
||||||
|
|
||||||
# Mac OS X
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
# Windows
|
|
||||||
Thumbs.db
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
[submodule "software/modules/zephyr_vnd7050aj_driver"]
|
|
||||||
path = software/modules/zephyr_vnd7050aj_driver
|
|
||||||
url = https://gitea.iten.pro/edi/zephyr_vnd7050aj_driver.git
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
{
|
|
||||||
"version": "2.0.0",
|
|
||||||
"tasks": [
|
|
||||||
{
|
|
||||||
"type": "shell",
|
|
||||||
"label": "Build Zephyr app",
|
|
||||||
"command": "west build -b weact_stm32g431_core .",
|
|
||||||
"group": "build",
|
|
||||||
"problemMatcher": [
|
|
||||||
"$gcc"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -39,7 +39,7 @@ Die Slave-Nodes sind die Arbeitseinheiten im Feld. Um bei der Fertigung kleiner
|
||||||
|
|
||||||
* **Mikrocontroller:** Ein `STM32G431PB`. Dieser ist zwar leistungsstark, bietet aber alle nötigen Peripherien (mehrere UARTs, ADCs, CAN) und ermöglicht ein einheitliches Hardware- und Software-Design.
|
* **Mikrocontroller:** Ein `STM32G431PB`. Dieser ist zwar leistungsstark, bietet aber alle nötigen Peripherien (mehrere UARTs, ADCs, CAN) und ermöglicht ein einheitliches Hardware- und Software-Design.
|
||||||
* **Peripherie pro Node:**
|
* **Peripherie pro Node:**
|
||||||
* **Zwei High-Side Ausgänge (+12V):** Realisiert über einen `VND7050AJ`. Perfekt zur Ansteuerung der 12V-Motorventile (`Öffnen`/`Schliessen`). Die `Sense`-Leitung des Treibers wird über einen AD-Wandler ausgelesen, um durch Messung des Motorstroms eine Endlagen-Erkennung ohne physische Endschalter zu realisieren (Motorstrom im Stillstand ≈ 0). Zusätzlich können die Temperatur und die Versorgungsspannung des Treibers ausgelesen werden.
|
* **Zwei High-Side Ausgänge (+12V):** Realisiert über einen `VND7050AJ`. Perfekt zur Ansteuerung der 12V-Motorventile (`Öffnen`/`Schliessen`). Die `Sense`-Leitung des Treibers wird über einen AD-Wandler ausgelesen, um durch Messung des Motorstroms eine Endlagen-Erkennung ohne physische Endschalter zu realisieren (Motorstrom im Stillstand ≈ 0).
|
||||||
* **Zwei Low-Side Ausgänge (0V):** Über N-Kanal-MOSFETs geschaltete Ausgänge. Nutzbar zur Ansteuerung von 12V-LEDs in Tastern oder zum Schalten des Halbleiter-Relais für die Pumpe.
|
* **Zwei Low-Side Ausgänge (0V):** Über N-Kanal-MOSFETs geschaltete Ausgänge. Nutzbar zur Ansteuerung von 12V-LEDs in Tastern oder zum Schalten des Halbleiter-Relais für die Pumpe.
|
||||||
* **Zwei digitale Eingänge:** Direkte, geschützte Eingänge am Controller zum Anschluss von Tastern oder den kapazitiven NPN-Sensoren.
|
* **Zwei digitale Eingänge:** Direkte, geschützte Eingänge am Controller zum Anschluss von Tastern oder den kapazitiven NPN-Sensoren.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,38 +29,33 @@ Alle Register sind in einer einzigen, durchgehenden Liste pro Register-Typ (`Inp
|
||||||
|
|
||||||
| Adresse (hex) | Name | Zugehörigkeit | Beschreibung |
|
| Adresse (hex) | Name | Zugehörigkeit | Beschreibung |
|
||||||
| :------------ | :----------------------------- | :---------------- | :---------------------------------------------------------------------------------------------------------------------------------------- |
|
| :------------ | :----------------------------- | :---------------- | :---------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **0x0000** | `VALVE_STATE_MOVEMENT` | Ventil | Kombiniertes Status-Register. **High-Byte**: Bewegung (`0`=Idle, `1`=Öffnet, `2`=Schliesst, `3`=Fehler). **Low-Byte**: Zustand (`0`=Geschlossen, `1`=Geöffnet). |
|
| **0x0000** | `VENTIL_ZUSTAND_BEWEGUNG` | Ventil | Kombiniertes Status-Register. **High-Byte**: Bewegung (`0`=Idle, `1`=Öffnet, `2`=Schliesst, `3`=Fehler). **Low-Byte**: Zustand (`0`=Geschlossen, `1`=Geöffnet). |
|
||||||
| **0x0001** | `REG_INPUT_MOTOR_OPEN_CURRENT_MA` | Ventil | Motorstrom beim Öffnen in Milliampere (mA). |
|
| **0x0001** | `MOTORSTROM_MA` | Ventil | Aktueller Motorstrom in Milliampere (mA). |
|
||||||
| **0x0002** | `REG_INPUT_MOTOR_CLOSE_CURRENT_MA` | Ventil | Motorstrom beim Schließen in Milliampere (mA). |
|
| **0x0020** | `DIGITAL_EINGAENGE_ZUSTAND` | Eingänge | Bitmaske der digitalen Eingänge. Bit 0: Eingang 1, Bit 1: Eingang 2. `1`=Aktiv. |
|
||||||
| **0x0020** | `REG_INPUT_DIGITAL_INPUTS_STATE` | Eingänge | Bitmaske der digitalen Eingänge. Bit 0: Eingang 1, Bit 1: Eingang 2. `1`=Aktiv. |
|
| **0x0021** | `TASTER_EVENTS` | Eingänge | Event-Flags für Taster (Clear-on-Read). Bit 0: Taster 1 gedrückt. Bit 1: Taster 2 gedrückt. |
|
||||||
| **0x0021** | `REG_INPUT_BUTTON_EVENTS` | Eingänge | Event-Flags für Taster (Clear-on-Read). Bit 0: Taster 1 gedrückt. Bit 1: Taster 2 gedrückt. |
|
| **0x00F0** | `FIRMWARE_VERSION_MAJOR_MINOR` | System | z.B. `0x0102` für v1.2. |
|
||||||
| **0x00F0** | `REG_INPUT_FIRMWARE_VERSION_MAJOR_MINOR` | System | z.B. `0x0102` für v1.2. |
|
| **0x00F1** | `FIRMWARE_VERSION_PATCH` | System | z.B. `3` für v1.2.3. |
|
||||||
| **0x00F1** | `REG_INPUT_FIRMWARE_VERSION_PATCH` | System | z.B. `3` für v1.2.3. |
|
| **0x00F2** | `DEVICE_STATUS` | System | `0`=OK, `1`=Allgemeiner Fehler. |
|
||||||
| **0x00F2** | `REG_INPUT_DEVICE_STATUS` | System | `0`=OK, `1`=Allgemeiner Fehler. |
|
| **0x00F3** | `UPTIME_SECONDS_LOW` | System | Untere 16 Bit der Uptime in Sekunden. |
|
||||||
| **0x00F3** | `REG_INPUT_UPTIME_SECONDS_LOW` | System | Untere 16 Bit der Uptime in Sekunden. |
|
| **0x00F4** | `UPTIME_SECONDS_HIGH` | System | Obere 16 Bit der Uptime. |
|
||||||
| **0x00F4** | `REG_INPUT_UPTIME_SECONDS_HIGH` | System | Obere 16 Bit der Uptime. |
|
| **0x00F5** | `SUPPLY_VOLTAGE_MV` | System | Aktuelle Versorgungsspannung in Millivolt (mV). |
|
||||||
| **0x00F5** | `REG_INPUT_SUPPLY_VOLTAGE_MV` | System | Aktuelle Versorgungsspannung in Millivolt (mV). |
|
| **0x0100** | `FWU_LAST_CHUNK_CRC` | Firmware-Update | Enthält den CRC16 des zuletzt im Puffer empfangenen Daten-Chunks. |
|
||||||
| **0x0100** | `REG_INPUT_FWU_LAST_CHUNK_CRC` | Firmware-Update | Enthält den CRC16 des zuletzt im Puffer empfangenen Daten-Chunks. |
|
|
||||||
|
|
||||||
## 3. Holding Registers (4xxxx, Read/Write)
|
## 3. Holding Registers (4xxxx, Read/Write)
|
||||||
|
|
||||||
| Adresse (hex) | Name | Zugehörigkeit | Beschreibung |
|
| Adresse (hex) | Name | Zugehörigkeit | Beschreibung |
|
||||||
| :------------ | :---------------------------- | :---------------- | :---------------------------------------------------------------------------------------------------------------------------------------- |
|
| :------------ | :---------------------------- | :---------------- | :---------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **0x0000** | `REG_HOLDING_VALVE_COMMAND` | Ventil | `1`=Öffnen, `2`=Schliessen, `0`=Bewegung stoppen. |
|
| **0x0000** | `VENTIL_BEFEHL` | Ventil | `1`=Öffnen, `2`=Schliessen, `0`=Bewegung stoppen. |
|
||||||
| **0x0001** | `REG_HOLDING_MAX_OPENING_TIME_S` | Ventil | Sicherheits-Timeout in Sekunden für den Öffnen-Vorgang. |
|
| **0x0001** | `MAX_OEFFNUNGSZEIT_S` | Ventil | Sicherheits-Timeout in Sekunden für den Öffnen-Vorgang. |
|
||||||
| **0x0002** | `REG_HOLDING_MAX_CLOSING_TIME_S` | Ventil | Sicherheits-Timeout in Sekunden für den Schliessen-Vorgang. |
|
| **0x0002** | `MAX_SCHLIESSZEIT_S` | Ventil | Sicherheits-Timeout in Sekunden für den Schliessen-Vorgang. |
|
||||||
| **0x0003** | `REG_HOLDING_END_CURRENT_THRESHOLD_OPEN_MA` | Ventil | Minimaler Stromschwellenwert in mA zur Endlagenerkennung beim Öffnen. |
|
| **0x0010** | `DIGITAL_AUSGAENGE_ZUSTAND` | Ausgänge | Bitmaske zum Lesen und Schreiben der Ausgänge. Bit 0: Ausgang 1, Bit 1: Ausgang 2. `1`=AN, `0`=AUS. |
|
||||||
| **0x0004** | `REG_HOLDING_END_CURRENT_THRESHOLD_CLOSE_MA` | Ventil | Minimaler Stromschwellenwert in mA zur Endlagenerkennung beim Schliessen. |
|
| **0x00F0** | `WATCHDOG_TIMEOUT_S` | System | Timeout des Fail-Safe-Watchdogs in Sekunden. `0`=Deaktiviert. |
|
||||||
| **0x0005** | `REG_HOLDING_OBSTACLE_THRESHOLD_OPEN_MA` | Ventil | Stromschwellenwert in mA für die Hinderniserkennung beim Öffnen. |
|
| **0x00F1** | `DEVICE_RESET` | System | Schreibt `1` um das Gerät neu zu starten. |
|
||||||
| **0x0006** | `REG_HOLDING_OBSTACLE_THRESHOLD_CLOSE_MA` | Ventil | Stromschwellenwert in mA für die Hinderniserkennung beim Schließen. |
|
| **0x0100** | `FWU_COMMAND` | Firmware-Update | `1`: **Verify Chunk**: Der zuletzt übertragene Chunk wurde vom Client als gültig befunden. Der Slave soll ihn nun ins Flash schreiben. `2`: **Finalize Update**: Alle Chunks sind übertragen. Installation abschliessen und neu starten. |
|
||||||
| **0x0010** | `REG_HOLDING_DIGITAL_OUTPUTS_STATE` | Ausgänge | Bitmaske zum Lesen und Schreiben der Ausgänge. Bit 0: Ausgang 1, Bit 1: Ausgang 2. `1`=AN, `0`=AUS. |
|
| **0x0101** | `FWU_CHUNK_OFFSET_LOW` | Firmware-Update | Untere 16 Bit des 32-Bit-Offsets, an den der nächste Chunk geschrieben werden soll. |
|
||||||
| **0x00F0** | `REG_HOLDING_WATCHDOG_TIMEOUT_S` | System | Timeout des Fail-Safe-Watchdogs in Sekunden. `0`=Deaktiviert. |
|
| **0x0102** | `FWU_CHUNK_OFFSET_HIGH` | Firmware-Update | Obere 16 Bit des 32-Bit-Offsets. |
|
||||||
| **0x00F1** | `REG_HOLDING_DEVICE_RESET` | System | Schreibt `1` um das Gerät neu zu starten. |
|
| **0x0103** | `FWU_CHUNK_SIZE` | Firmware-Update | Grösse des nächsten Chunks in Bytes (max. 256). |
|
||||||
| **0x0100** | `REG_HOLDING_FWU_COMMAND` | Firmware-Update | `1`: **Verify Chunk**: Der zuletzt übertragene Chunk wurde vom Client als gültig befunden. Der Slave soll ihn nun ins Flash schreiben. `2`: **Finalize Update**: Alle Chunks sind übertragen. Installation abschliessen und neu starten. |
|
| **0x0180** | `FWU_DATA_BUFFER` | Firmware-Update | **Startadresse** eines 128x16-bit Puffers (256 Bytes). Entspricht den Registern `40384` bis `40511`. |
|
||||||
| **0x0101** | `REG_HOLDING_FWU_CHUNK_OFFSET_LOW` | Firmware-Update | Untere 16 Bit des 32-Bit-Offsets, an den der nächste Chunk geschrieben werden soll. |
|
|
||||||
| **0x0102** | `REG_HOLDING_FWU_CHUNK_OFFSET_HIGH` | Firmware-Update | Obere 16 Bit des 32-Bit-Offsets. |
|
|
||||||
| **0x0103** | `REG_HOLDING_FWU_CHUNK_SIZE` | Firmware-Update | Grösse des nächsten Chunks in Bytes (max. 256). |
|
|
||||||
| **0x0180** | `REG_HOLDING_FWU_DATA_BUFFER` | Firmware-Update | **Startadresse** eines 128x16-bit Puffers (256 Bytes). Entspricht den Registern `40384` bis `40511`. |
|
|
||||||
|
|
||||||
## 4. Detaillierter Firmware-Update-Prozess
|
## 4. Detaillierter Firmware-Update-Prozess
|
||||||
|
|
||||||
|
|
@ -85,10 +80,10 @@ Diese Register gehören zum externen Füllstandsensor und können auf dem Bus eb
|
||||||
|
|
||||||
| Adresse (hex) | Name | R/W | Beschreibung |
|
| Adresse (hex) | Name | R/W | Beschreibung |
|
||||||
| :------------ | :------------------------- | :-- | :---------------------------------------------------------------------------------------------------------------------------------------- |
|
| :------------ | :------------------------- | :-- | :---------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **0x0000** | `NODE_ADDRESS` | R/W | Geräteadresse des Sensors (1-255). |
|
| **0x0000** | `NODE_ADRESSE` | R/W | Geräteadresse des Sensors (1-255). |
|
||||||
| **0x0001** | `BAUDRATE` | R/W | `0`=1200, `1`=2400, `2`=4800, `3`=9600, `4`=19200, `5`=38400, `6`=57600, `7`=115200. |
|
| **0x0001** | `BAUDRATE` | R/W | `0`=1200, `1`=2400, `2`=4800, `3`=9600, `4`=19200, `5`=38400, `6`=57600, `7`=115200. |
|
||||||
| **0x0002** | `UNIT` | R/W | `0`=Keine, `1`=cm, `2`=mm, `3`=MPa, `4`=Pa, `5`=kPa. |
|
| **0x0002** | `EINHEIT` | R/W | `0`=Keine, `1`=cm, `2`=mm, `3`=MPa, `4`=Pa, `5`=kPa. |
|
||||||
| **0x0003** | `DECIMAL_PLACES` | R/W | Anzahl der Dezimalstellen für den Messwert (0-3). |
|
| **0x0003** | `NACHKOMMASTELLEN` | R/W | Anzahl der Dezimalstellen für den Messwert (0-3). |
|
||||||
| **0x0004** | `CURRENT_MEASUREMENT` | R | Der skalierte Messwert als vorzeichenbehafteter 16-Bit-Integer. |
|
| **0x0004** | `MESSWERT_AKTUELL` | R | Der skalierte Messwert als vorzeichenbehafteter 16-Bit-Integer. |
|
||||||
| **0x0005** | `MEASUREMENT_RANGE_ZERO_POINT` | R/W | Rohwert für den Nullpunkt der Skala. |
|
| **0x0005** | `MESSBEREICH_NULLPUNKT` | R/W | Rohwert für den Nullpunkt der Skala. |
|
||||||
| **0x0006** | `MEASUREMENT_RANGE_END_POINT` | R/W | Rohwert für den Endpunkt der Skala. |
|
| **0x0006** | `MESSBEREICH_ENDPUNKT` | R/W | Rohwert für den Endpunkt der Skala. |
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,11 @@
|
||||||
| ✅ | **Phase 0: Planung & Definition** | | |
|
| ✅ | **Phase 0: Planung & Definition** | | |
|
||||||
| ✅ | Konzept erstellen und finalisieren | 30.06.2025 | Architektur, Komponenten und grundlegende Architektur sind festgelegt. |
|
| ✅ | Konzept erstellen und finalisieren | 30.06.2025 | Architektur, Komponenten und grundlegende Architektur sind festgelegt. |
|
||||||
| ✅ | MODBUS Register Map definieren | 30.06.2025 | Die "API" der Slaves ist definiert und bildet die Grundlage für die Software-Entwicklung. |
|
| ✅ | MODBUS Register Map definieren | 30.06.2025 | Die "API" der Slaves ist definiert und bildet die Grundlage für die Software-Entwicklung. |
|
||||||
| ✅ | Header- und deutsche Dokumentation aktualisiert | 10.07.2025 | Doxygen-Kommentare in Headern und deutsche .md-Dateien auf den neuesten Stand gebracht und übersetzt. |
|
|
||||||
| ☐ | **Phase 1: Slave-Node Prototyp (STM32 Eval-Board)** | | **Ziel:** Ein einzelner Slave wird auf dem Eval-Board zum Leben erweckt. |
|
| ☐ | **Phase 1: Slave-Node Prototyp (STM32 Eval-Board)** | | **Ziel:** Ein einzelner Slave wird auf dem Eval-Board zum Leben erweckt. |
|
||||||
| ✅ | 1.1 Entwicklungsumgebung für STM32/Zephyr einrichten | 30.06.2025 | Toolchain, VS Code, Zephyr-SDK, MCUBoot etc. installieren und ein "Hello World" zum Laufen bringen. |
|
| ✅ | 1.1 Entwicklungsumgebung für STM32/Zephyr einrichten | 30.06.2025 | Toolchain, VS Code, Zephyr-SDK, MCUBoot etc. installieren und ein "Hello World" zum Laufen bringen. |
|
||||||
| ✅ | 1.2 Hardware-Abstraktion (VND7050AJ, RS485) | 10.07.2025 | Implementierung der Treiber für den VND7050AJ und die RS485-Kommunikation. |
|
| ☐ | 1.2 Basis-Firmware für Slave-Node erstellen | | Hardware-Abstraktion (GPIOs, ADC, UART für RS485) implementieren. |
|
||||||
| ✅ | 1.3 Basis-Firmware für Slave-Node erstellen | 10.07.2025 | Hardware-Abstraktion (GPIOs) implementiert. |
|
| ☐ | 1.3 MODBUS-RTU Stack auf dem Slave implementieren | | Basierend auf der definierten Register-Map. Zuerst nur lesende Funktionen (Status, Version). |
|
||||||
| ✅ | 1.3 MODBUS-RTU Stack auf dem Slave implementieren | 10.07.2025 | Basierend auf der definierten Register-Map. Zuerst nur lesende Funktionen (Status, Version). |
|
| ☐ | 1.4 Kernlogik implementieren (z.B. Ventilsteuerung) | | Umsetzung der `VENTIL_ZUSTAND_BEWEGUNG` Logik, Strommessung für Endlagen etc. |
|
||||||
| ✅ | 1.4 Kernlogik implementieren (z.B. Ventilsteuerung) | 10.07.2025 | Umsetzung der `VALVE_STATE_MOVEMENT` Logik, Strommessung für Endlagen etc. |
|
|
||||||
| ☐ | **Phase 2: Verifikation der Slave-Firmware** | | **Ziel:** Nachweisen, dass der Slave sich exakt an die MODBUS-Spezifikation hält. |
|
| ☐ | **Phase 2: Verifikation der Slave-Firmware** | | **Ziel:** Nachweisen, dass der Slave sich exakt an die MODBUS-Spezifikation hält. |
|
||||||
| ☐ | 2.1 Slave-Node mit PC via USB-MODBUS-Adapter testen | | **Kritischer Meilenstein.** Mit Tools wie "QModMaster" oder einem Python-Skript die Register lesen & schreiben. Die Slave-Firmware wird so unabhängig vom Gateway validiert. |
|
| ☐ | 2.1 Slave-Node mit PC via USB-MODBUS-Adapter testen | | **Kritischer Meilenstein.** Mit Tools wie "QModMaster" oder einem Python-Skript die Register lesen & schreiben. Die Slave-Firmware wird so unabhängig vom Gateway validiert. |
|
||||||
| ☐ | 2.2 Firmware-Update Mechanismus testen | | Den kompletten Update-Prozess (Chunking, CRC-Check) mit einem Skript vom PC aus testen. Der Slave schreibt die Firmware dabei vorerst nur in einen ungenutzten RAM-Bereich. |
|
| ☐ | 2.2 Firmware-Update Mechanismus testen | | Den kompletten Update-Prozess (Chunking, CRC-Check) mit einem Skript vom PC aus testen. Der Slave schreibt die Firmware dabei vorerst nur in einen ungenutzten RAM-Bereich. |
|
||||||
|
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# This script sets up a Git pre-commit hook to automatically format C/C++ files
|
|
||||||
# in the 'software/' subdirectory using clang-format.
|
|
||||||
|
|
||||||
# Define the path for the pre-commit hook
|
|
||||||
HOOK_DIR=".git/hooks"
|
|
||||||
HOOK_FILE="$HOOK_DIR/pre-commit"
|
|
||||||
|
|
||||||
# Create the hooks directory if it doesn't exist
|
|
||||||
mkdir -p "$HOOK_DIR"
|
|
||||||
|
|
||||||
# Create the pre-commit hook script using a 'here document'
|
|
||||||
cat > "$HOOK_FILE" << 'EOF'
|
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# --- Pre-commit hook for clang-format ---
|
|
||||||
#
|
|
||||||
# This hook formats staged C, C++, and Objective-C files in the 'software/'
|
|
||||||
# subdirectory before a commit is made.
|
|
||||||
# It automatically finds the .clang-format file in the software/ directory.
|
|
||||||
#
|
|
||||||
|
|
||||||
# Directory to be formatted
|
|
||||||
TARGET_DIR="software/"
|
|
||||||
|
|
||||||
# Use git diff to find staged files that are Added (A), Copied (C), or Modified (M).
|
|
||||||
# We filter for files only within the TARGET_DIR.
|
|
||||||
# The grep regex matches common C/C++ and Objective-C file extensions.
|
|
||||||
FILES_TO_FORMAT=$(git diff --cached --name-only --diff-filter=ACM "$TARGET_DIR" | grep -E '\.(c|h|cpp|hpp|cxx|hxx|cc|hh|m|mm)$')
|
|
||||||
|
|
||||||
if [ -z "$FILES_TO_FORMAT" ]; then
|
|
||||||
# No relevant files to format, exit successfully.
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "› Running clang-format on staged files in '$TARGET_DIR'..."
|
|
||||||
|
|
||||||
# Run clang-format in-place on the identified files.
|
|
||||||
# clang-format will automatically find the .clang-format file in the software/ directory
|
|
||||||
# or any of its parent directories.
|
|
||||||
echo "$FILES_TO_FORMAT" | xargs clang-format -i
|
|
||||||
|
|
||||||
# Since clang-format may have changed the files, we need to re-stage them.
|
|
||||||
echo "$FILES_TO_FORMAT" | xargs git add
|
|
||||||
|
|
||||||
echo "› Formatting complete."
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Make the hook executable
|
|
||||||
chmod +x "$HOOK_FILE"
|
|
||||||
|
|
||||||
echo "✅ Git pre-commit hook has been set up successfully."
|
|
||||||
echo " It will now automatically format files in the '$PWD/software' directory before each commit."
|
|
||||||
|
|
@ -1,142 +0,0 @@
|
||||||
# Zephyr Project .clang-format configuration
|
|
||||||
# Based on Linux kernel style with Zephyr-specific adaptations
|
|
||||||
|
|
||||||
# Use LLVM as the base style and customize from there
|
|
||||||
BasedOnStyle: LLVM
|
|
||||||
|
|
||||||
# Language settings
|
|
||||||
Language: Cpp
|
|
||||||
|
|
||||||
# Indentation settings
|
|
||||||
IndentWidth: 8
|
|
||||||
TabWidth: 8
|
|
||||||
UseTab: ForIndentation
|
|
||||||
|
|
||||||
# Line length
|
|
||||||
ColumnLimit: 100
|
|
||||||
|
|
||||||
# Brace settings
|
|
||||||
BreakBeforeBraces: Linux
|
|
||||||
BraceWrapping:
|
|
||||||
AfterClass: true
|
|
||||||
AfterControlStatement: false
|
|
||||||
AfterEnum: true
|
|
||||||
AfterFunction: true
|
|
||||||
AfterNamespace: true
|
|
||||||
AfterStruct: true
|
|
||||||
AfterUnion: true
|
|
||||||
BeforeCatch: true
|
|
||||||
BeforeElse: false
|
|
||||||
IndentBraces: false
|
|
||||||
SplitEmptyFunction: true
|
|
||||||
SplitEmptyRecord: true
|
|
||||||
SplitEmptyNamespace: true
|
|
||||||
|
|
||||||
# Always add braces for control statements (Zephyr requirement)
|
|
||||||
RemoveBracesLLVM: false
|
|
||||||
|
|
||||||
# Control statement settings
|
|
||||||
SpaceBeforeParens: ControlStatements
|
|
||||||
SpacesInParentheses: false
|
|
||||||
|
|
||||||
# Function settings
|
|
||||||
AllowShortFunctionsOnASingleLine: None
|
|
||||||
AllowShortBlocksOnASingleLine: Empty
|
|
||||||
AllowShortIfStatementsOnASingleLine: Never
|
|
||||||
AllowShortLoopsOnASingleLine: false
|
|
||||||
AllowShortCaseLabelsOnASingleLine: false
|
|
||||||
|
|
||||||
# Pointer and reference alignment
|
|
||||||
PointerAlignment: Right
|
|
||||||
ReferenceAlignment: Right
|
|
||||||
|
|
||||||
# Spacing settings
|
|
||||||
SpaceAfterCStyleCast: false
|
|
||||||
SpaceAfterLogicalNot: false
|
|
||||||
SpaceBeforeAssignmentOperators: true
|
|
||||||
SpaceBeforeCpp11BracedList: false
|
|
||||||
SpaceBeforeCtorInitializerColon: true
|
|
||||||
SpaceBeforeInheritanceColon: true
|
|
||||||
SpaceBeforeRangeBasedForLoopColon: true
|
|
||||||
SpaceInEmptyParentheses: false
|
|
||||||
SpacesBeforeTrailingComments: 1
|
|
||||||
SpacesInAngles: false
|
|
||||||
SpacesInCStyleCastParentheses: false
|
|
||||||
SpacesInContainerLiterals: false
|
|
||||||
SpacesInSquareBrackets: false
|
|
||||||
|
|
||||||
# Alignment settings
|
|
||||||
AlignAfterOpenBracket: DontAlign
|
|
||||||
AlignConsecutiveAssignments: false
|
|
||||||
AlignConsecutiveDeclarations: false
|
|
||||||
AlignEscapedNewlines: Right
|
|
||||||
AlignOperands: false
|
|
||||||
AlignTrailingComments: false
|
|
||||||
|
|
||||||
# Breaking settings
|
|
||||||
AlwaysBreakAfterDefinitionReturnType: None
|
|
||||||
AlwaysBreakAfterReturnType: None
|
|
||||||
AlwaysBreakBeforeMultilineStrings: false
|
|
||||||
AlwaysBreakTemplateDeclarations: false
|
|
||||||
BinPackArguments: false
|
|
||||||
BinPackParameters: false
|
|
||||||
BreakBeforeBinaryOperators: None
|
|
||||||
BreakBeforeTernaryOperators: true
|
|
||||||
BreakConstructorInitializersBeforeComma: false
|
|
||||||
BreakAfterJavaFieldAnnotations: false
|
|
||||||
BreakStringLiterals: true
|
|
||||||
|
|
||||||
# Penalties (used for line breaking decisions)
|
|
||||||
PenaltyBreakAssignment: 2
|
|
||||||
PenaltyBreakBeforeFirstCallParameter: 19
|
|
||||||
PenaltyBreakComment: 300
|
|
||||||
PenaltyBreakFirstLessLess: 120
|
|
||||||
PenaltyBreakString: 1000
|
|
||||||
PenaltyExcessCharacter: 1000000
|
|
||||||
PenaltyReturnTypeOnItsOwnLine: 60
|
|
||||||
|
|
||||||
# Comment settings
|
|
||||||
ReflowComments: true
|
|
||||||
CommentPragmas: '^ IWYU pragma:'
|
|
||||||
|
|
||||||
# Sorting settings
|
|
||||||
SortIncludes: true
|
|
||||||
SortUsingDeclarations: true
|
|
||||||
|
|
||||||
# Preprocessor settings
|
|
||||||
IndentPPDirectives: None
|
|
||||||
MacroBlockBegin: ''
|
|
||||||
MacroBlockEnd: ''
|
|
||||||
|
|
||||||
# Misc settings
|
|
||||||
CompactNamespaces: false
|
|
||||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
|
||||||
ConstructorInitializerIndentWidth: 4
|
|
||||||
ContinuationIndentWidth: 4
|
|
||||||
Cpp11BracedListStyle: true
|
|
||||||
DerivePointerAlignment: false
|
|
||||||
DisableFormat: false
|
|
||||||
ExperimentalAutoDetectBinPacking: false
|
|
||||||
FixNamespaceComments: true
|
|
||||||
ForEachMacros: ['LISTIFY', 'FOR_EACH', 'FOR_EACH_FIXED_ARG', 'FOR_EACH_IDX', 'FOR_EACH_IDX_FIXED_ARG', 'FOR_EACH_NONEMPTY_TERM', 'Z_FOR_EACH', 'Z_FOR_EACH_FIXED_ARG', 'Z_FOR_EACH_IDX', 'Z_FOR_EACH_IDX_FIXED_ARG']
|
|
||||||
IncludeBlocks: Preserve
|
|
||||||
IncludeCategories:
|
|
||||||
- Regex: '^<zephyr/.*\.h>'
|
|
||||||
Priority: 1
|
|
||||||
- Regex: '^<.*\.h>'
|
|
||||||
Priority: 2
|
|
||||||
- Regex: '^<.*'
|
|
||||||
Priority: 3
|
|
||||||
- Regex: '.*'
|
|
||||||
Priority: 4
|
|
||||||
IndentCaseLabels: false
|
|
||||||
IndentWrappedFunctionNames: false
|
|
||||||
JavaScriptQuotes: Leave
|
|
||||||
JavaScriptWrapImports: true
|
|
||||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
|
||||||
MaxEmptyLinesToKeep: 1
|
|
||||||
NamespaceIndentation: None
|
|
||||||
ObjCBinPackProtocolList: Auto
|
|
||||||
ObjCBlockIndentWidth: 2
|
|
||||||
ObjCSpaceAfterProperty: false
|
|
||||||
ObjCSpaceBeforeProtocolList: true
|
|
||||||
|
|
@ -1,15 +1,17 @@
|
||||||
{
|
{
|
||||||
// Hush CMake
|
// Hush CMake
|
||||||
"cmake.configureOnOpen": false,
|
"cmake.configureOnOpen": false,
|
||||||
// IntelliSense
|
|
||||||
"C_Cpp.default.compilerPath": "${userHome}/zephyr-sdk-0.17.1/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc.exe",
|
// IntelliSense
|
||||||
"C_Cpp.default.compileCommands": "${workspaceFolder}/build/compile_commands.json",
|
"C_Cpp.default.compilerPath": "${userHome}/zephyr-sdk-0.17.1/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc.exe",
|
||||||
// File Associations
|
"C_Cpp.default.compileCommands": "${workspaceFolder}/build/compile_commands.json",
|
||||||
"files.associations": {
|
|
||||||
"app_version.h": "c"
|
// File Associations
|
||||||
},
|
"files.associations": {
|
||||||
"C_Cpp.clang_format_style": "file",
|
"array": "c",
|
||||||
"nrf-connect.applications": [
|
"string_view": "c",
|
||||||
"${workspaceFolder}/apps/slave_node"
|
"initializer_list": "c",
|
||||||
],
|
"span": "c",
|
||||||
|
"format": "c"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2,20 +2,32 @@
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"tasks": [
|
"tasks": [
|
||||||
{
|
{
|
||||||
"label": "Format All C/C++ Files",
|
"label": "West Build",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "find . -name \"*.c\" -o -name \"*.h\" | xargs clang-format -i",
|
"group": {
|
||||||
"problemMatcher": [],
|
"kind": "build",
|
||||||
"group": {
|
"isDefault": true
|
||||||
"kind": "build",
|
},
|
||||||
"isDefault": true
|
"linux": {
|
||||||
},
|
"command": "${userHome}/zephyrproject/.venv/bin/west"
|
||||||
"presentation": {
|
},
|
||||||
"reveal": "silent",
|
"windows": {
|
||||||
"clear": true,
|
"command": "${userHome}/zephyrproject/.venv/Scripts/west.exe"
|
||||||
"panel": "shared"
|
},
|
||||||
}
|
"osx": {
|
||||||
},
|
"command": "${userHome}/zephyrproject/.venv/bin/west"
|
||||||
|
},
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"-p",
|
||||||
|
"auto",
|
||||||
|
"-b",
|
||||||
|
"valve_node"
|
||||||
|
],
|
||||||
|
"problemMatcher": [
|
||||||
|
"$gcc"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"label": "West Configurable Build",
|
"label": "West Configurable Build",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.20.0)
|
cmake_minimum_required(VERSION 3.20.0)
|
||||||
|
|
||||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||||
project(bl_test)
|
project(ADC)
|
||||||
|
|
||||||
# Add application source files
|
|
||||||
target_sources(app PRIVATE src/main.c)
|
target_sources(app PRIVATE src/main.c)
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
.. zephyr:code-sample:: adc_dt
|
||||||
|
:name: Analog-to-Digital Converter (ADC) with devicetree
|
||||||
|
:relevant-api: adc_interface
|
||||||
|
|
||||||
|
Read analog inputs from ADC channels.
|
||||||
|
|
||||||
|
Overview
|
||||||
|
********
|
||||||
|
|
||||||
|
This sample demonstrates how to use the :ref:`ADC driver API <adc_api>`.
|
||||||
|
|
||||||
|
Depending on the target board, it reads ADC samples from one or more channels
|
||||||
|
and prints the readings on the console. If voltage of the used reference can
|
||||||
|
be obtained, the raw readings are converted to millivolts.
|
||||||
|
|
||||||
|
The pins of the ADC channels are board-specific. Please refer to the board
|
||||||
|
or MCU datasheet for further details.
|
||||||
|
|
||||||
|
Building and Running
|
||||||
|
********************
|
||||||
|
|
||||||
|
The ADC peripheral and pinmux is configured in the board's ``.dts`` file. Make
|
||||||
|
sure that the ADC is enabled (``status = "okay";``).
|
||||||
|
|
||||||
|
In addition to that, this sample requires an ADC channel specified in the
|
||||||
|
``io-channels`` property of the ``zephyr,user`` node. This is usually done with
|
||||||
|
a devicetree overlay. The example overlay in the ``boards`` subdirectory for
|
||||||
|
the ``nucleo_l073rz`` board can be easily adjusted for other boards.
|
||||||
|
|
||||||
|
Configuration of channels (settings like gain, reference, or acquisition time)
|
||||||
|
also needs to be specified in devicetree, in ADC controller child nodes. Also
|
||||||
|
the ADC resolution and oversampling setting (if used) need to be specified
|
||||||
|
there. See :zephyr_file:`boards/nrf52840dk_nrf52840.overlay
|
||||||
|
<samples/drivers/adc/adc_dt/boards/nrf52840dk_nrf52840.overlay>` for an example of
|
||||||
|
such setup.
|
||||||
|
|
||||||
|
Building and Running for ST Nucleo L073RZ
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
The sample can be built and executed for the
|
||||||
|
:zephyr:board:`nucleo_l073rz` as follows:
|
||||||
|
|
||||||
|
.. zephyr-app-commands::
|
||||||
|
:zephyr-app: samples/drivers/adc/adc_dt
|
||||||
|
:board: nucleo_l073rz
|
||||||
|
:goals: build flash
|
||||||
|
:compact:
|
||||||
|
|
||||||
|
To build for another board, change "nucleo_l073rz" above to that board's name
|
||||||
|
and provide a corresponding devicetree overlay.
|
||||||
|
|
||||||
|
Sample output
|
||||||
|
=============
|
||||||
|
|
||||||
|
You should get a similar output as below, repeated every second:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
ADC reading:
|
||||||
|
- ADC_0, channel 7: 36 = 65mV
|
||||||
|
|
||||||
|
.. note:: If the ADC is not supported, the output will be an error message.
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
/ {
|
||||||
|
vdd_sense: voltage-divider {
|
||||||
|
compatible = "voltage-divider";
|
||||||
|
/*
|
||||||
|
* This reference must provide one argument (the channel number)
|
||||||
|
* because of the "#io-channel-cells = <1>" in the &adc1 node.
|
||||||
|
*/
|
||||||
|
io-channels = <&adc1 1>;
|
||||||
|
output-ohms = <2200>;
|
||||||
|
full-ohms = <3200>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
&adc1 {
|
||||||
|
status = "okay";
|
||||||
|
|
||||||
|
pinctrl-0 = <&adc1_in1_pa0>;
|
||||||
|
pinctrl-names = "default";
|
||||||
|
|
||||||
|
st,adc-clock-source = "SYNC";
|
||||||
|
st,adc-prescaler = <4>;
|
||||||
|
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
/*
|
||||||
|
* This line is required by the st,stm32-adc driver binding.
|
||||||
|
* It declares that references to its channels need one extra argument.
|
||||||
|
*/
|
||||||
|
#io-channel-cells = <1>;
|
||||||
|
|
||||||
|
adc_channel_1: channel@1 {
|
||||||
|
reg = <1>;
|
||||||
|
zephyr,gain = "ADC_GAIN_1";
|
||||||
|
zephyr,reference = "ADC_REF_INTERNAL";
|
||||||
|
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
||||||
|
zephyr,resolution = <12>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
CONFIG_ADC=y
|
||||||
|
CONFIG_SENSOR=y
|
||||||
|
CONFIG_VOLTAGE_DIVIDER=y
|
||||||
|
CONFIG_LOG=y
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
sample:
|
||||||
|
name: ADC devicetree driver sample
|
||||||
|
tests:
|
||||||
|
sample.drivers.adc.adc_dt:
|
||||||
|
tags:
|
||||||
|
- adc
|
||||||
|
depends_on: adc
|
||||||
|
platform_allow:
|
||||||
|
- nucleo_l073rz
|
||||||
|
- disco_l475_iot1
|
||||||
|
- cc3220sf_launchxl
|
||||||
|
- cc3235sf_launchxl
|
||||||
|
- cy8cproto_063_ble
|
||||||
|
- stm32l496g_disco
|
||||||
|
- stm32h735g_disco
|
||||||
|
- nrf51dk/nrf51822
|
||||||
|
- nrf52840dk/nrf52840
|
||||||
|
- nrf54l15dk/nrf54l15/cpuapp
|
||||||
|
- nrf54h20dk/nrf54h20/cpuapp
|
||||||
|
- ophelia4ev/nrf54l15/cpuapp
|
||||||
|
- mec172xevb_assy6906
|
||||||
|
- gd32f350r_eval
|
||||||
|
- gd32f450i_eval
|
||||||
|
- gd32vf103v_eval
|
||||||
|
- gd32f403z_eval
|
||||||
|
- esp32_devkitc/esp32/procpu
|
||||||
|
- esp32s2_saola
|
||||||
|
- esp32c3_devkitm
|
||||||
|
- gd32l233r_eval
|
||||||
|
- lpcxpresso55s36
|
||||||
|
- mr_canhubk3
|
||||||
|
- longan_nano
|
||||||
|
- longan_nano/gd32vf103/lite
|
||||||
|
- rd_rw612_bga
|
||||||
|
- frdm_mcxn947/mcxn947/cpu0
|
||||||
|
- mcx_n9xx_evk/mcxn947/cpu0
|
||||||
|
- frdm_mcxc242
|
||||||
|
- ucans32k1sic
|
||||||
|
- xg24_rb4187c
|
||||||
|
- xg29_rb4412a
|
||||||
|
- raytac_an54l15q_db/nrf54l15/cpuapp
|
||||||
|
- frdm_mcxa166
|
||||||
|
- frdm_mcxa276
|
||||||
|
integration_platforms:
|
||||||
|
- nucleo_l073rz
|
||||||
|
- nrf52840dk/nrf52840
|
||||||
|
harness: console
|
||||||
|
timeout: 10
|
||||||
|
harness_config:
|
||||||
|
type: multi_line
|
||||||
|
regex:
|
||||||
|
- "ADC reading\\[\\d+\\]:"
|
||||||
|
- "- .+, channel \\d+: -?\\d+"
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Wolter HV <wolterhv@gmx.de>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/ {
|
||||||
|
zephyr,user {
|
||||||
|
io-channels = <&adc0 0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
&adc0 {
|
||||||
|
status = "okay";
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
channel@0 {
|
||||||
|
reg = <0>;
|
||||||
|
zephyr,gain = "ADC_GAIN_1_4";
|
||||||
|
zephyr,reference = "ADC_REF_INTERNAL";
|
||||||
|
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
||||||
|
zephyr,resolution = <12>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Wolter HV <wolterhv@gmx.de>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/ {
|
||||||
|
zephyr,user {
|
||||||
|
io-channels = <&adc0 0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
&adc0 {
|
||||||
|
status = "okay";
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
channel@0 {
|
||||||
|
reg = <0>;
|
||||||
|
zephyr,gain = "ADC_GAIN_1_4";
|
||||||
|
zephyr,reference = "ADC_REF_INTERNAL";
|
||||||
|
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
||||||
|
zephyr,resolution = <12>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Wolter HV <wolterhv@gmx.de>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/ {
|
||||||
|
zephyr,user {
|
||||||
|
io-channels = <&adc0 0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
&adc0 {
|
||||||
|
status = "okay";
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
channel@0 {
|
||||||
|
reg = <0>;
|
||||||
|
zephyr,gain = "ADC_GAIN_1_4";
|
||||||
|
zephyr,reference = "ADC_REF_INTERNAL";
|
||||||
|
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
||||||
|
zephyr,resolution = <12>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Wolter HV <wolterhv@gmx.de>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/ {
|
||||||
|
zephyr,user {
|
||||||
|
io-channels = <&adc0 0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
&adc0 {
|
||||||
|
status = "okay";
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
channel@0 {
|
||||||
|
reg = <0>;
|
||||||
|
zephyr,gain = "ADC_GAIN_1_4";
|
||||||
|
zephyr,reference = "ADC_REF_INTERNAL";
|
||||||
|
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
||||||
|
zephyr,resolution = <12>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/device.h>
|
||||||
|
#include <zephyr/devicetree.h>
|
||||||
|
#include <zephyr/drivers/sensor.h>
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
|
||||||
|
LOG_MODULE_REGISTER(adc_dt_example, LOG_LEVEL_DBG);
|
||||||
|
|
||||||
|
/* Get the voltage divider device */
|
||||||
|
#define VOLTAGE_DIVIDER_NODE DT_NODELABEL(vdd_sense)
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
const struct device *vdd_dev = DEVICE_DT_GET(VOLTAGE_DIVIDER_NODE);
|
||||||
|
struct sensor_value val;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!device_is_ready(vdd_dev)) {
|
||||||
|
LOG_ERR("Voltage divider device not ready");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INF("Voltage divider device ready!");
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
err = sensor_sample_fetch(vdd_dev);
|
||||||
|
if (err < 0) {
|
||||||
|
LOG_ERR("Could not fetch sample (%d)", err);
|
||||||
|
k_sleep(K_MSEC(1000));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = sensor_channel_get(vdd_dev, SENSOR_CHAN_VOLTAGE, &val);
|
||||||
|
if (err < 0) {
|
||||||
|
LOG_ERR("Could not get channel (%d)", err);
|
||||||
|
k_sleep(K_MSEC(1000));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INF("Voltage reading: %d.%06d V", val.val1, val.val2);
|
||||||
|
|
||||||
|
k_sleep(K_MSEC(1000));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
|
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||||
|
project(adc_test)
|
||||||
|
|
||||||
|
target_sources(app PRIVATE src/main.c)
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
&adc1 {
|
||||||
|
pinctrl-0 = <&adc1_in1_pa0>;
|
||||||
|
pinctrl-names = "default";
|
||||||
|
status = "okay";
|
||||||
|
|
||||||
|
st,adc-clock-source = "SYNC";
|
||||||
|
st,adc-prescaler = <4>;
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
CONFIG_ADC=y
|
||||||
|
CONFIG_ADC_STM32=y
|
||||||
|
CONFIG_LOG=y
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/drivers/adc.h>
|
||||||
|
#include <zephyr/device.h>
|
||||||
|
#include <zephyr/sys/printk.h>
|
||||||
|
|
||||||
|
// ADC-Knoten holen
|
||||||
|
static const struct device *adc_dev = DEVICE_DT_GET(DT_NODELABEL(adc1));
|
||||||
|
|
||||||
|
// Kanaldefinitionen
|
||||||
|
#define MY_SIGNAL_CHANNEL 1 // PA0
|
||||||
|
#define ADC_VREFINT_CHANNEL 18 // Intern
|
||||||
|
|
||||||
|
// Puffer für ZWEI Messwerte
|
||||||
|
static int16_t sample_buffer[2];
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
// Die VREFINT-Spannung in mV aus dem Datenblatt deines Controllers
|
||||||
|
#define VREFINT_MV 1212
|
||||||
|
|
||||||
|
printk("*** ADC Ratiometric Measurement (Single Sequence) ***\n");
|
||||||
|
|
||||||
|
if (!device_is_ready(adc_dev)) {
|
||||||
|
printk("ADC device not ready!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Einmaliges Setup der beiden Kanäle ---
|
||||||
|
const struct adc_channel_cfg signal_channel_cfg = {
|
||||||
|
.gain = ADC_GAIN_1,
|
||||||
|
.reference = ADC_REF_INTERNAL,
|
||||||
|
.acquisition_time = ADC_ACQ_TIME_DEFAULT, // Kurz für niederohmige Quellen
|
||||||
|
.channel_id = MY_SIGNAL_CHANNEL,
|
||||||
|
};
|
||||||
|
const struct adc_channel_cfg vrefint_channel_cfg = {
|
||||||
|
.gain = ADC_GAIN_1,
|
||||||
|
.reference = ADC_REF_INTERNAL,
|
||||||
|
.acquisition_time = ADC_ACQ_TIME_MAX, // Lang für VREFINT
|
||||||
|
.channel_id = ADC_VREFINT_CHANNEL,
|
||||||
|
};
|
||||||
|
|
||||||
|
adc_channel_setup(adc_dev, &signal_channel_cfg);
|
||||||
|
adc_channel_setup(adc_dev, &vrefint_channel_cfg);
|
||||||
|
|
||||||
|
// --- EINE Sequenz, die BEIDE Kanäle enthält ---
|
||||||
|
const struct adc_sequence sequence = {
|
||||||
|
.channels = BIT(MY_SIGNAL_CHANNEL) | BIT(ADC_VREFINT_CHANNEL),
|
||||||
|
.buffer = sample_buffer,
|
||||||
|
.buffer_size = sizeof(sample_buffer),
|
||||||
|
.resolution = 12,
|
||||||
|
};
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
err = adc_read(adc_dev, &sequence);
|
||||||
|
if (err != 0) {
|
||||||
|
printk("ADC read failed with code %d\n", err);
|
||||||
|
} else {
|
||||||
|
// Die Ergebnisse sind in der Reihenfolge der Kanalnummern im Puffer
|
||||||
|
// Kanal 1 (MY_SIGNAL_CHANNEL) kommt vor Kanal 18 (ADC_VREFINT_CHANNEL)
|
||||||
|
int16_t signal_raw = sample_buffer[0];
|
||||||
|
int16_t vrefint_raw = sample_buffer[1];
|
||||||
|
|
||||||
|
// Ratiometrische Berechnung
|
||||||
|
int32_t signal_mv = (int32_t)signal_raw * VREFINT_MV / vrefint_raw;
|
||||||
|
|
||||||
|
printk("Signal: raw=%4d | VREFINT: raw=%4d | Calculated Voltage: %d mV\n",
|
||||||
|
signal_raw, vrefint_raw, signal_mv);
|
||||||
|
}
|
||||||
|
|
||||||
|
k_msleep(2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/drivers/adc.h>
|
||||||
|
#include <zephyr/device.h>
|
||||||
|
|
||||||
|
// Definiere die Kanäle
|
||||||
|
#define ADC_VREFINT_CHANNEL 18 // Muss mit dem DTS übereinstimmen
|
||||||
|
#define MY_SIGNAL_CHANNEL 1 // Muss mit dem pinctrl im DTS übereinstimmen
|
||||||
|
|
||||||
|
// ADC Device
|
||||||
|
static const struct device *adc_dev = DEVICE_DT_GET(DT_NODELABEL(adc1));
|
||||||
|
|
||||||
|
// ADC Kanal Konfigurationen
|
||||||
|
static const struct adc_channel_cfg vrefint_channel_cfg = {
|
||||||
|
.gain = ADC_GAIN_1,
|
||||||
|
.reference = ADC_REF_INTERNAL, // Bedeutet VDDA
|
||||||
|
.acquisition_time = ADC_ACQ_TIME_MAX,
|
||||||
|
.channel_id = ADC_VREFINT_CHANNEL,
|
||||||
|
.differential = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct adc_channel_cfg signal_channel_cfg = {
|
||||||
|
.gain = ADC_GAIN_1,
|
||||||
|
.reference = ADC_REF_INTERNAL, // Bedeutet VDDA
|
||||||
|
.acquisition_time = ADC_ACQ_TIME_MAX,
|
||||||
|
.channel_id = MY_SIGNAL_CHANNEL,
|
||||||
|
.differential = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Puffer für die Messwerte
|
||||||
|
#define BUFFER_SIZE 1
|
||||||
|
static int16_t sample_buffer[BUFFER_SIZE];
|
||||||
|
|
||||||
|
// Sequenz für die Messungen
|
||||||
|
struct adc_sequence sequence_vrefint = {
|
||||||
|
.channels = BIT(ADC_VREFINT_CHANNEL),
|
||||||
|
.buffer = sample_buffer,
|
||||||
|
.buffer_size = sizeof(sample_buffer),
|
||||||
|
.resolution = 12, // STM32G4 hat 12-bit
|
||||||
|
};
|
||||||
|
|
||||||
|
struct adc_sequence sequence_signal = {
|
||||||
|
.channels = BIT(MY_SIGNAL_CHANNEL),
|
||||||
|
.buffer = sample_buffer,
|
||||||
|
.buffer_size = sizeof(sample_buffer),
|
||||||
|
.resolution = 12,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
if (!device_is_ready(adc_dev)) {
|
||||||
|
printk("ADC device not found\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kanäle konfigurieren
|
||||||
|
adc_channel_setup(adc_dev, &vrefint_channel_cfg);
|
||||||
|
adc_channel_setup(adc_dev, &signal_channel_cfg);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
// 1. VREFINT messen zur Kalibrierung
|
||||||
|
adc_read(adc_dev, &sequence_vrefint);
|
||||||
|
int16_t vrefint_raw = sample_buffer[0];
|
||||||
|
|
||||||
|
// 2. Dein eigentliches Signal messen
|
||||||
|
adc_read(adc_dev, &sequence_signal);
|
||||||
|
int16_t signal_raw = sample_buffer[0];
|
||||||
|
|
||||||
|
// 3. Spannung berechnen
|
||||||
|
// VREFINT Wert für STM32G431 bei 3.0V Vdda ist typ. 1.212V (1212 mV)
|
||||||
|
// Überprüfe den genauen Wert im Datenblatt für deinen Controller!
|
||||||
|
#define VREFINT_MV 1212
|
||||||
|
|
||||||
|
int32_t signal_mv = (int32_t)signal_raw * VREFINT_MV / vrefint_raw;
|
||||||
|
|
||||||
|
printk("VREFINT raw: %d, Signal raw: %d, Calculated Voltage: %d mV\n",
|
||||||
|
vrefint_raw, signal_raw, signal_mv);
|
||||||
|
|
||||||
|
k_msleep(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
#include <zephyr.h>
|
||||||
|
#include <drivers/adc.h>
|
||||||
|
|
||||||
|
#define PA0_PIN 0x04
|
||||||
|
#define ADC_CHANNEL 0x03
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
int16_t adc_value = 0;
|
||||||
|
|
||||||
|
// Initialize the ADC
|
||||||
|
adc_config_t adc_config;
|
||||||
|
adc_config.mode = ADC_MODE_SINGLE_SHOT;
|
||||||
|
adc_config.channel = ADC_CHANNEL_PA0;
|
||||||
|
adc_config.sampling_rate = ADC_SAMP_RATE_1MS;
|
||||||
|
|
||||||
|
adc_config.data_rate = ADC_DATA_RATE_4MS;
|
||||||
|
adc_config.aux = ADC_AUX_ALL;
|
||||||
|
|
||||||
|
adc_config.atten = ADC_ATTEN_DB_11;
|
||||||
|
adc_config.ref = ADC_REF_INTERNAL;
|
||||||
|
|
||||||
|
adc_config.cal = ADC_CAL_ALL;
|
||||||
|
|
||||||
|
if (adc_config_data(&adc_config, &adc_context) < 0) {
|
||||||
|
zephyr_printf("Failed to configure ADC\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the analog input value
|
||||||
|
if (adc_read(&adc_context, &adc_value) < 0) {
|
||||||
|
zephyr_printf("Failed to read ADC value\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
zephyr_printf("ADC Value: %d\n", adc_value);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
VERSION_MAJOR = 0
|
|
||||||
VERSION_MINOR = 0
|
|
||||||
PATCHLEVEL = 1
|
|
||||||
VERSION_TWEAK = 1
|
|
||||||
EXTRAVERSION = devel
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
# Enable Console and printk for logging via UART
|
|
||||||
CONFIG_CONSOLE=y
|
|
||||||
CONFIG_LOG=y
|
|
||||||
CONFIG_UART_CONSOLE=y
|
|
||||||
|
|
||||||
# Enable more detailed MCUMGR logging
|
|
||||||
CONFIG_MCUMGR_LOG_LEVEL_DBG=y
|
|
||||||
CONFIG_IMG_MANAGER_LOG_LEVEL_DBG=y
|
|
||||||
CONFIG_STREAM_FLASH_LOG_LEVEL_DBG=y
|
|
||||||
|
|
||||||
# Enable USB for MCUMGR only
|
|
||||||
CONFIG_USB_DEVICE_STACK=y
|
|
||||||
CONFIG_USB_CDC_ACM=y
|
|
||||||
CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=y
|
|
||||||
|
|
||||||
# USB CDC ACM buffer configuration for better MCUMGR performance
|
|
||||||
CONFIG_USB_CDC_ACM_RINGBUF_SIZE=1024
|
|
||||||
|
|
||||||
# Set log level to info for reasonable size
|
|
||||||
CONFIG_LOG_DEFAULT_LEVEL=3
|
|
||||||
|
|
||||||
# Enable MCUMGR info logging (not debug to save space)
|
|
||||||
CONFIG_MCUMGR_LOG_LEVEL_INF=y
|
|
||||||
|
|
||||||
# Enable USB CDC info logging
|
|
||||||
CONFIG_USB_CDC_ACM_LOG_LEVEL_INF=y
|
|
||||||
|
|
||||||
# STEP 5.2 - Enable mcumgr DFU in application
|
|
||||||
# Enable MCUMGR
|
|
||||||
CONFIG_MCUMGR=y # Enable MCUMGR management for both OS and Images
|
|
||||||
CONFIG_MCUMGR_GRP_OS=y
|
|
||||||
CONFIG_MCUMGR_GRP_IMG=y
|
|
||||||
|
|
||||||
# Configure MCUMGR transport to UART (will use USB-CDC via chosen device)
|
|
||||||
CONFIG_MCUMGR_TRANSPORT_UART=y
|
|
||||||
|
|
||||||
# Dependencies
|
|
||||||
# Configure dependencies for CONFIG_MCUMGR
|
|
||||||
CONFIG_NET_BUF=y
|
|
||||||
CONFIG_ZCBOR=y
|
|
||||||
CONFIG_CRC=y # Configure dependencies for CONFIG_MCUMGR_GRP_IMG
|
|
||||||
CONFIG_FLASH=y
|
|
||||||
CONFIG_IMG_MANAGER=y # Configure dependencies for CONFIG_IMG_MANAGER
|
|
||||||
CONFIG_STREAM_FLASH=y
|
|
||||||
CONFIG_FLASH_MAP=y # Configure dependencies for CONFIG_MCUMGR_TRANSPORT_USB_CDC
|
|
||||||
CONFIG_BASE64=y
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
#include <zephyr/kernel.h>
|
|
||||||
#include <zephyr/logging/log.h>
|
|
||||||
#include <app_version.h>
|
|
||||||
|
|
||||||
LOG_MODULE_REGISTER(bl_test_app, LOG_LEVEL_INF);
|
|
||||||
|
|
||||||
int main(void)
|
|
||||||
{
|
|
||||||
LOG_INF("Hello World from bl_test! This is version %s", APP_VERSION_EXTENDED_STRING);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
SB_CONFIG_BOOTLOADER_MCUBOOT=y
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
#include "common.dtsi"
|
|
||||||
|
|
||||||
/* Application Configuration - Firmware wird in slot0_partition geschrieben */
|
|
||||||
/ {
|
|
||||||
chosen {
|
|
||||||
zephyr,code-partition = &slot0_partition;
|
|
||||||
zephyr,uart-mcumgr = &cdc_acm_uart0;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,94 +0,0 @@
|
||||||
/*
|
|
||||||
* Common Devicetree Configuration für weact_stm32g431_core
|
|
||||||
* - Konfiguriert einen W25Q128 Flash-Speicher auf SPI2
|
|
||||||
* - Konfiguriert USB-CDC für MCUMGR
|
|
||||||
* - Setzt den Chip Select (CS) Pin auf PA5
|
|
||||||
* - Weist das Label "flash1" zu
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Partitions für internes Flash (STM32G431) */
|
|
||||||
&flash0 {
|
|
||||||
/delete-node/ partitions; /* Entferne die Standard-Partitionen */
|
|
||||||
partitions {
|
|
||||||
compatible = "fixed-partitions";
|
|
||||||
#address-cells = <1>;
|
|
||||||
#size-cells = <1>;
|
|
||||||
|
|
||||||
/* MCUboot bootloader - 48 KB */
|
|
||||||
boot_partition: partition@0 {
|
|
||||||
label = "mcuboot";
|
|
||||||
reg = <0x00000000 0x0000C000>;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Slot0 partition für primäres Application Image - 80 KB (20 sectors @ 4KB) */
|
|
||||||
slot0_partition: partition@C000 {
|
|
||||||
label = "image-0";
|
|
||||||
reg = <0x0000C000 0x00014000>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/* USB-CDC Konfiguration für MCUMGR */
|
|
||||||
&usb {
|
|
||||||
status = "okay";
|
|
||||||
cdc_acm_uart0: cdc_acm_uart0 {
|
|
||||||
compatible = "zephyr,cdc-acm-uart";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/ {
|
|
||||||
chosen {
|
|
||||||
zephyr,uart-mcumgr = &cdc_acm_uart0;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
&spi2 {
|
|
||||||
/* Definiere die Pins für SCK, MISO, MOSI auf Port B */
|
|
||||||
pinctrl-0 = <&spi2_sck_pb13 &spi2_miso_pb14 &spi2_mosi_pb15>;
|
|
||||||
pinctrl-names = "default";
|
|
||||||
status = "okay";
|
|
||||||
|
|
||||||
/* === Chip Select (CS) auf PA5 gesetzt === */
|
|
||||||
cs-gpios = <&gpioa 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
|
|
||||||
|
|
||||||
/* Definiere den Flash-Chip als SPI NOR Gerät */
|
|
||||||
flash1: flash@0 {
|
|
||||||
compatible = "jedec,spi-nor";
|
|
||||||
reg = <0>;
|
|
||||||
label = "flash1";
|
|
||||||
|
|
||||||
/* JEDEC ID für einen Winbond W25Q128 (16 MBytes) */
|
|
||||||
jedec-id = [ef 40 18];
|
|
||||||
|
|
||||||
/* Speichergröße in Bytes (16 MBytes) */
|
|
||||||
size = <DT_SIZE_M(16)>;
|
|
||||||
|
|
||||||
/* Maximale Taktfrequenz - angepasst an STM32G431 Limits */
|
|
||||||
spi-max-frequency = <1000000>;
|
|
||||||
|
|
||||||
/* Partitions für externes Flash */
|
|
||||||
partitions {
|
|
||||||
compatible = "fixed-partitions";
|
|
||||||
#address-cells = <1>;
|
|
||||||
#size-cells = <1>;
|
|
||||||
|
|
||||||
/* Slot1 partition für MCUboot (sekundäres Image) - 80 KB (20 sectors @ 4KB) */
|
|
||||||
slot1_partition: partition@0 {
|
|
||||||
label = "image-1";
|
|
||||||
reg = <0x00000000 0x00014000>;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Scratch partition für MCUboot - 80 KB (20 sectors @ 4KB) */
|
|
||||||
scratch_partition: partition@14000 {
|
|
||||||
label = "scratch";
|
|
||||||
reg = <0x00014000 0x00014000>;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Speicher partition für LittleFS - ~15.83 MB */
|
|
||||||
storage_partition: partition@28000 {
|
|
||||||
label = "storage";
|
|
||||||
reg = <0x00028000 0x00FD8000>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
CONFIG_LOG=y
|
|
||||||
CONFIG_MCUBOOT_LOG_LEVEL_INF=y
|
|
||||||
|
|
||||||
# Enable UART console for MCUboot debug output
|
|
||||||
CONFIG_UART_CONSOLE=y
|
|
||||||
CONFIG_CONSOLE=y
|
|
||||||
CONFIG_MCUBOOT_INDICATION_LED=y
|
|
||||||
|
|
||||||
# Enable external SPI flash support
|
|
||||||
CONFIG_SPI=y
|
|
||||||
CONFIG_SPI_NOR=y
|
|
||||||
CONFIG_SPI_NOR_SFDP_DEVICETREE=n
|
|
||||||
CONFIG_FLASH=y
|
|
||||||
CONFIG_FLASH_MAP=y
|
|
||||||
CONFIG_GPIO=y
|
|
||||||
|
|
||||||
# Add SPI NOR specific configurations - use 4KB page size (required by driver)
|
|
||||||
CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096
|
|
||||||
CONFIG_SPI_NOR_INIT_PRIORITY=80
|
|
||||||
|
|
||||||
# Set maximum image sectors manually since auto doesn't work with external flash
|
|
||||||
CONFIG_BOOT_MAX_IMG_SECTORS_AUTO=n
|
|
||||||
CONFIG_BOOT_MAX_IMG_SECTORS=80
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
#include "common.dtsi"
|
|
||||||
|
|
||||||
/* MCUboot Configuration - Bootloader wird in boot_partition geschrieben */
|
|
||||||
/ {
|
|
||||||
chosen {
|
|
||||||
zephyr,code-partition = &boot_partition;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
rsource "../../lib/Kconfig"
|
|
||||||
source "Kconfig.zephyr"
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
VERSION_MAJOR = 0
|
|
||||||
VERSION_MINOR = 0
|
|
||||||
PATCHLEVEL = 1
|
|
||||||
VERSION_TWEAK = 1
|
|
||||||
EXTRAVERSION = devel
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
# Disable UART console
|
|
||||||
CONFIG_UART_CONSOLE=n
|
|
||||||
|
|
||||||
# Enable RTT console
|
|
||||||
CONFIG_RTT_CONSOLE=y
|
|
||||||
CONFIG_USE_SEGGER_RTT=y
|
|
||||||
CONFIG_SHELL_BACKEND_RTT=y
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
/ {
|
|
||||||
chosen {
|
|
||||||
zephyr,console = &rtt;
|
|
||||||
zephyr,shell = &rtt;
|
|
||||||
zephyr,settings-partition = &storage_partition;
|
|
||||||
};
|
|
||||||
|
|
||||||
rtt: rtt {
|
|
||||||
compatible = "segger,rtt-uart";
|
|
||||||
#address-cells = <1>;
|
|
||||||
#size-cells = <0>;
|
|
||||||
label = "RTT";
|
|
||||||
status = "okay";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
&flash0 {
|
|
||||||
partitions {
|
|
||||||
compatible = "fixed-partitions";
|
|
||||||
#address-cells = <1>;
|
|
||||||
#size-cells = <1>;
|
|
||||||
|
|
||||||
/* Application partition starts at the beginning of flash */
|
|
||||||
slot0_partition: partition@0 {
|
|
||||||
label = "image-0";
|
|
||||||
reg = <0x00000000 DT_SIZE_K(120)>;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Use the last 8K for settings */
|
|
||||||
storage_partition: partition@1E000 {
|
|
||||||
label = "storage";
|
|
||||||
reg = <0x0001E000 DT_SIZE_K(8)>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
&usart1 {
|
|
||||||
modbus0 {
|
|
||||||
compatible = "zephyr,modbus-serial";
|
|
||||||
status = "okay";
|
|
||||||
};
|
|
||||||
status = "okay";
|
|
||||||
};
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
/ {
|
|
||||||
aliases {
|
|
||||||
vnd7050aj = &vnd7050aj;
|
|
||||||
};
|
|
||||||
|
|
||||||
vnd7050aj: vnd7050aj {
|
|
||||||
compatible = "st,vnd7050aj";
|
|
||||||
status = "okay";
|
|
||||||
|
|
||||||
input0-gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>;
|
|
||||||
input1-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>;
|
|
||||||
select0-gpios = <&gpio0 3 GPIO_ACTIVE_HIGH>;
|
|
||||||
select1-gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>;
|
|
||||||
sense-enable-gpios = <&gpio0 5 GPIO_ACTIVE_HIGH>;
|
|
||||||
fault-reset-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
|
|
||||||
io-channels = <&adc0 0>;
|
|
||||||
r-sense-ohms = <1500>;
|
|
||||||
k-vcc = <4000>;
|
|
||||||
};
|
|
||||||
|
|
||||||
modbus_uart: uart_2 {
|
|
||||||
compatible = "zephyr,native-pty-uart";
|
|
||||||
status = "okay";
|
|
||||||
current-speed = <19200>;
|
|
||||||
|
|
||||||
modbus0: modbus0 {
|
|
||||||
compatible = "zephyr,modbus-serial";
|
|
||||||
status = "okay";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
&adc0 {
|
|
||||||
#address-cells = <1>;
|
|
||||||
#size-cells = <0>;
|
|
||||||
ref-internal-mv = <3300>;
|
|
||||||
ref-external1-mv = <5000>;
|
|
||||||
|
|
||||||
channel@0 {
|
|
||||||
reg = <0>;
|
|
||||||
zephyr,gain = "ADC_GAIN_1";
|
|
||||||
zephyr,reference = "ADC_REF_INTERNAL";
|
|
||||||
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
|
||||||
zephyr,resolution = <12>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
/ {
|
|
||||||
aliases {
|
|
||||||
vnd7050aj = &vnd7050aj;
|
|
||||||
};
|
|
||||||
|
|
||||||
vnd7050aj: vnd7050aj {
|
|
||||||
compatible = "st,vnd7050aj";
|
|
||||||
status = "okay";
|
|
||||||
|
|
||||||
input0-gpios = <&gpiob 3 GPIO_ACTIVE_HIGH>;
|
|
||||||
input1-gpios = <&gpiob 4 GPIO_ACTIVE_HIGH>;
|
|
||||||
select0-gpios = <&gpiob 0 GPIO_ACTIVE_HIGH>;
|
|
||||||
select1-gpios = <&gpiob 1 GPIO_ACTIVE_HIGH>;
|
|
||||||
sense-enable-gpios = <&gpiob 6 GPIO_ACTIVE_HIGH>;
|
|
||||||
fault-reset-gpios = <&gpiob 5 GPIO_ACTIVE_LOW>;
|
|
||||||
io-channels = <&adc1 1>;
|
|
||||||
r-sense-ohms = <1500>;
|
|
||||||
k-vcc = <4000>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
&adc1 {
|
|
||||||
status = "okay";
|
|
||||||
pinctrl-0 = <&adc1_in1_pa0>;
|
|
||||||
pinctrl-names = "default";
|
|
||||||
st,adc-clock-source = "SYNC";
|
|
||||||
st,adc-prescaler = <4>;
|
|
||||||
#address-cells = <1>;
|
|
||||||
#size-cells = <0>;
|
|
||||||
|
|
||||||
channel@1 {
|
|
||||||
reg = <1>;
|
|
||||||
zephyr,gain = "ADC_GAIN_1";
|
|
||||||
zephyr,reference = "ADC_REF_INTERNAL";
|
|
||||||
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
|
||||||
zephyr,resolution = <12>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
&usart1 {
|
|
||||||
modbus0 {
|
|
||||||
compatible = "zephyr,modbus-serial";
|
|
||||||
status = "okay";
|
|
||||||
};
|
|
||||||
status = "okay";
|
|
||||||
pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa10>; // PA9=TX, PA10=RX for Modbus communication
|
|
||||||
pinctrl-names = "default";
|
|
||||||
};
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
#include <zephyr/dt-bindings/gpio/gpio.h>
|
|
||||||
|
|
||||||
&zephyr_udc0 {
|
|
||||||
cdc_acm_uart0: cdc_acm_uart0 {
|
|
||||||
compatible = "zephyr,cdc-acm-uart";
|
|
||||||
|
|
||||||
modbus0 {
|
|
||||||
compatible = "zephyr,modbus-serial";
|
|
||||||
status = "okay";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
&usart1 {
|
|
||||||
/delete-node/ modbus0;
|
|
||||||
};
|
|
||||||
|
|
@ -1,88 +0,0 @@
|
||||||
# Copyright (c) 2024, Eduard Iten
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
description: |
|
|
||||||
STMicroelectronics VND7050AJ dual-channel high-side driver.
|
|
||||||
This is a GPIO and ADC controlled device.
|
|
||||||
|
|
||||||
compatible: "st,vnd7050aj"
|
|
||||||
|
|
||||||
include: base.yaml
|
|
||||||
|
|
||||||
properties:
|
|
||||||
input0-gpios:
|
|
||||||
type: phandle-array
|
|
||||||
required: true
|
|
||||||
description: GPIO to control output channel 0.
|
|
||||||
|
|
||||||
input1-gpios:
|
|
||||||
type: phandle-array
|
|
||||||
required: true
|
|
||||||
description: GPIO to control output channel 1.
|
|
||||||
|
|
||||||
select0-gpios:
|
|
||||||
type: phandle-array
|
|
||||||
required: true
|
|
||||||
description: GPIO for MultiSense selection bit 0.
|
|
||||||
|
|
||||||
select1-gpios:
|
|
||||||
type: phandle-array
|
|
||||||
required: true
|
|
||||||
description: GPIO for MultiSense selection bit 1.
|
|
||||||
|
|
||||||
sense-enable-gpios:
|
|
||||||
type: phandle-array
|
|
||||||
required: true
|
|
||||||
description: GPIO to enable the MultiSense output.
|
|
||||||
|
|
||||||
fault-reset-gpios:
|
|
||||||
type: phandle-array
|
|
||||||
required: true
|
|
||||||
description: GPIO to reset a latched fault (active-low).
|
|
||||||
|
|
||||||
io-channels:
|
|
||||||
type: phandle-array
|
|
||||||
required: true
|
|
||||||
description: |
|
|
||||||
ADC channel connected to the MultiSense pin. This should be an
|
|
||||||
io-channels property pointing to the ADC controller and channel number.
|
|
||||||
|
|
||||||
r-sense-ohms:
|
|
||||||
type: int
|
|
||||||
required: true
|
|
||||||
description: |
|
|
||||||
Value of the external sense resistor connected from the MultiSense
|
|
||||||
pin to GND, specified in Ohms. This is critical for correct
|
|
||||||
conversion of the analog readings.
|
|
||||||
|
|
||||||
k-factor:
|
|
||||||
type: int
|
|
||||||
default: 1500
|
|
||||||
description: |
|
|
||||||
Factor between PowerMOS and SenseMOS.
|
|
||||||
|
|
||||||
k-vcc:
|
|
||||||
type: int
|
|
||||||
default: 8000
|
|
||||||
description: |
|
|
||||||
VCC sense ratio multiplied by 1000. Used for supply voltage calculation.
|
|
||||||
|
|
||||||
t-sense-0:
|
|
||||||
type: int
|
|
||||||
default: 25
|
|
||||||
description: |
|
|
||||||
Temperature sense reference temperature in degrees Celsius.
|
|
||||||
|
|
||||||
v-sense-0:
|
|
||||||
type: int
|
|
||||||
default: 2070
|
|
||||||
description: |
|
|
||||||
Temperature sense reference voltage in millivolts.
|
|
||||||
|
|
||||||
k-tchip:
|
|
||||||
type: int
|
|
||||||
default: -5500
|
|
||||||
description: |
|
|
||||||
Temperature sense gain coefficient multiplied by 1000.
|
|
||||||
Used for chip temperature calculation.
|
|
||||||
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
CONFIG_USB_DEVICE_STACK=y
|
|
||||||
CONFIG_USB_DEVICE_PRODUCT="Modbus slave node"
|
|
||||||
CONFIG_UART_LINE_CTRL=y
|
|
||||||
CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
# Enable Console and printk for logging
|
|
||||||
CONFIG_CONSOLE=y
|
|
||||||
CONFIG_LOG=y
|
|
||||||
|
|
||||||
# Enable Shell
|
|
||||||
CONFIG_SHELL=y
|
|
||||||
CONFIG_REBOOT=y
|
|
||||||
CONFIG_SHELL_MODBUS=n
|
|
||||||
CONFIG_SHELL_VALVE=y
|
|
||||||
CONFIG_SHELL_SYSTEM=y
|
|
||||||
|
|
||||||
# Enable Settings Subsystem
|
|
||||||
CONFIG_SETTINGS=y
|
|
||||||
CONFIG_SETTINGS_NVS=y
|
|
||||||
CONFIG_NVS=y
|
|
||||||
CONFIG_FLASH=y
|
|
||||||
CONFIG_FLASH_MAP=y
|
|
||||||
CONFIG_FLASH_PAGE_LAYOUT=y
|
|
||||||
|
|
||||||
# Config modbus
|
|
||||||
CONFIG_UART_INTERRUPT_DRIVEN=y
|
|
||||||
CONFIG_MODBUS=y
|
|
||||||
CONFIG_MODBUS_ROLE_SERVER=y
|
|
||||||
CONFIG_MODBUS_LOG_LEVEL_DBG=y
|
|
||||||
|
|
||||||
# enable Valve Driver
|
|
||||||
CONFIG_LIB_VALVE=y
|
|
||||||
CONFIG_LOG_VALVE_LEVEL=4
|
|
||||||
|
|
||||||
# Enable VND7050AJ
|
|
||||||
CONFIG_VND7050AJ=y
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
#include <zephyr/kernel.h>
|
|
||||||
#include <zephyr/logging/log.h>
|
|
||||||
#include <zephyr/settings/settings.h>
|
|
||||||
#include <app_version.h>
|
|
||||||
#include <lib/valve.h>
|
|
||||||
#include <lib/vnd7050aj.h>
|
|
||||||
|
|
||||||
LOG_MODULE_REGISTER(main, LOG_LEVEL_INF);
|
|
||||||
|
|
||||||
int main(void)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
LOG_INF("Starting Irrigation System CAN Node, Version %s", APP_VERSION_EXTENDED_STRING);
|
|
||||||
|
|
||||||
/* Initialize settings subsystem */
|
|
||||||
rc = settings_subsys_init();
|
|
||||||
if (rc != 0) {
|
|
||||||
LOG_ERR("Failed to initialize settings subsystem (%d)", rc);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
LOG_INF("Settings subsystem initialized");
|
|
||||||
|
|
||||||
/* Load settings from storage */
|
|
||||||
rc = settings_load();
|
|
||||||
if (rc == 0) {
|
|
||||||
LOG_INF("Settings loaded successfully");
|
|
||||||
} else {
|
|
||||||
LOG_WRN("Failed to load settings (%d)", rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize valve system */
|
|
||||||
rc = valve_init();
|
|
||||||
if (rc != 0) {
|
|
||||||
LOG_ERR("Failed to initialize valve system (%d)", rc);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
LOG_INF("Valve system initialized");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
SB_CONFIG_BOOTLOADER_MCUBOOT=y
|
|
||||||
SB_CONFIG_MCUBOOT_MODE_SINGLE_APP=y
|
|
||||||
|
|
||||||
CONFIG_LOG=y
|
|
||||||
CONFIG_MCUBOOT_LOG_LEVEL_INF=y
|
|
||||||
|
|
@ -2,9 +2,7 @@ cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||||
|
|
||||||
project(can_node LANGUAGES C)
|
project(firmware_node LANGUAGES C)
|
||||||
|
|
||||||
zephyr_include_directories(../../include)
|
zephyr_include_directories(../../include)
|
||||||
add_subdirectory(../../lib lib)
|
add_subdirectory(../../lib lib)
|
||||||
|
|
||||||
target_sources(app PRIVATE src/main.c)
|
target_sources(app PRIVATE src/main.c)
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
# Firmware Node Application
|
||||||
|
|
||||||
|
This Zephyr application provides firmware management capabilities for the irrigation system.
|
||||||
|
|
||||||
|
**Tested on Zephyr 4.1.99**
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
### Step 1: Shell with Reset Command
|
||||||
|
- Shell interface with custom "reset" command
|
||||||
|
- Warm reboot functionality
|
||||||
|
|
||||||
|
### Planned Features
|
||||||
|
- MCUboot support with partition manager
|
||||||
|
- Firmware version display
|
||||||
|
- MCUmgr support for OTA updates
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
```bash
|
||||||
|
west build -p auto -b weact_stm32g431_core apps/firmware_node -- -DBOARD_FLASH_RUNNER=blackmagicprobe
|
||||||
|
```
|
||||||
|
|
||||||
|
## Flashing
|
||||||
|
|
||||||
|
```bash
|
||||||
|
west flash
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Connect to the device via serial console and use the shell:
|
||||||
|
- `reset` - Reboot the system
|
||||||
|
- `help` - Show available commands
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Flash partition layout for STM32G431 (128KB total flash)
|
||||||
|
* MCUboot + single application slot configuration
|
||||||
|
*/
|
||||||
|
|
||||||
|
&flash0 {
|
||||||
|
partitions {
|
||||||
|
compatible = "fixed-partitions";
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
boot_partition: partition@0 {
|
||||||
|
label = "mcuboot";
|
||||||
|
reg = <0x00000000 0x0000A000>; /* 40 KB for MCUboot */
|
||||||
|
read-only;
|
||||||
|
};
|
||||||
|
|
||||||
|
slot0_partition: partition@A000 {
|
||||||
|
label = "image-0";
|
||||||
|
reg = <0x0000A000 0x00016000>; /* 88 KB for application */
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/ {
|
||||||
|
chosen {
|
||||||
|
zephyr,code-partition = &slot0_partition;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
# Board specific configuration for weact_stm32g431_core
|
||||||
|
# This file can be used for board-specific overrides if needed
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "flash_partitions_128kb.dtsi"
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
&flash0 {
|
||||||
|
partitions {
|
||||||
|
compatible = "fixed-partitions";
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
boot_partition: partition@0 {
|
||||||
|
label = "mcuboot";
|
||||||
|
reg = <0x00000000 0x00008000>; /* 32 KB */
|
||||||
|
read-only;
|
||||||
|
};
|
||||||
|
|
||||||
|
slot0_partition: partition@8000 {
|
||||||
|
label = "image-0";
|
||||||
|
reg = <0x00008000 0x00018000>; /* 96 KB */
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
# Partition manager configuration for firmware_node
|
||||||
|
|
||||||
|
# Boot partition (MCUboot)
|
||||||
|
mcuboot_primary:
|
||||||
|
address: 0x00000000
|
||||||
|
size: 0x8000
|
||||||
|
region: flash_primary
|
||||||
|
|
||||||
|
# Application partition (primary slot)
|
||||||
|
mcuboot_primary_app:
|
||||||
|
address: 0x00008000
|
||||||
|
size: 0x18000
|
||||||
|
region: flash_primary
|
||||||
|
|
||||||
|
# Secondary slot for updates
|
||||||
|
mcuboot_secondary:
|
||||||
|
address: 0x00020000
|
||||||
|
size: 0x18000
|
||||||
|
region: flash_primary
|
||||||
|
|
||||||
|
# Settings partition
|
||||||
|
settings_partition:
|
||||||
|
address: 0x00038000
|
||||||
|
size: 0x8000
|
||||||
|
region: flash_primary
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
# Enable Console and printk for logging
|
||||||
|
CONFIG_CONSOLE=y
|
||||||
|
CONFIG_LOG=y
|
||||||
|
CONFIG_LOG_PROCESS_THREAD=y
|
||||||
|
|
||||||
|
# Enable Shell
|
||||||
|
CONFIG_SHELL=y
|
||||||
|
CONFIG_REBOOT=y
|
||||||
|
|
||||||
|
# Enable the reset command
|
||||||
|
CONFIG_KERNEL_SHELL=y
|
||||||
|
|
||||||
|
# Enable settings for persistent storage
|
||||||
|
CONFIG_SETTINGS=y
|
||||||
|
CONFIG_SETTINGS_NVS=y
|
||||||
|
CONFIG_NVS=y
|
||||||
|
|
||||||
|
# Enable Flash and Flash Map for image trailer manipulation
|
||||||
|
CONFIG_FLASH=y
|
||||||
|
CONFIG_FLASH_MAP=y
|
||||||
|
CONFIG_FLASH_PAGE_LAYOUT=y
|
||||||
|
|
@ -0,0 +1,167 @@
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
#include <zephyr/shell/shell.h>
|
||||||
|
#include <zephyr/sys/reboot.h>
|
||||||
|
#include <zephyr/drivers/flash.h>
|
||||||
|
#include <zephyr/storage/flash_map.h>
|
||||||
|
#include <zephyr/devicetree.h>
|
||||||
|
|
||||||
|
LOG_MODULE_REGISTER(firmware_node, LOG_LEVEL_INF);
|
||||||
|
|
||||||
|
// Image header magic number (from MCUboot)
|
||||||
|
#define IMAGE_MAGIC 0x96f3b83d
|
||||||
|
#define IMAGE_HEADER_SIZE 32
|
||||||
|
|
||||||
|
// Function to invalidate current image and trigger serial recovery
|
||||||
|
static int invalidate_current_image(void)
|
||||||
|
{
|
||||||
|
const struct flash_area *fa;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
// Get the flash area for the current image slot (slot0_partition)
|
||||||
|
rc = flash_area_open(FIXED_PARTITION_ID(slot0_partition), &fa);
|
||||||
|
if (rc != 0) {
|
||||||
|
LOG_ERR("Failed to open flash area: %d", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the flash area is valid
|
||||||
|
if (fa->fa_id != FIXED_PARTITION_ID(slot0_partition)) {
|
||||||
|
LOG_ERR("Invalid flash area ID: %d", fa->fa_id);
|
||||||
|
flash_area_close(fa);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the flash device associated with this area
|
||||||
|
// This is necessary to perform erase operations
|
||||||
|
|
||||||
|
const struct device *flash_dev = flash_area_get_device(fa);
|
||||||
|
if (flash_dev == NULL) {
|
||||||
|
LOG_ERR("Failed to get flash device for area");
|
||||||
|
flash_area_close(fa);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct flash_pages_info page_info;
|
||||||
|
off_t last_block_offset;
|
||||||
|
|
||||||
|
// Find the last block of the flash area
|
||||||
|
rc = flash_get_page_info_by_offs(flash_dev, fa->fa_off + fa->fa_size - 1, &page_info);
|
||||||
|
if (rc != 0) {
|
||||||
|
LOG_ERR("Failed to get page info: %d", rc);
|
||||||
|
flash_area_close(fa);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the last block offset
|
||||||
|
rc = flash_get_page_info_by_offs(flash_dev, fa->fa_off + fa->fa_size - 1, &page_info);
|
||||||
|
if (rc != 0) {
|
||||||
|
LOG_ERR("Failed to get page info: %d", rc);
|
||||||
|
flash_area_close(fa);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
last_block_offset = page_info.start_offset;
|
||||||
|
|
||||||
|
// Convert absolute flash offset to relative offset within the flash area
|
||||||
|
off_t relative_offset = last_block_offset - fa->fa_off;
|
||||||
|
|
||||||
|
// Erase the image trailer/metadata at the end of the partition
|
||||||
|
LOG_INF("Erasing image trailer at absolute offset: %ld, relative offset: %ld, size: %d bytes",
|
||||||
|
last_block_offset, relative_offset, page_info.size);
|
||||||
|
rc = flash_area_erase(fa, relative_offset, page_info.size);
|
||||||
|
if (rc != 0) {
|
||||||
|
LOG_ERR("Failed to erase image trailer: %d", rc);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
LOG_INF("Image trailer erased successfully");
|
||||||
|
}
|
||||||
|
|
||||||
|
flash_area_close(fa);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
// Custom reset command handler
|
||||||
|
static int cmd_reset(const struct shell *shell, size_t argc, char **argv)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(argc);
|
||||||
|
ARG_UNUSED(argv);
|
||||||
|
|
||||||
|
shell_print(shell, "Resetting system...");
|
||||||
|
k_msleep(100); // Give time for the message to be sent
|
||||||
|
sys_reboot(SYS_REBOOT_COLD);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MCUboot serial recovery command handler
|
||||||
|
static int cmd_recovery(const struct shell *shell, size_t argc, char **argv)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(argc);
|
||||||
|
ARG_UNUSED(argv);
|
||||||
|
|
||||||
|
shell_print(shell, "Entering MCUboot serial recovery mode...");
|
||||||
|
shell_print(shell, "Corrupting current image magic to trigger recovery...");
|
||||||
|
|
||||||
|
// Invalidate the current image by corrupting its header
|
||||||
|
int rc = invalidate_current_image();
|
||||||
|
if (rc != 0) {
|
||||||
|
shell_error(shell, "Failed to invalidate image: %d", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
shell_print(shell, "Image magic corrupted. System will reset and MCUboot will detect bad image.");
|
||||||
|
shell_print(shell, "MCUboot should show error and wait for recovery.");
|
||||||
|
k_msleep(100); // Give time for the message to be sent
|
||||||
|
|
||||||
|
// Reset the system - MCUboot will detect invalid image and enter serial recovery
|
||||||
|
// log_process(true);
|
||||||
|
// sys_reboot(SYS_REBOOT_COLD);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command to show firmware info
|
||||||
|
static int cmd_info(const struct shell *shell, size_t argc, char **argv)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(argc);
|
||||||
|
ARG_UNUSED(argv);
|
||||||
|
|
||||||
|
const struct flash_area *fa;
|
||||||
|
int rc = flash_area_open(FIXED_PARTITION_ID(slot0_partition), &fa);
|
||||||
|
|
||||||
|
if (rc != 0) {
|
||||||
|
shell_error(shell, "Failed to open flash area: %d", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the first few bytes to check the image header
|
||||||
|
uint32_t magic;
|
||||||
|
rc = flash_area_read(fa, 0, &magic, sizeof(magic));
|
||||||
|
if (rc == 0) {
|
||||||
|
shell_print(shell, "Image magic: 0x%08x", magic);
|
||||||
|
if (magic == IMAGE_MAGIC) {
|
||||||
|
shell_print(shell, "Image header is valid");
|
||||||
|
shell_print(shell, "Image starts at flash offset: 0x%lx", (unsigned long)fa->fa_off);
|
||||||
|
shell_print(shell, "Image partition size: %d bytes", fa->fa_size);
|
||||||
|
} else {
|
||||||
|
shell_print(shell, "Image header is INVALID (expected 0x%08x)", IMAGE_MAGIC);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
shell_error(shell, "Failed to read image header: %d", rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
flash_area_close(fa);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHELL_CMD_REGISTER(reset, NULL, "Reset the system", cmd_reset);
|
||||||
|
SHELL_CMD_REGISTER(recovery, NULL, "Enter MCUboot serial recovery mode", cmd_recovery);
|
||||||
|
SHELL_CMD_REGISTER(info, NULL, "Show firmware info", cmd_info);
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
LOG_INF("Firmware Node starting up");
|
||||||
|
LOG_INF("Shell with reset command available");
|
||||||
|
LOG_INF("Serial recovery command available");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Sysbuild configuration for firmware_node with MCUboot
|
||||||
|
|
||||||
|
# Enable MCUboot as bootloader
|
||||||
|
set(SB_CONFIG_BOOTLOADER_MCUBOOT TRUE)
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Sysbuild configuration for firmware_node with MCUboot
|
||||||
|
|
||||||
|
# Enable MCUboot as bootloader
|
||||||
|
SB_CONFIG_BOOTLOADER_MCUBOOT=y
|
||||||
|
SB_CONFIG_MCUBOOT_MODE_SINGLE_APP=y
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../boards/flash_partitions_128kb.dtsi"
|
||||||
|
|
||||||
|
/ {
|
||||||
|
chosen {
|
||||||
|
zephyr,code-partition = &slot0_partition;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
# MCUboot configuration for firmware_node
|
||||||
|
# Enable basic console and logging for debugging
|
||||||
|
CONFIG_LOG=y
|
||||||
|
CONFIG_BOOT_BANNER=y
|
||||||
|
CONFIG_CONSOLE=y
|
||||||
|
CONFIG_UART_CONSOLE=y
|
||||||
|
CONFIG_PRINTK=y
|
||||||
|
|
||||||
|
# Single slot configuration (no upgrades)
|
||||||
|
CONFIG_SINGLE_APPLICATION_SLOT=y
|
||||||
|
|
||||||
|
# Enable serial recovery mode (temporarily commented out for debugging)
|
||||||
|
# CONFIG_MCUBOOT_SERIAL=y
|
||||||
|
# CONFIG_BOOT_SERIAL_UART=y
|
||||||
|
# CONFIG_BOOT_SERIAL_DETECT_PORT=y
|
||||||
|
|
||||||
|
# Disable signature validation for testing to save space
|
||||||
|
CONFIG_BOOT_SIGNATURE_TYPE_NONE=y
|
||||||
|
|
||||||
|
# Size optimizations to fit in 40KB flash
|
||||||
|
CONFIG_SIZE_OPTIMIZATIONS=y
|
||||||
|
CONFIG_CBPRINTF_NANO=y
|
||||||
|
CONFIG_MINIMAL_LIBC=y
|
||||||
|
CONFIG_ASSERT=n
|
||||||
|
|
||||||
|
# Disable debug features for size
|
||||||
|
CONFIG_DEBUG_INFO=n
|
||||||
|
CONFIG_DEBUG_OPTIMIZATIONS=n
|
||||||
|
|
||||||
|
# Minimal heap for size optimization
|
||||||
|
CONFIG_HEAP_MEM_POOL_SIZE=0
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
/*
|
||||||
|
* MCUboot device tree overlay for firmware_node
|
||||||
|
* Uses shared flash partition layout
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../boards/flash_partitions_128kb.dtsi"
|
||||||
|
|
||||||
|
/ {
|
||||||
|
chosen {
|
||||||
|
zephyr,code-partition = &boot_partition;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* MCUboot specific overlay for weact_stm32g431_core
|
||||||
|
* This overlay defines flash partitions for MCUboot
|
||||||
|
*/
|
||||||
|
|
||||||
|
&flash0 {
|
||||||
|
partitions {
|
||||||
|
compatible = "fixed-partitions";
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
boot_partition: partition@0 {
|
||||||
|
label = "mcuboot";
|
||||||
|
reg = <0x00000000 0x00008000>;
|
||||||
|
};
|
||||||
|
slot0_partition: partition@8000 {
|
||||||
|
label = "image-0";
|
||||||
|
reg = <0x00008000 0x0000E000>;
|
||||||
|
};
|
||||||
|
slot1_partition: partition@16000 {
|
||||||
|
label = "image-1";
|
||||||
|
reg = <0x00016000 0x0000E000>;
|
||||||
|
};
|
||||||
|
storage_partition: partition@24000 {
|
||||||
|
label = "storage";
|
||||||
|
reg = <0x00024000 0x00004000>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
&chosen {
|
||||||
|
zephyr,boot-partition = &boot_partition;
|
||||||
|
};
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
cmake_minimum_required(VERSION 3.20.5)
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
|
# Include the main 'software' directory as a module to find boards, libs, etc.
|
||||||
|
list(APPEND ZEPHYR_EXTRA_MODULES ${CMAKE_CURRENT_SOURCE_DIR}/../..)
|
||||||
|
|
||||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||||
|
|
||||||
project(gateway)
|
project(gateway)
|
||||||
target_sources(app PRIVATE src/main.c)
|
|
||||||
|
|
||||||
target_include_directories(app PRIVATE include)
|
target_sources(app PRIVATE src/main.c)
|
||||||
|
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
# README for the Hello World Zephyr Application
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
This is a minimal Hello World application built using the Zephyr RTOS. The application demonstrates basic logging functionality by printing a message every 5 seconds, including the version number of the application.
|
|
||||||
|
|
||||||
## Project Structure
|
|
||||||
|
|
||||||
The project consists of the following files:
|
|
||||||
|
|
||||||
- `src/main.c`: The entry point of the application that initializes logging and sets up a timer.
|
|
||||||
- `include/app_version.h`: Header file that defines the application version.
|
|
||||||
- `VERSION`: A text file containing the version number of the application.
|
|
||||||
- `prj.conf`: Configuration file for the Zephyr project, specifying necessary options.
|
|
||||||
- `CMakeLists.txt`: Build configuration file for CMake.
|
|
||||||
- `README.md`: Documentation for the project.
|
|
||||||
|
|
||||||
## Building the Application
|
|
||||||
|
|
||||||
To build the application, follow these steps:
|
|
||||||
|
|
||||||
1. Ensure you have the Zephyr development environment set up.
|
|
||||||
2. Navigate to the `apps/gateway` directory.
|
|
||||||
3. Run the following command to build the application:
|
|
||||||
|
|
||||||
```
|
|
||||||
west build -b <your_board> .
|
|
||||||
```
|
|
||||||
|
|
||||||
Replace `<your_board>` with the appropriate board name.
|
|
||||||
|
|
||||||
## Running the Application
|
|
||||||
|
|
||||||
After building the application, you can flash it to your board using:
|
|
||||||
|
|
||||||
```
|
|
||||||
west flash
|
|
||||||
```
|
|
||||||
|
|
||||||
Once the application is running, you will see log messages printed every 5 seconds, including the version number.
|
|
||||||
|
|
||||||
## Version
|
|
||||||
|
|
||||||
The version of this application can be found in the `VERSION` file and is also included in the log messages.
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
&flash0 {
|
|
||||||
reg = <0x0 0x400000>; /* 4MB flash */
|
|
||||||
};
|
|
||||||
|
|
||||||
#include "espressif/partitions_0x0_default_4M.dtsi"
|
|
||||||
|
|
||||||
/ {
|
|
||||||
chosen {
|
|
||||||
zephyr,shell-uart = &uart0;
|
|
||||||
zephyr,uart-mcumgr = &usb_serial;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
&usb_serial {
|
|
||||||
status = "okay";
|
|
||||||
};
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
#include "common_4MB.dtsi"
|
|
||||||
|
|
@ -1,47 +1,2 @@
|
||||||
# -------------------
|
# Gateway Configuration
|
||||||
# Logging and Console
|
CONFIG_NETWORKING=y
|
||||||
# -------------------
|
|
||||||
CONFIG_LOG=y
|
|
||||||
CONFIG_UART_CONSOLE=y
|
|
||||||
|
|
||||||
# -------------
|
|
||||||
# Zephyr Shell
|
|
||||||
# -------------
|
|
||||||
CONFIG_SHELL=y
|
|
||||||
CONFIG_KERNEL_SHELL=y
|
|
||||||
CONFIG_REBOOT=y
|
|
||||||
|
|
||||||
# -------------------
|
|
||||||
# MCUmgr OS Management
|
|
||||||
# -------------------
|
|
||||||
CONFIG_MCUMGR=y
|
|
||||||
CONFIG_MCUMGR_GRP_OS=y
|
|
||||||
CONFIG_MCUMGR_TRANSPORT_UART=y
|
|
||||||
|
|
||||||
# -------------------
|
|
||||||
# MCUmgr Filesystem Group
|
|
||||||
# -------------------
|
|
||||||
CONFIG_MCUMGR_GRP_FS=y
|
|
||||||
|
|
||||||
# -------------------
|
|
||||||
# LittleFS and Flash
|
|
||||||
# -------------------
|
|
||||||
CONFIG_FILE_SYSTEM=y
|
|
||||||
CONFIG_FILE_SYSTEM_LITTLEFS=y
|
|
||||||
CONFIG_FLASH=y
|
|
||||||
CONFIG_FLASH_MAP=y
|
|
||||||
|
|
||||||
# -------------------
|
|
||||||
# Settings Subsystem
|
|
||||||
# -------------------
|
|
||||||
CONFIG_SETTINGS=y
|
|
||||||
CONFIG_SETTINGS_FILE=y
|
|
||||||
CONFIG_SETTINGS_FILE_PATH="/lfs/settings.bin"
|
|
||||||
|
|
||||||
# -------------------
|
|
||||||
# Dependencies
|
|
||||||
# -------------------
|
|
||||||
CONFIG_NET_BUF=y
|
|
||||||
CONFIG_ZCBOR=y
|
|
||||||
CONFIG_CRC=y
|
|
||||||
CONFIG_BASE64=y
|
|
||||||
|
|
|
||||||
|
|
@ -1,136 +1,13 @@
|
||||||
#include <zephyr/fs/fs.h>
|
/*
|
||||||
#include <zephyr/fs/littlefs.h>
|
* Copyright (c) 2025 Eduard Iten
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
#include <zephyr/kernel.h>
|
#include <zephyr/kernel.h>
|
||||||
#include <zephyr/logging/log.h>
|
|
||||||
#include <zephyr/settings/settings.h>
|
|
||||||
#include <zephyr/shell/shell.h>
|
|
||||||
#include <app_version.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
LOG_MODULE_REGISTER(hello_world);
|
|
||||||
|
|
||||||
/* LittleFS mount configuration for 'storage_partition' partition */
|
|
||||||
FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(storage_partition);
|
|
||||||
static struct fs_mount_t littlefs_mnt = {
|
|
||||||
.type = FS_LITTLEFS,
|
|
||||||
.mnt_point = "/lfs",
|
|
||||||
.fs_data = &storage_partition, // default config macro
|
|
||||||
.storage_dev = (void *)FIXED_PARTITION_ID(storage_partition),
|
|
||||||
};
|
|
||||||
|
|
||||||
static char my_setting[32] = "default";
|
|
||||||
|
|
||||||
static int my_settings_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg)
|
|
||||||
{
|
|
||||||
if (strcmp(name, "value") == 0) {
|
|
||||||
if (len > sizeof(my_setting) - 1) {
|
|
||||||
len = sizeof(my_setting) - 1;
|
|
||||||
}
|
|
||||||
if (read_cb(cb_arg, my_setting, len) == len) {
|
|
||||||
my_setting[len] = '\0';
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
return -ENOENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int my_settings_export(int (*export_func)(const char *, const void *, size_t))
|
|
||||||
{
|
|
||||||
return export_func("my/setting/value", my_setting, strlen(my_setting));
|
|
||||||
}
|
|
||||||
|
|
||||||
SETTINGS_STATIC_HANDLER_DEFINE(my, "my/setting", NULL, my_settings_set, NULL, my_settings_export);
|
|
||||||
|
|
||||||
static int cmd_my_get(const struct shell *shell, size_t argc, char **argv)
|
|
||||||
{
|
|
||||||
shell_print(shell, "my_setting = '%s'", my_setting);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cmd_my_reset(const struct shell *shell, size_t argc, char **argv)
|
|
||||||
{
|
|
||||||
strcpy(my_setting, "default");
|
|
||||||
settings_save();
|
|
||||||
shell_print(shell, "my_setting reset to default");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Improved set command: join all arguments for whitespace support
|
|
||||||
static int cmd_my_set(const struct shell *shell, size_t argc, char **argv)
|
|
||||||
{
|
|
||||||
if (argc < 2) {
|
|
||||||
shell_error(shell, "Usage: my set <value>");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
// Join all argv[1..] with spaces
|
|
||||||
size_t i, pos = 0;
|
|
||||||
my_setting[0] = '\0';
|
|
||||||
for (i = 1; i < argc; ++i) {
|
|
||||||
size_t left = sizeof(my_setting) - 1 - pos;
|
|
||||||
if (left == 0)
|
|
||||||
break;
|
|
||||||
strncat(my_setting, argv[i], left);
|
|
||||||
pos = strlen(my_setting);
|
|
||||||
if (i < argc - 1 && left > 1) {
|
|
||||||
strncat(my_setting, " ", left - 1);
|
|
||||||
pos = strlen(my_setting);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
my_setting[sizeof(my_setting) - 1] = '\0';
|
|
||||||
settings_save();
|
|
||||||
shell_print(shell, "my_setting set to '%s'", my_setting);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
SHELL_STATIC_SUBCMD_SET_CREATE(my_subcmds,
|
|
||||||
SHELL_CMD(get, NULL, "Get my_setting", cmd_my_get),
|
|
||||||
SHELL_CMD(set, NULL, "Set my_setting (supports spaces)", cmd_my_set),
|
|
||||||
SHELL_CMD(reset, NULL, "Reset my_setting to default and compact settings file", cmd_my_reset),
|
|
||||||
SHELL_SUBCMD_SET_END);
|
|
||||||
|
|
||||||
SHELL_CMD_REGISTER(my, &my_subcmds, "My settings commands", NULL);
|
|
||||||
|
|
||||||
static void compact_settings_file(void)
|
|
||||||
{
|
|
||||||
struct fs_file_t file;
|
|
||||||
fs_file_t_init(&file);
|
|
||||||
int rc = fs_open(&file, "/lfs/settings.bin", FS_O_WRITE | FS_O_CREATE | FS_O_TRUNC);
|
|
||||||
if (rc == 0) {
|
|
||||||
fs_close(&file);
|
|
||||||
LOG_INF("Settings file compacted (truncated and recreated)");
|
|
||||||
} else if (rc == -ENOENT) {
|
|
||||||
LOG_INF("Settings file did not exist, created new");
|
|
||||||
} else {
|
|
||||||
LOG_ERR("Failed to compact settings file (%d)", rc);
|
|
||||||
}
|
|
||||||
settings_save();
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
int rc = fs_mount(&littlefs_mnt);
|
printk("Hello from Gateway!\n");
|
||||||
if (rc < 0) {
|
|
||||||
LOG_ERR("Error mounting LittleFS [%d]", rc);
|
|
||||||
} else {
|
|
||||||
LOG_INF("LittleFS mounted at /lfs");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize settings subsystem */
|
|
||||||
settings_subsys_init();
|
|
||||||
LOG_INF("Settings subsystem initialized");
|
|
||||||
|
|
||||||
/* Load settings from storage */
|
|
||||||
rc = settings_load();
|
|
||||||
if (rc == 0) {
|
|
||||||
LOG_INF("Settings loaded: my_setting='%s'", my_setting);
|
|
||||||
} else {
|
|
||||||
LOG_ERR("Failed to load settings (%d)", rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Compact settings file on each start */
|
|
||||||
compact_settings_file();
|
|
||||||
|
|
||||||
LOG_INF("Hello World! Version: %s", APP_VERSION_EXTENDED_STRING);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
SB_CONFIG_BOOTLOADER_MCUBOOT=y
|
|
||||||
SB_CONFIG_MCUBOOT_MODE_SINGLE_APP=y
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
#include "../boards/common_4MB.dtsi"
|
|
||||||
|
|
||||||
/* Application Configuration - Firmware goes to slot0_partition (0x20000) */
|
|
||||||
/ {
|
|
||||||
chosen {
|
|
||||||
zephyr,code-partition = &slot0_partition;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
CONFIG_LOG=y
|
|
||||||
CONFIG_MCUBOOT_LOG_LEVEL_INF=y
|
|
||||||
CONFIG_UART_CONSOLE=n
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
#include "../boards/common_4MB.dtsi"
|
|
||||||
|
|
||||||
/* MCUboot Configuration - Bootloader goes to boot_partition (0x0) */
|
|
||||||
/ {
|
|
||||||
chosen {
|
|
||||||
zephyr,code-partition = &boot_partition;
|
|
||||||
};
|
|
||||||
aliases {
|
|
||||||
mcuboot-button0 = &user_button1;
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit 6e669cfc4e400c3ef6e55c16401788ce0d804577
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
{
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"name": "Linux",
|
|
||||||
"compileCommands": "${workspaceFolder}/build/compile_commands.json",
|
|
||||||
"cStandard": "c99",
|
|
||||||
"cppStandard": "gnu++17",
|
|
||||||
"intelliSenseMode": "linux-gcc-arm"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"version": 4
|
|
||||||
}
|
|
||||||
|
|
@ -3,8 +3,6 @@ cmake_minimum_required(VERSION 3.20)
|
||||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||||
|
|
||||||
project(slave_node LANGUAGES C)
|
project(slave_node LANGUAGES C)
|
||||||
|
|
||||||
zephyr_include_directories(../../include)
|
zephyr_include_directories(../../include)
|
||||||
add_subdirectory(../../lib lib)
|
add_subdirectory(../../lib lib)
|
||||||
|
target_sources(app PRIVATE src/main.c)
|
||||||
target_sources(app PRIVATE src/main.c)
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
VERSION_MAJOR = 0
|
|
||||||
VERSION_MINOR = 0
|
|
||||||
PATCHLEVEL = 1
|
|
||||||
VERSION_TWEAK = 1
|
|
||||||
EXTRAVERSION = devel
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
/ {
|
|
||||||
aliases {
|
|
||||||
vnd7050aj = &vnd7050aj;
|
|
||||||
};
|
|
||||||
|
|
||||||
vnd7050aj: vnd7050aj {
|
|
||||||
compatible = "st,vnd7050aj";
|
|
||||||
status = "okay";
|
|
||||||
|
|
||||||
input0-gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>;
|
|
||||||
input1-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>;
|
|
||||||
select0-gpios = <&gpio0 3 GPIO_ACTIVE_HIGH>;
|
|
||||||
select1-gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>;
|
|
||||||
sense-enable-gpios = <&gpio0 5 GPIO_ACTIVE_HIGH>;
|
|
||||||
fault-reset-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
|
|
||||||
io-channels = <&adc0 0>;
|
|
||||||
r-sense-ohms = <1500>;
|
|
||||||
k-vcc = <4000>;
|
|
||||||
};
|
|
||||||
|
|
||||||
modbus_uart: uart_2 {
|
|
||||||
compatible = "zephyr,native-pty-uart";
|
|
||||||
status = "okay";
|
|
||||||
current-speed = <19200>;
|
|
||||||
|
|
||||||
modbus0: modbus0 {
|
|
||||||
compatible = "zephyr,modbus-serial";
|
|
||||||
status = "okay";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
&adc0 {
|
|
||||||
#address-cells = <1>;
|
|
||||||
#size-cells = <0>;
|
|
||||||
ref-internal-mv = <3300>;
|
|
||||||
ref-external1-mv = <5000>;
|
|
||||||
|
|
||||||
channel@0 {
|
|
||||||
reg = <0>;
|
|
||||||
zephyr,gain = "ADC_GAIN_1";
|
|
||||||
zephyr,reference = "ADC_REF_INTERNAL";
|
|
||||||
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
|
||||||
zephyr,resolution = <12>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,40 +1,16 @@
|
||||||
/ {
|
/ {
|
||||||
aliases {
|
vnd7050aj: vnd7050aj {
|
||||||
vnd7050aj = &vnd7050aj;
|
compatible = "vnd7050aj-valve-controller";
|
||||||
};
|
status = "okay";
|
||||||
|
|
||||||
vnd7050aj: vnd7050aj {
|
// VND7050AJ GPIO pin definitions
|
||||||
compatible = "st,vnd7050aj";
|
in0-gpios = <&gpiob 7 GPIO_ACTIVE_HIGH>; // IN0 (PB7) - Input 0 control signal
|
||||||
status = "okay";
|
in1-gpios = <&gpiob 9 GPIO_ACTIVE_HIGH>; // IN1 (PB9) - Input 1 control signal
|
||||||
|
rst-gpios = <&gpiob 3 GPIO_ACTIVE_HIGH>; // RST (PB3) - Reset pin for VND7050AJ
|
||||||
input0-gpios = <&gpiob 3 GPIO_ACTIVE_HIGH>;
|
sen-gpios = <&gpiob 4 GPIO_ACTIVE_HIGH>; // SEN (PB4) - Sense Enable for current monitoring
|
||||||
input1-gpios = <&gpiob 4 GPIO_ACTIVE_HIGH>;
|
s0-gpios = <&gpiob 6 GPIO_ACTIVE_HIGH>; // S0 (PB6) - Status/Select 0 output from VND7050AJ
|
||||||
select0-gpios = <&gpiob 7 GPIO_ACTIVE_HIGH>;
|
s1-gpios = <&gpiob 5 GPIO_ACTIVE_HIGH>; // S1 (PB5) - Status/Select 1 output from VND7050AJ
|
||||||
select1-gpios = <&gpiob 9 GPIO_ACTIVE_HIGH>;
|
};
|
||||||
sense-enable-gpios = <&gpiob 6 GPIO_ACTIVE_HIGH>;
|
|
||||||
fault-reset-gpios = <&gpiob 5 GPIO_ACTIVE_LOW>;
|
|
||||||
io-channels = <&adc1 1>;
|
|
||||||
r-sense-ohms = <1500>;
|
|
||||||
k-vcc = <4000>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
&adc1 {
|
|
||||||
status = "okay";
|
|
||||||
pinctrl-0 = <&adc1_in1_pa0>;
|
|
||||||
pinctrl-names = "default";
|
|
||||||
st,adc-clock-source = "SYNC";
|
|
||||||
st,adc-prescaler = <4>;
|
|
||||||
#address-cells = <1>;
|
|
||||||
#size-cells = <0>;
|
|
||||||
|
|
||||||
channel@1 {
|
|
||||||
reg = <1>;
|
|
||||||
zephyr,gain = "ADC_GAIN_1";
|
|
||||||
zephyr,reference = "ADC_REF_INTERNAL";
|
|
||||||
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
|
||||||
zephyr,resolution = <12>;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
&usart1 {
|
&usart1 {
|
||||||
|
|
@ -46,3 +22,43 @@
|
||||||
pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa10>; // PA9=TX, PA10=RX for Modbus communication
|
pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa10>; // PA9=TX, PA10=RX for Modbus communication
|
||||||
pinctrl-names = "default";
|
pinctrl-names = "default";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&adc1 {
|
||||||
|
status = "okay";
|
||||||
|
pinctrl-0 = <&adc1_in1_pa0 &adc1_in15_pb0>;
|
||||||
|
pinctrl-names = "default";
|
||||||
|
st,adc-clock-source = "SYNC";
|
||||||
|
st,adc-prescaler = <1>;
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
channel@1 {
|
||||||
|
reg = <1>;
|
||||||
|
zephyr,gain = "ADC_GAIN_1";
|
||||||
|
zephyr,reference = "ADC_REF_INTERNAL";
|
||||||
|
zephyr,acquisition-time = <ADC_ACQ_TIME_MAX>; // Use maximum acquisition time for stability
|
||||||
|
zephyr,resolution = <12>;
|
||||||
|
zephyr,vref-mv = <2048>; // STM32G431 VREFBUF at 2.048V
|
||||||
|
};
|
||||||
|
|
||||||
|
channel@15 {
|
||||||
|
reg = <15>;
|
||||||
|
zephyr,gain = "ADC_GAIN_1";
|
||||||
|
zephyr,reference = "ADC_REF_INTERNAL";
|
||||||
|
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
||||||
|
zephyr,resolution = <12>;
|
||||||
|
zephyr,vref-mv = <2048>; // STM32G431 VREFBUF at 2.048V
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
&pinctrl {
|
||||||
|
// Pinmux für PA0 als ADC1_IN1 (Analogmodus)
|
||||||
|
adc1_in1_pa0: adc1_in1_pa0 {
|
||||||
|
pinmux = <STM32_PINMUX('A', 0, ANALOG)>; // PA0 in den Analogmodus setzen
|
||||||
|
};
|
||||||
|
|
||||||
|
// Pinmux für PB0 als ADC1_IN15 (Analogmodus) - for lab supply testing
|
||||||
|
adc1_in15_pb0: adc1_in15_pb0 {
|
||||||
|
pinmux = <STM32_PINMUX('B', 0, ANALOG)>; // PB0 in den Analogmodus setzen
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
#include <zephyr/dt-bindings/gpio/gpio.h>
|
|
||||||
|
|
||||||
&zephyr_udc0 {
|
&zephyr_udc0 {
|
||||||
cdc_acm_uart0: cdc_acm_uart0 {
|
cdc_acm_uart0: cdc_acm_uart0 {
|
||||||
compatible = "zephyr,cdc-acm-uart";
|
compatible = "zephyr,cdc-acm-uart";
|
||||||
|
|
|
||||||
|
|
@ -1,88 +0,0 @@
|
||||||
# Copyright (c) 2024, Eduard Iten
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
description: |
|
|
||||||
STMicroelectronics VND7050AJ dual-channel high-side driver.
|
|
||||||
This is a GPIO and ADC controlled device.
|
|
||||||
|
|
||||||
compatible: "st,vnd7050aj"
|
|
||||||
|
|
||||||
include: base.yaml
|
|
||||||
|
|
||||||
properties:
|
|
||||||
input0-gpios:
|
|
||||||
type: phandle-array
|
|
||||||
required: true
|
|
||||||
description: GPIO to control output channel 0.
|
|
||||||
|
|
||||||
input1-gpios:
|
|
||||||
type: phandle-array
|
|
||||||
required: true
|
|
||||||
description: GPIO to control output channel 1.
|
|
||||||
|
|
||||||
select0-gpios:
|
|
||||||
type: phandle-array
|
|
||||||
required: true
|
|
||||||
description: GPIO for MultiSense selection bit 0.
|
|
||||||
|
|
||||||
select1-gpios:
|
|
||||||
type: phandle-array
|
|
||||||
required: true
|
|
||||||
description: GPIO for MultiSense selection bit 1.
|
|
||||||
|
|
||||||
sense-enable-gpios:
|
|
||||||
type: phandle-array
|
|
||||||
required: true
|
|
||||||
description: GPIO to enable the MultiSense output.
|
|
||||||
|
|
||||||
fault-reset-gpios:
|
|
||||||
type: phandle-array
|
|
||||||
required: true
|
|
||||||
description: GPIO to reset a latched fault (active-low).
|
|
||||||
|
|
||||||
io-channels:
|
|
||||||
type: phandle-array
|
|
||||||
required: true
|
|
||||||
description: |
|
|
||||||
ADC channel connected to the MultiSense pin. This should be an
|
|
||||||
io-channels property pointing to the ADC controller and channel number.
|
|
||||||
|
|
||||||
r-sense-ohms:
|
|
||||||
type: int
|
|
||||||
required: true
|
|
||||||
description: |
|
|
||||||
Value of the external sense resistor connected from the MultiSense
|
|
||||||
pin to GND, specified in Ohms. This is critical for correct
|
|
||||||
conversion of the analog readings.
|
|
||||||
|
|
||||||
k-factor:
|
|
||||||
type: int
|
|
||||||
default: 1500
|
|
||||||
description: |
|
|
||||||
Factor between PowerMOS and SenseMOS.
|
|
||||||
|
|
||||||
k-vcc:
|
|
||||||
type: int
|
|
||||||
default: 8000
|
|
||||||
description: |
|
|
||||||
VCC sense ratio multiplied by 1000. Used for supply voltage calculation.
|
|
||||||
|
|
||||||
t-sense-0:
|
|
||||||
type: int
|
|
||||||
default: 25
|
|
||||||
description: |
|
|
||||||
Temperature sense reference temperature in degrees Celsius.
|
|
||||||
|
|
||||||
v-sense-0:
|
|
||||||
type: int
|
|
||||||
default: 2070
|
|
||||||
description: |
|
|
||||||
Temperature sense reference voltage in millivolts.
|
|
||||||
|
|
||||||
k-tchip:
|
|
||||||
type: int
|
|
||||||
default: -5500
|
|
||||||
description: |
|
|
||||||
Temperature sense gain coefficient multiplied by 1000.
|
|
||||||
Used for chip temperature calculation.
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
# VND7050AJ Valve Controller binding
|
||||||
|
description: VND7050AJ valve controller GPIO configuration
|
||||||
|
|
||||||
|
compatible: "vnd7050aj-valve-controller"
|
||||||
|
|
||||||
|
properties:
|
||||||
|
in0-gpios:
|
||||||
|
type: phandle-array
|
||||||
|
description: GPIO for IN0 control signal
|
||||||
|
required: true
|
||||||
|
|
||||||
|
in1-gpios:
|
||||||
|
type: phandle-array
|
||||||
|
description: GPIO for IN1 control signal
|
||||||
|
required: true
|
||||||
|
|
||||||
|
rst-gpios:
|
||||||
|
type: phandle-array
|
||||||
|
description: GPIO for reset pin
|
||||||
|
required: true
|
||||||
|
|
||||||
|
sen-gpios:
|
||||||
|
type: phandle-array
|
||||||
|
description: GPIO for sense enable pin
|
||||||
|
required: true
|
||||||
|
|
||||||
|
s0-gpios:
|
||||||
|
type: phandle-array
|
||||||
|
description: GPIO for select 0 pin
|
||||||
|
required: true
|
||||||
|
|
||||||
|
s1-gpios:
|
||||||
|
type: phandle-array
|
||||||
|
description: GPIO for select 1 pin
|
||||||
|
required: true
|
||||||
|
|
@ -5,9 +5,6 @@ CONFIG_LOG=y
|
||||||
# Enable Shell
|
# Enable Shell
|
||||||
CONFIG_SHELL=y
|
CONFIG_SHELL=y
|
||||||
CONFIG_REBOOT=y
|
CONFIG_REBOOT=y
|
||||||
CONFIG_SHELL_MODBUS=y
|
|
||||||
CONFIG_SHELL_VALVE=y
|
|
||||||
CONFIG_SHELL_SYSTEM=y
|
|
||||||
|
|
||||||
# Enable Settings Subsystem
|
# Enable Settings Subsystem
|
||||||
CONFIG_SETTINGS=y
|
CONFIG_SETTINGS=y
|
||||||
|
|
@ -22,7 +19,9 @@ CONFIG_SETTINGS_LOG_LEVEL_DBG=y
|
||||||
CONFIG_UART_INTERRUPT_DRIVEN=y
|
CONFIG_UART_INTERRUPT_DRIVEN=y
|
||||||
CONFIG_MODBUS=y
|
CONFIG_MODBUS=y
|
||||||
CONFIG_MODBUS_ROLE_SERVER=y
|
CONFIG_MODBUS_ROLE_SERVER=y
|
||||||
CONFIG_MODBUS_LOG_LEVEL_DBG=y
|
CONFIG_MODBUS_BUFFER_SIZE=256
|
||||||
|
|
||||||
|
# Enable ADC driver
|
||||||
|
CONFIG_ADC=y
|
||||||
|
CONFIG_ADC_STM32=y
|
||||||
|
|
||||||
# Enable VND7050AJ
|
|
||||||
CONFIG_VND7050AJ=y
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,14 @@
|
||||||
#include <zephyr/kernel.h>
|
#include <zephyr/kernel.h>
|
||||||
#include <zephyr/logging/log.h>
|
|
||||||
#include <zephyr/settings/settings.h>
|
#include <zephyr/settings/settings.h>
|
||||||
#include <lib/fwu.h>
|
#include <zephyr/logging/log.h>
|
||||||
#include <lib/modbus_server.h>
|
#include <lib/modbus_server.h>
|
||||||
#include <lib/valve.h>
|
#include <lib/valve.h>
|
||||||
|
#include <lib/fwu.h>
|
||||||
|
|
||||||
LOG_MODULE_REGISTER(main, LOG_LEVEL_INF);
|
LOG_MODULE_REGISTER(main, LOG_LEVEL_INF);
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
int rc;
|
|
||||||
LOG_INF("Starting Irrigation System Slave Node");
|
LOG_INF("Starting Irrigation System Slave Node");
|
||||||
|
|
||||||
if (settings_subsys_init() || settings_load()) {
|
if (settings_subsys_init() || settings_load()) {
|
||||||
|
|
@ -19,12 +18,18 @@ int main(void)
|
||||||
valve_init();
|
valve_init();
|
||||||
fwu_init();
|
fwu_init();
|
||||||
|
|
||||||
rc = modbus_server_init();
|
if (modbus_server_init()) {
|
||||||
if (rc) {
|
LOG_ERR("Modbus RTU server initialization failed");
|
||||||
LOG_ERR("Modbus server initialization failed: %d", rc);
|
return 0;
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test supply voltage reading periodically
|
||||||
|
while (1) {
|
||||||
|
uint16_t supply_voltage = valve_get_supply_voltage();
|
||||||
|
LOG_INF("Supply voltage: %u mV", supply_voltage);
|
||||||
|
k_msleep(5000); // Read every 5 seconds
|
||||||
|
}
|
||||||
|
|
||||||
LOG_INF("Irrigation System Slave Node started successfully");
|
LOG_INF("Irrigation System Slave Node started successfully");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
SB_CONFIG_BOOTLOADER_MCUBOOT=y
|
|
||||||
SB_CONFIG_MCUBOOT_MODE_SINGLE_APP=y
|
|
||||||
|
|
||||||
CONFIG_LOG=y
|
|
||||||
CONFIG_MCUBOOT_LOG_LEVEL_INF=y
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
|
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||||
|
|
||||||
|
project(bootloader LANGUAGES C)
|
||||||
|
zephyr_include_directories(../../../include)
|
||||||
|
add_subdirectory(../../../lib lib)
|
||||||
|
target_sources(app PRIVATE src/main.c)
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
# Firmware Node Application
|
||||||
|
|
||||||
|
This Zephyr application provides firmware management capabilities for the irrigation system.
|
||||||
|
|
||||||
|
**Tested on Zephyr 4.1.99**
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
### Step 1: Shell with Reset Command
|
||||||
|
- Shell interface with custom "reset" command
|
||||||
|
- Warm reboot functionality
|
||||||
|
|
||||||
|
### Planned Features
|
||||||
|
- MCUboot support with partition manager
|
||||||
|
- Firmware version display
|
||||||
|
- MCUmgr support for OTA updates
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
```bash
|
||||||
|
west build -p auto -b weact_stm32g431_core apps/firmware_node -- -DBOARD_FLASH_RUNNER=blackmagicprobe
|
||||||
|
```
|
||||||
|
|
||||||
|
## Flashing
|
||||||
|
|
||||||
|
```bash
|
||||||
|
west flash
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Connect to the device via serial console and use the shell:
|
||||||
|
- `reset` - Reboot the system
|
||||||
|
- `help` - Show available commands
|
||||||
|
|
@ -2,4 +2,4 @@ VERSION_MAJOR = 0
|
||||||
VERSION_MINOR = 0
|
VERSION_MINOR = 0
|
||||||
PATCHLEVEL = 1
|
PATCHLEVEL = 1
|
||||||
VERSION_TWEAK = 0
|
VERSION_TWEAK = 0
|
||||||
EXTRAVERSION = devel
|
EXTRAVERSION = testing
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
#!/bin/bash
|
||||||
|
/home/edi/zephyr-sdk-0.17.1/arm-zephyr-eabi/bin/arm-zephyr-eabi-gdb \
|
||||||
|
-ex 'target extended-remote /dev/ttyACM0' \
|
||||||
|
-ex 'monitor swdp_scan' \
|
||||||
|
-ex 'attach 1' \
|
||||||
|
-ex 'monitor erase_mass' \
|
||||||
|
-ex 'detach' \
|
||||||
|
-ex 'quit' \
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
CONFIG_SHELL=y
|
||||||
|
CONFIG_REBOOT=y
|
||||||
|
|
||||||
|
# MCUboot support for recovery request function
|
||||||
|
CONFIG_MCUBOOT_BOOTUTIL_LIB=y
|
||||||
|
CONFIG_MCUBOOT_IMG_MANAGER=y
|
||||||
|
CONFIG_IMG_MANAGER=y
|
||||||
|
|
||||||
|
# Flash and Stream Configuration (required for IMG_MANAGER)
|
||||||
|
CONFIG_FLASH=y
|
||||||
|
CONFIG_STREAM_FLASH=y
|
||||||
|
|
||||||
|
# Retention system
|
||||||
|
CONFIG_RETENTION=y
|
||||||
|
CONFIG_RETENTION_BOOT_MODE=y
|
||||||
|
CONFIG_RETAINED_MEM=y
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <app_version.h>
|
||||||
|
#include <zephyr/shell/shell.h>
|
||||||
|
#include <zephyr/sys/reboot.h>
|
||||||
|
#include <zephyr/dfu/mcuboot.h>
|
||||||
|
#include <zephyr/retention/bootmode.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/* Shell command handler for "reset" */
|
||||||
|
static int cmd_reset(const struct shell *sh, size_t argc, char **argv)
|
||||||
|
{
|
||||||
|
shell_print(sh, "Rebooting system...");
|
||||||
|
k_sleep(K_MSEC(100)); // Optional delay for user to see the message
|
||||||
|
sys_reboot(SYS_REBOOT_WARM);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmd_download(const struct shell *sh, size_t argc, char **argv)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Set boot mode to serial recovery */
|
||||||
|
rc = bootmode_set(BOOT_MODE_TYPE_BOOTLOADER);
|
||||||
|
if (rc < 0) {
|
||||||
|
shell_error(sh, "Failed to set boot mode: %d", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
shell_print(sh, "Boot mode set to recovery. Rebooting to bootloader...");
|
||||||
|
k_sleep(K_MSEC(100));
|
||||||
|
sys_reboot(SYS_REBOOT_WARM);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Register the shell command */
|
||||||
|
SHELL_CMD_REGISTER(reset, NULL, "Reboot the system", cmd_reset);
|
||||||
|
SHELL_CMD_REGISTER(download, NULL, "Download firmware", cmd_download);
|
||||||
|
|
||||||
|
int main(void){
|
||||||
|
printk("Bootloader test version %s\n", APP_VERSION_EXTENDED_STRING);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Sysbuild configuration for firmware_node with MCUboot
|
||||||
|
|
||||||
|
# Enable MCUboot as bootloader
|
||||||
|
SB_CONFIG_BOOTLOADER_MCUBOOT=y
|
||||||
|
SB_CONFIG_MCUBOOT_MODE_SINGLE_APP=y
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "flash_partitions_128kb.dtsi"
|
||||||
|
|
||||||
|
/ {
|
||||||
|
chosen {
|
||||||
|
zephyr,code-partition = &slot0_partition;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* Devicetree Overlay for 128KB Flash
|
||||||
|
* - MCUboot Bootloader (32KB)
|
||||||
|
* - Application Slot (96KB)
|
||||||
|
*/
|
||||||
|
|
||||||
|
&flash0 {
|
||||||
|
/delete-node/ partitions;
|
||||||
|
partitions {
|
||||||
|
compatible = "fixed-partitions";
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
boot_partition: partition@0 {
|
||||||
|
label = "mcuboot";
|
||||||
|
reg = <0x00000000 DT_SIZE_K(32)>;
|
||||||
|
read-only;
|
||||||
|
};
|
||||||
|
|
||||||
|
slot0_partition: partition@8000 {
|
||||||
|
label = "image-0";
|
||||||
|
reg = <0x00008000 DT_SIZE_K(96)>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Add retention memory to the existing SRAM node */
|
||||||
|
&sram0 {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
retainedmem {
|
||||||
|
compatible = "zephyr,retained-ram";
|
||||||
|
status = "okay";
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
boot_mode: retention@7f00 {
|
||||||
|
compatible = "zephyr,retention";
|
||||||
|
status = "okay";
|
||||||
|
reg = <0x7f00 0x100>;
|
||||||
|
prefix = [08 04];
|
||||||
|
checksum = <1>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/ {
|
||||||
|
chosen {
|
||||||
|
zephyr,boot-mode = &boot_mode;
|
||||||
|
zephyr,console = &cdc_acm_uart0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
&zephyr_udc0 {
|
||||||
|
status = "okay";
|
||||||
|
|
||||||
|
cdc_acm_uart0: cdc_acm_uart0 {
|
||||||
|
compatible = "zephyr,cdc-acm-uart";
|
||||||
|
label = "CDC_ACM_0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
#
|
||||||
|
# MCUboot Configuration for Serial Recovery over USB-CDC
|
||||||
|
#
|
||||||
|
|
||||||
|
# Enables serial recovery mode in MCUboot.
|
||||||
|
CONFIG_MCUBOOT_SERIAL=y
|
||||||
|
|
||||||
|
# Tell MCUboot to check for a trigger to enter recovery
|
||||||
|
CONFIG_BOOT_SERIAL_BOOT_MODE=y
|
||||||
|
|
||||||
|
# --- USB Stack Configuration ---
|
||||||
|
CONFIG_USB_DEVICE_STACK=y
|
||||||
|
CONFIG_USB_DEVICE_PRODUCT="MCUboot Serial Recovery"
|
||||||
|
|
||||||
|
# Use USB CDC ACM for MCUboot serial recovery (not UART)
|
||||||
|
CONFIG_BOOT_SERIAL_CDC_ACM=y
|
||||||
|
|
||||||
|
# --- Disable Zephyr Console to avoid conflicts ---
|
||||||
|
# MCUboot's serial_adapter doesn't work well with the general console subsystem.
|
||||||
|
CONFIG_UART_CONSOLE=n
|
||||||
|
CONFIG_CONSOLE_HANDLER=n
|
||||||
|
CONFIG_CONSOLE=n
|
||||||
|
|
||||||
|
# --- Flash and Stream Configuration (required for IMG_MANAGER) ---
|
||||||
|
CONFIG_FLASH=y
|
||||||
|
CONFIG_STREAM_FLASH=y
|
||||||
|
|
||||||
|
# --- mcumgr Configuration ---
|
||||||
|
# MCUMGR requires NET_BUF, even for serial transport.
|
||||||
|
CONFIG_NET_BUF=y
|
||||||
|
CONFIG_NET_LOG=n
|
||||||
|
|
||||||
|
# Enables the mcumgr library and necessary command handlers
|
||||||
|
CONFIG_MCUMGR=y
|
||||||
|
CONFIG_IMG_MANAGER=y
|
||||||
|
CONFIG_MCUMGR_GRP_IMG=y
|
||||||
|
CONFIG_MCUMGR_GRP_OS=y
|
||||||
|
|
||||||
|
# --- Retention Configuration ---
|
||||||
|
CONFIG_RETAINED_MEM=y
|
||||||
|
CONFIG_RETENTION=y
|
||||||
|
CONFIG_RETENTION_BOOT_MODE=y
|
||||||
|
|
||||||
|
# --- Optional: Reduce memory usage ---
|
||||||
|
CONFIG_MAIN_STACK_SIZE=2048
|
||||||
|
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=1024
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
#include "flash_partitions_128kb.dtsi"
|
||||||
|
|
||||||
|
/ {
|
||||||
|
chosen {
|
||||||
|
zephyr,code-partition = &boot_partition;
|
||||||
|
zephyr,console = &cdc_acm_uart0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
&zephyr_udc0 {
|
||||||
|
status = "okay";
|
||||||
|
|
||||||
|
cdc_acm_uart0: cdc_acm_uart0 {
|
||||||
|
compatible = "zephyr,cdc-acm-uart";
|
||||||
|
label = "CDC_ACM_0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
# Gitignore settings for ESPHome
|
|
||||||
# This is an example and may include too much for your use-case.
|
|
||||||
# You can modify this file to suit your needs.
|
|
||||||
/.esphome/
|
|
||||||
/secrets.yaml
|
|
||||||
|
|
@ -1,106 +0,0 @@
|
||||||
# ===================================================================
|
|
||||||
# ESPHome Configuration
|
|
||||||
# CAN-Bus Master für ein Bewässerungssystem auf Basis des ESP32-C6
|
|
||||||
#
|
|
||||||
# Version 10: Finale Korrektur der Lambda-Signatur gemäß Dokumentation
|
|
||||||
# ===================================================================
|
|
||||||
|
|
||||||
esphome:
|
|
||||||
name: can-bridge
|
|
||||||
friendly_name: Irrigation can bridge
|
|
||||||
|
|
||||||
esp32:
|
|
||||||
board: esp32-c6-devkitm-1
|
|
||||||
framework:
|
|
||||||
type: esp-idf # Erforderlich für den ESP32-C6
|
|
||||||
|
|
||||||
# --- Netzwerk & Sicherheit ---
|
|
||||||
wifi:
|
|
||||||
ssid: !secret wifi_ssid
|
|
||||||
password: !secret wifi_password
|
|
||||||
fast_connect: true
|
|
||||||
|
|
||||||
api:
|
|
||||||
encryption:
|
|
||||||
key: !secret api_key
|
|
||||||
|
|
||||||
ota:
|
|
||||||
platform: esphome
|
|
||||||
password: !secret ota_password
|
|
||||||
|
|
||||||
logger:
|
|
||||||
|
|
||||||
web_server:
|
|
||||||
|
|
||||||
# --- Globale Variablen ---
|
|
||||||
globals:
|
|
||||||
- id: ventil_2_can_state
|
|
||||||
type: int
|
|
||||||
initial_value: '0' # Startet als "geschlossen"
|
|
||||||
|
|
||||||
# --- CAN-Bus Konfiguration ---
|
|
||||||
canbus:
|
|
||||||
- platform: esp32_can
|
|
||||||
id: my_can_bus
|
|
||||||
tx_pin: GPIO5
|
|
||||||
rx_pin: GPIO4
|
|
||||||
bit_rate: 125kbps
|
|
||||||
can_id: 0x000 # Erforderlich, um Parser-Fehler zu beheben.
|
|
||||||
on_frame:
|
|
||||||
# Horcht nur auf die Statusmeldung von Knoten 2 (ID 0x422)
|
|
||||||
- can_id: 0x422
|
|
||||||
then:
|
|
||||||
- lambda: |-
|
|
||||||
if (x.size() < 1) {
|
|
||||||
ESP_LOGW("on_can_frame", "Received empty Frame for ID 0x422");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int received_state = x[0];
|
|
||||||
id(ventil_2_can_state) = received_state;
|
|
||||||
ESP_LOGD("on_can_frame", "Received state from Valve 2: %i", received_state);
|
|
||||||
- valve.template.publish:
|
|
||||||
id: ventil_2
|
|
||||||
current_operation: !lambda |-
|
|
||||||
int state = id(ventil_2_can_state);
|
|
||||||
if (state == 2) {
|
|
||||||
return VALVE_OPERATION_OPENING;
|
|
||||||
} else if (state == 3) {
|
|
||||||
return VALVE_OPERATION_CLOSING;
|
|
||||||
} else {
|
|
||||||
return VALVE_OPERATION_IDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
# --- Home Assistant Entitäten ---
|
|
||||||
valve:
|
|
||||||
- platform: template
|
|
||||||
name: "Ventil 2"
|
|
||||||
id: ventil_2
|
|
||||||
|
|
||||||
# Diese Lambda meldet nur den binären End-Zustand (offen/geschlossen)
|
|
||||||
lambda: |-
|
|
||||||
if (id(ventil_2_can_state) == 0) {
|
|
||||||
return VALVE_CLOSED;
|
|
||||||
} else if (id(ventil_2_can_state) == 1) {
|
|
||||||
return VALVE_OPEN;
|
|
||||||
} else {
|
|
||||||
return NAN;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Aktionen zum Steuern des Ventils
|
|
||||||
open_action:
|
|
||||||
- canbus.send:
|
|
||||||
canbus_id: my_can_bus
|
|
||||||
can_id: 0x210
|
|
||||||
data: [0x02, 0x01]
|
|
||||||
|
|
||||||
close_action:
|
|
||||||
- canbus.send:
|
|
||||||
canbus_id: my_can_bus
|
|
||||||
can_id: 0x210
|
|
||||||
data: [0x02, 0x00]
|
|
||||||
|
|
||||||
stop_action:
|
|
||||||
- canbus.send:
|
|
||||||
canbus_id: my_can_bus
|
|
||||||
can_id: 0x210
|
|
||||||
data: [0x02, 0x03]
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import secrets
|
|
||||||
import string
|
|
||||||
import os
|
|
||||||
import base64
|
|
||||||
from ruamel.yaml import YAML
|
|
||||||
|
|
||||||
def generate_password(length=32):
|
|
||||||
"""Generate a random password."""
|
|
||||||
alphabet = string.ascii_letters + string.digits
|
|
||||||
return ''.join(secrets.choice(alphabet) for i in range(length))
|
|
||||||
|
|
||||||
def generate_api_key():
|
|
||||||
"""Generate a random 32-byte key and base64 encode it."""
|
|
||||||
return base64.b64encode(secrets.token_bytes(32)).decode('utf-8')
|
|
||||||
|
|
||||||
SECRETS_FILE = 'secrets.yaml'
|
|
||||||
# In a real ESPHome project, secrets are often included from a central location
|
|
||||||
# but for this script, we'll assume it's in the current directory.
|
|
||||||
# You might need to adjust this path.
|
|
||||||
secrets_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), SECRETS_FILE)
|
|
||||||
|
|
||||||
yaml = YAML()
|
|
||||||
yaml.preserve_quotes = True
|
|
||||||
# To prevent line wrapping
|
|
||||||
yaml.width = 4096
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(secrets_path, 'r') as f:
|
|
||||||
secrets_data = yaml.load(f)
|
|
||||||
if secrets_data is None:
|
|
||||||
secrets_data = {}
|
|
||||||
except FileNotFoundError:
|
|
||||||
print(f"Info: '{SECRETS_FILE}' not found. A new file will be created.")
|
|
||||||
secrets_data = {}
|
|
||||||
|
|
||||||
# Generate new random passwords
|
|
||||||
new_api_key = generate_api_key()
|
|
||||||
new_ota_password = generate_password()
|
|
||||||
|
|
||||||
# Update the dictionary with the new passwords
|
|
||||||
if 'api_password' in secrets_data:
|
|
||||||
del secrets_data['api_password']
|
|
||||||
secrets_data['api_key'] = new_api_key
|
|
||||||
secrets_data['ota_password'] = new_ota_password
|
|
||||||
|
|
||||||
# Write the updated dictionary back to the YAML file
|
|
||||||
with open(secrets_path, 'w') as f:
|
|
||||||
yaml.dump(secrets_data, f)
|
|
||||||
|
|
||||||
print(f"Successfully updated '{SECRETS_FILE}'.")
|
|
||||||
print("New values:")
|
|
||||||
print(f" api_key: {new_api_key}")
|
|
||||||
print(f" ota_password: {new_ota_password}")
|
|
||||||
|
|
@ -1,166 +0,0 @@
|
||||||
# ===================================================================
|
|
||||||
# ESPHome Configuration - Final Version
|
|
||||||
#
|
|
||||||
# This version corrects the C++ function call inside the valve actions
|
|
||||||
# to use the correct `send` method from the ModbusDevice base class,
|
|
||||||
# which is compatible with the esp-idf framework.
|
|
||||||
# ===================================================================
|
|
||||||
|
|
||||||
esphome:
|
|
||||||
name: irrigation-system
|
|
||||||
friendly_name: Bewässerung
|
|
||||||
|
|
||||||
esp32:
|
|
||||||
board: esp32-c6-devkitm-1
|
|
||||||
framework:
|
|
||||||
type: esp-idf # Set to esp-idf as required by the ESP32-C6 board
|
|
||||||
|
|
||||||
wifi:
|
|
||||||
ssid: !secret wifi_ssid
|
|
||||||
password: !secret wifi_password
|
|
||||||
fast_connect: true
|
|
||||||
|
|
||||||
api:
|
|
||||||
encryption:
|
|
||||||
key: !secret api_key
|
|
||||||
|
|
||||||
ota:
|
|
||||||
platform: esphome
|
|
||||||
password: !secret ota_password
|
|
||||||
|
|
||||||
logger:
|
|
||||||
|
|
||||||
web_server:
|
|
||||||
|
|
||||||
# ===================================================================
|
|
||||||
# HARDWARE SETUP - COMPLETE
|
|
||||||
# ===================================================================
|
|
||||||
|
|
||||||
# --- UART for RS485 Communication ---
|
|
||||||
uart:
|
|
||||||
id: uart_bus
|
|
||||||
tx_pin: GPIO1
|
|
||||||
rx_pin: GPIO2
|
|
||||||
baud_rate: 9600
|
|
||||||
data_bits: 8
|
|
||||||
stop_bits: 1
|
|
||||||
parity: NONE
|
|
||||||
|
|
||||||
# --- Base Modbus component for the bus ---
|
|
||||||
modbus:
|
|
||||||
- id: modbus_hub
|
|
||||||
uart_id: uart_bus
|
|
||||||
|
|
||||||
# --- Modbus Controller for the specific valve device ---
|
|
||||||
modbus_controller:
|
|
||||||
- id: valve_controller
|
|
||||||
modbus_id: modbus_hub
|
|
||||||
address: 0 # The Modbus address of your valve. Change if not 0.
|
|
||||||
# update_interval: 1s
|
|
||||||
|
|
||||||
# ===================================================================
|
|
||||||
# SENSORS - COMPLETE
|
|
||||||
# ===================================================================
|
|
||||||
sensor:
|
|
||||||
# This sensor reads the raw 16-bit value from the valve's input register.
|
|
||||||
- platform: modbus_controller
|
|
||||||
modbus_controller_id: valve_controller
|
|
||||||
name: "Valve Raw Status"
|
|
||||||
id: valve_raw_status
|
|
||||||
internal: true # Hide from Home Assistant UI
|
|
||||||
register_type: read # 'read' is the valid type for input registers
|
|
||||||
address: 0x0000 # The address of the register to read
|
|
||||||
value_type: U_WORD # Read the full 16-bit unsigned word
|
|
||||||
- platform: modbus_controller
|
|
||||||
modbus_controller_id: valve_controller
|
|
||||||
name: "VDD"
|
|
||||||
id: valve_vdd
|
|
||||||
register_type: read # 'read' is the valid type for input registers
|
|
||||||
address: 0x00FC # The address of the register to read
|
|
||||||
value_type: U_WORD # Read the full 16-bit unsigned word
|
|
||||||
entity_category: diagnostic # Mark as diagnostic
|
|
||||||
unit_of_measurement: "V"
|
|
||||||
accuracy_decimals: 2 # Show two decimal places
|
|
||||||
# Apply filters to convert the raw value to volts and update periodically
|
|
||||||
filters:
|
|
||||||
- lambda: |-
|
|
||||||
// Convert the raw VDD value to volts
|
|
||||||
return x / 1000.0; // Assuming the value is in millivolts
|
|
||||||
- heartbeat: 60s # Update every 60 seconds
|
|
||||||
- delta: 200 # Only update if the value changes by more than 200 mV
|
|
||||||
|
|
||||||
# ===================================================================
|
|
||||||
# TEXT SENSORS FOR HUMAN-READABLE STATUS
|
|
||||||
# ===================================================================
|
|
||||||
text_sensor:
|
|
||||||
# 1. This text sensor extracts the HIGH BYTE for the operation status.
|
|
||||||
- platform: template
|
|
||||||
name: "Valve Operation"
|
|
||||||
id: valve_operation_status
|
|
||||||
icon: "mdi:state-machine"
|
|
||||||
lambda: |-
|
|
||||||
// Extract the high byte from the raw status sensor
|
|
||||||
// using a bitwise right shift.
|
|
||||||
int operation_code = (int)id(valve_raw_status).state >> 8;
|
|
||||||
switch (operation_code) {
|
|
||||||
case 0: return {"Idle"};
|
|
||||||
case 1: return {"Opening"};
|
|
||||||
case 2: return {"Closing"};
|
|
||||||
case 3: return {"Obstacle Detected"};
|
|
||||||
case 4: return {"End Position Not Reached"};
|
|
||||||
default: return {"Unknown Operation"};
|
|
||||||
}
|
|
||||||
|
|
||||||
# 2. This text sensor extracts the LOW BYTE for the current valve state.
|
|
||||||
- platform: template
|
|
||||||
name: "Valve Position"
|
|
||||||
id: valve_position_status
|
|
||||||
icon: "mdi:valve"
|
|
||||||
lambda: |-
|
|
||||||
// Extract the low byte from the raw status sensor
|
|
||||||
// using a bitwise AND mask.
|
|
||||||
int state_code = (int)id(valve_raw_status).state & 0xFF;
|
|
||||||
switch (state_code) {
|
|
||||||
case 0: return {"Closed"};
|
|
||||||
case 1: return {"Open"};
|
|
||||||
default: return {"Unknown"};
|
|
||||||
}
|
|
||||||
|
|
||||||
# ===================================================================
|
|
||||||
# THE MAIN VALVE COMPONENT
|
|
||||||
# ===================================================================
|
|
||||||
valve:
|
|
||||||
- platform: template
|
|
||||||
name: "Modbus Controlled Valve"
|
|
||||||
id: modbus_valve
|
|
||||||
optimistic: false
|
|
||||||
# The lambda determines the current state (open or closed) of the valve.
|
|
||||||
lambda: |-
|
|
||||||
int state_code = (int)id(valve_raw_status).state & 0xFF;
|
|
||||||
if (state_code == 1) {
|
|
||||||
return true; // Open
|
|
||||||
} else if (state_code == 0) {
|
|
||||||
return false; // Closed
|
|
||||||
} else {
|
|
||||||
return {}; // Unknown
|
|
||||||
}
|
|
||||||
# Action to execute when the "OPEN" button is pressed.
|
|
||||||
open_action:
|
|
||||||
- lambda: |-
|
|
||||||
// Use the send() command inherited from ModbusDevice
|
|
||||||
// Function 0x06: Write Single Register
|
|
||||||
// Payload for value 1 is {0x00, 0x01}
|
|
||||||
const uint8_t data[] = {0x00, 0x01};
|
|
||||||
id(valve_controller).send(0x06, 0x0000, 1, 2, data);
|
|
||||||
# Action to execute when the "CLOSE" button is pressed.
|
|
||||||
close_action:
|
|
||||||
- lambda: |-
|
|
||||||
// Payload for value 2 is {0x00, 0x02}
|
|
||||||
const uint8_t data[] = {0x00, 0x02};
|
|
||||||
id(valve_controller).send(0x06, 0x0000, 1, 2, data);
|
|
||||||
# Action to execute when the "STOP" button is pressed.
|
|
||||||
stop_action:
|
|
||||||
- lambda: |-
|
|
||||||
// Payload for value 3 is {0x00, 0x03}
|
|
||||||
const uint8_t data[] = {0x00, 0x03};
|
|
||||||
id(valve_controller).send(0x06, 0x0000, 1, 2, data);
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
ruamel.yaml
|
|
||||||
esphome
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue