Author Topic: Timer interrupt for pic18f4550  (Read 5773 times)

0 Members and 1 Guest are viewing this topic.

Offline BibiricatTopic starter

  • Contributor
  • Posts: 43
Timer interrupt for pic18f4550
« on: March 17, 2013, 08:41:50 pm »
Hello.

I am trying to make a 50Hz pwm signal using interrupt and timer 0, however, i have tried a number of examples and i can't get the program to enter in the interrupt. I have tried a lot of configs, and i still can't get a single interrupt to work.
I am using pic18f4550 with usb bootloader .
I may have some extra config i don't need, and some missing config i need, so please feel free to correct me.

This is my code:

#include <p18f4550.h>

#pragma code REMAPPED_RESET_VECTOR=0x1000      //Because of the bootloader
   
extern void _startup (void);

void _reset (void)
{
   _asm goto _startup _endasm
}

void high_isr(void);

#pragma code
/************************************************************/
#pragma code high_vector=0x08
void interrupt_at_high_vector(void)
{
  _asm GOTO high_isr _endasm
}

#pragma code
/*****************High priority ISR **************************/

#pragma interrupt high_isr
void high_isr (void)
{
       if (INTCONbits.TMR0IF){  // Interrupt Check   
                INTCONbits.TMR0IF = 0;                 
                TMR0H = 0xEE;        //Timer0 initializare
                TMR0L = 0xEE;
            PORTBbits.RB7 = 0;                   
                 
       }
}

/***********************************************************/

void main(void)
{
   unsigned int second, check;
// config interrupt   
   INTCON = 0x20;             
   INTCON2 = 0x04;               //TMR0 high priority
    RCONbits.IPEN = 1;            //enable priority levels

// Timer0 configuration
   T0CONbits.TMR0ON = 0; // Stop the timer
   T0CONbits.T08BIT = 0; // Run in 16-bit mode
   T0CONbits.T0CS = 0; // Use system clock to increment timer
   T0CONbits.PSA = 0; // A prescaler is assigned for Timer0
   T0CONbits.T0PS2 = 1; // Use a 1:256 prescaler
   T0CONbits.T0PS1 = 1;
   T0CONbits.T0PS0 = 1;

   INTCONbits.GIEH = 0;
   INTCONbits.TMR0IE = 1;      //1 = Enables the TMR0 overflow interrupt
   INTCONbits.TMR0IF = 0;
   INTCONbits.INT0IF = 0;      //1 = The INT0 external interrupt occurred (must be cleared in software)

   T0CONbits.TMR0ON = 1;      // Start the timer

   TMR0L = 0x82;      //(255-130)*4/Fosc *prescaler=0.05ms
              TMR0H = 0x85;
              INTCONbits.GIEH = 1;          //enable interrupts

   // LED configuration
   TRISB = 0; // Configure portb as an output
   PORTBbits.RB7 = 1;


   
   while(1) // Program loop
   {
   

   }
}
 

Offline Psi

  • Super Contributor
  • ***
  • Posts: 9946
  • Country: nz
Re: Timer interrupt for pic18f4550
« Reply #1 on: March 17, 2013, 09:33:33 pm »
Just and though.
I don't really know the PIC interrupt syntax but with some micros you have to be careful using interrupts when you have a bootloader.
You can end up with interrupts in a memory area assigned for bootloader code and then be unable to call them from main.
Especially if you have played with the fuse bits to lockdown main code reading bootloader memory and/or vice versa.
« Last Edit: March 17, 2013, 09:41:25 pm by Psi »
Greek letter 'Psi' (not Pounds per Square Inch)
 

Offline DavidDLC

  • Frequent Contributor
  • **
  • Posts: 755
  • Country: us
Re: Timer interrupt for pic18f4550
« Reply #2 on: March 17, 2013, 11:21:31 pm »
This is working for me, but I'm using a different compiler, you can use it as a reference.

