From 9b22bc6acf6bb5ab0c929aa361821817c24579d4 Mon Sep 17 00:00:00 2001 From: kalipso Date: Mon, 27 Feb 2023 23:17:11 +0100 Subject: [PATCH] WIP working buffer copy with simple locking --- .envrc | 1 + CMakeLists.txt | 1 + commons.cpp | 1 + commons.hpp | 122 ++++++++++++++++++++++++++++++++++++++++++ main.cpp | 78 ++++++++++++++++++++++----- stm32f1xx_it.h | 33 ++++++------ uart_handler.cpp | 4 ++ uart_handler.hpp | 135 ++++++++++++++++++++++++++++++++++++++--------- 8 files changed, 322 insertions(+), 53 deletions(-) create mode 100644 .envrc create mode 100644 commons.cpp create mode 100644 commons.hpp diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/CMakeLists.txt b/CMakeLists.txt index c3b40be..57a2bdd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,7 @@ add_executable(stm32-blinky-f1 uart_handler.cpp spi.cpp rfm95.cpp + commons.cpp stm32f1xx_it.c stm32f1xx_hal_conf.h ) diff --git a/commons.cpp b/commons.cpp new file mode 100644 index 0000000..aec1aac --- /dev/null +++ b/commons.cpp @@ -0,0 +1 @@ +#include "commons.hpp" diff --git a/commons.hpp b/commons.hpp new file mode 100644 index 0000000..1bfe234 --- /dev/null +++ b/commons.hpp @@ -0,0 +1,122 @@ +#pragma once + +#include +#include +#include + +#include "logging.hpp" + +namespace commons { + +template +class lock +{ +public: + ~lock() { locker.unlock(); } + + static std::optional get(LockType& l) + { + if(!l.lock()) + { + log::debug("Could not acquire lock."); + return std::nullopt; + } + return lock{l}; + } + +private: + explicit lock(LockType& l) : locker{l} {} + LockType& locker; +}; + +class mutex +{ +public: + bool lock() + { + if(locked) + { + return false; + } + + locked = true; + return true; + } + + void unlock() + { + locked = false; + } + + bool is_locked() const { + return locked; + } + +protected: + bool locked = false; +}; + +} + +template +struct buffer { + constexpr buffer() {} + constexpr auto size() { return S; } + + bool copy_from(const std::span& input, uint16_t amount) + { + const auto lk = commons::lock::get(m); + if(!lk) + { + return false; + } + + if(amount > max_size) + { + return false; + } + + old_pos = new_pos; + + if (old_pos + amount > max_size) { + const auto size_to_copy = max_size - old_pos; + std::copy(input.begin(), + std::next(input.begin(), size_to_copy), + std::next(buf.begin(), old_pos)); + old_pos = 0; + + //TODO: this only works if amount is not double the size of main_buf + std::copy(std::next(input.begin(), size_to_copy), + input.begin() + amount, buf.begin()); + new_pos = amount - size_to_copy; + } else { + std::copy(input.begin(), + input.begin() + amount, + std::next(buf.begin(), old_pos)); + new_pos = old_pos + amount; + } + + return true; + } + + bool print() const + { + const auto lk = commons::lock::get(m); + if(!lk) + { + return false; + } + + uart_interface::write( + {reinterpret_cast(buf.data()), new_pos}); + return true; + } + +private: + static constexpr auto max_size = S; + std::array buf{}; + size_t old_pos = 0; + size_t new_pos = 0; + mutable commons::mutex m; +}; + diff --git a/main.cpp b/main.cpp index 4601bb1..366c545 100644 --- a/main.cpp +++ b/main.cpp @@ -1,9 +1,9 @@ #include #include -#include #include +#include "commons.hpp" #include "logging.hpp" #include "spi.hpp" @@ -71,6 +71,11 @@ class cmd_holder { std::array commands; }; +static bool updated_main_buf = false; +static buffer main_buffer; + +void print_buf(void) { main_buffer.print(); } + class cmd_handler { public: static constexpr auto MaxCmdLength = 24; @@ -110,6 +115,8 @@ class cmd_handler { iterator = symbols.begin(); if (func == nullptr) { + log::info("Unknown Command: ", current_cmd); + log::info("Type 'help' to show available commands."); return; } @@ -128,11 +135,12 @@ class cmd_handler { void print_help_() const { commands.print_help(); } private: - static constexpr cmd_holder<5> commands{ + static constexpr cmd_holder<6> commands{ std::make_tuple("ver", "Prints current version.", &print_version), std::make_tuple("error", "Set LogLevel to Error.", &loglevel_error), std::make_tuple("info", "Set LogLevel to Info.", &loglevel_info), std::make_tuple("debug", "Set LogLevel to Debug.", &loglevel_debug), + std::make_tuple("buf", "Prints gps uart buffer", &print_buf), std::make_tuple("help", "Prints available commands", &print_help)}; array_t symbols; @@ -162,7 +170,7 @@ void USART1_IRQHandler(void) { } void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { - if (huart != &gps_interface::s_UARTHandle) { + if (huart == &gps_interface::s_UARTHandle) { return; } @@ -174,9 +182,43 @@ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { return; } - gps_interface::write({reinterpret_cast(&value), 1}); cmd_handler::get().add_symbol(value); } + +void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) { + // const uint8_t value = *gps_interface::get_buf(); + // gps_interface::write({reinterpret_cast(&value), 1}); +} + +void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) { + // log::debug("DMA Callback"); + + HAL_GPIO_WritePin(LED_PORT, LED1_PIN, GPIO_PIN_SET); + if (main_buffer.copy_from(gps_interface::new_rx_buf, Size)) { + log::debug("Copied to main buff"); + updated_main_buf = true; + } + HAL_GPIO_WritePin(LED_PORT, LED1_PIN, GPIO_PIN_RESET); + + HAL_UARTEx_ReceiveToIdle_DMA(&gps_interface::s_UARTHandle, + gps_interface::new_rx_buf.data(), + gps_interface::new_rx_buf.size()); + __HAL_DMA_DISABLE_IT(&gps_interface::s_DMAHandle, DMA_IT_HT); +} + +/** + * @brief This function handles DMA1 channel6 global interrupt. + */ +void DMA1_Channel6_IRQHandler(void) { + /* USER CODE BEGIN DMA1_Channel6_IRQn 0 */ + + /* USER CODE END DMA1_Channel6_IRQn 0 */ + HAL_DMA_IRQHandler(&gps_interface::s_DMAHandle); + + /* USER CODE BEGIN DMA1_Channel6_IRQn 1 */ + + /* USER CODE END DMA1_Channel6_IRQn 1 */ +} } void initGPIO() { @@ -217,6 +259,13 @@ void initGPIO() { extern "C" { #include + +void start_interrupt() { + HAL_UARTEx_ReceiveToIdle_DMA(&gps_interface::s_UARTHandle, + gps_interface::new_rx_buf.data(), + gps_interface::new_rx_buf.size()); + __HAL_DMA_DISABLE_IT(&gps_interface::s_DMAHandle, DMA_IT_HT); +} } int main(void) { @@ -242,10 +291,9 @@ int main(void) { HAL_GPIO_WritePin(LoRa_CS_GPIO_Port, LoRa_CS_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(LoRa_RESET_GPIO_Port, LoRa_RESET_Pin, GPIO_PIN_SET); - HAL_Delay(10); + HAL_Delay(1000); log::debug("SPI1 Initialized."); - log::debug("Initialization done."); char OP_Mode = 0x01; @@ -259,16 +307,22 @@ int main(void) { HAL_GPIO_WritePin(LoRa_CS_GPIO_Port, LoRa_CS_Pin, GPIO_PIN_SET); // RF95_Init(); + while (1) { cmd_handler::get().run(); - gps_interface::write("TEST"); - // RF95_setModeRx_Continuous(); - HAL_GPIO_WritePin(LED_PORT, LED1_PIN, GPIO_PIN_RESET); + // gps_interface::write("TEST"); + // RF95_setModeRx_Continuous(); + // HAL_GPIO_WritePin(LED_PORT, LED1_PIN, GPIO_PIN_RESET); // RF95_receive(LoRa_buff); - HAL_Delay(500); - HAL_GPIO_WritePin(LED_PORT, LED1_PIN, GPIO_PIN_SET); - HAL_Delay(500); + // HAL_Delay(100); + // HAL_GPIO_WritePin(LED_PORT, LED1_PIN, GPIO_PIN_SET); + HAL_Delay(100); + + // if (updated_main_buf) { + // log::debug("Printing main buf"); + // updated_main_buf = !main_buffer.print(); + // } // std::string_view msg{reinterpret_cast(LoRa_buff)}; // log::info("Received Message"); diff --git a/stm32f1xx_it.h b/stm32f1xx_it.h index 4ea7520..c7815c5 100644 --- a/stm32f1xx_it.h +++ b/stm32f1xx_it.h @@ -1,20 +1,20 @@ /* USER CODE BEGIN Header */ /** - ****************************************************************************** - * @file stm32f1xx_it.h - * @brief This file contains the headers of the interrupt handlers. - ****************************************************************************** - * @attention - * - * Copyright (c) 2022 STMicroelectronics. - * All rights reserved. - * - * This software is licensed under terms that can be found in the LICENSE file - * in the root directory of this software component. - * If no LICENSE file comes with this software, it is provided AS-IS. - * ****************************************************************************** - */ + * @file stm32f1xx_it.h + * @brief This file contains the headers of the interrupt handlers. + ****************************************************************************** + * @attention + * + * Copyright (c) 2022 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ /* USER CODE END Header */ /* Define to prevent recursive inclusion -------------------------------------*/ @@ -22,7 +22,7 @@ #define __STM32F1xx_IT_H #ifdef __cplusplus - extern "C" { +extern "C" { #endif /* Private includes ----------------------------------------------------------*/ @@ -55,6 +55,9 @@ void SVC_Handler(void); void DebugMon_Handler(void); void PendSV_Handler(void); void SysTick_Handler(void); +void DMA1_Channel6_IRQHandler(void); +void USART1_IRQHandler(void); + /* USER CODE BEGIN EFP */ /* USER CODE END EFP */ diff --git a/uart_handler.cpp b/uart_handler.cpp index ef72567..70b30f1 100644 --- a/uart_handler.cpp +++ b/uart_handler.cpp @@ -3,6 +3,10 @@ template <> // uint8_t* uart_interface::rx_buff = new uint8_t[10]; uint8_t uart_interface::rx_buff = 0; +template <> +std::array uart_interface::new_rx_buf{}; template <> uint8_t gps_interface::rx_buff = 0; +template <> +std::array gps_interface::new_rx_buf{}; diff --git a/uart_handler.hpp b/uart_handler.hpp index f8b1971..96870c7 100644 --- a/uart_handler.hpp +++ b/uart_handler.hpp @@ -2,6 +2,7 @@ #include +#include #include #include "stm32f1xx_it.h" @@ -22,11 +23,22 @@ constexpr auto UART2_PORT = GPIOA_BASE; * small uart wrapper * assumes USART1 with default pins/port */ -template +enum class UartMode : uint8_t { + Blocking = 0, + Interrupt, + DMA, +}; + +template struct uart_handler { static void enable_clocks() { - __HAL_RCC_USART1_CLK_ENABLE(); - __HAL_RCC_USART2_CLK_ENABLE(); + if constexpr (UsartBase == USART1_BASE) { + __HAL_RCC_USART1_CLK_ENABLE(); + } else if constexpr (UsartBase == USART2_BASE) { + __HAL_RCC_USART2_CLK_ENABLE(); + } + __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_AFIO_CLK_ENABLE(); } @@ -46,13 +58,83 @@ struct uart_handler { HAL_GPIO_Init(reinterpret_cast(port), &ua_tx); HAL_GPIO_Init(reinterpret_cast(port), &ua_rx); - /* USART1 interrupt Init */ - HAL_NVIC_SetPriority(USART1_IRQn, 0, 0); - HAL_NVIC_EnableIRQ(USART1_IRQn); + // if constexpr (UsartBase == USART1_BASE) { + // /* USART1 interrupt Init */ + // HAL_NVIC_SetPriority(USART1_IRQn, 0, 0); + // HAL_NVIC_EnableIRQ(USART1_IRQn); + // } - /* USART2 interrupt Init */ - HAL_NVIC_SetPriority(USART2_IRQn, 0, 0); - HAL_NVIC_EnableIRQ(USART2_IRQn); + ///* USART2 interrupt Init */ + // HAL_NVIC_SetPriority(USART2_IRQn, 0, 0); + // HAL_NVIC_EnableIRQ(USART2_IRQn); + } + + static void init_mode() { + if (M == UartMode::Blocking) { + return; // nothing to od + } + + if constexpr (M == UartMode::Interrupt) { + constexpr auto GlobalInterrupt = [](auto Base) { + if (Base == USART1_BASE) { + return USART1_IRQn; + } + if (Base == USART2_BASE) { + return USART2_IRQn; + } + }(UsartBase); + + HAL_NVIC_SetPriority(GlobalInterrupt, 0, 0); + HAL_NVIC_EnableIRQ(GlobalInterrupt); + + HAL_UART_Receive_IT(&s_UARTHandle, &rx_buff, rx_buff_size); + return; + } + if constexpr (M == UartMode::DMA) { + /* DMA controller clock enable */ + __HAL_RCC_DMA1_CLK_ENABLE(); + __HAL_RCC_AFIO_CLK_ENABLE(); + __HAL_RCC_PWR_CLK_ENABLE(); + + /* System interrupt init*/ + + /** NOJTAG: JTAG-DP Disabled and SW-DP Enabled + */ + __HAL_AFIO_REMAP_SWJ_NOJTAG(); + + /* DMA interrupt init */ + /* DMA1_Channel6_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA1_Channel6_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(DMA1_Channel6_IRQn); + + s_DMAHandle.Instance = DMA1_Channel6; + s_DMAHandle.Init.Direction = DMA_PERIPH_TO_MEMORY; + s_DMAHandle.Init.PeriphInc = DMA_PINC_DISABLE; + s_DMAHandle.Init.MemInc = DMA_MINC_ENABLE; + s_DMAHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + s_DMAHandle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + s_DMAHandle.Init.Mode = DMA_NORMAL; + s_DMAHandle.Init.Priority = DMA_PRIORITY_LOW; + write("TRY DMA INIT"); + if (HAL_DMA_Init(&s_DMAHandle) != HAL_OK) { + write("FAILED"); + // Error_Handler(); + } + + __HAL_LINKDMA(&s_UARTHandle, hdmarx, s_DMAHandle); + + /* USART1 interrupt Init */ + HAL_NVIC_SetPriority(USART2_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(USART2_IRQn); + + HAL_DMA_Start_IT( + &s_DMAHandle, reinterpret_cast(&s_UARTHandle.Instance->DR), + reinterpret_cast(new_rx_buf.data()), new_rx_buf.size()); + + HAL_UARTEx_ReceiveToIdle_DMA(&s_UARTHandle, new_rx_buf.data(), + new_rx_buf.size()); + __HAL_DMA_DISABLE_IT(&s_DMAHandle, DMA_IT_HT); + } } static bool enable_oscillators() { @@ -101,32 +183,25 @@ struct uart_handler { return false; } - result = HAL_UART_Receive_IT(&s_UARTHandle, &rx_buff, rx_buff_size); - return result == HAL_OK; } static bool init() { enable_clocks(); init_gpio(); - if (!enable_oscillators()) { return false; } - return init_uart_handle(); + auto result = init_uart_handle(); + init_mode(); + return result; } static HAL_StatusTypeDef write(const std::string_view& message, uint32_t timeout = HAL_MAX_DELAY) { - // constexpr std::string_view carriage_return{"\r\n"}; - return write(reinterpret_cast(const_cast(message.data())), message.size(), timeout); - - // return write( - // reinterpret_cast(const_cast(carriage_return.data())), - // carriage_return.size(), timeout); } static HAL_StatusTypeDef write(uint8_t* buf, uint16_t size, @@ -135,9 +210,11 @@ struct uart_handler { } static UART_HandleTypeDef s_UARTHandle; + static DMA_HandleTypeDef s_DMAHandle; static uint8_t* get_buf() { return &rx_buff; } static const uint8_t* get_buf_c() { return &rx_buff; } + static std::array new_rx_buf; private: static constexpr auto pin_tx = PinTX; @@ -148,12 +225,18 @@ struct uart_handler { static uint8_t rx_buff; }; -template -UART_HandleTypeDef uart_handler::s_UARTHandle = - UART_HandleTypeDef(); +template +DMA_HandleTypeDef uart_handler::s_DMAHandle = DMA_HandleTypeDef(); -using uart_interface = - uart_handler; +template +UART_HandleTypeDef uart_handler::s_UARTHandle = UART_HandleTypeDef(); -using gps_interface = - uart_handler; +using uart_interface = uart_handler; + +using gps_interface = uart_handler;