Determine interrupt length
Matthias09
Posts: 47
Hey guys,
have a happy new year, filled with plenty of pleasures in live and lot's of success in programming!
I am currently working on a program with cyclical interrupts, with 50Mhz, I run 100000 interrupts per second or 1 interrupt every 10us. Now I have to ensure that within this 10us I can end the interrupt (which is lengthy, see below) and also have time to continue with my actual program.
With 50Mhz, I can do 500 clock cylces between the first and second interrupt, whereas every instruction needs 1-4 clock cycles to be exectuted. Now my question: give the interrupt routine below, how could I find out if 500 cycles are sufficient to finish all instructions before the next interrupt occurs? would I count the amount of instructions, and in worst case scenarios multiply them with 4 clock cylces each? Well you guess, I am a bit clueless Help would be as always most appreciated.
Though I write in Basic, I believe it is more helpful to use assembly code for that problem. Nevertheless, Basic code is below as well. As you can see the lenght of the executed interrupt depends on some variables. As I am interested in the maximum amount of clock cylces used, I would just assume that every part of the interrupt is running and not bother about them. (excluding if statements of course)
Thanks guys and happy new year!!!
Matthias
PS: what would happen if one interrupt needs longer than 10us. Would the next one be executed or skipped?
Post Edited (Matthias09) : 1/3/2010 1:13:32 PM GMT
have a happy new year, filled with plenty of pleasures in live and lot's of success in programming!
I am currently working on a program with cyclical interrupts, with 50Mhz, I run 100000 interrupts per second or 1 interrupt every 10us. Now I have to ensure that within this 10us I can end the interrupt (which is lengthy, see below) and also have time to continue with my actual program.
With 50Mhz, I can do 500 clock cylces between the first and second interrupt, whereas every instruction needs 1-4 clock cycles to be exectuted. Now my question: give the interrupt routine below, how could I find out if 500 cycles are sufficient to finish all instructions before the next interrupt occurs? would I count the amount of instructions, and in worst case scenarios multiply them with 4 clock cylces each? Well you guess, I am a bit clueless Help would be as always most appreciated.
Though I write in Basic, I believe it is more helpful to use assembly code for that problem. Nevertheless, Basic code is below as well. As you can see the lenght of the executed interrupt depends on some variables. As I am interested in the maximum amount of clock cylces used, I would just assume that every part of the interrupt is running and not bother about them. (excluding if statements of course)
Thanks guys and happy new year!!!
Matthias
PS: what would happen if one interrupt needs longer than 10us. Would the next one be executed or skipped?
ISR_Start: ; ISR_Start: INC Tix_LSB ; INC Tix ' waiting for 1 tix means waiting for 10us ADDB Tix_MSB,Z ;'-----ULTRASOUND----- ;'only run, when in measuremend mode in main loop MOV FSR,#General_Var+1 ; IF General_Var(1) = 5 THEN ' status of the USD: 2=wait+start pulse, 3=end pulse + prepare reading, 4=reading MOV __PARAM1,IND BANK $00 CJNE __PARAM1,#5,@__ELSE_1 JNB USD_Pin,@__ELSE_2 ; IF USD_Pin = 1 THEN ' measuring the ping pulse. count up time variable (rawdata) as long as there is high at the USD INC rawdata_LSB ; INC rawdata ' store results in rawdata ADDB rawdata_MSB,Z __ELSE_2: ; ENDIF __ENDIF_2: __ELSE_1: ; ENDIF __ENDIF_1: ;'-----ENCODER----- ;'run in every cycle (maybe not necessary) MOV __PARAM1,EncoderP ; EncVar(3) = EncoderP & %0000_0011 ' reads A and B channel. Filter out for reading only Pin 0, 1 AND __PARAM1,#%0000_0011 MOV FSR,#EncVar+3 MOV IND,__PARAM1 BANK $00 MOV __PARAM1,EncoderP ; EncVar(5) = EncoderP & %0000_0100 ' reads Index Channel. Filter out for reading Pin 2 AND __PARAM1,#%0000_0100 MOV FSR,#EncVar+5 MOV IND,__PARAM1 BANK $00 MOV FSR,#EncVar+5 ; IF EncVar(5) > 0 THEN ' If index channel is read, then set angle to 90 and leave this interrupt encoder part MOV __PARAM1,IND BANK $00 CJBE __PARAM1,#0,@__ELSE_3 MOV current_angle_LSB,#9000 & 255 ; current_angle = 9000 ' actually 90,00. MOV current_angle_MSB,#9000 >> 8 JMP @Exit_Encoder ; GOTO Exit_Encoder ' skip the rest in this cycle as I already have my value __ELSE_3: ; ENDIF __ENDIF_3: MOV FSR,#EncVar+2 ; EncVar(4) = EncVar(2) XOR EncVar(3) ' test for change: compare old and new measurement. XOR filters out changes (gives out 1 for 0, 1 and 1, 0) MOV __PARAM1,IND MOV FSR,#EncVar+3 XOR __PARAM1,IND MOV FSR,#EncVar+4 MOV IND,__PARAM1 BANK $00 MOV FSR,#EncVar+4 ; IF EncVar(4) > 0 THEN ' check if something changed, XOR wrote one or several 1 somewhere in EncVar(4). Doesn't matter where, but it's > 0 then MOV __PARAM1,IND BANK $00 CJBE __PARAM1,#0,@__ELSE_4 MOV FSR,#EncVar+2 ; EncVar(2) = EncVar(2) << 1 ' adjust old bits CLC RL IND BANK $00 MOV FSR,#EncVar+3 ; EncVar(2) = EncVar(2) XOR EncVar(3) ' test direction, save in same variable to safe space MOV __PARAM2,IND MOV FSR,#EncVar+2 XOR IND,__PARAM2 BANK $00 MOV FSR,#EncVar+2 ; IF EncVar(2).1 = 1 THEN MOV __PARAM1,IND BANK $00 JNB __PARAM1.1,@__ELSE_5 ADD current_angle_LSB,#25 & 255 ; current_angle = current_angle + 25 'increase with 0.25 (4 pulses per 1 circulation, 4 pulses per one degree) ADDB current_angle_MSB,C ADD current_angle_MSB,#25 >> 8 JMP @__ENDIF_5 ; ELSE __ELSE_5: SUB current_angle_LSB,#25 & 255 ; current_angle = current_angle - 25 'decrease SUBB current_angle_MSB,/C SUB current_angle_MSB,#25 >> 8 __ENDIF_5: ; ENDIF MOV FSR,#EncVar+3 ; EncVar(2) = EncVar(3) ' save current reading for next interrupt MOV __PARAM2,IND BANK $00 MOV FSR,#EncVar+2 MOV IND,__PARAM2 BANK $00 __ELSE_4: ; ENDIF __ENDIF_4: Exit_Encoder: ; Exit_Encoder: ;'-----STEPPER----- ;'just run it always. MOV FSR,#General_Var+1 ;IF General_Var(1) > 0 THEN MOV __PARAM1,IND BANK $00 CJBE __PARAM1,#0,@__ELSE_6 MOV FSR,#General_Var+2 ; INC General_Var(2) ' this and 100 below lets you control speed; I leave that to you INC IND BANK $00 MOV FSR,#General_Var+2 ; IF General_Var(2) >= 255 THEN ' step once per 18 milliseconds (180 * 100us) = 18000us = 18ms MOV __PARAM1,IND BANK $00 CJB __PARAM1,#255,@__ELSE_7 MOV FSR,#General_Var+2 ; General_Var(2) = 0 CLR IND BANK $00 CJNE StepperMode,#CW,@__ELSE_8 ; IF StepperMode = CW THEN MOV FSR,#General_Var+3 ; INC General_Var(3) INC IND BANK $00 JMP @__ENDIF_8 ; ELSEIF StepperMode = CCW THEN __ELSE_8: CJNE StepperMode,#CCW,@__ELSE_9 MOV FSR,#General_Var+3 ; DEC General_Var(3) DEC IND BANK $00 JMP @__ENDIF_8 ; ELSEIF StepperMode = Stop THEN __ELSE_9: CJNE StepperMode,#Stop,@__ELSE_10 JMP @StopStepper ; GOTO StopStepper __ELSE_10: ; ENDIF __ENDIF_8: MOV FSR,#General_Var+3 ; General_Var(3) = General_Var(3) & %111 ' Filter out 0-7. E.g. 15 = %1111 becomes %111 = 7. The 3 LST repeat after 8. That's what I need. AND IND,#%111 BANK $00 MOV FSR,#General_Var+3 ; IF General_Var(3) = 1 THEN MOV __PARAM1,IND BANK $00 CJNE __PARAM1,#1,@__ELSE_11 MOV StepperP,#%1000 ; StepperP = %1000 JMP @__ENDIF_11 ; ELSEIF General_Var(3) = 2 THEN __ELSE_11: MOV FSR,#General_Var+3 MOV __PARAM1,IND BANK $00 CJNE __PARAM1,#2,@__ELSE_12 MOV StepperP,#%1001 ; StepperP = %1001 JMP @__ENDIF_11 ; ELSEIF General_Var(3) = 3 THEN __ELSE_12: MOV FSR,#General_Var+3 MOV __PARAM1,IND BANK $00 CJNE __PARAM1,#3,@__ELSE_13 MOV StepperP,#%0001 ; StepperP = %0001 JMP @__ENDIF_11 ; ELSEIF General_Var(3) = 4 THEN __ELSE_13: MOV FSR,#General_Var+3 MOV __PARAM1,IND BANK $00 CJNE __PARAM1,#4,@__ELSE_14 MOV StepperP,#%0101 ; StepperP = %0101 JMP @__ENDIF_11 ; ELSEIF General_Var(3) = 5 THEN __ELSE_14: MOV FSR,#General_Var+3 MOV __PARAM1,IND BANK $00 CJNE __PARAM1,#5,@__ELSE_15 MOV StepperP,#%0100 ; StepperP = %0100 JMP @__ENDIF_11 ; ELSEIF General_Var(3) = 6 THEN __ELSE_15: MOV FSR,#General_Var+3 MOV __PARAM1,IND BANK $00 CJNE __PARAM1,#6,@__ELSE_16 MOV StepperP,#%0110 ; StepperP = %0110 JMP @__ENDIF_11 ; ELSEIF General_Var(3) = 7 THEN __ELSE_16: MOV FSR,#General_Var+3 MOV __PARAM1,IND BANK $00 CJNE __PARAM1,#7,@__ELSE_17 MOV StepperP,#%0010 ; StepperP = %0010 JMP @__ENDIF_11 ; ELSEIF General_Var(3) = 8 THEN __ELSE_17: MOV FSR,#General_Var+3 MOV __PARAM1,IND BANK $00 CJNE __PARAM1,#8,@__ELSE_18 MOV StepperP,#%1010 ; StepperP = %1010 __ELSE_18: ; ENDIF __ENDIF_11: StopStepper: ; StopStepper: __ELSE_7: ; ENDIF __ENDIF_7: __ELSE_6: ; ENDIF __ENDIF_6: ISR_Exit: ; ISR_Exit: MOV FSR,#__INTPARAMFSR ; RETURNINT ' end of interrupt handler MOV M,IND INC FSR MOV __PARAM1,IND INC FSR MOV __PARAM2,IND INC FSR MOV __PARAM3,IND INC FSR MOV __PARAM4,IND MOV W,#6 RETIW
INTERRUPT 100_000 ' 100000 interrupts per sec, or: 1 interrupt every 10us GOTO INTERRUPT_CODE ' write routine below after the definition of the subroutines. they have to be defined in the 1st half page of the memory ' and lengthy interrupt is pushing them downwards into 2nd half which makes them not callable anymore '============## SUBROUTINES ##====================================================================================================================================== STEPPER_TEST SUB 0 DRIVE_SERVO SUB 1 PROGRAM Start ' indicates the program starts at the label "start" ' this command must appear after the interrupt definition '============## INTERRUPT CODE ##====================================================================================================================================== INTERRUPT_CODE: ISR_Start: INC Tix ' waiting for 1 tix means waiting for 10us '-----ULTRASOUND----- 'only run, when in measuremend mode in main loop IF General_Var(1) = 5 THEN ' status of the USD: 2=wait+start pulse, 3=end pulse + prepare reading, 4=reading IF USD_Pin = 1 THEN ' measuring the ping pulse. count up time variable (rawdata) as long as there is high at the USD INC rawdata ' store results in rawdata ENDIF ENDIF '-----ENCODER----- 'run in every cycle (maybe not necessary) EncVar(3) = EncoderP & %0000_0011 ' reads A and B channel. Filter out for reading only Pin 0, 1 EncVar(5) = EncoderP & %0000_0100 ' reads Index Channel. Filter out for reading Pin 2 IF EncVar(5) > 0 THEN ' If index channel is read, then set angle to 90 and leave this interrupt encoder part current_angle = 9000 ' actually 90,00. GOTO Exit_Encoder ' skip the rest in this cycle as I already have my value ENDIF EncVar(4) = EncVar(2) XOR EncVar(3) ' test for change: compare old and new measurement. XOR filters out changes (gives out 1 for 0, 1 and 1, 0) IF EncVar(4) > 0 THEN ' check if something changed, XOR wrote one or several 1 somewhere in EncVar(4). Doesn't matter where, but it's > 0 then EncVar(2) = EncVar(2) << 1 ' adjust old bits EncVar(2) = EncVar(2) XOR EncVar(3) ' test direction, save in same variable to safe space IF EncVar(2).1 = 1 THEN current_angle = current_angle + 25 'increase with 0.25 (4 pulses per 1 circulation, 4 pulses per one degree) ELSE current_angle = current_angle - 25 'decrease ENDIF EncVar(2) = EncVar(3) ' save current reading for next interrupt ENDIF Exit_Encoder: '-----STEPPER----- 'just run always IF General_Var(1) > 0 THEN INC General_Var(2) ' this and 100 below lets you control speed; I leave that to you IF General_Var(2) >= 255 THEN ' step once per 18 milliseconds (180 * 100us) = 18000us = 18ms General_Var(2) = 0 IF StepperMode = CW THEN INC General_Var(3) ELSEIF StepperMode = CCW THEN DEC General_Var(3) ELSEIF StepperMode = Stop THEN GOTO StopStepper ENDIF General_Var(3) = General_Var(3) & %111 ' Filter out 0-7. E.g. 15 = %1111 becomes %111 = 7. The 3 LST repeat after 8. That's what I need. IF General_Var(3) = 1 THEN StepperP = %1000 ELSEIF General_Var(3) = 2 THEN StepperP = %1001 ELSEIF General_Var(3) = 3 THEN StepperP = %0001 ELSEIF General_Var(3) = 4 THEN StepperP = %0101 ELSEIF General_Var(3) = 5 THEN StepperP = %0100 ELSEIF General_Var(3) = 6 THEN StepperP = %0110 ELSEIF General_Var(3) = 7 THEN StepperP = %0010 ELSEIF General_Var(3) = 8 THEN StepperP = %1010 ENDIF StopStepper: ENDIF ENDIF ISR_Exit: RETURNINT ' end of interrupt handler
Post Edited (Matthias09) : 1/3/2010 1:13:32 PM GMT
Comments
It will also tell you if there are too many clocks used in the interrupt.
Bean.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Use BASIC on the Propeller with the speed of assembly language.
PropBASIC thread http://forums.parallax.com/showthread.php?p=867134·