CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Two way comm over SW UART timing issue

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Mark Logan



Joined: 21 Oct 2009
Posts: 10

View user's profile Send private message

Two way comm over SW UART timing issue
PostPosted: Thu Dec 17, 2009 9:37 am     Reply with quote

Good day all,

First post so be gentle. Firstly I am using a PIC18f452. What I'm trying to do is create a data logger for a digital pressure gauge. This gauge takes an ASCII command ?PRE+carriage return and returns the data in this format:

-0.03 , inH20

I am trying to dynamically update a LCD touchscreen to display whatever data, up until the comma, is shown on the gauge currently. All peripherals, LCD, gauge, etc. are working fine. However, I am having trouble parsing the data over the software UART. Both PIC and gauge are set to 9600 BAUD, no parity, no flow control and the gauge has 1 stop bit. I have the serial receive on the PIC jumped to RB0 to trigger an external interrupt. Once the EXT triggers, a timer interrupt is triggered to last the bit time. Since I am in 9600 BAUD, with a 20MHz external crystal, and I am using timer0(RTCC), the bit time is 69.4 us. Here is all code of any revelance. The issue is in int_EXT and int_timer0:

Code:


#include <18F452.h>

#device adc=8
#device *=16
#FUSES NOWDT                    //No Watch Dog Timer
#FUSES WDT64                   //Watch Dog Timer uses 1:64 Postscale
#FUSES HS                       //High speed Osc (> 4mhz)
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOOSCSEN                    //Oscillator switching is disabled, main oscillator is source
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES BORV20                   //Brownout reset at 2.0V
#FUSES NOPUT                    //No Power Up Timer
#FUSES STVREN                   //Stack full/underflow will cause reset
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOLVP                      //No Low Voltage Programming on B3(PIC16) or B5(PIC18)
#FUSES NOWRT                    //Program memory not write protected
#FUSES NOWRTD                   //Data EEPROM not write protected
#FUSES NOWRTB                   //Boot block not write protected
#FUSES NOWRTC                   //configuration not registers write protected
#FUSES NOCPD                    //No EE protection
#FUSES NOCPB                    //No Boot Block code protection
#FUSES NOEBTR                   //Memory not protected from table reads
#FUSES NOEBTRB                  //Boot block not protected from table reads

#use delay(clock=20000000)
#use RS232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,STREAM=LCD_UART)
#use RS232(baud=9600,parity=N,xmit=PIN_B6,rcv=PIN_B7,bits=8,STREAM=SW_UART)
#use i2c(Master, sda=PIN_C4,scl=PIN_C3)


short LCDrcvd=false;         //rcvd from LCD
short btnpress=false;         //button pressed
short reading=true;            //analog reading
char gaugedat[];            //ASCII reading from Crystal Digital Gauge
char gaugecmd[5]={'?','P','R','E',0x0d};


//interrupt routines

