Всем привет! В программировании МК новичок, пытаюсь заставить работать UART + DMA + RS485 на STM32L433cct6.
Проблема в том, что в буффер попадает отправленная команда, связывал с тем, что не успевает опуститься DE пин и МК считывает свою же команду с линии, победить смог только добавив адресный байт и фильтруя по нему.
Вторым странным фактом является то, что без HAL_Delay в SendCommand сообщение не отправляется.
Ну и вишенкой на торте: на другой МК сообщение отправляется поврежденное, первые 4 байта как и должны, а остальные какой-то шум.
Подозреваю, что проблемы именно в коде, кажется, я тут много лишнего накрутил, помогите найти ошибки, чтобы исправить и улучшить свои навыки)
Код для uart_dma.hpp
Код:
class DMA final {
public:
explicit DMA(UART_HandleTypeDef* huart, CRC_HandleTypeDef* hcrc);
~DMA();
DMA(const DMA&) = delete;
DMA& operator=(const DMA&) = delete;
// Initialization
void Initialize();
// Commands
void RegisterCommand(uint8_t cmd, BKUCommand::Command* handler);
void SendCommand(uint8_t id, uint16_t data);
// Transport operations
void HandleBuffer();
void HandleTxComplete();
void HandleError();
void HandleRxComplete();
void HandleTimComplete();
private:
// Hardware handles
UART_HandleTypeDef* _huart;
CRC_HandleTypeDef* _hcrc;
// Commands
static constexpr uint8_t START_BYTE = 0xA;
static constexpr size_t FRAME_SIZE = 7;
static constexpr size_t MAX_COMMANDS = 8;
struct CommandHandler {
uint8_t cmd;
BKUCommand::Command* handler;
};
CommandHandler _handlers[MAX_COMMANDS];
uint8_t _handler_count = 0;
// DMA
static constexpr size_t DMA_BUFFER_SIZE = 16;
uint8_t _dma_buffer[DMA_BUFFER_SIZE];
uint32_t _dma_pos = 0;
uint32_t _last_sent_time = 0;
// CRC
uint16_t calculateCRC(const uint8_t* data) const;
// Frame
void processFrame(const uint8_t* frame);
bool validateFrame(const uint8_t* frame) const;
// Tx
volatile bool _is_sending = false;
// Helper functions
BKUCommand::Command* findHandler(uint8_t cmd);
};
Код для uart_dma.cpp
Код:
#include "uart_dma.hpp"
#include <string.h>
#define ADDRESS 0xF
namespace UART {
DMA::DMA(UART_HandleTypeDef* huart, CRC_HandleTypeDef* hcrc) :
_huart(huart),
_hcrc(hcrc),
_handler_count(0) {
memset(_dma_buffer, 0, DMA_BUFFER_SIZE);
}
DMA::~DMA() {
HAL_UART_DMAStop(_huart);
}
void DMA::Initialize() {
HAL_CRC_Init(_hcrc);
HAL_UART_Receive_DMA(_huart, _dma_buffer, DMA_BUFFER_SIZE);
}
void DMA::RegisterCommand(uint8_t cmd, BKUCommand::Command* handler) {
if (_handler_count < MAX_COMMANDS) {
_handlers[_handler_count].cmd = cmd;
_handlers[_handler_count].handler = handler;
_handler_count++;
}
}
void DMA::SendCommand(uint8_t cmd, uint16_t data) {
if (__HAL_UART_GET_FLAG(_huart, UART_FLAG_BUSY)) {
return; // Ждем завершения предыдущей передачи
}
_is_sending = true;
uint8_t frame[FRAME_SIZE] = {
START_BYTE,
BKU_ADDRESS,
cmd,
static_cast<uint8_t>(data >> 8),
static_cast<uint8_t>(data & 0xFF)
};
uint16_t crc = calculateCRC(frame);
frame[5] = crc >> 8;
frame[6] = crc & 0xFF;
BKUCommand::Command* handler = findHandler(cmd);
if (handler != nullptr) {
handler->SetRequestTime(HAL_GetTick());
}
HAL_Delay(30);
HAL_UART_Transmit_DMA(_huart, frame, FRAME_SIZE);
}
BKUCommand::Command* DMA::findHandler(uint8_t cmd) {
for (uint8_t i = 0; i < _handler_count; i++) {
if (_handlers[i].cmd == cmd) {
return _handlers[i].handler;
}
}
return nullptr;
}
void DMA::HandleTxComplete() {
_is_sending = false;
}
void DMA::HandleRxComplete() {}
void DMA::HandleError() {
_is_sending = false;
_dma_pos = 0;
HAL_UART_DMAStop(_huart);
HAL_UART_Receive_DMA(_huart, _dma_buffer, DMA_BUFFER_SIZE);
__HAL_UART_CLEAR_FLAG(_huart, UART_FLAG_ORE | UART_FLAG_NE | UART_FLAG_FE);
}
void DMA::HandleBuffer() {
uint32_t current_pos = DMA_BUFFER_SIZE - __HAL_DMA_GET_COUNTER(_huart->hdmarx);
uint32_t bytes_to_process = (current_pos - _dma_pos) % DMA_BUFFER_SIZE;
if (bytes_to_process < FRAME_SIZE) {
return;
}
// Защита от переполнения буфера
if ((current_pos - _dma_pos) % DMA_BUFFER_SIZE > DMA_BUFFER_SIZE/2) {
_dma_pos = current_pos;
return;
}
while (_dma_pos != current_pos) {
// Если найден стартовый байт и достаточно данных для проверки
if (_dma_buffer[_dma_pos] == START_BYTE) {
uint8_t frame[FRAME_SIZE];
bool frame_complete = true;
// Проверяем, есть ли полный фрейм в буфере
for (int i = 0; i < FRAME_SIZE; i++) {
uint32_t pos = (_dma_pos + i) % DMA_BUFFER_SIZE;
if (pos == current_pos) { // Достигли текущей позиции DMA
frame_complete = false;
break;
}
frame[i] = _dma_buffer[pos];
}
if (validateFrame(frame)) {
processFrame(frame);
_dma_pos = (_dma_pos + FRAME_SIZE) % DMA_BUFFER_SIZE;
continue; // Пропускаем инкремент позиции
} else {
// Невалидный фрейм - пропускаем только стартовый байт
_dma_pos = (_dma_pos + 1) % DMA_BUFFER_SIZE;
continue;
}
}
// Переходим к следующему байту
_dma_pos = (_dma_pos + 1) % DMA_BUFFER_SIZE;
}
}
void DMA::processFrame(const uint8_t* frame) {
uint8_t cmd = frame[2];
uint16_t data = (frame[3] << 8) | frame[4];
BKUCommand::Command* handler = findHandler(cmd);
if (handler != nullptr) {
handler->ProcessPayload(data);
}
}
bool DMA::validateFrame(const uint8_t* frame) const {
if (frame[0] != START_BYTE) {
return false;
}
if (frame[1] != ADDRESS) {
return false;
}
uint16_t received_crc = (frame[5] << 8) | frame[6]; // Байты CRC в фрейме
uint16_t calculated_crc = calculateCRC(frame);
return true;
}
uint16_t DMA::calculateCRC(const uint8_t* data) const {
// Temporary buffer for alignment
uint32_t aligned_data[2] = {0};
memcpy(aligned_data, data, 5);
// Hardware CRC calculation
uint32_t crc = HAL_CRC_Calculate(_hcrc, aligned_data, 1); // 4 bytes = 1 word
return ~crc & 0xFFFF; // Inversion for CRC-16 standard compliance
}
}