Tutorial: Printf() with (and without) Processor Expert

In this post I tapped into how to print messages to a console using  the Kinetis/Freedom board. I’m not a fan of printf() for multiple reasons: It is simply a bad thing for embedded systems programming. But as many have asked for it, here is how to say “hello” from the Freedom Board using printf():

Hello World on the Terminal

Hello World on the Terminal

I’m using the Freedom KL25Z board with the CodeWarrior for MCU 10.3 and gcc build tools. But steps are  generic for any board and tool chains.

ANSI Library and printf()

The first thing to know about printf() is that ANSI specifies what it should do in terms of accepted arguments and formating, but does not specify how to send/receive the character stream, because the underlying hardware can be very different: which SCI/COM/UART used, which baud, which communication settings/etc. As such, a typical library implementation as in CodeWarrior comes with the implementation of the printf() functionality itself, but *without* the low-level UART implemenation. That low-level UART implementation and support is part of the application, not the library.

Low Level UART Support

In order for printf() to print things to a UART, it depends on low-level UART functions and settings. Basically it needs this functionality (function names are generic):

  • read_console(): reading characters from the console.
  • write_console(): writing characters to the console.
  • open_console(): opening and initializing the console. This includes register initialization, baud settings and allocation of buffers.
  • close_console(): the counterpart of open_console() to free up the port and memory.

Creating the project

💡 I’m using here Processor Expert. But if you do not like it, or if you want to go without it: either copy the code or do the same thing without it (but then you need to read the microcontroller manual in much more details).

I create a new project with File > New > Bareboard Project. I give a project name, specify the microcontroller, select the connection, and then there is this dialog which asks me about I/O support:

New Bareboard Project IO Support

New Bareboard Project IO Support

The important thing to know about this I/O support is: it does not add the low-level UART functionality (because it does not know which port/UART/baud/etc). What it does is it will configure to use the correct library in the build tool settings.

💡 If you decide not to use Processor Expert, then you need to copy/paste or create the needed low-level I/O functions. Best if you start with a Processor Expert working version, and then copy/paste things.

EWL Library Settings

So really what the above option does: it sets the library used in the project settings. CodeWarrior offers different libraries, where EWL is the default (EWL = Embedded Warrior Libraries). The EWL are a more optimized and right library for embedded systems. Below you see the different library selections depending on what you have selected in the wizard (so you can easily change this after the project is created):

EWL Library Settings

EWL Library Settings

Using printf()

Time to try it out e.g. in main():

#include <stdio.h>
...
for(;;) {
  printf("hello world!\r\n");
}
...

❗ I always make sure that I have <stdio.h> included if using printf().

But building it, I will have several errors:

Build Failed

Build Failed

So this is to my point from above: the Low Level UART Support is missing.

Adding Low Level UART Support

The simplest thing is to use Processor Expert:

💡 if not using Processor Expert: have a look in C:\Freescale\CW MCU v10.3\MCU\ARM_GCC_Support\UART for example implementations not using Processor Expert

For this I add the ConsoleIO component from the Processor Expert Components Library view to the project:

ConsoleIO in Components Library

ConsoleIO in Components Library

💡 right-click and ‘Add to Project’ or double-click to add it to the project.

Configuring ConsoleIO

The component shows up with errors because I need to configure it first:

ConsoleIO in Project with Errors

ConsoleIO in Project with Errors

I select the Serial_LDD and open the inspector for it (right-click on it and select ‘Inspector’). As I want to use the OpenSDA CDC, I configure it to use UART0 with 38400 baud using PTA1 and PTA2:

Console configured for FRDM-KL25Z and OpenSDA

Console configured for FRDM-KL25Z and OpenSDA

Now the errors are resolved, and I can generate code:

Generate Processor Expert Code

Generate Processor Expert Code

💡 To see what code has been generated,  double click on the ConsoleIO and Serial_LDD.

Building the project is now fine too: and with no errors.

💡 If things are not working: Verify your UART settings are correct, and that OpenSDA CDC is working properly. Unplugging and plugging the USB port might help for when the USB port is stuck on the host.

Downloading it to the target and running it should show now some text on the terminal:

Hello World on the Terminal

Hello World on the Terminal

Summary

Printf() and the likes need low-level UART drivers. An easy way is to have it provided by Processor Expert. If not using Processor Expert, then Processor Expert can be used as a base for copy-pasting the code, or the examples provided in CodeWarrior can be used.

Just be aware that printf() usually adds a lot overhead to the application, and is a common source of stack and buffer overflow. So use it carefully 😉

Happy Printf-ing 🙂