#int_EXT
void isr_ext0_isr(void)
{
   gaugecnt=0;
   disable_interrupts(int_EXT);
   disable_interrupts(GLOBAL);

   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_128);   // setup interrupts
      enable_interrupts(INT_TIMER0);
   
   //fgets(gaugedat,SW_UART);
   if (gaugedat[gaugecnt]==',')
      disable_interrupts(INT_TIMER0);

   enable_interrupts(GLOBAL);
   enable_interrupts(int_EXT);

}
#int_EXT2   //button pressed
void int_ext_isr(void)
{
   if (PROGMODE==0)
   {
      if (flag8)   //CONTINUE TO NEXT SLOT/WEDGE ON GRAPH
      {
         flag9=true;
         flag8=false;
      }
      else         //IF GRAPH SCREEN NOT SHOWN
      {
         if(flag4)   //IF GAUGE IS CONNECTED
         {
            if (!flag2 && !flag1)   //IF BUTTON NOT 'DISABLED' AND NOT 'PRESSED'
               if (presscount<7)
               {
                  presscount++;
                  flag1=true;
               }
         }
         else         //IF NOT CONNECTED
         {
            flag6=true;
            wedgecount=0;
            presscount=0;
         }
      }
   }
   else if (PROGMODE==1)
   {
      flag12=true;
   }
   else if (PROGMODE==3)
   {   
      btnpress=true;   
   }
}
#int_rda   //LCD data
void serial_isr()
{
   if (PROGMODE==0)//PSDS
   {
      buffer[next_in]=fgetc(LCD_UART);
      if ( buffer[next_in]== 0x00 )
      {
         next_in=0;
         if (buffer[0] == 0xd8)
            flag0=true;
      }
      else
         next_in++;
   }
   else if (PROGMODE==1)//TUBE
   {
      buffer[next_in]=fgetc(LCD_UART);
      if ( buffer[next_in]== 0x00 )
      {
         next_in=0;
         flag10=true;
      }
      else
         next_in++;
   }
   else if (PROGMODE==2)//TAP
   {
      buffer[next_in]=fgetc(LCD_UART);
      if ( buffer[next_in]== 0x00 )
      {
         next_in=0;
         if (buffer[0] == 0xd8)
            flag20=true;
      }
      else
         next_in++;
   }
   else if (PROGMODE==3)//PSI
   {
      buffer[next_in]=fgetc(LCD_UART);
      if ( buffer[next_in]== 0x00 )
      {
         next_in=0;
         LCDrcvd=true;
      }
      else
         next_in++;
   }
}
#int_timer0 //digital pressure gauge parsing
void timer0_isr()
{
      set_timer0(84);//bit time for accurate polling, 69.9 us
      if (fgetc(SW_UART)){
         gaugedat[gaugecnt]=fgetc(SW_UART);
         gaugecnt++;
      }   
      
}
#int_timer1   //timer
void timer1_isr()
{

   if (PROGMODE==1)
   {
      timercount++;
      if (timercount > timercount_TUBE)
      {
         flag14=true;
         timercount=0;
      }
   }
   else if (PROGMODE==2)
   {
      timdelay++;
      if (timdelay>timercount_TAP)
      {
         timdelay=0;
         flag22=true;
      }
   }
   else if (PROGMODE==3)
   {
      timercount++;
      if (timercount > timercount_PSI)
      {
         reading=true;
         timercount=0;
      }
   }
}

//INITIALIZES PIC
void initPSI(void)
{
   set_ERR(1);
   setup_wdt(WDT_ON);
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_psp(PSP_DISABLED);
   setup_spi(FALSE);   
   setup_wdt(WDT_OFF);
   setup_timer_0(RTCC_INTERNAL);
   setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
   setup_timer_2(T2_DISABLED,0,1);
   setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
   setup_low_volt_detect(FALSE);   
   setup_oscillator(False);
   output_float(EXT_BUTTON);
   ext_int_edge(2,L_TO_H);
   set_timer1(0);
   enable_interrupts(INT_TIMER1);   
   enable_interrupts(INT_RDA);   
   enable_interrupts(INT_EXT);
   enable_interrupts(INT_EXT2);   
   enable_interrupts(GLOBAL);   
   setup_wdt(WDT_OFF);

}

void PSI(void)
{

        while(1)
             {   
                if (reading)//read&output converted data (reading)
      {   
         set_ERR(22);//add serial command
         setup_wdt(WDT_ON);
         fprintf(SW_UART,gaugecmd);
         
         //fgets(gaugedat,SW_UART);
         fprintf(LCD_UART,"%C%C%C%S%C",LCD_SET_STRING,0x31,0x38,gaugedat,0x00);
         
         
         delay_ms(dt);
         reading=false;
         setup_wdt(WDT_OFF);
         

      }

   }
}


