STM32 print via UART without Nucleo/Discovery

I would like for debugging/trace purposes to print texts (preferably via printf but just text is also fine) from an STM32F103C8T6 to a (PC) terminal application.

I noticed that all examples use a Nucleo or Discovery board but I don't have those. I'm using ST Link/V2 and System Workbench (Eclipse).

Does anybody know how to do this or if it is even possible? (I guess so with some USB/RS232 converter maybe).

• You can print the string on any UART lines and use a UART to USB converter to see it on PC terminal. Because a Nucleo/Discovery has a onboard UART/USB converter which does exactly the same thing. – ammar.cma Nov 22 '17 at 10:25
• Check this tool: st.com/en/development-tools/stm-studio-stm32.html A bit better than sending strings. – Bence Kaulics Nov 22 '17 at 11:30
• @BenceKaulics If it works together with Eclipse than it would be very useful. – Michel Keijzers Nov 22 '17 at 11:41
• It is not a plugin but a completely independent tool. – Bence Kaulics Nov 22 '17 at 12:17
• @BenceKaulics I know ... but I cannot e.g. use ST Link Utility together (simulatenously) with Eclipse, probably with that tool I have the same problem. – Michel Keijzers Nov 22 '17 at 12:18

All the STM32F0 that I can think of come with UART hardware – meaning that you just need to write your string to some address, and trigger the transfer.

The knowledge of how to do that can be taken from the Reference Manual of that family (ST Document number RM0008), or just straight from the UART driver within the STM Cube software package.

Electrically, you'll really get a TTL UART – any TTL serial-to-USB converter will do. The Nucleo boards just contain a second microcontroller that plays a USB-to-STLink and USB-to-TTL-UART bridge.

