Corrupted serial on USB via printf

03 Jul 2011

I'm having a problem using printf via serial USB to PC.

For the first few cycles through my code, the output of a "printf" statement is fine, after about 30 seconds, the constant part of the statement becomes corrupted, and even a reset of the board doesn't restore normal function. The variable part of the statement stays properly formatted though !!

Powering down and restarting DOES restore the printf, but again it corrupts permanently after a few more seconds.

I'd be grateful for suggestions about what to look for !

There is an interrupt routine running, but the routine has no printing in it.

Thanks a lot.

Steve

03 Jul 2011

My guess is that your program corrupts itself.

03 Jul 2011

Ad van der Weiden wrote:

My guess is that your program corrupts itself.

Which is a neat trick, considering I'm talking about a constant term in printf such as

printf("State of system %s",statestring); Statestring is fine "State of the system %s" is corrupted, and doesn't reset until there is a complete powerdown.

If this was in in anyway a dynamic part of the program, I could understand it.

Steve

03 Jul 2011

So either the constant string "State of system %s" gets corrupted but not the %s and no \0 are inserted; or the temporary string that printf builds gets corrupted before it is sent out. Can you post how the string gets corrupted and if possible the relevant parts of your program?

03 Jul 2011

Ad van der Weiden wrote:

So either the constant string "State of system %s" gets corrupted but not the %s and no \0 are inserted; or the temporary string that printf builds gets corrupted before it is sent out. Can you post how the string gets corrupted and if possible the relevant parts of your program?

Thanks for your help Ad.

What's the best way to post code here ? Just cut and paste, or is there a method of linking it directly from my compiler space ?

Steve

03 Jul 2011

The string in your buffer might also contain control characters before or after the variable data. This could cause your terminal program to overwrite your constant text with garbage.

You can cut/paste code into your reply by surrounding it with lines which contain <<code>> and <</code>>. For example:

<<code>>
Paste code here
<</code>>

You can also right click on your program in the compiler, publish it and include a link in your posting.

03 Jul 2011

Thanks for the tips guys.

This is the code to drive a large 7 segment LED clock. There are 4 buttons for setting and mode purposes.

If the clock setting button is pressed, the clock enters setting mode, where 12 digits are displayed on the LED to show the time.

As it stands now, the program enters "display" mode, if no keys on the hardware or no keys on the serial terminal are pressed. Then it starts to spit out a string parsed off the RTC in a timer interrupt function parsing it into a string "DispDigits"

In run mode, a variable for the serial port, Settingdigits is assigned to DispDigits, in setting mode, DispDigits is assigned to Settingdigits.

Corruption happens in the final loop

 while (true)
    {wait(1.0);  
     pc.printf("Time Is %s \r\n",SettingDigits.c_str());
      
     } //end while loop. 

When "Time is" becomes replaced by garbage from the upper half of the ascii codemap

#include "mbed.h"
#include "DebouncedIn.h"

#include "string.h"
#include "string"

#include "stdio.h"
#include "stdlib.h"

///define SPI for displays
SPI spi(p11, p12, p13); // mosi, miso, sclk
 //spi.format (8,0);

DigitalOut Latch(p14);
DigitalOut OE (p15);
//Every 8th bit is a decimal point 

DebouncedIn button1 (p30); //buttons debounced by DebouncedIn.h
DebouncedIn button2 (p29);
DebouncedIn button3 (p28);
DebouncedIn button4 (p27);

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);

Ticker Tsystem, TTimeout;


int dispblink; //blinking character counter. 
// time units.
//char seconds,minutes,hours,day,month,year;

//Define character map for LED.
const char Seg7[11] = {0,1,2,4,8,16,32,64,128,128,128}; //0..9 are digits and 10= space
bool blink[12]  ;
char spidata[12];
char Sec_dp; //which bit in the SPI needs to be on.


string DispDigits,NewDigits,SettingDigits ;

int charpos,charctr;
int Display_mode,setctr;
//modeconstants
    int  leadsuppress=1;
    int  flashingseconds=2;
    int  clocksetting=4;


//timers
bool timedout, resettimeout;
bool waiting;
int waitctr,timingctr,Mychar;

//clock structures
struct tm  Clocktime;
time_t  Clocksecs;  

void timerout ()
 {  if (resettimeout) {timingctr=10;resettimeout=false;};
    timingctr--;
    if (timingctr==0) {timedout=true;} else {timedout=false;};  
  };

void DisplayMonitor()
    // Every 1/8 second, check to see if display needs to be updated 
    
   {char chardata;

     if (dispblink>7) { //reset blinking timer
        waiting=false;
        dispblink=0;}       
       else dispblink++;  
  
     if ((Display_mode & clocksetting) == 0) { //Get RTC time into a datastructure. 
          //read rtc into TM
          Clocksecs=time (NULL);
         led1=!led1;
           char buffer[12];
           strftime(buffer, 12, "%I%m%S%d%m%y", localtime(&Clocksecs));
           DispDigits=buffer;
           SettingDigits=DispDigits;
          } else {DispDigits=SettingDigits;};
         
      //Disp digits now has blanking/blinking sorted out      
      //Build SPI data for tranmission. 
       NewDigits=DispDigits;  
       for (charctr =0; charctr<=12; charctr++) {
         if (dispblink>4) {
            if (blink[charctr]==true) {
              NewDigits[charctr]=10;} else {NewDigits[charctr]=DispDigits[charctr];};         //Blank character temporarily 
             
         int Ord;
         Ord = int (NewDigits[charctr]) - int ('0');        
         chardata = Seg7 [Ord];  
         if (Display_mode && flashingseconds) {
            Sec_dp=atoi(NewDigits.substr(4,2).c_str()) % 60; 
            if (charctr==Sec_dp) {
               chardata=chardata | 8;} else {chardata=chardata & 0x11110111;};  // with whatever to mask on second DP 8 might be wrong
         spidata[charctr]=chardata;   
              }; 
            };
            
       //clock out the prepared data.
       
       Latch=false;
       OE=false;
       for (charctr =0;charctr<=12; charctr++) {
        spi.write(spidata[charctr]);
         }; 
       Latch=true;
       OE=true;    
     };
   }; //end of display monitor
 