A couple of notes about the code. Any variables that you don't see a declaration for ARE declared, there is MUCH MUCH more code that I have that would just waste your as well as my time by posting here. The entire code that I have compiles without error. Also, I know that the RTCC_DIV_128 is not the right setting for timer0, this is somehow the only way I can get the code to *sort of* work. Here's what's happening: the screen doesn't update at all when the digital gauge is connected, BUT when I use the serial port monitor in the PIC-C compiler, typing in a single character at a time from the keyboard *sometimes* updates the screen. It is as if the interrupt only triggers at the right time roughly half the time. This leads me to believe it is pretty much a timing issue that I can't seem to figure out. Is it something as simple as the timing, or are the other interrupts somehow interfering with the timing of my bit capture? Any help would be greatly appreciated, this is my last resort before I try to somehow add an external HW UART and just try to read from the whole buffer. Thanks ahead of time and sorry for the length of the code and post.

Mark
Ttelmah
Guest







PostPosted: Thu Dec 17, 2009 10:53 am     Reply with quote

First thing, get rid of the line 'enable_interrupts(GLOBAL)' inside the interrupt. This is an absolute 'no no', on the PIC. A search here will find explanations of 'why'...
This will potentially cause disastrous problems later.

Now, as to your main problem, the simple thing you need to understand, is the limitations of the software UART. The receive component, is a program, that _must_ be called before, or as soon as a character starts. Call it any later, and the character _will_ be missed.
The only way you _might_ be able to get this to work, would be to connect the serial input used by the software routine, to a line with an interrupt available, set this to be the only 'high priority' interrupt on the chip, and have the interrupt handler receive one character (probably with the option to sample 'late', since several instruction cycles will have occurred from the actual falling edge). Have this routine write the character to a software buffer, and test this buffer in your timer routine.

Best Wishes
Mark Logan



Joined: 21 Oct 2009
Posts: 10

View user's profile Send private message

PostPosted: Thu Dec 17, 2009 11:15 am     Reply with quote

Thanks for the reply Ttelmah, I've been lurking on this forum for a while now so I know that I'm in good hands with you. enable_interrupts(GLOBAL) is now gone, I seem to remember thinking that solved a problem I had earlier but that is not the case as it's still working.

As for the other suggestion, is this not what I am doing already? I have the serial input from the gauge going to RB0, which triggers the EXT interrupt. Are you saying to try the fgetc() in EXT as a variable, then store it in the array I am writing to in timer0, which acts as the buffer? I can try this method to see if it will work. I have only been in the embedded field for several months now, I have no misgivings admitting that I know next to nothing compared to some of you folks, so if I am missing something fundamental please forgive me.

I have been trying to get this to work for a while now, and am seriously starting to consider using an external UART, I have been checking out the Maxim MAX3110E as a possibility. It has the external UART as well as integrated RS232 capability, it seems that it might be easier to "grab" the data the gauge is giving me if it is already stored in it's own dedicated buffer. I was wondering if anyone might have had some thoughts/experience using an external UART? Thanks again for your help.

Mark
Ttelmah
Guest







PostPosted: Thu Dec 17, 2009 11:31 am     Reply with quote

In the code you have posted, the only 'fgetc', for the software UART, is in the timer interrupt. Also, the software serial receive line, goes to B7, which does not fire INT_EXT.
You don't show the interrupt setups, but if you are using INT_EXT, from the software serial line, it'll need to be set to trigger on the falling edge.
Then, the timer interrupt is probably too fast to actually allow anything much else to happen. It typically takes about 60 instruction times to get into and out of an interrupt. Worse though, as soon as you call fgetc, this interrupt will _hang_, till a start bit is seen. This is why you should only call fgetc, once the hardware has signalled there is a start bit already there (hence on the falling edge of the line).
You need to make the interrupt triggered by the software serial, be a high priority interrupt, if it is to have any hope of working, with all these other interrupts in use. Also use the sample_early option.

Best Wishes
Mark Logan



Joined: 21 Oct 2009
Posts: 10

View user's profile Send private message

PostPosted: Thu Dec 17, 2009 12:01 pm     Reply with quote

Ah I understand the confusion now, I have B7 jumped to B0, I apologize for not stating this earlier. I see what you mean about the falling edge, this is probably what is causing the fgetc() to only work some of the time. I will try this and see how it goes. Thanks again for your help.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group