Soliciting suggestions on improving a way to use the HAL libraries in a moderately object oriented C++ app
I've got a lot of help from people on this forum getting up to speed with STM32 controllers and the STM32 HAL libraries. Coming from the C# world, I've been kind of stubborn about trying to maintain a moderately object oriented architecture. That's been a really painful learning experience and I've got a long way to go but I've finally gotten to the point where I have something working well enough to move forward with. As an example, here's how I've combined my UARTs class with the HAL libraries and I'd value any input from this forum on how to improve it.
For background, there are 2 devices right now that need a UART, GPS1 and CTD1. Eventually, I know there will be 8 UART devices and probably more in the future. I'm trying to implement a non-blocking architecture so I use the HAL_UART_Receive_IT, ...Transmit_IT, ...Receive_DMA and ...Transmit_DMA functions. There's a class for each of the devices. All that happens in those classes is they call their respective initGPS1() or initCTD1() functions and then when they need to transmit something and receive the response, they call their ctd1RX... or GPSRX.. function. Right now, I'm erring on the side of keeping things specific at the expense of having several functions that look a lot like each other. If that becomes a problem, I can think about generalizing later.
Thanks in advance - Gene
//UARTs.hpp
#pragma once
#include <stm32h7xx_hal.h>
#include <stm32h7xx_hal_tim.h>
#include <iostream>
using namespace std;
#include "main.hpp"
#include "FIFO.hpp"
extern "C" void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
static uint8_t gps1MsgBuffer[128];
static uint8_t gps1MsgBufferIndex = 0;
static uint8_t gps1RXBuffer[32];
static uint8_t ctd1MsgBuffer[32];
static uint8_t ctd1MsgBufferIndex = 0;
static uint8_t ctd1RXBuffer[32];
static MainFIFORecordIDs gps1RecordID = undefined;
static MainFIFORecordIDs ctd1RecordID = undefined;
class UARTs
{
public:
UARTs()
{
}
void initGPS1_UART();
void initCTD1_UART();
void gps1RXitTXDMA(uint8_t cmd[], size_t size, MainFIFORecordIDs gpsRecordID);
void ctd1RXitTXit(uint8_t cmd[], size_t size, MainFIFORecordIDs ctdRecordID);
};
//UARTs.cpp
#include "UARTs.hpp"
static UART_HandleTypeDef gps1UART = UART_HandleTypeDef();
static DMA_HandleTypeDef gps1HDMA_tx;
static DMA_HandleTypeDef gps1HDMA_rx;
static UART_HandleTypeDef ctd1UART = UART_HandleTypeDef();
static DMA_HandleTypeDef ctd1HDMA_tx;
static DMA_HandleTypeDef ctd1HDMA_rx;
extern "C" void USART1_IRQHandler()
{
HAL_UART_IRQHandler(&gps1UART);
}
extern "C" void USART2_IRQHandler()
{
HAL_UART_IRQHandler(&ctd1UART);
}
extern "C" void DMA1_Stream1_IRQHandler()
{
HAL_DMA_IRQHandler(&gps1HDMA_tx);
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_1, GPIO_PIN_RESET);
}
extern "C" void DMA1_Stream0_IRQHandler()
{
HAL_DMA_IRQHandler(&gps1HDMA_rx);
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart == &gps1UART)
{
//cout << "GPS1 buffer index: " << gps1MsgBufferIndex << " GPS1 Msg Buffer: " << gps1MsgBuffer << endl;
HAL_UART_Receive_IT(&gps1UART, gps1RXBuffer, 1);
gps1MsgBuffer[gps1MsgBufferIndex] = gps1RXBuffer[0];
gps1MsgBufferIndex++;
if (gps1RXBuffer[0] == 10)
{
gps1MsgBufferIndex = 0;
enqueueMainFIFO(getSysTickCounter(), gps1RecordID, gps1MsgBuffer);
}
}
if (huart == &ctd1UART)
{
//cout << "CTD1 buffer index: " << ctd1MsgBufferIndex << " CTD1 Msg Buffer: " << ctd1MsgBuffer << endl;
HAL_UART_Receive_IT(&ctd1UART, ctd1RXBuffer, 1);
ctd1MsgBuffer[ctd1MsgBufferIndex] = ctd1RXBuffer[0];
ctd1MsgBufferIndex++;
//TODO maybe deal with unexpected messages here by making rxtxInProgress visible?
if(ctd1RXBuffer[0] == 10)
{
ctd1MsgBufferIndex = 0;
enqueueMainFIFO(getSysTickCounter(), ctd1RecordID, ctd1MsgBuffer);
}
}
}
void UARTs::gps1RXitTXDMA(uint8_t cmd[], size_t size, MainFIFORecordIDs id)
{
gps1RecordID = id;
HAL_UART_Receive_IT(&gps1UART, gps1RXBuffer, 1);
HAL_UART_Transmit_DMA(&gps1UART, (uint8_t*)cmd, size);
}
void UARTs::ctd1RXitTXit(uint8_t cmd[], size_t size, MainFIFORecordIDs id)
{
ctd1RecordID = id;
HAL_UART_Receive_IT(&ctd1UART, ctd1RXBuffer, 1);
HAL_UART_Transmit_IT(&ctd1UART, (uint8_t*)cmd, size);
}
void UARTs::initGPS1_UART()
{
__USART1_CLK_ENABLE();
__GPIOB_CLK_ENABLE();
GPIO_InitTypeDef uart1GPIO_InitStructure;
uart1GPIO_InitStructure.Pin = GPIO_PIN_6;
uart1GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
uart1GPIO_InitStructure.Alternate = GPIO_AF7_USART1;
uart1GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
uart1GPIO_InitStructure.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &uart1GPIO_InitStructure);
uart1GPIO_InitStructure.Pin = GPIO_PIN_7;
uart1GPIO_InitStructure.Mode = GPIO_MODE_AF_OD;
HAL_GPIO_Init(GPIOB, &uart1GPIO_InitStructure);
gps1UART.Instance = USART1;
gps1UART.Init.BaudRate = 9600;
gps1UART.Init.WordLength = UART_WORDLENGTH_8B;
gps1UART.Init.StopBits = UART_STOPBITS_1;
gps1UART.Init.Parity = UART_PARITY_NONE;
gps1UART.Init.HwFlowCtl = UART_HWCONTROL_NONE;
gps1UART.Init.Mode = UART_MODE_TX_RX;
if (HAL_UART_Init(&gps1UART) != HAL_OK)
asm("bkpt 255");
NVIC_EnableIRQ(USART1_IRQn);
__HAL_RCC_DMA1_CLK_ENABLE();
gps1HDMA_tx.Instance = DMA1_Stream1;
gps1HDMA_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
gps1HDMA_tx.Init.PeriphInc = DMA_PINC_DISABLE;
gps1HDMA_tx.Init.MemInc = DMA_MINC_ENABLE;
gps1HDMA_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
gps1HDMA_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
gps1HDMA_tx.Init.Mode = DMA_NORMAL;
gps1HDMA_tx.Init.Priority = DMA_PRIORITY_LOW;
gps1HDMA_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
gps1HDMA_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
gps1HDMA_tx.Init.MemBurst = DMA_MBURST_INC4;
gps1HDMA_tx.Init.PeriphBurst = DMA_PBURST_INC4;
gps1HDMA_tx.Init.Request = DMA_REQUEST_USART1_TX;
HAL_DMA_Init(&gps1HDMA_tx);
__HAL_LINKDMA(&gps1UART, hdmatx, gps1HDMA_tx);
/* Configure the DMA handler for reception process */
gps1HDMA_rx.Instance = DMA1_Stream0;
gps1HDMA_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
gps1HDMA_rx.Init.PeriphInc = DMA_PINC_DISABLE;
gps1HDMA_rx.Init.MemInc = DMA_MINC_ENABLE;
gps1HDMA_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
gps1HDMA_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
gps1HDMA_rx.Init.Mode = DMA_NORMAL;
gps1HDMA_rx.Init.Priority = DMA_PRIORITY_HIGH;
gps1HDMA_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
gps1HDMA_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
gps1HDMA_rx.Init.MemBurst = DMA_MBURST_INC4;
gps1HDMA_rx.Init.PeriphBurst = DMA_PBURST_INC4;
gps1HDMA_rx.Init.Request = DMA_REQUEST_USART1_RX;
HAL_DMA_Init(&gps1HDMA_rx);
__HAL_LINKDMA(&gps1UART, hdmarx, gps1HDMA_rx);
/* NVIC configuration for DMA transfer complete interrupt (USART1_RX) */
HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
/* NVIC configuration for DMA transfer complete interrupt (USART1_TX) */
HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
}
void UARTs::initCTD1_UART()
{
__USART2_CLK_ENABLE();
__GPIOD_CLK_ENABLE();
GPIO_InitTypeDef usart2GPIO_InitStructure;
usart2GPIO_InitStructure.Pin = GPIO_PIN_5;
usart2GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
usart2GPIO_InitStructure.Alternate = GPIO_AF7_USART2;
usart2GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
usart2GPIO_InitStructure.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOD, &usart2GPIO_InitStructure);
usart2GPIO_InitStructure.Pin = GPIO_PIN_6;
usart2GPIO_InitStructure.Mode = GPIO_MODE_AF_OD;
HAL_GPIO_Init(GPIOD, &usart2GPIO_InitStructure);
ctd1UART.Instance = USART2;
ctd1UART.Init.BaudRate = 9600;
ctd1UART.Init.WordLength = UART_WORDLENGTH_8B;
ctd1UART.Init.StopBits = UART_STOPBITS_1;
ctd1UART.Init.Parity = UART_PARITY_NONE;
ctd1UART.Init.HwFlowCtl = UART_HWCONTROL_NONE;
ctd1UART.Init.Mode = UART_MODE_TX_RX;
if (HAL_UART_Init(&ctd1UART) != HAL_OK)
asm("bkpt 255");
NVIC_EnableIRQ(USART2_IRQn);
}