Don't understand problem with setint

johndk

Senior Member
I've been trying to set up a simple interrupt to toggle my display on and off. I'm running a 28x2 and set up the following code to initialize the interrupt. The interrupt should be generated by a button push which will drive the appropriate pins (B.0 and B.1) to logic 1. Although A.3 is in the code, it is not used at the moment.

I must be missing something really obvious because the program totally ignores any button push. I have the pins connected to a 10k pulldown and have checked that the buttons generate the positive rail condition (in this case 3.26v).


Day_Mode:

setint OR %00000011,%00000011,B
do .......


My interrupt sub is as follows


interrupt:

pause 100 ;debounce

;b_next = pinB.0, b_display = pinA.3, b_menu = pinB.1
if b_next = 1 or b_display = 1 or b_menu = 1 then interrupt

sertxd("int",cr)
hi2csetup I2Cmaster, OLED_ADDR, i2cfast_8, i2cbyte

ptr = sp_display_state
if @ptr = 1 then
@ptr = 0
hi2cout (Disp_cmd, DISPLAYOFF)
else
@ptr = 1
hi2cout (Disp_cmd, DISPLAYON)
endif
ptr = sp_base_mode
read ee_base_status, @ptr

setint OR %00000011,%00000011,B
if @ptr > 0 then
goto day_mode
else
goto night_mode
endif
return

Pointing out my lack of mental capacity would be much appreciated. Derogatory statements may be added for bonus points.
 

eggdweather

Senior Member
When the interrupt occurs one of these conditions will be true:
if b_next = 1 or b_display = 1 or b_menu = 1 then interrupt
And so it will direct programme control back to the interrupt and never proceed to do what you want. I think you need to test for any 0 conditions or just delete that line.
 

johndk

Senior Member
Thanks Eggdweather.

All of those pins are connected to buttons (b_next , b_display , b_menu ) all of which are in the 0 state until one is pushed. So the condition should be okay, just waiting for the interrupt to be cleared (button unpushed). And, in fact, I had originally programmed without that line and got exactly the same ... nothing.
 

hippy

Technical Support
Staff member
The problem could be in the exit from the interrupt routine ...

Code:
if @ptr > 0 then
  goto day_mode
else
  goto night_mode
endif
return
The RETURN will never be reached, one of the two GOTO commands will have been executed. The interrupt needs to be terminated by a RETURN or only the first ever interrupt will be responded to.

Start with simpler code which just reports if an interrupt occurs and get it working reliably before having it do something more complicated -

Code:
#Picaxe 28X2
#Terminal 9600

Gosub Interrupt_Enable
Do
  SerTxd( "-" )
  Pause 1000
Loop

Interrupt:
  Do 
    SerTxd( "+" )
    Pause 100
  Loop Until pinB.1 = 0 And pinB.0 = 0

  SerTxd( "INTERRUPT" )

Interrupt_Enable:
  SetInt OR %00000011,%00000011,B
  Return
 
Last edited:

westaust55

Moderator
Are you saying that the line:
SERTXD ("Int",CR)
Is not being performed -that is nothing appearing on screen?

A few comments - unlikely to solve problem but for better code:
1. Contact bounce (from my machine code/assembler programming days) is over with in under 5 ms so a PAUSE 5 at default clock speed should suffice.

2. You test to check if any of the three pins loops back to the Interrupt: label so you keep performing the PAUSE 100
Add a label such as Wait4Release: after the PAUSE and just go back to that.

3. Better to set a flag (see a bit variable or two or put a value in a byte variable) within the Interrupt routine to indicate what has happened then Return and let the main loop us the flag and decide what to do next (and clear the flags).

4. As hippy has already mentioned - DON'T break out of an Interrupt routine with a GOTO.
If the Return is not performed you do not branch back to the main program and after a few interrupts there will be an error in programme execution due to stack return vector overflow.
 

johndk

Senior Member
Thanks for the ideas.

