View previous topic :: View next topic |
Author |
Message |
TSEYFARTH
Joined: 01 Jul 2006 Posts: 1054
|
Posted: Thu Oct 22, 2015 6:44 am Post subject: Exiting from an Isr Handler? |
|
|
Hello all.
I have a potentially large amount of code to handle an interrupt from a radio part. What I found is that if I try to exit the label after handling the specific item that generated the ISR, I get errors. If I use a Sub to handle the ISR, I also get errors. What is the best way to do this?
Thanks in advance!
Tim
Code: |
rfm24_Nirq_int:
#If Print_Nirq_int
print #2, "IN - rfm24_Nirq_int"
#EndIf
RFM_Int_Area = 1
restore RFM24_GET_INT_STATUS
Api_SendCommand
Read_Cmd_Buf RFM24_Interrupt_Status(1),9 '8 '5 '01/02/15b
If RFM24_Interrupt_Status(4).7 <> 1 And RFM24_Interrupt_Status(5).7 <> 1 Then
restore RFM24_CLEAR_INTERRPTS
Api_SendCommand
End If
' NAME 7 6 5 4 3 2 1 0
'0x00 1 CTS CTS
'0x01 2 INT_PEND X X X X X CHIP_INT_PEND MODEM_INT_PEND PH_INT_PEND
'0x02 3 INT_STATUS X X X X X CHIP_INT_STATUS MODEM_INT_STATUS PH_INT_STATUS
'0x03 4 PH_PEND FILTER_MATCH_PEND FILTER_MISS_PEND PACKET_SENT_PEND PACKET_RX_PEND CRC_ERROR_PEND X TX_FIFO_ALMOST_EMPTY_PEND RX_FIFO_ALMOST_FULL_PEND
'0x04 5 PH_STATUS FILTER_MATCH FILTER_MISS PACKET_SENT PACKET_RX CRC_ERROR X TX_FIFO_ALMOST_EMPTY RX_FIFO_ALMOST_FULL
'0x05 6 MODEM_PEND X POSTAMBLE_DETECT_PEND INVALID_SYNC_PEND RSSI_JUMP_PEND RSSI_PEND INVALID_PREAMBLE_PEND PREAMBLE_DETECT_PEND SYNC_DETECT_PEND
'0x06 7 MODEM_STATUS X POSTAMBLE_DETECT INVALID_SYNC RSSI_JUMP RSSI INVALID_PREAMBLE PREAMBLE_DETECT SYNC_DETECT
'0x07 8 CHIP_PEND X CAL_PEND FIFO_UNDERFLOW_OVERFLOW_ERROR_PEND STATE_CHANGE_PEND CMD_ERROR_PEND CHIP_READY_PEND LOW_BATT_PEND WUT_PEND
'0x08 9 CHIP_STATUS X CAL FIFO_UNDERFLOW_OVERFLOW_ERROR STATE_CHANGE CMD_ERROR CHIP_READY LOW_BATT WUT
'Group Number Name Default Summary Feature Available
'0x01 0x00 INT_CTL_ENABLE 0x04 This property provides for global enabling of the three interrupt groups (Chip, Modem and Packet Handler) in order to generate HW interrupts at the NIRQ pin. revB1B
'0x01 0x01 INT_CTL_PH_ENABLE 0x00 Enable individual interrupt sources within the Packet Handler Interrupt Group to generate a HW interrupt on the NIRQ output pin. revB1B
'0x01 0x02 INT_CTL_MODEM_ENABLE 0x00 Enable individual interrupt sources within the Modem Interrupt Group to generate a HW interrupt on the NIRQ output pin. revB1B
'0x01 0x03 INT_CTL_CHIP_ENABLE 0x04 Enable individual interrupt sources within the Chip Interrupt Group to generate a HW interrupt on the NIRQ output pin. revB1B
If RFM24_Interrupt_Status(4).0=1 Then 'FIFO ALMOST FULL
RFM24_bit_FIFO_AlmostFull = 1
RFM_Int_Area = 2
#If Print_Nirq_int
Print #2, "FIFO ALMOST FULL"
#EndIf
ElseIf RFM24_Interrupt_Status(4).1=1 Then 'FIFO ALMOST EMPTY
RFM24_bit_FIFO_AlmostEmpty = 1
RFM_Int_Area = 3
#If Print_Nirq_int
Print #2, "FIFO ALMOST EMPTY"
#EndIf
ElseIf RFM24_Interrupt_Status(5).4=1 Then 'For Rx int.
' PACKET_INFO
' Number: 0x16
' the PACKET_INFO command should be sent after reception of a valid packet and prior to re-entering RX mode, else the response value will always be zero.
RFM_Int_Area = 4
InTxd_State = 0
InRxd_State = 0
RFM24_RxLED = 0 'Turn ON
RFM_RX_LED_On_Count = 0
Si4460_Int_Waiting = 1
'#If Print_Nirq_int
Print #2, "1- Received RXD Int"
'#EndIf
ElseIf RFM24_Interrupt_Status(5).5=1 Then 'For Tx int.
Tx_Dta_Ready_4_Upload = 0 'reset ready to upload
RFM24_bit_Tx_Pending = 0
InTxd_State = 0
InRxd_State = 0
Tx_DTA_Sent = 1
InRxd_State = 1
RFM_Int_Area = 5
#If Print_Nirq_int
Print #2, "Txd complete"
' Call Get_FRR_B_READ
' Print "PH_Status= ";PH_Status
' Print "PH_Status1= ";PH_Status_Ary(1)
' Print "PH_Status2= ";PH_Status_Ary(2)
#EndIf
ElseIf RFM24_Interrupt_Status(5).3=1 Then 'CRC Error, downloand and dump the data
'Copy the Interrupt status to the Error Int Status
RFM_Int_Area = 6
bts = MEMCOPY(RFM24_Interrupt_Status(1), RFM24_ErrorInterrupt_Status(1), 9)
RFM24_bit_Tx_Pending = 0
RFM_Error = 1
'//-------- PER ERRATA CHANGE STATE TO SLEEP --------//
restore RFM24_STANDBY '09/07/15a
Api_SendCommand
restore RFM24_RESET_RX_FIFO 'ADDED 060715A Need to clear the FIFO following a CRC error 060715a
Api_SendCommand
restore RFM24_START_RX '09/07/15a
Api_SendCommand
#If Print_Nirq_int
Print #2, "CRC ERR"
#EndIf
ElseIf RFM24_Interrupt_Status(9).3 = 1 Then 'CMD Error - SELF HEALING
RFM_Int_Area = 7
RFM24_bit_Tx_Pending = 0
InTxd_State = 0
InRxd_State = 0
#If Print_Nirq_int
Print #2, "Cmd Error"
' Read_Cmd_Buf RFM24_Interrupt_Status(1),5
' Print "***COMMAND ERROR CAUSE ****"
' Print "Txd_Rxd_State_counter " ; Txd_Rxd_State_counter
' Print "RFM24_Interrupt_Status 1 Decimal " ; RFM24_Interrupt_Status(1)
' Print "RFM24_Interrupt_Status 2 Decimal " ; RFM24_Interrupt_Status(2)
' Print "RFM24_Interrupt_Status 3 Decimal " ; RFM24_Interrupt_Status(3)
' Print "RFM24_Interrupt_Status 4 Decimal " ; RFM24_Interrupt_Status(4)
' Print "RFM24_Interrupt_Status 5 Decimal " ; RFM24_Interrupt_Status(5)
' Print "**** END Cmd Error ****"
' Print ""
#EndIf
ElseIf RFM24_Interrupt_Status(9).5 = 1 Then '"FIFO Under_Over flow" ADDED 06071c
RFM_Int_Area = 8
Print #2, "RFM_Int_Area = "; RFM_Int_Area
#If Print_Nirq_int
Print #2, "FIFO Under_Over flow"
#EndIf
If InRxd_State = 1 Then 'If in RXD MODE 'ADDED 060715A
restore RFM24_RESET_RX_FIFO 'ADDED 060715A
Api_SendCommand
'#If Print_Nirq_int
'Print #2, "FIFO Over flow"
Print #2, "RFM_Int_Area = "; RFM_Int_Area
'#EndIf
InRxd_State = 0
End If
If InTxd_State = 1 Then 'If in TXD MODE 'ADDED 10/18/15a
RFM_Int_Area = 10
restore RFM24_RESET_TX_FIFO 'ADDED 060715A
Api_SendCommand
RFM24_bit_Tx_Pending = 0 'added 10/18/15a
'#If Print_Nirq_int
'Print #2, "FIFO Under flow"
Print #2, "RFM_Int_Area = "; RFM_Int_Area
'#EndIf
InTxd_State = 0
End If
Else '//---- Do the prep work to report the error ----//
RFM_Int_Area = 9
RFM24_bit_Tx_Pending = 0
Print #2, "RFM_Int_Area = "; RFM_Int_Area
'Sleep 1
'SPI_Active 2
'Ready 3
'Ready2 4
'TX_Tune 5
'RX_Tune 6
'TX 7
'RX 8
End If
Return
|
(BASCOM-AVR version : 2.0.7.9 , Latest : 2.0.7.8 ) |
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Thu Oct 22, 2015 8:51 am Post subject: Re: Exiting from an Isr Handler? |
|
|
TSEYFARTH wrote: | What I found is that if I try to exit the label after handling the specific item that generated the ISR, I get errors. |
Errors from your code I assume, not from Bascom?
What label?
I only see one, rfm24_Nirq_int, which seems to be the ISR.
In an ISR, only one Return is allowed: the last. Every other return a) doesn't restore previously saved (PUSH'd) registers, which results in random behaviour, and b) a RET instead of RETI is created, which means interrupts don't get re-enabled, thus stay disabled.
On the other hand the IF/ELSEIF/ELSE/ENDIF block already does, what you want.
If one ELSEIF is executed, the following ones are omitted and the code internally jumps to the end of the ISR.
Quote: | If I use a Sub to handle the ISR, I also get errors. What is the best way to do this? |
If you pack everything from the ISR into a sub, it should not make a difference, however I do not see a reason or gain for that.
Critical in an ISR is to call subs/functions, or modify variables, which can be used or modified from main code at the same time, as the results may get unpredictable.
Take for example the sub Api_SendCommand, if this code is executed by non-ISR code while the ISR kicks in, the different order of commands sent to the device can irritate it.
This can be avoided by making critical sections atomic, means the critical block needs to be encapsulated by Disable/Enable Interrupts.
And one more thing, as I do not know where Api_SendCommand comes from: if this is Basic code and no floats are used therein, normal saving and restoring of registers within the ISR works fine. However, if it is ASM-code, or contains floats, which use registers R12-R15, while also main code uses it, then you should declare:
Code: | ON your_interrupt rfm24_Nirq_int SAVEALL |
Already using Restore within the ISR and main code will make that necessary, as R8/R9 is normally not saved, but is the data pointer for the Read-command. |
|
Back to top |
|
|
TSEYFARTH
Joined: 01 Jul 2006 Posts: 1054
|
Posted: Thu Oct 22, 2015 11:34 pm Post subject: |
|
|
Hi MWS,
I believe you answered it here:
Quote: |
In an ISR, only one Return is allowed: the last. Every other return a) doesn't restore previously saved (PUSH'd) registers, which results in random behaviour, and b) a RET instead of RETI is created, which means interrupts don't get re-enabled, thus stay disabled.
On the other hand the IF/ELSEIF/ELSE/ENDIF block already does, what you want.
If one ELSEIF is executed, the following ones are omitted and the code internally jumps to the end of the ISR.
|
I was thinking that using multiple Returns or Exit Sub (for a sub) would speed it up, but it won't, and your explanation makes perfect sense!
Also the calls are to BASCOM code, and do not use any floats.
Thanks MWS,
Tim |
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Fri Oct 23, 2015 2:37 am Post subject: |
|
|
TSEYFARTH wrote: | Also the calls are to BASCOM code, and do not use any floats. |
OK, but then still take care about the Restores in your ISR.
Processor registers R8 and R9 hold the data pointer, which is modified by Restore, but not saved by default in the ISR.
That means, if you do a Restore, followed by a Read in the main loop, and the ISR kicks in immediately after the Restore, then the Restores in the ISR will alter the data pointer, resulting in a flawed Read after return from the ISR. |
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You cannot download files in this forum
|
|