DT-Ints latency and other interrupt conciderations


Closed Thread
Results 1 to 40 of 59

Hybrid View

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


    Did you find this post helpful? Yes | No

    Default

    Well let's see what we can do here ...

    Since it's an 18F, with "qualified" ASM handlers ...
    You can remove the remaining overhead by removing DT_INTS all together, and using an ASM ISR, written in PBP of course.

    Something like this ...
    Code:
    DEFINE INTHAND _ISR
    DEFINE NO_CLRWDT 1
    
    ;---------------------------------------------------------------------------
    ISR:
      IF INTCON3.1 THEN             ' IF INT2 triggered
    DoStep:
        If PortB.1 = 1 THEN         'Direction signal connected to PortB.1
          Setpoint = Setpoint + 1    'Setpoint is a 32bit variable
        ELSE
          Setpoint = Setpoint - 1
        ENDIF
        INTCON3.1 = 0               ' clear the int flag
      ENDIF
        
    RollOver:
      IF PIR3.2 = 1 THEN            ' if IC2QEIF triggered
        IF QEICON.5 = 1 then
          Position.Word1 = Position.Word1 + 1    'Position is a LONG
        ELSE
          Position.Word1 = Position.Word1 - 1
        ENDIF
        PIR3.2 = 0                  ' clear the int flag
      ENDIF
    @   RETFIE FAST                 ; return from interrupt with shadow regs
    Setpoint is handled as a LONG, but if you can use a BYTE sized result, you can change it to Setpoint.byte0 to reduce it by a few instructions.

    The NO_CLRWDT drops a couple more instructions, but make sure the WDT is OFF.

    Compiled, it looks like this, including both handlers ...
    Code:
    _ISR
            btfss   INTCON3, 001h
            goto    _RollOver
    _DoStep
            btfss   PORTB, 001h
            goto    L00003
            incf    _Setpoint, F
            clrf    WREG
            addwfc  (_Setpoint) + 1, F
            addwfc  (_Setpoint) + 2, F
            addwfc  (_Setpoint) + 3, F
            goto    L00004
    L00003
            decf    _Setpoint, F
            clrf    WREG
            subwfb  (_Setpoint) + 1, F
            subwfb  (_Setpoint) + 2, F
            subwfb  (_Setpoint) + 3, F
    L00004
            bcf     INTCON3, 001h
    _RollOver
            btfss   PIR3,  002h
            goto    L00005
            btfss   QEICON, 005h
            goto    L00007
            incf    _Position??WORD1, F
            movlw   0
            addwfc  (_Position??WORD1) + 1, F
            goto    L00008
    L00007
            decf    _Position??WORD1, F
            movlw   0
            subwfb  (_Position??WORD1) + 1, F
    L00008
            bcf     PIR3,   002h
    L00005
        RETFIE FAST                 ; return from interrupt with shadow regs
    Hope that gets it closer.
    DT

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


    Did you find this post helpful? Yes | No

    Default

    Thanks Darrel,
    Now I'm a bit confused.... Will this allow me to still use DT-Ints for the low-priority interrupts? The actual servo-loop code is, as I said earlier, triggered as a low priority interrupt by TMR2 and I also have a second low priority interrupt for handling USART comms (which isn't used during the tests I've made so far).

    Does the RETFIE FAST automatically restore the STATUS, W etc registers or is that not needed due to the "shadow regs"? As you can see I really suck at the low level stuff...

    Before seeing your message I tried changing the RollOver ISR to type ASM but it didn't make much difference. Up to 20kHz it works fine, above that it starts to fall apart and I can't really see why.

    Your assistance is much apprecited, thanks!

    /Henrik.

  3. #3
    Join Date
    Feb 2005
    Location
    Kolkata-India
    Posts
    563


    Did you find this post helpful? Yes | No

    Default Shadow Fight !!

    Hi,

    Darrel correct me if I am wrong, I am a bit rusty here.

    The shadow registers are not memory mapped but are actually hardware registers, a single level deep hardware stack that can save your context (W,Status, BSR). Optional during <b>call, something s , </b> or a <b>return, something s , </b> and automatic when entering interrupt. You decide whether you want to restore them by Retfie Fast . So when a low priority interrupt (0x0018h) is interrupted by a high priority one, the context saved while entering the low priority is lost. Thus it works best if you are using only HP Ints or using it for only HP Ints.
    Regards

    Sougata

  4. #4
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,612


    Did you find this post helpful? Yes | No

    Default

    Hi again,
    I'll start by quoting myself:
    Before seeing your message I tried changing the RollOver ISR to type ASM but it didn't make much difference. Up to 20kHz it works fine, above that it starts to fall apart and I can't really see why.
    Correction/clarification somewhere between 17.5-18kHz something happens which makes the TMR2 LP interrupt frequency start to drop. I guess the HP priority interrupts are stealing so much time that the TMR2 interrupts "runs over itself".

    At 32kHz the high priority DoStep ISR still tracks the step pulses correctly but now the TMR2 ISR is only run at ~550Hz instead of 1220Hz which can be both heard and felt from the motor. Going higher than this (I tried 33kHz) completely unstabilizes the servo-loop so I don't know how high the INT2 interrupt will actually track the pulses.

    /Henrik.

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


    Did you find this post helpful? Yes | No

    Default

    I think that both INT2 and TMR2 interrupts should be HIGH priority.
    The USART can be LOW priority, since servicing it is not really time critical.
    But no, you won't be able to use DT_INTS for just the Low Priority.

    Sougata is correct about the shadow registers...
    They are only good for High Priority interrupts.
    For Low priority ints you have to save W, STATUS and BSR in the ISR.

    What are you doing with the USART handler?
    Stuffing the bytes in a buffer?
    <br>
    DT

  6. #6
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,612


    Did you find this post helpful? Yes | No

    Default

    Hi,
    At the moment I'm not doing anything with the USART interrupt - it's never been fired during these tests. But I'll need to use it for the "front end" later on - if I get there - and the is to stuff data into a buffer and signal the main program when a LF or CR arrives.

    Just so we're all on the same page, here are the current interupts:
    INT2_INT - High priority ISR in ASM
    IC2QEIF_INT - High priority ISR in PBP but "declared" as ASM in the INT_LIST macro
    TMR2_INT - Low priroity ISR in PBP
    RX_INT - Low priotity ISR in PBP


    I originally had the TMR2 interrupt as high priority but then I didn't get more than a few kHz before it started to miss pulses. The DoServo routine that is run as the TMR2 ISR is quite "heavy" since it does all the math including the PID routine:
    Code:
    DoServo:                                    'Interrupt handler starts here.
    PortB.5 = 1                                 'Used for timing purposes
    GetPosition:
    'Since the position counter isn't double buffered we can get to situations
    'where the lowbyte overflows between readings of the high and low byte. This
    'is prevented by reading the high byte two times and compare the two readings.
    'If they are the same then we're fine, if not re-read the registers.
      
        PosHigh = POSCNTH                       'Get high byte of counter
        PosLow = POSCNTL                        'Get low byte of counter
        PosTemp = POSCNTH                       'Get high byte again
        
        If PosHigh - PosTemp = 0 then Goto Done 'Compare, if equal we're done.
        
        PosHigh = POSCNTH                       'If not, get values again.
        PosLow = POSCNTL
    
    Done:  
    'The high word of the Position variable is handled by the RollOver ISR that gets
    'tripped by IC2QEIF when POSCNT = MAXCNT.
        
        Position.Word0 = POSHIGH * 256 + PosLow 'Put high and lowbyte together.
        Speed = Position - oldPosition          'Calculate current motor speed.
    
        INTCON3.4 = 0                           'Temporarily disable INT2 interrupt
        TempStepBuffer = StepBuffer
        StepBuffer = 0
        INTCON3.4 = 1                           'Re-enable INT2 interrupt.
    
        If TempStepBuffer.7 = 1 then            'Step buffer is negative
         Setpoint = Setpoint - ABS (TempStepBuffer)
        Else
         SetPoint = Setpoint + TempStepBuffer
        Endif
        pid_Error = Setpoint - Position          'Calculate error....
        
    'Now we have our error-signal in the variable that the PID-routine expects
    'so we call the PID-filter with a GOSUB. The filter will respond with the
    'output in variable pid_out.
    
        Gosub PID                               'and send to PID filter
    ' (PID filter execution time measured to ~190uS worst case @20Mhz)
     
        If pid_out.15 = 0 then                  'If the output from the pid-filter
           Direction = 1                        'is positive we want to drive the
           Duty = pid_Out                       'motor forward.
        Else
           Direction = 0                        'If it's negative we want to drive
           Duty = ABS (pid_Out)                 'it backwards.
        Endif
    
        CCP1CON.5 = Duty.1                      'Set the two LSB's of the dutycycle-
        CCP1CON.4 = Duty.0                      'register. Then shift them out and
        CCPR1L = Duty >> 2                      'set the remainig 8 bits.
        
        oldPosition = Position                  'Store position for next interrupt.
    
    ISRCount = ISRCount + 1
    PortB.5 = 0
    
    @  INT_RETURN                               ;ISR is complete, return from here.
    The actual PID code isn't shown here, I've measured the execution time of the complete DoServo ISR and it seems to vary alot, from 160uS all the way up to 400uS.

    So, I guess I'll need to stick with DT-Ints since re-writing the DoServo routine including the PID code in ASM would take me years. Question is what else, if anything, can be improved to increase the speed. The thing is that I was hoping to add more code to the DoServo routine but I guess that may not be a good idea.

    Thanks alot guys!

    /Henrik.

  7. #7
    Join Date
    Feb 2005
    Location
    Kolkata-India
    Posts
    563


    Did you find this post helpful? Yes | No

    Default Any possibilities of checking INTs within INTs

    Henrik,

    I wonder if there could be any hardware optimizations however I would just like to remind you:

    Even if an Interrupt is Enabled (IE bit), the Flag (IF bit) always gets set. So it might just be possible to check within an interrupt that if other sources triggered. This enables you to pre-service that interrupt without a return then re-entry. This can save a lot of cycles with the penalty of a bit more code space.
    Regards

    Sougata

Members who have read this thread : 2

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