Interrupt on timer

Thread Starter

sakishrist

Joined Dec 4, 2009
26
Hello,

I have been trying for days now to understand the interrupts but with no luck. I have been looking for sample code on the net but I didn't find anything useful. What seems to be working for others is not working for me. For example, I found this code:
Rich (BB code):
#include <p18f14k50.h>

//pragma codes
#pragma code high_vector=0x08
#pragma config FOSC = IRC //enable the internal oscillator




//function prototypes
void oscillator(void);
void timer(void);
void high_isr(void);

void interrupt_at_high_vector(void)
{
   _asm goto high_isr _endasm
}

/*******Oscillator function - This function will set the oscillator to 31 kHz***********/
void oscillator(void)
{
//Set oscillator to 31 kHz
OSCCONbits.IRCF2 = 0;
OSCCONbits.IRCF1 = 0;
OSCCONbits.IRCF0 = 0;

//Device clock derived directly from the LFINTOSC internal oscillator
OSCTUNEbits.INTSRC = 0;
}
/*******End Oscillator Function********************************************************/


/*******Timer function - Will start the timer and set pre-scalar to 1:128**********/
void timer(void) 
{
//Pre-scalar value of 1:128. This should give about 4 seconds for the timer0 interrupt flag to go high 
T0CONbits.T0PS2 = 1;
T0CONbits.T0PS1 = 1;
T0CONbits.T0PS0 = 0;

T0CONbits.TMR0ON = 1; //Enables Timer0
}
/*******End Timer Function********************************************************/

void main(void)
{
        INTCONbits.GIE = 1; //enable high priority global interrupts
        RCONbits.IPEN = 1; //enable priority levels on interrupts
        
        INTCONbits.TMR0IF = 0; //clears timer interrupt flag
        INTCONbits.TMR0IE = 1; //enable Timer0 interrupt bit
        T0CONbits.T08BIT = 1; //Set Timer0 as an 8-bit timer
        INTCON2bits.TMR0IP = 1; //Timer0 Interrupt bit set to high priority
        
        TRISC = 0x00; //set all PORTC bits as an output
        
        oscillator();
        timer();
}    

        
//High Interrupt Vector function
#pragma interrupt high_isr            // declare function as high priority isr
void high_isr(void)
{
    if(INTCONbits.TMR0IF = 1)
        {
            LATCbits.LATC0=1 //Turn on LED at RC0
        }
}
I changed the header file for my microcontroller (18F4620) and tried to build the code but I got this error: section 'high_vector' can not fit the absolute section. Section 'high_vector' start=0x00000008, length=0x0000004a
I am not quite sure if I really understand what that means. So could you explain to me what I am doing wrong.

Could you provide some other links to any sample code about interrupts on timer?

I am using MPLAB IDE with C18
Thanks
 

Thread Starter

sakishrist

Joined Dec 4, 2009
26
I was told to add a while(1); loop in my main routine and to make the following changes:
//#pragma code high_vector=0x08 //remove this line from here
#pragma config FOSC = IRC //enable the internal oscillator

//and surround ISR this way...
#pragma code high_vector=0x08
void interrupt_at_high_vector(void)
{
_asm goto high_isr _endasm
}
#pragma code
The thing is I still get this error message when attempting to compile it. I thought I might be getting that error because of the lkr file I use which looks like this:
// $Id: 18f4620.lkr,v 1.3 2004/04/26 18:09:00 curtiss Exp $
// File: 18f4620.lkr
// Sample linker script for the PIC18F4620 processor

LIBPATH .

FILES c018i.o
FILES clib.lib
FILES p18f4620.lib

CODEPAGE NAME=vectors START=0x00 END=0x0029 PROTECTED
CODEPAGE NAME=page START=0x002A END=0xFFFF
CODEPAGE NAME=idlocs START=0x200000 END=0x200007 PROTECTED
CODEPAGE NAME=config START=0x300000 END=0x30000D PROTECTED
CODEPAGE NAME=devid START=0x3FFFFE END=0x3FFFFF PROTECTED
CODEPAGE NAME=eedata START=0xF00000 END=0xF003FF PROTECTED

