Hardware Interrupts on the ATMega168/328

On a project I am currently working on, I had the opportunity to learn a lot about some nuances between interrupts on the AVR ATMega168/328 chips. One interesting reference in the datasheet is the table listing the interrupt vectors, including their program address, their source, the interrupt definition. all the domains . They are listed by vector number which also defines their priority; that is to say, if more than one are supposed to execute, the one with higher priority will take precedence (interrupts will not interrupt each other unless you use ISR_NOBLOCK in the ISR definition).


Something I was interested in was putting my device to sleep and waking it up with a hardware interrupt. In other words, I had the choice between using INT0/1 or PCINT0/1. Before I go any further, let me explain one confusing thing: PCINT is a name of certain physical pins, but in this instance, we are talking about the interrupt vector! PCINT0 the interrupt vector is NOT tied to the pin PCINT0.


These two types of interrupts differ in several respects.

INT0/1 is uniquely tied to a physical pin, while PCINT0/1 is tied to a whole port (ie: six pins!). This means that when you activate the PCINT0/1 vectors (which is in one place in memory), any of the pins can fire the interrupt. When that happens, the microcontroller will check to see who actually fired the interrupt and compare that to the enabled pins (another place in memory). I don’t think that this would immediately cause problems in program flow, but it’s something to keep in mind. Imagine that you are using one of those non-interrupt pins on an interrupt-enabled port as output. Any edge, incoming or outgoing, will fire that interrupt and it will take a couple of commands to figure out that the edge it received is not a valid interrupt. Even though you won’t enter the full Interrupt Service Routine (ISR), those couple of commands happening a couple thousands times per second could ruin your communications!

Perhaps something more immediately relevant, however, is that if you have two enabled interrupt pins on a port that shares the vector, you’ll need to define within the ISR different behavior based on the different pins.¬†Similarly, in the definition of the ISR for INT0/1 you can easily say RISING, FALLING, or CHANGE to tell it whether or not to enter the routine; you need to find a way to program that within the routine for PCINT0/1 if you want different behavior based on those conditions.

Those are many of the issues with the PCINT0/1 interrupt vectors that make them more of a hassle, but there is something about them that is nice, other than the fact that they afford you additional hardware interrupts! The PCINT0/1 interrupts depend on the asynchronous clock while the INT0/1 interrupts depend on the I/O clock. Power save mode of the ATMega168/328 turns off the I/O clock which makes the INT0/1 based hardware interrupts not available for wake up! This was not immediately available in the documentation but I did find an AVR Freak link of errata and an error in the hardware interrupts section summary is corrected.

So that’s an overview of what I learned! If you want some specific examples, I found this site to be very helpful!

Comments are closed.