Introduction
Microcontrollers (MCUs) contain a wide range of hardware modules (peripherals) designed to perform specialized tasks like communication, timing and waveform generation. Typically, each peripheral has a number of signals indicating its status, an operation is completed, data availability or the peripherals are ready to receive new commands. It is up to the central processing unit (CPU) to check each module for relevant updates. The CPU then has to service the requests from each module. With an increasing number of peripheral modules, the CPU spends increasingly more time to check and service all modules. This CPU load causes longer response time and higher power consumption. Traditionally, MCUs use two main methods to monitor and service peripherals: polling and interrupts.
Polling means manually reading and checking a status bit updated by a monitored peripheral. This gives the designer a high degree of freedom to decide how often and in which order to check the different peripherals. In a simple use case where the application only waits for a specific status, a very tight loop can be made; checking this status bit and immediately servicing it when it occurs. Even though this approach would allow a very fast response time, there are few major drawbacks using the polling method. First, the responsiveness decreases as the number of status bits to check increases. Second, the CPU needs to run in active mode while it is executing the code testing every status bit, which increases power consumption.
As the number of peripherals and status bits involved in an application increases, an interrupt system provides better responsiveness. An interrupt system is a scheme in which the peripherals can send a request to interrupt the CPU execution. Since the peripherals prompt the CPU when service is needed, there is no need for the CPU to actively poll the status bits. However, when a peripheral can request service from the CPU at any time, with no regard to other peripherals' needs, this creates the risk of an interrupt request pile-up. Therefore, an interrupt controller is used to determine the order in which pending interrupts will be serviced by the CPU. Traditionally, interrupt handling for tinyAVR® and megaAVR® devices use a predefined priority, based on the interrupt vector address. The XMEGA® MCU family makes it possible to tailor the priority queue using a Programmable Multilevel Interrupt Controller (PMIC), which allows the user to assign interrupts to three priority levels. Interrupt handling techniques have become more configurable in the tinyAVR 0- and 1-series, and megaAVR 0-series. This application note describes the functionality of the new interrupt controller in detail, which uses a combination of predefined priority and multilevel controller.