how to sync a uart dma receive for gps parsing
Hi, I'm working with a stm32f722 and a ublox f9p gps. I just have 2 ubx messages. One with 36 bytes long and the other with 72 bytes. They income with a variable interval between them (a couple of byte time at most, usually they come together). This two messages are coming at a 5Hz data rate.
So I've tried several ways to parse them and for one reason or another I can make it work.
My goal is to parse the 2 messages as soon as they are available.
My first guess was to config a circular DMA between uart and memory. On Half complete CB ISR I take the first 54 bytes and pass trough ubx state machine parser. If the 72 bytes long msg is coming first the parser will not get any valid msg, but on Rx Complete CB the other 54 bytes will be send to SM and I will obtain the 2 messages. If the first msg is the 36 byte long, then I will get a valid msg on HC CB and the other on TC CB. That's will be ok.
The problem here is that I need to sync the DMA Rx call to the data stream. If I call DMA Rx in the middle of the stream I will process some bytes of current frame and some bytes of the next frame.
So, does anybody suggest a way to make that synchronization? I've think on a timer that interrupt at 20 msec. At the beginning each byte received will reset the timer counter. On the timer ISR I've set a flag indicating that the blank part of the frame is reach, then abort the DMA transfer and start a new DMA Rx request. The problem here is that for some reason it not sync. I've noticed that some overrun is happening and in order to get the uart working again I need to deinit and reinit the uart and the sync process fail.
uint8_t rxbuff[108]={0};
ublox_t ublox;
uint8_t ubx_msgids[100]={0};
uint8_t idx=0;
uint8_t f_is_sync = 0;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1) //GNSS
{
if (!f_is_sync){
__HAL_TIM_SET_COUNTER(&htim14, 0);
}else{
HAL_GPIO_WritePin(GP2_GPIO_Port, GP2_Pin, GPIO_PIN_RESET);
}
}
}
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1) //GNSS
{
if (!f_is_sync){
__HAL_TIM_SET_COUNTER(&htim14, 0);
}else{
HAL_GPIO_WritePin(GP2_GPIO_Port, GP2_Pin, GPIO_PIN_SET);
}
}
}
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart){
if (huart->Instance == USART1) // ECT-400 UART
{
HAL_GPIO_WritePin(LED_G_GPIO_Port, LED_G_Pin, GPIO_PIN_RESET);
__HAL_TIM_SET_COUNTER(&htim14, 0);
HAL_UART_DeInit(&huart1);
MX_USART1_UART_Init(); //my initialization code
__HAL_TIM_SET_COUNTER(&htim14, 0);
HAL_UART_Receive_DMA(&huart1, rxbuff, 108);
HAL_GPIO_WritePin(LED_G_GPIO_Port, LED_G_Pin, GPIO_PIN_SET);
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM14){
HAL_GPIO_TogglePin(GP1_GPIO_Port, GP1_Pin);
HAL_TIM_Base_Stop_IT(&htim14);
HAL_DMA_Abort(&hdma_usart1_rx);
f_is_sync = 1;
HAL_UART_Receive_DMA(&huart1, rxbuff, 108);
}
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_DMA_Init();
MX_TIM14_Init();
ublox_init(&ublox);
HAL_UART_Receive_DMA(&huart1, rxbuff, 108);
__HAL_TIM_CLEAR_IT(&htim14, TIM_IT_UPDATE);
__HAL_TIM_SET_COUNTER(&htim14, 0);
HAL_GPIO_TogglePin(GP1_GPIO_Port, GP1_Pin);
HAL_TIM_Base_Start_IT(&htim14);
while (1);
}This is part of the code. The GPIO set and reset are for debug with an oscilloscope what is happening.
EDIT:
I'm testing this code (it was working on old HAL library)
uint8_t sync=1;
// Rutina para sincronizar el comienzo del mensaje
while(sync)
{
// Read two bytes
HAL_UART_Receive(&huart1, rxbuff, 2, 200);
// If they are SYNC bytes
if(rxbuff[0]==0xB5 && rxbuff[1]==0x62)
{
// Receive remaining 106 bytes
HAL_UART_Receive(&huart1, &rxbuff[2], 106, 10);
// We are in sync with GPS
sync=0;
}
}
// Ask for 108 bytes in DMA mode
HAL_UART_Receive_DMA(&huart1, rxbuff, 108);The problem here is that the call to HAL_UART_Receive_DMA produce an Overrun error and DMA process is not working at all.
