Interrupt on the AVR controller in Atmel AVR Studio. Interrupts - Studying AVR - Article catalog - Microcontrollers - it's easy! In what environment to program microcontroller interrupts

Interrupt systems are an important part of any control system.

How efficiently the microprocessor system performs its functions largely depends on its operation. The general structure of the MK-51 interrupt system is shown in Fig. 14.3.

Microcontrollers of the MK-51 family provide support for five interrupt sources:

* two external interrupts arriving via inputs INT0 and INT1 (port lines P3: P3.2 and P3.3, respectively);

* two interruptions from timers/counters T/C0 and T/C1;

* serial port interrupt.

Interrupt requests are recorded in the special function registers of the microcontroller: flags IE0, IE1, TF0, TF1 interrupt requests from INT0, INT1, T/C0 and T/C1 are contained in the TCON control register (Table 14.4), and flags RI and TI requests for an interrupt from the serial port - in the SCON register for controlling the serial port.

Table 14.4. TCON Register Format

0 IT0 Setting the type of interrupt INT0

1 IE0 Interrupt request flag INT0

2 IT1 Setting the type of interrupt INT1

3 IE1 Interrupt request flag INT1

4 TR0 Enable timer/counter 0

5 TF0 Overflow flag (interrupt request) timer/counter 0

6 TR1 Enable timer/counter 1

7 TF1 Overflow flag (interrupt request) of timer/counter 1

Flags TF0 and TF1 are set by hardware when the corresponding timer/counter overflows (more precisely, when T/Cx transitions from the “all ones” state to the “all zeros” state).

Flags IE0 and IE1 are set by hardware from external interrupts IT0 and IT1, respectively. An external request can cause the flag to be set either when the signal level at the corresponding input is low, or when this signal switches from high to low level (with a frequency not exceeding half the external clock frequency of the MK).

The request type is configured by software setting the IT0 and IT1 bits in the TCON control register. Setting ITx = 0 configures the interrupt system to request a low signal level, ITx = 1 - sets the interrupt to request a low signal level.

The TI and RI flags are set by the serial interface hardware after the end of transmission or after the end of reception, respectively.

All specified interrupt request flags are programmatically available for setting and resetting. Setting the interrupt request flag in software results in the same response from the microcontroller as setting the same flag in hardware.

Flags TF0 and TF1 are reset by hardware when control is transferred to the corresponding interrupt routine.

Resetting the IEx flags is performed in hardware when servicing the interrupt only if the interrupt has been configured to sense the fall of the INTx signal. If the interrupt has been configured to sense the level of the request signal, then resetting the IEx flag must be performed by the interrupt service program, acting on the interrupt source to remove the request.

The TI and RI flags can only be reset by software.

Each type of interrupt is individually enabled or disabled by setting or clearing the corresponding bits of the IE interrupt enable register. This register also contains a general disable bit for all interrupts. The format of the IE register is given in table. 14.5.

Table 14.5. Assignment of IE register bits

Register position

Bit mnemonics

Function

Disable interruptions from all sources

Not used

Not used

Disable interrupt from serial port

Disable T/C1 timer/counter interrupt

Disable interrupt from external source INT1

Disable Timer/Counter Interrupt T/C0

Disable interrupt from external source INT0

Each type of interrupt can be programmatically assigned one of two possible priorities: 0 - lowest or 1 - highest.

Priorities are configured by setting or clearing the corresponding bit in the IP interrupt priority register. The format of this register is given in table. 14.6.

When interrupt requests are received simultaneously from sources that have different priorities, the request from the higher priority source is processed first.

In the case of simultaneous receipt of several interrupt requests with the same priority, the order of their processing is determined by the microcontroller hardware and cannot be changed by software. This order corresponds to the sequence of polling interrupt request flags, which looks like this:

IT0 -> TF0 -> IT1 -> TF1 -> (RI, TI)

Table 14.6. IP register bit assignments

Register position Bit mnemonic Function

7 - Not used

6 - Not used

5 - Not used

4 PS Serial port interrupt priority

3 PT1 Timer/Counter Interrupt Priority T/C1

2 PX1 Interrupt priority from external source INT1

1 PT0 Timer/Counter Interrupt Priority T/C0

0 PX0 Interrupt priority from external source INT0

A hardware-implemented interrupt handler call consists of the following actions:

* saving the value of the program counter on the stack;

The interrupt handler entry points for each interrupt source are fixed in hardware. Their values ​​are given in table. 14.7.

Table 14.7. Addresses of entry points to interrupt handlers

Interrupt source

Addresses of entry points to interrupt handlers

External interrupt( ITO)

