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.

MSP430G2553: Help with switching timer capture on both edges; current design occasionally reverses pattern

Part Number: MSP430G2553

Hello and thanks for looking. I am trying to implement a button press release that is tied to a second PWM pin using the WDT to debounce the button. The result should be: Btn down, pwm on; Btn up pwm off. This system must also capture the timing of the button state changes to get an accurate determination of button up/down time (capture of TA1CCR2 to a variable is not shown in this demo code). In trying to achieve this, I have several questions but the biggest problem with the current set up is that the relationship between the button state and the pwm behavior reverses after multiple button presses. At first, the system works as described but after several button press/release cycles, I the pwm turns on when the button is released, then switches back after more, etc.

I have read good discussions on timing of the raising and clearing of the CCIE flag in this forum, but my application doesn't seem to require highly accurate counts as in those examples. If I can get timing accurate to within a 10 - 40 ms range that would be fine. I see button bounce on a scope that is well within the WDT 'time out' for debouncing, so that appears to be working well.

So, my question is how to implement this relatively simple scenario. I am using the MSP430G2553 Timer1_A3 for capture on pin P2_5 attached to the button and Timer0_A3 on pin P2_6 for the pwm output. Related questions are...

Can I use PxREN to set up internal pullup (datasheet says this is for pin when configured as I/O)? I have an external pullup working now.

Do I need to stop the timer in order to switch the edge that triggers an interrupt (TA1CTL)?

Do I have to reset COV in TA1CCTL2?

Is it permissible to test the state of the pin with PxIN & BTN_KEY? As currently used, this does not seem to work as expected.

Finally, while debugging this I noticed that the debugger reports that the CMx bit of TA1CCTL2 is CM_3 when I am toggling between CM_1 and CM_2 even though I can see that I am correctly toggling bit CCIE. Why might that be?

Thanks for any thoughts and here is my code...

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <msp430.h>
#define BTN_KEY BIT5 //attach key to P2_5 TA1.2
#define BUZZER BIT6 // Buzzer -> P2_6
void PortsInit(void);
void InitBuzzer(void);
volatile char edge = 0; //used to toggle CCR2 edge detect
int main(void)
{
WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer
PortsInit();
P2DIR &= ~BTN_KEY; //Set Btn as input
P2SEL = BTN_KEY; //Set Btn for Timer1_A CCI1A capture
InitBuzzer();
//Set up Timer1A
TA1CTL = MC_2 | ID_3 | TASSEL_2 | TACLR;// | TAIE;
// capture on falling edge, CCI1A input, synchronous cap, capture mode, ints enabled
TA1CCTL2 = CM_2 | CCIS_1 | SCS | CAP | CCIE;
__enable_interrupt();
for ( ; ; ){
// do nothing
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

  • > TA1CTL |= MC_0; // stop timer

    This doesn't stop the timer, since MC_0==0. Try:

    > TA1CTL &= ~MC_3; // stop timer

    ------------------------

    > TA1CCTL2 |= CM_1; // trigger on rising edge

    Similarly, this doesn't set CM=1, it sets the low bit of CM. (After one round, CM=3 and it stays there.) Try instead:

    > TA1CCTL2 = (TA1CCTL2 & ~CM_3) | CM_1; // trigger on rising edge

    Alternatively, since (a) you're overall interested in both edges and (b) you're checking the actual state of the pin, you might consider using CM=3 after all.

    ------------------------

    Checking the state of the pin is a good idea. Strategically, though, you should check it after the debouncing is done (in the WDT ISR), not immediately after you see the first transition.

    Bounces happen very fast, and there's a non-small chance it will have transitioned twice before you look. Thus it's more reliable to look only later, after it has settled down.

    ------------------------

    For your specific questions:

    - If you have an external pullup, you don't need the REN resistor.

    - If you're not interested in COV, you can ignore it completely. Checking the pin directly replaces most anything COV would tell you.

    - You don't need to stop the timer to switch the edge (CM field).

  • Thank you for the quick and thorough reply. Your correction on setting the CM bits helps. Also, using both edges and checking in the WDT ISR works as needed. I see that it is okay to use the internal pullup resistor in this case and I've removed the external one I had.

    I have a remaining question regarding setting the P2SEL bit for the BTN_KEY (for timer capture purposes). After setting P2OUT = 0 and P2DIR = 0xFF in the PortsInit(), I then set up the BTN_KEY with 

    Fullscreen
    1
    2
    3
    4
    P2DIR &= ~BTN_KEY; //Set Btn as input
    P2OUT |= BTN_KEY; // along with REN, set pullup
    P2REN |= BTN_KEY; //Pullup resistor
    P2SEL = BTN_KEY; //Set Btn for Timer1_A CCI1A capture
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    This works fine but if I were to set P2SEL |= BTN_KEY, that sets the P2_6 and P2_7 as well. I've looked at the datasheet for this processor family and see that there is some consideration of interactions between REN and SEL but that seems to be with a different chip. Is there a better way to set just this bit? I feel that this is in the compiler's users guide, so I'll dig in there to look for macros to define bits.

    Thanks again and I'll mark this issue as resolved.

    Regards,

    Nick

  • That's a good question, which I overlooked. At Reset, P2SEL=0xC0 (bits 6/7 pre-set) to enable the 32kHz oscillator (XIN/XOUT). This is somewhat unusual, but very useful.

    These two pins are interrelated. To do PWM on P2.6, (P2SEL.6) you need to also turn off P2SEL.7 and set P2.6 as an output, to shut down the oscillator. [Ref data sheet (SLAS735J) Table 21]. This is what the code you ended up with (using "P2SEL=") is doing, though you only need to do it once.

    Those two pins (on the F2/G2 series) are special. For any other pins (on any other series) using "|=" would be the correct action.

  • That makes sense. I am using an old launchpad boosterpack mk1 which has the buzzer tied to P2_6 (XIN). I should have realized this pin was 'special.'

    Thanks again,

    Nick

**Attention** This is a public forum