ACCESSBANK NAME=accessram START=0x0 END=0x7F
DATABANK NAME=gpr0 START=0x80 END=0xFF
DATABANK NAME=gpr1 START=0x100 END=0x1FF
DATABANK NAME=gpr2 START=0x200 END=0x2FF
DATABANK NAME=gpr3 START=0x300 END=0x3FF
DATABANK NAME=gpr4 START=0x400 END=0x4FF
DATABANK NAME=gpr5 START=0x500 END=0x5FF
DATABANK NAME=gpr6 START=0x600 END=0x6FF
DATABANK NAME=gpr7 START=0x700 END=0x7FF
DATABANK NAME=gpr8 START=0x800 END=0x8FF
DATABANK NAME=gpr9 START=0x900 END=0x9FF
DATABANK NAME=gpr10 START=0xA00 END=0xAFF
DATABANK NAME=gpr11 START=0xB00 END=0xBFF
DATABANK NAME=gpr12 START=0xC00 END=0xCFF
DATABANK NAME=gpr13 START=0xD00 END=0xDFF
DATABANK NAME=gpr14 START=0xE00 END=0xEFF
DATABANK NAME=gpr15 START=0xF00 END=0xF7F
ACCESSBANK NAME=accesssfr START=0xF80 END=0xFFF PROTECTED

SECTION NAME=CONFIG ROM=config

STACK SIZE=0x100 RAM=gpr14
I tried to change the values and I got it to compile but now when I execute the code I just get no leds turning on.

So first of all, can I freely change the values in the lkr file? And what exactly are those values?

So what could the problem be now that I managed to compile it?

Thanks
 

Thread Starter

sakishrist

Joined Dec 4, 2009
26
Please, could you help me or at least tell me where I should look for the answer? If there are any books that might be useful.

Thanks
 

Thread Starter

sakishrist

Joined Dec 4, 2009
26
Thanks a lot. I appreciate it but I just have some difficulty fully understanding this and converting it to c.

I found some books so I'll see if I can find something there that can either help me convert the sample you provided or write a new one entirely in c.

I'll post here as soon as I find something useful.

Thanks again.
 

Tahmid

Joined Jul 2, 2008
343
Hey,
Just coded this, hope it helps clear your doubts, and it's tested to work.
Rich (BB code):
#include <p18f4620.h>

void interrupt_at_high_vector(void);
void high_isr(void);

#pragma config OSC = XT //Crystal oscillator
#pragma config WDT = OFF //Watchdog Timer off
#pragma config MCLRE = OFF //Master clear off
#pragma config LVP = OFF //LVP off
#pragma config XINST = OFF //XINST off

#pragma code high_vector=0x08
void interrupt_at_high_vector(void)
{
  _asm GOTO high_isr _endasm
}
#pragma code /* return to the default code section */
#pragma interrupt high_isr
void high_isr(void)
{
    LATC = 1; //RC0 HIGH
    INTCONbits.TMR0IF = 0; //CLEAR TMR0 INT FLAG
}

void main(void){
    TRISC = 0;
    LATC = 0;
    INTCON = 0xA0; //GIE AND TMR0IE
    T0CON = 0x85; //16-BIT, TMRON, PRESCALER 1:128
    while (1); //wait for interrupt
}
Hope you understand this and it helps you.
For any problem, feel free to ask.
Tahmid.
 

Thread Starter

sakishrist

Joined Dec 4, 2009
26
Thanks a lot. It works but could you please tell me what the problem was with the other program? I tried to understand what made the difference but I don't really get it.

Thanks
 

spinnaker

Joined Oct 29, 2009
7,830
Hey,
Just coded this, hope it helps clear your doubts, and it's tested to work.
Rich (BB code):
#include <p18f4620.h>

void interrupt_at_high_vector(void);
void high_isr(void);

#pragma config OSC = XT //Crystal oscillator
#pragma config WDT = OFF //Watchdog Timer off
#pragma config MCLRE = OFF //Master clear off
#pragma config LVP = OFF //LVP off
#pragma config XINST = OFF //XINST off

#pragma code high_vector=0x08
void interrupt_at_high_vector(void)
{
  _asm GOTO high_isr _endasm
}
#pragma code /* return to the default code section */
#pragma interrupt high_isr
void high_isr(void)
{
    LATC = 1; //RC0 HIGH
    INTCONbits.TMR0IF = 0; //CLEAR TMR0 INT FLAG
}

