Function: setint

Yex2

Well-known member
Hello,

I need some help with that function. I see that more than one gate can be used to trigger the interrupt.

The question is: can it be different interrupt or is it going to be the same with conditions inside?

For example, I want to turn on a LED if pin 0 is high and another if pin 1 is high. Normally I would do it this way. But can it be done using two distinct interrupt functions?:

Code:
setint %00000011,%00000011


main:

do

...

...

loop


interrupt:

if pin0 = 1 then : high 3

else if pin1 = 1 then : high 4

endif

setint %00000011,%00000011

return
******************************

Is something like this possible:

Code:
interrupt_0:
high 3
setint %00000011,%00000011
return


interrupt_1:
high 4
setint %00000011,%00000011
return
****************************

The obviously advantage would be the speed of execution.

Thank for your input,

Yves
 

hippy

Technical Support
Staff member
Unfortunately the PICAXE only supports one interrupt handling routine so, when interrupts come from two or more sources, one would need to determine which sources had trigged the interrupt and handle those accordingly, as in your first code.

It is possible to dynamically change the interrupt trigger so the interrupt will only occur whenever each source activates and deactivates. That can be used to improve overall responsiveness.
 

Yex2

Well-known member
Unfortunately the PICAXE only supports one interrupt handling routine so, when interrupts come from two or more sources, one would need to determine which sources had trigged the interrupt and handle those accordingly, as in your first code.
OK that is what I though. Thanks hippy!

It is possible to dynamically change the interrupt trigger so the interrupt will only occur whenever each source activates and deactivates. That can be used to improve overall responsiveness.
Can you provide an example for this?

Yex
 

hippy

Technical Support
Staff member
Here's example code of interrupting only on changes. Click pins C.1 and C.2 on and off to trigger an interrupt.

This runs in the PE6 simulator and should also run on physical hardware with the "MASK" constants changed to match.
Code:
#Picaxe 20M2
#Terminal 4800

;               76543210
Symbol MASKA = %00000010 ; C.1
Symbol MASKB = %00000100 ; C.2

Symbol MASK  = %00000110 ; All of the above

Symbol level = b2

PowerOnReset:
  SerTxd( "Started", CR, LF )
  Gosub Interrupt_Enable

MainLoop:
  Do
    Pause 100
  Loop

Interrupt:

  b0 = pinsC ^ level

  b1 = b0 And MASKA
  If b1 <> 0 Then
    b1 = b1 And level
    If b1 <> 0 Then
      SerTxd( "A (C.1) went low", CR, LF )
    Else
      SerTxd( "A (C.1) went high", CR, LF )
    End If
  End If

  b1 = b0 And MASKB
  If b1 <> 0 Then
    b1 = b1 & level
    If b1 <> 0 Then
      SerTxd( "B (C.2) went low", CR, LF )
    Else
      SerTxd( "B (C.2) went high", CR, LF )
    End If
  End If
  
  level = level ^ b0 And MASK
  SetInt Not level, MASK
  Return

Interrupt_Enable:
  level = pinsC And MASK
  SetInt Not level, MASK
  Return
 

Yex2

Well-known member
Hello hippy,

I'm having a discussion on the French forum about the time it takes for a pic to execute a line of code. There must be a way to know or calculate the time.

Can you provide insight in the matter ?

Thanks,

Yex
 

AllyCat

Senior Member
Hi,

The definitive thread is probably here but it is rather old now. The normal method is to add the instruction(s) into a FOR..NEXT loop and measure the increase in time over, say, 10 seconds. But the "direct" method that I use is described in post #12.

Cheers,, Alan.
 

hippy

Technical Support
Staff member
I'm having a discussion on the French forum about the time it takes for a pic to execute a line of code. There must be a way to know or calculate the time.
There is no easy way to determine the time it takes to execute a specific line of code accurately but it is usually possible to determine if a piece of code will complete within the time one wants it to run in.

One subtly shifts the question from how long it takes to; is it likely to work ?

For example, you appear to be wanting to determine how many pulses come from a flow meter. You could count those pulses using code like this -
Code:
#Picaxe 20M2

Symbol MASK    = %00000010 ; C.1

Symbol counter = w1 ; b3:b2
Symbol level   = b4 
 
Main:
  Gosub Interrupt_Enable
  Do
    Pause 100
  Loop

