I'm porting some old code that uses a pin-change interrupt flag as an edge detector. The new target micro is an AVR (ATmega169). I'm having real trouble getting the INT0 logic to work like I think it should.
I set DDRD = 0xe5 (INT0 is on bit 1 of port D), PORTD = 0x20, and EICRA = EICRA | ISC00_MASK | ISC01_MASK to look for positive edges.
Not familiar with the ATMega169, but what about setting INT0 in EIMSK?
Quoting:
formatting link
"External Interrupt Mask Register - EIMSK
[...]
Bit 0 - INT0: External Interrupt Request 0 Enable
When the INT0 bit is set (one) and the I-bit in the Status Register (SREG) is set (one), the external pin interrupt is enabled. The Interrupt Sense Control0 bits 1/0 (ISC01 and ISC00) in the External Interrupt Control Register A (EICRA) define whether the external interrupt is activated on rising and/or falling edge of the INT0 pin or level sensed. [...]"
PCINT is on B and E, but INT0 is a dedicated, polarity-programmable interrupt on PD1.
Well, I solved my problem - it turns out very simply the pin on the IC wasn't soldered properly. My scope probe was on the trace, not the actual pin - when I probed the pin I saw it wasn't actually changing. A drop of solder fixed the problem.
However, do you have the port B PCINTs working in your application? I am now trying to get the same sort of functionality working on
Note that I don't want to actually fire the interrupt - I just need to poll the pin-change IRQ bit for one of the pins of port B.
I have used the port change interrupt to read an optical encoder. IIRC it had 3 bits of output, A, B, and index. PCINT was the best available option as all other resources were allocated.
A minor problem with PCINT is that there is not a register indicating which pin changed to fire the interrupt. By the time you get around to reading it it may be unchanged (due to bouncing). So it helps to keep a copy of the prior values laying around to XOR the current values against.
If (as in my case with the optical encoder) the value has to be stable for a bit to be valid, be prepared to exit the interrupt handler having done nothing.
Unless the shaft was turning fast my optical encoder bounced a lot when it was making changes. The solution was once phase A or B changed to disable that pin change interrupt and enable the other. When one was changing the other was stable.
I'm not permitted to use interrupts in this code. I am simply trying to use the IRQ bit as an edge detector - which isn't working at all : ( I'm pretty baffled and wondering if this feature actually works. No response from Atmel FAE yet.
Sorry to come in late on this one. But it should be possible to do what you want.
Let's say for example that you want to get a signal from a pin change on PB7. Then you need to do the following:
Set DDRB bit 7 Set PORTB bit 7 to enable the internal pull-up on PB7 Clear the PUD bit in MCUCR to enable internal pull-ups globally Set PCMSK1 bit 7 (PCINT15 bit) Set EIMSK bit 7 (PCIE1 bit) Clear SREG bit 7 (I bit)
Now any change on PINB7 should set bit 7 in EIFR (PCIF1). Note that in order to clear this bit, you must write a 1 to it when it is set,
Is it necessary to set PCIE1 if you do not actually want the IRQ to fire? I want/need to poll this bit in mainline code, I can't let an ISR grab it. (Having said this, the IRQ wouldn't fire when I tried it the normal way, with PCIE1 set, anyway).
Oops, sorry I originally wrote "Set DDRB bit 7 to 0" and then edited it incorrectly.
Yes, as Linnix says the PCIE1 bit enables the pin change block for PC15 through to PC8 to function. That will allow the PCIE1 flag to be set. Clearing the I bit in SREG stops that flag propagating through to the interrupt mechanism.
This isn't how I understood it - as I understood it, yes you have to set PCMSKxxx to enable the specific pin, but then the PCINT8..15 interrupt, PCIE1, is ANDED with PCIF1 and it's the result of this that is then gated with the global interrupt flag to determine if the core gets an interrupt. However, the point is moot - even when I set PCIE1 and disable global interrupts, the request flag is STILL not being set.
Atmel claims that my exact same code works on their hardware, so I'm baffled. I can physically see the pin changing state (and I've even verified that the micro is seeing that change of state). Beyond mysterious.
Well that certainly does sound strange. I've used the pin-change flag on a mega2561 in exactly the same way as you are trying to. It's possible that the mega169 uses a different block but I would think that's unlikely as they would have to rewrite and test the Verilog.
Maybe Ulf will come along soon and give us a definitive answer.
Of course the problem turns out to be my fault (well, someone else in my team originally, but my fault for not spotting it). Our circuit can use the 169/329/649 but initial bring-up was done on the 169. Someone forgot or ignored my advice to include avr.h and instead included mega169.h
MOST of the registers are the same between 169 and 32/649 but not all of them. The PCINT bit assignments in particular are different!
Also, it is not necessary to set the interrupt mask for PCIE1 in order to see PCIF1 toggling.
I can't blame Atmel for this - we were using the wrong header file. We should have included avr.h and let the compiler pick the correct chip- specific header based on the project settings.
I agree this would be an issue if we needed binary compatibility, but in practice we don't (the administrative requirements of changing micros are massive and the cost of SWQA for a recompile-to-new-chip operation is negligible).
I agree. We can blame Atmel for many other faults, but not for product migrations. If we force them to be binary compatible, then we end up with a static uC architecture.
We are moving off the 169 purely for cost reason. Our new uC (6502) is 75% off, but it's difficult to port the hardware/software. The 169 fits so well in the original project, if only they have lower cost solution.
By the way, our new uC will be die-bounded Chip-On-Board One-Time- Programmable. Atmel is certainly capable of providing COG and OTP, but unwilling to do so.
Energy metering project? (That's what the mega169/329/649 were designed for). Are you using one of the 6502 variants e.g. from Sunplus, intended for toy use? Just out of interest, what's your cost target? We moved to the mega169 because it's significantly under $1.
I can't see that an OTP version of the mega169 would really be cheaper
- since it's not a standard part, there would be big NREs.
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.