Compare commits
47 Commits
adc-testin
...
main
| Author | SHA1 | Date |
|---|---|---|
|
|
0c4a728c17 | |
|
|
d92a1d9533 | |
|
|
9325fa20c8 | |
|
|
08c47f00f8 | |
|
|
1cba00df8c | |
|
|
35bd208cc0 | |
|
|
48cfcd5d4c | |
|
|
d76b897eb2 | |
|
|
0713f8255e | |
|
|
fc089e5a33 | |
|
|
ef966cb078 | |
|
|
6f304efb57 | |
|
|
e1ae96506d | |
|
|
6cb17be451 | |
|
|
54e991294b | |
|
|
0227e54198 | |
|
|
c3c23efc95 | |
|
|
4466b677a6 | |
|
|
dcbd02ad7a | |
|
|
8467b3e347 | |
|
|
fc0add8583 | |
|
|
66cdc3ae27 | |
|
|
32bb77926f | |
|
|
4df0181d7f | |
|
|
d6fb501594 | |
|
|
76d0d0647c | |
|
|
3de42a46c2 | |
|
|
ddaaa8988d | |
|
|
b937c52bcc | |
|
|
3c2235733b | |
|
|
a3e8d5c168 | |
|
|
5fd904de9e | |
|
|
92bb171e85 | |
|
|
bd8a7a766c | |
|
|
8f89713866 | |
|
|
bf29061db6 | |
|
|
c1622bb01c | |
|
|
222ffea568 | |
|
|
a9a0626913 | |
|
|
b11f844415 | |
|
|
2e8a86bc54 | |
|
|
224adccf6b | |
|
|
9b7159d5a4 | |
|
|
bc327acc41 | |
|
|
c9b0f38576 | |
|
|
edf0fb2563 | |
|
|
537d76ef5d |
|
|
@ -1 +1,65 @@
|
||||||
**/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
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "software/modules/zephyr_vnd7050aj_driver"]
|
||||||
|
path = software/modules/zephyr_vnd7050aj_driver
|
||||||
|
url = https://gitea.iten.pro/edi/zephyr_vnd7050aj_driver.git
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"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).
|
* **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 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,33 +29,38 @@ 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** | `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). |
|
| **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). |
|
||||||
| **0x0001** | `MOTORSTROM_MA` | Ventil | Aktueller Motorstrom in Milliampere (mA). |
|
| **0x0001** | `REG_INPUT_MOTOR_OPEN_CURRENT_MA` | Ventil | Motorstrom beim Öffnen in Milliampere (mA). |
|
||||||
| **0x0020** | `DIGITAL_EINGAENGE_ZUSTAND` | Eingänge | Bitmaske der digitalen Eingänge. Bit 0: Eingang 1, Bit 1: Eingang 2. `1`=Aktiv. |
|
| **0x0002** | `REG_INPUT_MOTOR_CLOSE_CURRENT_MA` | Ventil | Motorstrom beim Schließen in Milliampere (mA). |
|
||||||
| **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. |
|
| **0x0020** | `REG_INPUT_DIGITAL_INPUTS_STATE` | Eingänge | Bitmaske der digitalen Eingänge. Bit 0: Eingang 1, Bit 1: Eingang 2. `1`=Aktiv. |
|
||||||
| **0x00F0** | `FIRMWARE_VERSION_MAJOR_MINOR` | System | z.B. `0x0102` für v1.2. |
|
| **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. |
|
||||||
| **0x00F1** | `FIRMWARE_VERSION_PATCH` | System | z.B. `3` für v1.2.3. |
|
| **0x00F0** | `REG_INPUT_FIRMWARE_VERSION_MAJOR_MINOR` | System | z.B. `0x0102` für v1.2. |
|
||||||
| **0x00F2** | `DEVICE_STATUS` | System | `0`=OK, `1`=Allgemeiner Fehler. |
|
| **0x00F1** | `REG_INPUT_FIRMWARE_VERSION_PATCH` | System | z.B. `3` für v1.2.3. |
|
||||||
| **0x00F3** | `UPTIME_SECONDS_LOW` | System | Untere 16 Bit der Uptime in Sekunden. |
|
| **0x00F2** | `REG_INPUT_DEVICE_STATUS` | System | `0`=OK, `1`=Allgemeiner Fehler. |
|
||||||
| **0x00F4** | `UPTIME_SECONDS_HIGH` | System | Obere 16 Bit der Uptime. |
|
| **0x00F3** | `REG_INPUT_UPTIME_SECONDS_LOW` | System | Untere 16 Bit der Uptime in Sekunden. |
|
||||||
| **0x00F5** | `SUPPLY_VOLTAGE_MV` | System | Aktuelle Versorgungsspannung in Millivolt (mV). |
|
| **0x00F4** | `REG_INPUT_UPTIME_SECONDS_HIGH` | System | Obere 16 Bit der Uptime. |
|
||||||
| **0x0100** | `FWU_LAST_CHUNK_CRC` | Firmware-Update | Enthält den CRC16 des zuletzt im Puffer empfangenen Daten-Chunks. |
|
| **0x00F5** | `REG_INPUT_SUPPLY_VOLTAGE_MV` | System | Aktuelle Versorgungsspannung in Millivolt (mV). |
|
||||||
|
| **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** | `VENTIL_BEFEHL` | Ventil | `1`=Öffnen, `2`=Schliessen, `0`=Bewegung stoppen. |
|
| **0x0000** | `REG_HOLDING_VALVE_COMMAND` | Ventil | `1`=Öffnen, `2`=Schliessen, `0`=Bewegung stoppen. |
|
||||||
| **0x0001** | `MAX_OEFFNUNGSZEIT_S` | Ventil | Sicherheits-Timeout in Sekunden für den Öffnen-Vorgang. |
|
| **0x0001** | `REG_HOLDING_MAX_OPENING_TIME_S` | Ventil | Sicherheits-Timeout in Sekunden für den Öffnen-Vorgang. |
|
||||||
| **0x0002** | `MAX_SCHLIESSZEIT_S` | Ventil | Sicherheits-Timeout in Sekunden für den Schliessen-Vorgang. |
|
| **0x0002** | `REG_HOLDING_MAX_CLOSING_TIME_S` | Ventil | Sicherheits-Timeout in Sekunden für den Schliessen-Vorgang. |
|
||||||
| **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. |
|
| **0x0003** | `REG_HOLDING_END_CURRENT_THRESHOLD_OPEN_MA` | Ventil | Minimaler Stromschwellenwert in mA zur Endlagenerkennung beim Öffnen. |
|
||||||
| **0x00F0** | `WATCHDOG_TIMEOUT_S` | System | Timeout des Fail-Safe-Watchdogs in Sekunden. `0`=Deaktiviert. |
|
| **0x0004** | `REG_HOLDING_END_CURRENT_THRESHOLD_CLOSE_MA` | Ventil | Minimaler Stromschwellenwert in mA zur Endlagenerkennung beim Schliessen. |
|
||||||
| **0x00F1** | `DEVICE_RESET` | System | Schreibt `1` um das Gerät neu zu starten. |
|
| **0x0005** | `REG_HOLDING_OBSTACLE_THRESHOLD_OPEN_MA` | Ventil | Stromschwellenwert in mA für die Hinderniserkennung beim Öffnen. |
|
||||||
| **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. |
|
| **0x0006** | `REG_HOLDING_OBSTACLE_THRESHOLD_CLOSE_MA` | Ventil | Stromschwellenwert in mA für die Hinderniserkennung beim Schließen. |
|
||||||
| **0x0101** | `FWU_CHUNK_OFFSET_LOW` | Firmware-Update | Untere 16 Bit des 32-Bit-Offsets, an den der nächste Chunk geschrieben werden soll. |
|
| **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. |
|
||||||
| **0x0102** | `FWU_CHUNK_OFFSET_HIGH` | Firmware-Update | Obere 16 Bit des 32-Bit-Offsets. |
|
| **0x00F0** | `REG_HOLDING_WATCHDOG_TIMEOUT_S` | System | Timeout des Fail-Safe-Watchdogs in Sekunden. `0`=Deaktiviert. |
|
||||||
| **0x0103** | `FWU_CHUNK_SIZE` | Firmware-Update | Grösse des nächsten Chunks in Bytes (max. 256). |
|
| **0x00F1** | `REG_HOLDING_DEVICE_RESET` | System | Schreibt `1` um das Gerät neu zu starten. |
|
||||||
| **0x0180** | `FWU_DATA_BUFFER` | Firmware-Update | **Startadresse** eines 128x16-bit Puffers (256 Bytes). Entspricht den Registern `40384` bis `40511`. |
|
| **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. |
|
||||||
|
| **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
|
||||||
|
|
||||||
|
|
@ -80,10 +85,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_ADRESSE` | R/W | Geräteadresse des Sensors (1-255). |
|
| **0x0000** | `NODE_ADDRESS` | 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** | `EINHEIT` | R/W | `0`=Keine, `1`=cm, `2`=mm, `3`=MPa, `4`=Pa, `5`=kPa. |
|
| **0x0002** | `UNIT` | R/W | `0`=Keine, `1`=cm, `2`=mm, `3`=MPa, `4`=Pa, `5`=kPa. |
|
||||||
| **0x0003** | `NACHKOMMASTELLEN` | R/W | Anzahl der Dezimalstellen für den Messwert (0-3). |
|
| **0x0003** | `DECIMAL_PLACES` | R/W | Anzahl der Dezimalstellen für den Messwert (0-3). |
|
||||||
| **0x0004** | `MESSWERT_AKTUELL` | R | Der skalierte Messwert als vorzeichenbehafteter 16-Bit-Integer. |
|
| **0x0004** | `CURRENT_MEASUREMENT` | R | Der skalierte Messwert als vorzeichenbehafteter 16-Bit-Integer. |
|
||||||
| **0x0005** | `MESSBEREICH_NULLPUNKT` | R/W | Rohwert für den Nullpunkt der Skala. |
|
| **0x0005** | `MEASUREMENT_RANGE_ZERO_POINT` | R/W | Rohwert für den Nullpunkt der Skala. |
|
||||||
| **0x0006** | `MESSBEREICH_ENDPUNKT` | R/W | Rohwert für den Endpunkt der Skala. |
|
| **0x0006** | `MEASUREMENT_RANGE_END_POINT` | R/W | Rohwert für den Endpunkt der Skala. |
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,13 @@
|
||||||
| ✅ | **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 Basis-Firmware für Slave-Node erstellen | | Hardware-Abstraktion (GPIOs, ADC, UART für RS485) implementieren. |
|
| ✅ | 1.2 Hardware-Abstraktion (VND7050AJ, RS485) | 10.07.2025 | Implementierung der Treiber für den VND7050AJ und die RS485-Kommunikation. |
|
||||||
| ☐ | 1.3 MODBUS-RTU Stack auf dem Slave implementieren | | Basierend auf der definierten Register-Map. Zuerst nur lesende Funktionen (Status, Version). |
|
| ✅ | 1.3 Basis-Firmware für Slave-Node erstellen | 10.07.2025 | Hardware-Abstraktion (GPIOs) implementiert. |
|
||||||
| ☐ | 1.4 Kernlogik implementieren (z.B. Ventilsteuerung) | | Umsetzung der `VENTIL_ZUSTAND_BEWEGUNG` Logik, Strommessung für Endlagen etc. |
|
| ✅ | 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) | 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. |
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
#!/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."
|
||||||
|
|
@ -0,0 +1,142 @@
|
||||||
|
# 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,17 +1,15 @@
|
||||||
{
|
{
|
||||||
// Hush CMake
|
// Hush CMake
|
||||||
"cmake.configureOnOpen": false,
|
"cmake.configureOnOpen": false,
|
||||||
|
|
||||||
// IntelliSense
|
// IntelliSense
|
||||||
"C_Cpp.default.compilerPath": "${userHome}/zephyr-sdk-0.17.1/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc.exe",
|
"C_Cpp.default.compilerPath": "${userHome}/zephyr-sdk-0.17.1/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc.exe",
|
||||||
"C_Cpp.default.compileCommands": "${workspaceFolder}/build/compile_commands.json",
|
"C_Cpp.default.compileCommands": "${workspaceFolder}/build/compile_commands.json",
|
||||||
|
|
||||||
// File Associations
|
// File Associations
|
||||||
"files.associations": {
|
"files.associations": {
|
||||||
"array": "c",
|
"app_version.h": "c"
|
||||||
"string_view": "c",
|
},
|
||||||
"initializer_list": "c",
|
"C_Cpp.clang_format_style": "file",
|
||||||
"span": "c",
|
"nrf-connect.applications": [
|
||||||
"format": "c"
|
"${workspaceFolder}/apps/slave_node"
|
||||||
}
|
],
|
||||||
}
|
}
|
||||||
|
|
@ -2,31 +2,19 @@
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"tasks": [
|
"tasks": [
|
||||||
{
|
{
|
||||||
"label": "West Build",
|
"label": "Format All C/C++ Files",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
|
"command": "find . -name \"*.c\" -o -name \"*.h\" | xargs clang-format -i",
|
||||||
|
"problemMatcher": [],
|
||||||
"group": {
|
"group": {
|
||||||
"kind": "build",
|
"kind": "build",
|
||||||
"isDefault": true
|
"isDefault": true
|
||||||
},
|
},
|
||||||
"linux": {
|
"presentation": {
|
||||||
"command": "${userHome}/zephyrproject/.venv/bin/west"
|
"reveal": "silent",
|
||||||
},
|
"clear": true,
|
||||||
"windows": {
|
"panel": "shared"
|
||||||
"command": "${userHome}/zephyrproject/.venv/Scripts/west.exe"
|
}
|
||||||
},
|
|
||||||
"osx": {
|
|
||||||
"command": "${userHome}/zephyrproject/.venv/bin/west"
|
|
||||||
},
|
|
||||||
"args": [
|
|
||||||
"build",
|
|
||||||
"-p",
|
|
||||||
"auto",
|
|
||||||
"-b",
|
|
||||||
"valve_node"
|
|
||||||
],
|
|
||||||
"problemMatcher": [
|
|
||||||
"$gcc"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "West Configurable Build",
|
"label": "West Configurable Build",
|
||||||
|
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
.. 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.
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
/ {
|
|
||||||
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>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
CONFIG_ADC=y
|
|
||||||
CONFIG_SENSOR=y
|
|
||||||
CONFIG_VOLTAGE_DIVIDER=y
|
|
||||||
CONFIG_LOG=y
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
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+"
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
/*
|
|
||||||
* 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>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
/*
|
|
||||||
* 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>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
/*
|
|
||||||
* 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>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
/*
|
|
||||||
* 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>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
#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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
cmake_minimum_required(VERSION 3.20)
|
|
||||||
|
|
||||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
|
||||||
project(adc_test)
|
|
||||||
|
|
||||||
target_sources(app PRIVATE src/main.c)
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
&adc1 {
|
|
||||||
pinctrl-0 = <&adc1_in1_pa0>;
|
|
||||||
pinctrl-names = "default";
|
|
||||||
status = "okay";
|
|
||||||
|
|
||||||
st,adc-clock-source = "SYNC";
|
|
||||||
st,adc-prescaler = <4>;
|
|
||||||
};
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
CONFIG_ADC=y
|
|
||||||
CONFIG_ADC_STM32=y
|
|
||||||
CONFIG_LOG=y
|
|
||||||
|
|
@ -1,73 +0,0 @@
|
||||||
#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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,80 +0,0 @@
|
||||||
#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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
#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,8 +1,7 @@
|
||||||
# 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(ADC)
|
project(bl_test)
|
||||||
|
|
||||||
|
# Add application source files
|
||||||
target_sources(app PRIVATE src/main.c)
|
target_sources(app PRIVATE src/main.c)
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
VERSION_MAJOR = 0
|
||||||
|
VERSION_MINOR = 0
|
||||||
|
PATCHLEVEL = 1
|
||||||
|
VERSION_TWEAK = 1
|
||||||
|
EXTRAVERSION = devel
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
# 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
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
SB_CONFIG_BOOTLOADER_MCUBOOT=y
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
#include "common.dtsi"
|
||||||
|
|
||||||
|
/* Application Configuration - Firmware wird in slot0_partition geschrieben */
|
||||||
|
/ {
|
||||||
|
chosen {
|
||||||
|
zephyr,code-partition = &slot0_partition;
|
||||||
|
zephyr,uart-mcumgr = &cdc_acm_uart0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* 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>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
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
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
#include "common.dtsi"
|
||||||
|
|
||||||
|
/* MCUboot Configuration - Bootloader wird in boot_partition geschrieben */
|
||||||
|
/ {
|
||||||
|
chosen {
|
||||||
|
zephyr,code-partition = &boot_partition;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -2,7 +2,9 @@ cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||||
|
|
||||||
project(firmware_node LANGUAGES C)
|
project(can_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,2 @@
|
||||||
|
rsource "../../lib/Kconfig"
|
||||||
|
source "Kconfig.zephyr"
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
VERSION_MAJOR = 0
|
||||||
|
VERSION_MINOR = 0
|
||||||
|
PATCHLEVEL = 1
|
||||||
|
VERSION_TWEAK = 1
|
||||||
|
EXTRAVERSION = devel
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
# Disable UART console
|
||||||
|
CONFIG_UART_CONSOLE=n
|
||||||
|
|
||||||
|
# Enable RTT console
|
||||||
|
CONFIG_RTT_CONSOLE=y
|
||||||
|
CONFIG_USE_SEGGER_RTT=y
|
||||||
|
CONFIG_SHELL_BACKEND_RTT=y
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
/ {
|
||||||
|
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";
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
/ {
|
||||||
|
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>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
/ {
|
||||||
|
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";
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
#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;
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
# 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,4 @@
|
||||||
|
CONFIG_USB_DEVICE_STACK=y
|
||||||
|
CONFIG_USB_DEVICE_PRODUCT="Modbus slave node"
|
||||||
|
CONFIG_UART_LINE_CTRL=y
|
||||||
|
CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
# 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
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
SB_CONFIG_BOOTLOADER_MCUBOOT=y
|
||||||
|
SB_CONFIG_MCUBOOT_MODE_SINGLE_APP=y
|
||||||
|
|
||||||
|
CONFIG_LOG=y
|
||||||
|
CONFIG_MCUBOOT_LOG_LEVEL_INF=y
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
# 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
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
# Board specific configuration for weact_stm32g431_core
|
|
||||||
# This file can be used for board-specific overrides if needed
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2021 Nordic Semiconductor ASA
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "flash_partitions_128kb.dtsi"
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
&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 */
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
# 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
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
# 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
|
|
||||||
|
|
@ -1,167 +0,0 @@
|
||||||
#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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
# Sysbuild configuration for firmware_node with MCUboot
|
|
||||||
|
|
||||||
# Enable MCUboot as bootloader
|
|
||||||
set(SB_CONFIG_BOOTLOADER_MCUBOOT TRUE)
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
# Sysbuild configuration for firmware_node with MCUboot
|
|
||||||
|
|
||||||
# Enable MCUboot as bootloader
|
|
||||||
SB_CONFIG_BOOTLOADER_MCUBOOT=y
|
|
||||||
SB_CONFIG_MCUBOOT_MODE_SINGLE_APP=y
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2021 Nordic Semiconductor ASA
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "../boards/flash_partitions_128kb.dtsi"
|
|
||||||
|
|
||||||
/ {
|
|
||||||
chosen {
|
|
||||||
zephyr,code-partition = &slot0_partition;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
# 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
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
/*
|
|
||||||
* MCUboot device tree overlay for firmware_node
|
|
||||||
* Uses shared flash partition layout
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "../boards/flash_partitions_128kb.dtsi"
|
|
||||||
|
|
||||||
/ {
|
|
||||||
chosen {
|
|
||||||
zephyr,code-partition = &boot_partition;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
/*
|
|
||||||
* 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,9 +1,8 @@
|
||||||
cmake_minimum_required(VERSION 3.20)
|
cmake_minimum_required(VERSION 3.20.5)
|
||||||
|
|
||||||
# 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_sources(app PRIVATE src/main.c)
|
||||||
|
|
||||||
|
target_include_directories(app PRIVATE include)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
# 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.
|
||||||
|
|
@ -2,4 +2,4 @@ VERSION_MAJOR = 0
|
||||||
VERSION_MINOR = 0
|
VERSION_MINOR = 0
|
||||||
PATCHLEVEL = 1
|
PATCHLEVEL = 1
|
||||||
VERSION_TWEAK = 0
|
VERSION_TWEAK = 0
|
||||||
EXTRAVERSION = testing
|
EXTRAVERSION = devel
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
&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";
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
#include "common_4MB.dtsi"
|
||||||
|
|
@ -1,2 +1,47 @@
|
||||||
# Gateway Configuration
|
# -------------------
|
||||||
CONFIG_NETWORKING=y
|
# Logging and Console
|
||||||
|
# -------------------
|
||||||
|
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,13 +1,136 @@
|
||||||
/*
|
#include <zephyr/fs/fs.h>
|
||||||
* Copyright (c) 2025 Eduard Iten
|
#include <zephyr/fs/littlefs.h>
|
||||||
*
|
|
||||||
* 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)
|
||||||
{
|
{
|
||||||
printk("Hello from Gateway!\n");
|
int rc = fs_mount(&littlefs_mnt);
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
SB_CONFIG_BOOTLOADER_MCUBOOT=y
|
||||||
|
SB_CONFIG_MCUBOOT_MODE_SINGLE_APP=y
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
#include "../boards/common_4MB.dtsi"
|
||||||
|
|
||||||
|
/* Application Configuration - Firmware goes to slot0_partition (0x20000) */
|
||||||
|
/ {
|
||||||
|
chosen {
|
||||||
|
zephyr,code-partition = &slot0_partition;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
CONFIG_LOG=y
|
||||||
|
CONFIG_MCUBOOT_LOG_LEVEL_INF=y
|
||||||
|
CONFIG_UART_CONSOLE=n
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
#include "../boards/common_4MB.dtsi"
|
||||||
|
|
||||||
|
/* MCUboot Configuration - Bootloader goes to boot_partition (0x0) */
|
||||||
|
/ {
|
||||||
|
chosen {
|
||||||
|
zephyr,code-partition = &boot_partition;
|
||||||
|
};
|
||||||
|
aliases {
|
||||||
|
mcuboot-button0 = &user_button1;
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 6e669cfc4e400c3ef6e55c16401788ce0d804577
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Linux",
|
||||||
|
"compileCommands": "${workspaceFolder}/build/compile_commands.json",
|
||||||
|
"cStandard": "c99",
|
||||||
|
"cppStandard": "gnu++17",
|
||||||
|
"intelliSenseMode": "linux-gcc-arm"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": 4
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,8 @@ 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)
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
VERSION_MAJOR = 0
|
||||||
|
VERSION_MINOR = 0
|
||||||
|
PATCHLEVEL = 1
|
||||||
|
VERSION_TWEAK = 1
|
||||||
|
EXTRAVERSION = devel
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
/ {
|
||||||
|
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,15 +1,39 @@
|
||||||
/ {
|
/ {
|
||||||
|
aliases {
|
||||||
|
vnd7050aj = &vnd7050aj;
|
||||||
|
};
|
||||||
|
|
||||||
vnd7050aj: vnd7050aj {
|
vnd7050aj: vnd7050aj {
|
||||||
compatible = "vnd7050aj-valve-controller";
|
compatible = "st,vnd7050aj";
|
||||||
status = "okay";
|
status = "okay";
|
||||||
|
|
||||||
// VND7050AJ GPIO pin definitions
|
input0-gpios = <&gpiob 3 GPIO_ACTIVE_HIGH>;
|
||||||
in0-gpios = <&gpiob 7 GPIO_ACTIVE_HIGH>; // IN0 (PB7) - Input 0 control signal
|
input1-gpios = <&gpiob 4 GPIO_ACTIVE_HIGH>;
|
||||||
in1-gpios = <&gpiob 9 GPIO_ACTIVE_HIGH>; // IN1 (PB9) - Input 1 control signal
|
select0-gpios = <&gpiob 7 GPIO_ACTIVE_HIGH>;
|
||||||
rst-gpios = <&gpiob 3 GPIO_ACTIVE_HIGH>; // RST (PB3) - Reset pin for VND7050AJ
|
select1-gpios = <&gpiob 9 GPIO_ACTIVE_HIGH>;
|
||||||
sen-gpios = <&gpiob 4 GPIO_ACTIVE_HIGH>; // SEN (PB4) - Sense Enable for current monitoring
|
sense-enable-gpios = <&gpiob 6 GPIO_ACTIVE_HIGH>;
|
||||||
s0-gpios = <&gpiob 6 GPIO_ACTIVE_HIGH>; // S0 (PB6) - Status/Select 0 output from VND7050AJ
|
fault-reset-gpios = <&gpiob 5 GPIO_ACTIVE_LOW>;
|
||||||
s1-gpios = <&gpiob 5 GPIO_ACTIVE_HIGH>; // S1 (PB5) - Status/Select 1 output from VND7050AJ
|
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>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -22,43 +46,3 @@
|
||||||
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,3 +1,5 @@
|
||||||
|
#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";
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
# 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,35 +0,0 @@
|
||||||
# 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,6 +5,9 @@ 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
|
||||||
|
|
@ -19,9 +22,7 @@ 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_BUFFER_SIZE=256
|
CONFIG_MODBUS_LOG_LEVEL_DBG=y
|
||||||
|
|
||||||
# Enable ADC driver
|
|
||||||
CONFIG_ADC=y
|
|
||||||
CONFIG_ADC_STM32=y
|
|
||||||
|
|
||||||
|
# Enable VND7050AJ
|
||||||
|
CONFIG_VND7050AJ=y
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,15 @@
|
||||||
#include <zephyr/kernel.h>
|
#include <zephyr/kernel.h>
|
||||||
#include <zephyr/settings/settings.h>
|
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
|
#include <zephyr/settings/settings.h>
|
||||||
|
#include <lib/fwu.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()) {
|
||||||
|
|
@ -18,16 +19,10 @@ int main(void)
|
||||||
valve_init();
|
valve_init();
|
||||||
fwu_init();
|
fwu_init();
|
||||||
|
|
||||||
if (modbus_server_init()) {
|
rc = modbus_server_init();
|
||||||
LOG_ERR("Modbus RTU server initialization failed");
|
if (rc) {
|
||||||
return 0;
|
LOG_ERR("Modbus server initialization failed: %d", rc);
|
||||||
}
|
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");
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
SB_CONFIG_BOOTLOADER_MCUBOOT=y
|
||||||
|
SB_CONFIG_MCUBOOT_MODE_SINGLE_APP=y
|
||||||
|
|
||||||
|
CONFIG_LOG=y
|
||||||
|
CONFIG_MCUBOOT_LOG_LEVEL_INF=y
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
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)
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
# 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
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
#!/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' \
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
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
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
#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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
# Sysbuild configuration for firmware_node with MCUboot
|
|
||||||
|
|
||||||
# Enable MCUboot as bootloader
|
|
||||||
SB_CONFIG_BOOTLOADER_MCUBOOT=y
|
|
||||||
SB_CONFIG_MCUBOOT_MODE_SINGLE_APP=y
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2021 Nordic Semiconductor ASA
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "flash_partitions_128kb.dtsi"
|
|
||||||
|
|
||||||
/ {
|
|
||||||
chosen {
|
|
||||||
zephyr,code-partition = &slot0_partition;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
/*
|
|
||||||
* 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";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
#
|
|
||||||
# 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
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
#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";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
# 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
|
||||||
|
|
@ -0,0 +1,106 @@
|
||||||
|
# ===================================================================
|
||||||
|
# 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]
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
#!/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}")
|
||||||
|
|
@ -0,0 +1,166 @@
|
||||||
|
# ===================================================================
|
||||||
|
# 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);
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
ruamel.yaml
|
||||||
|
esphome
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue