我试图在装配中对TM4C123GX Launchpad进行编程,以便使用16/32位Timer0A定期打开外部LED。我按照用户手册(TM4C123GH6PM)中的说明进行操作,但出于某种原因,它不起作用。我打开定时器时钟,打开NVIC中的中断并设置中断级别,将Timer设置为在超时时中断,并配置其他部分。 GPIO部分工作正常。 当我读取RIS位超时(GPTMRIS中的TATORIS位)时,即使在GPTMICR中将其清零后,它也始终设置为1。为什么中断不起作用?这是我的代码。
startup_rvmdk.S:
;...
EXPORT __Vectors
__Vectors
DCD StackMem + Stack ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NmiSR ; NMI Handler
;...
DCD IntDefaultHandler ; ADC Sequence 3
DCD IntDefaultHandler ; Watchdog timer
DCD Timer0A_Handler ; Timer 0 subtimer A
DCD IntDefaultHandler ; Timer 0 subtimer B
;...
;I added the Timer0A_Handler here.
Timer0A_Handler PROC
EXPORT Timer0A_Handler
;write "high" to data register for port F pin 1 to turn on red LED. GPIODATA
LDR r0, =AHB_PORTB
LDR r1, =PB5_MASK ;Get RAM address of PB5 mask value
LDR r2,[r1] ;Grab value of PB5 mask
EOR r2, r2, #0xF0 ;Toggle mas to toggle PB5
STR r2,[r1] ;Store the toggled mask to properly toggle next time
STR r2,[r0,#GPIODATAPB5]
;LDR r2,[r0,#GPIODATAPB5]
;Clear RIS bit
LDR r0, =NVIC_BASE
LDR r1,[r0, #GPTMICR]
BFC r1,#0,#1
ORR r1,r1,#1
STR r1,[r0, #GPTMICR]
;return to __main
BX LR
ENDP
;...
my_Constants.S:
AREA My_Constants, CODE, READONLY
THUMB
;defining addresses here for practice
;general base addresses
AHB_PORTB EQU 0x40059000
SYS_CONTROL EQU 0x400FE000
NVIC_BASE EQU 0xE0000000
SYS_PERIPH EQU 0xE000E000
TIMER16_0 EQU 0x40030000
;offsets
;RCGC Run-time offsets
RCGCGPIO EQU 0x608
RCGCTIMER EQU 0x604
;GPIO offsets
GPIOHBCTL EQU 0x06C
GPIOCTL EQU 0x52C
GPIODIR EQU 0X400
GPIOAFSEL EQU 0X420
GPIODR2R EQU 0X500
GPIOPUR EQU 0X510
GPIODEN EQU 0X51C
GPIODATAPB5 EQU 0x3FC;0X080
;SysTick offsets
STCTRL EQU 0X010
STRELOAD EQU 0X014
STCURRENT EQU 0X018
SYSPRI3 EQU 0XD20
;NVIC offsets
NVIC_ENn EQU 0x100
NVIC_DISn EQU 0x180
NVIC_PRIn EQU 0x440
;Timer offsets
GPTMCTL EQU 0x00C
GPTMCFG EQU 0x000
GPTMTAMR EQU 0x004
GPTMTBMR EQU 0x008
GPTMTAILR EQU 0x028
GPTMTBILR EQU 0x02C
GPTMTAPR EQU 0x038
GPTMTBPR EQU 0x03C
GPTMIMR EQU 0x018
GPTMRIS EQU 0x01C
GPTMICR EQU 0x024
END
my_Variables.S:
AREA My_Variables, DATA, READWRITE
THUMB
EXPORT PB5_MASK
PB5_MASK DCD 240;0x000000F0
END
main.S:
;Include constants I define to main
INCLUDE my_Constants.s
IMPORT PB5_MASK
AREA |.text|, CODE, READONLY
THUMB
EXPORT __main
ENTRY
;Input arguments:
; r0: IRQn
; r1: 1 = Enable, 0 = Disable
NVIC_Init PROC
PUSH {r4, LR} ;Push context onto stack
AND r2, r0, #0x1F ;Bitoffset
MOV r3, #1
LSL r3, r3, r2 ;Shift enable/disable bit to correct bit position
LDR r4, =NVIC_BASE ;NVIC base address
CMP r1, #0 ;Want to enable to disable?
LDRNE r1, =NVIC_ENn
LDREQ r1, =NVIC_DISn
ADD r1, r4, r1 ;add offset to base address
LSR r2, r0, #5 ;find register number n. IRQn/32
LSL r2, r2, #2 ;Wordoffset with 0 extend. Finds register n address
STR r3, [r1, r2]
POP {r4,LR}
BX LR
ENDP
;Input Arguments:
; r0: IRQn
; r1: Priority level 0~7
NVIC_Priority PROC
PUSH {r4, LR} ;Push context onto stack
AND r2, r0, #0x03 ;Bitoffset for TBB (case index)
LDR r3, =NVIC_BASE
LDR r4, =NVIC_PRIn
ADD r3, r3, r4
LSR r4, r0, #2 ;
LSL r4, r4, #2
TBB [PC, r2]
BranchTable
DCB (Case_0 - BranchTable)/2 ;index 0: Case_0
DCB (Case_0 - BranchTable)/2 ;index 1: Case_1
DCB (Case_0 - BranchTable)/2 ;index 2: Case_2
DCB (Case_0 - BranchTable)/2 ;index 3: Case_3
ALIGN
Case_0
LSL r1, r1, #5 ;Shift to [7:5]
B exit
Case_1
LSL r1, r1, #13 ;Shift to [15:13]
B exit
Case_2
LSL r1, r1, #21 ;Shift to [23:21]
B exit
Case_3
LSL r1, r1, #29 ;Shift to [31:29]
B exit
exit
STR r1, [r3, r4]
POP {r4,LR}
BX LR
ENDP
GPIO_Init PROC
;Save context
PUSH {LR}
;select APB. GPIOHBCTL
LDR r0, =SYS_CONTROL
LDR r1,[r0, #GPIOHBCTL]
ORR r1, r1, #(1<<1) ;Enable port B AHB instead. "Note that GPIO can only be accessed through the AHB aperture
STR r1,[r0, #GPIOHBCTL]
;set to output. GPIODIR
LDR r0, =AHB_PORTB
LDR r1,[r0,#GPIODIR]
ORR r1, r1, #(1<<5);pin5
STR r1,[r0,#GPIODIR]
;set mode to GPIO (nor alternate function). GPIOAFSEL
LDR r0, =AHB_PORTB
LDR r1,[r0,#GPIOAFSEL]
BFC r1,#0,#8 ;clears fields. 0 = GPIO
STR r1,[r0,#GPIOAFSEL]
;to drive strength to 2mA. GPIODR2R
LDR r0, =AHB_PORTB
LDR r1,[r0,#GPIODR2R]
ORR r1, r1, #(1<<5);pin5
STR r1,[r0,#GPIODR2R]
;set to pull up. GPIOPUR
LDR r0, =AHB_PORTB
LDR r1,[r0,#GPIOPUR]
ORR r1, r1, #(1<<5) ;pin5
STR r1,[r0,#GPIOPUR]
;enable digital output. GPIODEN
LDR r0, =AHB_PORTB
LDR r1,[r0,#GPIODEN]
ORR r1,r1, #(1<<5);pin 1 = digital output enable
STR r1,[r0,#GPIODEN]
;write "high" to data register for port B pin 5 to turn on red LED. GPIODATA
LDR r0, =AHB_PORTB
LDR r1,[r0,#GPIODATAPB5]
LDR r2, =PB5_MASK ;get RAM address of PB5 mask (pointer)
LDR r3,[r2] ;get the value of PB5 mask
ORR r1, r1, r3 ;Set PB5 to 'high'
STR r1,[r0,#GPIODATAPB5]
;Restore context
POP {LR}
BX LR
ENDP
;Initializes RCGC for GPIO and Timer0 at run-time
RCGC_Init PROC
;Save context
PUSH {LR}
;Initialize Timer0 for run-time via RCGC
LDR r0, =SYS_CONTROL
LDR r1,[r0, #RCGCTIMER]
BFC r1,#0,#6 ;clear fields [5:0]
ORR r1, r1, #1 ;R0 = 1: enable Timer0
STR r1,[r0, #RCGCTIMER]
;Initialize GPIO PortB for run-time via RCGC
;Enable clock. RCGCGPIO
LDR r0, =SYS_CONTROL
LDR r1,[r0,#RCGCGPIO]
ORR r1, r1, #(1<<1) ;enable port B clock(bit 5)
STR r1,[r0,#RCGCGPIO]
;Restore context
POP {LR}
BX LR
ENDP
;Specifically for Timer0. Generalize this function
TIMER_Init PROC
;Save context
PUSH {LR}
;Disable Timer0A
LDR r1, =TIMER16_0
LDR r2,[r1, #GPTMCTL]
BFC r2,#0,#1 ;clear TAEN to disable Timer0A
STR r2,[r1, #GPTMCTL]
;Seperate timers A & B for 16 bit timers
LDR r1, =TIMER16_0
LDR r2,[r1, #GPTMCFG]
BFC r2,#0,#2 ;Clear bits
ORR r2, r2, #0x4 ;Seperate timers
STR r2,[r1, #GPTMCFG]
;Set timer mode to periodic
LDR r1, =TIMER16_0
LDR r2,[r1, #GPTMTAMR]
BFC r2,#7,#1 ;No snapshot mode
BFC r2,#5,#1 ;Disable interrupts when counter == CCR
;ORR r2,r2,#(1<<5);Enable interrupts when counter == CCR
BFC r2,#4,#1 ;count down
BFC r2,#0,#2
ORR r2, r2,#(0x02);Set periodic mode
STR r2,[r1, #GPTMTAMR]
;Set ARR value
LDR r1, =TIMER16_0
LDR r2,[r1, #GPTMTAILR]
BFC r2,#0,#32 ;
MOV r2,#0x3E42
STR r2,[r1, #GPTMTAILR]
;Set Prescale value
LDR r1, =TIMER16_0
LDR r2,[r1, #GPTMTAPR]
BFC r2,#0,#8
ORR r2,r2,#0xFF
STR r2,[r1, #GPTMTAPR]
;Set interrupts at timeout
LDR r1, =TIMER16_0
LDR r2,[r1, #GPTMIMR]
BFC r2,#0,#1
ORR r2,r2,#1;Enable interrupts at timeout
STR r2,[r1, #GPTMIMR]
;Prevents Timer0A from freezing during debug
LDR r1, =TIMER16_0
LDR r2,[r1, #GPTMCTL]
BFC r2,#9,#1
ORR r2,r2,#(1<<9) ;Set TASTAL to 1 to prevent stopping during debug
BFC r2,#4,#1
ORR r2,r2,#(1<<4) ;Set RCTEN to 1 to prevent stopping during debug
STR r2,[r1, #GPTMCTL]
;Enable Timer0A
LDR r1, =TIMER16_0
LDR r2,[r1, #GPTMCTL]
BFC r2,#0,#1
ORR r2,r2,#1 ;Set TAEN to enable Timer0A
STR r2,[r1, #GPTMCTL]
;Restore context
POP {LR}
BX LR
ENDP
__main PROC
;Setup clocks for GPIO and GPTM at run-time
BL RCGC_Init
;Setup GPIO first
BL GPIO_Init
;Enable Timer0A interrupt
MOV r0, #19; Timer0A is IRQn = 19
MOV r1, #1; r1 = 1: Enable
BL NVIC_Init
;Setup priority level for Timer0A
MOV r0, #19; Timer0A is IRQn = 19
MOV r1, #1 ;priority #1
BL NVIC_Priority
;Setup Timer0A
BL TIMER_Init
while
;Read interrupt bit to see if it's working...
LDR r1, =NVIC_BASE
LDR r2,[r1, #GPTMRIS]
BFC r2,#1,#31 ;shows only TATORIS bit in r2. If 1 = interrupt. If 0 = no interrupt
;Clear RIS bit
LDR r0, =NVIC_BASE
LDR r1,[r0, #GPTMICR]
BFC r1,#0,#1
ORR r1,r1,#1
STR r1,[r0, #GPTMICR]
B while
ENDP
END
编辑1:
我看了一下屏蔽的中断寄存器GPTMMIR,寄存器肯定会设置为中断(一段时间后位变高),但是程序没有进入处理程序。我认为我自己在向量表中输入处理程序的名称是很重要的。我不知道这是否是原因,但没有处理程序名称(IntDefaultHandler)。有没有理由不进入处理程序?谢谢。
编辑2:
我也查看了NVIC中的ACTIVE寄存器,看看中断是否有效。我注意到NVIC的基地址错误,所以中断根本没有设置。我修复它并尝试调试,但是即使GPTMMIS位设置为1,ACTIVE显示的Timer0A位也为0。
编辑3:
发现了问题!我使用了错误的NVIC基地址和GPTMICR。中断没有工作,因为我根本没有访问NVIC寄存器,并且中断没有被清除,因为我也没有访问GPTMICR。我将使用更新的代码进行最终编辑。
编辑4:
这是更新后的代码。改变了四个部分。
my_Constants.S:
NVIC_BASE EQU 0xE0000000
startup_rvmdk.S:
;清除RIS位
LDR r0,= NVIC_BASE
LDR r0,= TIMER16_0
LDR r1,[r0,#GPTMICR]
main.S:
BranchTable
DCB(Case_0 - BranchTable)/ 2;索引0:Case_0
DCB( Case_0 - BranchTable)/ 2; Case_0-&gt; Case_1
DCB( Case_0 - BranchTable)/ 2; Case_0-&gt; Case_2
DCB( Case_0 - BranchTable)/ 2; Case_0-&gt; Case_3
ALIGN
用SYS_PERIPH替换NVIC_BASE的每个实例。
答案 0 :(得分:0)
所以我找到了解决方案。使用NVIC的基地址时(两次)我犯了一个错误。分支表也是错误的,GPTMICR的基地址也是错误的。以下是更正。
my_Constants.S:
NVIC_BASE EQU 0xE0000000
startup_rvmdk.S:
LDR r0,= NVIC_BASE
;Clear RIS bit
LDR r0, =TIMER16_0
LDR r1,[r0, #GPTMICR]
main.S:
BranchTable
DCB (Case_0 - BranchTable)/2 ;index 0: Case_0
DCB (Case_1 - BranchTable)/2 ;Case_0->Case_1
DCB (Case_2 - BranchTable)/2 ;Case_0->Case_2
DCB (Case_3 - BranchTable)/2 ;Case_0->Case_3
ALIGN
用SYS_PERIPH替换NVIC_BASE的每个实例。