Timer-counter(TFO)

External interrupt(IT1)

Timer-counter(TF1)

Serial port(R1 or T1)

The first command of the interrupt handler should be located at the specified address. As a rule, such a command is a command to unconditionally jump to the place in the program where the handler is actually located.

When switching to the interrupt handling routine, automatically, regardless of the state of the IE register, all interrupts that have a priority level equal to the priority level of the serviced interrupt are disabled - that is, nested interrupts with an equal priority level are disabled. Thus, a low-priority interrupt (having a "0" in the corresponding bit of the IP register) can be interrupted by a high-priority interrupt (having a "1" in the corresponding bit of the IP register), but not a low-priority one. Servicing a high priority interrupt cannot be interrupted by another source.

Returning from the interrupt handler is accomplished using the RETI instruction, which restores from the stack the value of the PC program counter stored there at the time the interrupt handler was called, and the interrupt priority logic.


Let's talk about interruptions. The word interrupt speaks for itself; a process is stopped for some time in order to perform additional actions. Interrupts can be external or internal. Let me give you a simple example I heard from my friend...

He got ready to wash the dishes in the kitchen, started with excitement, rolling up his sleeves... but the dishes turned out to be greasy and he was forced to stop to find a detergent for washing greasy dishes on one of the kitchen shelves, after which he continued his task again. But at some point the phone rang, and he again paused from his work, picked up the phone, his mother-in-law called and said that she was coming to visit, so he needed to go to the store to buy groceries before she arrived. I went to the store and only then washed the dishes.

This example shows two types of interruptions, the first is associated with the execution of the main work - searching for detergent for greasy dishes - an internal interruption, the second - phone call– external interruption.
In a microcontroller, external interrupts arise due to signals coming from other sources, internal interrupts arise due to devices built into the microcontroller itself. Why are interruptions so attractive?
The first is that we can stop the main process to perform some other function, and then continue this process.
The second, and probably in many cases the main one, is considered to be the acceleration of the process of performing all functions, due to internal additional devices. Let's return to our example. Let's say my friend started washing the dishes when his wife had already arrived home. Seeing the greasy dishes, he asks her to find dishwashing liquid, and while he is washing, she will already bring him this liquid. But then the phone rang, my wife picked up the phone, talked to her mother and went to the store. Together, everything was done very quickly!
And it’s even easier to get stuck – i.e. there is no main program.
My friend sits on the sofa and does nothing, the housekeeper sees the dirty dishes, tells him about it, and having received permission, begins to wash herself. When the phone rings, he tells his wife to pick up the phone, the wife is talking on the phone, and the conversation goes to the grocery store... Beauty! In this case, several I/O devices operate simultaneously in the microcontroller (in modern microcontrollers there can be quite a lot of them) and the overall processor performance increases many times, but interrupts from the devices are processed sequentially one after another (not simultaneously), depending on the priority ( in our example, the wife has higher priority than the housekeeper).

Several registers are responsible for managing interrupts
SREG – status register(states). We look at the table of input/output devices. The seventh bit of the SREG register is the I (interrupt) flag, which is called the global interrupt enable flag. If the flag is omitted (the seventh bit is zero), then all interrupts are disabled. If the flag is raised (set I to 1), we enable interrupts.

The I flag is set and reset with the commands:
SEI - enable interrupts
CLI - disable interrupts
Which interrupts will work is set using registers called - interrupt masks.
Interrupt masks are designated as follows:
TIMSK,..,..,.. – management of interrupts from timers and other built-in devices.
GIMSK (GIKR in the Mega family) - management of all external interrupts.
Interrupt masks in turn depend on interrupt flags:
TIFR and GIFR respectively(not to be confused with the global interrupt enable flag).

Interrupt execution sequence:
When the microcontroller is turned on, all interrupt flags are reset to 0. To enable interrupts, the program must set flag I of the SREG register to 1. After this, register the mask registers with local interrupts set (the interruptions that we need).
When an interrupt request (signal) arrives, it raises the interrupt flag (even if the interrupt is disabled, to organize nested interrupts and priority between different interrupts). If interrupts are not disabled, the controller will contact the appropriate (Interrupt Vectors) - interrupt vector, pausing the current program.
Interrupt vector is a fixed line in the program area where the program goes when an interrupt occurs.
The entire list of interrupt vectors is called interrupt vector table, which is located at the beginning of the program code.
So, at the moment the interrupt vector is accessed, the I flag of the SREG register and the flag that caused the interrupt are reset to 0, disabling other interrupts. If other interrupt requests occur while the interrupt is executing, the flags for those interrupts remain raised. Upon completion of the current interrupt, the I flag of the SREG register is raised, allowing the next one to execute. If several requests arrive and their flags are raised, then the interrupt whose vector is smaller at the address in the table, closer to the beginning of memory, will be executed first. The second one follows, and so on. In addition, the programmer can organize a so-called nested interrupt, when another interrupt occurs during the execution of the interrupt program. Then the execution of the current interrupt is stopped and a new one is executed, after which the execution of the stopped interrupt is resumed.

