Trying to understand registers on MSP430G2553

MrChips

Joined Oct 2, 2009
35,017
For a simple program, I would define these in the main.c file.

For example:
Code:
#define ON 1
#define OFF 0
#define RED_LED PORT1_bit.P0
#define GREEN_LED PORT1_bit.P6
 

Thread Starter

StrongPenguin

Joined Jun 9, 2018
307
Code:
#include <msp430.h>

void main(void) {
    WDTCTL = WDTPW | WDTHOLD;       // Stop watchdog timer

    //PM5CTL0 &= ~LOCKLPM5;
    //P1DIR |= 0xFF;
    P2DIR |= 0xFF;
    P2SEL &= ~(BIT6 + BIT7);   //To enable pins 7 and 8



    while(1)        //1,3,7
    {
        unsigned long long int ctr;
        //unsigned char *j[8] = {BIT0, BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7};

        P2OUT = 0x00;

        for(ctr = 0; ctr < 25000 ; ctr++);
            {
               P2OUT++;
            }
    }

}
@Mark Hughes Here is the entire code. I've // the PM5 part, as you can see, because It won't compile. It just says "#20 identifier XXXX unidentified on them both.

@geekoftheweek I have downloaded the guide, but I now see I have looked in the wrong places. I'm most definitely going to read that part.

Btw..I'm trying to make a simple 8 bit counting program, but when I execute that code, nothing happens, at all. And when I remove the ; semcolon after the for loop, the leds just all turn on.

Anybody spot an error?
 

MrChips

Joined Oct 2, 2009
35,017
Some code comments:

1) No need to complicate code
P2DIR |= 0xFF;

Do this:
P2DIR = 0xFF;

2) Again, don't make the code more complex than it needs to be.
P2SEL &= ~(BIT6 + BIT7); //To enable pins 7 and 8

Port configration bits are set to default values on power on.
You can ignore setting P2SEL.

3)
while(1);

is a complete statement, creating an endless loop, same as

while(1)
{
}

Code execution never gets past this statement.

4) Remove this
P2OUT = 0x00;

5) Your for( ) loop makes no sense.
You will not be able to see the LEDs flash.
 

geekoftheweek

Joined Oct 6, 2013
1,429
Eliminate the brackets after the for(ctr = 0; ctr < 25000 ; ctr++);

Code:
for(ctr = 0; ctr < 25000 ; ctr++);
P2OUT++;
When you eliminate the semicolon and all the leds stay on it's probably actually working, but just happening faster than the eye can see. Without the semicolon the for will loop through whatever is in the brackets. With the semicolon and no brackets it creates a delay.
 

Mark Hughes

Joined Jun 14, 2016
409
@StrongPenguin,
I recommend that you go find the sample code for your board, and get that to run before you start doing your own thing. You must determine why the code won't compile with PM5CTL0 &= ~LOCKLPM5; inserted. Do you by chance have another c-compiler in your system path? That really pisses Code Composer Studio (and other Eclipse installations) off. In fact -- I half expect that your problem is that CCS is trying to use the wrong compiler for your code. Edit your system path to remove any other instances and try to compile again.
Please put PM5CTL0 &= ~LOCKLPM5; in your code, and post a screen-capture of the complete error message that accompanies it.
Thanks,
Mark
 

MrChips

Joined Oct 2, 2009
35,017
Eliminate the brackets after the for(ctr = 0; ctr < 25000 ; ctr++);

Code:
for(ctr = 0; ctr < 25000 ; ctr++);
P2OUT++;
When you eliminate the semicolon and all the leds stay on it's probably actually working, but just happening faster than the eye can see. Without the semicolon the for will loop through whatever is in the brackets. With the semicolon and no brackets it creates a delay.
Thanks for this. My mistake. I see the semicolon now.

This is ok, with or without the curly braces.
Code:
for(ctr = 0; ctr < 25000 ; ctr++);
{
    P2OUT++;
}
But you do have to be careful. An optimizing compiler could choose to eliminate the delay loop since ctr is never used.
 