32 thoughts on “Tutorial: Printf() with (and without) Processor Expert

  1. Hi, in your tutorial of LCD, you put this code:

    for(;;) {
    uint8_t cnt;
    uint8_t buf[5];

    LCD1_GotoXY(2,1);
    UTIL1_Num16uToStr(buf, sizeof(buf), cnt);
    LCD1_WriteString((char*)buf);
    cnt++;
    WAIT1_Waitms(100);
    }

    How I should write the line code for sending the string data by “Printf()”?

    Like

  2. Pingback: Be Aware of the Baud Problem | MCU on Eclipse

  3. Pingback: printf() with the FRDM-KL25Z Board and without Processor Expert | MCU on Eclipse

  4. Hello Erich,

    I’m with problems to use other serial ports besides the PTA1 and PTA2.
    Indeed, i used this ports and the SD Card, but i couldn’t inlcude a serial communication in PTC3 and PTC4 in this project (didnt work).

    I dont know why, but, the PTC3 and PTC4 worked well without the SD card.
    Do you know why this happens ? In some projects sometimes i can use others ports (e.g. PTE0 and PTE1), in others dont.. this doesn’t make sense to me

    Like

  5. Hi, I would like to use my KL25Z to display in the terminal an input from other device. In the user manual I read the following: “The primary serial port interface signals are PTA1 and PTA2. These signals are connected to both the OpenSDA and to the J1 I/O connector. ” So I think I just have to connect the RX and TX from my other device to the TX and RX respectively to my KL25Z and join the GND of course. But how could I print the received data to the console? Thanks in advance.

    Like

    • If you are using the signals connected to the OpenSDA micrcontroller, then you need to make sure that the K20 does not interfer with it. It would be better if you would use a UART/SCI which is separate. And how to print things on the console: as described in this article, but using different pins.
      Having said that: you probably better use Processor Expert: it is much, much easier with it.

      Like

  6. Hi!
    If I want to create my project without processor expert…In what part of the processor expert’s code can I find the clock and ports configurations?

    Like

  7. If you have turned on the console IO, how do you turn it off? If I select EWL_NOIO, I get an undefined reference to ‘_pformatter’ in vsnprintf.c.

    Like

    • It sounds like you are still using printf() in your application. Remove any calls to printf() and its variants from your application code.
      You might need to do a Project > Clean too and then rebuild.

      Like

      • Yep. I use sprintf for formating strings for LCD display. I needed to go back to EWL, and just not use ‘puts’ or ‘printf’. as long as I don’t use those, I don’t get any errors. Thanks!

        Like

  8. Hi Erich,

    I am trying to use the consoleIO component as you instructed. I have used it before in a simple project and it worked just fine; but now I am using it in a MQXLite project and its giving two build errors.

    ARM_GCC_Support/ewl/EWL_C/src/stdio/printf.c undefined reference to ‘_pformatter’

    mingw32-make.***[XXX(ProjectName.elf] Error1

    is there anything I am doing wrong?

    Thanks.

    Kaustubh

    Like

  9. Hi Erich
    Thanks for another helpful post! I got to run the console in just a few minutes. However, it seems now, that the rest of my application is freezing. I have a Processor Expert Application and in ProcessorExpert.c main() I make calls to gets() repeatedly every 1 or 10ms and flag triggered to printf(). I call my application parts from several timeticks generated by a 100us PIT. I noticed, that when debugging, the breakpoints are only caught until gets() is called for the first time and then no breakpoints are reached anymore, even though the application should actually pass by this piece of code (PIT-Triggered). However, it stops when new data arrives in the input buffer. Also it appears, that the printf data is only arriving at the remote terminal, when I send some other data from that terminal. Any ideas?
    Cheers, Adrian

    Like

    • Hi Adrian,
      could it be that your 100us PIT is keeping your CPU pretty much all the time in interrupt mode? gets() and printf() are big beasts consuming a lot of CPU cycles. Not sure if this is your problem? The other thing is that printf() and the UART usually are not using flow control, so it is very likely that if you are not able to handle the input/output in a timely fashon, you will loose data.

      Like

      • Hi Erich
        The 100us PIT only sets trigger flags. This structure has proven to be fine using an KL25 at 48MHz. It comes like a set of task triggers (100us, 1ms, 10ms, 100ms), which allow me to make program calls in more or less real time; without task priorities, of course. It rather seems to me, that the gets() method puts the system in some kind of “wait mode”. As I see, I can still break at interrupts in the ISR in Events.c. But everything else called from the ProcessorExpert.c/main() is not running anymore, except the interesting observation that in ProcessorExpert.c/main() the program only breaks, if I send a CR (component setting “Rx new line sequence) at the end of my console entry. So it really seems to be waiting for something. Should I rather use an other method than gets()?

        Like

      • ah, good hint concerning gets()! However getc() seems to do the same thing… 😦 and so does scanf()… in a “normal” OS environment you would probably place this in a seperate thread with a timeout… what do I do in a bareboard situation?

        Like

        • hmm, there must be a way to check if something is in the buffer, and only in that case to call getc()? I assume what you run into is that getc() itself blocks if nothing is in the buffer.

          Like

  10. hello erich,
    i am new to codewarrior, so i am learning some basic programs in it,, so can you help me to send some data to teraterm using UART in KL25Z.

    Like

    • Depends what you have on the PC. If having a serial port, then you need a level shifter (translating the 3.3V signals from the UART to the RS-232 compliant levels), plus a terminal program on the host.
      Same applies to a UART-to-USB converter (you need a terminal program), but then the USB will do the ‘level shifting’ (actually protocol conversion).

      Like

What do you think?

This site uses Akismet to reduce spam. Learn how your comment data is processed.