printf hangs after several lines

12 Nov 2010

While using printf statements to debug some ADC-related code, I encountered a "hang" condition in the serial output. I have distilled the code into the following test program. In my system, with the program's four analog inputs connected to +3.3 volts, this test program will print 8 diagnostic lines, then hang.

Changing almost anything in the code makes the problem seem to vanish -- for example, commenting out the floating point variable assignments immediately following the while() statement will let things execute properly. So it seems quite timing-specific.

Could there be some sort of issue between the Ticker interrupts and the serial interrupts...leading to a deadly embrace, perhaps?

Thanks for any light you can shed.

hb

/******************************************************** 
/   PC serial bug demo
/ Run this program with a PC connected via the USB cable.
/ I used XP Pro SP3, with Hyper Terminal v5.1
/ The default comm settings are used (9600-8-N-1)
/
/ Analog input pins15, 16, 19, and 20 are connected directly
/ to 3.3 volts for this test.
/
/ Output ceases after the "killer" printf has executed
/ eight times.
********************************************************/

// Included files
#include "mbed.h"

// mbed declarations
AnalogIn    analog0(p20);
AnalogIn    analog1(p15);
AnalogIn    analog2(p16);
AnalogIn    analog3(p19);
Ticker      timer;
Serial      pc(USBTX, USBRX); // tx, rx

// Constants and strings
#define VERSION 7
#define sampledelay_us  2000     // Interval between ADC samples

// Interrupt (timer) routine
void ADC_sample() {
    float foo;
       
    foo = analog0.read_u16();     
}

// Main program
int main () {
    float fvar1 = 0;
    float fvar2 = 0;
    float fvar3;

// Initialization
    pc.printf("\r\n\nPC  test, v. %d.\r\n", VERSION);
    timer.attach_us(&ADC_sample, sampledelay_us);

//  Signon
    printf("\r\nPC serial  lockup test program.\r\n");

//  Test
    while (1) {
        fvar1 = analog1;
        fvar2 = analog2; 
        fvar3 = analog3 *330;
// Killer printf statement follows... 
        printf("fvar1 = %7.6f, fvar2 = %7.6f. Temp (C) = %8.6f; (F) = %8.6f).\r\n", fvar1, fvar2, fvar3, 32 + 9*fvar3/5); // Hangs after 8 lines
        wait(0.5);
    }
}

16 Nov 2010

Printf is deadly with almost any interrupts as far as I can tell.

you can use sprintf to a buffer followed by a loop of putcs - see Cookbook/Serial Interrupts

Also might disable interrupts around the printf - if your code can tolerate the increased latency.

 

 

 

16 Nov 2010

Hi,

You may find this has nothing to do with printf().

You are reading from the analog block both outside and inside an interrupt i.e. you could initiate a read from the analog block with a read from analog1, and wait for it to complete. Then get an interrupt and restart an analog read again. When the interrupt read completes, you'd return from the interrupt, and the first read is now waiting to complete, but it never will.

So for example, you could try:

__disable_irq();
fvar1 = analog1;
fvar2 = analog2; 
fvar3 = analog3 *330;
__enable_irq();

Not sure if that is the problem, but worth a try.

Simon

17 Nov 2010

Hi Simon.

Your explanation fits the facts perfectly. And disabling interrupts in the main body of the code during analog conversions does indeed fix the problem, as you predicted.

I got lulled into complacency with the ease of use of the magic libraries, and just sort of assumed the conversion was instantaneous.

Note to self: RTFM before posting any more bug reports :-)

Thanks for the help.

--

hb

17 Nov 2010

printf() should never need interrupts off unless

1. Someone incorrectly tries to use printf() or any other library call from within an interrupt service routine (ISR) or a function called by an ISR

2. You have a multi-threaded situation with preemptive task scheduling - printf() is not normally reentrant.

17 Nov 2010 . Edited: 17 Nov 2010

Here is a short example based on longer code I was working on that made me suspect the printf issues. It works fine like this, but just remove the interrupt disable and enable lines and it hangs right away on my mbed. So something with the shared UART might be the issue or some unexpected conflict with printf and getc, but someone else said in another forum post that even a printf to USB serial (with serial rx interrupts enabled on another serial port UART) made his code hang. Adding a while(device.readable()) loop in the interrupt code to empty the rx buffer does not change anything, same thing happens.

I used sprintf with putcs instead of printfs and the problem goes away and got the same report back about putcs fixing it from the person using the USB serial printf with interrupts. I guess writing my own getc code going directly to the UART data register might fix it also? I would think getc is pretty simple and was a bit surprised by this problem. So I have at least one fix, but thought it was a bit strange that it works this way.

#include "mbed.h"

DigitalOut myled(LED1);
DigitalOut myled2(LED2);
Serial device(p9, p10);
//jumper p9 to p10 for loopback test
void rx_interrupt();
char temp;

int main() {
    device.baud(9600);
    device.attach(&rx_interrupt);
    while (1) {
        myled = 1;
        __disable_irq();
        device.printf("ABC");
        __enable_irq();
        myled = 0;
        __disable_irq();
        device.printf("ABC");
        __enable_irq();
    }
}
void rx_interrupt() {
    myled2=1;
    temp = device.getc();
    myled2=0;
}