mckenney

Joined Nov 10, 2018
125
> You must determine why the code won't compile with PM5CTL0 &= ~LOCKLPM5; inserted.
The G2553 doesn't have a PM5CTL0 register. It only appears in the FR series. Just remove the line.

> But you do have to be careful. An optimizing compiler could choose to eliminate the delay loop since ctr is never used.
There are ways to force the optimizer to keep such loops, but software loops have the additional problem that it's very difficult to know just how long you're delaying for.

The MSP430 (library) has a function __delay_cycles(N), which spins for N CPU clock cycles. It expands to inline assembly, and since it's "asm volatile" the optimizer can't remove it, and you know how long (denominated in MCLKs) it takes. You can only provide a constant for an argument, but it's easy enough to enclose it in a loop counted by a variable.
 

geekoftheweek

Joined Oct 6, 2013
1,429
This is ok, with or without the curly braces.
Code:
for(ctr = 0; ctr < 25000 ; ctr++);
Thanks for the correction. I've always used braces to make it easier for me to read and was under the impression that is how things worked.

Correction... have to quit getting on here when I'm tired. I always used braces because I've never used for as a delay.
 
Last edited:

Thread Starter

StrongPenguin

Joined Jun 9, 2018
307
@MrChips Omitting P2SEL results in the last two bits not counting up, no matter how long I wait. I Googled this, and the reason for needing to set P7 and 8 was because of XIN and XOUT.

@Mark Hughes I think @mckenney helps us fine with this. Nor can I find PM5 in the User Guide.

@mckenney Sounds interesting, I will definitely look into that timer function.

I can see there are many "know your compiler" hints throughout this post. Before following the advice on removing curly braces, I also kept getting an Advice from the compiler telling me to count down. Oh well, there's room for improvement :)

Btw..code runs now. Counts up to bingo.
 

MrChips

Joined Oct 2, 2009
35,017
My mistake. Usually I would be using P1OUT for a test such as this. All pins on PORT1 are available as GPIO by default.

More importantly "know your MCU".
 

mckenney

Joined Nov 10, 2018
125
> Might even be an application engineer for TI.
Mark flatters me. I don't work for TI, I just lurk at the E2E Forum.

> Advice from the compiler telling me to count down
One person's opinion: Ignore the ULP Advice. It is Advice (severity 0) not a Warning (severity 5) or Error (severity 10), and I have a "difference of opinion" with many of them. They meant well. It can be disabled in the Build Settings.
 

mckenney

Joined Nov 10, 2018
125
> Are you Bruce McKenney?
My friends call me "47378" for short :)-)). I don't know about the rest of that stuff, but I have picked up a few things over the years.

I was intrigued by the project that you were working with over at the E2E, so I thought I'd see what AAC was about. I'm mostly a firmware guy, very weak in analog/electronics. (My brother is the Analog Guy.)

And now I guess I have formally hijacked this thread. Sorry.
 

Thread Starter

StrongPenguin

Joined Jun 9, 2018
307
I don't mind hijacking form this point on, as I have found what I sought. And If need be, I know where to find you all :D:cool:

Thanks for all the help, guys.
 

Thread Starter

StrongPenguin

Joined Jun 9, 2018
307
A little question here.

The struggle is real. I've ventured into Timer A and it's plethora of registers and flags and stuff, and there are a lot of terms I don't understand. Like "Timer_A capture/compare 0" "Timer_A capture/compare control 0", for instance. What is being captured and compared with what?

On page 357 (EDIT: Of the Family Guide) is a nice diagram of the timer. Would it be smart to study this diagram closely, just to know what's going on? Right now, its all just gibberish for me.

This is what I'm trying to make sens of now. Found it on Github.

Code:
#include <msp430.h>

#define LED BIT6                        // Green LED -> P1.6