As an example, the table of interrupt vectors for ATtiny2313 is given

The interrupt vector table for Atmega16 is as follows:

When compared, the tables do not match at all.
In the ATtiny family, the interrupt vector line occupies 16 bits, and in the Mega family it takes 32 bits (pay attention to the addresses of the interrupt vectors; let me remind you that the address line in the program area is represented by a 16-bit word).

The program code for ATtiny2313 may look like this:
.cseg .org 0 rjmp Reset rjmp INT_0 rjmp INT_1 rjmp Timer1_capt1 rjmp Timer1_comp1 rjmp Timer1_OVF1 rjmp Timer0_OVF0 rjmp UART_RX rjmp UART_UDRE rjmp UART_TX rjmp ANA_COMP rjmp PCINT rjmp Timer1_compB rjmp Timer0_compA rj mp Timer0_compB rjmp USI_START rjmp USI_OVERFLOW rjmp EE_READY rjmp WDT_ OVERFLOW

As you can see, the interrupt vector creates a relative jump to the interrupt program labels. The table below shows the options; 1. When there are no interruptions; 2, 3. with external interrupt at input INT_1.
If the labels are “empty” (there is no program under the label), then nothing happens, and the program sequentially “runs through” the remaining labels and safely reaches the command RETI- Interrupt return - exit from the interrupt handler as shown in the first column of the table.

To execute an interrupt program, for example, at the INT_1 input, you need to remove the INT_1: label from the list. This is shown schematically in the second column of the table.
But, it is inconvenient for the programmer to write all the interrupts and separate labels for them each time, especially in the latest models, where the table is quite large; it is easier to immediately write the RETI command in the interrupt vector line if the interrupt is not used. Then the program will look as shown in the third column of the table.

AVR controllers, depending on the model, can have from 1 to 8 inputs external interrupts.
Let's consider the external interrupt management system. For this purpose, the following combinations of I/O registers are provided depending on the model (see the corresponding DataSheet):
- GIMSK, EIFR, PCMSK, MCUCR;
- GIKR, GIFR, MCUCR;
- EIMSK, EICR, EIFR;
GIMSK, GIKR, EIMSK - interrupt masks,
EIFR, PCMSK, GIFR, EIFR – interrupt flags
For permission or prohibition external interrupts control registers are intended: GIMSK-(General Interrupt Mask Register)(Tiny), GICR- (General Interrupt Control Register)(Mega), MCUCR – (MCU Control Register)




EIFR- External Interrupt Flag Register: 1 - enabled, 0 - disabled. Each bit (flag) allows the corresponding pin to act as an interrupt source.

GIMSK register control bits:
Bit 7 – INT1: External Interrupt Request 1 Enable – INT1 interrupt enable bit: 1 – enabled, 0 – disabled. The interrupt will be generated even if the INT1 pin is configured as an output. The INT1 bit is set to interrupt in the EIFR flag register. The INT1 pin is synchronized with the clock generator.

Bit 6 – INT0: External Interrupt Request 0 Enable - interrupt enable bit INT0: 1 – enabled, 0 – disabled. The interrupt will be generated even if the INT0 pin is configured as an output. The INT0 bit is set to interrupt in the EIFR flag register. The INT10 pin is synchronized with the clock generator.

Bit 5 – PCIE: Pin Change Interrupt Enable – interrupt enable bit on PCINT0…7 pins: 1 – enabled, 0 – disabled. Any change on any of the PCINT0...7 pins will generate an interrupt. Pins PCINT0...7 are configured for interruption individually, by bits in the PCMSK flag register.

PCMSK- Pin Change Mask Regiser - flag register PCMSK: 1 - allowed, 0 - disabled. Each bit (flag) allows the corresponding pin to act as an interrupt source. The PCINT0...7 pins are not synchronized with the clock generator, i.e. an interrupt occurs when a change occurs on any of the pins.

Mega8

and the corresponding flag register


Bit 7

Bit 6 – INT0: External Interrupt Request 0 Enable - interrupt enable bit INT0: 1 – enabled, 0 – disabled. The interrupt will be generated even if the INT0 pin is configured as an output. INT0 bit is set to interrupt in the GIFR flags register



