Sometimes when working with an embedded system sending information to a serial port is useful. It can be used to provide system telemetry data, user feedback, or to aid with debugging a program. With most embedded development environments there is support for the old C standard printf(). Generally to use printf() a user needs to provide the putchar() routine that directs character output to your serial port. The STM32CubeIDE is no different and has printf() support. DigiKey provides a nice tutorial on the subject including enabling the floating point support.
There are only two steps needed to provide basic printf() support. First create a UART project instance in STM32CubeIDE. Use the Connectivity Category and select the UART you want to use. This assigns the processor GPIO pins for the TX and RX signals and creates a UART instance and handle. Under Parameter Settings set the desired basic settings such as baud rate, word length, parity, and stop bits.
The next step is to redirect printf() output to use the UART instance. First include the standard IO (stdio.h) header file. Based on your complier, the second part creates the interface to output a single character to the UART instance using the STM32 hardware abstraction layer (HAL) function. With the STM32 environment, you need the UART handle from the created UART instance (e.g., hlpuart1 in the sample code). The necessary code segment is shown below and is placed in the Private Function Prototypes (PFP) code area.
/* USER CODE BEGIN PFP */
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&hlpuart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
One issue with using printf() is that the CPU is involved with moving each formatted character to the UART. The printf() function actually performs two activities. First a character string is created based on the formatting string and arguments in the printf() function call. The second activity is moving that character string to the UART one byte at a time.
One way to improve the printf() CPU I/O efficiency is create the output formatted character string but use DMA to move the character string bytes to the UART. Using a DMA channel eliminates the need for the CPU to move the individual character string bytes to the UART.
In the STM32 IDE when configuring the UART you can assign a DMA channel to the UART transmitter. For an out going message the DMA transfer is setup as memory to peripheral (transmit) with a byte data width.
When you are ready to send a message first use sprintf() to create the formatted character string in a memory buffer. Once the string has been created start the transmit DMA using the HAL DMA api call (HAL_UART_Transmit_DMA). A small code segment is shown below using sprintf() and the HAL DMA api.
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
// check if ready to output
// flag set by timer interrupt, use DMA to transmit data
if(outputState == XMITNOW) {
sprintf(currentOutBuffer, "%llu, %lu, %08lX, %llu, %llu, %llu, %llu\n", ++outSequence, outputADCSums->pdCount, outputADCSums->error, outputADCSums->violet, outputADCSums->blue, outputADCSums->red, outputADCSums->green);
HAL_UART_Transmit_DMA(&hlpuart1, (uint8_t *)currentOutBuffer, strlen(currentOutBuffer));
outputState = OUTPUT_IDLE;
}
}
/* USER CODE END 3 */
The STM32 IDE programming environment and HAL api greatly simplifies using a DMA channel to transmit formatted character strings without involving the CPU. Hopefully this example gets you started using DMA for your data transfers.