I will try tinkering with them. But the first question by westaust55 is relevant. I never see the 'int' . That told me that it is not being triggered. So the fact that I may not be returning from the interrupt properly is a secondary question.

And thanks for the 5ms recommendation. I really had no idea how much bounce to expect. I initially put in 10 ms, but wasn't sure that was enough. I'll go back to that if I can get the interrupt to trigger.
 

inglewoodpete

Senior Member
Hi John, Did you try hippy's code? Did it work? That will prove that interrupts are occurring.

As an aside, I would add
Code:
[color=Blue]SerTxd ([/color][color=Red]"+"[/color][color=Blue])[/color]
into the loop within hippy's Interrupt routine.
 

westaust55

Moderator
Hi John, Did you try hippy's code? Did it work? That will prove that interrupts are occurring.
As an aside, I would add
Code:
[color=Blue]SerTxd ([/color][color=Red]"+"[/color][color=Blue])[/color]
into the loop within hippy's Interrupt routine.

hippy
already has the line:
SerTxd( "INTERRUPT" )
in the Interrupt: subroutine

@johndk,

I tried you code as follows in the PE5 simulator and it is working (with a few lines commented out):
Code:
Day_Mode:

setint OR %00000011,%00000011,B
do 

  Sertxd ("+")
  PAUSE 100
LOOP

Night_Mode:
do

Loop

;My interrupt sub is as follows

interrupt:

pause 100 ;debounce

;b_next = pinB.0, b_display = pinA.3, b_menu = pinB.1
SYMBOL b_next = pinB.0
SYMBOL b_menu = pinB.1
SYMBOL b_display = pinA.3


if b_next = 1 or b_display = 1 or b_menu = 1 then interrupt

sertxd("int",cr)
;hi2csetup I2Cmaster, OLED_ADDR, i2cfast_8, i2cbyte

;ptr = sp_display_state
if @ptr = 1 then
@ptr = 0
;hi2cout (Disp_cmd, DISPLAYOFF)
else
@ptr = 1
;hi2cout (Disp_cmd, DISPLAYON)
endif
;ptr = sp_base_mode
;read ee_base_status, @ptr

setint OR %00000011,%00000011,B
if @ptr > 0 then
goto day_mode
else
goto night_mode
endif
return
If the hardware is correct then the initial SETINT command may not be getting actioned.

Suggest that you post your complete code for review.
 

hippy

Technical Support
Staff member
the first question by westaust55 is relevant. I never see the 'int' . That told me that it is not being triggered.
Though it could be that it is triggering immediately, then never getting out of the debounce loop to show the "int", or perhaps the "int" is being output before the Terminal is ready to display it.
 

inglewoodpete

Senior Member
Though it could be that it is triggering immediately, then never getting out of the debounce loop to show the "int", or perhaps the "int" is being output before the Terminal is ready to display it.
That's why I suggested the sertxd for "+" within the debounce loop in post #7. (I think this was misunderstood by WA55 in post #8)
 

johndk

Senior Member
Problem solved. I knew it was going to be something obvious that I should have spotted.

My slot switching bit me again! In coming back from a function in another slot, the interrupt was no longer active. Resetting the interrupt on the slot return did the trick.

Those slots are very handy for large code. But because they wipe system state, they're also annoying. Is there any way to cache system state and restore on return?
 

hippy

Technical Support
Staff member
Those slots are very handy for large code. But because they wipe system state, they're also annoying. Is there any way to cache system state and restore on return?
There is no way to do that automatically except by keeping details of your system state in variables or scratchpad which will not be cleared when switching between slots.
 

johndk

Senior Member
Okay, I get that. But are all of the system state variables accessible? If so, it would be trivial to write a routine that would cache and restore.
 

inglewoodpete

