I'm trying to learn arm assembler (on stm32) and had faced with a problem. I've configured timer interrupt on TIM2. ISR was executed, but on return from interrupt program counter loaded with 0. I've investigated how interrupt is calling and checked the stack for main thread registers values. In the stack program counter value is correct, but NVIC doesn't take it. Does anyone have ideas why it can be so?
.thumb
.syntax unified
.text
.org 0x00000000
SP: .word STACKINIT
RESET: .word main + 1
NMI_HANDLER: .word nmi_fault + 1
HARD_FAULT: .word hard_fault + 1
MEMORY_FAULT: .word memory_fault + 1
BUS_FAULT: .word bus_fault + 1
USAGE_FAULT: .word usage_fault + 1
.org 0x000000B0
TIMER2_INTERRUPT: .word timer2_interupt + 1
main:
push {lr}
bl cpu_init
pop {lr}
push {lr}
bl sleep_mode_init
pop {lr}
push {lr}
bl timer2_init
pop {lr}
cpsie i
push {lr}
bl timer2_enable
pop {lr}
_main_loop:
b _main_loop
bx lr
@ initialize timer 2 for using
timer2_init:
push {r0, r1}
@ TIM2 timer clock enable
@ load value from RCC_APB1ENR register
ldr r1, =RCC_APB1ENR
ldr r0, [r1]
@ set bit 0 (TIM2 timer clock enable)
orr r0, r0, 0x01
@ store r0 to RCC_APB1ENR
str r0, [r1]
@ load value from TIM2_CR1 register
ldr r1, =TIM2_CR1
ldr r0, [r1]
@ set timer2 Clock division bits (to 00), Auto-reload preload enable bit, Update request source bit and Counter enable bit
ldr r0, =0x8D
str r0, [r1]
@ set timer2 prescaler register
ldr r1, =TIM2_PSC
ldr r0, =0x10000 @ maximum prescaler value
str r0, [r1]
@ set auto-reload value to 1 (The counter is blocked while the auto-reload value is null.)
ldr r1, =TIM2_ARR
ldr r0, =0xFFFF @=0x01
str r0, [r1]
@ clear pending state for TIM2 interrupt
ldr r1, =NVIC_ICPR0
ldr r0, [r1]
orr r0, r0, 0x10000000
str r0, [r1]
@ set timer2 interrupt priority (each priority register contains priority for 4 interrrupts (each priority 8bit long))
ldr r1, =NVIC_IPR7
ldr r0, =0x23000000 @ priority 35 as defined in manuals
str r0, [r1]
@ set 28th bit in NVIC_ISER0 register, this should enable TIM2 interrupt
ldr r1, =NVIC_ISER0
ldr r0, [r1]
orr r0, r0, 0x10000000
str r0, [r1]
pop {r0, r1}
bx lr
@ sets Update interrupt enable bit in TIM2_DIER register
@ function does not take, nor recieve parameters
timer2_enable:
push {r0, r1}
ldr r1, =TIM2_DIER
ldr r0, [r1]
orr r0, r0, 0x01
str r0, [r1]
pop {r0, r1}
bx lr
@ initialize CPU for using
@ function does not take, nor recieve parameters
cpu_init:
push {r0, r1}
@ set RCC_CFGR register to system clock
ldr r1, =RCC_CFGR @ load address of RCC_CFGR registers
ldr r0, =0x5000000 @ high speed (clock) internal selected (HSI)
str r0, [r1] @ store value from r0 to address in r1
pop {r0, r1}
bx lr
@ initialize sleep mode behaviours
sleep_mode_init:
push {r0, r1}
@ set SLEEPONEXIT bit in System Control register (if the SLEEPONEXIT bit is set, the MCU enters Sleep mode as soon as it exits the lowest priority ISR)
@ read SCR register value (system control register)
ldr r1, =SCR
ldr r0, [r1]
@ set SLEEPONEXIT bit (first bit)
orr r0, r0, 0x02
@ store r0 value to SCR register
str r0, [r1]
pop {r0, r1}
bx lr
timer2_interupt:
@ check values in stack
mov r1, 0x18
ldr r0, [sp, r1]
bx lr
nmi_fault:
bkpt
bx lr
hard_fault:
bkpt
bx lr
memory_fault:
bkpt
bx lr
bus_fault:
bkpt
bx lr
usage_fault:
bkpt
bx lr
.end
User contributions licensed under CC BY-SA 3.0