2
\$\begingroup\$

I want to understand how the PIC instruction timing works. I've written the code below, and it toggles PORTB, pin 3. I analyze the results with an oscilloscope.

The PIC runs on 8MHz internal clock = 2MHz instruction clock (i.e. 500ns/single word instruction).

The oscilloscope shows me square waves with a period of 14*500ns.

My questions are:

  1. I want to match the observed square wave with the corresponding instructions. My idea is if I start at a rising edge I would say I've toggled LATB soo my chain of events is

btg -> retfie -> nop -> (now i'm guessing..) goto 0x000008 -> nop -> goto highPriInt -> nop -> btg

Is this correct? another idea would be

btg -> retfie -> nop -> nop (in loop) -> something for 1 cycle -> goto highPriInt -> nop -> btg

Question 2:

I never reset any interrupt flags but the highPriInt is called all the time. I know the 'retfie' command resets GIE bit but I thought I would have to clear the TMR0IF bit before another Timer interrupt could occur??

Best regards R

    ORG     0x000000        ; Action on reset
    goto    main

    ORG     0x000008        ; High priority interrupt vector
    goto    highPriInt

    ORG     0x000018        ; Low priority interrupt vector
    goto    lowPriInt

main:
    clrf    PORTB       ; Clear port B
    clrf    TRISB       ; Set all as outputs

    movlw   0xFF        ; Set Fosc to 8MHz
    iorwf   OSCCON, 1

    movlw   0x5F        ; Setup Timer0, not started yet!
    movwf   T0CON

    bsf     INTCON, 5       ; Enable Timer0 interrupts
    bsf     INTCON, 7       ; Enable globla interrupts
    bsf     T0CON, 7        ; Enable Timer0

loop:
    nop
    bra     loop

highPriInt:
    btg     LATB, 3     ; Toggles Port B pin 3
    retfie

lowPriInt:
    retfie

END
\$\endgroup\$
  • \$\begingroup\$ Note that branch instructions take two cycles on most PIC devices. This is because the program counter is more than 8 bits wide, so must load two values to execute it. \$\endgroup\$ – rdtsc Oct 9 '15 at 17:13
  • \$\begingroup\$ Yes, that is why I added the 'nop's after each branching \$\endgroup\$ – RedSmolf Oct 9 '15 at 19:10
  • \$\begingroup\$ Which PIC are you referring to? \$\endgroup\$ – tcrosley Oct 9 '15 at 19:39
  • \$\begingroup\$ Sorry forgot to write that. I'm using PIC18F4550 \$\endgroup\$ – RedSmolf Oct 9 '15 at 19:42
  • \$\begingroup\$ Many, if not all 8-bit PICs take 4 cycles to implement an instruction. \$\endgroup\$ – SunnyBoyNY Oct 9 '15 at 20:01
1
\$\begingroup\$

In most cases with the PIC 12/16/18F if you don't clear the interrupt flag then the interrupt service routine will continue to fire.

From this Microchip document (page 3):

Generally the interrupt flag bit(s) must be cleared in software before re-enabling the global interrupt to avoid recursive interrupts.

Therefore the behaviour you are seeing is by design - you need to clear T0IF to prevent further interrupts from firing.

\$\endgroup\$
0
\$\begingroup\$

Interrupt routines keep being called if you don't reset the interrupt pending flag. This is true for many other CPU's as well, so it's always good practice to clear the interrupt pending flag at the end of your ISR routine.

On PICs and some other (older) CPUs you may also see that 1 interrupt "vector" is shared for multiple interrupts. In that case you should use the pending flag to execute the specific interrupt handler code and clear the flag within that handler.

I do not recommend clearing (all) interrupt pending flags willy-nilly at the end of the ISR routine without branching. In that case you could reset a pending flag (and miss the ISR) that was triggered while the CPU was handling another ISR.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.