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():
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:
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):
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:
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:
💡 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:
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:
Now the errors are resolved, and I can generate 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:
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 🙂
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()”?
LikeLike
Hi, not sure if I understand what you want to accomplish? If you want to write to the LCD using printf(), I think this is not a good idea. Possible, but then you need to write a wrapper for the LCD (dealing with string length, \n conversion, etc). I would not do it that way. If you want to use printf() like things, then use sprintf(), write to a buffer and then send it to the LCD with the LCD1_WriteString().
If you want to use normal printf() to write to a console, then see https://mcuoneclipse.com/2013/02/07/tutorial-printf-with-and-without-processor-expert/.
LikeLike
Hi, I mean to do both things:Write toward LCD (withouth fprintf() ), and send the same string (which I am sendign to the LCD) using fprintf toward the console.
LikeLike
Hello, I simply would add a second call with printf() which writes the text to the console. As simple as that?
LikeLike
I have tried this:
for(;;) {
uint8_t cnt;
uint8_t buf[5];
LCD1_GotoXY(2,1);
UTIL1_Num16uToStr(buf, sizeof(buf), cnt);
LCD1_WriteString((char*)buf);
// printf(buf);
// printf(*buf);
cnt++;
WAIT1_Waitms(100);
}
(but without the “//”). I have errors.
LikeLike
Hello,
You need to add the library option and low level UART support. See https://mcuoneclipse.com/2013/02/07/tutorial-printf-with-and-without-processor-expert/.
And: printf(*buf) will not work. And depending on what you have in your string, using printf(buf) will be dangerous too. Better use printf(“%s”, buf);
LikeLike
Pingback: Be Aware of the Baud Problem | MCU on Eclipse
Pingback: printf() with the FRDM-KL25Z Board and without Processor Expert | MCU on Eclipse
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
LikeLike
Hi Thiago,
this is really hard to guess: I recommend you use a logic analyzer to see what is going on with you pins?
LikeLike
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.
LikeLike
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.
LikeLike
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?
LikeLike
Hi Daniel,
it is in Cpu.c (inside Generated_Code).
LikeLike
ok! thanks
LikeLike
Hi Erich, what is the difference between asynchroserial component and cosole IO component ??
LikeLike
Hi jose,
the ConsoleIo component is really only a small wraper for terminal usage and printf() as shown in this article, while the Asynchroserial is a full UART/serial componet.
LikeLike
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.
LikeLike
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.
LikeLike
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!
LikeLike
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
LikeLike
Hi Kaustubh,
have you created the project with ‘No I/O’ option? I guess this is whay you are missig this pformatter in the library.
Erich
LikeLike
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
LikeLike
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.
LikeLike
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()?
LikeLike
Yes, gets() waits for a line ending (CR/LF). Can you use getc() instead?
LikeLike
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?
LikeLike
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.
LikeLike
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.
LikeLike
Hi sneha,
this tutorial is exactly about this, how to send data to a terminal program either through UART or USB CDC. Which terminal program you are using really does not matter.
LikeLike
hii erich,
how to receive the string from KL25Z board to the PC using UART?
LikeLike
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).
LikeLike