AVR Optimization #2: ATmega328P Interrupts Using Register-Level Coding |
This page should be undertaken only after completing,
AVR Optimization #1: Introduction to Register-Level (Mid-Level) Coding of the ATmega328P
With bit-level coding of the ATmega328P's Digital IO registers (0x0020-0x005F) under your belt, it's time to excavate the next level of SRAM Addresses.
Libraries (Arduino and Third-Party). Libraries offer the novice coder the classic tradeoff between deep understanding and speed of project development. As your embedded skill set matures, greater understanding, clarity, confidence, and efficiency are typically found in the direct manipulation of the MCU's hardware using as close to its native instruction set as possible. To this end, in the exercises below we will do our best to avoid using many of the arduino and third-party libraries suggested by web tutorials in favour of direct register manipulation. On the other hand, establishing and maintaining your own personal library of tested resources is to your significant advantage as we will also introduce in the tasks below.
Review the ATmega328P's SRAM Register File one more time.
Here's a question for you. Based solely on the undefined (grayed out) addresses of the 328P's digital IO ports, what ports might you expect to find if you examined the ATmega2560's Register File?
Interrupts: The to Software Optimization
Our ACES program places a high premium on productivity. Since organization and efficiency drive productivity, it is necessary to dig deeper into the architecture of the AVR microcontroller to familiarize ourselves with its capabilities in support of our code strategies and structures.
It's pretty obvious that watching your phone constantly for incoming text messages is not a productive use of your time. Likewise, standing at your front door waiting for that Amazon delivery is also a colossal waste of time. Finally, you could probably bring in the green bins from the curb rather than watching and waiting for the kettle to boil up your next cup of tea. The good news is that most of these 'Events' come with associated 'Alerts'. Today's microntrollers are no different and the AVR family is no exception. For example, the analogRead() function initiates an analog-to-digital conversion process that takes time. To the human this takes virtually no time at all but, to the MCU, these are precious clock cycles that could be used to perform a parallel task while the conversion is waiting to complete. So, wouldn't it be terrific to simply launch an analog-to-digital conversion, then do something else and wait to be alerted (ie. interrupted) that the conversion is complete and ready for reading? This sounds highly productive. The AVR line of MCUs has a builtin architecture for alerting or interrupting your code when it finishes certain tasks. We need to exploit this.
The most efficient software for the embedded developer is typically none at all. This may sound flippant but if the hardware platform your developing on has native circuitry for a given task, there is (likely) no software routine that will perform more efficiently. Review the ATmega328P's Interrupt Vector Table (IVT) to the right.
This table suggests there are as many as 26 different sources of events on the ATmega328P that have the ability to complete the following sequence,
The order in which these Interrupts are listed carries with it additional meaning. Implied in this order is a sense of priority. By being #1, a hard (or soft) Reset has the highest prioritiy and takes precedence over any other task your MCU is performing, resets the Program Counter to 0, and code starts from the beginning again. We'll start our formal implementation of Interrupt coding with the Reset Interrupt.
You are familiar with the effect of pressing the Reset button on the UNO or Nano, however further optimization is accessible through a deeper understanding of the subtleties the various Reset sources of AVR MCUs. These sources can be detected and subsequently impact how your code chooses to restart.
Chapter 11 of the ATmega328P datasheet introduces the concept of System Control and, in particular, the Reset Function. The MCU offers four hardware Reset triggers that include: Power On, External, BrownOut, and Watchdog. At the end of this chapter, there is a description of the Registers that can be inspected and manipulated. For our purposes, we'll limit ourselves to a simple distinction between the Power On and External Reset triggers. Page 54 of the ATmega328P datasheet presents a detailed discussion of the MCUSR Register, (see: ATmega328P Register Summary) in which the source of a Reset can be identified through the use of flags (bits).
Task.
Interrupt #2 and #3. External Interrupt Requests 0 and 1 (INT0 and INT1)
From your previous year's experience you are aware that MCUs have digital pins that can be configured to respond to changing voltage levels presented by external behaviour. By way of example, the ATtiny84 has ONE such pin, the ATmega328P has TWO, and the ATmega2560 has SIX!
The two on the ATmega328P are referred to as INT0 and INT1 (digital pins 2 and 3 respectively). As can be seen from the IVT (below, left), each has a separate vector address and immediately follow the System Reset Interrupt in order of priority. An excerpt from Chapter 13 of the ATmega328P datasheet appears below right. Configured correctly, the ATmega328P can sense and respond to four voltage level behaviours presented on the INT0 and INT1 pins.
(Informative) Sparkfun Video Series: Level-Up Your Arduino Code: External Interrupts
ATmega328P Interrupt Vector Table | ATmega328P External Interrupt Registers |
---|---|
Task.
Interrupt #4, #5, and #6. Pin Change Interrupt Requests 0, 1, and 2
for 2022. 20/21 ICS4U ACES were the first class to be introduced to the ACES Rotary Encoder. A few short months later A. Goldman and S. Atkinson used their familiarity with the device to support their Clue Capturer prototype for their ECE190 course at Waterloo. Their achievement is the inspiration behind this project segment of your journey.
(Informative) Sparkfun Video Series: Level-Up Your Arduino Code: Rotary Encoders
Your Bourns PEC11L-4215F-S0015 Rotary Encoder offers three sources for useful interrupts. These are A, B, and SW. Given that the ATmega328P only provides two external interrupts, we look beyond INT0 and INT1.
In reading Chapter 13 of the ATmega328P datasheet you discover that interrupts can be triggered on ANY digital IO pin in the event that a logical level change has been detected in hardware. A little bit of software detective work is required to determine which pin was triggered as the 24 pins (PCINT0..PCTIN23) are organized into three separate banks defined by the respective Ports. Pins on PortB are mapped to PCINT0..7, pins on PortC are mapped to PCINT8..15, and pins on PortD are mapped to PCINT16..23.
A sample of the applicable Pin Change Interrupt registers of the ATmega328P appears below.
'Get Acquainted' Tasks: Rotary Encode Pin Change Interrupts
Interrupt #7. Watchdog Time-Out Interrupt (with and without a System Reset, as well as Power-down sleep mode)
The Watchdog Timer (WDT) is an MCU subsystem that can be configured to perform scheduled functionality. From the ATmega328P datasheet, 'The watchdog timer is clocked from an on-chip oscillator which runs at 128kHz. By controlling the watchdog timer prescaler, the watchdog reset interval can be adjusted as shown in Table 11-2 on page 55.". Review this Excel workbook to lock in the connection between crystal oscillation binary counting and frequency division:
BinaryCountingFrequencyDivision.xlsx
Note. Your MCU's onboard Timer/Counters (discussed in future lessons) can be used for the general task of periodic scheduling but are best reserved for their signal modulation and demodulation capabilities if possible rather than mere overflow interrupts.
From Table 11-1 to the right it can be seen that there are FIVE courses of action that that can be taken following the end of an elapsed WatchDog Timer interval. We'll start with a simple Interrupt.
The WDTON fuse determines whether the WDT subsystem is required as a fail-safe function (see AVR FUSE Calculator). The default setting has it off (WDTON=1). Should regularly-scheduled, unconditional System Resets be required, advanced applications may wish to set this fuse (WDTON=0) to enable this protection feature.
WDT Tasks.
In the exercises that follow we'll explore the three WDT Modes of operation,
Imagine a remotely-situated solar-powered, MCU-based sensor device (ie a roof, mountain top, at-sea, space, etc.) that collects (and possibly transmits) data to a central location. The third WDT mode that deserves to be mentioned is a System Reset only, without the benefit of a prior interrupt. Regularly-scheduled reboots could make the difference in avoiding costly repairs and more space junk. A simple modification to the previous code would result in a System Reset ONLY mode. So, for a final look at the WDT we turn our attention to the System Reset ONLY and an interesting context: overall MCU power consumption.
Imagine, again, a solar-powered MCU-based system. Understandably, optimum use of power would contribute to its viability and sustainability. This final segment provides some insights into how some aspects of such a prototype could be implemented to conserve power between readings. One 24-minute video I encourage you to watch is Kevin Darrah's Low Power Arduino! Deep Sleep Tutorial. This video presentation contains applicable and inspiring material for our final WDT investigation.