This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C123GH6PM: ISR is called only once

Part Number: TM4C123GH6PM


Hi,

I was trying to write some assembly code for TM4123GXl TIVA C kit. I wrote simply assembly program in Keil MDK5.  Following is the program flow and configuration:

GPIOF.0 as input (Push Button -2 on board)

GPIOF.1 as out (onboard Red LED)

What program does: toggle LED on each button (SW2) press.

How Program Responds: Upon each button press, An interrupt is generated for GPIOF.0, In the ISR the led bit is checked and toggled.

Whats the problem: ISR is called only once. subsequect button press doesn't trigger the ISR.

Following is the complete code:

;
;	@description: Turn ON RED LED on Tivs-C TM4C123GXL Launchpad
;				  upon SW2 press


; clock / bus control registers
RCGC2GPIO_REG               EQU	        0x400FE108
GPIOHBCTL_REG               EQU	        0x400FE06C

;NVIC Registers
NVIC_EN0_REG                EQU         0xE000E100
	
; gpio registers
GPIOFDIR_APB_REG            EQU	        0x40025400
GPIOFDEN_APB_REG            EQU	        0x4002551C
GPIOFDATA_APB_REG           EQU	        0x4002500C
GPIOFLOCK_APB_REG           EQU	        0x40025520
GPIOFCR_APB_REG	            EQU	        0x40025524
GPIOFPUR_APB_REG            EQU	        0x40025510
GPIOFPDR_APB_REG            EQU	        0x40025514
    
GPIOIS_APB_REG              EQU         0x40025404
GPIOIBE_APB_REG             EQU         0x40025408
GPIOIEV_APB_REG             EQU         0x4002540C
GPIOIM_APB_REG              EQU         0x40025410
GPIOICR_APB_REG             EQU         0x4002541C    


; register values
GPIO_UNLOCK_VAL	            EQU	        0x4C4F434B
GPIOF_NVIC_BIT              EQU         0x40000000
DELAY_VALUE	                EQU	        500000

                AREA 	|.text|, CODE, READONLY, ALIGN=2
                THUMB
                ENTRY
                EXPORT Main

Main
				
                BL		__gpio_init
              
                BL		__config_interrupt
                
                B       .


__config_interrupt
                
				; enable edge detection on PF.0
                LDR	    R1,	    =GPIOIS_APB_REG
                LDR	    R0,	    [R1]
                AND	    R0,     R0,     #0x3E  ; clear bit-0
                STR     R0,	    [R1]
                
				; Interrupt generation is controlled by GPIOIEV reg
                LDR	    R1,	    =GPIOIBE_APB_REG
                LDR	    R0,	    [R1]
                AND	    R0,     R0,     #0x3E  ; clear bit-0
                STR     R0,	    [R1]
                
                
				; falling edge (button pressed) generate interrupt
                LDR	    R1,	    =GPIOIEV_APB_REG
                LDR	    R0,	    [R1]
                AND	    R0,     R0,     #0x3E  ; clear bit-0
                STR     R0,	    [R1]

				; enable interrupt for PF.0
                LDR	    R1,	    =GPIOIM_APB_REG
                LDR	    R0,	    [R1]
                ORR	    R0,     R0,     #0x01  ; set bit-0
                STR     R0,	    [R1]

                ; enable GPIO-F interrupt at NVIC side
                ; assuming the core in previllaged mode
                LDR	    R1,	    =NVIC_EN0_REG
                LDR	    R0,	    =GPIOF_NVIC_BIT
                STR     R0,	    [R1]

                BX      LR
                

                
                
