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

problems with high baud rates and #use rs232

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







problems with high baud rates and #use rs232
PostPosted: Thu Jun 10, 2004 3:15 pm     Reply with quote

my program uses a timer1 interrupt to run PWM on a number of pins of a PIC 16F877. i listen over serial (#use rs232) to commands from a Rabbit RCM2200 microcontroller. the program works fine at 28.8k baud rate, but i am running into problems when i try to increase the baud rate to 57,600. i am clocking the PIC at 20 MHz.

i'm not sure how #use RS232 configures the USART, and perhaps the problem is linked to this ... maybe a buffer gets overloaded with too much incomming data.

another problem could be the interrupt frequency ... but i tried slowing this to 1/10 of the current speed, and it still can't handle 57.6k.

the program will run for a few seconds at 57.6k, but then crashes - it won't communicate over serial. i am sending data at the rate of 30 characters a second, so i'm surprised by the results.

here is the source:

Code:
#include <16f877.h>
#include <stdlib.h>
#FUSES HS,NOWDT,NOPROTECT,NOBROWNOUT,NOCPD,NOLVP //High Speed Osc, No code protect,
         //No brownout protect, no something??, no low-voltage programming

#USE FAST_IO(A)
#USE FAST_IO(B)
#USE FAST_IO(C)     //Use Fast IO means compiler assumes you've set tristate
#USE FAST_IO(D)     //registers for the ports correctly before read/write ops
#USE FAST_IO(E)

#use delay (clock=20000000)    //tells delay clock speed for calculating time
#use rs232(baud=57600, xmit=PIN_C6,rcv=PIN_C7, brgh1ok, errors)   //serial setup stuff

#DEFINE NUM_LEDS 30        //really need a comment here, huh

int CONST LED_PINS [NUM_LEDS]=            //LED Pin definition tablex
{
PIN_A0,PIN_A1,PIN_A2, 
PIN_A3,PIN_A5,PIN_E0,
PIN_E1,PIN_E2,PIN_C0,
PIN_C1,PIN_C2,PIN_C3,
PIN_D0,PIN_D1,PIN_D2,
PIN_B5,PIN_B6,PIN_B7,
PIN_B2,PIN_B3,PIN_B4,
PIN_D7,PIN_B0,PIN_B1,
PIN_D4,PIN_D5,PIN_D6,

PIN_D3,PIN_C4,PIN_C5   //Test LED
};

signed int speed [NUM_LEDS];   //used for modulation test
                  
signed int LED_VALS [NUM_LEDS];     //holds LED PWM values
signed int NEW_LED_VALS [NUM_LEDS];   //update *this* table, interrupt copies it over automatically
                                      // OR ELSE you get bad boundary condition errors b/c of optimizations

int control,control2;         //Variables to hold serial data
int frame=0;                  //Counts how many times PWM interrupt has occured
int loop,loop2;               //Temporary loop variables
int1 toggle=TRUE;             //Used for testing in previous versions


//NEW : changed the number of frames to 50

#INT_TIMER1
void do_pwm()
{
   loop=0;
  for (loop=0;loop<NUM_LEDS;loop++)            //Loop through all 30 LEDS
   {
      if (LED_VALS[loop]==frame)               //If an LEDS value==frame counter, turn it off
        *(LED_PINS[loop]/8) &= (0xFF^(1<<(LED_PINS[loop]&7))); //Turns off LED[loop]
   }
   frame+=1;                                  //Increment the frame counter
   if (frame==100)           //If we're at frame 100 restart the PWM cycle
   {
      frame=0;               //Reset frame to 0
     for(loop=0;loop<NUM_LEDS;++loop)       //Turn LEDS on
     {
       LED_VALS[loop]=NEW_LED_VALS[loop];  //Update all LED Values from the new table

       if(LED_VALS[loop]!=0)                //Only turn on if LED value not equal 0
           *(LED_PINS[loop]/8) |= (1<<(LED_PINS[loop]&7)); //Turn LED on
      
     }
   }

   //NEW : slowing the interrupt cycle
   set_timer1(64935); // 400 instrctions between interrupts
   //set_timer1(65335);  //When timer rolls over at 65535 interrupt will occur again
                       //so 65535-65335=200 instructions later int happens again
}

void main()
{
   int16 a=0;
   signed int temp;
   SETUP_ADC(ADC_OFF);                 //Turn ADC off
   SETUP_UART(TRUE);                   //Turn on hardware UART
   SET_UART_SPEED(57600);              //Set hardware UART speed
   SET_TRIS_A(0);                      //Port A all outputs
   SET_TRIS_B(0);                      //Port B all outputs
   SET_TRIS_C(0x80);                   //Port C all outputs except for serial recieve pin
   SET_TRIS_D(0);                      //Port D all outputs
   SET_TRIS_E(0);                      //Port E all outpus
   SETUP_TIMER_0(RTCC_INTERNAL);       //Turn on Timer0 (8bit)
   SETUP_TIMER_1(T1_INTERNAL);         //Turn on Timer1 (16bit) used for PWM interrupt
   ENABLE_INTERRUPTS(GLOBAL);          //Enable interrupts
   ENABLE_INTERRUPTS(INT_TIMER1);      //Turn on Timer1 interrupt for PWM
   srand(37);                          //seed random # generator (for modulation test)
                                                         
   {
      LED_VALS[loop2]=(rand()/400)+10;
      speed[loop2]=((rand()/3000)-5);
      if (speed[loop2]==0) speed[loop2]=1;
   }
//   printf("Welcome to LED Testing\n\r");
   putc('x');                          //Send an 'x' over serial to let rabbit know i'm alive
   while (TRUE)                     //Main Loop
   {
      a++;
     if (kbhit())                      //check if there is a character in the serial buffer
        if(getch()=='s')               //if an 's' is recieved we want to set an led value
         {   
  //          printf("Set LED ");     //used for serial debugging
            while (!kbhit()) ;       //wait in loop for next character [note loop is empty]
            control=getch();         //control stores which LED to modify
            if ( (control>0) && (control<=NUM_LEDS))  //Is control in the right range?
            {
//               printf("%u to ",control);
               while(!kbhit()) ;     //Wait for the new value
              {
                 control2=getch()-1;        //Grab the new value
                  NEW_LED_VALS[control-1]=control2;  //Put the new value in the NEW table,
                                                     //Which is updated every cycle (100 frame)
//                  printf("%u\n\r",control2);  //debuggin stuff
                  putc('s');               //Send out an 's' as confirmation
               }
            }
           
         }

   }
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Jun 10, 2004 8:40 pm     Reply with quote

Well, your isr is massively long. Maybe you can't help that.
But at 57600 baud, one character period is 173 us.
The hardware USART's receive fifo is 2-deep, plus the
incoming shift register.

I didn't figure out exactly how long your ISR takes,
I just glanced at it. But it's got to go through at least
one of those 30-iteration for-loops every interrupt.
The amount of ASM code is massive, including the
calls. It adds up.

I think you need to time it. Either do it empirically
with logic analyzer or scope (put in code to put out
a pulse at the start of the ISR, and another pulse at
the end), or add it up by hand. That analysis will
tell you if it's too long and is causing you to lose chars.
Sergio



Joined: 16 Oct 2003
Posts: 11
Location: Arkansas, USA

View user's profile Send private message

PostPosted: Thu Jun 10, 2004 10:31 pm     Reply with quote

I am using a software interrupt at 115200 baud (20Mhz xtal) without any problems. I did discover that kbhit was too slow for those speeds. Instead I rolled up a simpler one that just keeps looking if the line at the pin went down. I am making the assumption that if it goes down then a character is being sent.

I also never recive more than two characters at a time hence a buffer of only 2. Which makes buffering simpler.

I need to simplify it but here's my code:

#int_ext
void serial2()
{
Display_LCD_Flag=1;
timeout=0;
timeout_error=FALSE;

#use RS232(baud=115200, xmit=PIN_B6, rcv=PIN_B0) //Amulet Software port
while(RCV_PIN&&(++timeout<765)); //This gives about 2ms timeout

if(!RCV_PIN)
serial_rcv[0]=getc();
else
timeout_error=TRUE;

timeout=0;
while(RCV_PIN&&(++timeout<765)); //This gives about 2ms timeout

if(!RCV_PIN)
serial_rcv[1]=getc();
else
timeout_error=TRUE;

menu=serial_rcv[1];
}
_________________
Sergio
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Fri Jun 11, 2004 6:50 am     Reply with quote

As PCM Programmer already said: 57000 baud results in 173us per character.
At 20MHz this is equivalent to 865 instructions. Your interrupt routine should take no longer to execute than this.

A quick study of the assembly code of your interrupt handler showed you are using a minimum of 420 instructions in every interrupt. This is safe, but every 100th interrupt you are using at least 1320 instructions and with all leds on this can go up to at least 2300 instructions. This is too long!

The UART has a 2 bytes FIFO buffer, but your interrupt routine takes too long to execute and you will get an occasional overrun error. This error will be automatically cleared by the 'errors' parameter in your #use rs232 statement. Your protocol will be 'out of sync' and your program hangs.

The following suggestions:
1) Make your interrupt routine faster. Especially every 100th loop is a killer, maybe you can spread this over multiple calls?
2) Add a timeout to your protocol, so it can recover from errors.
3) Remove the setup_uart() and set_uart_speed() calls, you don't need them as #use rs232 is setting everything ok. You only need those functions if you want to change a setting during runtime.

Carlo
jroth
Guest







PostPosted: Fri Jun 11, 2004 1:59 pm     Reply with quote

Thanks.

I optimized the interrupt loop and have been able to get the program to run at 57600 baud.
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