Determine interrupt length
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·