GIFR – General Interrupt Flag Register: 1 – enabled, 0 – disabled. Each bit (flag) allows the corresponding pin to act as an interrupt source.

GICR register control bits:
Bit 7– : External Interrupt Request 1 Enable – interrupt enable bit INT1: 1 – allowed, 0 – prohibited. The interrupt will be generated even if the INT1 pin is configured as an output. INT1 bit is set to interrupt in the GIFR flags register

Bit 6 – INT0: External Interrupt Request 0 Enable - interrupt enable bit INT0: 1 – allowed, 0 – prohibited. The interrupt will be generated even if the INT0 pin is configured as an output. INT0 bit is set to interrupt in the GIFR flags register

Bit 5 – INT2: External Interrupt Request 2 Enable - interrupt enable bit INT2: 1 – allowed, 0 – prohibited. The interrupt will be generated even if the INT2 pin is configured as an output. INT2 bit is set to interrupt in the GIFR flags register

The functions of the INT0 and INT1 inputs in all controllers are controlled by the low-order bits of the MCUCR register

MCUCR– MCU Control Register
Control bits:
Bits 1, 0 – ISC01, ISC00 (Interrupt Sense Control 0 Bit 1 and Bit 0) – the state of these bits determines the event on the INT0 pin, which generates an INT0 interrupt:
ISC01=0, ISC00=0 – logical zero level;
ISC01=0, ISC00=1 – any change of logical state;
ISC01=1, ISC00=0 – on a falling edge;
ISC01=1, ISC00=1 – on a rising edge.

Bits 3, 2 – ISC11, ISC10 (Interrupt Sense Control 1 Bit 1 and Bit 0) – the state of these bits determines the signal level at the INT1 pin, which generates the INT1 interrupt:
ISC11=0, ISC10=0 – logical zero level;
ISC11=0, ISC10=1 – any change of logical state;
ISC11=1, ISC10=0 – on a falling edge;
ISC11=1, ISC10=1 – on a rising edge.

Well, it seems like we’ve talked to a minimum about external interruptions.
It is clear that in order for interrupts to work, they need to be registered accordingly.
Let's add the initialization of the interrupt on INT1 started for tiny on the rising edge of the signal:

Ldi r16.0x80 ; write in r16 the number 0b10000000 ldi r17.0x0C ; write in r17 the number 0b00001100 out MCUCR,r17 ; the interrupt will be generated on the rising edge ISC11=1, ISC10=1 out GIMSK,r16 ; set the mask INT0 sei
By the way, you can generate an interrupt on tiny2313 on any PCINT0…7 pins, on Mega up to series 48 these features are not available...
There are operations during which interrupts may occur that can cause the program to crash. In such cases, before starting the operation we write CLI, and after SEI. Such operations are called - atomic.
It is desirable that interrupt programs be compact and executed at maximum speed, because the purpose of any interrupt is to capture an event. If according to various reasons the program runs slowly, it is enough to record the event and process it a little later.

In order not to clutter the presented material with unnecessary information, I recommend that readers use datasheets, and if everything is not clear, then ask questions more often on the forums.
Next, we will consider in detail internal interrupts based on built-in timers. readers. To participate in the voting, register and log in to the site with your username and password.

One of the advantages of the ATmega8 microcontroller is its wide range of different interrupts.

Interrupt is an event upon the occurrence of which the execution of the main program is suspended and a function is called that handles an interrupt of a certain type.

Interrupts are divided into internal and external. Sources of internal interrupts include built-in microcontroller modules (timers, USART transceiver, etc.). External interrupts occur when external signals arrive at the microcontroller pins (for example, signals at the RESET and INT pins). The nature of the signals leading to the occurrence of an interrupt is set in the control register MCUCR, in particular in the bits - ISC00 (bit 0) and ISC01 (bit 1) for input INT 0; ISC10 (bit2) and ISC11 (bit3) for INT1 input.

In the ATmega8 microcontroller, each interrupt has its own interrupt vector(address at the beginning of the program memory area in which the command for jumping to the specified interrupt routine is stored). In mega8, all interrupts have the same priority. If several interrupts occur simultaneously, the interrupt with the lower vector number will be processed first.

Interrupt vectors in Atmega8

Address Interrupt source Description
0x0000 RESET Reset signal
0x0001 INT0 External interrupt request at INT0 input
0x0002 INT1 External interrupt request at INT1 input
0x0003 T/C1 Timer capture T/C1
0x0004 T/C1 Match T/C1 Timer Compare Register A
0x0005 T/C1 Match with compare register B of timer T/C1
0x0006 T/C1 T/C1 counter overflow
0x0007 T/C0 T/C0 counter overflow
0x0008 SPI SPI data transfer completed
0x0009 UART The UART transceiver has completed receiving data.
0x000A UART UART data register is empty
0x000B UART Data transmission by UART transceiver is completed
0x000C ANA_COMP Interrupt from analog comparator

