STM32CubeWB
STM32CubeWB copied to clipboard
HAL_UARTEx_ReceiveToIdle_DMA(). DMA in ring mode. When the HAL_UARTEx_RxEventCallback() interrupt is called, the HAL_UARTEx_GetRxEventType() function does not return the HAL_UART_RXEVENT_IDLE status if the index of the last received byte is equal to the size of the HAL_UARTEx_ReceiveToIdle_DMA.
Describe the set-up
- The board - STM32WB55CC
- IDE - STM32CubeIDE version: 1.12.0.
- HAL version - 1.16.0
Describe the bug I use the HAL_UARTEx_ReceiveToIdle_DMA() function. DMA in ring mode. When the HAL_UARTEx_RxEventCallback() interrupt is called, the HAL_UARTEx_GetRxEventType() function does not return the HAL_UART_RXEVENT_IDLE status if the index of the last received byte is equal to the size of the HAL_UARTEx_ReceiveToIdle_DMA.
How To Reproduce
.io configuration:
#MicroXplorer Configuration settings - do not modify
CAD.formats=
CAD.pinconfig=
CAD.provider=
Dma.LPUART1_RX.0.Direction=DMA_PERIPH_TO_MEMORY
Dma.LPUART1_RX.0.EventEnable=DISABLE
Dma.LPUART1_RX.0.Instance=DMA1_Channel3
Dma.LPUART1_RX.0.MemDataAlignment=DMA_MDATAALIGN_BYTE
Dma.LPUART1_RX.0.MemInc=DMA_MINC_ENABLE
Dma.LPUART1_RX.0.Mode=DMA_NORMAL
Dma.LPUART1_RX.0.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
Dma.LPUART1_RX.0.PeriphInc=DMA_PINC_DISABLE
Dma.LPUART1_RX.0.Polarity=HAL_DMAMUX_REQ_GEN_RISING
Dma.LPUART1_RX.0.Priority=DMA_PRIORITY_LOW
Dma.LPUART1_RX.0.RequestNumber=1
Dma.LPUART1_RX.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,SignalID,Polarity,RequestNumber,SyncSignalID,SyncPolarity,SyncEnable,EventEnable,SyncRequestNumber
Dma.LPUART1_RX.0.SignalID=NONE
Dma.LPUART1_RX.0.SyncEnable=DISABLE
Dma.LPUART1_RX.0.SyncPolarity=HAL_DMAMUX_SYNC_NO_EVENT
Dma.LPUART1_RX.0.SyncRequestNumber=1
Dma.LPUART1_RX.0.SyncSignalID=NONE
Dma.LPUART1_TX.1.Direction=DMA_MEMORY_TO_PERIPH
Dma.LPUART1_TX.1.EventEnable=DISABLE
Dma.LPUART1_TX.1.Instance=DMA1_Channel4
Dma.LPUART1_TX.1.MemDataAlignment=DMA_MDATAALIGN_BYTE
Dma.LPUART1_TX.1.MemInc=DMA_MINC_ENABLE
Dma.LPUART1_TX.1.Mode=DMA_NORMAL
Dma.LPUART1_TX.1.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
Dma.LPUART1_TX.1.PeriphInc=DMA_PINC_DISABLE
Dma.LPUART1_TX.1.Polarity=HAL_DMAMUX_REQ_GEN_RISING
Dma.LPUART1_TX.1.Priority=DMA_PRIORITY_LOW
Dma.LPUART1_TX.1.RequestNumber=1
Dma.LPUART1_TX.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,SignalID,Polarity,RequestNumber,SyncSignalID,SyncPolarity,SyncEnable,EventEnable,SyncRequestNumber
Dma.LPUART1_TX.1.SignalID=NONE
Dma.LPUART1_TX.1.SyncEnable=DISABLE
Dma.LPUART1_TX.1.SyncPolarity=HAL_DMAMUX_SYNC_NO_EVENT
Dma.LPUART1_TX.1.SyncRequestNumber=1
Dma.LPUART1_TX.1.SyncSignalID=NONE
Dma.Request0=LPUART1_RX
Dma.Request1=LPUART1_TX
Dma.Request2=USART1_RX
Dma.Request3=USART1_TX
Dma.RequestsNb=4
Dma.USART1_RX.2.Direction=DMA_PERIPH_TO_MEMORY
Dma.USART1_RX.2.EventEnable=DISABLE
Dma.USART1_RX.2.Instance=DMA1_Channel1
Dma.USART1_RX.2.MemDataAlignment=DMA_MDATAALIGN_BYTE
Dma.USART1_RX.2.MemInc=DMA_MINC_ENABLE
Dma.USART1_RX.2.Mode=DMA_CIRCULAR
Dma.USART1_RX.2.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
Dma.USART1_RX.2.PeriphInc=DMA_PINC_DISABLE
Dma.USART1_RX.2.Polarity=HAL_DMAMUX_REQ_GEN_RISING
Dma.USART1_RX.2.Priority=DMA_PRIORITY_LOW
Dma.USART1_RX.2.RequestNumber=1
Dma.USART1_RX.2.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,SignalID,Polarity,RequestNumber,SyncSignalID,SyncPolarity,SyncEnable,EventEnable,SyncRequestNumber
Dma.USART1_RX.2.SignalID=NONE
Dma.USART1_RX.2.SyncEnable=DISABLE
Dma.USART1_RX.2.SyncPolarity=HAL_DMAMUX_SYNC_NO_EVENT
Dma.USART1_RX.2.SyncRequestNumber=1
Dma.USART1_RX.2.SyncSignalID=NONE
Dma.USART1_TX.3.Direction=DMA_MEMORY_TO_PERIPH
Dma.USART1_TX.3.EventEnable=DISABLE
Dma.USART1_TX.3.Instance=DMA1_Channel2
Dma.USART1_TX.3.MemDataAlignment=DMA_MDATAALIGN_BYTE
Dma.USART1_TX.3.MemInc=DMA_MINC_ENABLE
Dma.USART1_TX.3.Mode=DMA_NORMAL
Dma.USART1_TX.3.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
Dma.USART1_TX.3.PeriphInc=DMA_PINC_DISABLE
Dma.USART1_TX.3.Polarity=HAL_DMAMUX_REQ_GEN_RISING
Dma.USART1_TX.3.Priority=DMA_PRIORITY_LOW
Dma.USART1_TX.3.RequestNumber=1
Dma.USART1_TX.3.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,SignalID,Polarity,RequestNumber,SyncSignalID,SyncPolarity,SyncEnable,EventEnable,SyncRequestNumber
Dma.USART1_TX.3.SignalID=NONE
Dma.USART1_TX.3.SyncEnable=DISABLE
Dma.USART1_TX.3.SyncPolarity=HAL_DMAMUX_SYNC_NO_EVENT
Dma.USART1_TX.3.SyncRequestNumber=1
Dma.USART1_TX.3.SyncSignalID=NONE
File.Version=6
KeepUserPlacement=false
LPUART1.BaudRate=115200
LPUART1.IPParameters=BaudRate
Mcu.CPN=STM32WB55CCU6
Mcu.Family=STM32WB
Mcu.IP0=DMA
Mcu.IP1=LPUART1
Mcu.IP2=NVIC
Mcu.IP3=RCC
Mcu.IP4=SYS
Mcu.IP5=USART1
Mcu.IPNb=6
Mcu.Name=STM32WB55CCUx
Mcu.Package=UFQFPN48
Mcu.Pin0=PA2
Mcu.Pin1=PA3
Mcu.Pin2=PA8
Mcu.Pin3=PA9
Mcu.Pin4=PA10
Mcu.Pin5=PA13
Mcu.Pin6=PA14
Mcu.PinsNb=7
Mcu.ThirdPartyNb=0
Mcu.UserConstants=
Mcu.UserName=STM32WB55CCUx
MxCube.Version=6.8.0
MxDb.Version=DB.6.0.80
NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.DMA1_Channel1_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true
NVIC.DMA1_Channel2_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true
NVIC.DMA1_Channel3_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true
NVIC.DMA1_Channel4_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true
NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.ForceEnableDMAVector=true
NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.LPUART1_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true\:false
NVIC.USART1_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
PA10.GPIOParameters=GPIO_Label
PA10.GPIO_Label=USART1_RX
PA10.Mode=Asynchronous
PA10.Signal=USART1_RX
PA13.Mode=Serial_Wire
PA13.Signal=SYS_JTMS-SWDIO
PA14.Mode=Serial_Wire
PA14.Signal=SYS_JTCK-SWCLK
PA2.GPIOParameters=GPIO_Label
PA2.GPIO_Label=LPUART1_TX_DEBUG
PA2.Mode=Asynchronous
PA2.Signal=LPUART1_TX
PA3.GPIOParameters=GPIO_Label
PA3.GPIO_Label=LPUART1_RX_DEBUG
PA3.Mode=Asynchronous
PA3.Signal=LPUART1_RX
PA8.GPIOParameters=GPIO_Label
PA8.GPIO_Label=PIN_DEBUG
PA8.Locked=true
PA8.Signal=GPIO_Output
PA9.GPIOParameters=GPIO_Label
PA9.GPIO_Label=USART1_TX
PA9.Mode=Asynchronous
PA9.Signal=USART1_TX
PCC.Ble.ConnectionInterval=1000.0
PCC.Ble.DataLength=6
PCC.Ble.IsUsed=false
PCC.Ble.Mode=NOT_SELECTED
PCC.Ble.PowerLevel=Min
PCC.Zigbee.IsUsed=false
PCC.Zigbee.Mode=Sleepy End Device
PCC.Zigbee.Payload=15
PCC.Zigbee.PoolPeriodicity=480.0
PCC.Zigbee.PowerLevel=Min
PCC.Zigbee.RequestPeriodicity=1500.0
PinOutPanel.RotationAngle=0
ProjectManager.AskForMigrate=true
ProjectManager.BackupPrevious=false
ProjectManager.CompilerOptimize=6
ProjectManager.ComputerToolchain=false
ProjectManager.CoupleFile=true
ProjectManager.CustomerFirmwarePackage=
ProjectManager.DefaultFWLocation=true
ProjectManager.DeletePrevious=true
ProjectManager.DeviceId=STM32WB55CCUx
ProjectManager.FirmwarePackage=STM32Cube FW_WB V1.16.0
ProjectManager.FreePins=false
ProjectManager.HalAssertFull=false
ProjectManager.HeapSize=0x200
ProjectManager.KeepUserCode=true
ProjectManager.LastFirmware=true
ProjectManager.LibraryCopy=1
ProjectManager.MainLocation=Core/Src
ProjectManager.NoMain=false
ProjectManager.PreviousToolchain=STM32CubeIDE
ProjectManager.ProjectBuild=false
ProjectManager.ProjectFileName=UART_problem_project.ioc
ProjectManager.ProjectName=UART_problem_project
ProjectManager.ProjectStructure=
ProjectManager.RegisterCallBack=
ProjectManager.StackSize=0x400
ProjectManager.TargetToolchain=STM32CubeIDE
ProjectManager.ToolChainLocation=
ProjectManager.UnderRoot=true
ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_USART1_UART_Init-USART1-false-HAL-true,5-MX_LPUART1_UART_Init-LPUART1-false-HAL-false
RCC.ADCFreq_Value=128000000
RCC.AHBFreq_Value=32000000
RCC.APB1Freq_Value=32000000
RCC.APB1TimFreq_Value=32000000
RCC.APB2Freq_Value=32000000
RCC.APB2TimFreq_Value=32000000
RCC.APB3Freq_Value=16000000
RCC.Cortex2Freq_Value=32000000
RCC.CortexFreq_Value=32000000
RCC.FCLKCortexFreq_Value=32000000
RCC.FamilyName=M
RCC.HCLK3Freq_Value=32000000
RCC.HCLKFreq_Value=32000000
RCC.HCLKRFFreq_Value=16000000
RCC.HSE_VALUE=32000000
RCC.HSI48_VALUE=48000000
RCC.HSI_VALUE=16000000
RCC.I2C1Freq_Value=32000000
RCC.I2C3Freq_Value=32000000
RCC.IPParameters=ADCFreq_Value,AHBFreq_Value,APB1Freq_Value,APB1TimFreq_Value,APB2Freq_Value,APB2TimFreq_Value,APB3Freq_Value,Cortex2Freq_Value,CortexFreq_Value,FCLKCortexFreq_Value,FamilyName,HCLK3Freq_Value,HCLKFreq_Value,HCLKRFFreq_Value,HSE_VALUE,HSI48_VALUE,HSI_VALUE,I2C1Freq_Value,I2C3Freq_Value,LCDFreq_Value,LPTIM1Freq_Value,LPTIM2Freq_Value,LPUART1Freq_Value,LSCOPinFreq_Value,LSI_VALUE,MCO1PinFreq_Value,MSIClockRange,PLLPoutputFreq_Value,PLLQoutputFreq_Value,PLLRCLKFreq_Value,PLLSAI1PoutputFreq_Value,PLLSAI1QoutputFreq_Value,PLLSAI1RoutputFreq_Value,PWRFreq_Value,RFWKPFreq_Value,RNGFreq_Value,RTCClockSelection,RTCFreq_Value,SAI1Freq_Value,SMPS1Freq_Value,SMPSCLockSelectionVirtual,SMPSFreq_Value,SYSCLKFreq_VALUE,USART1Freq_Value,USBFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value,VCOSAI1OutputFreq_Value
RCC.LCDFreq_Value=32768
RCC.LPTIM1Freq_Value=32000000
RCC.LPTIM2Freq_Value=32000000
RCC.LPUART1Freq_Value=32000000
RCC.LSCOPinFreq_Value=32000
RCC.LSI_VALUE=32000
RCC.MCO1PinFreq_Value=32000000
RCC.MSIClockRange=RCC_MSIRANGE_10
RCC.PLLPoutputFreq_Value=128000000
RCC.PLLQoutputFreq_Value=128000000
RCC.PLLRCLKFreq_Value=128000000
RCC.PLLSAI1PoutputFreq_Value=128000000
RCC.PLLSAI1QoutputFreq_Value=128000000
RCC.PLLSAI1RoutputFreq_Value=128000000
RCC.PWRFreq_Value=32000000
RCC.RFWKPFreq_Value=31250
RCC.RNGFreq_Value=32000
RCC.RTCClockSelection=RCC_RTCCLKSOURCE_LSE
RCC.RTCFreq_Value=32768
RCC.SAI1Freq_Value=128000000
RCC.SMPS1Freq_Value=16000000
RCC.SMPSCLockSelectionVirtual=RCC_SMPSCLKSOURCE_MSI
RCC.SMPSFreq_Value=8000000
RCC.SYSCLKFreq_VALUE=32000000
RCC.USART1Freq_Value=32000000
RCC.USBFreq_Value=128000000
RCC.VCOInputFreq_Value=32000000
RCC.VCOOutputFreq_Value=256000000
RCC.VCOSAI1OutputFreq_Value=256000000
USART1.BaudRate=38400
USART1.IPParameters=BaudRate,WordLength,Parity,VirtualMode-Asynchronous
USART1.Parity=PARITY_EVEN
USART1.VirtualMode-Asynchronous=VM_ASYNC
USART1.WordLength=WORDLENGTH_9B
board=custom
isbadioc=false
in main:
USER CODE 0
/* USER CODE BEGIN 0 */
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
// debug_pin_toggle(1);
// printf( "Size= %i, rxEventType = %i\n\r", Size, (int)rxEventType);
printf("Size= %i, RxEventType = ", Size);
HAL_UART_RxEventTypeTypeDef rxEventType;
rxEventType = HAL_UARTEx_GetRxEventType(huart);
switch (rxEventType)
{
case HAL_UART_RXEVENT_IDLE:
printf( "IDLE\n\r" );
printf( "\n\r" );
break;
case HAL_UART_RXEVENT_HT:
printf( "HT\n\r" );
break;
case HAL_UART_RXEVENT_TC:
printf( "TC\n\r" );
break;
default:
printf( "???\n\r" );
break;
}
}
/* USER CODE END 0 */
USER CODE 2
/* USER CODE BEGIN 2 */
#define RX_BUFFER_SIZE 8
static uint8_t rx_buffer[RX_BUFFER_SIZE];
HAL_StatusTypeDef halStatus = HAL_OK;
halStatus = HAL_UARTEx_ReceiveToIdle_DMA(&huart1, rx_buffer, RX_BUFFER_SIZE);
if ( halStatus != HAL_OK )
printf("ReceiveToIdle_error\n\r");
/* USER CODE END 2 */
How we can reproduce the problem:
- Initialize the USART in asynchronous mode. RX DMA in cyclic mode. An example of a project in the .ioc format was given above.
- Generating a project.
- in main, we insert the code USER CODE END 0 and USER CODE END 2 that was given above.
- Launches the project.
- Send 4 bytes of data from any UART.
- Get it if we create a UART printf:
Size = 4, RxEventType = HT
Size = 4, RxEventType = IDLE
There is no mistake. The HAL_UARTEx_RxEventCallback function is called 2 times: 1 time when filled 1/2 rx_buffer. HAL_UART_RXEVENT_HT 2 times that the package is finished. HAL_UART_RXEVENT_IDLE 7. Send 4 bytes of data from any UART. 8. Get it if we create a UART printf:
Size = 8, RxEventType = TC
There's a mistake. The HAL_UARTEx_RxEventCallback function is called 1 time. With the status HAL_UART_RXEVENT_TC.
Additional context perhaps this is not a bug, but a feature. But in the current code it is impossible to determine the end of reception if HAL_UART_RXEVENT_IDLE == HAL_UART_RXEVENT_TC.
the bug occurs around in this place. If you add to the condition
(nb_remaining_rx_data <= huart->RxXferSize)
then everything will work in cyclic DMA mode. But the normal DMA mode will break.
Screenshots
half complete:
full complete:
Hello @hayar2,
Thank you for this report. We will get back to you as soon as we analyze it further. This may take some time. Thank you for your comprehension.
With regards,
Hi @hayar2,
If I understand well, your point is that by the end of the transfer HAL_UARTEx_GetRxEventType() does not return HAL_UART_RXEVENT_IDLE and it returns only HAL_UART_RXEVENT_TC.
The HAL_UART_RXEVENT_IDLE should be returned when an Idle event occurs before the reception has been completed as mentioned in the function description
https://github.com/STMicroelectronics/STM32CubeWB/blob/d7e2d6d82b45b0323367351daa7270568f981a0f/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_uart_ex.c#L965-L966
And as per the description of the HAL_UARTEx_ReceiveToIdle_DMA() function, UART will receive an amount of data in DMA mode till either the expected number of data is received or an IDLE line event occurs.
https://github.com/STMicroelectronics/STM32CubeWB/blob/d7e2d6d82b45b0323367351daa7270568f981a0f/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_uart_ex.c#L885-L889
Actually, the IDLE line event is triggered if UART RX line is inactive for one frame. The frame time depends on your baudrate. Higher baudrate, lower frame.
In your case, the IDLE line event has been detected since all expected data are not received yet. Indeed, if at least one data has already been received, IDLE event is to be notified to user for.
Using the same code, when transferring a data size equal to 8, as the number of received data is exactly equal to the amount of data expected to be received, no idle line event will be generated. The HAL_UARTEx_GetRxEventType() function will return only half transfer and transfer complete events. The HAL_UART_RXEVENT_HT is generated when the fourth character is received and HAL_UART_RXEVENT_TC is generated by the end of transfer.
Size = 4, RxEventType = HT
Size = 8, RxEventType = TC
I hope I've been able to answer your question.
With regards,
okay, how to detect the end of a package in a cyclic mode when HAL_UARTEx_ReceiveToIdle_DMA Size equal to 8 bytes. if received 16 bytes, 24 bytes, 32 bytes?
sorry for my English. If something is unclear, let me know.
Hi @hayar2,
The HAL_UART_RXEVENT_TC event could notify you the end of transfer it is trigged once the reception has been completed and the expected number of data has been received.
With regards,
Changed the HAL_UARTEx_RxEventCallback() function. Added the output of the received bytes to another uart(printf):
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
debug_pin_toggle(1);
printf("Size= %i, RxEventType = ", Size);
HAL_UART_RxEventTypeTypeDef rxEventType;
rxEventType = HAL_UARTEx_GetRxEventType(huart);
switch (rxEventType)
{
case HAL_UART_RXEVENT_IDLE:
printf( "IDLE\n\r" );
break;
case HAL_UART_RXEVENT_HT:
printf( "HT\n\r" );
break;
case HAL_UART_RXEVENT_TC:
printf( "TC\n\r" );
break;
default:
printf( "???\n\r" );
break;
}
static int startIdx = 0;
int endIdx = Size;
// if ( startIdx == endIdx )
// return;
if ( endIdx < startIdx )
{
startIdx = 0;
}
for (int idx = startIdx; idx < endIdx; idx++)
{
printf("0x%X ", huart->pRxBuffPtr[idx]);
}
printf("\n\r\n\r");
startIdx = endIdx;
}
when I send 24 bytes, the following happens:
image
It turns out I received 3 packages? But in fact I only accepted 1 package.
Hi @hayar2,
I didn't get your question precisely. Would you please give me more details ?
With regards,
of course. how to detect the end of a package in this case?
ST Internal Reference: 178447
Fixed in : 273007f20a5c7bca2698668905a71515cf2116fd