This commit is contained in:
cfif 2024-12-04 13:10:48 +03:00
commit a2e2ae6878
3 changed files with 492 additions and 0 deletions

89
Inc/SerialPortNation.h Normal file
View File

@ -0,0 +1,89 @@
//
// Created by xemon on 29.08.22.
//
#ifndef SERIALPORT_SERIALPORT_NIIET_H
#define SERIALPORT_SERIALPORT_NIIET_H
#include "SerialPortIO.h"
#include "cmsis_os2.h"
#include "n32g45x.h"
#define UART_DMA_SEND
typedef struct {
USART_Module *uart;
DMA_Module *DMA_RX;
DMA_Module *DMA_TX;
DMA_ChannelType *Rx_DMA_Channel;
DMA_ChannelType *Tx_DMA_Channel;
uint32_t DMA_INT_RX;
uint32_t DMA_INT_TX;
osMessageQueueId_t rxDataQueue;
osMessageQueueId_t rxDataSnifferQueue;
osMessageQueueId_t txAccessQueue;
// dma_channel_type *txDmaChannel;
uint8_t *rxDmaBuf;
uint32_t rxDmaOffset;
DMA_InitType dma_rx_init_struct;
DMA_InitType dma_tx_init_struct;
} tSerialPortNation;
void vSerialPortInit(
tSerialPortNation *env,
USART_Module *USARTx,
uint32_t BoundRate,
IRQn_Type irqChanel,
uint8_t irqPriority,
uint32_t rxBufferLength,
uint32_t rxSnifferLength
);
void vSerialPortInitDMA(
tSerialPortNation *env,
USART_Module *USARTx,
DMA_Module *DMA_RX,
DMA_ChannelType *Rx_DMA_Channel,
IRQn_Type RX_DMA_Channel_IRQ,
uint32_t DMA_INT_RX,
DMA_Module *DMA_TX,
DMA_ChannelType *Tx_DMA_Channel,
IRQn_Type TX_DMA_Channel_IRQ,
uint32_t DMA_INT_TX,
uint8_t *DMA_BUF,
uint16_t DMA_BUF_LEN,
uint32_t BoundRate,
IRQn_Type irqChanel,
uint8_t irqPriority,
uint32_t rxBufferLength,
uint32_t rxSnifferLength
);
#define SerialPort_InitName(ENV, NAME, BOUND_RATE, PRIORITY, LEN) \
vSerialPortInit(ENV, NAME, BOUND_RATE, NAME##_IRQn, PRIORITY, LEN,0)
#define vSerialPortInitNameWithSniffer(ENV, NAME, BOUND_RATE, PRIORITY, LEN, SNIFFER_LEN) \
vSerialPortInit(ENV, NAME, BOUND_RATE, NAME##_IRQn, PRIORITY, LEN,SNIFFER_LEN)
tSerialPortIO SerialPort_GetIo(tSerialPortNation *env);
void SerialPort_IrqProcessing_DmaRxLoop(tSerialPortNation *env);
tSerialPortIO SerialPort_GetSnifferIo(tSerialPortNation *env);
void vSerialPortIrqProcessing(tSerialPortNation *env);
void SerialPort_IrqProcessing_UartIdle(tSerialPortNation *env);
void SerialPort_IrqProcessing_DmaTx(tSerialPortNation *env);
uint16_t vSerialPortTransmit(tSerialPortNation *env, uint8_t *data, uint16_t size, uint32_t timeout);
#endif //SERIALPORT_SERIALPORT_NIIET_H

371
Src/SerialPortNation.c Normal file
View File

@ -0,0 +1,371 @@
//
// Created by xemon on 29.08.22.
//
#include <SystemDelayInterface.h>
#include "SerialPortNation.h"
#include "n32g45x_usart.h"
void pub() {
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
}
static void vSerialPortInitNVICEnable(IRQn_Type UARTx_IRQn_Chanel, uint8_t irqSubPriority) {
NVIC_InitType NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = UARTx_IRQn_Chanel;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = irqSubPriority;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
static void vSerialPortInitUSART(USART_Module *USARTx, uint32_t BoundRate) {
USART_InitType USART_InitStructure;
USART_InitStructure.BaudRate = BoundRate;
USART_InitStructure.WordLength = USART_WL_8B;
USART_InitStructure.StopBits = USART_STPB_1;
USART_InitStructure.Parity = USART_PE_NO;
USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE;
USART_InitStructure.Mode = USART_MODE_RX | USART_MODE_TX;
USART_Init(USARTx, &USART_InitStructure);
}
static void vSerialPortInitStructure(
tSerialPortNation *env,
USART_Module *USARTx,
uint32_t rxBufferLength,
uint32_t rxSnifferLength
) {
env->rxDataQueue = osMessageQueueNew(rxBufferLength, 1, NULL);
if (rxSnifferLength) {
env->rxDataSnifferQueue = osMessageQueueNew(rxSnifferLength, 1, NULL);
} else {
env->rxDataSnifferQueue = 0;
}
env->uart = USARTx;
}
void vSerialPortInit(
tSerialPortNation *env,
USART_Module *USARTx,
uint32_t BoundRate,
IRQn_Type irqChanel,
uint8_t irqSubPriority,
uint32_t rxBufferLength,
uint32_t rxSnifferLength
) {
//Перед инициализацией UART и включением прерывания необходимо инициализировать саму структуру SerialUartNation,
//так как сразу после активации прерывания (в случае наличия входящих данных) может сработать обработчик этого
// прерывания и вслучае отсуствия валидных указателей в структуре произайдет HardFault
vSerialPortInitStructure(env, USARTx, rxBufferLength, rxSnifferLength);
vSerialPortInitUSART(USARTx, BoundRate);
USART_ConfigInt(USARTx, USART_INT_RXDNE, ENABLE);
vSerialPortInitNVICEnable(irqChanel, irqSubPriority);
NVIC_SetPriority(irqChanel, irqSubPriority);
USART_Enable(USARTx, ENABLE);
}
void SerialPort_RxDmaBufToQueue(tSerialPortNation *env, uint32_t bufEnd) {
for (uint32_t i = env->rxDmaOffset; i < bufEnd; ++i) {
osMessageQueuePut(env->rxDataQueue, &env->rxDmaBuf[i], 0x0, 0U);
if (env->rxDataSnifferQueue) {
osMessageQueuePut(env->rxDataSnifferQueue, &env->rxDmaBuf[i], 0x0, 0U);
}
}
}
void SerialPort_IrqProcessing_DmaRxLoop(tSerialPortNation *env) {
if (DMA_GetIntStatus(env->DMA_INT_RX, env->DMA_RX) != RESET) {
SerialPort_RxDmaBufToQueue(env, env->dma_rx_init_struct.BufSize);
env->rxDmaOffset = 0;
DMA_ConfigInt(env->Rx_DMA_Channel, DMA_INT_TXC, DISABLE);
DMA_ClrIntPendingBit(env->DMA_INT_RX, env->DMA_RX);
}
}
void SerialPort_IrqProcessing_UartIdle(tSerialPortNation *env) {
// Смотрим idle прерывание
if (USART_GetFlagStatus(env->uart, USART_FLAG_IDLEF)) {
// Сброс прерывания
USART_ReceiveData(env->uart);
USART_ClrFlag(env->uart, USART_FLAG_IDLEF);
size_t bufEnd = env->dma_rx_init_struct.BufSize - env->Rx_DMA_Channel->TXNUM;
SerialPort_RxDmaBufToQueue(env, bufEnd);
env->rxDmaOffset = bufEnd;
}
}
static const uint8_t DUMMY_BYTE = 0xFF;
void SerialPort_IrqProcessing_DmaTx(tSerialPortNation *env) {
if (DMA_GetIntStatus(env->DMA_INT_TX, env->DMA_TX)) {
osMessageQueuePut(env->txAccessQueue, &DUMMY_BYTE, 0, 0);
DMA_ClrIntPendingBit(env->DMA_INT_TX, env->DMA_TX);
}
}
void vSerialPortInitDMA(
tSerialPortNation *env,
USART_Module *USARTx,
DMA_Module *DMA_RX,
DMA_ChannelType *Rx_DMA_Channel,
IRQn_Type RX_DMA_Channel_IRQ,
uint32_t DMA_INT_RX,
DMA_Module *DMA_TX,
DMA_ChannelType *Tx_DMA_Channel,
IRQn_Type TX_DMA_Channel_IRQ,
uint32_t DMA_INT_TX,
uint8_t *DMA_BUF,
uint16_t DMA_BUF_LEN,
uint32_t BoundRate,
IRQn_Type irqChanel,
uint8_t irqPriority,
uint32_t rxBufferLength,
uint32_t rxSnifferLength
) {
// включаем тактирование uart и нужных DMA
if (DMA_RX == DMA1 || DMA_TX == DMA1) {
RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA1, ENABLE);
}
if (DMA_RX == DMA2 || DMA_TX == DMA2) {
RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA2, ENABLE);
}
// заполняем параметры и создаем все очереди до начала работы порта (иначе при раннем сробатывании прервывания все упадет)
env->txAccessQueue = osMessageQueueNew(1, 1, NULL);
env->rxDataQueue = osMessageQueueNew(rxBufferLength, 1, NULL);
if (rxSnifferLength) {
env->rxDataSnifferQueue = osMessageQueueNew(rxSnifferLength, 1, NULL);
} else {
env->rxDataSnifferQueue = 0;
}
env->rxDmaBuf = DMA_BUF;
env->rxDmaOffset = 0;
// инициализируем uart
env->uart = USARTx;
env->DMA_RX = DMA_RX;
env->DMA_TX = DMA_TX;
env->Rx_DMA_Channel = Rx_DMA_Channel;
env->Tx_DMA_Channel = Tx_DMA_Channel;
env->DMA_INT_RX = DMA_INT_RX;
env->DMA_INT_TX = DMA_INT_TX;
vSerialPortInitUSART(USARTx, BoundRate);
// инициализируем RX DMA в циклическом режиме
DMA_DeInit(Rx_DMA_Channel);
if (env->uart == USART1)
env->dma_rx_init_struct.PeriphAddr = USART1_BASE + 0x04;
if (env->uart == USART2)
env->dma_rx_init_struct.PeriphAddr = USART2_BASE + 0x04;
if (env->uart == UART4)
env->dma_rx_init_struct.PeriphAddr = UART4_BASE + 0x04;
env->dma_rx_init_struct.MemAddr = (uint32_t) DMA_BUF;
env->dma_rx_init_struct.Direction = DMA_DIR_PERIPH_SRC;
env->dma_rx_init_struct.BufSize = DMA_BUF_LEN;
env->dma_rx_init_struct.PeriphInc = DMA_PERIPH_INC_DISABLE;
env->dma_rx_init_struct.DMA_MemoryInc = DMA_MEM_INC_ENABLE;
env->dma_rx_init_struct.PeriphDataSize = DMA_PERIPH_DATA_SIZE_BYTE;
env->dma_rx_init_struct.MemDataSize = DMA_MemoryDataSize_Byte;
env->dma_rx_init_struct.CircularMode = DMA_MODE_CIRCULAR;
env->dma_rx_init_struct.Priority = DMA_PRIORITY_VERY_HIGH;
env->dma_rx_init_struct.Mem2Mem = DMA_M2M_DISABLE;
DMA_Init(Rx_DMA_Channel, &env->dma_rx_init_struct);
// инициализируем TX DMA
DMA_DeInit(Tx_DMA_Channel);
if (env->uart == USART1)
env->dma_tx_init_struct.PeriphAddr = USART1_BASE + 0x04;
if (env->uart == USART2)
env->dma_tx_init_struct.PeriphAddr = USART2_BASE + 0x04;
if (env->uart == UART4)
env->dma_tx_init_struct.PeriphAddr = UART4_BASE + 0x04;
env->dma_tx_init_struct.MemAddr = 0;
env->dma_tx_init_struct.Direction = DMA_DIR_PERIPH_DST;
env->dma_tx_init_struct.BufSize = 0;
env->dma_tx_init_struct.PeriphInc = DMA_PERIPH_INC_DISABLE;
env->dma_tx_init_struct.DMA_MemoryInc = DMA_MEM_INC_ENABLE;
env->dma_tx_init_struct.PeriphDataSize = DMA_PERIPH_DATA_SIZE_BYTE;
env->dma_tx_init_struct.MemDataSize = DMA_MemoryDataSize_Byte;
env->dma_tx_init_struct.CircularMode = DMA_MODE_NORMAL;
env->dma_tx_init_struct.Priority = DMA_PRIORITY_VERY_HIGH;
env->dma_tx_init_struct.Mem2Mem = DMA_M2M_DISABLE;
DMA_Init(Tx_DMA_Channel, &env->dma_tx_init_struct);
USART_EnableDMA(USARTx, USART_DMAREQ_RX | USART_DMAREQ_TX, ENABLE);
// включаем прерывания uart
DMA_ConfigInt(env->Rx_DMA_Channel, DMA_INT_TXC, ENABLE);
vSerialPortInitNVICEnable(RX_DMA_Channel_IRQ, irqPriority);
NVIC_SetPriority(RX_DMA_Channel_IRQ, irqPriority);
DMA_EnableChannel(Rx_DMA_Channel, ENABLE);
// включаем tx dma и прерывания на нем
DMA_ConfigInt(env->Tx_DMA_Channel, DMA_INT_TXC, ENABLE);
vSerialPortInitNVICEnable(TX_DMA_Channel_IRQ, irqPriority);
NVIC_SetPriority(TX_DMA_Channel_IRQ, irqPriority);
DMA_EnableChannel(Tx_DMA_Channel, ENABLE);
// включаем uart и прерывания на нем
USART_ConfigInt(USARTx, USART_INT_IDLEF, ENABLE);
vSerialPortInitNVICEnable(irqChanel, irqPriority);
NVIC_SetPriority(irqChanel, irqPriority);
USART_Enable(USARTx, ENABLE);
}
/// bag
void vSerialPortIrqProcessing(tSerialPortNation *env) {
uint8_t data;
uint16_t stat = env->uart->STS;
FlagStatus res = USART_GetFlagStatus(env->uart, USART_FLAG_RXDNE);
if (res != RESET) {
while (USART_GetFlagStatus(env->uart, USART_FLAG_RXDNE) != RESET) {
stat = env->uart->STS;
data = USART_ReceiveData(env->uart);
osMessageQueuePut(env->rxDataQueue, &data, 0x0, 0U);
if (env->rxDataSnifferQueue) {
osMessageQueuePut(env->rxDataSnifferQueue, &data, 0x0, 0U);
}
}
SystemDelayMs(20);
} else {
USART_ClrFlag(env->uart, USART_FLAG_OREF);
SystemDelayMs(500);
return;
}
}
static uint16_t vSerialPortReceiveQueue(
tSerialPortNation *env, uint8_t *data, uint16_t size, uint32_t timeout, osMessageQueueId_t queueId
) {
uint16_t received = 0;
if (timeout) {
uint32_t endMs = SystemGetMs() + timeout;
uint32_t leftMs;
while (size && ((timeout == SystemWaitForever) || (endMs > SystemGetMs()))) {
leftMs = endMs - SystemGetMs();
if (osMessageQueueGet(queueId, data, NULL, leftMs) == osOK) {
--size;
++received;
++data;
}
}
} else {
while (size) {
if (osMessageQueueGet(queueId, data, NULL, 0) == osOK) {
--size;
++received;
++data;
} else {
return received;
}
}
}
return received;
}
static uint16_t vSerialPortReceive(tSerialPortNation *env, uint8_t *data, uint16_t size, uint32_t timeout) {
return vSerialPortReceiveQueue(env, data, size, timeout, env->rxDataQueue);
}
static uint16_t vSerialPortReceiveSniffer(tSerialPortNation *env, uint8_t *data, uint16_t size, uint32_t timeout) {
return env->rxDataSnifferQueue
? vSerialPortReceiveQueue(env, data, size, timeout, env->rxDataSnifferQueue)
: 0;
}
uint16_t vSerialPortTransmit(tSerialPortNation *env, uint8_t *data, uint16_t size, uint32_t timeout) {
uint16_t sent = 0;
uint32_t endMs = SystemGetMs() + timeout;
#ifndef UART_DMA_SEND
while (size && ((timeout == SystemWaitForever) || (endMs > SystemGetMs()))) {
while (USART_GetFlagStatus(env->uart, USART_FLAG_TXC) == RESET) {
if (!((timeout == SystemWaitForever) || (endMs > SystemGetMs()))) {
return sent;
}
}
USART_SendData(env->uart, *data);
--size;
++data;
++sent;
while (USART_GetFlagStatus(env->uart, USART_FLAG_TXC) == RESET) {
if (!((timeout == SystemWaitForever) || (endMs > SystemGetMs()))) {
return sent;
}
}
}
#endif
#ifdef UART_DMA_SEND
DMA_EnableChannel(env->Tx_DMA_Channel, DISABLE);
env->dma_tx_init_struct.BufSize = size;
env->dma_tx_init_struct.MemAddr = (uint32_t) data;
DMA_Init(env->Tx_DMA_Channel, &env->dma_tx_init_struct);
DMA_EnableChannel(env->Tx_DMA_Channel, ENABLE);
uint8_t res;
sent = (osMessageQueueGet(env->txAccessQueue, &res, 0, timeout) == osOK) ? size : 0;
DMA_EnableChannel(env->Tx_DMA_Channel, DISABLE);
while (USART_GetFlagStatus(env->uart, USART_FLAG_TXC) == RESET) {
if (!((timeout == SystemWaitForever) || (endMs > SystemGetMs()))) {
return sent;
}
}
#endif
return sent;
}
tSerialPortIO SerialPort_GetIo(tSerialPortNation *env) {
tSerialPortIO io = {
.env = env,
.receive = (SerialPortIOTransaction) vSerialPortReceive,
.transmit = (SerialPortIOTransaction) vSerialPortTransmit
};
return io;
}
tSerialPortIO SerialPort_GetSnifferIo(tSerialPortNation *env) {
tSerialPortIO io = {
.env = env,
.receive = (SerialPortIOTransaction) vSerialPortReceiveSniffer,
.transmit = (SerialPortIOTransaction) vSerialPortTransmit
};
return io;
}

32
modular.json Normal file
View File

@ -0,0 +1,32 @@
{
"dep": [
{
"type": "git",
"provider": "NAVIGATOR_UVEOS_NATION_TELIT",
"repo": "DeviceStartup_NATION_N32G45X"
},
{
"type": "git",
"provider": "NAVIGATOR_UVEOS_NATION_TELIT",
"repo": "PeripheralDriver_NATION_N32G45X"
},
{
"type": "git",
"provider": "NAVIGATOR_UVEOS_NATION_TELIT",
"repo": "SerialPort"
},
{
"type": "git",
"provider": "NAVIGATOR_UVEOS_NATION_TELIT",
"repo": "SystemDelayInterface"
}
],
"cmake": {
"inc_dirs": [
"Inc"
],
"srcs": [
"Src/**.c"
]
}
}