cancel
Showing results for 
Search instead for 
Did you mean: 

I would like to use the standard io functions like printf, getc, getchar, putc etc. directly to the UART. Why is this not possible? It's very, very annoying and a waste of my time. WHY IS ANSI C NOT PROPERLY SUPPORTED?

MLee.2
Associate II
 
8 REPLIES 8
Jack Peacock_2
Senior III

Which UART/USART/LPUART will be used as the console? Many STM32s have up to six UARTs plus a low power LPUART for the STM32L series.

ANSI C (as in K & R book) defines a syntax but not the implementation. Remember this is "bare iron", no operating system. You have to provide your own UART drivers and the code for those routines.

Jack Peacock

MLee.2
Associate II

This is something that other compilers support - io stream support is pretty fundamental! Hardware abstraction should be an addition to standard ANSI C, not an extra complication to overcome. If 8 bit PIC micro can support streams - is it unreasonable to expect a Cortex M4 to be able to do the same?

I wasted the best part of a day until I came across this - https://shawnhymel.com/1873/how-to-use-printf-on-stm32/#comments

Come on ST! Up your game here! You won't get many converts, no matter how cheap and powerful the hardware if you make your products so user unfriendly.

Olivier GALLIEN
ST Employee

​Hi @Community member​ 

Please have a look to AN4989 Debug Toolbox chapter "7 Printf debugging. "

https://www.st.com/content/ccc/resource/technical/document/application_note/group0/3d/a5/0e/30/76/51/45/58/DM00354244/files/DM00354244.pdf/jcr:content/translations/en.DM00354244.pdf

It has not been yet update with STM32CubeIDE but I guess SW4STM32 solution should fit.

Hope it help,

Olivier

Olivier GALLIEN
In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.

So, It's not much more than a glorified assembler then? What is the point of a c compiler that doesn't support *standard* c libraries? The clue is in the name - stdio.h

Not very impressed with ST ARM Cortex tbh - I might as well be using an 8051!

This is why ST also provides the HAL and Cube software. If you need handholding to write drivers then use the ST tools to generate the code for you.

A compiler is not equivalent to a library. What you are asking for is a library with these routines that's customized to whatever combination of pins, clock rates and UART instances that you want to use. Compilers have no knowledge of the specific PCB layout you are using. I'm curious, how do you expect the GCC, or some other compiler, to know you are using an STM32L431 with the console on LPUART1 mapped to port B, with a variable clock rate from 4MHz (MSI default), scaled up to 80MHz when you switch to the PLL, but which also has to switch to the LSE clock on low power modes? Oh yeah, maybe the console is also half-duplex RS-485, so where do the bus turnaround times come from?

You may think that's an exaggeration but I have an ST USART driver that does handle those conditions, and I've encountered all of them. Embedded is not Windows programming, you have to do the hard stuff yourself. Writing your own drivers is never a waste of time when the code is reused over a number of years.

Even on 8051s you had to select the pins for TX and RX (at least on SiLabs versions with pin mapping), and on some versions whether it was UART1 or UART2. I don't recall that the SDCC compiler ever had options to do this for you....

Jack Peacock

The whole point of having an ANSI C compiler is precisely so that you *can* utilise library functions, no? Other embedded C compilers seem to manage to implement the stdio.h iostream functionality just fine. I have actually written serial interfaces in assembler - and it's not something that is a productive use of my time. I must admit to being a little bit irked.

This should work - if the compiler were ANSI C compliant - but it doesn't and therefore it isn't!

 /* Initialize all configured peripherals */

 MX_GPIO_Init();

 MX_USART2_UART_Init();

 /* USER CODE BEGIN 2 */

 char Data[] = "hello world\n\r";

 /* USER CODE END 2 */

 /* Infinite loop */

 /* USER CODE BEGIN WHILE */

 while (1)

 {

 HAL_UART_Transmit(&huart2, (uint8_t*)Data, sizeof(Data), 1000);

 HAL_GPIO_TogglePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin);

 HAL_Delay(500);

 printf("HELLO WORLD\n");

 HAL_GPIO_TogglePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin);

 HAL_Delay(500);

 }

> This should work

And what magic exactly would make the compiler - whatever it is - know, that you want to printf() exactly onto USART2? Why not onto USART1 or any other USART/LPUART/any other communication channel of choice?

> ANSI C compliant

ANSI-C is a concept long gone. You may want to talk about C standardized by ISO, maybe the most common revision is C-99 (but the newest C-11 is not different); for checking conformance please refer to C99 chapter 4, specifically verse 6.

I believe OlivierG's answer above should fulfill your requirement.

I don't use Cube, and I believe the generic "standard" printf() and kin ought never be used in microcontroller environment except perhaps for crude initial experiments.

JW

berendi
Principal

The current standards (not ANSI C) distinguish between hosted systems, where things like stdio, file systems, processes etc work as expected, and standalone systems where they don't.

Even if there is a distinction, a standard C program compiled with a proper toolchain for STM32 comes very close.

What does printf("hello world\n"); on a proper operating system do when there is no terminal attached, or it is blocked by flow control? It will either hang or the output goes to the bit bucked, depending on the circumstances. What does getchar() do? Return an error, EOF, or hangs until the terminal becomes available. Ot it might be killed by a signal, I don't know. It is still compliant to ANSI C/POSIX/C-whatever standards.

What does an embedded program do? More or less the same. it either ignores the I/O request (but usually returns some error condition), or hangs on it.

What exactly should the development environment implement in your opinion? Would stdout on UART1 be enough, or you'd need stdin and stderr as well? Do you need a file system, processes, threads, signals, local and network sockets, pipes, job control, too? They are part of the same standards printf is in. Where should it stop? And how should it fit in the on-chip flash?

Oh, and of course it should have a POSIX shell and utilities to be called through system() or execl(), shouldn't it? Head over to the STM32 MPU forum, they have something for you.