2022-01-13 07:59 AM
Hi everyone, im using an STM32WB and i just managed to get my own BLE<->UART bridge to "half work".
But my problem is about UART managing.
If i receive data with length of less than 247bytes(set by me) just stays in the rx bufer and no DMA transfer complete happens.
I set up the DMA to listen for the next incoming 247 bytes
HAL_UARTEx_ReceiveToIdle_DMA(&huart1, NotifyCharData, RxBuf_SIZE);
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx,DMA_IT_HT);//we dont want the half done transaction interrupt
Whenever the data arrives(stream of data uartRx) ,it gets written into a BLE characteristic, everything works like a charm, but if the last uart received message is less than 247length DMA rx doesnt trigger after an idle time.
No IDLE event occurs.
/**
* @brief Receive an amount of data in DMA mode till either the expected number of data is received or an IDLE event occurs.
* @note Reception is initiated by this function call. Further progress of reception is achieved thanks
* to DMA services, transferring automatically received data elements in user reception buffer and
* calling registered callbacks at half/end of reception. UART IDLE events are also used to consider
* reception phase as ended. In all cases, callback execution will indicate number of received data elements.
* @note When the UART parity is enabled (PCE = 1), the received data contain
* the parity bit (MSB position).
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the received data is handled as a set of uint16_t. In this case, Size must indicate the number
* of uint16_t available through pData.
* @note Dual core specific: there is no support for unaligned accesses on the Cortex-M0+ processor.
* When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* address of user data buffer for storing data to be received, should be aligned on a half word frontier (16 bits)
* (as received data will be handled by DMA from halfword frontier). Depending on compilation chain,
* use of specific alignment compilation directives or pragmas might be required to ensure proper alignment for pData.
* @param huart UART handle.
* @param pData Pointer to data buffer (uint8_t or uint16_t data elements).
* @param Size Amount of data elements (uint8_t or uint16_t) to be received.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
I dont even know what does an "IDLE event" mean, i tought DMA triggered after a short time of bus inactivity (as seen in this video ) but no.
Solved! Go to Solution.
2022-01-14 04:24 AM
ding ding ding,
i was not using the uart in IT mode so i didint enabled the uart1 global interrupt at all.
Now it detects the IDLE state!
/**
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
if(huart1.gState==1<<7){
//IDLE STATE
}
/* USER CODE END USART1_IRQn 1 */
}
2023-08-09 09:57 AM - edited 2023-08-09 10:36 AM
I am trying to understand the example below. Since HAL_UARTEx_RxEventCallback is called also on full complete, is it possible that Size < old_pos? That is, is it possible that a single call to HAL_UARTEx_RxEventCallback will cover a buffer wrap around?
Edit: Anything wrong with this event handler? We are using DMA to IDLE, circular rx buffer, and DMA is set to one byte at a time.
void Serial::uart_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) {
// Map the HAL's hurart to our Serial wrapper class.
Serial *serial = serial::get_serial_by_huart(huart);
const uint16_t new_pos = Size;
constexpr size_t kBufferSize = sizeof(serial->_rx_dma_buffer);
// Assertion: Wrap around cannot happen within one invocation
// since the handler is invoked also on full complete.
if (new_pos < serial->_rx_last_pos) {
Error_Handler();
}
// Assertion: New pos can be equal to the buffer size, e.g.
// on a full complete event, but not above it.
if (new_pos > kBufferSize) {
Error_Handler();
}
// Copy the new bytes.
BaseType_t task_woken = pdFALSE;
const uint32_t len = new_pos - serial->_rx_last_pos;
serial->rx_data_arrived_isr(&serial->_rx_dma_buffer[serial->_rx_last_pos], len,
&task_woken);
// Remember the new position, adjusting to for wrap around.
serial->_rx_last_pos =
new_pos >= kBufferSize ? (new_pos - kBufferSize) : new_pos;
portYIELD_FROM_ISR(task_woken)
}
2023-10-16 04:38 AM
Hi
The IDLE interrupt is calling a standard callback
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
}
2023-10-16 02:20 PM
@Javier1 wrote:Hi @TDK , yes, it is implemented
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size){ //restarts the DMA listening of the UART rx (next 247 bytes) if(huart->Instance ==USART1){ HAL_UARTEx_ReceiveToIdle_DMA(&huart1, NotifyCharData, RxBuf_SIZE); __HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT); } return; }>>The TC IRQ won't fire unless you receive all characters.
What about that "idle event".
Isnt there a programmable timeout i can use for the TC interruption to trigger even if the buffer is not full?
If interrupts no longer work, then HAL_UARTEx_ReceiveToIdle_DMA returned HAL_BUSY. You don't check the HAL status. Rewrite you code to set an error flag that you can check in main loop.
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size){
//restarts the DMA listening of the UART rx (next 247 bytes)
if(huart->Instance ==USART1){
if(HAL_UARTEx_ReceiveToIdle_DMA(&huart1, NotifyCharData, RxBuf_SIZE) != HAL_OK)
{
// set an error flag, poll for flag in main loop, and call HAL_UARTEx_ReceiveToIdle_DMA again.
return;
}
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
}
return;
}
2023-11-17 07:28 AM - edited 2023-11-17 07:31 AM
So, one year later, i had a similar problem.
Imagine how happy i was to google about it and this thread pops up first.
Anyway, i am implementing HAL_UARTEx_ReceiveToIdle_DMA() again in a stm32g4.
The reason why this was not working for me this time is:
As i am using
HAL_UARTEx_ReceiveToIdle_DMA()
to setup the Rx stream.
I was getting worried why my callback was never reached...
The reason being was using (incorrectly)
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
instead of (correct)
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)