I'm trying to code a very simple LED flasher as a starter app, and I can't get the damn thing to work. (This is on PIC16F627 and simulated on MPLAB.) The timer1 rollover never fires. Code follows as attachment.
AFAIK (could be wrong, but I think not) the program memory addresses are counted in whole-instruction increments, not in bytes. So 0x05 is the instruction after. Still, I commented the "org 0x05" out, rebuilt and reran, unfortunately with no more success. The same result: the rollover bit in PIR1 gets set as the timer runs, but the ISR is never called.
Damn, who writes these chip manuals anyhow? They buried that info in a boolean-gate diagram on page 103. No thought to mention "actually, timer1 needs PEIE" in the section actually about timer1!
Another hint you'll find in Microchip's datasheets is that they often summarize the various SFR bits and registers required for a given function, in the section related to the function (in this case TMR1). You'd probably have to search to find the function of that bit if you hadn't run into it before, but at least you'd know to look. I have a datasheet here with that info in Table 7-2. The relevant stuff to TMR1 is spread over 6 bytes in 2 banks. Also, the midrange reference manual provides more detail organized differently (although it may not always match newer chips exactly, it can be helpful).
Best regards, Spehro Pefhany
--
"it's the network..." "The Journey is the reward"
speff@interlog.com Info for manufacturers: http://www.trexon.com
You probably know this already, but just in case, you are not saving and restoring context in the ISR. That means that most anything beyond your simple loop at Main: will fail because things will be corrupted by the ISR. Don't bother trying to figure out the save/restore stuff yourself, just look it up. It requires the use of the swapf (swap nibbles) instruction... and there are some banking issues (code and data) . Let's not even get into nested ISRs. You have to admire an architecture that requires an application note to explain how to do a table lookup.
Best regards, Spehro Pefhany
--
"it's the network..." "The Journey is the reward"
speff@interlog.com Info for manufacturers: http://www.trexon.com
There's a design approach I've been using to minimize that: "either spin and poll without using interrupts, or do everything inside the ISR". This was mainly practise code at interrupt handling.
Thanks, now I know what to look for, google makes finding it easy. Banking issues? I'm guessing, switch off GIE before changing banks away from 0, then run the ISR manually after switching back so as to avoid dropping interrupts. Is that right?
"brought to you by the folks who did INTERCAL and Malbolge"
The 16Cxxx PIC architecture requires the programmer to be aware of a lot of things that are not very obvious. There are some pretty clunky things about interrupts in particular.
First, the stack is used only for return address information.
You cannot push data onto it.
Second, the MOVFW instruction affects the ZERO flag.
This means that when an ISR needs to save the context it must:
Save the W register to a file register location that is allocated at the same offset in all banks.
Save the status register into the W register using the SWAPF nibble instruction. The SWAPF instruction must be used because it does not affect the flags in the status register.
Microchip has application notes and code examples on how to do this.
-------------
You should not need to switch off the GIE from within an ISR as the interrupt system is disabled until the RETFIE instruction is executed.
You need to know about this when doing nested interrupts. When using nested interrupts you really need to understand the PIC very thoroughly.
-------------
But the single most important thing about ISR code:
NEVER USE ALL OF THE AVAILABLE REAL TIME IN THE INTERRUPT SERVICE ROUTINES!
In fact using more than 20% of the processor bandwidth in the ISRs can make debug quite a challenge. Plus the interrupt response could be quite bad.
Which may actually be an advantage (for severely limited definitions of advantage) since the stack can be ignored and let to wrap around if you're coding in C and you want to use functions as if they were gotos, such as for coroutines.
Ah, that explains the swapf.
I was meaning: switch off the GIE when executing "regular" non-interrupt code that leaves bank 0 (to avoid being interrupted while in an unexpected bank).
Also, if code passes through a critical section with GIE off, am I right it's a good idea to run the ISR manually to catch any missed interrupts (and rely on the retfie at the end to re-enable GIE)?
When I said "do everything inside the ISR" I was meaning: sleep, wake on a timer interrupt, do what needs to be done, and sleep again. So the processor spends most of its time sleeping. Also, when doing this, only turn on the one timer interrupt; use the ISR to poll the others.
It is good practice, to protect critical code sections, but why not save the context inside the ISR? If you let the PIC sleeping, the additonal instructions should not be a problem!
Sorry, but it looks like you are missunderstanding the term ISR! An ISR is a pice of code, which is not called directly from the ohter code stuff. The entry to the ISR is placed to a special adress, and the processor itself run this code, if an event is detected. This event can be each enabled interrupt condition. If the processor jumps to the ISR, GIE will automaticly disabled, and inside the ISR you should never(!) re-enable interrupts (GIE). The RETFIE instruction is needed to leave the ISR and also re-enables interrupts. This is made to prevent nested runs of the ISR.
You can also manualy check the interrupt conditions in your main programm, without(!) implementing an ISR. Then do not enable any interrupt, and only check the xxxF bits in INTCON and PIR1.
If the PIC should sleep most time, and do some things from time to time, then you don't need implicitly a timer with interrupt. Often the the Watchdog is the better way, and with postscaler the PIC can sleep up to
2.3 sec. But please read the manual sections about all related things and conditions.
Nope, not misunderstanding, being sneaky by doubling up the use of the ISR code. Based on the assumption: "retfie" is exactly equivalent to "bsf INTCON, 7" followed by "return". Therefore it doesn't matter who calls the ISR so long as this behaviour is intended.
The code sequence I was thinking about:
normal code
GIE off
critical section (at this stage we need to check interrupts and switch on GIE)
jump to ISR via a normal "call"
ISR has been written to check interrupt bits
ISR conditionally does what needs doing
ISR finishes with "retfie"
retfie re-enables GIE and returns
Result: code saved and simplified by checking interrupts in one place.
The interrupt flags are sticky and are maintained regardless of the interrupt enables. (This also means it's usually disastrous to enable interrupts in the ISR.)
We have not told you one of the really sneaky bit of the interrupt handling on the PIC processors.
There are two global interrupt enable bits.
One bit is the GIE bit in the INTCON register, bit 7.
The other is buried inside the PIC with no direct access from the program.
This bit is "set" when the RETFIE is executed and "cleared" when any interrupt is processed.
For an interrupt to occur at least one interrupt source must be enabled, the GIE bit in INTCON must be set to one and the internal global interrupt enable must be "set". If the interrupt source is one of the peripheral device then the PEIE bit in INTCON must also be set to one.
-----
An a second note as to "what else was wrong" in your code.
There is a bug with the way you reload the TIMER ONE count register from the ISR.
The bug is that the "t1rollover" is used to update TIMER ONE only when "rollover_count" reaches zero.
This means the TIMER ONE will request an interrupt 10 milliseconds after the call to "SetClock" then count 65536 cycles 99 more times until "rollover_count" reaches zero. This results in a 6,498,064 cycles between changes of the LED. Or about 1.6 seconds using a 4MHz clock.
ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here.
All logos and trade names are the property of their respective owners.