For "easy" debugging, the UART is certainly the least error-prone communications interface in the chip. If you're tempted to directly communicate with the PC: Your MCU comes with a USB2 transceiver. You can, adding a few resistors, directly connect that to your PC, and let it look like a serial adapter itself, just giving you your messages or data! That is, given you have a firmware that handles the USB stack. ST offers a library to do that, and that comes with examples. Be warned though that USB is way more complicated than UART, and if you just want to occasionally print short strings, UART certainly is sufficient. The USB interface allows you to send USB data packets through USB2 Full Speed (that's the 12Mb/s standard) – that can be hell of an advantage if you need e.g. to build something that samples a signal rapidly (that's why I used USB on an ARM the first time) in the long term.

• Thanks for the answer ... I just need some data (I doubt I need 12 MB/s, at least not for now)... I will check further into the TTL serial to USB converter ... will my PC automatically detect it as a com port or should I install a driver to have it visible in a terminal application? – Michel Keijzers Nov 22 '17 at 10:31
• Windows generally comes with drivers installed because this has been around for a while. Use HyperTerminal or PuTTY to open the COM port on the baud rate you set in firmware and you should be able to see the ASCII characters. – ammar.cma Nov 22 '17 at 10:33
• @ammar.cma Thanks ... also I found this learn.sparkfun.com/tutorials/how-to-install-ftdi-drivers/all to install ftdi drivers, so even in case it is not autoamtically I can try that. – Michel Keijzers Nov 22 '17 at 10:34
• @MichelKeijzers It depends on the TTL/USB adapter you get and which chip it uses inside. FTDI is common, but cheap knockoffs come from different vendors and thus different drivers. Although, you shouldn't have a problem with drivers. (tons of online tutorials for that) – ammar.cma Nov 22 '17 at 10:36
• @ammar.cma I have a cheap knockoff probably ... but I will check if it works (when I have time)... it's a 'hobby' project getting out of hand a bit :-) ... but a good way to learn about microprocessors. – Michel Keijzers Nov 22 '17 at 10:49

There is no problem with it. You have few options. The first way is to configure your UART (the process may be very straightforward if you use CubeMX) to send text and then hook-up RX and GND pins of your USB-RS232 to TX and GND pins of your board respectively. Then you can transmit your logs for example with function HAL_Uart_Transmit(). More advanced option is to redirect stdout to that UART. But it will take a lot of effort to configure and run this.

There is a third way to solve your problem and it is called semihosting. I have a very tiny experience with it and I cant recommend using it. A semihosted event halts the MCU and needs support from the debug tools to handle the semihosted operation and without debug tools attached, a semihosted event will permanently halt the MCU.

• I will try the first mechanism ... the SWO seems good, but it's not nice to have not simultaneously an IDE open (I need to upload very often). And it's for a hobby project, probably Keil is too expensive to buy just for some hobby. The last sounds interesting too, although I'm afraid it will affect my real program which I want to debug (using interrupts via DMA). – Michel Keijzers Nov 22 '17 at 11:04
• @MichelKeijzers keil have free evaluational licenses with 32kb code limit. If your app is less than that, you can give it a try. Believe me: with SWO you can achieve your result much faster, than with any other way. Besides there are still some ways to make it work with System Workbench. – Vadimchik Nov 22 '17 at 11:15
• Currently I use only 15 KB, but I'm sure eventually I will use more. I'm using now a STM32F103C8T6 which has 64 KB, but eventually I use a 512 KB version, and I think I will need at least a few hundred (not sure yet though). But for 'hardware tests' I can use the prints in a smaller footprint. I will also check the 'some ways' link, thank you – Michel Keijzers Nov 22 '17 at 11:26
• @MichelKeijzers You can use ITM with the IDE still open and connected. In fact that's how I used it the first time I used STM32. I did not know that you could read printfs over debug interface. I was surprised to see printf output when I had neither connected the USB port nor the UART on the MCU to my computer. You can use breakpoints etc. also. Point is it does not interfere with the way you'd normally use your IDE and Debugger. – Dojo Feb 22 '18 at 16:28
• @MichelKeijzers I had tried this in AC6 System Workbench. Just got a mailer form ST that True Studio Pro is now free! Got to try it! – Dojo Feb 22 '18 at 17:28

The procedure is pretty much the same as with a Nucleo board. As was later pointed out to me, the specifics will be different on different STM32 chips, but here's what I used (on an STM32WB55). I assume your job will be similar at a high-level, but the details of the specific API calls may be different.

Also note that if you use CubeMX to assign and configure the UART, then code for steps 1 and 2 should be auto-generated, allowing you to skip to step 3.

1. Configure the GPIO pins used by the UART (in the STM HAL environment, implement the function HAL_UART_MspInit. The HAL library will call it when you are ready to initialize the UART.
• Make sure you select pins that have UART/USART capability on your chip. Look for your chip's ...hal_gpio_ex.h header (e.g. st32wbxx_hal_gpio_ex.h) to see the table of GPIO pins and alternate functions. In my case, I'm using PB6 (USART1_TX) and PB7 (USART1_RX), which are the ones used by the ST-Link interface on my Nucleo board. Your chip may have different options available.
• Enable the appropriate clocks for the device and GPIO pins you're using (e.g. USART1 and GPIOB in my case)
• Initialize the GPIO pins. Mode should be is AF_PP. I set pull to PULLUP. Set the alternate mode as appropriate for your chip (see above. In my case AF7_USART1).
2. Initialize the appropriate UART via a call to HAL_UART_Init. The parameters I use (on an STM32WB55) are:
• Instance = USART1 (use whatever you chose above when configuring the GPIOs)
• Init.BaudRate = 115200
• Init.WordLength = UART_WORDLENGTH_8B. Note that this length includes any parity. So if you use parity, set this to _9B (or configure your terminal for 7-bit words).
• Init.StopBits = UART_STOPBITS_1
• Init.Parity = UART_PARITY_NONE
• Init.Mode = UART_MODE_TX_RX (you could use just _TX, if you're never going to read from the UART)
• Init.HwFlowCtl = UART_HWCONTROL_NONE. I haven't seen a need for CTS/RTS when using a USB connection to a terminal emulator on a PC. But you may need it for your application. If you do, be sure to wire and configure the corresponding GPIO pins.
• Init.OverSampling = UART_OVERSAMPLING_16. I'm not sure what this does. This is what ST's sample code uses
• Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE. Not sure about this either. ST's sample code uses this.
• Init.ClockPrescaler = UART_PRESCALER_DIV1. Not sure why you might want a different prescaler. Maybe to run at lower power or when your baudrate is much lower than your clock (e.g. 115200 bps with a 64 MHz clock)
• AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT. Unless you want to use one of the advanced features (auto baud detect looks like it might be useful)

With this in place, you can call HAL_UART_Transmit to send bytes over the UART. If you want to link it up to printf, there's a bit more to go.

1. Add a "syscalls.c" file to your project, if you don't already have one. Copy it from one of ST's sample programs. The CubeMX tool, if you use it, should generate one for you. This will provide most of the glue for stdout
2. Implement the function int __io_putchar(int c). This is called repeatedly by code in syscalls for writing characters to your console. Your implementation should call HAL_UART_Transmit to send the character to the UART. Be sure to return the character that was written to the UART as well

Of course, after doing this, be sure to attach something (like your ST Link) to your configured GPIO UART pins (minimum TX and RX. CTS and RTS if you're using hardware flow control) so you can connect them to a PC.

• Beware in getting so deep into the hardware configuration detail that this is substantially different between STM32 subfamilies, and specifically what you describe for the will not match the STM32F103 mentioned in the question. – Chris Stratton Aug 30 at 13:20
• What doesn't match? I wrote that the particular GPIO pins used will be different. Are the HAL functions incompatible across products? That pretty much undermines the point of having a HAL. – David C. Aug 30 at 14:59
• Most except for the actual line coding and perhaps the oversampling mismatches; in practice an MCU HAL like this doesn't really abstract hardware unique details, it just names them, and the hardware itself is notably different between the chip you are familiar with and the one the question is about. – Chris Stratton Aug 30 at 15:24