/*************************************************************************************************
// I N T E R R U P T   S E R V I C E S   **********************************************************
//*************************************************************************************************
#pragma interrupt HighPriorityInt
void HighPriorityInt(void)
{
}//HighPriorityInt

#pragma interruptlow LowPriorityInt
void LowPriorityInt(void)
{

if ( INTCONbits.TMR0IF == 1)
{
   PORTBbits.RB7 = 1;
   INTCONbits.TMR0IF = 0;                        //Need to clear timer interuption flag 
   TMR0L = Timer_Low;                            //Init value for Counter
   TMR0H = Timer_High;                           //Init value for Counter
   PORTBbits.RB7 = 0;
}

}//LowPriorityInt


//*************************************************************************************************
// V E C T O R  R E M A P P I N G  ****************************************************************
//*************************************************************************************************
#pragma code high_vector=0x08
void interrupt_at_high_vector(void)
{
    _asm goto HighPriorityInt _endasm
}
#pragma code low_vector=0x18

void interrupt_at_low_vector(void)
{
    _asm goto LowPriorityInt _endasm
}
#pragma code



// *** Interrupt configuration *** //
INTCONbits.TMR0IF = 0;                           //Clear timer interuption flag 
RCONbits.IPEN = 0;                               //Enable/Disable priority levels
INTCONbits.GIEH = 0;                             //Enable/Disable high priority interrupt
INTCONbits.GIEL = 0;                             //Enable/Disable low priority interrupt
INTCONbits.TMR0IE = 0;                           //Enable/Disable Timer 0 interrupt
INTCON2bits.TMR0IP = 0;                          //Timer 0 is low priority interrupt

// *** Timer 0 Configuration *** //
T0CONbits.T08BIT = 0;                            //1=8 bit timer, 0=16 bit timer
T0CONbits.T0CS = 0;                              //Use internal clock, use as Timer
T0CONbits.PSA = 1;                               //Do not use prescaler

TMR0L = Timer_Low;                               //Init value for Timer 0
TMR0H = Timer_High;                              //Init value for Timer 0
T0CONbits.TMR0ON = 0;                            //Enable Timer = 1 Disable Timer = 0
 

Offline DavidDLC

  • Frequent Contributor
  • **
  • Posts: 755
  • Country: us
Re: Timer interrupt for pic18f4550
« Reply #3 on: March 17, 2013, 11:23:44 pm »
Sorry:

T0CONbits.TMR0ON = 1;                            //Enable Timer = 1 Disable Timer = 0

Should be 1, I had it temporary disabled for some testing.
 

Offline ecat

  • Frequent Contributor
  • **
  • Posts: 296
  • Country: gb
Re: Timer interrupt for pic18f4550
« Reply #4 on: March 18, 2013, 01:26:01 am »
At the very least...

Quote
TMR0H is not the actual high byte of Timer0 in 16-bit mode. It is actually a buffered version of the real high
byte of Timer0 which is not directly readable nor writable (refer to Figure 11-2). TMR0H is updated with
the contents of the high byte of Timer0 during a read of TMR0L. This provides the ability to read all 16 bits of
Timer0 without having to verify that the read of the high and low byte were valid, due to a rollover between
successive reads of the high and low byte.

Similarly, a write to the high byte of Timer0 must also take place through the TMR0H Buffer register. The high
byte is updated with the contents of TMR0H when a write occurs to TMR0L
. This allows all 16 bits of Timer0
to be updated at once.

So, to set TH & TL you MUST write the values in the correct order

TMR0H = Timer_High;      // must set TH before writing to TL
TMR0L = Timer_Low;       // writing to TL updates TL and TH

@DavidDLC,
Your code may appear to work but in reality the first interrupt will be slow to appear, after that the value you set in TH will be the previous value written to the TH buffer, not necessarily the value currently in Timer_High.


@Bibiricat,
You have the same problem in your initialisation code

TMR0L = 0x82;      //(255-130)*4/Fosc *prescaler=0.05ms
TMR0H = 0x85;

So, TL = 0x82, the TH buffer = 0x85 but the actual TH register = ?? ie whatever happened to be in the TH buffer at the time TL was written, after a reset it could well be zero.

In this case you are running a 1/255 prescaler. At 8MHz: 8000000 / 4 / 256 = 7812.5Hz timer frequency, assuming 0 in TH your count to interrupt will be around 0xff00 (65280), 65280 * 1 / 7812.5 = 8.35584 seconds

You appear to be running at 2MHz (? from the TMR0L comment above), so the time to your first interrupt will be around 40 seconds, after which you will run at your 0xEEEE timings.

Your code looks feasible, are you perhaps declaring the code bad before the 40 seconds are up? I've certainly done this at least once... or twice ;)


 

Offline JTR

  • Regular Contributor
  • *
  • Posts: 107
  • Country: au
Re: Timer interrupt for pic18f4550
« Reply #5 on: March 18, 2013, 02:36:38 pm »
What you are doing is useless. There is not point in trying to remap the interrupt vectors @ 0x0008 and 0x0018 if you have a bootloader installed. The bootloader is not going to write these new values. It has already remapped the vectors to 0x1008 and 0x1018 and you must pick up the vectors from these addresses. You will not be able to change this as the bootloader protects its own space and will not erase and write to it.

This is the sort of system you need to use: (assuming microchip HID bootloader)


#define REMAPPED_RESET_VECTOR_ADDRESS      0x1000
#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS   0x1008
#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS   0x1018


#pragma code REMAPPED_HIGH_INTERRUPT_VECTOR = REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS

void Remapped_High_ISR(void) {
    _asm goto InterruptHandlerHigh _endasm
}

#pragma code REMAPPED_LOW_INTERRUPT_VECTOR = REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS

void Remapped_Low_ISR(void) {
    _asm goto InterruptHandlerLow _endasm
}


#pragma interrupt InterruptHandlerHigh

void InterruptHandlerHigh(void) {

}

#pragma interruptlow InterruptHandlerLow

void InterruptHandlerLow(void) {
}

Try it and see how you go.

EDIT:

To make your firmware compatible in case there is no bootloader installed you can add the following code. If there is a bootloader this code will not be written into the PIC but it is harmless in that case.

//set the initial vectors so this works without the bootloader too.
#pragma code HIGH_INTERRUPT_VECTOR = 0x08

void High_ISR(void) {
    _asm goto REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS _endasm
}
#pragma code LOW_INTERRUPT_VECTOR = 0x18

void Low_ISR(void) {
    _asm goto REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS _endasm
}
« Last Edit: March 18, 2013, 02:39:35 pm by JTR »
 

Offline DavidDLC

  • Frequent Contributor
  • **
  • Posts: 755
  • Country: us
Re: Timer interrupt for pic18f4550
« Reply #6 on: March 18, 2013, 06:13:19 pm »
At the very least...

Quote
TMR0H is not the actual high byte of Timer0 in 16-bit mode. It is actually a buffered version of the real high
byte of Timer0 which is not directly readable nor writable (refer to Figure 11-2). TMR0H is updated with
the contents of the high byte of Timer0 during a read of TMR0L. This provides the ability to read all 16 bits of
Timer0 without having to verify that the read of the high and low byte were valid, due to a rollover between
successive reads of the high and low byte.

Similarly, a write to the high byte of Timer0 must also take place through the TMR0H Buffer register. The high
byte is updated with the contents of TMR0H when a write occurs to TMR0L
. This allows all 16 bits of Timer0
to be updated at once.

So, to set TH & TL you MUST write the values in the correct order

TMR0H = Timer_High;      // must set TH before writing to TL
TMR0L = Timer_Low;       // writing to TL updates TL and TH

@DavidDLC,
Your code may appear to work but in reality the first interrupt will be slow to appear, after that the value you set in TH will be the previous value written to the TH buffer, not necessarily the value currently in Timer_High.


Ahh good to know !

Thank you.
 

Offline BibiricatTopic starter

  • Contributor
  • Posts: 43
Re: Timer interrupt for pic18f4550
« Reply #7 on: March 18, 2013, 07:48:28 pm »
Thanks all of you  for the code/advice . Managed to finally get the interrupts working. Now i just have to tune it for the 50Hz signal i want.
Also i am using 20MHz external crystal .

 The final code is this:

Code: [Select]
#include <p18f4550.h> // Always include the header file

#define REMAPPED_RESET_VECTOR_ADDRESS      0x1000
#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS   0x1008
#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS    0x1018

#define Timer_Low 0x88
#define Timer_High 0x88
void InterruptHandlerHigh(void);
void InterruptHandlerLow(void);
/***************Bootloader************************************/
#pragma code REMAPPED_RESET_VECTOR = REMAPPED_RESET_VECTOR_ADDRESS
extern void _startup (void);
void _reset (void)
{
   _asm goto _startup _endasm
}
#pragma code

