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: GPIO Interrupt Not happening if controller resetted during ISR Execution

Part Number: TM4C123GH6PM

I was debugging my code and restarted the code while ISR was being serviced. After reset though, the Interrupt stopped getting detected.

The problem doesn't occur if I restart my code any where in the program but happens if I reset it in the ISR.

Note: I am clearing my Interrupt at the very start of ISR.

Is this normal or is there a way to fix this problem?

My Code:

/*!
 * @author      Yash Bansod
 * @date        19th September 2017
 *
 * @brief       PWM Servo
 * @details     The program controls the position of an external servo motor by
 *              varying the Duty Cycle of the PWM. The Duty Cycle can be increased by
 *              clicking the onboard switch SW2(PF0) or decreased by clicking SW1(PF4).
 *              The PWM module .
 * @note        The tm4c123ghpm_startup_ccs.c contains the vector table for the
 *              microcontroller. It was modified to execute the specified ISR on
 *              Timer0A and PortF Interrupts.
 */
/* -----------------------          Include Files       --------------------- */
#include <stdint.h>                         // Library of Standard Integer Types
#include <stdbool.h>                        // Library of Standard Boolean Types
#include "inc/tm4c123gh6pm.h"               // Definitions for interrupt and register assignments on Tiva C
#include "inc/hw_memmap.h"                  // Macros defining the memory map of the Tiva C Series device
#include "inc/hw_types.h"                   // Defines common types and macros
#include "inc/hw_gpio.h"                    // Defines Macros for GPIO hardware
#include "inc/hw_pwm.h"                     // Defines and Macros for Pulse Width Modulation (PWM) ports
#include "driverlib/debug.h"                // Macros for assisting debug of the driver library
#include "driverlib/pwm.h"                  // API function prototypes for PWM ports
#include "driverlib/sysctl.h"               // Defines and macros for System Control API of DriverLib
#include "driverlib/interrupt.h"            // Defines and macros for NVIC Controller API of DriverLib
#include "driverlib/gpio.h"                 // Defines and macros for GPIO API of DriverLib
#include "driverlib/pin_map.h"              // Mapping of peripherals to pins for all parts
#include "driverlib/rom.h"                  // Defines and macros for ROM API of driverLib

#define PWM_FREQUENCY 50                    // Define a macro for the frequency of the PWM signal in Hz

/* -----------------------      Global Variables        --------------------- */
uint32_t ui32Period;                        // Variable to store PWM time period
volatile uint8_t ui8Adjust = 75;            // Variable to store Duty Cycle of LED

/* -----------------------      Function Prototypes     --------------------- */
void PortFIntHandler(void);                 // Prototype for ISR of GPIO PortF

/* -----------------------          Main Program        --------------------- */
int main(void){
    // Set the System clock to 80MHz and the PWM Module clock to 1.25 MHz
    ROM_SysCtlClockSet(SYSCTL_SYSDIV_2_5 |SYSCTL_USE_PLL |SYSCTL_OSC_MAIN |SYSCTL_XTAL_16MHZ);
    ROM_SysCtlPWMClockSet(SYSCTL_PWMDIV_64);

    // Enable the clock for peripherals PortF and PortD and PWM1
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM1);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

    // Configure the PD0 for PWM signal (PWM module 1 generator 0)
    ROM_GPIOPinTypePWM(GPIO_PORTD_BASE, GPIO_PIN_0);
    ROM_GPIOPinConfigure(GPIO_PD0_M1PWM0);

    // Remove the Lock present on Switch SW2 (connected to PF0) and commit the change
    HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
    HWREG(GPIO_PORTF_BASE + GPIO_O_CR) |= GPIO_PIN_0;
    HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = 0;

    // Set the PF0, PF4 as Input and configure them to be Pulled-up
    ROM_GPIODirModeSet(GPIO_PORTF_BASE, GPIO_PIN_4|GPIO_PIN_0, GPIO_DIR_MODE_IN);
    ROM_GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_4 | GPIO_PIN_0, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);

    // Configure and enable the Interrupt for PF0 and PF4
    ROM_IntEnable(INT_GPIOF);
    ROM_GPIOIntTypeSet(GPIO_PORTF_BASE, GPIO_PIN_4 | GPIO_PIN_0, GPIO_FALLING_EDGE);
    GPIOIntEnable(GPIO_PORTF_BASE, GPIO_INT_PIN_0 | GPIO_INT_PIN_4);
    // Master interrupt enable API for all interrupts
    ROM_IntMasterEnable();

    // Calculate the Timer period of the PWM Module.
    uint32_t ui32PWMClock = SysCtlClockGet() / 64;
    ui32Period = (ui32PWMClock / PWM_FREQUENCY) - 1;
    // Configure thE PWM1 Genrator0 to work in Count Down Mode
    ROM_PWMGenConfigure(PWM1_BASE, PWM_GEN_0, PWM_GEN_MODE_DOWN);
    // Load the calculated time period to the Generator0 of the PWM1 Module
    ROM_PWMGenPeriodSet(PWM1_BASE, PWM_GEN_0, ui32Period);

    // Set the PWM duty cycle to a specified value
    ROM_PWMPulseWidthSet(PWM1_BASE, PWM_OUT_0, ui8Adjust * ui32Period / 1000);
    // Enable the PWM0 pin of the PWM Module 1 as output
    ROM_PWMOutputState(PWM1_BASE, PWM_OUT_0_BIT, true);
    // Enable the PWM Generator
    ROM_PWMGenEnable(PWM1_BASE, PWM_GEN_0);

    while (1);
}