Interrupt management

4 registers are responsible for managing interrupts in ATmega8:

GIMSK(aka GICR) - prohibit/enable interrupts based on signals at inputs INT0, INT1

GIFR- management of all external interrupts

TIMSK, TIFR- management of interruptions from timers/counters

Register GIMSK(GICR)

INTFx=1: an interrupt occurred at the INTx input. When entering the interrupt handling routine, INTFx is automatically reset to the log state. 0

Register TIMSK

7 6 5 4 3 2 1 0
TOIE1
OCIE1A
OCIE1B
-
TICIE
-
TOIE0
-

TOIE1=1: T/C1 overflow interrupt enabled

OCIE1A=1: interrupt when comparison register A matches the contents of counter T/C1 enabled

OCIE1B=1: interrupt when comparison register B matches the contents of counter T/C1 enabled

TICIE=1: interrupt enabled when the capture condition is met

TOIE0=1: T/C0 overflow interrupt enabled

Register TIFR

7 6 5 4 3 2 1 0
TOV1
OCF1A
OCF1B
-
ICF1
-
TOV0
-

TOV1=1: T/C1 overflow occurred

OCF1A=1: comparison register A coincided with the contents of counter T/C1 allowed

OCF1B=1: comparison register B matches the contents of counter T/C1 allowed

ICF=1: capture conditions met

TOV0=1: T/C0 overflow occurred

When entering the interrupt handling subroutine, the TIFR register flag corresponding to the interrupt is automatically reset to the log state. 0

Interrupts only work when general interrupts are enabled in the SREG status register (bit 7 = 1). When an interrupt occurs, this bit is automatically reset to 0, disabling subsequent interrupts.

In this example, the INT0 pin is enabled in pull-up input mode. When the pin is shorted to ground using a button, logic 0 is set on it (the edge of the signal drops from the supply voltage to 0) and the interrupt handler is triggered, turning on the light bulb connected to the zero pin of port B

void lampON()
{
PORTB.0=1;
DDRB.0=1;
}

interrupt void ext_int0_isr(void)
{
lampON();
}

DDRD.2=0;
PORTD.2=1;

