Files
templates/c/protocan-transport/ports/stm32f4/pcan_uart_stm32f4.h
Andrey Kruchinkin 3dc636e012 feat(protocan-transport): транспортный уровень ProtoCAN и каталог GUI
Перенесён из репозитория protocan-transport, который подключался
сабмодулем в CAN_to_RS485.

Кадрирование AA 55 с CRC16 поверх любого байтового потока (RS485, RS232,
USB CDC), разбор 29-битного идентификатора, общее адресное пространство
регистров и каталог с подпиской на поток значений для SETGUI. Состояние
живёт в структурах вызывающего, поэтому в одной прошивке поднимается
сколько угодно независимых каналов. Порт STM32F4 (USART + DMA) в комплекте.

Хостовые тесты test_transport и test_gui проходят.
2026-08-23 01:15:35 +03:00

111 lines
4.6 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @file pcan_uart_stm32f4.h
* @brief Порт транспорта на USART + DMA для STM32F4.
*
* Передача - пакетная: DMA отдаёт непрерывный кусок очереди целиком,
* одно прерывание на пакет вместо одного на байт.
* Приём - кольцевой DMA, позиция вычисляется по NDTR, поэтому длина
* посылки заранее не нужна и байты не теряются между вызовами.
*
* Чего порт НЕ делает намеренно (это забота платы):
* - не включает такты RCC для USART, DMA и GPIO;
* - не настраивает выводы и альтернативные функции;
* - не разрешает прерывания в NVIC.
* Так один и тот же порт живёт на любой плате без правок.
*
* ВАЖНО про буферы: на STM32F407 DMA не имеет доступа к CCM RAM
* (0x10000000). Буферы обязаны лежать в основном SRAM (0x20000000),
* иначе передача молча не пойдёт.
*
* Прерывания, которые нужно прокинуть из вектора:
* DMAx_StreamN_IRQHandler -> pcan_uart_dma_tx_irq()
* USARTx_IRQHandler -> pcan_uart_irq()
*/
#ifndef PCAN_UART_STM32F4_H
#define PCAN_UART_STM32F4_H
#include "stm32f4xx.h"
#include "pcan_link.h"
#include "pcan_ring.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
USART_TypeDef *uart;
uint32_t pclk_hz; /**< частота шины этого USART */
uint32_t baud;
DMA_TypeDef *dma;
DMA_Stream_TypeDef *tx_stream;
uint8_t tx_stream_idx; /**< 0..7, нужен для флагов LISR/HISR */
uint8_t tx_channel; /**< 0..7 */
DMA_Stream_TypeDef *rx_stream;
uint8_t rx_stream_idx;
uint8_t rx_channel;
/** Управление драйвером RS485. NULL - обычный полнодуплексный UART. */
GPIO_TypeDef *de_port;
uint8_t de_pin;
uint8_t de_active_low; /**< 1, если DE активен низким уровнем */
} pcan_uart_cfg_t;
typedef struct {
pcan_uart_cfg_t cfg;
pcan_ring_t tx; /**< очередь передачи */
uint8_t *rx_buf; /**< кольцо приёма DMA */
uint16_t rx_size;
uint16_t rx_tail;
volatile uint16_t tx_chunk; /**< длина текущей DMA-посылки */
volatile uint8_t tx_busy;
uint32_t rx_overruns; /**< подозрение на потерю в кольце */
uint32_t uart_errors; /**< ORE / FE / NE / PE */
} pcan_uart_t;
/**
* @brief Настраивает USART и оба потока DMA.
* @param tx_buf,tx_size очередь передачи, размер - степень двойки;
* @param rx_buf,rx_size кольцо приёма, размер - степень двойки.
* @return false при неверных аргументах.
*/
bool pcan_uart_init(pcan_uart_t *u, const pcan_uart_cfg_t *cfg,
uint8_t *tx_buf, uint16_t tx_size,
uint8_t *rx_buf, uint16_t rx_size);
/** Заполняет интерфейс для pcan_link_init(). */
void pcan_uart_io(pcan_uart_t *u, pcan_io_t *io);
/**
* @brief Забирает принятые DMA байты в буфер вызывающего.
*
* Порт не знает, какой протокол поверх него живёт, поэтому отдаёт сырые
* байты: на одном и том же UART так работают и кадр полевой шины,
* и GUI-протокол.
*
* @return число скопированных байт; 0 - новых данных нет.
*/
size_t pcan_uart_read(pcan_uart_t *u, uint8_t *out, size_t max);
/**
* @brief Отдаёт принятые DMA байты в канал pcan_link. Из главного цикла.
* @return число разобранных кадров.
*/
size_t pcan_uart_poll(pcan_uart_t *u, pcan_link_t *link);
/** Обработчик прерывания потока DMA передачи. */
void pcan_uart_dma_tx_irq(pcan_uart_t *u);
/** Обработчик прерывания USART: снимает DE по флагу TC, считает ошибки. */
void pcan_uart_irq(pcan_uart_t *u);
#ifdef __cplusplus
}
#endif
#endif /* PCAN_UART_STM32F4_H */