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.

MSP432P401R using PMAP and Timer_A1 for "button pressed" detection

Hey Guys,

I am trying to implement a "button pressed" detection via PMAP and Timer_A1 but the Timer_a1 doesn't jump in the appropriate ISR, in fact doesn't realize there's an interrupt at all, so I wanted to ask, if somebody sees my fault here:

I have a button connected to P2.6. when I am pushing the button it grounds P2.6. So I first configured P2.6 as a Input with Pull Up. When I now push the button the processor jumps in the appropriate ISR of the PORT2_IRQHandler. In the ISR I remap P2.6 to service CCI1A for Timer_A1, so that when I release the button a CC interrupt is generated when P2.6 goes high again. Maybe there is the problem: When I remap P2.6 to serve as CCI1A  I also reconfigure the Port as an input with primary periphral module function (driverLib API). Is it possible, that the Pull Up is therefore disabled, so that there will not be a transistion from GND to Vcc?

Here are my Timer_A1 configuration structs and the ISrs:

/* Timer_A1 for BUTTON0_MSP432 detection */
const Timer_A_ContinuousModeConfig TimerButton0ConConfig =
{
		TIMER_A_CLOCKSOURCE_ACLK,           // ACLK Clock Source
        TIMER_A_CLOCKSOURCE_DIVIDER_2,       // ACLK/2 = 16,384kHz
        TIMER_A_TAIE_INTERRUPT_DISABLE,      // Disable Timer ISR
        TIMER_A_SKIP_CLEAR                   // Skup Clear Counter
};

const Timer_A_CaptureModeConfig TimerButton0CapConfig =
{
		TIMER_A_CAPTURECOMPARE_REGISTER_1,		// Using CCI1A
		TIMER_A_CAPTUREMODE_RISING_EDGE,		// rising edge selection
		TIMER_A_CAPTURE_INPUTSELECT_CCIxA,		// CCI1A select
		TIMER_A_CAPTURE_SYNCHRONOUS,				// no race condiction possible
		TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE,	// enable interupt
		TIMER_A_OUTPUTMODE_OUTBITVALUE            // Output bit value
};

ISRs:

/**
 * \brief	PORT2 ISR
 * \author 	Benjamin Brammer
 * \date   	15.07.16
 *
 * This interrupt is triggered if BUTTON0_MSP432 or
 * BUTTON1_MSP432 is pressed. It either starts the button-pressed
 * detection routine via Timer_A1 or just sets an event marker.
 */

void PORT2_IRQHandler(void)
{
    uint32_t status;

    status = MAP_GPIO_getEnabledInterruptStatus(GPIO_PORT_P2);
    MAP_GPIO_clearInterruptFlag(GPIO_PORT_P2, status);

    if(status & GPIO_PIN6)
    {
    	PMAP_configurePorts((const uint8_t *) port_mapping2, PMAP_P2MAP, 1,
    			PMAP_ENABLE_RECONFIGURATION);
    	GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P2,
    	            GPIO_PIN6, GPIO_PRIMARY_MODULE_FUNCTION);
    	Timer_A_enableCaptureCompareInterrupt(TIMER_A1_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_1);
    	Interrupt_enableInterrupt(INT_TA1_N);
    	Timer_A_startCounter(TIMER_A1_BASE, TIMER_A_CONTINUOUS_MODE);
    }
    //GPIO_disableInterrupt(GPIO_PORT_P2, GPIO_PIN6 |
		//	GPIO_PIN7);

}


/**
 * \brief	Timer_A1_CapComp ISR
 * \author 	Benjamin Brammer
 * \date   	27.07.16
 *
 * This interrupt checks if a correct button press has
 * been detected. Therfore if the button is released this ISR
 * is triggered and compares the CCIA1 Value with the expected value
 * for 1 second pressing. If a true press has been detected, the
 * apropriate routine is executed, depending on the measurement state.
 *
 */