__gpio_init	
				; use APB bus for GPIOF
                LDR	    R1,	    =GPIOHBCTL_REG
				LDR	    R0,	    [R1]
				AND	    R0,     R0,     #0x1F  ; clear bit-5
				STR	    R0,	    [R1]
				
                ; enable clock to GPIO-F
                LDR     R1,     =RCGC2GPIO_REG
                LDR	    R0,	    [R1] 
                ORR	    R0,     R0,     #0x20
                STR	    R0,	    [R1]
				
				
                ; unlock GPIOCR Register for write access
                LDR	    R1,	    =GPIOFLOCK_APB_REG
                LDR	    R0,	    =GPIO_UNLOCK_VAL
                STR	    R0,	    [R1]
				
                ; unlock GPIOAFSEL, GPIOPUR, GPIOPDR, and GPIODEN for PF.0-1
                LDR	    R1,     =GPIOFCR_APB_REG
                LDR	    R0,	    [R1]
                ORR	    R0,     R0,     #0x03
                STR	    R0,	    [R1]
				
                ; set PF.0 as input, PF.1 direction as output
                LDR	    R1,	    =GPIOFDIR_APB_REG
                MOV	    R0,	    #0x02
                STR	    R0,	    [R1]

                ; pull up PF.0
                LDR	    R1,     =GPIOFPUR_APB_REG
                LDR	    R0,	    [R1]
                ORR	    R0,     R0,     #0x01
                STR	    R0,	    [R1]				
			

                ; enable digital functionality for PF.0-1
                LDR	    R1,	    =GPIOFDEN_APB_REG
                MOV	    R0,	    #0x03
                STR	    R0,	    [R1]

                BX      LR

                ALIGN 
            
            
                AREA    |.text|, CODE, READONLY
    
GPIOF_Handler   PROC
                EXPORT GPIOF_Handler                
                ; assuming we are only expecting PF.0 interrupt from GPIO-F
                ; in case of multiple interrupts on, a check is required 
                ; to see which interrupt event has occured 
                
                ; clear the interrupt
                LDR	    R1,	    =GPIOICR_APB_REG
				LDR	    R0,	    [R1]
				ORR	    R0,     R0,     #0x1 ; set bit-0
				STR	    R0,	    [R1]

                ; disable the further ISR (prevent interrupt re-enterent)
                LDR	    R1,	    =GPIOIM_APB_REG
                LDR	    R0,	    [R1]
                AND	    R0,     R0,     #0x3E  ; set bit-0
                STR     R0,	    [R1]


				; read data register value for PF.1
                LDR		R1,		=GPIOFDATA_APB_REG                
				LDR		R0, 	[R1]				
				AND		R0, 	R0,		#0x2				
				CMP 	R0, 	#0x2				
				BNE		LED_ON

				; turn OFF LED
				AND 	R0,		R0,		#0x01
				STR		R0, 	[R1]
                B       INT_ENABLE
								
LED_ON			
				; turn ON LED
				ORR		R0, 	R0, 	#0x02				
				STR		R0, 	[R1]
                
                                
				
