HenrikOlsson
- 18th August 2016, 21:38
With this post I'd like to visually demonstrate what kind of latency and overhead to expect when using DT-Ints. I'd like to point out that I am i no way criticising DT-ints, they are wonderful to work with and I could not imagine PBP without them but when you need to interrupt at high speed they are not that great and I wanted to put some numbers on it.
To measure this I wrote a very simple piece of code, all it does is toggle an output as fast as it can. Then a periodic timer interrupt was introduced and in the actual interrupt service routine a short pulse on another output was created. Here's what that looks like on a scope:
8292
The top (blue) trace shows the output normally toggling at a fast rate. The bottom (yellow) trace shows the pulse generated by the code in the interrupt service routine. If we zoom in a little bit we can put some cursors on the screen and measure the latency:
8291
As soon as the interrupt trips the main code stops executing (output stops toggling) but OUR code in the interrupt service routine (which is what generates the pulse on the yellow trace) doesn't start to exectute until around DT-Ints have had to time to store a copy of the system variables which in this case takes around 7us. This PIC is running at 64MHz which means the latency on entry is roughly 112 instruction cycles.
As soon as the falling edge of the pulse occurs we're done in the ISR and DT-Ints now has to restore all the system variables, clearing the interrupt flag and so on which takes slightly longer than on entry, around 8us or 128 instruction cycles:
8290
So, even though we're only spending 5us in the actual interrupt service routine the main routine is suspended for almost 21us - at 64MHz clock frequency. Even if no code at all was actually executed in the ISR the save and restore process that DT-Ints needs to perform takes, at the very least, somewhere around 240 instruction cycles. Now, 240 instruction cycles at 64MHz is "only" 15us which may no seem like much but if you're trying to interrupt at, lets say 25kHz you only got 40us between each interrupt. Spending 15 of those traveling to and from the interrupt plus, lets say, 5us in the ISR makes the 64MHz PIC "feel" like a 32MHz PIC. Any software timed commands in the main code (like PAUSE, SERIN, PULSIN etc) will off by a factor of 2.
The above tests were done on an 18F25K20 running at 64MHz, using PBP 3.0.8.0 with support for LONGs disabled. With LONGs enabled the 15us overhead increases to roughly 18us or around 290 instruction cycles.
Here's the code I used:
DEFINE OSC 64
DEFINE LOADER_USED 1 ' We're using a bootloader.
INCLUDE "DT_INTS-18.bas"
INCLUDE "ReEnterPBP-18.bas"
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR0_INT, _TimezUp, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM
ANSEL = 0
ANSELH = 0
TRISB = %11111100 ' PortB.0 and PortB.1 are outputs.
' Configure TMR0 to roll over at a rate of 31250Hz (every 32us)
T0CON=%11000010 ' TMR0 on, 8bit mode, 1:2 prescaler
@ INT_ENABLE TMR0_INT ; Enable INT0 interrupts
Main:
LATB.1 = !LATB.1 ' Toggle PortB.1 as fast as we can
Goto Main
TimezUp:
' Create a short pulse on PortB.0
LATB.0 = 1
PAUSEUS 5
LATB.0 = 0
@ INT_RETURN
/Henrik.
To measure this I wrote a very simple piece of code, all it does is toggle an output as fast as it can. Then a periodic timer interrupt was introduced and in the actual interrupt service routine a short pulse on another output was created. Here's what that looks like on a scope:
8292
The top (blue) trace shows the output normally toggling at a fast rate. The bottom (yellow) trace shows the pulse generated by the code in the interrupt service routine. If we zoom in a little bit we can put some cursors on the screen and measure the latency:
8291
As soon as the interrupt trips the main code stops executing (output stops toggling) but OUR code in the interrupt service routine (which is what generates the pulse on the yellow trace) doesn't start to exectute until around DT-Ints have had to time to store a copy of the system variables which in this case takes around 7us. This PIC is running at 64MHz which means the latency on entry is roughly 112 instruction cycles.
As soon as the falling edge of the pulse occurs we're done in the ISR and DT-Ints now has to restore all the system variables, clearing the interrupt flag and so on which takes slightly longer than on entry, around 8us or 128 instruction cycles:
8290
So, even though we're only spending 5us in the actual interrupt service routine the main routine is suspended for almost 21us - at 64MHz clock frequency. Even if no code at all was actually executed in the ISR the save and restore process that DT-Ints needs to perform takes, at the very least, somewhere around 240 instruction cycles. Now, 240 instruction cycles at 64MHz is "only" 15us which may no seem like much but if you're trying to interrupt at, lets say 25kHz you only got 40us between each interrupt. Spending 15 of those traveling to and from the interrupt plus, lets say, 5us in the ISR makes the 64MHz PIC "feel" like a 32MHz PIC. Any software timed commands in the main code (like PAUSE, SERIN, PULSIN etc) will off by a factor of 2.
The above tests were done on an 18F25K20 running at 64MHz, using PBP 3.0.8.0 with support for LONGs disabled. With LONGs enabled the 15us overhead increases to roughly 18us or around 290 instruction cycles.
Here's the code I used:
DEFINE OSC 64
DEFINE LOADER_USED 1 ' We're using a bootloader.
INCLUDE "DT_INTS-18.bas"
INCLUDE "ReEnterPBP-18.bas"
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR0_INT, _TimezUp, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM
ANSEL = 0
ANSELH = 0
TRISB = %11111100 ' PortB.0 and PortB.1 are outputs.
' Configure TMR0 to roll over at a rate of 31250Hz (every 32us)
T0CON=%11000010 ' TMR0 on, 8bit mode, 1:2 prescaler
@ INT_ENABLE TMR0_INT ; Enable INT0 interrupts
Main:
LATB.1 = !LATB.1 ' Toggle PortB.1 as fast as we can
Goto Main
TimezUp:
' Create a short pulse on PortB.0
LATB.0 = 1
PAUSEUS 5
LATB.0 = 0
@ INT_RETURN
/Henrik.