I'm developing a program that uses interrupts from Timer0, Timer1, and the PortB INT pin. Timer0 and Timer1 interrupts are sort of synchronous to each other, as the Timer 1 interrupt can only happen after the Timer 0 interrupt sets up the right conditions. The Timer0 and Timer1 interrupts co-exist peacefully and don't seem to interfere with each other. However, the INT interrupt is asynchronous to the other two interrupts, and can happen at any time.
Nothing happens in the very tight main loop until a flag variable indicates that Timer0 and Timer 1 have done their thing, at which point the main program code runs once and waits for the next TMR0/TMR1 interrupt indication. The only thing that interrupts the body of the main program is the INT interrupt.
The program works just fine when only Timer0 and Timer1 interrupts are running, but the asynchronous INT interrupt sometimes crashes the whole system. I'm not sure if the problem is the INT interrupt per-se (one line of code) , or something to do with the fact that this interrupt is asynchronous with everything else the system is doing and can happen at any time. I've carefully checked to make sure no other interrupts are enabled, so I'm pretty sure it's something related to the active interrupts.
I've spent the better part of a week trying all sorts of -process-of-elimination tests to resolve this, but it's still eluding me. My question: Are there any known issues with interrupts in GCBasic that I should be aware of, things like certain functions that shouldn't be interrupted (such as EEPROM), timing issues related to possible simultaneous interrupts, etc?
Thanks
Joe
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Have you tried disabling interrupts when in the PortB INT sub, by using INTOff and INTOn on entry/exit? Or vice-versa in the Timer0 and Timer1 int subs. I think some of the 18f's have a priority interrupt, which may be useful?, have not tried personally.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Well, you are right on the interrupt dsiable/enable.
I am sure its been thought of, but one could poll the input pin, rather that use an interrupt. This doesn't answer the question, but if you are in a jam.
Doing serial comms like RS232 , one wire, or I2C, it seems conceivable that you could hang the system in an unexpected state. That could be a reason to use the watchdog timer for a reset.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I finally updated to using the latest version. I believe there is still a problem with the interrupt handler, at least for the 12F that I am using. You can search the forums for an earlier post. The newest code is much improved! The sysw and sysstatus are now allocated in the upper shared bank memory as it must. Prior versions I had to manually edit this. But I believe there is still one problem left. The SysIntOffCount variable is not set correctly, if just prior to the interrupt a bank other than 0 was selected. I have not analyzed what happens if the variable is set incorrectly. There is a bank select in the interupt handler next, so everything after is ok.
Thanks for the insights on this. I also wondered if it was a problem with context-saving/restoration, or if a bank pointer is wrong somewhere, as the entry/exit code is a bit different than what Im used to. I'll give it a try.
How did you try your changes? Did you edit the .asm file that GCBasic makes and then re-run the assembler on it? Or did you somehow put some assembly code right in the GCBasic source code?
Joe
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I use a text search and replace program on the .asm file as part of the compile script. Then assemble and run in microchip's IDE.
I made a slight mistake above. If the clrf STATUS is inserted as shown, the SysSTATUS variable does not need to be in upper memory, only SysW. Also, as it is depending on where SysIntOffCount is allocated, it can overwrite some random Bank 1 setting. This can cause all kinds of trouble (thats very hard to discover).
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
>The SysIntOffCount variable is not set correctly, if just prior to the interrupt a bank other than 0
>was selected. I have not analyzed what happens if the variable is set incorrectly.
>There is a bank select in the interupt handler next, so everything after is ok.
For what i know, GcBasic only add banksels when needed; i'm not 100% sure, but perhaps you can't see banksels in interrupt routine because there are not variables in other banks than bank0.
To see if there is a real problem you should compile a program with some variables in bank1...
Regards.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I am using GCBasic for my interrupt routines, and except as stated above, they work quite fine. If you are familiar, it doesn't take long to look the code over after compile to see any obvious issues. Debug finds the others.
With the newest versions, GCBasic now handles advanced context saves (and now longer interrupt disables before any advanced math) so you can even use advanced math in your interrupt routines. Tedious to do that in assembly. Even though I have wrote lots of assembler in my days, that PIC instruction set it too much of a pain for me.
GCBasic does not store variables in bank 1 (that I have ever seen). But the problem lies if you are setting a parameter in bank 1 for some hardware on the chip, and the interrupt hits. This is the need for the clrf STATUS instruction.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
>GCBasic does not store variables in bank 1 (that I have ever seen).
If you have just a few variables then all will fit in Bank0, but when you have many then they will be placed in Bank1, 2...
>But the problem lies if you are setting a parameter in bank 1 for some hardware on the chip,
>and the interrupt hits. This is the need for the clrf STATUS instruction.
Ok... now i see.
What i did is editing the gcbaic.bas file and recompile it, now i have this interrupt context save:
What's in the interrupt, an array, a string, or a hard coded reference to FSR? GCBASIC won't save FSR if it's not changed in the interrupt, and it won't save PCLATH unless there's a pagesel.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
In my first try it didn't work because i used an "alias" to point a variable to FSR, i ussually do this to decrement the number of variables used in functions and to have a shorter code.
For example i was doing it in this function:
Function Peek (MemAdr As Word)
Dim MemAdr As Word Alias SysCalcTempA_H, FSR '...<<-----------HERE
Dim Peek As byte Alias SysCalcTempX
SET STATUS.IRP OFF
if SysCalcTempA_H.0 ON then SET STATUS.IRP ON
PEEK = INDF
End function
The memadress is parsed to FSR before the function is called.
This way i don't need to create 2 or 3 new variables in each function i use, and also save some instructions.
When i have a lot of variables and Bank1 1 is in use i also have a lot of banksels that bloats the code and slow speed (i think banksels take 2 instructions in some pics) then keeping everything in Bank0 is a good thing for some pics when speed is needed.
I used this function inside interrupts and FSR save didn't work because i used FSR "aliased", but using FSR directly works great.
I think now interrupts can work very well.
I like that System variables saving on interrupts only occur when needed... good Job!!
Regards... and thanks again .. :)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I'm developing a program that uses interrupts from Timer0, Timer1, and the PortB INT pin. Timer0 and Timer1 interrupts are sort of synchronous to each other, as the Timer 1 interrupt can only happen after the Timer 0 interrupt sets up the right conditions. The Timer0 and Timer1 interrupts co-exist peacefully and don't seem to interfere with each other. However, the INT interrupt is asynchronous to the other two interrupts, and can happen at any time.
Nothing happens in the very tight main loop until a flag variable indicates that Timer0 and Timer 1 have done their thing, at which point the main program code runs once and waits for the next TMR0/TMR1 interrupt indication. The only thing that interrupts the body of the main program is the INT interrupt.
The program works just fine when only Timer0 and Timer1 interrupts are running, but the asynchronous INT interrupt sometimes crashes the whole system. I'm not sure if the problem is the INT interrupt per-se (one line of code) , or something to do with the fact that this interrupt is asynchronous with everything else the system is doing and can happen at any time. I've carefully checked to make sure no other interrupts are enabled, so I'm pretty sure it's something related to the active interrupts.
I've spent the better part of a week trying all sorts of -process-of-elimination tests to resolve this, but it's still eluding me. My question: Are there any known issues with interrupts in GCBasic that I should be aware of, things like certain functions that shouldn't be interrupted (such as EEPROM), timing issues related to possible simultaneous interrupts, etc?
Thanks
Joe
Have you tried disabling interrupts when in the PortB INT sub, by using INTOff and INTOn on entry/exit? Or vice-versa in the Timer0 and Timer1 int subs. I think some of the 18f's have a priority interrupt, which may be useful?, have not tried personally.
According to Microchip:
"When an interrupt is responded to, the GIE bit is cleared to disable any further interrupt, ...."
and:
"The “return from interrupt” instruction, RETFIE, exits the interrupt routine, as well as sets the IE bit, which re-enables interrupts.
So I don't see the need to do any further interrupt disabling within the interrupt handler. Am I missing something?
Joe
According to Microchip:
"When an interrupt is responded to, the GIE bit is cleared to disable any further interrupt, ...."
and:
"The “return from interrupt” instruction, RETFIE, exits the interrupt routine, as well as sets the IE bit, which re-enables interrupts.
So I don't see the need to do any further interrupt disabling within the interrupt handler. Am I missing something?
Joe
Well, you are right on the interrupt dsiable/enable.
I am sure its been thought of, but one could poll the input pin, rather that use an interrupt. This doesn't answer the question, but if you are in a jam.
Doing serial comms like RS232 , one wire, or I2C, it seems conceivable that you could hang the system in an unexpected state. That could be a reason to use the watchdog timer for a reset.
I finally updated to using the latest version. I believe there is still a problem with the interrupt handler, at least for the 12F that I am using. You can search the forums for an earlier post. The newest code is much improved! The sysw and sysstatus are now allocated in the upper shared bank memory as it must. Prior versions I had to manually edit this. But I believe there is still one problem left. The SysIntOffCount variable is not set correctly, if just prior to the interrupt a bank other than 0 was selected. I have not analyzed what happens if the variable is set incorrectly. There is a bank select in the interupt handler next, so everything after is ok.
Interrupt
;Save Context
movwf SysW
swapf STATUS,W
movwf SysSTATUS
incf SysIntOffCount,F
banksel STATUS
The correct code should be:
'Interrupt handler:
;Save Context
movwf SysW
swapf STATUS,W
clrf STATUS
The clrf STATUS instruction is missing, as resets to bank 0. Try adding this and see if your problems are corrected.
Thanks for the insights on this. I also wondered if it was a problem with context-saving/restoration, or if a bank pointer is wrong somewhere, as the entry/exit code is a bit different than what Im used to. I'll give it a try.
How did you try your changes? Did you edit the .asm file that GCBasic makes and then re-run the assembler on it? Or did you somehow put some assembly code right in the GCBasic source code?
Joe
I use a text search and replace program on the .asm file as part of the compile script. Then assemble and run in microchip's IDE.
I made a slight mistake above. If the clrf STATUS is inserted as shown, the SysSTATUS variable does not need to be in upper memory, only SysW. Also, as it is depending on where SysIntOffCount is allocated, it can overwrite some random Bank 1 setting. This can cause all kinds of trouble (thats very hard to discover).
Thanks,
It sounds like it might be better all around if I handle interrupts in my own assembler-based code rather than let GCBasic handle them. Do you agree?
Hello..
>The SysIntOffCount variable is not set correctly, if just prior to the interrupt a bank other than 0
>was selected. I have not analyzed what happens if the variable is set incorrectly.
>There is a bank select in the interupt handler next, so everything after is ok.
For what i know, GcBasic only add banksels when needed; i'm not 100% sure, but perhaps you can't see banksels in interrupt routine because there are not variables in other banks than bank0.
To see if there is a real problem you should compile a program with some variables in bank1...
Regards.
I am using GCBasic for my interrupt routines, and except as stated above, they work quite fine. If you are familiar, it doesn't take long to look the code over after compile to see any obvious issues. Debug finds the others.
With the newest versions, GCBasic now handles advanced context saves (and now longer interrupt disables before any advanced math) so you can even use advanced math in your interrupt routines. Tedious to do that in assembly. Even though I have wrote lots of assembler in my days, that PIC instruction set it too much of a pain for me.
GCBasic does not store variables in bank 1 (that I have ever seen). But the problem lies if you are setting a parameter in bank 1 for some hardware on the chip, and the interrupt hits. This is the need for the clrf STATUS instruction.
>GCBasic does not store variables in bank 1 (that I have ever seen).
If you have just a few variables then all will fit in Bank0, but when you have many then they will be placed in Bank1, 2...
>But the problem lies if you are setting a parameter in bank 1 for some hardware on the chip,
>and the interrupt hits. This is the need for the clrf STATUS instruction.
Ok... now i see.
What i did is editing the gcbaic.bas file and recompile it, now i have this interrupt context save:
;Save Context
movwf SysW
swapf STATUS,W
clrf STATUS
movwf SysSTATUS
swapf PCLATH,W
clrf PCLATH
movwf AASysPCLATH
swapf FSR,W
movwf AASysFSR
incf AASysIntOffCount,F
What do you think?
The "AASys..." variable names is to be sure (not 100% but enought) that this variables will be placed into Bank0.
I edited gcbasic.bas (lines 891-... in my version) and added some lines, here is what i have now:
'Add context save code
CurrLine = SubStart
AddVar "SysW", "BYTE", 1, 0, "REAL", ""
AddVar "SysSTATUS", "BYTE", 1, 0, "REAL", ""
AddVar "AASysPCLATH", "BYTE", 1, 0, "REAL", "" ' ..............Variable added
AddVar "AASysFSR", "BYTE", 1, 0, "REAL", "" '..................Variable added
AddVar "AASysIntOffCount", "BYTE", 1, 0, "REAL", "" '...........Name changed to AASys...
If ChipFamily = 14 Then
'Will need to put SysW, SysSTATUS into shared bank
CurrLine = StringListInsert(CurrLine, ";Save Context")
CurrLine = StringListInsert(CurrLine, " movwf SysW")
CurrLine = StringListInsert(CurrLine, " swapf STATUS,W")
CurrLine = StringListInsert(CurrLine, " clrf STATUS") '........... Line added
CurrLine = StringListInsert(CurrLine, " movwf SysSTATUS")
CurrLine = StringListInsert(CurrLine, " swapf PCLATH,W") ' Line added
CurrLine = StringListInsert(CurrLine, " clrf PCLATH") ' Line added
CurrLine = StringListInsert(CurrLine, " movwf AASysPCLATH") ' Line added
CurrLine = StringListInsert(CurrLine, " swapf FSR,W") ' Line aded
CurrLine = StringListInsert(CurrLine, " movwf AASysFSR") ' Line added
CurrLine = StringListInsert(CurrLine, " incf AASysIntOffCount,F") ' Name changed
Of course the correspondient lines should be added to restore contex.
Have uploaded a new update, which should save FSR correctly.
Joe, I'd recommend writing interrupts in GCBASIC, I do. The number of interrupt related bugs is dropping, and it should be usable.
Hugh,
I downloaded and installed the 8/9 update, but the context save in the compiled code looks unchanged - no FSR or PCLATH save.
Joe
What's in the interrupt, an array, a string, or a hard coded reference to FSR? GCBASIC won't save FSR if it's not changed in the interrupt, and it won't save PCLATH unless there's a pagesel.
Ok.. i have tried it and works great!!
In my first try it didn't work because i used an "alias" to point a variable to FSR, i ussually do this to decrement the number of variables used in functions and to have a shorter code.
For example i was doing it in this function:
Function Peek (MemAdr As Word)
Dim MemAdr As Word Alias SysCalcTempA_H, FSR '...<<-----------HERE
Dim Peek As byte Alias SysCalcTempX
SET STATUS.IRP OFF
if SysCalcTempA_H.0 ON then SET STATUS.IRP ON
PEEK = INDF
End function
The memadress is parsed to FSR before the function is called.
This way i don't need to create 2 or 3 new variables in each function i use, and also save some instructions.
When i have a lot of variables and Bank1 1 is in use i also have a lot of banksels that bloats the code and slow speed (i think banksels take 2 instructions in some pics) then keeping everything in Bank0 is a good thing for some pics when speed is needed.
I used this function inside interrupts and FSR save didn't work because i used FSR "aliased", but using FSR directly works great.
I think now interrupts can work very well.
I like that System variables saving on interrupts only occur when needed... good Job!!
Regards... and thanks again .. :)