Перенесён из репозитория protocan-transport, который подключался сабмодулем в CAN_to_RS485. Кадрирование AA 55 с CRC16 поверх любого байтового потока (RS485, RS232, USB CDC), разбор 29-битного идентификатора, общее адресное пространство регистров и каталог с подпиской на поток значений для SETGUI. Состояние живёт в структурах вызывающего, поэтому в одной прошивке поднимается сколько угодно независимых каналов. Порт STM32F4 (USART + DMA) в комплекте. Хостовые тесты test_transport и test_gui проходят.
111 lines
4.6 KiB
C
111 lines
4.6 KiB
C
/**
|
||
* @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 */
|