Senior Member
There is no way to do that automatically except by keeping details of your system state in variables or scratchpad which will not be cleared when switching between slots.
Okay, I get that. But are all of the system state variables accessible? If so, it would be trivial to write a routine that would cache and restore.
As hippy says, your system state variables. That means anything that could be lost or reset when you do a slot swap. So that would be interrupt flags and mask and possibly others. Read up on the RUN command to determine its impact on your program.

From my experience, interrupts can work seamlessly across multiple program slots. However, you need to (re)initialise interrupts as execution commences in each slot.
 
Last edited:

johndk

Senior Member
Yes, Pete, I discovered that refreshing the interrupt on return from another slot does the trick very nicely. What I'm actually after is the various system variables that get wiped, not the program byte variables. For instance, system variables such as 'timer'. I was hoping I could cache them in one quick routine and restore on return without having to pick them out one by one.
 

Technical

Technical Support
Staff member
A slot change is best considered as a total reset (excluding the bX / wX variable blanking that occurs on a power up reset). Therefore anything that is not a bX or wX variable does need reconfiguring after a slot change.
 

hippy

Technical Support
Staff member
But are all of the system state variables accessible? If so, it would be trivial to write a routine that would cache and restore.
No, not all system variables are accessible, but you can use variables to shadow what the system state should be, so things can be set to the same state.

For example you can have a variable which indicates whether interrupts are enabled or not, even on which pins. Then, after a slot change, the running slot can check that variable, and set interrupts to how they should be using SETINT.

Code:
; This File : IRQ-Slot0.bas

#Picaxe 28X2
#Slot 0

#Include "IRQ-include.inc"

MainSlot0:
  If pinC.1 = 1 Then
    Gosub InterruptEnable
  End If
  If pinC.2 = 1 Then
    Gosub InterruptDisable
  End If
  Run 1
Code:
; This File : IRQ-Slot1.bas

#Picaxe 28X2
#Slot 1

#Include "IRQ-include.inc"

MainSlot1:
  If pinC.1 = 1 Then
    Gosub InterruptEnable
  End If
  If pinC.2 = 1 Then
    Gosub InterruptDisable
  End If
  Run 0
Code:
; This File : IRQ-Include.inc

InterruptInclude:

  Symbol interruptEnabledFlag = b27

  If interruptEnabledFlag <> 0 Then
    Gosub InterruptEnable
  End If
  Goto InterruptIncludeEnd

Interrupt:
  
  ; [i]Interrupt handler code here[/i]

InterruptEnable:
  interruptEnabledFlag = 1
  SetInt %00000011, %00000011, B
  Return

InterruptDisable:
  interruptEnabledFlag = 0
  SetInt OFF
  Return

InterruptIncludeEnd:
 

johndk

Senior Member
My code already looks something like hippy's post. I guess what I'm really looking for is a reference to what system variables are accessible and where to find them. There are scattered references throughout the basic manual. Is there any document which collects all of the system variables, their functions and their accessibility in one handy reference? With something like that in hand, I think I can work out what I'm trying to accomplish.
 

hippy

Technical Support
Staff member
I guess what I'm really looking for is a reference to what system variables are accessible and where to find them. There are scattered references throughout the basic manual.
I think it depends on what you mean by 'system variables'.

For a lot of things, such as whether interrupts are enabled or not, which pins and polarity are being used, whether in an interrupt handling routine or outside it, that state is only available as internal firmware variables which are not accessible to user programs. The same too for HSERSETUP, HI2CSETUP, PWMOUT and SERVO current settings etc.

The only way to get back to a same state for most things is to remember which state one were in and repeat the commands necessary to produce the same state. There's no easy 'save this and restore it later' to set the state as it previously was.

The system variables which are accessible are the 's_w0' through 's_w7' word variables ( which 'time' 'task', 'hserptr' etc are aliased to ) and the 'flags' byte variable which are used to control and/or report various states. Those are described in PICAXE Manual 2 "Basic Commands" in the "Variables - System" and "Variables - Special Function" sections.
 
Top