Strange results with PBP3 and instant interrupts


Closed Thread
Results 1 to 15 of 15

Hybrid View

  1. #1
    Join Date
    May 2006
    Location
    Del Rio, TX, USA
    Posts
    343


    Did you find this post helpful? Yes | No

    Default Re: Strange results with PBP3 and instant interrupts

    R.G,
    From a overall perspective, the best way to handle interrupts is to do as little as possible inside them, and let the maid code loop do all the heavy lifting. So along those lines, here are some suggestions:
    - Get rid of the the line: "INT_Handler TMR1_INT, _T1handler, PBP, yes"
    - Set a flag in the "ReloadTMR1" to track when it has been called
    - In you main loop, check to see if the flag has been set
    - - if yes, run T1Handler and clear the flag

    If your main code loop is really long, you can check the flag a couple of times in the loop.

    I don't think using PBP "bits" into an ASM part is really safe ...
    Unless you are REALLY careful, and fully understand what's happening behind the scenes at the assembly level, this is good advice.

  2. #2
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,615


    Did you find this post helpful? Yes | No

    Default Re: Strange results with PBP3 and instant interrupts

    Hi,
    While I agree that you shouldn't spend more time in the interrupt than neccessary (ie, don't use any Pause or other commands that "holds" the processor) using the interrupt to set a flag which is then polled and handled in the main routine kind of defeats the purpose of the interrupt in the first place IMHO. You might as well poll the interrupt flag in the main routine and then GOSUB a handler that reloads the timer and resets the flag.

    Obviosuly it depends on how often the code is supposed to run and with what latency etc. For example if something is to be run at 1Hz and a couple of ms or whatever worth of "jitter" doesn't matter then having a tick count maintained by the ISR which signals the main routine is a good idea. But if the code needs to run at specific and precise intervals then having it in the ISR is the way to go.

    Depending in the application it can also be a good idea to split the tasks between the ISR and the main routine. For example use the ISR to capture and calculate the value, then signal the main routine that a new value is ready and have IT send it instead of holding up the ISR with a HSEROUT or whatever. Even better in this case is of course an interrupt driven TX-routine as well but that's not the point.

    /Henrik.

  3. #3
    Join Date
    Mar 2011
    Posts
    13


    Did you find this post helpful? Yes | No

    Default Re: Strange results with PBP3 and instant interrupts

    Thanks for the reading, and the good advice. What you're saying is generally correct, and it is always possible that I have flatly missed something on the return from interrupt.

    However, the interrupt scheme is the DT instant interrupts include files; it may be a little roundabout but it works in general. And while interrupts do need to be short and quick, I did use exactly this code, statement for statement, in the 2.60a compiler and it worked perfectly for other PICs.

    I do need the preciseness of running the code on the interrupts. I normally use flags to the main routine as Henrik suggests when I can, but this needs the timing precision, and equally important, not having a second interrupt happen while the actions are being taken.

    And, as I mentioned, I recoded the logic into other (longer and clumsier) statements, and it started working. That was the one that got me. It appears that the single statement was what was throwing off the timer interrupt. It looked like it made the ISR miss the service interval, and let the timer count through its full 16 bits instead of being reset. And removing that one statement made the longer and clumsier coding work.

  4. #4
    Join Date
    Mar 2011
    Posts
    13


    Did you find this post helpful? Yes | No

    Default Re: Strange results with PBP3 and instant interrupts

    Yet more interesting results.

    The "DIG" statement works outside of an interrupt routine and does not interfere with interrupts.
    A "DIG" statement inside the interrupt routine sometimes make the timer interrupt miss.

  5. #5
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,615


    Did you find this post helpful? Yes | No

    Default Re: Strange results with PBP3 and instant interrupts

    Hi,
    The only thing I can think of is that the DIG operator (combined witht the rest of the ISR) consumes too many cycles and that the interrupt overruns itself. Can you, just as a test, increase the time between interrupts to say 2ms instead of 1 and see if that takes care of it?

    /Henrik.
    Last edited by HenrikOlsson; - 12th December 2011 at 21:02.

  6. #6
    Join Date
    Mar 2011
    Posts
    13


    Did you find this post helpful? Yes | No

    Default Re: Strange results with PBP3 and instant interrupts

    Yep. I'll give it a try in the next day or so.

    I coded around it by using a sacrificial variable to accumulate the count, then using DIG outside the interrupt routine to separate digits. That works fine.

  7. #7
    Join Date
    Mar 2011
    Posts
    13


    Did you find this post helpful? Yes | No

    Default Re: Strange results with PBP3 and instant interrupts

    I stripped out the extraneous stuff and verified that this test code compiles and gives the same strange results as the whole program. It's running on a 16F1518 with an external 4MHz crystal. I watched the interrupt speed by copying the LSB of the interrupt counter variable to an output pin, and watching it on an oscilloscope.

    Things to note:
    - I tried Henrik's suggestion of slowing the interrupts down. Worked fine, and this stub shows missed interrupts at 725Hz, but not at 700Hz. I wanted to get to 1mS, which had worked with 2.60a and other PICs.
    - I tried subbing in a different statement with the same variables (n, Value), and found that it worked fine to at least 2000Hz.
    - All I can guess at is that Value is a WORD variable, and maybe the use of DIG takes longer on words. I didn't try it with a BYTE variable.

    I'm well aware that I make silly mistakes in programs, but it looks to me like the use of the DIG function is what does this.

    Code:
    ' Name        : DIG Interrupt statement test
    ' Compiler    : PICBASIC PRO 3.0
    ' Target PIC  : 16F1518
    ' Oscillator  : set to 4MHz external crystal
    ' =======================================
    ' RA4 = output test pin
    ' RA6 = Oscillator/crystal pin 
    ' RA7 = Oscillator/crystal pin 
    '
    DEFINE OSC 4    ; use external 4MHz crystal
    ' Includes for interrupts
    wsave     VAR    BYTE $20 SYSTEM
    wsave1    VAR BYTE $A0 SYSTEM
    '
    INCLUDE "DT_INTS-14.bas"     ' Base Interrupt System
    INCLUDE "ReEnterPBP.bas"     ' Include if using PBP interrupts
    ' Variable Declarations
    i                Var Byte    ' counter for which digit is being displayed in the display Mpx 
    n                Var Byte    ' transfer variable for converting digit number to segments in lookup table
    Value            Var WORD    '
    
    '===============config bits=================
    #CONFIG
          __config _CONFIG1, _FOSC_XT & _PWRTE_ON & _MCLRE_ON & _CP_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _WDTE_OFF & _FCMEN_OFF
          __config _CONFIG2, _WRT_OFF & _VCAPEN_OFF & _BORV_19 & _LPBOR_OFF & _LVP_OFF
    #ENDCONFIG
    '================================
    ASM
    INT_LIST  macro    ; IntSource,        Label,  Type, ResetFlag?
            INT_Handler   TMR1_INT,   ReloadTMR1,   ASM,  no    ; MUST be first
            INT_Handler   TMR1_INT,   _T1handler,   PBP,  yes
        endm
        INT_CREATE               ; Creates the interrupt processor
    ENDASM
    ' ============================================================
    ;--- Change these to match the desired interrupt frequency ----------
    ;*** found that 700 works, 725 or greater frequency does not***
    @Freq       = 725                 ; Frequency of Interrupts in Hz
    @Prescaler  = 1                   ; Timers Prescaler setting
    T1CON = $00                       ; $30 = Prescaler 1:8, TMR1 OFF
    ; $00=1:1, $10=1:2, $20=1:4, $30=1:8 --  Must match @Prescaler value
    
    @ INT_ENABLE  TMR1_INT            ; enable Timer 1 interrupts
    GOSUB StartTimer                  ; Start the Timer
    '======== pre- main loop code here =================
    ' Initialization
    OSCCON = $68        ' set oscillator control for 4MHZ, external
    ANSELA = 0
    ANSELB = 0
    ANSELC = 0 
    TRISB = 000000
    TRISC = 111111
    TRISA = 000000
    PORTB = 111111
    PORTA = 110111
    Value = 100
    
    '============ main loop starts here=================
    mainloop:
    Value = Value + 1
    IF Value > 299 THEN Value = 0    ' Value increments from 0 to 299, rolls over to 0
    Pause 300
    GOTO mainloop
    '============================================================
    
    T1handler: 
    i = i +1
    IF i > 3 THEN i = 0 ' force i to be 0..2 and roll over to 0
        i = i & 000011
        PORTA.4 = i.0    ' wiggle the output bit for debug purposes
        n = Value DIG i    ' this statement causes missed interrupts after four are caught
    '    n = Value & 000111    ' this alternative statement works fine at 2000Hz 
    @ INT_RETURN  ' done with this interrupt pass
    
    ;---[TMR1 reload - interrupt handler]-----------------------------------------
    ASM                               ; Calculate Timer Reload Constant
    ReloadInst  = 8                   ; # of Intructions used to reload timer
      if ((Prescaler == 1)||(Prescaler == 2)||(Prescaler == 4)||(Prescaler == 8))
    MaxCount    = 65536 + (ReloadInst / Prescaler)
    TimerReload = MaxCount - (OSC*1000000/4/Prescaler/Freq)
        if ((TimerReload < 0) || (TimerReload > (65535-ReloadInst)))
            error Invalid Timer Values - check "OSC", "Freq" and "Prescaler"
        endif
      else
          error Invalid Prescaler
      endif
    ENDASM
    
    @Timer1 = TMR1L                   ; map timer registers to a word variable
    Timer1       VAR WORD EXT
    TimerReload  CON EXT              ; Get the External Constant
    TMR1ON       VAR T1CON.0          ; Alias the Timers ON/OFF bit
    
    ;---Reload Timer1------
    ASM
    ReloadTMR1
        MOVE?CT  0, T1CON, TMR1ON     ;  1     stop timer
        MOVLW    LOW(TimerReload)     ;  1     Add TimerReload to the 
        ADDWF    TMR1L,F              ;  1     value in Timer1
        BTFSC    STATUS,C             ;  1/2
        INCF     TMR1H,F              ;  1
        MOVLW    HIGH(TimerReload)    ;  1
        ADDWF    TMR1H,F              ;  1
        MOVE?CT  1, T1CON, TMR1ON     ;  1     start timer
      INT_RETURN
    ENDASM
    
    ;---Start/Stop controls -----
    StartTimer:
        Timer1  = TimerReload         ; Load Timer
        TMR1ON = 1                    ; start timer
    RETURN
    
    StopTimer:
        TMR1ON = 0                    ; stop timer
    RETURN

  8. #8
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default Re: Strange results with PBP3 and instant interrupts

    Like Henrik said, @ 4Mhz the DIG command takes longer than the interrupt period.
    But it's a little different than you might think.

    The digit number that you request makes a huge difference in the execution time.

    @ 4Mhz, DIG 0 takes ~322us, well within the 1ms period.
    But DIG 1 has to do another divide, so it takes ~638 uS.
    DIG 2 = 950us.
    And finally, DIG 3 takes ~1.28ms, obviously too long to be in a 1ms interrupt.
    After that, the timer reload leaves it overflowed and it has to count all the way back to 65536 before the next interrupt happens. Which is why it seemed like it was doing 4 interrupts at a time.



    These times were measured by wrapping the DIG command with HIGH/LOW statements and reading the pulse width on a scope.
    Code:
    HIGH PORTA.3
        n = Value DIG i    ' this statement causes missed interrupts after four are caught
    LOW PORTA.3
    After bumping up the oscillator to 16Mhz internal, the commands take 1/4th of the time and everything works within the 1ms.

    But since the digit only changes when the variable in the mainloop changes, there's no need to calculate it every time in the interrupt handler.
    Setting the segment patterns in the mainloop will reduce the interrupt handlers time significantly. Then the interrupt handler just puts the pattern to the pins.
    You could probably run at ~20Khz, not that you would want to. 1Khz is fine and there lots of time left over for the mainlop to use.

    So that brings us back to how could it work on PBP 2.60 with a 16F, and not on PBP3 with an enhanced core..

    Well, I don't think that's possible.
    I ran the same program on a 16F886 @ 4Mhz, and DIG took even longer
    DIG 0 = 385us
    DIG 1 = 760us
    DIG 2 = 1.15ms
    DIG 3 = 1.54ms

    Maybe you were running at a different frequency and didn't remember it?
    DT

Members who have read this thread : 0

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts