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/README.md b/README.md index 9e3034c..4410c45 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# Mini v2 node custom application +# UAV Lights node custom application -This repository introduces a simple Cyphal application written for the [RL Mini v2](https://docs.raccoonlab.co/guide/can_pwm/can_pwm_mini_v2.html) and [RL Micro](https://docs.raccoonlab.co/guide/can_pwm/can_pwm_micro.html) nodes. Based on this project you can write your custom application if the original CAN-PWM convertor application doesn't suit your requirements. +This repository introduces a simple Cyphal application written for the [UAV Lights](https://docs.raccoonlab.co/guide/ui_leds/) node. Based on this project you can write your custom application if the original application doesn't suit your requirements. | View | Top view | Bot view | | ---- | --- | ------ | -| drawing | drawing | drawing| +| drawing | drawing | drawing| The default capabilities of the node are shown on the picture below: @@ -14,17 +14,17 @@ The default capabilities of the node are shown on the picture below: The node has 6 user pins. By default 4 of them are configured as PWM and 2 of them as UART RX, but you can change the configuration to support I2C, ADC, GPIO or something else. -Please, refer to the [Mini v2 hardware](https://docs.raccoonlab.co/guide/can_pwm/can_pwm_mini_v2.html#pinout) page for the details. +Please, refer to the [UAV Lights hardware](https://docs.raccoonlab.co/guide/ui_leds/hardware.html) page for the details. Below you can see a brief description of hardware capabilities: -drawing +drawing ## 2. STM32CubeMX -The pinout configuration is based on the [STM32CubeMX](https://www.st.com/en/development-tools/stm32cubemx.html) generated project: [Libs/mini_v2](https://github.com/RaccoonLabHardware/mini_v2_ioc) with the following configuration: +The pinout configuration is based on the [STM32CubeMX](https://www.st.com/en/development-tools/stm32cubemx.html) generated project: [Libs/stm32-cube-project](https://github.com/RaccoonLabHardware/lights-v0-software) with the following configuration: -drawing +drawing If you need to use custom pinout configuration, it is recommended to use either [STM32CubeMX](https://www.st.com/en/development-tools/stm32cubemx.html) or [STM32CubeIDE](https://www.st.com/en/development-tools/stm32cubeide.html) to modify .ioc file and regenerate your custom project. @@ -36,7 +36,7 @@ You are expected to use the following software: - [gui_tool](https://dronecan.github.io/GUI_Tool/Overview/) for DroneCAN. Hardware requirements: -- Mini v2 or Micro node +- UAV Lights node - STM32 programmer and CAN-sniffer (for example [RL sniffer and programmer](https://docs.raccoonlab.co/guide/programmer_sniffer/)) ## 4. Usage @@ -46,16 +46,16 @@ The project is based on the CMake build system, but it is suggested to interract **Step 1. Clone the repository with submodules** ```bash -git clone https://github.com/RaccoonlabDev/mini_v2_node --recursive -cd mini_v2_node +git clone https://github.com/RaccoonlabDev/uav_lights_node --recursive +cd uav_lights_node git submodule update --init --recursive ``` -**Step 2. Connect Sniffer and Programmer to Mini v2 node.** +**Step 2. Connect Sniffer and Programmer to UAV Lights node.** -An example of connection scheme suitable for bench test for Mini v2 node and RL Programmer-Sniffer is shown below: +An example of connection scheme suitable for bench test for UAV Lights node and RL Programmer-Sniffer is shown below: -drawing +drawing You can also use other sniffer and programmers. For details refer to: [Programmer usage](https://docs.raccoonlab.co/guide/programmer_sniffer/programmer.html) and [Sniffer usage](https://docs.raccoonlab.co/guide/programmer_sniffer/sniffer.html#_4-1-cyphal-usage) pages. @@ -90,7 +90,7 @@ source scripts/init.sh ~/Download/Yukon ``` -Please, refer to the [Mini node docs](https://docs.raccoonlab.co/guide/can_pwm/can_pwm_cyphal.html). +Please, refer to the [UAV Lights docs](https://docs.raccoonlab.co/guide/ui_leds/cyphal.html). It has a detailed steps about how to perform bench testing of the node. **Q&A** @@ -99,7 +99,7 @@ If you are strugguling with the software building, please refer to the build wor ## 5. Customization -The peripherals are initialised in [Libs/stm32-cube-project/Core/Src/main.c](https://github.com/RaccoonLabHardware/mini-v2-software/blob/main/Core/Src/main.c), which are automatically generated based on the configuratation file [can_pwm_v2.ioc](https://github.com/RaccoonLabHardware/mini-v2-software/blob/main/can_pwm_v2.ioc) file. If you want to use a different peripheral configuration, you should update can_pwm_v2.ioc with STM32CubeIDE or STM32CubeMX. +The peripherals are initialised in [Libs/stm32-cube-project/Core/Src/main.c](https://github.com/RaccoonLabHardware/lights-v0-software/blob/main/Core/Src/main.c), which are automatically generated based on the configuratation file [project.ioc](https://github.com/RaccoonLabHardware/lights-v0-software/blob/main/can_pwm_v2.ioc) file. If you want to use a different peripheral configuration, you should update can_pwm_v2.ioc with STM32CubeIDE or STM32CubeMX. The main application is started in [Src/cyphal_application/application.cpp](Src/cyphal_application/application.cpp). By default it just blinks the RGB LED, subscribes to the setpoint topic to control PWM1 and publishes a feedback with the latest applied setpoint. Note, that the application is as simple as possible: it controls only a single PWM and doesn't have safety features like TTL, but you are free to extend it as you want. @@ -114,7 +114,6 @@ You can also easily create custom Integer and String registers. An example is sh The project has a few dependencies which are attached to the repository as submodules. They are: -- [Libs/mini_v2](https://github.com/RaccoonLabHardware/mini_v2_ioc) is a project generated with the STM32CubeMX. It is based on .ioc file corresponded to the default firmware of the Mini v2 node. You may only need to change it if you want to use an a different peripheral configuration. +- [Libs/stm32-cube-project](https://github.com/RaccoonLabHardware/lights-v0-software) is a project generated with the STM32CubeMX. It is based on .ioc file corresponded to the default firmware of the UAV Lights node. You may only need to change it if you want to use an a different peripheral configuration. - [Libs/Cyphal](https://github.com/RaccoonlabDev/libcanard_cyphal_application) is a general-purpose application based on the [Cyphal libcanard](https://github.com/OpenCyphal/libcanard), [o1heap](https://github.com/pavel-kirienko/o1heap) and other libraries with minimal required features to start and some features related to UDRAL/DS015. - [Src/libparams](https://github.com/PonomarevDA/libparams) is a simple library with ROM driver implementation that allows to store configuration parameters in persistent memory. -- [not yet] Src/libsqcan is a general-purpose application based on [DroneCAN libcanard](https://github.com/dronecan/libcanard) with minimal required features to start. The DroneCAN part is not publically released yet. 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 diff --git a/assets/connection.png b/assets/connection.png deleted file mode 100644 index 013c897..0000000 Binary files a/assets/connection.png and /dev/null differ diff --git a/assets/yukon.png b/assets/yukon.png index 8f52715..468a100 100644 Binary files a/assets/yukon.png and b/assets/yukon.png differ