Mercurial > public > ostc4
view Small_CPU/Src/uart_Internal.c @ 923:6fc0e3d230e4 Evo_2_23 tip
UART6 DMA handling:
Make sure that RX transmission uses DMA stream 2
author | Ideenmodellierer |
---|---|
date | Mon, 04 Nov 2024 20:21:02 +0100 |
parents | 7c996354b8ac |
children |
line wrap: on
line source
/** ****************************************************************************** * @file uart_Internal.c * @author heinrichs weikamp gmbh * @version V0.0.1 * @date 03-November-2044 * @brief Control functions for devices connected to the internal UART * @verbatim ============================================================================== ##### How to use ##### ============================================================================== @endverbatim ****************************************************************************** * @attention * * <h2><center>© COPYRIGHT(c) 2015 heinrichs weikamp</center></h2> * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "uart.h" #include "uart_Internal.h" #include "uartProtocol_GNSS.h" #include "GNSS.h" #include "externalInterface.h" #include "data_exchange.h" #include <string.h> /* memset */ static uint8_t isEndIndication6(uint8_t index); static uint8_t gnssState = UART_GNSS_INIT; /* Private variables ---------------------------------------------------------*/ #define TX_BUF_SIZE (40u) /* max length for commands */ #define CHUNK_SIZE (25u) /* the DMA will handle chunk size transfers */ #define CHUNKS_PER_BUFFER (6u) #define REQUEST_INT_SENSOR_MS (1500) /* Minimum time interval for cyclic sensor data requests per sensor (UART mux) */ #define COMMAND_TX_DELAY (30u) /* The time the sensor needs to recover from a invalid command request */ #define TIMEOUT_SENSOR_ANSWER (300) /* Time till a request is repeated if no answer was received */ static receiveStateGnss_t rxState = GNSSRX_READY; static uint8_t GnssConnected = 0; /* Binary indicator if a sensor is connected or not */ static uint8_t writeIndex = 0; static uint8_t dataToRead = 0; DMA_HandleTypeDef hdma_usart6_rx, hdma_usart6_tx; uint8_t tx6Buffer[CHUNK_SIZE]; /* tx uses less bytes */ uint8_t tx6BufferQue[TX_BUF_SIZE]; /* In MUX mode command may be send shortly after each other => allow q 1 entry que */ uint8_t tx6BufferQueLen; uint8_t rxBufferUart6[CHUNK_SIZE * CHUNKS_PER_BUFFER]; /* The complete buffer has a X * chunk size to allow variations in buffer read time */ uint8_t txBufferUart6[CHUNK_SIZE * CHUNKS_PER_BUFFER]; /* The complete buffer has a X * chunk size to allow variations in buffer read time */ static uint8_t rx6WriteIndex; /* Index of the data item which is analysed */ static uint8_t rx6ReadIndex; /* Index at which new data is stared */ static uint8_t dmaRx6Active; /* Indicator if DMA reception needs to be started */ static uint8_t dmaTx6Active; /* Indicator if DMA reception needs to be started */ /* Exported functions --------------------------------------------------------*/ void UART_clearRx6Buffer(void) { uint16_t index = 0; do { rxBufferUart6[index++] = BUFFER_NODATA_LOW; rxBufferUart6[index++] = BUFFER_NODATA_HIGH; } while (index < sizeof(rxBufferUart6)); rx6ReadIndex = 0; rx6WriteIndex = 0; } void GNSS_IO_init() { GPIO_InitTypeDef GPIO_InitStruct = { 0 }; /* Peripheral clock enable */ __HAL_RCC_USART6_CLK_ENABLE() ; __HAL_RCC_GPIOA_CLK_ENABLE() ; /**USART6 GPIO Configuration PA11 ------> USART6_TX PA12 ------> USART6_RX */ GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FAST; GPIO_InitStruct.Alternate = GPIO_AF8_USART6; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* USART6 DMA Init */ /* USART6_RX Init */ hdma_usart6_rx.Instance = DMA2_Stream2; hdma_usart6_rx.Init.Channel = DMA_CHANNEL_5; hdma_usart6_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_usart6_rx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_usart6_rx.Init.MemInc = DMA_MINC_ENABLE; hdma_usart6_rx.Init.PeriphDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart6_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart6_rx.Init.Mode = DMA_NORMAL; hdma_usart6_rx.Init.Priority = DMA_PRIORITY_LOW; hdma_usart6_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; HAL_DMA_Init(&hdma_usart6_rx); __HAL_LINKDMA(&huart6, hdmarx, hdma_usart6_rx); /* USART6_TX Init */ hdma_usart6_tx.Instance = DMA2_Stream6; hdma_usart6_tx.Init.Channel = DMA_CHANNEL_5; hdma_usart6_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma_usart6_tx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_usart6_tx.Init.MemInc = DMA_MINC_ENABLE; hdma_usart6_tx.Init.PeriphDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart6_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart6_tx.Init.Mode = DMA_NORMAL; hdma_usart6_tx.Init.Priority = DMA_PRIORITY_LOW; hdma_usart6_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; HAL_DMA_Init(&hdma_usart6_tx); __HAL_LINKDMA(&huart6, hdmatx, hdma_usart6_tx); /* USART6 interrupt Init */ HAL_NVIC_SetPriority(USART6_IRQn, 0, 0); HAL_NVIC_EnableIRQ(USART6_IRQn); MX_USART6_DMA_Init(); } void MX_USART6_DMA_Init() { /* DMA controller clock enable */ __HAL_RCC_DMA2_CLK_ENABLE(); /* DMA interrupt init */ /* DMA2_Stream2_IRQn interrupt configuration */ HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn); /* DMA2_Stream6_IRQn interrupt configuration */ HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn); } void MX_USART6_UART_DeInit(void) { HAL_DMA_Abort(&hdma_usart6_rx); HAL_DMA_DeInit(&hdma_usart6_rx); HAL_DMA_Abort(&hdma_usart6_tx); HAL_DMA_DeInit(&hdma_usart6_tx); HAL_UART_DeInit(&huart6); HAL_UART_DeInit(&huart6); } void MX_USART6_UART_Init(void) { huart6.Instance = USART6; huart6.Init.BaudRate = 9600; huart6.Init.WordLength = UART_WORDLENGTH_8B; huart6.Init.StopBits = UART_STOPBITS_1; huart6.Init.Parity = UART_PARITY_NONE; huart6.Init.Mode = UART_MODE_TX_RX; huart6.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart6.Init.OverSampling = UART_OVERSAMPLING_16; HAL_UART_Init(&huart6); UART_clearRx6Buffer(); dmaRx6Active = 0; dmaTx6Active = 0; tx6BufferQueLen = 0; } void UART6_SendCmdUbx(const uint8_t *cmd, uint8_t len) { if(len < TX_BUF_SIZE) /* A longer string is an indication for a missing 0 termination */ { if(dmaRx6Active == 0) { UART_StartDMA_Receiption(); } memcpy(tx6Buffer, cmd, len); if(HAL_OK == HAL_UART_Transmit_DMA(&huart6,tx6Buffer,len)) { dmaTx6Active = 1; } } } uint8_t isEndIndication6(uint8_t index) { uint8_t ret = 0; if(index % 2) { if(rxBufferUart6[index] == BUFFER_NODATA_HIGH) { ret = 1; } } else { if(rxBufferUart6[index] == BUFFER_NODATA_LOW) { ret = 1; } } return ret; } void UART6_StartDMA_Receiption() { if(dmaRx6Active == 0) { if(((rx6WriteIndex / CHUNK_SIZE) != (rx6ReadIndex / CHUNK_SIZE)) || ((isEndIndication6(rx6WriteIndex)) && (isEndIndication6(rx6WriteIndex + 1)))) /* start next transfer if we did not catch up with read index */ { if(HAL_OK == HAL_UART_Receive_DMA (&huart6, &rxBufferUart6[rx6WriteIndex], CHUNK_SIZE)) { dmaRx6Active = 1; } } } } void UART6_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart == &huart6) { dmaRx6Active = 0; rx6WriteIndex+=CHUNK_SIZE; if(rx6WriteIndex >= CHUNK_SIZE * CHUNKS_PER_BUFFER) { rx6WriteIndex = 0; } UART6_StartDMA_Receiption(); } } void UART6_TxCpltCallback(UART_HandleTypeDef *huart) { if(huart == &huart6) { dmaTx6Active = 0; UART6_WriteData(); if(tx6BufferQueLen) { memcpy(tx6Buffer, tx6BufferQue, tx6BufferQueLen); HAL_UART_Transmit_DMA(&huart6,tx6Buffer,tx6BufferQueLen); dmaTx6Active = 1; tx6BufferQueLen = 0; } } } void UART6_ReadData() { uint8_t localRX = rx6ReadIndex; uint8_t futureIndex = rx6ReadIndex + 1; uint8_t moreData = 0; if(futureIndex >= CHUNK_SIZE * CHUNKS_PER_BUFFER) { futureIndex = 0; } if((!isEndIndication6(localRX)) || (!isEndIndication6(futureIndex))) do { while((!isEndIndication6(localRX)) || (moreData)) { moreData = 0; UART6_Gnss_ProcessData(rxBufferUart6[localRX]); if(localRX % 2) { rxBufferUart6[localRX] = BUFFER_NODATA_HIGH; } else { rxBufferUart6[localRX] = BUFFER_NODATA_LOW; } localRX++; rx6ReadIndex++; if(rx6ReadIndex >= CHUNK_SIZE * CHUNKS_PER_BUFFER) { localRX = 0; rx6ReadIndex = 0; } futureIndex++; if(futureIndex >= CHUNK_SIZE * CHUNKS_PER_BUFFER) { futureIndex = 0; } } if(!isEndIndication6(futureIndex)) { moreData = 1; } } while(moreData); } void UART6_WriteData(void) { if(huart6.hdmatx->State == HAL_DMA_STATE_READY) { huart6.gState = HAL_UART_STATE_READY; dmaTx6Active = 0; } if(huart6.hdmarx->State == HAL_DMA_STATE_READY) { huart6.RxState = HAL_UART_STATE_READY; dmaRx6Active = 0; } } void UART6_Gnss_SendCmd(uint8_t GnssCmd) { const uint8_t* pData; uint8_t txLength = 0; switch (GnssCmd) { case GNSSCMD_LOADCONF_0: pData = configUBX; txLength = sizeof(configUBX) / sizeof(uint8_t); break; case GNSSCMD_LOADCONF_1: pData = setNMEA410; txLength = sizeof(setNMEA410) / sizeof(uint8_t); break; case GNSSCMD_LOADCONF_2: pData = setGNSS; txLength = sizeof(setGNSS) / sizeof(uint8_t); break; case GNSSCMD_GET_PVT_DATA: pData = getPVTData; txLength = sizeof(getPVTData) / sizeof(uint8_t); break; case GNSSCMD_GET_NAV_DATA: pData = getNavigatorData; txLength = sizeof(getNavigatorData) / sizeof(uint8_t); break; default: break; } if(txLength != 0) { UART6_SendCmdUbx(pData, txLength); } } void UART6_Gnss_Control(void) { static uint32_t warmupTick = 0; switch (gnssState) { case UART_GNSS_INIT: gnssState = UART_GNSS_WARMUP; warmupTick = HAL_GetTick(); UART_clearRxBuffer(); break; case UART_GNSS_WARMUP: if(time_elapsed_ms(warmupTick,HAL_GetTick()) > 1000) { gnssState = UART_GNSS_LOADCONF_0; } break; case UART_GNSS_LOADCONF_0: UART6_Gnss_SendCmd(GNSSCMD_LOADCONF_0); gnssState = UART_GNSS_LOADCONF_1; rxState = GNSSRX_DETECT_ACK_0; break; case UART_GNSS_LOADCONF_1: UART6_Gnss_SendCmd(GNSSCMD_LOADCONF_1); gnssState = UART_GNSS_LOADCONF_2; rxState = GNSSRX_DETECT_ACK_0; break; case UART_GNSS_LOADCONF_2: UART6_Gnss_SendCmd(GNSSCMD_LOADCONF_2); gnssState = UART_GNSS_IDLE; rxState = GNSSRX_DETECT_ACK_0; break; case UART_GNSS_IDLE: UART6_Gnss_SendCmd(GNSSCMD_GET_PVT_DATA); gnssState = UART_GNSS_GET_PVT; rxState = GNSSRX_DETECT_HEADER_0; break; default: break; } } void UART6_Gnss_ProcessData(uint8_t data) { GNSS_Handle.uartWorkingBuffer[writeIndex++] = data; switch(rxState) { case GNSSRX_DETECT_ACK_0: case GNSSRX_DETECT_HEADER_0: if(data == 0xB5) { writeIndex = 0; memset(GNSS_Handle.uartWorkingBuffer,0, sizeof(GNSS_Handle.uartWorkingBuffer)); GNSS_Handle.uartWorkingBuffer[writeIndex++] = data; rxState++; } break; case GNSSRX_DETECT_ACK_1: case GNSSRX_DETECT_HEADER_1: if(data == 0x62) { rxState++; } else { rxState = GNSSRX_DETECT_HEADER_0; } break; case GNSSRX_DETECT_ACK_2: if(data == 0x05) { rxState++; } else { rxState = GNSSRX_DETECT_HEADER_0; } break; case GNSSRX_DETECT_ACK_3: if((data == 0x01) || (data == 0x00)) { GnssConnected = 1; rxState = GNSSRX_READY; } else { rxState = GNSSRX_DETECT_HEADER_0; } break; case GNSSRX_DETECT_HEADER_2: if(data == 0x01) { rxState++; } else { rxState = GNSSRX_DETECT_HEADER_0; } break; case GNSSRX_DETECT_HEADER_3: switch(data) { case 0x21: rxState = GNSSRX_READ_NAV_DATA; dataToRead = 20; break; case 0x07: rxState = GNSSRX_READ_PVT_DATA; dataToRead = 92; break; case 0x02: rxState = GNSSRX_READ_POSLLH_DATA; break; default: rxState = GNSSRX_DETECT_HEADER_0; break; } break; case GNSSRX_READ_NAV_DATA: case GNSSRX_READ_PVT_DATA: case GNSSRX_READ_POSLLH_DATA: if(dataToRead > 0) { dataToRead--; } else { switch(rxState) { case GNSSRX_READ_NAV_DATA: GNSS_ParseNavigatorData(&GNSS_Handle); break; case GNSSRX_READ_PVT_DATA: GNSS_ParsePVTData(&GNSS_Handle); break; case GNSSRX_READ_POSLLH_DATA: GNSS_ParsePOSLLHData(&GNSS_Handle); break; default: rxState = GNSSRX_DETECT_HEADER_0; break; } rxState = GNSSRX_DETECT_HEADER_0; gnssState = UART_GNSS_IDLE; } break; default: rxState = GNSSRX_READY; break; } } void UART6_HandleUART() { static uint8_t retryRequest = 0; static uint32_t lastRequestTick = 0; static uint32_t TriggerTick = 0; static uint8_t timeToTrigger = 0; uint32_t tick = HAL_GetTick(); if(gnssState != UART_GNSS_INIT) { UART6_ReadData(); UART6_WriteData(); } if(gnssState == UART_GNSS_INIT) { lastRequestTick = tick; TriggerTick = tick - 10; /* just to make sure control is triggered */ timeToTrigger = 1; retryRequest = 0; } else if(((retryRequest == 0) /* timeout or error */ && (((time_elapsed_ms(lastRequestTick,tick) > (TIMEOUT_SENSOR_ANSWER)) && (gnssState != UART_GNSS_IDLE)) /* retry if no answer after half request interval */ || (gnssState == UART_GNSS_ERROR)))) { /* The channel switch will cause the sensor to respond with an error message. */ /* The sensor needs ~30ms to recover before he is ready to receive the next command => transmission delay needed */ TriggerTick = tick; timeToTrigger = COMMAND_TX_DELAY; retryRequest = 1; } else if(time_elapsed_ms(lastRequestTick,tick) > 1000) /* switch sensor and / or trigger next request */ { lastRequestTick = tick; TriggerTick = tick; retryRequest = 0; timeToTrigger = 1; if((gnssState == UART_GNSS_GET_PVT)) /* timeout */ { gnssState = UART_GNSS_IDLE; } timeToTrigger = 1; } if((timeToTrigger != 0) && (time_elapsed_ms(TriggerTick,tick) > timeToTrigger)) { timeToTrigger = 0; UART6_Gnss_Control(); } } /************************ (C) COPYRIGHT heinrichs weikamp *****END OF FILE****/