void main(void){
    TRISC = 0;
    LATC = 0;
    INTCON = 0xA0; //GIE AND TMR0IE
    T0CON = 0x85; //16-BIT, TMRON, PRESCALER 1:128
    while (1); //wait for interrupt
}
Hope you understand this and it helps you.
For any problem, feel free to ask.
Tahmid.

Excellent example Tahmid. Nice and simple and easy to understand. The MPLAB sample in the PC18F45K20 is very hard to follow. Your sample makes things easy.

I have taken what you have done and modified the code to have the interrupt routine toggle RD0 on and off. I also broke out each of the bits to show how they are set and I added code to test for the Timer 0 interrupt. Not really needed here but just to show how to test for the flag. Hopefully this will help others.


Code:
#include <p18f45k20.h>

/* 

The following program deonstrates a method of using an interrupt on the 
internal timer for the 8 bit PIC microcontroller.  The code is written for
the 18F45K20 demo board.  This board has a LED at RD0-RD7.  The interrupt 
routine will toggle the light at RD0 on and off.
*/



void interrupt_at_high_vector(void);
void high_isr(void);

#pragma config FOSC = INTIO67
#pragma config MCLRE = OFF //Master clear off
#pragma config WDTEN = OFF, WDTPS = 32768 
#pragma config LVP = OFF //LVP off
#pragma config XINST = OFF //XINST off
#pragma code high_vector=0x08


void interrupt_at_high_vector(void)
{
  _asm GOTO high_isr _endasm
}


#pragma code /* return to the default code section */
#pragma interrupt high_isr
void high_isr(void)
{
    if (INTCONbits.TMR0IF == 1)    //Check Timer 0 Interrupt Flag tp be sure this is a Timer 0 interrupt.
    {
        if (LATD)
            LATD=0;                //RDO LOW        
        else
            LATD = 1;            //RD0 HIGH

        INTCONbits.TMR0IF = 0;     //CLEAR TMR0 INT FLAG
    }
}

void main(void){
    

    TRISD = 0;
    LATD = 0;

    INTCONbits.GIE         = 1;    //Set Global Interrupt Enable
    INTCONbits.TMR0IE     = 1;    //Set Timer 0 Interrupt Enable    
    //The INTCON bits can also be set by using INTCON = 0xA0;    

      
    T0CONbits.TMR0ON     = 1;    //Turn on timer 0
    T0CONbits.T08BIT     = 0;    //Disable 8 bit / enable 16 bit
    T0CONbits.T0CS        = 0;    //Use the internal clock
    T0CONbits.T0SE        = 0;    //Increment on low to high transition TOCK pin 1 (not used)
    T0CONbits.PSA        = 0;    //Use timer prescaler

    
    //Set prescaler to 1:2
    T0CONbits.T0PS0        = 0;
    T0CONbits.T0PS1        = 0;
    T0CONbits.T0PS2        = 0;
    // The T0CON bits can also be set by using T0CON = 0x85


    while (1);                     //wait for interrupt
}
 

Thread Starter

sakishrist

Joined Dec 4, 2009
26
in Mplab the latest sample does not work unless I add "#pragma code high_vector=0x08" before "interrupt at high_vector".

Anyways, although it works fine now, could you explain what is the difference between
void interrupt_at_high_vector(void)
{
_asm GOTO high_isr _endasm
}
and
void high_isr(void)
{
if (INTCONbits.TMR0IF == 1) //Check Timer 0 Interrupt Flag tp be sure this is a Timer 0 interrupt.
{
if (LATD)
LATD=0; //RDO LOW
else
LATD = 1; //RD0 HIGH

INTCONbits.TMR0IF = 0; //CLEAR TMR0 INT FLAG
}
}
What exactly does each other do? Also can I name them as I want?

And finally, what exactly is the purpose of "#pragma code high_vector=0x08" and "#pragma code"?

Thanks a lot
 

spinnaker

Joined Oct 29, 2009
7,830
Yes you can name them anything you want. You just need to remember to change the #pragma code high_vector=0x08 statement. This is the statement that connects your interrupt service routine (ISR) to the interrupt vector.

Your ISR vector may be at a different place than the chip I am using. You will need to check your datasheet.

