diff --git a/CMakeLists.txt b/CMakeLists.txt index d4fbe87..07b99cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,7 @@ add_executable(${EXECUTABLE} ${stm32CubeMxGeneratedFiles} ${applicationSourceCode} ${BUILD_SRC_DIR}/params.cpp + ${ROOT_DIR}/Src/platform/${APP_PLATFORM}/adc.cpp ${ROOT_DIR}/Src/platform/${APP_PLATFORM}/pwm.cpp ${ROOT_DIR}/Src/platform/${APP_PLATFORM}/led.cpp ${ROOT_DIR}/Src/platform/${APP_PLATFORM}/platform_specific.cpp diff --git a/Src/cyphal_application/CMakeLists.txt b/Src/cyphal_application/CMakeLists.txt index 9a6270a..52481e1 100644 --- a/Src/cyphal_application/CMakeLists.txt +++ b/Src/cyphal_application/CMakeLists.txt @@ -12,9 +12,11 @@ include(${ROOT_DIR}/Libs/Cyphal/CMakeLists.txt) set(applicationSourceCode ${CYPHAL_SRC} + ${ROOT_DIR}/Src/cyphal_application/circuit_status/circuit_status.cpp ${ROOT_DIR}/Src/cyphal_application/setpoint/setpoint.cpp ${ROOT_DIR}/Src/cyphal_application/feedback/feedback.cpp ${ROOT_DIR}/Src/cyphal_application/application.cpp + ${ROOT_DIR}/Libs/Cyphal/Udral/circuit_status.cpp ) set(applicationHeaders ${ROOT_DIR}/Libs/Cyphal/Cyphal @@ -30,6 +32,7 @@ set(applicationHeaders set(LIBPARAMS_PARAMS ${ROOT_DIR}/Libs/Cyphal/Cyphal/params.yaml ${CMAKE_CURRENT_LIST_DIR}/params.yaml + ${CMAKE_CURRENT_LIST_DIR}/circuit_status/params.yaml ${CMAKE_CURRENT_LIST_DIR}/setpoint/params.yaml ${CMAKE_CURRENT_LIST_DIR}/feedback/params.yaml ) diff --git a/Src/cyphal_application/README.md b/Src/cyphal_application/README.md index 4c4a0e6..4babd95 100644 --- a/Src/cyphal_application/README.md +++ b/Src/cyphal_application/README.md @@ -2,8 +2,11 @@ The node has the following interface: | № | Type | Message | Topic name | | -- | ---- | ------- | ----------- | -| 1 | sub | reg.udral.service.actuator.common.sp.Vector31 | setpoint | {'type': 'Port', 'data_type': 'reg.udral.service.actuator.common.sp.Vector31', 'enum_base': 'PARAM_SUB_SETPOINT'}| -| 2 | pub | reg.udral.service.actuator.common.Feedback.0.1 | feedback | {'type': 'Port', 'data_type': 'reg.udral.service.actuator.common.Feedback.0.1', 'enum_base': 'PARAM_PUB_FEEDBACK_1'}| +| 1 | pub | uavcan.si.sample.voltage.Scalar.1.0 | crct.5v | {'type': 'Port', 'note': 'Voltage 5V', 'data_type': 'uavcan.si.sample.voltage.Scalar.1.0', 'enum_base': 'PARAM_PUB_CRCT_5V'}| +| 2 | pub | uavcan.si.sample.voltage.Scalar.1.0 | crct.vin | {'type': 'Port', 'note': 'Voltage Vin', 'data_type': 'uavcan.si.sample.voltage.Scalar.1.0', 'enum_base': 'PARAM_PUB_CRCT_VIN'}| +| 3 | pub | uavcan.si.sample.temperature.Scalar.1.0 | crct.temperature | {'type': 'Port', 'note': 'STM32 internal temperature', 'data_type': 'uavcan.si.sample.temperature.Scalar.1.0', 'enum_base': 'PARAM_PUB_CRCT_TEMPERATURE'}| +| 4 | sub | reg.udral.service.actuator.common.sp.Vector31 | setpoint | {'type': 'Port', 'data_type': 'reg.udral.service.actuator.common.sp.Vector31', 'enum_base': 'PARAM_SUB_SETPOINT'}| +| 5 | pub | reg.udral.service.actuator.common.Feedback.0.1 | feedback | {'type': 'Port', 'data_type': 'reg.udral.service.actuator.common.Feedback.0.1', 'enum_base': 'PARAM_PUB_FEEDBACK_1'}| The node has the following registers: diff --git a/Src/cyphal_application/application.cpp b/Src/cyphal_application/application.cpp index 636c513..7c637f7 100644 --- a/Src/cyphal_application/application.cpp +++ b/Src/cyphal_application/application.cpp @@ -9,6 +9,7 @@ #include "params.hpp" #include "setpoint/setpoint.hpp" #include "feedback/feedback.hpp" +#include "circuit_status/circuit_status.hpp" #include "periphery/led/led.hpp" void init_persistent_storage() { @@ -33,6 +34,9 @@ void application_entry_point() { FeedbackPublisher feedback(&cyphal); init_res |= feedback.init(); + CircuitStatus crct(&cyphal); + init_res |= crct.init(); + while (true) { auto led_color = (init_res >= 0) ? LedColor::BLUE_COLOR : LedColor::RED_COLOR; LedPeriphery::toggle(led_color); @@ -41,5 +45,6 @@ void application_entry_point() { auto crnt_time_ms = HAL_GetTick(); feedback.process(crnt_time_ms); + crct.process(crnt_time_ms); } } diff --git a/Src/cyphal_application/circuit_status/circuit_status.cpp b/Src/cyphal_application/circuit_status/circuit_status.cpp new file mode 100644 index 0000000..031b2b1 --- /dev/null +++ b/Src/cyphal_application/circuit_status/circuit_status.cpp @@ -0,0 +1,74 @@ +/// This software is distributed under the terms of the MIT License. +/// Copyright (c) 2024 Dmitry Ponomarev. +/// Author: Dmitry Ponomarev + +#include "circuit_status.hpp" +#include +#include "cyphal.hpp" +#include "params.hpp" +#include "periphery/adc/adc.hpp" + +#include "uavcan/si/sample/electric_current/Scalar_1_0.h" +#include "uavcan/si/sample/voltage/Scalar_1_0.h" +#include "uavcan/si/sample/temperature/Scalar_1_0.h" + +#define ADC_RAW_TO_5V (3.3f * 2.0f / 4095.0f) +#define ADC_RAW_TO_VIN (3.3f * 19.0f / 4095.0f) + +#ifdef STM32G0B1xx + static const uint16_t TEMP_REF = 30; + static const uint16_t ADC_REF = 943; ///< v_ref / 3.3 * 4095 + static const uint16_t AVG_SLOPE = 3.1; ///< avg_slope/(3.3/4096) +#else // STM32F103xB + static const uint16_t TEMP_REF = 25; + static const uint16_t ADC_REF = 1750; ///< v_ref / 3.3 * 4095 + static const uint16_t AVG_SLOPE = 5; ///< avg_slope/(3.3/4096) +#endif + +int8_t CircuitStatus::init() { + AdcPeriphery::init(); + return 0; +} + +void CircuitStatus::process(uint32_t crnt_time_ms) { + if (_prev_pub_ts_ms + 500 > crnt_time_ms) { + return; + } + _prev_pub_ts_ms = crnt_time_ms; + + { + voltage_5v_publisher.setPortId(paramsGetIntegerValue(PARAM_PUB_CRCT_5V_ID)); + if (voltage_5v_publisher.isEnabled()) { + uavcan_si_sample_voltage_Scalar_1_0 msg{ + 0, + AdcPeriphery::get(AdcChannel::ADC_5V) * ADC_RAW_TO_5V + }; + voltage_5v_publisher.publish(msg); + } + } + + { + voltage_vin_publisher.setPortId(paramsGetIntegerValue(PARAM_PUB_CRCT_VIN_ID)); + if (voltage_vin_publisher.isEnabled()) { + uavcan_si_sample_voltage_Scalar_1_0 msg{ + 0, + AdcPeriphery::get(AdcChannel::ADC_VIN) * ADC_RAW_TO_VIN + }; + voltage_vin_publisher.publish(msg); + } + } + + { + temperature_publisher.setPortId(paramsGetIntegerValue(PARAM_PUB_CRCT_TEMPERATURE_ID)); + if (temperature_publisher.isEnabled()) { + uint16_t raw_temperature = AdcPeriphery::get(AdcChannel::ADC_TEMPERATURE); + float temperature = (ADC_REF - raw_temperature) / AVG_SLOPE + TEMP_REF + 273; + uavcan_si_sample_temperature_Scalar_1_0 msg{ + 0, + temperature + }; + temperature_publisher.publish(msg); + } + } + +} diff --git a/Src/cyphal_application/circuit_status/circuit_status.hpp b/Src/cyphal_application/circuit_status/circuit_status.hpp new file mode 100644 index 0000000..62b7b46 --- /dev/null +++ b/Src/cyphal_application/circuit_status/circuit_status.hpp @@ -0,0 +1,33 @@ +/// This software is distributed under the terms of the MIT License. +/// Copyright (c) 2024 Dmitry Ponomarev. +/// Author: Dmitry Ponomarev + +#ifndef SRC_CYPHAL_APPLICATION_CIRCUIT_STATUS_CIRCUIT_STATUS_HPP_ +#define SRC_CYPHAL_APPLICATION_CIRCUIT_STATUS_CIRCUIT_STATUS_HPP_ + +#include "cyphal_publishers.hpp" +#include "Udral/circuit_status.hpp" + +#ifdef __cplusplus +extern "C" { +#endif + +class CircuitStatus { +public: + explicit CircuitStatus(cyphal::Cyphal* driver) : voltage_5v_publisher(driver, 65535), + voltage_vin_publisher(driver, 65535), + temperature_publisher(driver, 65535) {}; + int8_t init(); + void process(uint32_t crnt_time_ms); +private: + RaccoonLab::CircuitStatusVoltagePublisher voltage_5v_publisher; + RaccoonLab::CircuitStatusVoltagePublisher voltage_vin_publisher; + RaccoonLab::CircuitStatusTemperaturePublisher temperature_publisher; + uint32_t _prev_pub_ts_ms = 0; +}; + +#ifdef __cplusplus +} +#endif + +#endif // SRC_CYPHAL_APPLICATION_CIRCUIT_STATUS_CIRCUIT_STATUS_HPP_ diff --git a/Src/cyphal_application/circuit_status/params.yaml b/Src/cyphal_application/circuit_status/params.yaml new file mode 100644 index 0000000..4034d94 --- /dev/null +++ b/Src/cyphal_application/circuit_status/params.yaml @@ -0,0 +1,22 @@ +# This is a short form that generates Integer & String registers related to the subscriber with PORT_NAME=feedback: +# - Integer register with name `uavcan.pub.feedback.id` +# - String register with name `uavcan.pub.feedback.type` +# The generated registers have proper flags, data type and min, max and default values. +# They correspond the standard: https://github.com/OpenCyphal/public_regulated_data_types/blob/master/uavcan/register/384.Access.1.0.dsdl +uavcan.pub.crct.5v: + type: Port + note: Voltage 5V + data_type: uavcan.si.sample.voltage.Scalar.1.0 + enum_base: PARAM_PUB_CRCT_5V + +uavcan.pub.crct.vin: + type: Port + note: Voltage Vin + data_type: uavcan.si.sample.voltage.Scalar.1.0 + enum_base: PARAM_PUB_CRCT_VIN + +uavcan.pub.crct.temperature: + type: Port + note: STM32 internal temperature + data_type: uavcan.si.sample.temperature.Scalar.1.0 + enum_base: PARAM_PUB_CRCT_TEMPERATURE