SREG|= (1 while(1) (

The example above also shows how interrupt vectors are set in Code Vision AVR (interrupt void ext_int0_isr(void)). Interrupt vectors are set similarly for other cases:

EXT_INT0 2
EXT_INT1 3
TIM2_COMP 4
TIM2_OVF 5
TIM1_CAPT 6
TIM1_COMPA 7
TIM1_COMPB 8
TIM1_OVF 9
TIM0_OVF 10
SPI_STC 11
USART_RXC 12
USART_DRE 13
USART_TXC 14
ADC_INT 15
EE_RDY 16
ANA_COMP 17
TWI 18
SPM_READY 19

Part AVR microcontrollers includes a large number of peripheral devices (ADC, Timer/Counters, EXTI, Analog Comparator, EEPROM, USART, SPI, I2C, etc.), each of which can perform certain actions on data/signals and other information. These devices are integrated into the microcontroller to improve application efficiency and reduce costs when developing all kinds of devices based on AVR microcontrollers.

The processor communicates/controls peripheral devices through I/O Registers, which are located in Data Memory, allowing them to be used like regular variables. Each device has its own I/O registers.

All I/O Registers can be divided into three groups: data registers, control registers and status registers.

Using control registers, the device is configured to operate in one mode or another, with a certain frequency, accuracy, etc., and using Data Registers, the result of the work is read of this device(analog-to-digital conversion, received data, timer/counter value, etc.). It would seem that there is nothing complicated here (in fact, there really is nothing complicated here :)), turned on the device, indicated the desired operating mode, and then all that remains is to clip coupons, read the ready-made data and use them in calculations. The whole question is “when” to read this very data (has the device completed its work or is still processing data), because all peripheral devices work in parallel with the microcontroller core, and even at different frequencies. The question arises of implementing communication and synchronization between the processor and peripheral device.

As you probably already guessed, to implement communication and synchronization between the device and the processor, “Status Registers” are used, which store the current operating state of a particular device. Each state in which the device may be in corresponds to a “bit in the register state” (flag), the current value of which “speaks” about the current state of this device or its individual function (work completed/not completed, error during data processing, register empty, etc.).

The communication mechanism between the processor and a peripheral device is implemented by flag polling, which are responsible for a particular function of this device. Depending on the value of a particular flag (device state), you can change the flow of program execution (branching). Eg:

Checking if a certain flag is set (some event has occurred):

if (RegX & (1<< Flag) ) // if the flag in the RegX register is set
{
// do something
}

Waiting for the completion of some action (event):

while(!(RegX & (1<

Querying flags is a rather resource-intensive task, both in terms of program size and program speed. Since the total number of flags in AVR microcontrollers is quite large (an advantage), the implementation of communication between the processor and the device by polling flags leads to a decrease in the efficiency (code speed / code size) of the program you write, in addition, the program becomes very confusing, which contributes to the appearance of errors that are difficult to detect even with detailed debugging of the code.

In order to increase the efficiency of programs for AVR microcontrollers, as well as to facilitate the process of creating and debugging these programs, the developers have equipped all peripheral devices with “interrupt sources” ( Interrupt sources), some devices may have multiple interrupt sources.

Using interrupt sources, it is implemented synchronization mechanism, between the processor and the peripheral device, that is, the processor will begin receiving data, polling flags, and other actions on the peripheral device only when the device is ready for this (it will report the completion of data processing, an error during data processing, the register is empty, etc.) etc.), by generating an “interrupt request” ( Interrupt request), depending on the value of some flag (device/function/event state).

In the literature, very often, the entire chain of events, from the “interrupt request” (IRQ) to the “interrupt service procedure” (ISR), is abbreviated as an interrupt ( Interrupt).

What is an interrupt?


Interrupt is a signal that notifies the processor about the occurrence of an event. In this case, the execution of the current sequence of commands is suspended and control is transferred to the interrupt handling procedure corresponding to this event, after which code execution continues exactly from the point where it was interrupted (return of control). (Wiki)

Interrupt routine(Interrupt Service Routine) is nothing more than a function/subroutine that should be executed when a certain event occurs. We will use the word “procedure” in order to emphasize its difference from all other functions.

The main difference between the procedure and simple functions is that instead of the usual “return from function” (assembly command RET), you should use “return from interrupt” (assembler command RETI) - " RETurn from Interrupt".

AVR interrupt properties:

  • Each peripheral device that is part of the AVR microcontrollers has at least one interrupt source. Among all these interruptions, one should also include the reset interrupt, the purpose of which is different from all the others.
  • Each interrupt has a strictly assigned vector (link) pointing to the Interrupt service routine. All interrupt vectors are located at the very beginning of the program memory and together form the “interrupt vectors table”.
  • Each interrupt is associated with a specific “Interrupt Enable bit”. Thus, in order to use a specific interrupt, you should write to its “Interrupt Enable bit” - log. unit. Further, regardless of whether you have enabled certain interrupts or not, the microcontroller will not begin processing these interrupts until a logical one is written to the “Global Interrupt Enable bit” in the SREG status register. Also, to disable all interrupts (for an indefinite time), a logical zero should be written to the general interrupt enable bit.

The Reset interrupt, unlike all others, cannot be disabled. Such interruptions are also called Non-maskable interrupts.

  • Each interrupt has a strictly defined priority. The priority of an interrupt depends on its location in the “interrupt vector table”. The lower the vector number in the table, the higher the priority of the interrupt. That is, the highest priority is the reset interrupt, which is located first in the table, and accordingly in memory programs. The external interrupt INT0, following the Reset interrupt in the “interrupt vector table”, has a priority lower than that of Reset, but higher than that of all other interrupts, etc.

The interrupt vector table, except for the Reset vector, can be moved to the beginning of the Boot section of Flash memory by setting the IVSEL bit in the GICR register. The reset vector can also be moved to the beginning of the Boot section of Flash memory by programming the fuse bit - BOOTRST.



Fig.1 ATmega16 interrupt vector table

Interrupt routine prototype


To declare a function as an interrupt handling routine, you must follow certain prototyping rules so that the compiler/linker can correctly identify and associate the interrupt you need with its handling routine.

First, the interrupt service routine cannot accept anything as an argument (void), and also cannot return anything (void). This is due to the fact that all interrupts in AVR are asynchronous, so it is not known where the execution of the program will be interrupted, from whom to receive and to whom to return the value, and also to minimize the time of entry and exit from the interrupt.

void isr(void)

Secondly, before the function prototype, you should indicate that it is an interrupt handling procedure. As you know, in the C language only the code used in the main function is executed. Since the interrupt handling procedure in the main function is not used anywhere, so that the compiler does not “throw out” it as unnecessary, before the procedure prototype it should be indicated that this function is an interrupt handling procedure.

Prototype of interrupt handling procedure in AVR Studio environment

#include

ISR (XXX_vect)
{

}

In AVR Studio (AVR GCC), each interrupt routine begins with an ISR macro definition, followed by the following construct in parentheses:

XXX_vect

where “XXX” is the name of the interrupt vector. All vector names for a specific AVR microcontroller can be found in the “interrupt vector table” of the microcontroller’s datasheet or in its header file. For example, the “interrupt vector table” for the ATmega16 microcontroller is shown in Fig. 1, where in the Source column all the names of the interrupt vectors are listed. The names can also be found in the header file of this microcontroller (C:\Program Files\Atmel\AVR Tools\AVR Toolchain\avr\include\avr\iom16.h), see Fig. 2. All we need to do is find the name of the vector we need in the table and add the suffix “_vect” to it.


Fig.2 ATmega16 header file for AVR Studio

For example, let’s write an interrupt handling procedure for receiving a byte via USART (USART, Rx Complete):

ISR (USART_RXC_vect)
{
// Interrupt handler body
}

By the way: before using any interrupt in AVR Studio, you should include the header files io.h and interrupt.h in the project:

#include
#include

You can read more about interrupt handlers in AVR Studio (AVR GCC) in the Introduction to avr-libc’s interrupt handling section.

Prototype of interrupt handling procedure in ImageCraft environment

#pragma interrupt_handler : iv_XXX
void< handler_name>(void)
{
// Interrupt handler body
}

In the ImageCraft environment, the prototype interrupt routine looks like this:

void< handler_name>(void)

Where , this is whatever name you want to give this interrupt handler. One of the requirements for declaring interrupt handling procedures is that before the function prototype it should be indicated that it is an interrupt handler. This is done using a pragma directive interrupt_handler :

#pragma interrupt_handler : iv_XXX

Where this is the name of the function that will be used as an interrupt handler, and the construction “iv_XXX” is the name of the interrupt vector (XXX) with the prefix “iv_”. As in the case of AVR Studio, all vector names for a specific AVR microcontroller can be found in the “interrupt vector table” of the datasheet of a given microcontroller or in its header file (see Fig. 3).


Fig.3 ATmega16 header file for ImageCraft IDE

For example, the procedure for handling an interrupt for receiving a byte via USART (USART, Rx Complete) in the ImageCraft environment will look like this:

#pragma interrupt_handler usart_rxc_isr: iv_USART_RXC
void usart_rxc_isr(void)
{
// Interrupt handler body
}

More information about interrupt handling procedures in the ImageCraft IDE can be found in the Help->Programming the AVR->Interrupt Handlers menu of the development environment.

Sometimes, if several interrupt handlers need to do the same thing, then to save program memory, you can direct several interrupt vectors to the same interrupt routine.

In AVR Studio it looks like this:

ISR (INT0_vect)
{
// Do something
}
ISR(INT1_vect, ISR_ALIASOF(INT0_vect) ) ;

First comes the interrupt processing procedure for a specific vector, in this case INT0. All other procedures can refer to any interrupt handler using the construct:

ISR (YYY_vect, ISR_ALIASOF(XXX_vect) ) ;

where YYY is the name of the interrupt vector that refers to the previously declared interrupt handler for vector XXX.

In ImageCraft it looks like this:

#pragma interrupt_handler : iv_XXX : iv_YYY
void< handler_name>(void)
{
// Interrupt handler body
}

#pragma interrupt_handler : iv_XXX
#pragma interrupt_handler : iv_YYY
void< handler_name>(void)
{
// Interrupt handler body
}

where vectors XXX and YYY refer to the same interrupt handler .

How does the interrupt work in AVR microcontrollers?

1. Let's assume that " interrupt request” (IRQ).

By the way: if several requests for interrupt processing occur simultaneously, the interrupt with the highest priority will be processed first, all other requests will be processed after the completion of the high-priority interrupt.

2. Examination.

If the enable bit for this interrupt is set (Interrupt enable bit), and the I-bit (general interrupt enable bit) of the processor status register (SREG) is set, then the processor begins preparing the interrupt service routine, while the general interrupt enable bit (I-bit of the register SREG) is reset, thus disabling all other interrupts. This occurs so that no other event can interrupt the processing of the current interrupt.

By the way: if in the interrupt handling procedure you set the I-bit to the log state. units, then any activated interrupt can in turn interrupt the processing of the current interrupt. Such interrupts are called nested interrupts.

3. Preparation.

The processor completes execution of the current assembly instruction, and then places the address of the next instruction on the stack (PC->STACK). Next, the processor checks which interrupt source has submitted an “interrupt request” (IRQ), after which, using the vector of this source (link) from the vector table (which is firmly assigned to each interrupt source), it proceeds to the interrupt processing procedure (JMP instruction). That's it, the processor spends at least 4 clock cycles (depending on the moment the request appears and the duration of execution of the current instruction). This is a very good response time to IRQ, compared to microcontrollers from other manufacturers.

By the way: if an IRQ occurs while the microcontroller is in sleep mode, the response time to the IRQ increases by another four clock cycles, plus the time stored in the fuse bits SUT1 and SUT0 (Start-Up Time).

Interrupt - an event that requires an immediate response from the processor. The response is that the processor interrupts processing of the current program ( interrupted program) and proceeds to execute some other program ( interrupting program), specially designed for this event. Upon completion of this program, the processor returns to executing the interrupted program.

Each event requiring an interruption is accompanied by interrupt signal, notifying the computer about this, and called interrupt request.

Program status represents a set of states of all storage elements at the corresponding point in time (for example, after the last command was executed). When an interrupt occurs, the microcontroller stores the contents of the program counter on the stack and loads the address of the corresponding interrupt vector into it. The last command of the interrupt service routine must be a command that returns to the main program and restores the previously stored program counter. While the interrupt handler is executing, some information may change. Therefore, when moving to the interrupt handler, it is necessary to save the elements that are being changed. The set of such elements is program state vector. In this case, other information about the state of memory cells is not significant or can be restored programmatically.

Vector initial state contains all the necessary information for the initial launch of the program. In many cases, the initial state vector contains only one element - the starting address of the program being launched.

Interrupt vector is the vector of the initial state of the interrupting program (handler) and contains all the necessary information for moving to the handler, including its starting address. Each interrupt type has its own interrupt vector, which initiates the execution of the corresponding handler. Typically, interrupt vectors are stored in specially allocated fixed memory locations with short addresses, which represent interrupt vector table. To jump to the appropriate interrupt program, the processor must have an interrupt vector and the address of this vector. At this address, as a rule, there is an unconditional jump command to the interrupt handling subroutine.

As a rule, the control of storing and returning is assigned to the interrupt handler. In this case, the handler consists of three parts - preparatory (prologue) and final (epilogue), which ensure program switching, and the actual interrupting program, which performs the operations requested by the request. Response time is defined as the time interval from the moment an interrupt request is received until the interrupting program begins execution.


tp– system response time to interruption;
t z– time for storing the state of the interrupted program;
t ppr– time of the actual interrupting program;
t in– time to restore the state of the interrupted program

If there are several sources of requests, a certain order of servicing incoming requests must be established, called priority relationships or service discipline. The set of all possible processor interrupt types is interrupt system microcontroller. The service discipline determines which of several requests received simultaneously should be processed first, and whether this request interrupt one or another interrupt handler.
If a higher priority interrupt request is received while an interrupt is being processed, control is transferred to the higher priority interrupt handler and the lower priority interrupt handler is suspended. Arises interrupt nesting. The maximum number of programs that can suspend each other is called depth of interruptions.

If the interrupt request is not serviced by the time a new request arrives from the same source (same priority), then interrupt system saturation. In this case, part of the interrupt requests will be lost, which for normal operation microcontroller is not allowed.

Characteristics of the interrupt system are:

  • total number of interrupt requests number of sources of interrupt requests;
  • interrupt representation type - as a rule, an interrupt request is represented by a logical signal level;
  • interrupt priority – determines the order in which each interrupt request is processed; the higher the priority, the shorter the delay in the execution of the interrupting program for it;
  • response time – the time interval between the appearance of the interrupt request and the start of execution of the interrupting program;
  • interruption delay – determined by the total time for storing and restoring the program;
  • depth, usually coincides with the number of priority levels in the interrupt system;
  • interrupt system saturation;
  • permissible moments of program interruption (usually the end of execution of the next command).

Interrupt masking used to tell the microcontroller to respond to each type of interrupt or to ignore it. The interrupt mask represents a binary code whose bits are assigned to the sources of the interrupt request. The one bit in the binary code tells the microcontroller to handle this type of interrupt. A zero bit, on the contrary, does not allow the microcontroller to proceed to processing interrupts of the specified type.
As a rule, in addition to masking interrupts, there is also a global interrupt enable bit, the zero value of which disables all interrupt handlers (except for hardware reset and jump to the beginning of the executing program).
In addition to the interrupt mask binary code, there is also a binary code interrupt flags, which allows the interrupt handler to set the source of the interrupt if there are several sources with the specified request in the microcontroller.




Top