Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Junebug multi-interrupt prog fails at 115200 baud

Status
Not open for further replies.

futz

Active Member
I have the Junebug controlling two servos (using modified Mike, K8LH's 8-servo algorithm that I found here) driving a pan-tilt, my CMUcam and a 2-wire LCD. All works pretty well at 19200 baud, but that data rate is unacceptably slow. So I rewrote for high-priority interrupt-driven receive at 115200 baud, and put the servo updates as low-priority.

If I disable the servo interrupt that works fine, but when I turn on that second interrupt things fall apart. The code still seems to still sorta be alive in there - the servos twitch a bit when the ball is in front of them, but otherwise they aren't under my control and just wander around aimlessly. The LCD displays gibberish, only occasionally flashing something sensible.

Though it might be something dumb in my code, I suspect 115200 baud may be a bit much to ask of an 18F1320 running on the 8MHz internal clock. Do you think I should move to an 18F1320 on a breadboard with 20MHz clock?
 
Last edited:
The 18F1320 can only go 8MHz on its internal clock. Plus the 1% accurate osc may not be accurate enough at 115K
Have you tried 56K?
 
The 18F1320 can only go 8MHz on its internal clock. Plus the 1% accurate osc may not be accurate enough at 115K
Have you tried 56K?
The camera will do 38400, but not 56K. I was too lazy to calculate my own SPBRG for 38400. Used the precalculated numbers out of the datasheet, and the next thing I can use (without having to think too much) after 19200 is 115200.

Anyway, it's not such a big deal to breadboard up an 18F1320 with a 20MHz crystal and try it. Maybe I'll try that this afternoon.
 
Another route would be to use 18F1330 in place of the 18F1320 on the Junebug. It allows you to use the internal clock with the PLL for 32MHz.

It also has 3 breapoints. :)

EDIT: Check the datasheet to make sure it has everything you need. The steal a timer or 2 to beef up the PWM hardware.
 
Futz,

You should have about 86.8 usecs or approximately 170 instruction cycles between bytes with a 115200 baud rate. Your modified K8LH soft 8-channel Servo ISR code is relatively short so you should keep it at the high priority vector to avoid servo 'jitter'. Your serial ISR should be on the low priority vector.

If your processing overhead is causing you to lose incoming characters then you might consider implementing an Rx circular buffer.

Code:
//--< typedef and defines >------------------------------------------

typedef unsigned char u08;

#define buffer_full RxPush+1 == RxPull

//--< variables >----------------------------------------------------

u08 RxBuff [16]@0xA0;       // 16 byte circular Rx buffer, A0..AF
u08 RxPull = 0xA0;          // circular Rx buffer pull (rd) pointer
u08 RxPush = 0xA0;          // circular Rx buffer push (wr) pointer

//--< functions >----------------------------------------------------

u08 rdy232()                // test for Rx character available
{ return(RxPull!=RxPush);   // 0 = buffer empty, 1 = char available
}
u08 get232()                // pull Rx char from circular buffer
{ fsr = RxPull;             // setup buffer indirect address
  RxPull = fsr + 1;         // increment circular 'pull' pointer
  RxPull.4 = 0;             // pseudo %16 (circular A0..AF range)
  return indf;              // return Rx character
}
Code:
void isr_lo()
{ fsr = RxPush;             // setup buffer indirect address
  indf = rcreg;             // push Rx char into circular buffer
  if(!buffer_full)          // if buffer not full
  { RxPush++;               // increment circular 'push' pointer
    RxPush.4 = 0;           // pseudo %16 (circular A0..AF range)
  }
}
 
Last edited:
Hey Futz,

It just occured to me that you can only update a servo position once every 20 msecs. So, why would 19200 baud be too slow?

Mike
 
Last edited:
Are there any 18 pin 18F' PIC devices with two CCP modules? If so, use both CCP modules in PWM mode which would allow you to use the low priority interrupt for the servo ISR since you've got hundreds of microseconds to service it, not to mention completely 'jitter' free hardware servo outputs;

Code:
unsigned int frame = 20;
unsigned int pulse1;
unsigned int pulse2;
unsigned int servo1 = 1500;     // # of 1-usec 'ticks' (1500-us)
unsigned int servo2 = 1500;

/*****************************************************************
 *  K8LH 2-Channel Dual CCP Hi-Rez 'PWM' Servo Algorithm Driver  *
 *****************************************************************/
void isr_hi ()
{ if(PIR1bits.TMR2IF)
  { PIR1bits.TMR2IF = 0;        // clear TMR2 interrupt flag
    if (frame == 20)            // 20 PWM frames/20 msec period
    { frame = 0;                // reset frame number
      pulse1 = servo1;          // setup work variables
      pulse2 = servo2;          //
    }
    frame++;                    // increment frame number
   /**************************************************************
    *  setup CCP1 PWM duty cycle for next 1000 usec PWM 'frame'  *
    *                                                            */
    if(pulse1 > 1000)           // if pulse1 > 1000 usecs
    { CCPR1L = 250;             // do a 100% duty cycle frame
      pulse1 -= 1000;           // subtract 1000 usecs
    }
    else                        // do a variable or 0% frame
    { CCP1CONbits.CCP1Y = (pulse1 & 1);
      CCP1CONbits.CCP1X = (pulse1 & 2);
      CCPR1L = (pulse1 >>= 2);
      pulse1 = 0;               // remaining frames are %0
    }
   \**************************************************************
    *  setup CCP2 PWM duty cycle for next 1000 usec PWM 'frame'  *
    *                                                            */
    if(pulse2 > 1000)           // if pulse2 > 1000 usecs
    { CCPR2L = 250;             // do a 100% duty cycle frame
      pulse2 -= 1000;           // subtract 1000 usecs
    }
    else                        // do a variable or 0% frame
    { CCP2CONbits.CCP2Y = (pulse1 & 1);
      CCP2CONbits.CCP2X = (pulse1 & 2);
      CCPR2L = (pulse2 >>= 2);
      pulse2 = 0;               // remaining frames are %0
    }
  }
}
 
You can get 0.16% bit rate error for 38400 baud and 8 MHz INTOSC by using BRGH = 1 and either BRG16 = 0 (SPBRG = 12) or BRG16 = 1 (SPBRG = 51).
 

Attachments

  • Futz SPBRG.PNG
    Futz SPBRG.PNG
    29.2 KB · Views: 142
Last edited:
I knew I'd get a bunch of very good suggestions here. Lots to think about. I have to run right now, but (hopefully) this afternoon I'll get tinkering with it.

Thanks guys. Will let ya know how it goes. I'll put up a YouTube movie of it when it's working properly (and most likely a page or two on the web-site).
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top