commit a2e2ae6878220ed9b5c164564f95f383d52653e3 Author: cfif Date: Wed Dec 4 13:10:48 2024 +0300 Init diff --git a/Inc/SerialPortNation.h b/Inc/SerialPortNation.h new file mode 100644 index 0000000..25ba48e --- /dev/null +++ b/Inc/SerialPortNation.h @@ -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 diff --git a/Src/SerialPortNation.c b/Src/SerialPortNation.c new file mode 100644 index 0000000..6d9ac93 --- /dev/null +++ b/Src/SerialPortNation.c @@ -0,0 +1,371 @@ +// +// Created by xemon on 29.08.22. +// +#include +#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; +} \ No newline at end of file diff --git a/modular.json b/modular.json new file mode 100644 index 0000000..b1feaea --- /dev/null +++ b/modular.json @@ -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" + ] + } +} \ No newline at end of file