INT_ENABLE      
                ; re-enable interrupt for PF.0
                LDR	    R1,	    =GPIOIM_APB_REG
                LDR	    R0,	    [R1]
                ORR	    R0,     R0,     #0x01  ; set bit-0
                STR     R0,	    [R1]

                
                ENDP


                END

  • kowalski said:
    Whats the problem: ISR is called only once.    Subsequent button press doesn't trigger the ISR.

    I was going to 'Yell at you' for (missing) the fact that PF0 is a 'devil pin' - and requires 'special handling.'      (and then blame that MISS - on your use of the HIGHLY Demanding - 'ASM!')   Yet - you recognized that need - and provided the necessary Unlock - good that!

    Kindly advise -  (this) code block:

    ; disable the further ISR (prevent interrupt re-enterent)
    LDR R1, =GPIOIM_APB_REG
    LDR R0, [R1]
    AND R0, R0, #0x3E ; set bit-0       Is it not  'unlikely'  - that the 'AND' Operator (in accord w/#0x3E)  will 'SET' bit_0?
    STR R0, [R1]

    You intended that  this code block, 'Prevent Re-Entrance to the ISR!'      (thus - this should have been a (very first) place to look!)

    Note too - assuming yours is an LPad - those board switches will BOUNCE - and your code (ideally) will 'WAIT until Signal has Settled' - and then (carefully) manage the 'further bounces' which follow 'Switch Release!'  

    Is it not likely that you have (unexpectedly)  ''Remained and/or Returned w/in the ISR'  - and thus cannot,  'Trigger  that (the PF0 ISR) which (awaits) further (or more proper) clearance?'    (so that it may - in fact - enable and/or Respond -  to a  NEW Trigger!)

  • Thanks @Guru. I checked the code in debugger and verified:

    ; disable the further ISR (prevent interrupt re-enterent)
    LDR R1, =GPIOIM_APB_REG
    LDR R0, [R1]
    AND R0, R0, #0x3E ; set bit-0 VERIFIED
    STR R0, [R1]


    I modified my program to

    1. disable PF.0 Interrupt at the start of ISR
    2. perform ISR Operation
    3. Generate a dummy delay
    4. at the last clear the PF.0 interrupt (flag is already set so bounce will just over write it.)
    5. In Main program after some DELAY (to account for button bounce effect) enable PF.0 Interrupt,....

    Yet the program still doesn't trigger the ISR. Another interesting/weird/Strange behavior is after ISR, the program loopback to Reset_Handler.

    New ISR:

    GPIOF_Handler PROC
    EXPORT GPIOF_Handler
    ; assuming we are only expecting PF.0 interrupt from GPIO-F
    ; in case of multiple interrupts on, a check is required
    ; to see which interrupt event has occured


    ; disable the further ISR (prevent interrupt re-enterent)
    LDR R1, =GPIOIM_APB_REG
    LDR R0, [R1]
    AND R0, R0, #0x3E ; set bit-0
    STR R0, [R1]


    ; read data register value for PF.1
    LDR R1, =GPIOFDATA_APB_REG
    LDR R0, [R1]
    AND R0, R0, #0x2
    CMP R0, #0x2
    BNE LED_ON

    ; turn OFF LED
    AND R0, R0, #0x01
    STR R0, [R1]

    B debouce_delay

    LED_ON
    ; turn ON LED
    ORR R0, R0, #0x02
    STR R0, [R1]

    debouce_delay
    LDR R2, =DELAY_VALUE
    delay SUB R2, R2, #0x1
    CMP R2, #0
    BNE delay

    ; clear the interrupt at the END
    LDR R1, =GPIOICR_APB_REG
    LDR R0, [R1]
    ORR R0, R0, #0x1 ; set bit-0
    STR R0, [R1]

    ENDP
  • Thank you - however, 'I'm at a loss to explain how your code line:'

    AND R0, R0, #0x3E ; set bit-0 VERIFIED    

    has been 'first'  (believed) - and later (verified) - to 'SET bit_0.'      By  'Set' - do you mean the creation of a, 'logic high or '1'?     (Is it not the 'OR' Operator - which (more) normally - achieves such 'bit-setting?')

    Can you detail your thinking (in this Bit Setting) - especially your 'Verification' - before we 'dig (even) deeper?'

    Your 1st post notes that you, 'Checked your code - In the Keil Debugger.'     Is it (both) 'legal' - and 'without unanticipated effects' - that your  'Debug method of checking'  proves proper & correct?    Some MCU Registers prove 'Read Sensitive' - and having them, 'OPEN w/in the Debugger' - is a 'known cause' of  (similar) error!     (it is usual that such Registers are 'noted as such' (sensitive) - w/in the MCU manual.)

    And of course - for a (near) instant - and vastly more efficient 'SOLUTION' - use of the vendor's API would (surely) 'Speed, Ease & Enhance' your achievement of, 'Correctly Behaved Interrupts & their handling.'

  • Dear Guru,

    Thanks for your reply. Following are my points.

    1. "Can you detail your thinking (in this Bit Setting) - especially your 'Verification' - before we 'dig (even) deeper?'"
    Ans:
    LDR R1, =GPIOIM_APB_REG
    a. first load address of GPIOIM register into R1

    LDR R0, [R1]
    b. Load GPIOIM register value into R0 . Lets say R0 now is equal to 0x03 (PF.0, PF.1 interrupts are enabled)

    AND R0, R0, #0x3E ; set bit-0 VERIFIED
    c. Now just to clear bit-0 only of GPIOIM register, i performed bitwise AND operation. i.e. R0 & 0x3E => 0x03 & 0x3E ==> 00 0011 & 11 1110 => 0x2

    STR R0, [R1]
    d. finally store value into GPIOIM


    2. The GPIOIM register is not read sensitive as per launchpad datasheet. Its bits must be set clear explicitly by a write operation.

    I will check all the code once again while focusing on points you mentioned and will get back here.

  • Thank you - your provided detail (both) helpful & appreciated.

    Would it not prove 'more understandable' - thus effective - to place the 'ASM comment'  (i.e. set bit_0) one code line lower?

    (i.e. Upon the line which lists:   STR R0, [R1]   thus   STR R0, [R1] ;  set bit_0 )      It is noted that we 'agree' - that the 'And Operator- is capable of  'Bit-Clearing, only.'

    Here are further suggestions - which attempt to, 'Better comply w/'KISS' - surely to aid your efforts:

    • as pin 'PF0' IS a 'devil pin' - let's (at least temporarily) replace it with a (normal) GPIO
    • have you 'scoped' PF0?     Both during 'Switch Inactive' (PF0 should prove 'pulled-high') & during 'Switch Active' (PF0 should 'bounce' - then (settle) at/around  Gnd.
    • several such scope-caps should 'advise & inform' the necessary delay required - to insure that the 'Port Read' is achieved - when PF0's input has stabilized.    (you've not described 'how' your present delays were determined)
    • to simplify (another KISS compliant method) replace that "bouncy switch" with a GPIO Output - set to 'Open Drain' - and then driven active.   No bounce will be encountered - and you should be able to note the 'exact moment of 'Entry to the ISR.'    (especially if you toggle (another) bit as the 1st ISR code instruction)
    • as your code (properly) recognizes & responds to the GPIO Interrupt (ONCE) - yet 'never again' - does that not  suggest TWO POTENTIAL ISSUES:
      • the interrupt set-up code is somehow altered - in the process of  ISR recognition & response
      • the ISR is 'improperly' or not 'fully cleared' - thus any 'return to the ISR'  (i.e. 2nd visit) is prevented
    • should this method (still) fail to meet expectations - your use of the (apparently dreaded) 'API'  should quickly/easily resolve!    You may then observe the (proper) Register Settings - and compare those with the ones resulting from the (thus far) failing - ASM.

    May it be noted that the (simple) Set-Up & Programming of a GPIO-based interrupt - benefits little (i.e. almost  Zero)  thru the employ of  ASM.    (Neither 'Speed of Execution' nor 'Code Bloat' - proves 'in play' here.)

    Does the market not:

    • 'Belong to the SWIFT
    • those first Arriving 
    • who prove best able to exploit such 'Rarefied Air' and, 'Maximize Profits'

    And (unfortunately)  the 'Non-Strategic' use of  'ASM'  (insures)  that ASM advocates will rarely (i.e. never) be among those (profit maximizing)  'Early Arrivals!'

  • Dear


    After hours of digging the code, i couldn't find anything that could possible be responsible for the problem... So what i did was a little reverse engineering. I wrote the same code using CMSIS register definitions. The program behaved as expected. So i compiled the C-file into .s (assembly) file and reversed engineered what is happening inside the program. AND Guess what i found the bug... Oh man i was missing one instruction at the end of GPIOF_Handler ISR i.e.

    BX LR

    Off course we have to get back to the calling point from ISR. And this was a reason why after ISR handling the program was jumping to Reset_Handler. After adding this instruction, everything works like a charm though the button bounce effect still exist causing LED to toggle multiple times (obviously). :-)

    Thanks
  • Bravo - how nice of you to 'Close the Loop' - and you (may) note - that I did suggest employing the API (written entirely in 'C') - and then scrutinizing the 'generated ASM code' - seeking (any/all) program or Register 'deltas.'     AND - one of my 'suspected' items (listed) was the FAILURE of the ASM Code to 'properly CLEAR the ISR - and that WAS your Issue - was it not?     (meaning TWO Green Pennants should wave)

    However - does not my (caution) Re: 'TURTLE HERD - in a HURRY - flashing their  HI-BEAMS'  at  'Your (pardon) 'slow moving (ASM) vehicle'  (which should NEVER enter the FAST Lane)  remain?

    Note: our 'Turtle liaison' reported their (successful) programming: 

    • 4x4 matrix keypad
    • 5 'softkeys'  resident just beneath a graphic OLED
    • and five - 5x7 (dot matrix) multi-color LEDs

    in a (highly) similar time-frame!       That 'speaks to something' does it not?      (Reality - proves not always - kind & pleasant...)

  • Thanks ... you indeed suggested these points... many thanks dear.