Good day,
My code for configuring the NVIC and peripheral interrupts are already working as expected, but the only problem now is the debugger shows that the processor always jumps to the default handler (__default_handler) and never on my defined interrupt handler whenever I trigger the interrupt source.
I already added the specific interrupt vector in the vector table from the file vector_table_M.s and included it in my project. Am I missing something else?
Hardware: Tiva C Launchpad from TI
IDE: IAR Embedded Workbench
Thanks for any help,
William
Yes, my vector table is located at the default ROM address 0x0, and I did override the default table provided by IAR. The default vector table only had the core exceptions up to SysTick, so I just added the device specific exceptions following the correct order listed in the datasheet. Also yes, I believe my added vectors had a "weak" symbol just like in the core exceptions, but I already defined a handler in my main code which has exactly the right name I defined at the vector table.
Did you actually look at the binary, or are you just saying that you think you did all the right things at source level?
I guess another possibility is that code you're unaware of (in bootloader, or startup code, or *something*) has changed the vector table address...
I did carefully look at my source code and even the map file but everything seemed fine. By looking at the binary, do you mean the object dump? If yes, in what particular section should I inspect?
As far as I know only the linker script file can alter the vector table address. I left it with the default value (0x0). My code is running just fine on the board (unless I trigger the interrupt ofcourse), so does that already confirm the vector table is at the right address? (Well, the processor did jump to the reset handler).
If you do something like:
arm-none-eabi-objdump -D myfile.elf
You'll get a "disassembly" output that starts something like:
00004000 <exception_table>: 4000: 20030000 andcs r0, r3, r0 4004: 00004e1d andeq r4, r0, sp, lsl lr 4008: 00004e09 andeq r4, r0, r9, lsl #28 400c: 00004e09 andeq r4, r0, r9, lsl #28 4010: 00004e09 andeq r4, r0, r9, lsl #28 4014: 00004e09 andeq r4, r0, r9, lsl #28 4018: 00004e09 andeq r4, r0, r9, lsl #28 ... 402c: 00004e09 andeq r4, r0, r9, lsl #28 4030: 00004e09 andeq r4, r0, r9, lsl #28 4034: 00000000 andeq r0, r0, r0 4038: 00004e09 andeq r4, r0, r9, lsl #28 403c: 00004e9d muleq r0, sp, lr 4040: 00004e09 andeq r4, r0, r9, lsl #28 4044: 00004e09 andeq r4, r0, r9, lsl #28 4048: 00004e09 andeq r4, r0, r9, lsl #28 404c: 00004e09 andeq r4, r0, r9, lsl #28 4050: 00004e09 andeq r4, r0, r9, lsl #28 4054: 00004e09 andeq r4, r0, r9, lsl #28 4058: 00004e09 andeq r4, r0, r9, lsl #28 405c: 00004e09 andeq r4, r0, r9, lsl #28 4060: 00004e09 andeq r4, r0, r9, lsl #28 4064: 00004e09 andeq r4, r0, r9, lsl #28 4068: 00004e09 andeq r4, r0, r9, lsl #28 406c: 00004e09 andeq r4, r0, r9, lsl #28 4070: 00004da9 andeq r4, r0, r9, lsr #27 4074: 00004daf andeq r4, r0, pc, lsr #27 4078: 00004db5 ; <UNDEFINED> instruction: 0x00004db5 407c: 00004dbb ; <UNDEFINED> instruction: 0x000
(the "disassembly" is bogus, but this is pretty much the most obvious way to look at the vectors.This particular code is for SAMD51 and was compiled to work with a bootloader, so it's vector table is a 0x4000 instead of 0x0.)
20030000 is the initial stack pointer, 0x4e1d is the start address, and then there are a bunch of vectors that are "obviously" the default vector (0x4e09), and a few that are obviously NOT the default vector. The first thing I'd check is whether the particular vector you think you've added is NOT the default vector any more. Then you can use arm-none-eabi-nm -SC myfile.elf |grep -i handler to see if it actually matches your function:arm-none-eabi-nm -SC myfile.elf | grep -i handler00004e08 00000002 W AC_Handler ;; bunch of handlers set to the weak Dummy Handler...00004e08 00000002 W ADC0_0_Handler ;;; ...00004e08 00000002 W DAC_3_Handler00004e08 00000002 W DAC_4_Handler00004e08 00000002 W DMAC_0_Handler00004e08 00000002 W DMAC_1_Handler00004e08 00000002 W DMAC_2_Handler00004e08 00000002 W DMAC_3_Handler00004e08 00000002 W DMAC_4_Handler00004e08 00000002 W DebugMon_Handler00004e08 00000002 T Dummy_Handler00004da8 00000006 T EIC_0_Handler ;; Non-default handlers!00004de4 00000006 T EIC_10_Handler00004dea 00000006 T EIC_11_Handler00004df0 00000006 T EIC_12_Handler
I see your point. I used the "ielfdump" utility provided by IAR, and these are the sections I found useful.
The symtab shows the vector table is at the correct address and my handler is defined and named "GPIOPortJ_Handler" at address 0x1fd.
62: __vector_table 0x0 4 Data Gb 63: Region$$Table$$Base 0x0 Ext -- Gb 64: Region$$Table$$Limit 0x0 Ext -- Gb 65: __iar_systems$$module 0x1 Abs -- Gb 66: gpio_setup 0x11d 5 Code Gb 0x36 67: int_setup 0x153 5 Code Gb 0x2a 68: clear_int 0x17d 5 Code Gb 0x20 69: main 0x19d 5 Code Gb 0x24 70: GPIOPortJ_IRQHandler 0x1fd 5 Code Gb 0x20 71: SysTick_Handler 0x21d 5 Code Gb 0xc 72: __cmain 0x235 5 Code Gb 73: ?main 0x235 5 Code Gb 74: _call_main 0x241 5 Code Gb 75: _main 0x24f 5 Code Gb 76: __low_level_init 0x253 5 Code Gb 0x4 77: exit 0x257 5 Code Gb 0x4 78: _exit 0x25d 5 Code Gb 79: __exit 0x269 5 Code Gb 0x14 80: __iar_program_start 0x27d 5 Code Gb 81: CSTACK$$Base 0x2000'0000 6 -- Gb 82: CSTACK$$Limit 0x2000'8000 6 -- Gb 83: __iar_rom_use_0nuD_mcWsqA 0x286 Abs -- Gb
This is the vector table and you can see the exception I'm interested at has the custom function I defined, and everything else has the default handler.
Section #4 A0: $d: `.intvec7`: __vector_table: 0x0: 0x2000'8000 DC32 CSTACK$$Limit 0x4: 0x0000'027d DC32 __iar_program_start 0x8: 0x0000'025b DC32 __default_handler 0xc: 0x0000'025b DC32 __default_handler 0x10: 0x0000'025b DC32 __default_handler 0x14: 0x0000'025b DC32 __default_handler 0x18: 0x0000'025b DC32 __default_handler 0x1c: 0x0000'0000 DC32 0x0 0x20: 0x0000'0000 DC32 0x0 0x24: 0x0000'0000 DC32 0x0 0x28: 0x0000'0000 DC32 0x0 0x2c: 0x0000'025b DC32 __default_handler 0x30: 0x0000'025b DC32 __default_handler 0x34: 0x0000'0000 DC32 0x0 0x38: 0x0000'025b DC32 __default_handler 0x3c: 0x0000'021d DC32 SysTick_Handler 0x40: 0x0000'025b DC32 __default_handler 0x44: 0x0000'025b DC32 __default_handler . . . . . . 0x110: 0x0000'025b DC32 __default_handler 0x114: 0x0000'025b DC32 __default_handler 0x118: 0x0000'01fd DC32 GPIOPortJ_IRQHandler
The handler itself:
`.text_4`: GPIOPortJ_IRQHandler: 0x1fc: 0x480a LDR.N R0, [PC, #0x28] ; 0xe000'e104 0x1fe: 0x6800 LDR R0, [R0] 0x200: 0xf5b0 0x2f00 CMP.W R0, #524288 ; 0x80000 0x204: 0xd109 BNE.N @21a 0x206: 0x4809 LDR.N R0, [PC, #0x24] ; 0x4006'03fc 0x208: 0x6801 LDR R1, [R0] 0x20a: 0xf051 0x0102 ORRS.W R1, R1, #2 0x20e: 0x6001 STR R1, [R0] 0x210: 0x4807 LDR.N R0, [PC, #0x1c] ; 0x4006'43fc 0x212: 0x6801 LDR R1, [R0] 0x214: 0xf091 0x0102 EORS.W R1, R1, #2 0x218: 0x6001 STR R1, [R0] @21a: 0x21a: 0x4770 BX LR
Is this information enough? It's really weird because whenever I trigger the interrupt, a bus fault still occurs and it jumps straight to the default handler and I really can't say what exactly the problem is anymore.
Also, this is the .s file from IAR that I modified and added to my project. I'll just leave it here in case it provides any useful info.
/************************************************** * * Part one of the system initialization code, contains low-level * initialization, plain thumb variant. * * Copyright 2008-2017 IAR Systems AB. * * $Revision: 112610 $ * **************************************************/ ; ; The modules in this file are included in the libraries, and may be replaced ; by any user-defined modules that define the PUBLIC symbol __iar_program_start or ; a user defined start symbol. ; To override the cstartup defined in the library, simply add your modified ; version to the workbench project. ; ; The vector table is normally located at address 0. ; When debugging in RAM, it can be located in RAM, aligned to at least 2^6. ; The name "__vector_table" has special meaning for C-SPY, which ; is where to find the SP start value. ; If vector table is not located at address 0, the user has to initialize the NVIC vector ; table register (VTOR) before using interrupts. ; ; Cortex-M version ; MODULE ?vector_table AAPCS INTERWORK, VFP_COMPATIBLE, RWPI_COMPATIBLE PRESERVE8 CFI Names cfiNames0 CFI StackFrame CFA R13 DATA CFI Resource R0:32, R1:32, R2:32, R3:32, R4:32, R5:32, R6:32, R7:32 CFI Resource R8:32, R9:32, R10:32, R11:32, R12:32, R13:32, R14:32 CFI EndNames cfiNames0 CFI Common cfiCommon0 Using cfiNames0 CFI CodeAlign 2 CFI DataAlign 4 CFI ReturnAddress R14 CODE CFI CFA R13+0 CFI R0 Undefined CFI R1 Undefined CFI R2 Undefined CFI R3 Undefined CFI R4 SameValue CFI R5 SameValue CFI R6 SameValue CFI R7 SameValue CFI R8 SameValue CFI R9 SameValue CFI R10 SameValue CFI R11 SameValue CFI R12 Undefined CFI R14 SameValue CFI EndCommon cfiCommon0 ;; Forward declaration of sections. SECTION CSTACK:DATA:NOROOT(3) SECTION .intvec:CODE:NOROOT(2) EXTERN __iar_program_start PUBLIC __vector_table DATA __iar_init$$done: ; The vector table is not needed ; until after copy initialization is done __vector_table DCD sfe(CSTACK) DCD __iar_program_start DCD NMI_Handler DCD HardFault_Handler DCD MemManage_Handler DCD BusFault_Handler DCD UsageFault_Handler DCD 0 DCD 0 DCD 0 DCD 0 DCD SVC_Handler DCD DebugMon_Handler DCD 0 DCD PendSV_Handler DCD SysTick_Handler ;; ;; Device Specific Interrupts ;; DCD GPIOPortA_IRQHandler DCD GPIOPortB_IRQHandler DCD GPIOPortC_IRQHandler DCD GPIOPortD_IRQHandler DCD GPIOPortE_IRQHandler DCD UART0_IRQHandler DCD UART1_IRQHandler DCD SSI0_IRQHandler DCD I2C0_IRQHandler DCD PWMFault_IRQHandler DCD PWMGen0_IRQHandler DCD PWMGen1_IRQHandler DCD PWMGen2_IRQHandler DCD QEI0_IRQHandler DCD ADCSeq0_IRQHandler DCD ADCSeq1_IRQHandler DCD ADCSeq2_IRQHandler DCD ADCSeq3_IRQHandler DCD Watchdog_IRQHandler DCD Timer0A_IRQHandler DCD Timer0B_IRQHandler DCD Timer1A_IRQHandler DCD Timer1B_IRQHandler DCD Timer2A_IRQHandler DCD Timer2B_IRQHandler DCD Comp0_IRQHandler DCD Comp1_IRQHandler DCD Comp2_IRQHandler DCD SysCtrl_IRQHandler DCD FlashCtrl_IRQHandler DCD GPIOPortF_IRQHandler DCD GPIOPortG_IRQHandler DCD GPIOPortH_IRQHandler DCD USART2_IRQHandler DCD SSI1_IRQHandler DCD Timer3A_IRQHandler DCD Timer3B_IRQHandler DCD I2C1_IRQHandler DCD QEI1_IRQHandler DCD CAN0_IRQHandler DCD CAN1_IRQHandler DCD CAN2_IRQHandler DCD Ethernet_IRQHandler DCD Hibernate_IRQHandler DCD USB0_IRQHandler DCD PWMGen3_IRQHandler DCD uDMAST_IRQHandler DCD uDMAError_IRQHandler DCD ADC1Seq0_IRQHandler DCD ADC1Seq1_IRQHandler DCD ADC1Seq2_IRQHandler DCD ADC1Seq3_IRQHandler DCD I2S0_IRQHandler DCD EBI0_IRQHandler DCD GPIOPortJ_IRQHandler ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Default interrupt handlers. ;; PUBWEAK NMI_Handler PUBWEAK HardFault_Handler PUBWEAK MemManage_Handler PUBWEAK BusFault_Handler PUBWEAK UsageFault_Handler PUBWEAK SVC_Handler PUBWEAK DebugMon_Handler PUBWEAK PendSV_Handler PUBWEAK SysTick_Handler PUBWEAK GPIOPortA_IRQHandler PUBWEAK GPIOPortB_IRQHandler PUBWEAK GPIOPortC_IRQHandler PUBWEAK GPIOPortD_IRQHandler PUBWEAK GPIOPortE_IRQHandler PUBWEAK UART0_IRQHandler PUBWEAK UART1_IRQHandler PUBWEAK SSI0_IRQHandler PUBWEAK I2C0_IRQHandler PUBWEAK PWMFault_IRQHandler PUBWEAK PWMGen0_IRQHandler PUBWEAK PWMGen1_IRQHandler PUBWEAK PWMGen2_IRQHandler PUBWEAK QEI0_IRQHandler PUBWEAK ADCSeq0_IRQHandler PUBWEAK ADCSeq1_IRQHandler PUBWEAK ADCSeq2_IRQHandler PUBWEAK ADCSeq3_IRQHandler PUBWEAK Watchdog_IRQHandler PUBWEAK Timer0A_IRQHandler PUBWEAK Timer0B_IRQHandler PUBWEAK Timer1A_IRQHandler PUBWEAK Timer1B_IRQHandler PUBWEAK Timer2A_IRQHandler PUBWEAK Timer2B_IRQHandler PUBWEAK Comp0_IRQHandler PUBWEAK Comp1_IRQHandler PUBWEAK Comp2_IRQHandler PUBWEAK SysCtrl_IRQHandler PUBWEAK FlashCtrl_IRQHandler PUBWEAK GPIOPortF_IRQHandler PUBWEAK GPIOPortG_IRQHandler PUBWEAK GPIOPortH_IRQHandler PUBWEAK USART2_IRQHandler PUBWEAK SSI1_IRQHandler PUBWEAK Timer3A_IRQHandler PUBWEAK Timer3B_IRQHandler PUBWEAK I2C1_IRQHandler PUBWEAK QEI1_IRQHandler PUBWEAK CAN0_IRQHandler PUBWEAK CAN1_IRQHandler PUBWEAK CAN2_IRQHandler PUBWEAK Ethernet_IRQHandler PUBWEAK Hibernate_IRQHandler PUBWEAK USB0_IRQHandler PUBWEAK PWMGen3_IRQHandler PUBWEAK uDMAST_IRQHandler PUBWEAK uDMAError_IRQHandler PUBWEAK ADC1Seq0_IRQHandler PUBWEAK ADC1Seq1_IRQHandler PUBWEAK ADC1Seq2_IRQHandler PUBWEAK ADC1Seq3_IRQHandler PUBWEAK I2S0_IRQHandler PUBWEAK EBI0_IRQHandler PUBWEAK GPIOPortJ_IRQHandler SECTION .text:CODE:REORDER:NOROOT(1) CFI Block cfiBlock0 Using cfiCommon0 CFI Function __default_handler THUMB NMI_Handler HardFault_Handler MemManage_Handler BusFault_Handler UsageFault_Handler SVC_Handler DebugMon_Handler PendSV_Handler SysTick_Handler GPIOPortA_IRQHandler GPIOPortB_IRQHandler GPIOPortC_IRQHandler GPIOPortD_IRQHandler GPIOPortE_IRQHandler UART0_IRQHandler UART1_IRQHandler SSI0_IRQHandler I2C0_IRQHandler PWMFault_IRQHandler PWMGen0_IRQHandler PWMGen1_IRQHandler PWMGen2_IRQHandler QEI0_IRQHandler ADCSeq0_IRQHandler ADCSeq1_IRQHandler ADCSeq2_IRQHandler ADCSeq3_IRQHandler Watchdog_IRQHandler Timer0A_IRQHandler Timer0B_IRQHandler Timer1A_IRQHandler Timer1B_IRQHandler Timer2A_IRQHandler Timer2B_IRQHandler Comp0_IRQHandler Comp1_IRQHandler Comp2_IRQHandler SysCtrl_IRQHandler FlashCtrl_IRQHandler GPIOPortF_IRQHandler GPIOPortG_IRQHandler GPIOPortH_IRQHandler USART2_IRQHandler SSI1_IRQHandler Timer3A_IRQHandler Timer3B_IRQHandler I2C1_IRQHandler QEI1_IRQHandler CAN0_IRQHandler CAN1_IRQHandler CAN2_IRQHandler Ethernet_IRQHandler Hibernate_IRQHandler USB0_IRQHandler PWMGen3_IRQHandler uDMAST_IRQHandler uDMAError_IRQHandler ADC1Seq0_IRQHandler ADC1Seq1_IRQHandler ADC1Seq2_IRQHandler ADC1Seq3_IRQHandler I2S0_IRQHandler EBI0_IRQHandler GPIOPortJ_IRQHandler Default_Handler __default_handler CALL_GRAPH_ROOT __default_handler, "interrupt" NOCALL __default_handler B __default_handler CFI EndBlock cfiBlock0 END
Are you sure about the vector number?
I found GPIO J uses vector 67 (TM4C1294NCPDT).
I don't know what to say.. I double checked the table order and it turned out my handler was pointing to the wrong exception. After fixing it, it finally worked.
I went through all this trouble just because I didn't double check everything. Lesson learned I think. This seems to be a silly problem, but at least I learned more about startup files and disassembly because of this
Thanks to you and Bill.
Cheers
Ah. Thanks for the update!Yeah, all the memory dumps I asked for looked correct (maybe the technique will come in handy again sometime.)I was just getting around to "Wait, does the Tiva-C Launchpad even HAVE a Port J? Isn't that a TM4C123GH6PM that has vectors at 0x118 as "reserved"", and trying to figure our whether my documentation was up to date...
There are some other TM4C chips (TM4C123GH6PGE) with a PortJ vector at 118, but they're not (AFAIK) on Launchpads...
BTW, my main theory for the possibly-corrupt vector table was that somehow you had added your new vectors, but the compiler was still including the default vector table from "somewhere else", resulting in your vectors getting appended rather than located at 0...