When an interrupt takes place, the MCU looks at the interrupt vector, gets an address and executes the code there.


I am still new at this myself so I am not sure why there is assembler code there but I suspect that it has to be in a proper code boundary or some such thing, so the easiest way is to use an assembler goto to execute the actual code that you want to execute.

The second function is probably not really needed, if you wanted to write the first one all in assembler.

But no matter what you do, as in any ISR you want the code to be as short and as fast as possible.
 

spinnaker

Joined Oct 29, 2009
7,830
It was in my previous post but I was a bit wrong. In interrupt vectors that I have experience, an address is placed at the vector. But is is looking to me like in PICS an instruction is placed there or actually block of instructions. This is the instruction generated by your interrupt_at_high_vector function.

Apparently I was wrong about having to change the label at #pragma code. Apparently you can give that any label you want. Tha lable is just that a label but you should probably name it the same as your ISR for clarity.


When the compiler sees #pragma code high_vector=0x08 it assigns all the code generated to a specific location. It will continue assign code to that location until another #pragma code is encountered.

This must be why the first ISR has to be really short. #08h is the high priority interrupt vector. #18h is the low interrupt vector.

It looks like each interrupt vector gets 8 bytes. So that is why you need to jump to a second ISR to do any real work.

The datasheet is not 100% clear on any of this, so it is pretty much what I have figure out on my own so I could be wrong. :)
 

Tahmid

Joined Jul 2, 2008
343
The datasheet only states everything in brief. The reference manual explains all those in details. It is available on the Microchip website for free.
 

Tahmid

Joined Jul 2, 2008
343
For those who program in ASM(assembler):
Rich (BB code):
    LIST P=18F4620
    #INCLUDE <P18F4620.INC>
    __CONFIG _CONFIG1H, _OSC_XT_1H & _FCMEN_OFF_1H & _IESO_OFF_1H
    __CONFIG _CONFIG2L, _PWRT_OFF_2L & _BOREN_OFF_2L
    __CONFIG _CONFIG2H, _WDT_OFF_2H
    __CONFIG _CONFIG3H, _MCLRE_OFF_3H & _LPT1OSC_OFF_3H & _PBADEN_OFF_3H
    __CONFIG _CONFIG4L, _STVREN_OFF_4L & _LVP_OFF_4L & _XINST_OFF_4L & _DEBUG_OFF_4L
    __CONFIG _CONFIG5L, _CP0_OFF_5L & _CP1_OFF_5L & _CP2_OFF_5L & _CP3_OFF_5L
    __CONFIG _CONFIG5H, _CPB_OFF_5H & _CPD_OFF_5H
    __CONFIG _CONFIG6L, _WRT0_OFF_6L & _WRT1_OFF_6L & _WRT2_OFF_6L & _WRT3_OFF_6L
    __CONFIG _CONFIG6H, _WRTB_OFF_6H & _WRTC_OFF_6H & _WRTD_OFF_6H
    __CONFIG _CONFIG7L, _EBTR0_OFF_7L & _EBTR1_OFF_7L & _EBTR2_OFF_7L & _EBTR3_OFF_7L
    __CONFIG _CONFIG7H, _EBTRB_OFF_7H

    ORG 0x00
    GOTO MAIN

    ORG 0x08
    GOTO ISRH
;=================================================================================
ISRH
    BSF        LATC, 0 ;RC0 = 1
    BCF        INTCON, TMR0IF ;CLEAR FLAG
    RETFIE
;=================================================================================
MAIN
    CLRF    TRISC
    CLRF    LATC
    MOVLW    0xA0
    MOVWF    INTCON ;GIE AND TMR0IE
    MOVLW    0x85
    MOVWF    T0CON ;16-BIT, TMR0 ON, PRESCALER 1:128
WAIT
    GOTO    WAIT
;=================================================================================
    END
;=================================================================================
Same program as the one I posted earlier, only in ASM instead of C.
 

spinnaker

Joined Oct 29, 2009
7,830
The datasheet isn't usually enough. Normally you should take a look at the Reference Manual which helps a lot.
I'll have to take a look again. I am not sure I saw a reference manual for my PIC (18F45K20). Or is it a general reference manual?


Was I right on how I described (the second time) how interrupt vectors work in PICs?
 
Top