/* -----------------------      Function Definition     --------------------- */
void PortFIntHandler(void){
    // The ISR for GPIO PortF Interrupt Handling
    GPIOIntClear(GPIO_PORTF_BASE , GPIO_INT_PIN_4 | GPIO_INT_PIN_0);

    // If SW1(PF4) is pressed then reduce the duty cycle
    if(ROM_GPIOPinRead(GPIO_PORTF_BASE, GPIO_PIN_4 | GPIO_PIN_0)== GPIO_PIN_0){
        ui8Adjust--;
        if (ui8Adjust < 50){
            ui8Adjust = 50;
        }
        ROM_PWMPulseWidthSet(PWM1_BASE, PWM_OUT_0, ui8Adjust * ui32Period / 1000);
    }
    // If SW2(PW0) is pressed then increase the duty cycle
    if(ROM_GPIOPinRead(GPIO_PORTF_BASE, GPIO_PIN_4 | GPIO_PIN_0)== GPIO_PIN_4){
        ui8Adjust++;
        if (ui8Adjust > 100){
            ui8Adjust = 100;
        }
        ROM_PWMPulseWidthSet(PWM1_BASE, PWM_OUT_0, ui8Adjust * ui32Period / 1000);
    }
}

  • Yash,
    Are you using CCS?
    When you say "restarted the code", did you click on that button with a "loop arrow" on the debuggers control interface?
    My experience is that restarting the code during debugging causes trouble - or at least, uncertainty - and should be avoided. I wouldn't call it a "problem" as you said, because there is certainly other ways to debug your code without frequently restarting it. Let's see what other folks comment about this being something expected or not, but "leaving with it" is probably fine...
    Regards
    Bruno
  • Well described & well presented post - good job.   (imho)

    May we ask:

    • your description of "just how" you "Reset the MCU?"
    • your description of "how you verified" that such Reset occurred (during/within) the ISR?

  • Hi Bruno,
    Thanks for the inputs. "Restart" is not really a reset. It does not set the PC to 0x0 but rather directly to the entry point. This is normally the _c_int00. No part of the MCU hardware is reset. It may have something to do with the restart does not clear the interrupt flags before the PC is moved to the entry point that renders the subsequent interrupt not being properly recognized to the CPU. Normally I don't use restart. I just click the system reset.
  • Yes I am using CCS7
    Yes I mean the loop arrow on the debuggers control interface
  • I did not reset the MCU with the reset button. I meant, "restart the code" while ISR was being serviced.
    Also for the description of how I restarted the code while it was in ISR: well I put a breakpoint on the line 94 and when the program stopped there on me pressing the button, I clicked the restart code button.
    I called it reset as I thought that was what was happening when I pressed restart. Now I know I was wrong.
  • Alright, we know know almost all these missing details! Just pending is cb1's question of "how are you sure it reset"? Did you set a breakpoint somewhere close to the SysCtlClockSet line, is it?

    Still, as Charles pointed out, that arrow doesn't do much, and it is not really a serious reset. I guess that the basic answer is: don't rely on that for your debugging.

    Charles, by "just click the system reset", do you mean some hidden command on the CCS interface? Or the physical reset button on a board? Of course, that second option messes up the ongoing debugger even further, right?

  • Hello charles,
    I don't think this was the issue of the interrupt flag not being cleared. As I mentioned, even if I restart my code after the GPIOIntClear() has been processed but the PC is still in ISR the problem persists.
    I also tried adding GPIOIntClear() API just after enabling the Interrupt for GPIO (After line 64) but still my interrupt won't work. I am skeptical that this is a problem and my interrupts may not get serviced if reset happens while ISR is being serviced.
    I would like to know a way to make sure that this isn't a problem.
  • Hi Bruno,
    I meant by clicking the system reset under Run->System Reset will reset the device. Yes, this will reset the device and the debug will start all over. Sometimes I use the Core reset under Run->Core Reset. I believe this will only move the PC to the 0x0 without resetting the device.
  • No, I set the breakpoint at line 94 (in the ISR) to halt the program if it enters the ISR.
    I have no way of knowing what happens if my controller is resetted while ISR is being processed.
    Nevertheless, I want to know what I am doing wrong that is causing this problem. Even if restart is just causing the PC to jump to the start point, clearing the interrupt flag just after I enable interrupts to a peripheral should solve the problem right?
    Also, If I restart after the flag clear has happened in ISR why does the problem still persist.
    Note: the problem doesn't happen if I restart the code any where else (in the main).
  • Yash,
    What I mean is: there is no problem here, as in "There is no risk that your final product will not enter the ISR after reset, when a hard reset happens exactly while the program was serving that ISR before".
    It may just be some program pointer mess up caused by the restart function executed by CCS during debug.
    But if you want to double check, here is a simple idea: do again your "restart within the ISR", and let the program run. It will then be running the while(1) loop, right? Press and release your push button. Maybe you are not getting an interrupt, and code will never enter the ISR - but pause the execution anyway, and look at the GPIO interrupt registers, let us know if that particular interrupt flag is set. We can then take from there.
    Bruno
  • Thank you this solved my problem. I tried the system and core reset while my ISR was being processed and the interrupts are still working. Thank you.
  • Hi Yash,
    Do you have the compiler optimization on? Would you mind try one thing? Turn off the optimization and try again and see if it makes a difference. Sometimes with the optimization ON, the breakpoint you place in the C window may not correspond to the actual assembly code.
  • Hi Yash,
    If you are satisfied with using system/core reset for your debug then it is up to you to try experimenting with the compiler optimization.
  • I do not have my compiler optimizations on. I am debugging in debug mode and all optimizations are off. Anyway thanks a lot for the support, the problem was happening only If i restart the code, it doesn't happen if I reset the code.
  • Thanks, I tried it with the release mode and it too is working after reset.