void TA1_N_IRQHandler(void)
{
	uint_fast16_t timerAcaptureValue;

    Timer_A_clearCaptureCompareInterrupt(TIMER_A1_BASE,
            TIMER_A_CAPTURECOMPARE_REGISTER_1);

    timerAcaptureValue = Timer_A_getCaptureCompareCount(TIMER_A1_BASE,
                TIMER_A_CAPTURECOMPARE_REGISTER_1);

    if (measureState == IDLE && (timerAcaptureValue >= BUTTON_PRESS_COUNT))
    {
      measureState = INIT;
      BOARD_LED_MEASURE_START_ON;
      Timer_A_stopTimer(TIMER_A1_BASE);
    }
    else if (measureState == ACTIVE && (timerAcaptureValue >= BUTTON_PRESS_COUNT))
    {
    	measureState = FINISH;
    }


    /* remaping P2.6 as an GPIO Input for BUTTON0_MSP432 press detection */
    PMAP_configurePorts((const uint8_t *) port_mapping3, PMAP_P2MAP, 1,
        			PMAP_ENABLE_RECONFIGURATION);
    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P2, GPIO_PIN6 |
    			GPIO_PIN7);

}

best regards

Benni

  • I tried my code with the default mapping, and it worked absolutely fine. So there seems to be something wrong with the mapping..
  • Benjamin,

    If you reconfigure the port to be used as Timer Input, the settings you used for the GPIO configuration would be written over. If your objective is to time how long a button is pressed, then you may have better results by starting/stopping the timer within the GPIO ISR.  Psuedo code would be something similar to following:

    bool PressedFlag = false
    
    GPIO_P2 ISR ()
    
    {
    
     if (PressedFlag)
    
     {
    
        //Handle button being released
    
        StopTimer
    
         Read CCR Register to get time
    
        Change GPIO Interrupt Edge to Rising
    
        PressedFlag = false
    
     }
    
     else
    
     {
    
         //Handle Button being pressed
    
        Clear Timer CCR
    
         Start Timer
    
         Change  GPIO Interrupt Edge to Falling
    
         PressedFlag = True
    
      }
    }

    Of course, this pseudo code doesn't take into account button debounce.You will have to decide how to handle that in your application, but another timer running could serve that purpose (or same time base different CCR).

    If you just want to know when a button is released, then just change the GPIO interrupt to a rising edge after your debounce period.

  • Hello JH,

    thanks for your reply. Actually I checked the GPIO configuration after I reconfigured P2.6 for Timer usage, but everything stays like prior initialized (REN, DIR and so on). So far the routine works well, although I think that using the API for checking If the right CCIFG has been set, takes quite a while (I updated a lot in the code). maybe I will use the CMSIS notation to check that.

    Debouncing the button seems to be no problem since the first interrupt is triggered as an GPIO interrupt on a falling edge. After that I reconfigure the port as a Timerr CCInput on rising edge (now with the default port mapping). So when it is first triggered, even if there is a debounce, it doesn't trigger a second interrupt since the Port is now a CC input. So far it works really good, but I will keep testing it, to be sure I don't need a seperate debunce routine.

    Here is my routine so far:

    /**
     * \brief	PORT2 ISR
     * \author 	Benjamin Brammer
     * \date   	15.07.16
     *
     * This interrupt is triggered if BUTTON0_MSP432 or
     * BUTTON1_MSP432 is pressed. It either starts the button-pressed
     * detection routine via Timer_A1 or just sets an event marker.
     * IMPORTANT!! pressing BUTTON0_MSP432 and BUTTON1_MSP432 simultaneously
     * will result in erroneous behaviour since in both cases Timer_A0 is used
     * to debounce button pressing!
     *
     */
    
    void PORT2_IRQHandler(void)
    {
        uint32_t status;
    
        status = MAP_GPIO_getEnabledInterruptStatus(GPIO_PORT_P2);
        MAP_GPIO_clearInterruptFlag(GPIO_PORT_P2, status);
    
        if(status & GPIO_PIN6)
        {
        	/* seting up TA0_CCI3A */
        	GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P2,
        	            GPIO_PIN6, GPIO_PRIMARY_MODULE_FUNCTION);
    
        	/* configuring TimerA0 as BUTTON0_MSP432 detection timer */
    		Timer_A_initCapture(TIMER_A0_BASE, &TimerButton0CapConfig);
        	Interrupt_enableInterrupt(INT_TA0_N);
        	Timer_A_startCounter(TIMER_A0_BASE, TIMER_A_CONTINUOUS_MODE);
        }
        else if(status & GPIO_PIN7)
        {
        	GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P2,
        	    	            GPIO_PIN7, GPIO_PRIMARY_MODULE_FUNCTION);
        	/* configuring TimerA0 as BUTTON0_MSP432 detection timer */
    		Timer_A_initCapture(TIMER_A0_BASE, &TimerButton1CapConfig);
    		Interrupt_enableInterrupt(INT_TA0_N);
    		Timer_A_startCounter(TIMER_A0_BASE, TIMER_A_CONTINUOUS_MODE);
    
        }
    
    }
    
    
    /**
     * \brief	Timer_A1_CapComp ISR
     * \author 	Benjamin Brammer
     * \date   	27.07.16
     *
     * This interrupt checks if a correct button press has
     * been detected. Therfore if the button is released this ISR
     * is triggered and compares the CCIA1 Value with the expected value
     * for 1 second pressing. If a true press has been detected, the
     * apropriate routine is executed, depending on the measurement state.
     *
     */
    
    void TA0_N_IRQHandler(void)
    {
    	uint_fast16_t timerAcaptureValue;
    
        if(TIMER_A_CAPTURECOMPARE_INTERRUPT_FLAG & Timer_A_getCaptureCompareInterruptStatus(TIMER_A0_BASE,
        		TIMER_A_CAPTURECOMPARE_REGISTER_3, TIMER_A_CAPTURECOMPARE_INTERRUPT_FLAG))
        {
        	timerAcaptureValue = Timer_A_getCaptureCompareCount(TIMER_A0_BASE,
        	                TIMER_A_CAPTURECOMPARE_REGISTER_3);
    
        	if (measureState == IDLE && (timerAcaptureValue >= BUTTON_PRESS_COUNT))
        	    {
        	      measureState = INIT;
        	      BOARD_LED_MEASURE_START_ON;
        	      Timer_A_stopTimer(TIMER_A0_BASE);
        	      Interrupt_disableInterrupt(INT_TA0_N);
        	    }
        	    else if (measureState == ACTIVE && (timerAcaptureValue >= BUTTON_PRESS_COUNT))
        	    {
        	    	BOARD_LED_MEASURE_STOP_ON;
        	    	measureState = FINISH;
        	    	Timer_A_stopTimer(TIMER_A0_BASE);
        	    	Interrupt_disableInterrupt(INT_TA0_N);
        	    }
        	    else if (measureState == FINISH && (timerAcaptureValue >= BUTTON_PRESS_COUNT))
        	    {
    
        	    }
        	Timer_A_clearCaptureCompareInterrupt(TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_3);
        }
        else if(TIMER_A_CAPTURECOMPARE_INTERRUPT_FLAG & Timer_A_getCaptureCompareInterruptStatus(TIMER_A0_BASE,
        		TIMER_A_CAPTURECOMPARE_REGISTER_4, TIMER_A_CAPTURECOMPARE_INTERRUPT_FLAG))
        {
    
        }
    
    
        /* remaping P2.6 as an GPIO Input for BUTTON0_MSP432 press detection */
        GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P2, GPIO_PIN6 |
        			GPIO_PIN7);
    }

    best regards

    Benni

  • OK. Right now I am really troubled!

    I tried to update my code and implementing a button debounce as long with a different approach on using the Timer for checking if a button has been pressed, but now the MSP432 behaves really strange: I didn't really change some basic ISR handling, just added new features, but now, when the PORT2 gets an interrupt from the falling edge and treis to check which of the enabled interrupt flags is set, it allways reads zero in my status variable. So as if there wasn't recognized which pin of PORT2 triggered the interrupt. Really strange. Also when I check the register values there sometimes seems to be no recognition of the initiated interrupt through P2.6.
    What dark sorcery is this? I will try to factory reset the MSP432 and try again. Here's my new code, maybee there is something wrong here, but i don't think so, since the MSP's behaviour isn't allways the same,..

    /**
     * \brief	PORT2 ISR
     * \author 	Benjamin Brammer
     * \date   	15.07.16
     *
     * This interrupt is triggered if BUTTON0_MSP432 or
     * BUTTON1_MSP432 is pressed. It either starts the button-pressed
     * detection routine via Timer_A0 or just sets an event marker.
     * IMPORTANT!! pressing BUTTON0_MSP432 and BUTTON1_MSP432 simultaneously
     * will result in erroneous behaviour since in both cases Timer_A0 is used
     * to debounce button pressing!
     *
     */
    
    void PORT2_IRQHandler(void)
    {
        uint_fast16_t status;
    
        status = GPIO_getEnabledInterruptStatus(GPIO_PORT_P2);
        GPIO_clearInterruptFlag(GPIO_PORT_P2, status);
    
    
        if((status & GPIO_PIN6) && !buttonPressed)
        {
        	button0 = true;
        	buttonPressed = true;
    
        	/* starting Timer_A0 for button pressed detection */
        	Timer_A_startCounter(TIMER_A0_BASE, TIMER_A_UP_MODE);
    
        }
        else if((status & GPIO_PIN7) && !buttonPressed)
        {
        	buttonPressed = true;
    
        	/* starting Timer_A0 for button pressed detection */
        	Timer_A_startCounter(TIMER_A0_BASE, TIMER_A_UP_MODE);
    
        }
    }

    and here the Timer ISR:

    /**
     * \brief	Timer_A0_CapComp ISR
     * \author 	Benjamin Brammer
     * \date   	27.07.16
     *
     * This interrupt checks if a correct button press has
     * been detected.
     *
     */
    
    void TA0_N_IRQHandler(void)
    {
    	/* halting the timer */
    	Timer_A_stopTimer(TIMER_A0_BASE);
    
    	if(button0)
    	{
    		if (measureState == IDLE && !GPIO_getInputPinValue(GPIO_PORT_P2
    		, GPIO_PIN6))
    			{
    			  measureState = INIT;
    			  BOARD_LED_MEASURE_START_ON;
    
    			}
    			else if (measureState == ACTIVE && !GPIO_getInputPinValue(GPIO_PORT_P2
    					, GPIO_PIN6))
    			{
    				BOARD_LED_MEASURE_STOP_ON;
    				measureState = FINISH;
    			}
    			else if (measureState == FINISH && !GPIO_getInputPinValue(GPIO_PORT_P2
    					, GPIO_PIN6))
    			{
    
    			}
    
    		buttonPressed = false;
    		button0 = false;
    
    	}
    	else if(!GPIO_getInputPinValue(GPIO_PORT_P2
    			, GPIO_PIN7))
    	{
    
    		buttonPressed = false;
    
    	}
    	
    	buttonPressed = false;
    }

  • very strange. I know tried a full evaluation after the factory reset. It seems there's something wrong with the API...

    When I press one of my buttons at P2.7 or 2.6 the appropriate interrupt is enabled and the programm jumps to the ISR, but i don't get the correct value from the GPIO_getEnabledInterruptStatus(GPIO_PORT_P2) API. It returns zero..what is basically impossible. I made two screenshots where you see the variable content of status and the register values of PORT2. And the registers show, that the MSP does recognize the correct interrupt, but the API doesn't handle the right data to the varibale..

    and here the regiters

  • when i use low level register programming it works fine. so there is obviously a problem with the API
  • Ben,

    Which version of the MSP432 Launchpad are you using? The black board or the red one? Your issue with the API not functioning properly makes me think of the CMSIS update that was done to the APIs. Basically, if you have the older board, the newer APIs won't function properly. If you still use the APIs that are located in ROM though, you should be fine no matter what version of the board you use. Please see the following Twiki page for information on this and potential workarounds.

    processors.wiki.ti.com/.../MSP432_CMSIS_Update
  • Hey JH,

    thanks for your fast reply. I am not using the Launchpad (but I have the black one). Instead I am using a custom board with the XMSP401RIPZR. It was purchased around April this year from TI.

    But it's strange..wouldn't the Processor use the ROM APIs when I don't use MAP_ ? Basically I also tried that but it didn't work. Maybe I need to clean the project first and then rebuild it again?

    best regards

    Benni

  • ah ok, have to use the ROM prefix, sorry ;)
  • sadly the ROM version of GPIO APIs do not exist :(

    so i'll just keep it with the register programming.
    I must say, I am quite dissapointed about that..

  • Ben,

    Since you are using stand alone pre-release silicon, we cannot guarantee full functionality with the current SW offering. We have recently RTM'd (fully released - No longer says XMS on chip) MSP432 and some changes to the SW offering were needed to be made for various reasons. Unfortunately some of the more current changes and the changes made for the CMSIS compatibility has made some of the APIs not function correctly on the earlier versions of the pre-release silicon. Growing pains for sure, but they could not be avoided.

    As you stated, register level programming will work fine, but if you want the APIs , you will need the released silicon for this.

  • thanks for your infos and the help. I will keep it that way and refer to the new chip for a next revision of the custom board.

    greets

    Benni

**Attention** This is a public forum