int main(){

    Tsystem.attach (DisplayMonitor,0.125);
    TTimeout.attach (timerout,1.0);
    Serial pc(USBTX, USBRX); // tx, rx
    pc.printf("Hello Clock 5.00 \n\r");
    timedout=false;
    Display_mode=0;
    DispDigits =' ';
    NewDigits =' ';
    wait(1);
    if (pc.readable() ) {Mychar=pc.getc();};
    //check buttons are pressed
    if ((button3.read() ==true) | (Mychar=='l')) 
            {Display_mode=Display_mode+leadsuppress;};
            
    if ((button4.read() ==true) | (Mychar=='f')) 
            {Display_mode=Display_mode+flashingseconds;};
            
    if  ((button1.read() == true) | (Mychar=='c'))
            {Display_mode=Display_mode+clocksetting;};
   
    pc.printf("Got Mode\n\r");
    Display_mode=clocksetting;
    //if button pressed enter setting mode
    //freeze display with current time.  

    if ( ( button1.read() ==true ) || (Display_mode == clocksetting))  {
    //wait for mode setting button to be released
        pc.printf("In setting mode\n\r");
        setctr='0';
        charpos=0;
        SettingDigits="000000000000";
        resettimeout=true;  
        waiting=false; 
        while (timedout== false) {
        //In setting mode 
         Mychar=0;
        if (pc.readable() ) {Mychar=pc.getc();};
     
         if ( ((button1.read()==true) & (button2.read()==false)) | (Mychar=='.' )) 
                 {resettimeout=true; 
                 if (charpos < 12) 
                   {charpos++;if (charpos==4) charpos=6;} //skip seconds on way up 
                    else charpos=0;setctr=NewDigits[charpos];};
                    
         if ( ((button2.read()==true) & (button1.read()==false)) | (Mychar==',' )) 
                 {resettimeout=true; 
                 if (charpos > 0) 
                   {charpos--; if (charpos==5) charpos=3;} //Skip Seconds on the way DOWN
                   else charpos=12;setctr=NewDigits[charpos];};
                   
         if ( ((button3.read()==true) & (button4.read()==false)) | (Mychar=='[' )) {resettimeout=true; if (setctr<'9') setctr++;else setctr='0';};
         if ( ((button4.read()==true) & (button3.read()==false)) | (Mychar==']' )) {resettimeout=true; if (setctr>'0') setctr--;else setctr='9';};
     
         SettingDigits[charpos]=setctr;
         pc.printf("Charpos Setctr %d %s \r\n",charpos, SettingDigits.c_str());
         blink[charpos]=true;
         //Add key delay, so the display doesn't scroll too fast.
         wait(0.25);
         }
           pc.printf("Finished Setting:Set RTC %s \n\r",SettingDigits.c_str());
        // As we exit setting mode, adjust RTC to read new time. 

         Clocktime.tm_hour = atoi  (SettingDigits.substr(0,2).c_str());        
         Clocktime.tm_sec  = int (0);
         Clocktime.tm_min  = atoi (SettingDigits.substr(2,2).c_str());
         Clocktime.tm_mday = atoi (SettingDigits.substr(6,2).c_str());
         Clocktime.tm_mon  = atoi (SettingDigits.substr(8,2).c_str())+1;
         Clocktime.tm_year = atoi (SettingDigits.substr(10,3).c_str())+100;
         
         pc.printf ("Tm_hour %d \r\n",Clocktime.tm_hour);
         pc.printf ("Tm_Min %d \r\n",Clocktime.tm_min);
         pc.printf ("Tm_sec %d \r\n",Clocktime.tm_sec);
         pc.printf ("Tm_mday %d \r\n",Clocktime.tm_mday);
         pc.printf ("Tm_mon %d \r\n",Clocktime.tm_mon);
         pc.printf ("Tm_year %d \r\n",Clocktime.tm_year);
         set_time(mktime(&Clocktime));
         pc.printf("Parsed clock into RTC ");
       }; //end setting mode
 
   pc.printf("In Clock Mode\n\r");
//   Display_mode=Display_mode || 0x111110111; //turn off clock setting mode

     Display_mode=0;
    while (true)
    {wait(1);
     pc.printf("Time Is %s \r\n",SettingDigits.c_str());
      
    } //end while loop. 
     
 
      
}; // end program

03 Jul 2011

hmm, I'm afraid I'm not familiar with the string type. I really don't know the semantics of this type. However, even though you seem to use only static and automatic variables, I would not be surprised that the string type allocates space on the heap. How this causes the effect you observe, I really don't know.

03 Jul 2011

Hi Ad,

I'm coming into Mbed and C++ from 25 years in Pascal and Delphi programming ! The String type seemed to be a natural construct for me. I didn't realise it was novel in C++

Steve

03 Jul 2011

This code looks a bit suspicious to me:

char buffer[12];
strftime(buffer, 12, "%I%m%S%d%m%y", localtime(&Clocksecs));

You have only reserved enough characters for the digits themselves and not the NULL terminator. If this buffer is too short then strftime will return 0 and leave the buffer in an indeterminate state (which could mean corrupted.) buffer should contain room for at least 13 characters. I also suspect that you wanted the %m after %I to be %M for minutes and not month. Is this code running in your failure scenario? If so it could lead to problems with the contents of SettingDigits.

You might also want to printf("SettingDigits length = %u\r\n", strlen(SettingDigits.c_str())) to see if it returns more than the expected 12.

03 Jul 2011

Wow. Well done for spotting that potential problem. I'll take a look at it in after dinner.

You're also right on the %m / %M thing too.

Thanks a lot Adam. I've been banging my head on that one all day.

Steve

03 Jul 2011

Adam Green wrote:

This code looks a bit suspicious to me:

char buffer[12];
strftime(buffer, 12, "%I%m%S%d%m%y", localtime(&Clocksecs));

Adam, Many thanks, that's fixed it. I increased the size of buffer to 16 - problem gone.

Steve

03 Jul 2011

Excellent! Glad it helped.