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: MSP432P401R - Push button random problems

Part Number: MSP432P401R

Hello, I have made a code that allows me, by pressing the button P1.4, to change the direction of the H-bridge having that, if you had activated the high transistor of phase B and the low transistor of phase C and you suddenly press the button, they become deactivated and the high transistor of phase C and the low transistor of phase B become activated and each time you press the button again they alternate, activating again the high of B and the low of C and so on. It does it correctly, but sometimes when I press the pushbutton it does not alternate in the direction and the same transistors remain activated when they should have been switched. It may be an effect of the pushbutton debouncing, but if so, how could I modify the code in a 'simple' way to fix it? Thanks a lot!

  1. #include "msp.h"
  2. #include <stdint.h>
  3. #include <stdio.h>
  4. volatile uint8_t pulsador = 0; //Variable to change the direction on the H-bridge
  5. volatile uint8_t contador_ms = 0;
  6. volatile uint8_t conteo = 0;
  7. uint8_t duty_cycle = 14; // +/- el 50% of Duty Cycle
  8. void pulsadores(void){ // Use pushbutton S2 (P1.4) to change direction on the H-bridge.
  9.     P1SEL0 &= ~BIT4; // Function I/O
  10.     P1SEL1 &= ~BIT4;
  11.     P1DIR &= ~BIT4
  12.     P1REN |= BIT4
  13.     P1OUT |= BIT4
  14.     P1IES |= BIT4
  15.     P1IFG &= ~BIT4
  16.     P1IE |= BIT4
  17. }
  18. void transistors(void){
  19.     /* TB: P7.5; TC: P7.6
  20.      * BB: P7.1; BC: P7.2
  21.      */
  22.     // Pines Transistores High (PWM)
  23.     P7SEL0 |= (BIT5 | BIT6); // Set PIN P7.5 and P7.6 for output on Timer
  24.     P7SEL1 &= ~(BIT5 | BIT6);
  25.     P7DIR |= (BIT5 | BIT6);
  26.     // Pines Transistores Low (GPIO)
  27.     P7SEL0 &= ~(BIT1 | BIT2);
  28.     P7SEL1 &= ~(BIT1 | BIT2);
  29.     P7DIR |= (BIT1 | BIT2); // output
  30. }
  31. void TimerA0(void){
  32.     // This timer will be used to change states during the sequence.
  33.     TA0CCR0 = 374; // (375-1) Tperiode del PWM: 1 ms
  34.     TA0CTL |= TASSEL_2 | ID_3 | MC_1 | TACLR
  35. }
  36. void TimerA1_PWM(void){ // Timer to control the 2 PWM pins
  37.     TA1CCR0 = 29; // (30-1) PWM period: 10 us -> As SMCLK = 3MHz, the counter counts in Up Mode every 1/3MHz = 0.333 us. Therefore, 30 - 0.333us = 10 us
  38.     TA1CTL |= TASSEL_2 | ID_3 | MC_1 | TACLR
  39.     TA1CCTL2 |= OUTMOD_7; // Mode CCR2: Reset/Set
  40.     TA1CCTL3 |= OUTMOD_7; // Mode CCR3: Reset/Set
  41. }
  42. void TimerA2_Antirebotes(void){ 
  43.     TA2CCR0 = 1023; // (1024-1) To obtain 250 ms of anti-rebounds -> The counter counts in Up Mode every 1/(4.096 kHz) = 0.244 ms. Therefore, 1024 - 0.244 ms = 250 ms
  44.     TA2CTL |= TASSEL_1 | ID_3 | MC_1 | TACLR; // ACLK clock with a frequency of 32.768 kHz and with a frequency divider of 8, Up Mode -> fACLK = 4.096 kHz
  45. }
  46. void delay_ms(uint8_t tiempo){
  47.     contador_ms = 0;
  48.     TA0CTL |= MC_1; // up
  49.     TA0CCTL0 |= CCIE
  50.     while(contador_ms < tiempo);
  51.     TA0CTL &= ~MC_3; // stop timer
  52. }
  53. void init_interrupciones(void){
  54.     NVIC_EnableIRQ(TA0_0_IRQn);// Enable interrupts in TimerA0_0
  55.     NVIC_EnableIRQ(TA2_0_IRQn); // Enable interrupts in TimerA2_0
  56.     NVIC_EnableIRQ(PORT1_IRQn); // enable interr PORT1
  57.     __enable_irq(); // Enable global interrupt
  58. }
  59. void main(void)
  60. {
  61.     WDT_A->CTL = WDT_A_CTL_PW | WDT_A_CTL_HOLD;     // stop watchdog timer
  62.     pulsadores();
  63.     transistors();
  64.     TimerA0();
  65.     TimerA2_Antirebotes();
  66.     TimerA1_PWM();
  67.     init_interrupciones();
  68.     while(1){
  69.         if(pulsador%2 == 0){
  70.             if(conteo==1){
  71.                 P7OUT &= ~BIT1; // BB y TC en OFF
  72.                 TA1CCR2 = 0;
  73.                 delay_ms(10);
  74.                 conteo = 0;
  75.             }
  76.             else if(conteo==0){
  77.                 P7OUT |= BIT2; // BC en ON
  78.                 TA1CCR3 = duty_cycle; // TB en ON
  79.                 delay_ms(10); // 10 ms en ON
  80.                 P7OUT &= ~BIT2; // BC en OFF
  81.                 TA1CCR3 = 0; // TB en OFF
  82.                 delay_ms(10); // 10 ms en ON
  83.             }
  84.         }
  85.         else if(pulsador%2 != 0){
  86.             if(conteo==1){
  87.                 P7OUT &= ~BIT2; // TB y BC en OFF
  88.                 TA1CCR3 = 0;
  89.                 delay_ms(10);
  90.                 conteo = 0;
  91.             }
  92.             else if(conteo==0){
  93.                 P7OUT |= BIT1; // BB en ON
  94.                 TA1CCR2 = duty_cycle; // TC en ON
  95.                 delay_ms(10); // 10 ms en ON
  96.                 P7OUT &= ~BIT1; // BB en OFF
  97.                 TA1CCR2 = 0; // TC en OFF
  98.                 delay_ms(10); // 10 ms en OFF
  99.             }
  100.         }
  101.     }
  102. }
  103. void TA0_0_IRQHandler(void){ // Interrupt Timer A0
  104.     TA0CCTL0 &= ~CCIFG
  105.     contador_ms++;
  106. }
  107. void TA2_0_IRQHandler(void){ // Interrupt Timer A2
  108.     TA2CCTL0 &= ~CCIFG
  109.     P1IFG &= ~BIT4; // we lower the flag of the pushbutton so that it does not remain depressed
  110.     P1IE |= BIT4; // We reactivate interruptions on pushbutton P1.4
  111. }
  112. void PORT1_IRQHandler(void) // Interrupt Port P1
  113. {
  114.     P1IE &= ~BIT4; // We deactivate interrupts on pushbutton P1.4
  115.     pulsador++;
  116.     conteo++;
  117.     if(pulsador > 5){ // So that it does not increase indefinitely, and can reach the limit value of 255
  118.         pulsador = 0
  119.     }
  120.     TA2CCTL0 |= CCIE; // We enable interrupts in the Timer A2_0
  121. }
  •    TA2CCR0 = 1023; // (1024-1) To obtain 250 ms of anti-rebounds[...]

    I suspect 250ms is too aggressive, and you'll lose (intentional) button presses that are close together. Something like 8-10ms is probably sufficient, e.g.:

       TA2CCR0 = 32-1; // (32-1) To obtain 8 ms of anti-rebounds[...]

    This improved things when I did it.

    [Edit: Minor wording change.]

  • I have tried it with the change you mentioned, but it still has the same problem.. I can't quite explain why it happens

  • I was only able to generate your symptom (LED as a proxy) by pushing the button very rapidly. Can you elaborate on your test case (e.g. what exactly is "sometimes")?

    There's another small window where if the button is pushed very close to the end of a TA2 cycle (TA2R == 0x3FE) the actual debounce time would end up being very short. I was not able to demonstrate this, but the indicated fix would be to add to the PORT1 ISR:

    > TA2R = 0;  // Full cycle for debounce

    > TA2CCTL0 = CCIE;  // Clear any recent (stale) CCIFG and then enable

    [Also, I was using a Launchpad -- based on some measurements I did some years ago, those buttons bounce very little, if at all. A different button might have different behavior.]