2025-05-19 11:00 AM
I've got the NUCLEO-G491RE board and have it connected to my PC over the only USB port which is of course also used for the debugger.
Both printf() and HAL_UART_Transmit() work to send data to a terminal program on the PC, but I can't use polling for my communication (there's too much else going on). If I call HAL_UART_Transmit_IT() it returns HAL_OK but doesn't actually transmit anything, and any subsequent calls to printf() or HAL_UART_Transmit() no longer do anything.
I'm assuming this is because this isn't a "real" UART but some kind of virtual UART that gets converted into USB commands that cooperate with the debugger.
Is there a way to use interrupt-driven communication over this (virtual) serial port?
Thanks,
Chris
2025-05-19 11:13 AM
If HAL_UART_Transmit_IT is not working, probably an issue with interrupts or incorrect code. Here is an example that uses it correctly:
It's a real UART, sending out and receiving UART data on TX and RX pins, it's not a USB-based anything. The ST-link chip translates between UART and USB.
2025-05-19 11:21 AM
HAL_UART_Transmit_IT() returns immediately, the data transfer occurs later and in the background.
You need the UARTx_IRQHandler() handing the transfer off to the HAL layer.
You can't have multiple transfers in-flight, and HAL_UART_Transmit() likely knows the state caused by the pending interrupt transfer, in-progress.
If you want buffering and queuing, you need to implement that.
>>Is there a way to use interrupt-driven communication over this (virtual) serial port?
Yes, if you want an unblocked approach you'll need to feed your data into a larger ring-buffer, and start a HAL_UART_Transmit_IT() on a portion of it, updating that, and subsequent transmissions via the call-back.
2025-05-19 11:41 AM
I've got code like this:
sprintf(tx_buffer, "Button pressed\r\n");
HAL_UART_Transmit(&hcom_uart [0], (const uint8_t*)tx_buffer, strlen(tx_buffer), COM_POLL_TIMEOUT);
that works, and when I inspect hcom_uart[0].Instance with the debugger it's set to 0x40008000 which is LPUART1 and not one of the USARTs (right?)
When I look at LPUART1 in the IOC file, it's disabled and grayed out so I can't make any changes to it. It does have a tooltip that doesn't like to appear, but when it does it says "Status: Not available" and "IP under HMI BSP driver control". Because this is happening, I can't view any of the details for the LPUART1 (like whether interrupts are enabled).
The example code you linked is for a USART, not a UART, and definitely not for a UART that is under HMI BSP driver control, so I'm not sure how to take that code and apply it to my situation.
2025-05-19 12:12 PM
If you can get polling to work but not interrupt, then as @TDK mentions, you have issues with your code.
The VCP is no different than using a external USB<>Serial adapter. They both do the same thing, except with the Nucleo, you can debug and have COM port using one USB cable.
Post your code so it can be dissected
2025-05-19 12:33 PM
Here is all the user code I have:
#define TX_BUF_SIZE 1000
uint8_t tx_buffer[TX_BUF_SIZE];
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
int numPresses = 0;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USB_Device_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Initialize led */
BSP_LED_Init(LED_GREEN);
/* Initialize USER push-button, will be used to trigger an interrupt each time it's pressed.*/
BSP_PB_Init(BUTTON_USER, BUTTON_MODE_EXTI);
/* Initialize COM1 port (115200, 8 bits (7-bit data + 1 stop bit), no parity */
BspCOMInit.BaudRate = 115200;
BspCOMInit.WordLength = COM_WORDLENGTH_8B;
BspCOMInit.StopBits = COM_STOPBITS_1;
BspCOMInit.Parity = COM_PARITY_NONE;
BspCOMInit.HwFlowCtl = COM_HWCONTROL_NONE;
if (BSP_COM_Init(COM1, &BspCOMInit) != BSP_ERROR_NONE)
{
Error_Handler();
}
/* USER CODE BEGIN BSP */
/* -- Sample board code to send message over COM1 port ---- */
printf("Welcome to STM32 world !\r\n");
// Transmit();
/* -- Sample board code to switch on led ---- */
BSP_LED_On(LED_GREEN);
/* USER CODE END BSP */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* -- Sample board code for User push-button in interrupt mode ---- */
if (BspButtonState == BUTTON_PRESSED)
{
numPresses++;
/* Update button state */
BspButtonState = BUTTON_RELEASED;
/* -- Sample board code to toggle led ---- */
BSP_LED_Toggle(LED_GREEN);
if (numPresses == 3)
{
sprintf(tx_buffer, "Button pressed, numPresses=%d\r\n", numPresses);
HAL_UART_Transmit_IT(&hcom_uart[0], (const uint8_t*)tx_buffer, strlen(tx_buffer));
}
else
{
sprintf(tx_buffer, "Button pressed, numPresses=%d\r\n", numPresses);
HAL_UART_Transmit(&hcom_uart[0], (const uint8_t*)tx_buffer, strlen(tx_buffer), 1000);
}
}
}
/* USER CODE END WHILE */
}
The first two times I press the button it calls HAL_UART_Transmit() and I see those messages. The third time it calls HAL_UART_Transmit_IT() and I see nothing. The fourth time also calls HAL_UART_Transmit() but I never see those messages either.
In my IOC I have "Virtual Com Port" checked under Bsp which means LPUART1 under Connectivity is disabled.
2025-05-19 12:36 PM
BTW, the automatically-generated code:
/* Initialize COM1 port (115200, 8 bits (7-bit data + 1 stop bit), no parity */
BspCOMInit.BaudRate = 115200;
BspCOMInit.WordLength = COM_WORDLENGTH_8B;
BspCOMInit.StopBits = COM_STOPBITS_1;
BspCOMInit.Parity = COM_PARITY_NONE;
BspCOMInit.HwFlowCtl = COM_HWCONTROL_NONE;
if (BSP_COM_Init(COM1, &BspCOMInit) != BSP_ERROR_NONE)
{
Error_Handler();
}
has an incorrect comment, right? An 8-bit word length means 8-bit data + 1 stop bit for a total of 9 bits, yes?
2025-05-19 12:46 PM - edited 2025-05-19 12:47 PM
Primary HAL when you plan IT = require enable IT same for DMA. You generate in MX? Then in USART/UART window click NVIC and set checkbox for interrupt.
2025-05-19 12:52 PM
And if I turn off the Virtual Com Port and instead enable the LPUART1 directly, I never get anything showing up in my terminal:
int main(void)
{
/* USER CODE BEGIN 1 */
int numPresses = 0;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USB_Device_Init();
MX_LPUART1_UART_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Initialize led */
BSP_LED_Init(LED_GREEN);
/* Initialize USER push-button, will be used to trigger an interrupt each time it's pressed.*/
BSP_PB_Init(BUTTON_USER, BUTTON_MODE_EXTI);
/* USER CODE BEGIN BSP */
/* -- Sample board code to send message over COM1 port ---- */
// printf("Welcome to STM32 world !\r\n");
// Transmit();
/* -- Sample board code to switch on led ---- */
BSP_LED_On(LED_GREEN);
/* USER CODE END BSP */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* -- Sample board code for User push-button in interrupt mode ---- */
if (BspButtonState == BUTTON_PRESSED)
{
numPresses++;
/* Update button state */
BspButtonState = BUTTON_RELEASED;
/* -- Sample board code to toggle led ---- */
BSP_LED_Toggle(LED_GREEN);
if (numPresses == 3)
{
sprintf(tx_buffer, "Button pressed, numPresses=%d\r\n", numPresses);
HAL_UART_Transmit_IT(&hlpuart1, (const uint8_t*)tx_buffer, strlen(tx_buffer));
}
else
{
sprintf(tx_buffer, "Button pressed, numPresses=%d\r\n", numPresses);
HAL_UART_Transmit(&hlpuart1, (const uint8_t*)tx_buffer, strlen(tx_buffer), 1000);
}
}
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
/* USER CODE END 3 */
}
static void MX_LPUART1_UART_Init(void)
{
/* USER CODE BEGIN LPUART1_Init 0 */
/* USER CODE END LPUART1_Init 0 */
/* USER CODE BEGIN LPUART1_Init 1 */
/* USER CODE END LPUART1_Init 1 */
hlpuart1.Instance = LPUART1;
hlpuart1.Init.BaudRate = 115200;
hlpuart1.Init.WordLength = UART_WORDLENGTH_8B;
hlpuart1.Init.StopBits = UART_STOPBITS_1;
hlpuart1.Init.Parity = UART_PARITY_NONE;
hlpuart1.Init.Mode = UART_MODE_TX_RX;
hlpuart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
hlpuart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
hlpuart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
hlpuart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&hlpuart1) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetTxFifoThreshold(&hlpuart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetRxFifoThreshold(&hlpuart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_DisableFifoMode(&hlpuart1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN LPUART1_Init 2 */
/* USER CODE END LPUART1_Init 2 */
}
2025-05-19 12:53 PM
No can do - when I have "virtual com port" enabled, there are NO options under LPUART1, the entire section is grayed out. And if I disable "Virtual com port" (see my next reply) then I never get anything showing up in my terminal program.