Good Old printf()

Good old printf() is probably the oldest debugging tool ever used, I mean beside a light bulb (nowadays replaced by an LED) … yet it represents a pretty sophisticated one when working in a deeply embedded control project. If you take the standard definition of the printf() function (as in the ANSI C standard) it assumes that you will be able to convert and print integers and floating point numbers of any size, and use a myriad of formatting options.

Assuming you have a serial port (UART) to spare for the interface with a terminal (Hyper- if you use a PC) it is the code space requirements (even excluding the floating point support) for a full implementation that makes it a difficult choice. It could be pretty large (several K of code), comparable if not more than the entire program memory available on some 8-bit microcontrollers.

So in the past I have used a bit of everything to avoid relying on printf() for my debugging/diagnostic output.  Mostly macros including itoa() followed by puts() and a mix of other hand made optimizations for simple hex output.

In the 16-bit and 32-bit world, there is a little bit more room to breathe, and  with a smart compiler’s help, things get manageable.

With MPLAB C32 for example you can count on the printf() function to be smart enough to avoid carrying all the floating point extra weight in your project, if you elect not to use it.  Use the linker option to exclude the floating point libraries  in the Project Options dialog box.

Also the “stdout” stream, which is the default output “channel” associated with all the printing functions in “stdio.h” is by default already associated to the UART2 serial port. This means that if you are using the Explorer16 demonstration board, you don’t need to re-direct stdout (creating a custom _mon_putc() function as suggested in chapter 9 of the PIC32 Explorer book) but you are still responsible for initializing properly the UART module and perhaps most importantly choosing a suitable baud rate.

The choice of the baud-rate being perhaps the trickiest part of the plan. In fact while we all agree that the faster the merrier, there are limits on how accurate the baud rate can be give the oscillator options selected for your hardware platform.

First of all you want a crystal to be used for your oscillator input, unless you are comfortable with operating at room temperature only ( or a very limited temperature range) in which case the internal RC oscillator (FRC) could be used.

Secondly depending on the selected configuration of the PLL (if used) and the resulting clock speed you will have to determine if the desired baud rate can be achieved with the required accuracy. UARTS need better than  +/- 2% accuracy to inter-operate correctly so you need to do the math (this is well documented in all PIC data sheets).

Using the PIC32 peripheral libraries you can initialize UART2 as follows:

OpenUART2( UART_EN, UART_TX_ENABLE,  mUARTBRG(FPB, brate));

Notice the use of the mUARTBRG() macro to calculate the baud rate divider for you.

This is very convenient, but it works only if you are ok using the divide by 16 (default) mode of the UART baud rate generator.

Sometimes, even if the main clock frequency would allow the use of the div16 mode, the resulting accuracy could be insufficient or simply worse than the one obtained by using the div4 mode instead.

So here is a solution to initialize UART2 for printf() debugging use and make the decision between div4 and div16 automatic:

void init_dbg_uart( int baudrate)
{   // initialize the UART2 for default stdout redirection
    // optimize baudrate divider for best approximation
    int c1 = UART_EN;
    int c2 = UART_TX_ENABLE;
    int c3 = FPB/16/baudrate;
    int c4 = FPB/4/baudrate;

    // check if /4 gives a better approx
    if ((FPB/16.0/c3)>(FPB/4.0/c4))
    {   // use the /4 factor
        c3=c4;
        // select BREGH =1
        c1 |= UART_BRGH_FOUR;
    }
    // enable UART2 (RS232) TX on Explorer16 board
    OpenUART2( c1, c2, c3-1);
 }

Just remember to define FPB with the value of your peripheral bus clock of choice.

This entry was posted in PIC32, Tips and Tricks and tagged . Bookmark the permalink.