ATmega328P中断向量表1字/2字条目均生效的原因探究
问题:ATmega328P中断向量表两种条目大小为何均能正常工作?
在搭载ATmega328P的Arduino Uno开发板与avr-g++编译环境中:
- 使用标准启动文件和库的LED闪烁定时器中断代码,反汇编显示中断向量表每个条目为2字(4字节),代码运行正常;
- 手写启动代码和中断向量表时,反汇编显示每个条目为1字(2字节),代码同样运行正常。
按逻辑,处理器应决定向量表条目大小,仅一种情况有效,但为何两种方式均能正常工作?
使用标准启动文件的代码(blink.cpp)
#define F_CPU 16000000UL #include <avr/io.h> #include <avr/interrupt.h> ISR(TIMER1_COMPA_vect) { PORTB ^= _BV(PB5); // Toggle LED } int main(void) { DDRB |= _BV(DDB5); // Set PB5 as output // Configure Timer1: CTC mode, prescaler 256, 1Hz interrupt TCCR1A = 0; TCCR1B = _BV(WGM12) | _BV(CS12); // CTC mode, prescaler 256 OCR1A = 62500 - 50000; // 16MHz / 256 / 1Hz TIMSK1 = _BV(OCIE1A); // Enable Timer1 Compare Match A interrupt sei(); // Enable global interrupts while (1) ; }
编译命令
avr-g++ -mmcu=atmega328p -Os -o blink.elf blink.cpp -Wa,-adhlns=blink.lst -Wl,-Map,blink.map avr-objcopy -O ihex blink.elf blink.hex avr-objdump -d -S blink.elf > blink.final.lst
反汇编片段
... 00000000 <__vectors>: 0: 0c 94 34 00 jmp 0x68 ; 0x68 <__ctors_end> 4: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt> ... 28: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt> 2c: 0c 94 40 00 jmp 0x80 ; 0x80 <__vector_11> 30: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt> ... 64: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
完整blink.hex
:100000000C9434000C943E000C943E000C943E0082 :100010000C943E000C943E000C943E000C943E0068 :100020000C943E000C943E000C943E000C94400056 :100030000C943E000C943E000C943E000C943E0048 :100040000C943E000C943E000C943E000C943E0038 :100050000C943E000C943E000C943E000C943E0028 :100060000C943E000C943E0011241FBECFEFD8E04C :10007000DEBFCDBF0E9452000C9463000C940000C0 :100080001F920F920FB60F9211248F939F9385B1F9 :1000900090E2892785B99F918F910F900FBE0F90A5 :1000A0001F901895259A109280008CE08093810013 :1000B00084ED90E3909389008093880082E08093A0 :0A00C0006F007894FFCFF894FFCF93 :00000001FF
手写启动代码的实现
启动文件blink.S
.section .vectors, "ax", @progbits .global __vectors __vectors: rjmp reset_handler ; Vector 0: Reset ; Other interrupts can be dummy jumps to safe handlers or zeros rjmp dummy_handler ; Vector 1 ... rjmp dummy_handler ; Vector 10 .extern __vector_11 ; Declare ISR from C++ rjmp __vector_11 ; Vector 11: Timer/Counter1 Capture Event ISR ; Further vectors... rjmp dummy_handler ; Vector 12 ... rjmp dummy_handler ; Vector 26 .equ RAMEND, 0x08FF ; Last SRAM address for ATmega328P .equ SPL, 0x3D ; I/O register address for Stack Pointer Low .equ SPH, 0x3E ; I/O register address for Stack Pointer High reset_handler: ; Initialize stack pointer ldi r16, lo8(RAMEND) out SPL, r16 ldi r16, hi8(RAMEND) out SPH, r16 ; Call main() call main rjmp . ; Loop forever if main returns dummy_handler: rjmp . ; Loop forever for unexpected interrupts .global main
业务代码blink.cpp
#include <avr/io.h> #include <avr/interrupt.h> ISR(TIMER1_COMPA_vect) { PORTB ^= (1 << PB5); // Toggle LED } void timer1CompASetup(uint16_t ocr1aValue) { TCCR1A = 0; TCCR1B = (1 << WGM12) | (1 << CS12); // CTC mode, prescaler 256 OCR1A = ocr1aValue; // 16MHz / 256 / 1Hz TIMSK1 = (1 << OCIE1A); // Timer1 COMPA interrupt enable } int main(void) { timer1CompASetup(62500 - 1); DDRB |= (1 << 5); // PB5 output (LED pin) sei(); while (1) ; }
编译命令
avr-g++ -mmcu=atmega328p -Os -nostartfiles -nostdlib -nodefaultlibs -ffreestanding -o blink.elf blink.S blink.cpp -Wa,-adhlns=blink.lst -Wl,-e,__vectors,-Map,blink.map,--section-start=.vectors=0x0000 avr-objcopy -O ihex blink.elf blink.hex avr-objdump -d -S blink.elf > blink.final.lst
反汇编片段
00000000 <__vectors>: 0: 19 c0 rjmp .+50 ; 0x34 <reset_handler> 2: 1f c0 rjmp .+62 ; 0x42 <dummy_handler> ... 14: 16 c0 rjmp .+44 ; 0x42 <dummy_handler> 16: 16 c0 rjmp .+44 ; 0x44 <__vector_11> 18: 14 c0 rjmp .+40 ; 0x42 <dummy_handler> ... 32: 07 c0 rjmp .+14 ; 0x42 <dummy_handler>
完整blink.hex
:1000000019C01FC01EC01DC01CC01BC01AC019C013 :1000100018C017C016C016C014C013C012C011C03B :1000200010C00FC00EC00DC00CC00BC00AC009C06C :1000300008C007C00FEF0DBF08E00EBF0E944100CF :1000400000C000C01F920F920FB60F9211248F9321 :100050009F9385B190E2892785B99F918F910F90E9 :100060000FBE0F901F901895109280002CE02093E7 :100070008100909389008093880082E080936F00D4 :10008000089583E294EF0E943400259A7894FFCF7C :00000001FF
内容的提问来源于stack exchange,提问作者vd1
相关产品推荐
相关产品推荐

