SX/B Interrupt Latency
Wia
Posts: 5
Hello,
I have a question about the time it takes for the SX to respond to an interrupt.
In my code, I want to trigger an interrupt on the rising edge of pin RB.0. The interrupt service routine simply toggles pin RC.0 high and then low.
According to the SX datasheet, the interrupt latency should be 3 clock cycles. (I am using a 50MHz external crystal.) When I look at pins RB.0 and RC.0 on an oscilloscope, the rising edge of RC.0 occurs over 1us after the rising edge of RB.0. That is over 50 clock cycles.
Does SX/B automatically add some latency in the interrupt response? Or am I just doing something very wrong? I have just started learning SX/B (yesterday!), so hopefully I am just missing something simple. Any help would be greatly appreciated!
Thank you!
I have a question about the time it takes for the SX to respond to an interrupt.
In my code, I want to trigger an interrupt on the rising edge of pin RB.0. The interrupt service routine simply toggles pin RC.0 high and then low.
According to the SX datasheet, the interrupt latency should be 3 clock cycles. (I am using a 50MHz external crystal.) When I look at pins RB.0 and RC.0 on an oscilloscope, the rising edge of RC.0 occurs over 1us after the rising edge of RB.0. That is over 50 clock cycles.
Does SX/B automatically add some latency in the interrupt response? Or am I just doing something very wrong? I have just started learning SX/B (yesterday!), so hopefully I am just missing something simple. Any help would be greatly appreciated!
Thank you!
DEVICE SX48, OSCHS3 FREQ 50_000_000 ID "Test" ' ------------------------------------------------------------------------- ' I/O Pins ' ------------------------------------------------------------------------- ADC_DATA PIN RD 'ADC Data input on Port D PIX_DATA PIN RE 'Pixel Data output on Port E SX_CLK PIN RC.0 'SX generated clock PX_CLK PIN RB.0 'Pixel Clock (interrupt input) GPIO_0 PIN RB.1 'GPIO_0 from PMT Controller GPIO_1 PIN RB.2 'GPIO_1 from PMT Controller SEL PIN RB.3 'Select from PMT Controller, analog or photon count ' ------------------------------------------------------------------------- ' Variables ' ------------------------------------------------------------------------- ADC_In VAR Byte Int_Check VAR Byte ' ========================================================================= INTERRUPT ' ========================================================================= ISR_Start: 'Int_Check = WKPND_B 'If Int_Check <>%00000001 Then ISR_Exit 'Check to make sure that interrupt due to pin RB.0 SX_CLK = 1 'NOP 'NOP SX_CLK = 0 ISR_Exit: WKPND_B = 0 'Reset Port B interrupt flags RETURNINT ' ========================================================================= PROGRAM Start ' ========================================================================= ' ------------------------------------------------------------------------- ' Program Code ' ------------------------------------------------------------------------- Start: TRIS_B = %11111111 TRIS_C = %11111110 TRIS_D = %11111111 TRIS_E = %00000000 WKPND_B = %00000000 'Clear pending register WKED_B = %00000000 'Interrupt on rising edge WKEN_B = %11111110 'Enable interrupts on bit 0 only ADC_In = 0 SX_CLK = 0 'clock resets to 0 Main: ADC_In = ADC_DATA 'read the ADC PIX_DATA = ADC_In 'output pixel data GOTO Main
Comments
The SX only preserves the W, FSR and Status registers (and of course the stack and program counter) upon entry/exit of the ISR. SX/B cleverly preserves PARAM1-PARAM5 and M so that they are not clobbered when the user does things like use SX/B statements (which often use the PARAM variables as workspace) or change pin directions or do READs (which would clobber the M register).
You may want to use the NOCODE option for your ISR, and manually save M only if your ISR ends up using M for any reason (otherwise, don't save it). And of course, DON'T use PARAM variables in the ISR.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
1uffakind.com/robots/povBitMapBuilder.php
1uffakind.com/robots/resistorLadder.php
Post Edited (Zoot) : 4/20/2010 9:38:15 PM GMT
Thank you for your quick reply.
I checked out the List file, and I saw the extra instructions at the beginning and end of the ISR you mentioned. It looks like at the most there will be 10 clock cycles delay added at the beginning of the ISR from these instructions, so I am still not sure if this is where the huge latency is coming from.
I did try your suggestion of using the NOCODE option, and I had some interesting results.
Changing nothing in the above code except for adding NOCODE, the latency was drastically reduced, but there are now two interrupts triggered for each rising edge on pin RB.0. The first pulse generated by the ISR occurs 0.4us after the rising edge of RB.0, and the second occurs 1us after the same rising edge.
I figured that something other than the RB.0 interrupt must be causing the interrupt, so I added in code for checking the WKPND_B register (which was commented out in the code pasted above). So, the code for the ISR is now...
I now only have one interrupt per RB.0 rising edge, but the latency is back to 1us and for some reason it misses every third edge. It consistently triggers for two edges and then skips one. My input signal is a clean square wave without ringing, so I don't believe the input is the source of the problem.
Do you know how this could be caused just by adding "NOCODE"? Or have I just set my interrupt up incorrectly?
Again, thank you very much for your help!!
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
1uffakind.com/robots/povBitMapBuilder.php
1uffakind.com/robots/resistorLadder.php
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
1uffakind.com/robots/povBitMapBuilder.php
1uffakind.com/robots/resistorLadder.php
I've added the line
to my code, but I still get the same results.
Do I need to do something else to disable the PWM interrupts?
If I could get rid of the extra trigger for every pulse, the interrupt latency would still be either 0.4us (~20 clk cycles) or 1us (~50 clk cycles) depending on if I am eliminating the first or the second trigger. Is this latency normal? In my final design, I would need to be able to handle a trigger every 1us, so this timing probably wouldn't work out for me.
Thanks so much for all your help so far.
Doesn't give you much time in the mainline to do anything useful (like a read an ADC) as you might miss the next interrupt. You could think about incrementing a counter in the ISR for each edge on the sample, so that if the counter was > 1 you would know you missed a pin input (but could do something useful anyway):
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
1uffakind.com/robots/povBitMapBuilder.php
1uffakind.com/robots/resistorLadder.php
I realized that there was something wrong with my external crystal circuit, and I wasn't actually running at 50MHz. (After reading through the forum, I tried every combination of OSCHS2, OSCHS3, 1Mohm resistor, 10k resistor, no resistor, C1=15pF C2=33pF, C1=15pF C2=15pF... but with no luck.) I switched to the ceramic oscillator, and now I am actually at 50MHz. This has reduced the latency, but it still seems that the interrupt is taking far longer than it should. (I am still hoping for the 3 clock cycles described in the datasheet - or at least something close to 3.) Also, whenever I add the "NOCODE" option, I still trigger the interrupt twice for every rising edge. (The first at .2us, and the second at .4us). Removing NOCODE, I only trigger once at .4us. Any idea what could be causing the first faster trigger? If I could somehow only trigger on that one, the timing would probably be fast enough. I'll also try implementing your above code and see how that goes.
Thank you for all the time and thought you've put into the response. This has been really helpful.
Where are you getting 3 cycles? A pin-edge interrupt will take 5 cycles, possibly 6
Second, these instructions in SX/B are actually many more assembly instructions than you think:
Look at the list file (view list) and you'll see. If NOCODE isn't used, then you'll see even more.
Now, if you are ONLY checking for ONE possible pin on interrupt, and you've turned RTCC interrupts off, then you don't need to actually check WKPND_B, only clear it (the interrupt won't happen except on that one pin change):
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
1uffakind.com/robots/povBitMapBuilder.php
1uffakind.com/robots/resistorLadder.php
The 3-cycles interrupt info I was getting from the SX48 datasheet...
Fast and Deterministic Interrupt
• Jitter-free 3-cycle internal interrupt response
• Hardware context save/restore of key resources such
as PC, W, STATUS, and FSR within the 3-cycle
interrupt response time
• External wakeup/interrupt capability on Port B (8
pins)
The key word I was missing there was INTERNAL.
Thank you for posting the timing information for a pin-edge interrupt. I was not able to find this anywhere in the datasheet.
I've gotten rid of the code for checking WKPND_B, and that has helped a bit.
Thanks again for the help!
The point of the "deterministic" timing is that you can time things precisely if you are bit-banging at high speeds. If you know the INT takes 3 cycles, and you know you've got 10 cycles worth of instructions before a pin's state is toggled, then it will take 13 cycles after the interrupt detection to get your results. So you can plan for things very precisely.
Note also that while many instructions may only take one code word, that doesn't mean they only take once cycle. For example, JMP Label is one single instruction word, but takes 3 cycles to execute.
The pin-edge interrupt info is taken from the discussion about pin-edge interrupts in the SXKey / SX manual, not the datasheet.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
1uffakind.com/robots/povBitMapBuilder.php
1uffakind.com/robots/resistorLadder.php