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