/**************************************************************/
//**************************************************************
// V E C T O R  R E M A P P I N G  *****************************
//**************************************************************


#pragma code REMAPPED_HIGH_INTERRUPT_VECTOR = REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS

void Remapped_High_ISR(void) {
    _asm goto InterruptHandlerHigh _endasm
}
#pragma code
#pragma code REMAPPED_LOW_INTERRUPT_VECTOR = REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS

void Remapped_Low_ISR(void) {
    _asm goto InterruptHandlerLow _endasm
}
#pragma code
/**************Interrupts*************************************/
#pragma interrupt InterruptHandlerHigh

void InterruptHandlerHigh(void) {
if ( INTCONbits.TMR0IF == 1)
{
   
    INTCONbits.TMR0IF = 0;                        //Need to clear timer interuption flag 
    TMR0L = Timer_Low;                            //Init value for Counter
    TMR0H = Timer_High;                           //Init value for Counter
    if(PORTBbits.RB7 == 0) PORTBbits.RB7 = 1;
    else PORTBbits.RB7 = 0;
}
}

#pragma interruptlow InterruptHandlerLow

void InterruptHandlerLow(void) {
}
/*************************************************************/


void main(void)
{
// LED configuration
TRISB = 0; // Configure portb as an output
PORTBbits.RB7 = 1;

// *** Interrupt configuration *** //
INTCONbits.TMR0IF = 0;                           //Clear timer interuption flag 
RCONbits.IPEN = 1;                               //Enable/Disable priority levels
INTCONbits.GIEH = 1;                             //Enable/Disable high priority interrupt
INTCONbits.GIEL = 0;                             //Enable/Disable low priority interrupt
INTCONbits.TMR0IE = 1;                           //Enable/Disable Timer 0 overflow interrupt
INTCON2bits.TMR0IP = 1;                          //Timer 0 is high priority interrupt

// *** Timer 0 Configuration *** //
T0CONbits.T08BIT = 0;                            //1=8 bit timer, 0=16 bit timer
T0CONbits.T0CS = 0;                              //Use internal clock, use as Timer
T0CONbits.PSA = 1;                               //Do not use prescaler


TMR0H = Timer_High;                              //Init value for Timer 0
TMR0L = Timer_Low;                               //Init value for Timer 0
T0CONbits.TMR0ON = 1;                            //Enable Timer = 1 Disable Timer = 0


while(1) // Program loop
{


}
}
« Last Edit: March 18, 2013, 08:23:52 pm by Bibiricat »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf