From 6d1242158cc85c113e71bee4fef3b035fe36ce3b Mon Sep 17 00:00:00 2001 From: PonomarevDA Date: Mon, 25 Dec 2023 22:54:25 +0300 Subject: [PATCH] add uav lights node --- .github/workflows/build_dronecan.yml | 27 ------ .gitmodules | 2 +- Libs/stm32-cube-project | 2 +- Src/cyphal_application/CMakeLists.txt | 10 +- Src/cyphal_application/README.md | 3 +- Src/cyphal_application/application.cpp | 20 ++-- Src/cyphal_application/feedback/feedback.cpp | 43 -------- Src/cyphal_application/feedback/feedback.hpp | 28 ------ Src/cyphal_application/feedback/params.yaml | 9 -- Src/cyphal_application/lights/lights.cpp | 64 ++++++++++++ Src/cyphal_application/lights/lights.hpp | 23 +++++ .../{setpoint => lights}/params.yaml | 6 +- Src/cyphal_application/setpoint/setpoint.cpp | 43 -------- Src/cyphal_application/setpoint/setpoint.hpp | 26 ----- Src/periphery/adc/adc.cpp | 28 ++++++ Src/periphery/adc/adc.hpp | 33 +++++++ Src/periphery/led/led.cpp | 30 +----- Src/periphery/led/led.hpp | 9 +- Src/periphery/pwm/pwm.cpp | 97 ------------------- Src/periphery/pwm/pwm.hpp | 37 ------- Src/periphery/ws2812/rgb_color.h | 54 +++++++++++ Src/periphery/ws2812/ws2812.c | 74 ++++++++++++++ Src/periphery/ws2812/ws2812.h | 48 +++++++++ 23 files changed, 346 insertions(+), 370 deletions(-) delete mode 100644 .github/workflows/build_dronecan.yml delete mode 100644 Src/cyphal_application/feedback/feedback.cpp delete mode 100644 Src/cyphal_application/feedback/feedback.hpp delete mode 100644 Src/cyphal_application/feedback/params.yaml create mode 100644 Src/cyphal_application/lights/lights.cpp create mode 100644 Src/cyphal_application/lights/lights.hpp rename Src/cyphal_application/{setpoint => lights}/params.yaml (80%) delete mode 100644 Src/cyphal_application/setpoint/setpoint.cpp delete mode 100644 Src/cyphal_application/setpoint/setpoint.hpp create mode 100644 Src/periphery/adc/adc.cpp create mode 100644 Src/periphery/adc/adc.hpp delete mode 100644 Src/periphery/pwm/pwm.cpp delete mode 100644 Src/periphery/pwm/pwm.hpp create mode 100644 Src/periphery/ws2812/rgb_color.h create mode 100644 Src/periphery/ws2812/ws2812.c create mode 100644 Src/periphery/ws2812/ws2812.h diff --git a/.github/workflows/build_dronecan.yml b/.github/workflows/build_dronecan.yml deleted file mode 100644 index 60fe415..0000000 --- a/.github/workflows/build_dronecan.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: build_dronecan -on: [push] -jobs: - build_dronecan: - runs-on: ubuntu-22.04 - timeout-minutes: 10 - steps: - - uses: actions/checkout@v3 - with: - token: ${{ secrets.ACCESS_TOKEN }} - submodules: recursive - fetch-depth: 0 - - - uses: actions/checkout@v3 - with: - repository: RaccoonlabDev/libsqcan - path: 'Libs/libsqcan' - token: ${{ secrets.ACCESS_TOKEN }} - fetch-depth: 0 - - - name: Checkout libsqcan - run: cd Libs/libsqcan && git checkout dd10256 - - - name: Install dependencies - run: ./scripts/tools/install_for_ubuntu.sh --yes - - - run: make dronecan diff --git a/.gitmodules b/.gitmodules index 802f5fd..8626023 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,4 +9,4 @@ url = git@github.com:PonomarevDA/tools.git [submodule "Libs/stm32-cube-project"] path = Libs/stm32-cube-project - url = https://github.com/RaccoonLabHardware/mini-v2-software.git + url = https://github.com/RaccoonLabHardware/lights-v0-software.git diff --git a/Libs/stm32-cube-project b/Libs/stm32-cube-project index dd64a69..6f196b2 160000 --- a/Libs/stm32-cube-project +++ b/Libs/stm32-cube-project @@ -1 +1 @@ -Subproject commit dd64a6993f5364fb88b151d1e256a786f6c19fe1 +Subproject commit 6f196b28431bcea6a690954cbd033b25b32bb962 diff --git a/Src/cyphal_application/CMakeLists.txt b/Src/cyphal_application/CMakeLists.txt index 9a29483..410b9a6 100644 --- a/Src/cyphal_application/CMakeLists.txt +++ b/Src/cyphal_application/CMakeLists.txt @@ -1,10 +1,11 @@ set(applicationSourceCode - Src/periphery/pwm/pwm.cpp + Src/periphery/adc/adc.cpp Src/periphery/led/led.cpp + Src/periphery/ws2812/ws2812.c - Src/cyphal_application/setpoint/setpoint.cpp - Src/cyphal_application/feedback/feedback.cpp + Src/cyphal_application/lights/lights.cpp Src/cyphal_application/application.cpp + Libs/Cyphal/Udral/rgbled.cpp ) set(applicationHeaders Src @@ -14,6 +15,5 @@ set(applicationHeaders list(APPEND cyphalRegisters ${CMAKE_CURRENT_LIST_DIR}/params.yaml - ${CMAKE_CURRENT_LIST_DIR}/setpoint/params.yaml - ${CMAKE_CURRENT_LIST_DIR}/feedback/params.yaml + ${CMAKE_CURRENT_LIST_DIR}/lights/params.yaml ) diff --git a/Src/cyphal_application/README.md b/Src/cyphal_application/README.md index 4c4a0e6..370c41e 100644 --- a/Src/cyphal_application/README.md +++ b/Src/cyphal_application/README.md @@ -2,8 +2,7 @@ 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 | sub | reg.udral.physics.optics.HighColor.0.1 | lights | {'type': 'Port', 'data_type': 'reg.udral.physics.optics.HighColor.0.1', 'enum_base': 'RGBLED'}| The node has the following registers: diff --git a/Src/cyphal_application/application.cpp b/Src/cyphal_application/application.cpp index 6f65a4d..4b84d79 100644 --- a/Src/cyphal_application/application.cpp +++ b/Src/cyphal_application/application.cpp @@ -8,16 +8,16 @@ #include "main.h" #include "string_params.hpp" #include "params.hpp" -#include "setpoint/setpoint.hpp" -#include "feedback/feedback.hpp" +#include "lights/lights.hpp" #include "periphery/led/led.hpp" + void init_persistent_storage() { paramsInit(static_cast(IntParamsIndexes::INTEGER_PARAMS_AMOUNT), NUM_OF_STR_PARAMS); paramsLoadFromFlash(); auto node_name_param_idx = static_cast(IntParamsIndexes::INTEGER_PARAMS_AMOUNT); - paramsSetStringValue(node_name_param_idx, 19, (const uint8_t*)"co.raccoonlab.mini"); + paramsSetStringValue(node_name_param_idx, 21, (const uint8_t*)"co.raccoonlab.lights"); } void application_entry_point() { @@ -28,19 +28,13 @@ void application_entry_point() { cyphal::Cyphal cyphal; int init_res = cyphal.init(); - SetpointSubscriber setpoint(&cyphal); - init_res |= setpoint.init(); - - FeedbackPublisher feedback(&cyphal); - init_res |= feedback.init(); + RgbLights lights(&cyphal); + init_res |= lights.init(); while (true) { - auto led_color = (init_res >= 0) ? LedColor::BLUE_COLOR : LedColor::RED_COLOR; - LedPeriphery::toggle(led_color); + LedPeriphery::toggle(); cyphal.process(); - - auto crnt_time_ms = HAL_GetTick(); - feedback.process(crnt_time_ms); + lights.update(); } } diff --git a/Src/cyphal_application/feedback/feedback.cpp b/Src/cyphal_application/feedback/feedback.cpp deleted file mode 100644 index db07ba8..0000000 --- a/Src/cyphal_application/feedback/feedback.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/// This software is distributed under the terms of the MIT License. -/// Copyright (c) 2023 Dmitry Ponomarev. -/// Author: Dmitry Ponomarev - -#include "feedback.hpp" -#include -#include "reg/udral/service/actuator/common/Feedback_0_1.h" -#include "cyphal.hpp" -#include "params.hpp" -#include "periphery/pwm/pwm.hpp" - -int8_t FeedbackPublisher::init() { - return 0; -} - -void FeedbackPublisher::process(uint32_t crnt_time_ms) { - if (_prev_pub_ts_ms + 1000 > crnt_time_ms) { - return; - } - - publish_msg(crnt_time_ms); -} - -void FeedbackPublisher::publish_msg(uint32_t crnt_time_ms) { - _prev_pub_ts_ms = crnt_time_ms; - - reg_udral_service_actuator_common_Feedback_0_1 msg; - - msg.heartbeat.health.value = uavcan_node_Health_1_0_NOMINAL; - msg.heartbeat.readiness.value = reg_udral_service_common_Readiness_0_1_ENGAGED; - - uint32_t pwm_ccr_reg_value = PwmPeriphery::get_duration(PwmPin::PWM_1); - uint32_t pwm_duration = std::clamp(pwm_ccr_reg_value, 1000ul, 2000ul); - msg.demand_factor_pct = (pwm_duration - 1000) / 10; - setPortId(paramsGetIntegerValue(PARAM_PUB_FEEDBACK_1_ID)); - - uint8_t buffer[reg_udral_service_actuator_common_Feedback_0_1_EXTENT_BYTES_]; - size_t buffer_size = reg_udral_service_actuator_common_Feedback_0_1_EXTENT_BYTES_; - int32_t result = reg_udral_service_actuator_common_Feedback_0_1_serialize_(&msg, buffer, &buffer_size); - if (NUNAVUT_SUCCESS == result) { - push(buffer_size, buffer); - } -} diff --git a/Src/cyphal_application/feedback/feedback.hpp b/Src/cyphal_application/feedback/feedback.hpp deleted file mode 100644 index 560126e..0000000 --- a/Src/cyphal_application/feedback/feedback.hpp +++ /dev/null @@ -1,28 +0,0 @@ -/// This software is distributed under the terms of the MIT License. -/// Copyright (c) 2022-2023 Dmitry Ponomarev. -/// Author: Dmitry Ponomarev - -#ifndef SRC_CYPHAL_APPLICATION_FEEDBACK_HPP_ -#define SRC_CYPHAL_APPLICATION_FEEDBACK_HPP_ - -#include "cyphal_publishers.hpp" - -#ifdef __cplusplus -extern "C" { -#endif - -class FeedbackPublisher: public cyphal::CyphalPublisher { -public: - FeedbackPublisher(cyphal::Cyphal* driver_) : CyphalPublisher(driver_, 0) {}; - int8_t init(); - void process(uint32_t crnt_time_ms); - void publish_msg(uint32_t crnt_time_ms); -private: - uint32_t _prev_pub_ts_ms = 0; -}; - -#ifdef __cplusplus -} -#endif - -#endif // SRC_CYPHAL_APPLICATION_FEEDBACK_HPP_ diff --git a/Src/cyphal_application/feedback/params.yaml b/Src/cyphal_application/feedback/params.yaml deleted file mode 100644 index 67e6c5d..0000000 --- a/Src/cyphal_application/feedback/params.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# 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.feedback: - type: Port - data_type: reg.udral.service.actuator.common.Feedback.0.1 - enum_base: PARAM_PUB_FEEDBACK_1 diff --git a/Src/cyphal_application/lights/lights.cpp b/Src/cyphal_application/lights/lights.cpp new file mode 100644 index 0000000..7d766f5 --- /dev/null +++ b/Src/cyphal_application/lights/lights.cpp @@ -0,0 +1,64 @@ +/// This software is distributed under the terms of the MIT License. +/// Copyright (c) 2023 Dmitry Ponomarev. +/// Author: Dmitry Ponomarev + +#include "lights.hpp" +#include +#include "cyphal.hpp" +#include "params.hpp" +#include "main.h" +#include "periphery/ws2812/ws2812.h" +#include "periphery/adc/adc.hpp" + +extern TIM_HandleTypeDef htim2; + +static constexpr uint8_t RED_SCALE = 256 / (reg_udral_physics_optics_HighColor_0_1_MAX_RED + 1); +static constexpr uint8_t GREEN_SCALE = 256 / (reg_udral_physics_optics_HighColor_0_1_MAX_GREEN + 1); +static constexpr uint8_t BLUE_SCALE = 256 / (reg_udral_physics_optics_HighColor_0_1_MAX_BLUE + 1); + + +int8_t RgbLights::init() { + int8_t res; + + res = ws2812bInit(32, &htim2, TIM_CHANNEL_3); + if (res < 0) { + return res; + } + + res = _rgbled_sub.init(); + if (res < 0) { + return res; + } + + res = AdcPeriphery::init(); + if (res < 0) { + return res; + } + + return 0; +}; + +void RgbLights::update() { + static uint32_t next_time_ms = 0; + if (HAL_GetTick() < next_time_ms) { + return; + } + next_time_ms = HAL_GetTick() + 10; + + auto color = _rgbled_sub.get(); + static Leds_Color_t leds; + + // static uint8_t counter = 0; + // leds.colors[counter].shades.red = color.red * RED_SCALE; + // leds.colors[counter].shades.green = color.green * GREEN_SCALE; + // leds.colors[counter].shades.blue = color.blue * BLUE_SCALE; + // counter = (counter + 1) % 32; + + for (uint_fast8_t led_idx = 0; led_idx < 32; led_idx++) { + leds.colors[led_idx].shades.red = color.red * RED_SCALE; + leds.colors[led_idx].shades.green = color.green * GREEN_SCALE; + leds.colors[led_idx].shades.blue = color.blue * BLUE_SCALE; + } + ws2812bSetColors(&leds); + ws2812bStartOnce(); +} diff --git a/Src/cyphal_application/lights/lights.hpp b/Src/cyphal_application/lights/lights.hpp new file mode 100644 index 0000000..7155fc8 --- /dev/null +++ b/Src/cyphal_application/lights/lights.hpp @@ -0,0 +1,23 @@ +/// This software is distributed under the terms of the MIT License. +/// Copyright (c) 2023 Dmitry Ponomarev. +/// Author: Dmitry Ponomarev + +#ifndef SRC_CYPHAL_APPLICATION_LIGHTS_LIGHTS_HPP_ +#define SRC_CYPHAL_APPLICATION_LIGHTS_LIGHTS_HPP_ + +#include "cyphal_subscribers.hpp" +#include "Udral/rgbled.hpp" +#include "Udral/circuit_status.hpp" + +class RgbLights { +public: + RgbLights(cyphal::Cyphal* driver) : _rgbled_sub(driver), _temp_pub(driver, 0) {}; + int8_t init(); + void update(); +private: + + cyphal::HighColorSubscriber _rgbled_sub; + RaccoonLab::CircuitStatusTemperaturePublisher _temp_pub; +}; + +#endif // SRC_CYPHAL_APPLICATION_LIGHTS_LIGHTS_HPP_ diff --git a/Src/cyphal_application/setpoint/params.yaml b/Src/cyphal_application/lights/params.yaml similarity index 80% rename from Src/cyphal_application/setpoint/params.yaml rename to Src/cyphal_application/lights/params.yaml index ea4f9e7..563a703 100644 --- a/Src/cyphal_application/setpoint/params.yaml +++ b/Src/cyphal_application/lights/params.yaml @@ -3,7 +3,7 @@ # - String register with name `uavcan.pub.setpoint.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.sub.setpoint: +uavcan.sub.lights: type: Port - data_type: reg.udral.service.actuator.common.sp.Vector31 - enum_base: PARAM_SUB_SETPOINT + data_type: reg.udral.physics.optics.HighColor.0.1 + enum_base: RGBLED diff --git a/Src/cyphal_application/setpoint/setpoint.cpp b/Src/cyphal_application/setpoint/setpoint.cpp deleted file mode 100644 index 7afc54e..0000000 --- a/Src/cyphal_application/setpoint/setpoint.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/// This software is distributed under the terms of the MIT License. -/// Copyright (c) 2023 Dmitry Ponomarev. -/// Author: Dmitry Ponomarev - -#include "setpoint.hpp" -#include -#include "reg/udral/service/actuator/common/sp/Vector31_0_1.h" -#include "cyphal.hpp" -#include "params.hpp" -#include "periphery/pwm/pwm.hpp" - -SetpointSubscriber::SetpointSubscriber(cyphal::Cyphal* driver_) : - CyphalSubscriber(driver_, 0) { -}; - -int8_t SetpointSubscriber::init() { - PwmPeriphery::init(PwmPin::PWM_1); - PwmPeriphery::init(PwmPin::PWM_2); - PwmPeriphery::init(PwmPin::PWM_3); - PwmPeriphery::init(PwmPin::PWM_4); - - port_id = paramsGetIntegerValue(IntParamsIndexes::PARAM_SUB_SETPOINT_ID); - if (driver->subscribe(this, - reg_udral_service_actuator_common_sp_Vector31_0_1_EXTENT_BYTES_, - cyphal::CanardTransferKindMessage) < 0) { - return -1; - } - - return 0; -} - -void SetpointSubscriber::callback(const cyphal::CanardRxTransfer& transfer) { - const uint8_t* payload = static_cast(transfer.payload); - size_t payload_len = transfer.payload_size; - reg_udral_service_actuator_common_sp_Vector31_0_1 msg; - if (reg_udral_service_actuator_common_sp_Vector31_0_1_deserialize_(&msg, payload, &payload_len) < 0) { - return; - } - - float setpoint_clamped = std::clamp(msg.value[0], 0.0f, 1.0f); - uint32_t pwm_duration = setpoint_clamped * 1000 + 1000; - PwmPeriphery::set_duration(PwmPin::PWM_1, pwm_duration); -} diff --git a/Src/cyphal_application/setpoint/setpoint.hpp b/Src/cyphal_application/setpoint/setpoint.hpp deleted file mode 100644 index 7b669ee..0000000 --- a/Src/cyphal_application/setpoint/setpoint.hpp +++ /dev/null @@ -1,26 +0,0 @@ -/// This software is distributed under the terms of the MIT License. -/// Copyright (c) 2022-2023 Dmitry Ponomarev. -/// Author: Dmitry Ponomarev - -#ifndef SRC_CYPHAL_APPLICATION_SETPOINT_SETPOINT_HPP_ -#define SRC_CYPHAL_APPLICATION_SETPOINT_SETPOINT_HPP_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "cyphal_subscribers.hpp" - -class SetpointSubscriber: public cyphal::CyphalSubscriber { -public: - SetpointSubscriber(cyphal::Cyphal* driver); - int8_t init(); -private: - void callback(const cyphal::CanardRxTransfer& transfer) override; -}; - -#ifdef __cplusplus -} -#endif - -#endif // SRC_CYPHAL_APPLICATION_SETPOINT_SETPOINT_HPP_ diff --git a/Src/periphery/adc/adc.cpp b/Src/periphery/adc/adc.cpp new file mode 100644 index 0000000..678fdb5 --- /dev/null +++ b/Src/periphery/adc/adc.cpp @@ -0,0 +1,28 @@ +/// This software is distributed under the terms of the MIT License. +/// Copyright (c) 2022-2023 Dmitry Ponomarev. +/// Author: Dmitry Ponomarev + +#include "adc.hpp" +#include "main.h" + +extern ADC_HandleTypeDef hadc1; + +int8_t AdcPeriphery::init() { + HAL_ADCEx_Calibration_Start(&hadc1); + _is_adc_already_inited = true; + return 0; +} + +uint16_t AdcPeriphery::get(AdcChannel channel) { + if (!_is_adc_already_inited || channel >= AdcChannel::ADC_NUMBER_OF_CNANNELS) { + return 0; + } + + HAL_ADC_Start(&hadc1); + uint8_t channels_amount = static_cast(AdcChannel::ADC_NUMBER_OF_CNANNELS); + uint16_t _adc_raw[static_cast(AdcChannel::ADC_NUMBER_OF_CNANNELS)]; + for (size_t ch_idx = 0; ch_idx < channels_amount; ch_idx++) { + _adc_raw[ch_idx] = (uint16_t)HAL_ADC_GetValue(&hadc1); + } + return _adc_raw[static_cast(channel)]; +} diff --git a/Src/periphery/adc/adc.hpp b/Src/periphery/adc/adc.hpp new file mode 100644 index 0000000..6c95dc3 --- /dev/null +++ b/Src/periphery/adc/adc.hpp @@ -0,0 +1,33 @@ +/// This software is distributed under the terms of the MIT License. +/// Copyright (c) 2022-2023 Dmitry Ponomarev. +/// Author: Dmitry Ponomarev + +#ifndef SRC_APPLICATION_PERIPHERY_ADC_ADC_HPP_ +#define SRC_APPLICATION_PERIPHERY_ADC_ADC_HPP_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum class AdcChannel : uint8_t { + ADC_VIN, + ADC_5V, + ADC_TEMPERATURE, + ADC_NUMBER_OF_CNANNELS, +}; + +class AdcPeriphery { +public: + static int8_t init(); + static uint16_t get(AdcChannel channel); +private: + static inline bool _is_adc_already_inited = false; +}; + +#ifdef __cplusplus +} +#endif + +#endif // SRC_APPLICATION_PERIPHERY_ADC_ADC_HPP_ diff --git a/Src/periphery/led/led.cpp b/Src/periphery/led/led.cpp index 6dbd1f1..80fe016 100644 --- a/Src/periphery/led/led.cpp +++ b/Src/periphery/led/led.cpp @@ -7,35 +7,11 @@ void LedPeriphery::reset() { - HAL_GPIO_WritePin(INTERNAL_LED_BLUE_GPIO_Port, INTERNAL_LED_BLUE_Pin, GPIO_PIN_SET); - HAL_GPIO_WritePin(INTERNAL_LED_GREEN_GPIO_Port, INTERNAL_LED_GREEN_Pin, GPIO_PIN_SET); - HAL_GPIO_WritePin(INTERNAL_LED_RED_GPIO_Port, INTERNAL_LED_RED_Pin, GPIO_PIN_SET); + HAL_GPIO_WritePin(INTERNAL_LED_GPIO_Port, INTERNAL_LED_Pin, GPIO_PIN_SET); } -void LedPeriphery::toggle(LedColor led_color) { +void LedPeriphery::toggle() { auto crnt_time_ms = HAL_GetTick(); GPIO_PinState state = (crnt_time_ms % 1000 > 500) ? GPIO_PIN_SET : GPIO_PIN_RESET; - - switch (led_color) { - case LedColor::RED_COLOR: - HAL_GPIO_WritePin(INTERNAL_LED_RED_GPIO_Port, INTERNAL_LED_RED_Pin, state); - HAL_GPIO_WritePin(INTERNAL_LED_GREEN_GPIO_Port, INTERNAL_LED_GREEN_Pin, GPIO_PIN_SET); - HAL_GPIO_WritePin(INTERNAL_LED_BLUE_GPIO_Port, INTERNAL_LED_BLUE_Pin, GPIO_PIN_SET); - break; - - case LedColor::GREEN_COLOR: - HAL_GPIO_WritePin(INTERNAL_LED_RED_GPIO_Port, INTERNAL_LED_RED_Pin, GPIO_PIN_SET); - HAL_GPIO_WritePin(INTERNAL_LED_GREEN_GPIO_Port, INTERNAL_LED_GREEN_Pin, state); - HAL_GPIO_WritePin(INTERNAL_LED_BLUE_GPIO_Port, INTERNAL_LED_BLUE_Pin, GPIO_PIN_SET); - break; - - case LedColor::BLUE_COLOR: - HAL_GPIO_WritePin(INTERNAL_LED_RED_GPIO_Port, INTERNAL_LED_RED_Pin, GPIO_PIN_SET); - HAL_GPIO_WritePin(INTERNAL_LED_GREEN_GPIO_Port, INTERNAL_LED_GREEN_Pin, GPIO_PIN_SET); - HAL_GPIO_WritePin(INTERNAL_LED_BLUE_GPIO_Port, INTERNAL_LED_BLUE_Pin, state); - break; - - default: - break; - } + HAL_GPIO_WritePin(INTERNAL_LED_GPIO_Port, INTERNAL_LED_Pin, state); } diff --git a/Src/periphery/led/led.hpp b/Src/periphery/led/led.hpp index 93361c1..1599f9c 100644 --- a/Src/periphery/led/led.hpp +++ b/Src/periphery/led/led.hpp @@ -11,17 +11,10 @@ extern "C" { #endif -enum class LedColor { - RED_COLOR, - GREEN_COLOR, - BLUE_COLOR, - COLORS_AMOUNT, -}; - class LedPeriphery { public: static void reset(); - static void toggle(LedColor led_color); + static void toggle(); }; #ifdef __cplusplus diff --git a/Src/periphery/pwm/pwm.cpp b/Src/periphery/pwm/pwm.cpp deleted file mode 100644 index 46f8b00..0000000 --- a/Src/periphery/pwm/pwm.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/// This software is distributed under the terms of the MIT License. -/// Copyright (c) 2022-2023 Dmitry Ponomarev. -/// Author: Dmitry Ponomarev - -#include "pwm.hpp" -#include "main.h" - -extern TIM_HandleTypeDef htim3; -extern TIM_HandleTypeDef htim4; - -int8_t PwmPeriphery::init(PwmPin pwm_pin) { - switch (pwm_pin) { - case PwmPin::PWM_1: - if (HAL_OK != HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_2)) { - return -1; - } - TIM4->CCR2 = 1000; - break; - - case PwmPin::PWM_2: - if (HAL_OK != HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1)) { - return -1; - } - TIM4->CCR1 = 1000; - break; - - case PwmPin::PWM_3: - if (HAL_OK != HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1)) { - return -1; - } - TIM3->CCR1 = 1000; - break; - - case PwmPin::PWM_4: - if (HAL_OK != HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2)) { - return -1; - } - TIM3->CCR2 = 1000; - break; - - default: - return -1; - } - - return 0; -} - -void PwmPeriphery::set_duration(const PwmPin pwm_pin, uint32_t duration_us) { - switch (pwm_pin) { - case PwmPin::PWM_1: - TIM4->CCR2 = duration_us; - break; - - case PwmPin::PWM_2: - TIM4->CCR1 = duration_us; - break; - - case PwmPin::PWM_3: - TIM3->CCR1 = duration_us; - break; - - case PwmPin::PWM_4: - TIM3->CCR2 = duration_us; - break; - - default: - break; - } -} - -uint32_t PwmPeriphery::get_duration(PwmPin pwm_pin) { - uint32_t pwm_duration; - - switch (pwm_pin) { - case PwmPin::PWM_1: - pwm_duration = TIM4->CCR2; - break; - - case PwmPin::PWM_2: - pwm_duration = TIM4->CCR1; - break; - - case PwmPin::PWM_3: - pwm_duration = TIM3->CCR1; - break; - - case PwmPin::PWM_4: - pwm_duration = TIM3->CCR2; - break; - - default: - pwm_duration = 0; - break; - } - - return pwm_duration; -} diff --git a/Src/periphery/pwm/pwm.hpp b/Src/periphery/pwm/pwm.hpp deleted file mode 100644 index cf7e5f2..0000000 --- a/Src/periphery/pwm/pwm.hpp +++ /dev/null @@ -1,37 +0,0 @@ -/// This software is distributed under the terms of the MIT License. -/// Copyright (c) 2023 Dmitry Ponomarev. -/// Author: Dmitry Ponomarev - -#ifndef SRC_APPLICATION_PERIPHERY_PWM_HPP_ -#define SRC_APPLICATION_PERIPHERY_PWM_HPP_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @note PWM pinout related to RaccoonLab Mini v2 node - */ -enum class PwmPin { - PWM_1, // PB7 - PWM_2, // PB6 - PWM_3, // PB4 - PWM_4, // PB5 - PWM_AMOUNT, -}; - - -class PwmPeriphery { -public: - static int8_t init(PwmPin pin); - static void set_duration(const PwmPin pin, uint32_t duration_us); - static uint32_t get_duration(PwmPin pin); -}; - -#ifdef __cplusplus -} -#endif - -#endif // SRC_APPLICATION_PERIPHERY_PWM_HPP_ diff --git a/Src/periphery/ws2812/rgb_color.h b/Src/periphery/ws2812/rgb_color.h new file mode 100644 index 0000000..aa5726c --- /dev/null +++ b/Src/periphery/ws2812/rgb_color.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2019 Dmitry Ponomarev + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#ifndef DEVICES_RGB_LEDS_RGB_COLOR_ +#define DEVICES_RGB_LEDS_RGB_COLOR_ + +#include +#include +#include + +#define MAX_NUM_OF_LEDS 32 +#define SHADES_PER_LED 3 + +#define RGB_LED_GREEN_COLOR (0xFF << 0) | (0x00 << 8) | (0x00 << 16) +#define RGB_LED_RED_COLOR (0x00 << 0) | (0xFF << 8) | (0x00 << 16) +#define RGB_LED_BLUE_COLOR (0x00 << 0) | (0x00 << 8) | (0xFF << 16) + + +typedef union { + struct { + uint8_t green; + uint8_t red; + uint8_t blue; + } shades; + uint8_t raw[SHADES_PER_LED]; +} Color_t; + +typedef union { + Color_t colors[MAX_NUM_OF_LEDS]; + uint8_t shades[MAX_NUM_OF_LEDS * SHADES_PER_LED]; +} Leds_Color_t; + + +inline void rgbLedClear(Leds_Color_t* leds, size_t number_of_leds) { + if (leds == NULL || number_of_leds > MAX_NUM_OF_LEDS) { + return; + } + + memset(leds, 0x00, number_of_leds * 3); +} + +inline void rgbLedSetValue(Color_t* color, uint32_t value) { + if (color == NULL) { + return; + } + + memcpy(color, &value, 3); +} + +#endif // DEVICES_RGB_LEDS_RGB_COLOR_ diff --git a/Src/periphery/ws2812/ws2812.c b/Src/periphery/ws2812/ws2812.c new file mode 100644 index 0000000..350c681 --- /dev/null +++ b/Src/periphery/ws2812/ws2812.c @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2019-2023 Dmitry Ponomarev + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include "ws2812.h" +#include +#include + + +#define BUF_OFFSET 4 +#define BITS_PER_SHADE 8 +#define PWM_PERIOD_LOW 29 +#define PWM_PERIOD_HIGH 58 +#define MAX_BUF_SIZE 2 * BUF_OFFSET + MAX_NUM_OF_LEDS * SHADES_PER_LED * BITS_PER_SHADE + + +static TIM_HandleTypeDef* timer = NULL; +static uint32_t timer_channel = 0; +static uint16_t ccr_values[MAX_BUF_SIZE] = {0x00}; +static uint16_t BUF_SIZE = 0; +static uint8_t LEDS_NUM = 0; + + +int8_t ws2812bInit(uint8_t number_of_leds, TIM_HandleTypeDef* timer_ptr, uint32_t channel) { + if (number_of_leds > MAX_NUM_OF_LEDS || timer_ptr == NULL) { + LEDS_NUM = 0; + BUF_SIZE = 0; + return WS2812_ERROR; + } + + LEDS_NUM = number_of_leds; + BUF_SIZE = 2 * BUF_OFFSET + number_of_leds * SHADES_PER_LED * BITS_PER_SHADE; + timer = timer_ptr; + timer_channel = channel; + return WS2812_OK; +} + +/** + * @note hack: + * - sometimes RED is PURPLE, it probably means that the first bit was ignored + * - sometimes BLUS is Yellow, it probably means that the first bit was ignored too + * - So, we increase buffer size from necessary 96 to 104, by adding 4 bytes at the start and + * at the end of buffer filled by zeros. + * This increases stability of leds. + */ +void ws2812bSetColors(const Leds_Color_t* ledsColor) { + const size_t SHADES_AMOUNT = LEDS_NUM * SHADES_PER_LED; + for (size_t shade_num = 0; shade_num < SHADES_AMOUNT; shade_num++) { + for (size_t bit_num = 0; bit_num < BITS_PER_SHADE; bit_num++) { + bool is_bit_high = ledsColor->shades[shade_num] >> (7 - bit_num) & 0x01; + uint16_t ccr_value = is_bit_high ? PWM_PERIOD_HIGH : PWM_PERIOD_LOW; + ccr_values[BUF_OFFSET + shade_num * BITS_PER_SHADE + bit_num] = ccr_value; + } + } +} + +int8_t ws2812bStartOnce() { + if (LEDS_NUM == 0) { + return WS2812_ERROR; + } + if (HAL_TIM_PWM_Start_DMA(timer, timer_channel, (uint32_t*)ccr_values, BUF_SIZE) != HAL_OK) { + return WS2812_ERROR; + } + return WS2812_OK; +} + +void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef* htim) { + if (htim != NULL && htim == timer) { + HAL_TIM_PWM_Stop_DMA(timer, timer_channel); + } +} diff --git a/Src/periphery/ws2812/ws2812.h b/Src/periphery/ws2812/ws2812.h new file mode 100644 index 0000000..3667496 --- /dev/null +++ b/Src/periphery/ws2812/ws2812.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2019-2023 Dmitry Ponomarev + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#ifndef DEVICES_RGB_LEDS_WS2812_H_ +#define DEVICES_RGB_LEDS_WS2812_H_ + +#include "main.h" +#include "rgb_color.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define WS2812_OK 0 +#define WS2812_ERROR -1 + +/** + * @brief Initialize module + * @param number_of_leds - no more than MAX_NUM_OF_LEDS + * @param timer_ptr - any timer + * @param channel - any channel corresponded the timer + * @return WS2812_ERROR if periphery or params is not ok, otherwise return WS2812_OK + */ +int8_t ws2812bInit(uint8_t number_of_leds, TIM_HandleTypeDef* timer_ptr, uint32_t channel); + +/** + * @brief Fill DMA buffer by values corresponded desired colors + * @note Do not actually start PWM. + * This method may has an affect on resulting RGB leds color if it is called during + * DMA work. + */ +void ws2812bSetColors(const Leds_Color_t* leds_color); + +/** + * @brief Run single cycle of setting saved RGB color + * @return WS2812_ERROR if error occured, otherwise WS2812_OK + */ +int8_t ws2812bStartOnce(); + +#ifdef __cplusplus +} +#endif + +#endif // DEVICES_RGB_LEDS_WS2812_H_ \ No newline at end of file