void main(void)
{
    WDTCTL = WDTPW + WDTHOLD;           // Stop watchdog timer

    P1DIR |= LED;                       // Set LED pin -> Output
    P1OUT &=~ LED;                      // Turn OFF LED

    TACCR0 = 9000;                      // Set Timer Timeout Value - P1.2 off time can be altered here, higher number slower blink
    TACCTL0 |= CCIE;                    // Enable Overflow Interrupt
    TACTL |= MC_1 + TASSEL_1 + TACLR ;  // Set Mode -> Up Count, Clock -> ACLK, Clear Timer

    __bis_SR_register(LPM3_bits + GIE); // Goto LPM3 (Only ACLK active), Enable CPU Interrupt
}

#pragma vector = TIMER0_A0_VECTOR       // CCR0 Interrupt Vector
__interrupt void CCR0_ISR(void)
{
    P1OUT ^= LED;                       // Toggle LED
}
 
Last edited:

mckenney

Joined Nov 10, 2018
125
On page 357 is a nice diagram of the timer. Would it be smart to study this diagram closely, just to know what's going on? Right now, its all just gibberish for me.
I won't try to talk someone out of reading the book, but that diagram probably has more than you're interested in right now. I do suggest you skim section 12.2 below it (max 5 minutes), just so you've seen the terms once.

A timer is a counter which ticks based on some chosen clock. In Continuous mode, it counts until it passes 65535, when it overflows to 0. In Up mode, it counts until it's equal to a particular register (CCR0), then it resets to 0. The mode is set with the MC bits. It keeps counting until told to stop (by setting MC=0).

The Capture/Compare Registers (CCRs) do different things in Capture vs Compare mode. Most timer applcations use Compare. As the counter counts, when it becomes equal to one of the CCRs, it acts according to the corresponding CCTL register (one possible action is "nothing"). It can alter the state of an output pin (OUTMOD), and/or it can generate an interrupt (CCIE/CCIFG).

The most interesting clocks are ACLK (low-frequency) and SMCLK (high-frequency). If you don't have a crystal, ACLK is around 10kHz, and can vary by 40% (but it's cheap!). SMCLK is typically run at the full CPU speed (1-16MHz).

That's section 12.2. (I may have left out a few things.) Just knowing this much is enough to do 75% of what you'll want a timer for.
Code:
    TACCR0 = 9000;                      // Set Timer Timeout Value - P1.2 off time can be altered here, higher number slower blink
This sets the "top" value for Up mode. When the counter reaches 9000, it resets to 0. 9000 is a bit of a magic number; I suspect it was chosen to be around 10000 (one second).
Code:
    TACCTL0 |= CCIE;                    // Enable Overflow Interrupt
When the counter reaches the value in TACCR0, it triggers an interrupt (TIMER0_A0_VECTOR, see below). It also resets to 0, but that's because of Up mode (below).
Code:
    TACTL |= MC_1 + TASSEL_1 + TACLR ;  // Set Mode -> Up Count, Clock -> ACLK, Clear Timer
The timer is clocked by ACLK (TASSEL=1), in Up mode (MC=1). Setting MC=something-non-0 starts it counting.
Code:
#pragma vector = TIMER0_A0_VECTOR       // CCR0 Interrupt Vector
__interrupt void CCR0_ISR(void)
{
    P1OUT ^= LED;                       // Toggle LED
}
This is the (CCR0) timer ISR. Nobody cares what the function name is. __interrupt assures the proper entry/exit sequence. The _VECTOR name is what puts it into the proper spot in the interrupt vectors up at the top of memory.
 

MrChips

Joined Oct 2, 2009
35,017
Timer capture and timer compare are two very powerful and very useful modes of timer operation that are almost universal across most MCUs.

Think of it this way.

Timer capture is used to time external events, i.e. it is used to time-stamp an event or to measure time intervals, i.e. used for INPUT.

Timer compare is used to generate waveforms, time delays, PWM, etc. i.e. used for OUTPUT.
 
Top