Calibrating PIC microcontroller internal oscillator

I am describing here a method to calibrate PIC micro-controllers.One day I antecedently erased the the oscillator calibration value in my PIC pic16f676.Then searched for a solution to recalibrate it.I found this link from Microchip's website AN250 - Auto-calibration of the PIC12F6XX Internal RC Oscillator .

But for this method needs an additional reference pulse generator of 5kHz.But I don't have these things.So I tried an alternate method.In this method, we need a PC with serial port to calibrate PIC micro-controller. Other things we needed are,

    A compiler for PIC. I use PICC Lite edition.
     PIC burning software . I use Picprog

Here is a simple c source code

#include <htc.h>
#include <conio.h>

__CONFIG(FOSC_INTRCIO & WDTE_OFF & PWRTE_ON & CP_OFF & CPD_OFF & BOREN_OFF & MCLRE_OFF);



/*************************************
 * Tunable parameters
 */

/* Transmit and Receive port bits */
#define TxData RA2  /* bit3 in port A */

#define XTAL   4000000 /* Crystal frequency (Hz). */
#define BRATE   1200 /* Baud rate. */
// #define BRATE   9600 /* Baud rate. */
#define RX_OVERSAMPLE 8  /* Amount of oversampling the receiver does. 
           Must be a power of two */

#define TIMER_VALUE XTAL / (4 * BRATE * RX_OVERSAMPLE)

// 1 start bit + 8 data bits + 2 stop bits + safe.
#define TRANSMIT_NUM_BITS 13 

#if (RX_OVERSAMPLE-1)&RX_OVERSAMPLE
#error RX_OVERSAMPLE_value must be a power of 2
#endif

static unsigned char sendbuffer;   // Where the output char is stored.
           // it is received.

static unsigned char send_bitno;
static unsigned char myosccal;
static bit    tx_next_bit;

#define LENGTH(a) (sizeof(a)/sizeof((a)[0]))

const char* const text = "Hello world. ";

/**
 * init_uart
 * 
 * Initialises the serial port:
 * 
 *  Sets up the I/O directions for the appropriate PortA pins;
 *  Sets up Timer0.
 * 
 * */
void
init_uart(void)
{
 // skipoversamples = 1;   // check each interrupt for start bit


 TRISA = 0x1B;     // Set up I/O direction.
 TRISC = 0xFE;

 /* Set up the timer. */
 T0CS = 0;      // Set timer mode for Timer0.
 TMR0 = (2-TIMER_VALUE);   // +2 as timer stops for 2 cycles
         // when writing to TMR0
 T0IE = 1;      // Enable the Timer0 interrupt.
 GIE = 1;
}

void
putch(char c)
{
 while(send_bitno)
  continue;
 tx_next_bit = 0;
 sendbuffer = c;
 send_bitno = TRANSMIT_NUM_BITS*RX_OVERSAMPLE;
}

interrupt void
serial_isr(void)
{
 // Reset Timer0 value
 // This is added to TMR0 because there is a delay to get to the isr.
 PORTC |= 1;
 TMR0 += -TIMER_VALUE + 4; // +2 as timer stops for 2 cycles when writing 
        // to TMR0 +2 for tweak
 T0IF = 0;

 
 /*** TRANSMIT ***/
 /* This will be called every RX_OVERSAMPLEth time
  * (because the RECEIVE needs to over-sample the incoming
  * data). */

 if(send_bitno) {
         if((send_bitno & (RX_OVERSAMPLE-1)) == 0) {
   TxData = tx_next_bit;  // Send next bit.
   tx_next_bit = sendbuffer & 1;
   sendbuffer = (sendbuffer >> 1) | 0x80;
  }
  send_bitno--;
 }
 PORTC &= ~1;
}


void
main(void)
{
 unsigned int i;
 
 init_uart();
 myosccal = 0;
 OSCCAL=myosccal;
 while(1){
  for(i=0;i<13;i++) 
   putch(text[i%13]);
  putch('#');
  putch('#');
  putch(0x61+((myosccal/16)&0xF));
  putch(0x61+(myosccal&0xF));
  putch('#');
  putch('#');
  myosccal++;
  OSCCAL=myosccal;
 }
}




Really this code is a modified version of code from "picc-9_82" package from microchip.com. This program will produce a "Hello wolrd ." string to PortA2. We can connect PortA2 to PC's serial port by using a max232 level shifter IC . I am using this circuit

Connect PIC to PC's RS232

screen /dev/ttyS0 1200,cs8,-parenb,-cstopb,-hupcl

and observe the output

Now copy and paste the  clearly visible strings from this to a new text file

Now format it for the easiness of the observation.then choose the string from the middle.

I choose "Hello world. ##cg##".Now note the two characters between two "##" .Here it is cg

Know look at the source code let's understand how the 'cg' is produced.

putch(0x61+((myosccal/16)&0xF));

putch(0x61+(myosccal&0xF));


suppose that myosccal=0x26. then its binary is "0010 0110"
first charector is produced by adding Bit 4-7 to 0x61
ie binary "0010" + 0x61 = 0x63 = Ascii charector 'c'
second charector is produced by adding Bit 0-3 to 0x61
ie binary "0110" + 0x61 = 0x67 = Ascii charector 'g'

So the original value of 'myosccal' is first_part . second_part. Here it is "0010 0110" = 0x26
So this is the calibration value of PIC's internal oscillator.

Now we can burn this to pic
I simply made a an asm file cal.asm

list    p=16f676
include "p16f676.inc"

org 0x3ff   ;address of calibration value
retlw 0x26  ;0x26 is the calibration value
end

then converted into hex

gpasm  cal.asm


then burned into PIC using picprog

picprog --burn --erase --force-calibration -i cal.hex


Comments

Popular posts from this blog

Creating a bootable windows USB from Linux