Sometimes implementation of UART communication is asymmetric. In general, Rx tasks are time critical and total size of the data is unknown, thus it is best to handle the task in an interrupt service routine where individual incoming bytes are checked without delay. While Tx tasks can be implemented rather relaxed manner. For example, you can use a blocking call inside the main loop.
In this sense, UART HAL functions provided by STM32Cube framework is useful for Tx but not very much so for Rx task. Thus you may have to write your own UART interrupt handler using LL drivers while still using HAL UART Tx functions in Tx task.
Use STM32Cube to generate all the chores of setting the UART module except the interrupt part. LL interrupt is activated after the UART port is initialized using LL functions:Source file
Source file
Source file
Source file
Source file
Source file
In this sense, UART HAL functions provided by STM32Cube framework is useful for Tx but not very much so for Rx task. Thus you may have to write your own UART interrupt handler using LL drivers while still using HAL UART Tx functions in Tx task.
Use STM32Cube to generate all the chores of setting the UART module except the interrupt part. LL interrupt is activated after the UART port is initialized using LL functions:
414 void SerialComm_Init() 415 { 416 LL_USART_EnableIT_RXNE(huart1.Instance); 417 }Then write the interrupt handler to call Rx routine:
126 void USART1_IRQHandler(void) 127 { 128 if(LL_USART_IsActiveFlag_RXNE(USART1) && LL_USART_IsEnabledIT_RXNE(USART1)) 129 { 130 SerialComm_RxRoutine(); 131 } 132 }In STM32Cube convention, this interrupt handler is located in the interrupt handler file (stm32xxx_it.c). In actual Rx routine, each incoming byte is checked by the packet decoder (SerialComm_Decoder) and loaded into one of the two pingpong buffers when valid packet is received.
419 void SerialComm_RxRoutine() 420 { 421 pkt_status status; 422 423 status = SerialComm_Decoder(LL_USART_ReceiveData8(huart1.Instance), 424 UartIsrBuf); 425 426 if(status == PKT_RECEIVED) 427 { 428 // switch ping pong buffer 429 if(UartIsrBuf == UartRxBuf1) 430 { 431 UartIsrBuf = UartRxBuf2; 432 UartRxBuf = UartRxBuf1; 433 } 434 else 435 { 436 UartIsrBuf = UartRxBuf1; 437 UartRxBuf = UartRxBuf2; 438 } 439 // raise flag 440 bPktReceived = true; 441 } 442 }At this point you need another task that checks this pingpong buffer and generates events when new packet is loaded. This task runs in regular interval, whose frequency should be higher than packet rate that the protocol defines.
386 void UartRxTask() 387 { 388 int i; 389 uint8_t event[EVT_QWIDTH]; 390 391 // packet received 392 if(bPktReceived) 393 { 394 // event id 395 event[0] = EVT_UART_RXPKT; 396 // event data size 397 event[1] = UartRxBuf[1]; 398 399 // copy the payload 400 for(i = 0; i< UartRxBuf[1]; i++) 401 { 402 event[2+i] = UartRxBuf[2+i]; 403 } 404 405 // register the event 406 Evt_EnQueue(event); 407 // clear the flag 408 bPktReceived = 0; 409 } 410 }Finally, the main event handler takes care of the events.
166 case EVT_UART_RXPKT: 167 168 if(event[2] == SYS_SRESET) 169 { 170 HAL_NVIC_SystemReset(); 171 } 172 else if(event[2] == SYS_WRESET) 173 { 174 HAL_NVIC_SystemReset(); 175 } 176 else if(event[2] == DIO_SETVAL) 177 { 178 if(event[3] == 0x01) 179 { 180 HAL_GPIO_WritePin(TEST_LED_GPIO_Port, TEST_LED_Pin, 181 GPIO_PIN_SET); 182 183 SerialComm_SendByte(PKT_ACK); 184 } 185 }For the Tx task, you can use either LL function or HAL function (blocking call).
166 case EVT_UART_RXPKT: 167 168 if(event[2] == SYS_SRESET) 169 { 170 HAL_NVIC_SystemReset(); 171 } 172 else if(event[2] == SYS_WRESET) 173 { 174 HAL_NVIC_SystemReset(); 175 } 176 else if(event[2] == DIO_SETVAL) 177 { 178 if(event[3] == 0x01) 179 { 180 HAL_GPIO_WritePin(TEST_LED_GPIO_Port, TEST_LED_Pin, 181 GPIO_PIN_SET); 182 183 SerialComm_SendByte(PKT_ACK); 184 } 185 }<< source code >>
Comments
Post a Comment