Например TDA7294

Форум РадиоКот • Просмотр темы - STM32 + DMA + RS485, буфер считывает эхо
Форум РадиоКот
Здесь можно немножко помяукать :)

Текущее время: Чт авг 14, 2025 13:49:36

Часовой пояс: UTC + 3 часа


ПРЯМО СЕЙЧАС:



Начать новую тему Ответить на тему  [ Сообщений: 3 ] 
Автор Сообщение
Не в сети
 Заголовок сообщения: STM32 + DMA + RS485, буфер считывает эхо
СообщениеДобавлено: Вт июл 22, 2025 22:34:36 
Родился

Зарегистрирован: Вт июл 22, 2025 22:26:09
Сообщений: 1
Рейтинг сообщения: 0
Всем привет! В программировании МК новичок, пытаюсь заставить работать 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
    }

}



Вернуться наверх
 
В сети
 Заголовок сообщения: Re: STM32 + DMA + RS485, буфер считывает эхо
СообщениеДобавлено: Ср июл 23, 2025 09:28:19 
Грызет канифоль
Аватар пользователя

Карма: 7
Рейтинг сообщений: 69
Зарегистрирован: Ср сен 02, 2015 07:47:20
Сообщений: 285
Рейтинг сообщения: 0
Проблема в том, что в буффер попадает отправленная команда, связывал с тем, что не успевает опуститься DE пин и МК считывает свою же команду с линии, победить смог только добавив адресный байт и фильтруя по нему.

Если не нужно эхо, то приёмник надо отключать до первого байта отправки. С другой стороны, эхо у полудуплексных линий используется для контроля отсутствия коллизий в "эфире".

_________________
Репозиторий STM32: https://cloud.mail.ru/public/2i19/Y4w8kKEiZ
Актуальность репозитория: 1 июля 2025 года
Если чего-то не хватает с сайта st.com - пишите, докачаю.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: STM32 + DMA + RS485, буфер считывает эхо
СообщениеДобавлено: Ср июл 23, 2025 11:25:08 
Сверлит текстолит когтями

Зарегистрирован: Вт ноя 19, 2019 06:10:18
Сообщений: 1228
Рейтинг сообщения: 0
radiokayro13 писал(а):
Подозреваю, что проблемы именно в коде

Зачем аппаратный CRC, когда используете программный? Оставьте его для USB и Ethernet, в которых он реально нужен.
Где управление трансивером? Или он у вас с автодектом? Или UART им управляет?
Приём через DMA не_требует защиты от переполнения. Нужен только один дополнительный байт для проверки правильной длины посылки.

Странно у вас там всё. Вам нужно обработать два прерывания: первое от DMA по окончании отправки всего блока, которое разрешит прерывание от UART, и второе от UART, когда в линию уйдёт последний байт посылки. Прерывании от UART означает, что посылка ушла в линию и можно сигнализировать об окончании передачи и переключать трансивер на приём.

Добавлено after 32 minutes 32 seconds:
Настройку UART не вижу.


Вернуться наверх
 
Показать сообщения за:  Сортировать по:  Вернуться наверх
Начать новую тему Ответить на тему  [ Сообщений: 3 ] 

Часовой пояс: UTC + 3 часа


Кто сейчас на форуме

Сейчас этот форум просматривают: vit-kbk и гости: 26


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Русская поддержка phpBB
Extended by Karma MOD © 2007—2012 m157y
Extended by Topic Tags MOD © 2012 m157y