Interrupt:
  counter = level Max 1 + counter
  level = level ^ MASK
  SetInt level, MASK
  Return 

Interrupt_Enable:
  level = pinsC & MASK ^ MASK
  SetInt level, MASK
  Return
Then one can add up the number of words and symbols within the Interrupt routine; 17 'tokens' by my count.

And we have an established 'rule of thumb' that a "High <pin>" command takes 250us at 4MHz, so about 125us per token, so that interrupt routine should take about 17 x 125us, around 2ms at 4MHz.

So we can determine whether the code is likely to run fast enough or not. If you have a pulse every 10ms (100Hz) it should do fine, keep an accurate count. If it is a pulse every 1ms (1kHz) it will not be fast enough. With a pulse every 3ms (330Hz), maybe, maybe not.

But that's at 4MHz and every doubling of speed using SETFREQ halves the execution time, so, on an M2, the fastest speed of that interrupt is at 32MHz, when it takes about 250us. So that should be good for counting up to 4kHz. The slower the pulse rate is than that the more likely it is to be okay.

Looking at your posts in the other forum it seems 180Hz, a pulse every 5ms, would not be unreasonable to expect. If so then the PICAXE should be able to handle that at 4MHz and easily so at a higher operating speed.
 

hippy

Technical Support
Staff member
Code:
counter = level Max 1 + counter
I am counting rising edges there. It is equally possible to count both rising and falling edges.

If the pulses are square waves we will have doubled the resolution, increased the count accuracy and, if not, we have simply ended up with a count twice as large as it would otherwise be.

And the big advantage of counting both is it allows that code to be reduced to a simple -
Code:
counter = counter + 1
or
Code:
inc counter
Both of which are the same as far as the compiler is concerned so "inc" won't actually save more tokens than the first, but both do save tokens, increase execution speed, will allow higher pulse rates to be counted.
 

Yex2

Well-known member
Thanks AllyCat,

Hi Hippy,

I already wrote the interrruption code which is this. The chips frequency is set to 16 MHz :

Code:
interrupt:                          
if time > cycle then : today = 0 : endif     

inc impulsions                    
    if impulsions    >=etalon then     
        inc today                    
        inc total                
        impulsions =impulsions - etalon     
    endif

    if pinC.3 = 0 then                 
        setint %1000,%1000             
    else setint %0,%1000         
    endif

    enabletime                     
    time = 0                    
return
The flow-meter used generate a square wave that can either stop on LOW or HIGH, which is why the setint must be conditional to it's current state. Also it does read twice the pulse as you suggested.

The flow-meter is frequency range is from 32 to 90 Hz. Since I read both state (low and high) it's double and becomes 64 to 180 Hz. So the speed of the pulse will vary from ± 15.6 ms to 5.6 ms.

So my original question was to find out how fast is my interrupt routine is executed? Can it miss any pulse ?

My personal tests indicated that I'm not missing any pulse but I would like to know for sure.

Regards,

Yves
 
Last edited:

hippy

Technical Support
Staff member
So my original question was to find out how fast is my interrupt routine is executed? Can it miss any pulse ?
42 tokens at 125us per token gives about 5ms at 4MHz (200Hz), about 1.3ms at 16MHz (760Hz), so it should be fine.

That is also worse case, assuming all code would be executed every interrupt, and I don't believe it would be.
 

Yex2

Well-known member
Ok thank you hippy.

Other question: is my interrupt routine as efficient as the one you suggested?

I'm referring to this method or resetting the interrupt:

Code:
    if pinC.3 = 0 then                
        setint %1000,%1000            
    else setint %0,%1000        
    endif
Compare to yours:

Code:
Interrupt:
  inc counter
  level = level ^ MASK
  SetInt level, MASK
  Return

Interrupt_Enable:
  level = pinsC & MASK ^ MASK
  SetInt level, MASK
  Return
 

hippy

Technical Support
Staff member
Other question: is my interrupt routine as efficient as the one you suggested?
It's not as efficient but, as it's fast enough, it doesn't really matter.

You do notionally have a case where you could drop a pulse edge because you are setting the next interrupt condition depending on what pinC.3 is at the time you set it, where I look for the opposite of what it last was.

If you had a short pulse, got an interrupt when it went high, and the signal had returned low before you set the SETINT again, you would then interrupt on the next high, so would have missed the going low edge completely.

But, if it is a square wave, that doesn't really matter either.
 
Top