What am I doing wrong?

nextPart2912043.rat7JAi7FX Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8Bit

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.

Can someone tell me what I'm doing wrong?

Reply to
Julian Morrison
Loading thread data ...

I don't know that CPU, but I saw this:

; interrupt vector org 0x04 goto ISR ... ; Subroutines org 0x05 Init clrf porta

Reply to
Steve at fivetrees

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.

Reply to
Julian Morrison

You need to set PEIE, as well as GIE for the TMR1 interrupts to work.

Best regards, Spehro Pefhany

--
"it's the network..."                          "The Journey is the reward"
speff@interlog.com             Info for manufacturers: http://www.trexon.com
 Click to see the full signature
Reply to
Spehro Pefhany

Thanks! It works now.

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!

At least it wasn't any worse mistake.

Again, thanks :-)

Reply to
Julian Morrison

No problem.

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
 Click to see the full signature
Reply to
Spehro Pefhany

P.S.

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
 Click to see the full signature
Reply to
Spehro Pefhany

D'oh! As you can see I'm still new to this.

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"

Reply to
Julian Morrison

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.

Reply to
Keyser Soze

To Keyser and Julian.

In fact, it's even described in the manual, how to save the context during interrupt (chapter 14.7 in the PIC16F62x manual).

Nested interrupts on PIC are a very bad sugestion on a newbe.

This applies not only to PICs, but for most other micros.

At least: It is always a more helpful, to read also about related things (here the basics about interrupt on PIC) in the manual.

HTH Michael

Reply to
Michael Lange

You are posting to usenet with a completely ambiguous subject line.

Reply to
Scott Moore

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.

Reply to
Julian Morrison

Julian Morrison schrieb:

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.

HTH Michael

Reply to
Michael Lange

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:

  1. normal code
  2. GIE off
  3. critical section (at this stage we need to check interrupts and switch on GIE)
  4. jump to ISR via a normal "call"
  5. ISR has been written to check interrupt bits
  6. ISR conditionally does what needs doing
  7. ISR finishes with "retfie"
  8. retfie re-enables GIE and returns

Result: code saved and simplified by checking interrupts in one place.

Reply to
Julian Morrison

Why not just re-enable GIE - the interrupt will just happen if one is pending.

Reply to
Mike Harrison

It will? What counts as "pending"? Will the interrupt fire if it happened at any time while GIE was off? Or, only if the cause is ongoing?

Reply to
Julian Morrison

Yes, so you don't have to do anything.

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.)

Reply to
toby

Julian Morrison schrieb:

Not exactly, RETFIE prevent to re-enter the ISR before the return is executed! And that is a big difference.

Arrrghh!

My result: It's not sneaky, you are fully missunderstand the whole concept of intrerrupts!

This is my last hint: Before you think about such crazy stuff, study the basics and made some spimle things working.

Michael

Reply to
Michael Lange

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.

But then you have already found this one. :)

Reply to
Keyser Soze

this should be ---> 6.5 seconds

Reply to
Keyser Soze

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.