12 July 2010

Tutorial 03: Flipping Bits

Now that we have access to the registers, how do we actually flip the switches (change the bits)?  We'll examine the ways to do this using the following example: we'll use a G2001 with an LED connected from P1.4 to ground.  If P1.4 is at 0 V, nothing happens, but if P1.4 is at Vcc, the LED will turn on.  Since we've connected to P1.4, we should be able to control it by fiddling with bit 4 in the P1 registers.  (Keep in mind that we're not changing the 4th bit, at least not in the way we normally think of it.  The 1st bit is bit 0, so bit 4 is technically the 5th bit, but who's counting?)

Before we look at setting bit values, we should take a look at the ways we can represent the values in 8-bit registers.  We could always use regular decimal notation, but unfortunately it has little advantage to counter the confusion caused by having to use 8-bit numbers in a non-multiple base (the decimal base is, of course, 10).  

The clearest way to represent the value is in binary notation, or base 2.  The register has 8 digits, each is a 0 or 1, corresponding to the value in each bit.  To make a binary 2 clear from a decimal 10, we can preface the number with the notation 0b (first character is a zero), such as 0b10.

Another common notation used is hexadecimal (base 16).  This notation is convenient because each 8-bit value is represented by exactly two digits, each a value from 0-9 or a-f.  The preface for hexadecimal is 0x, so the number 2 in hex is 0x02.  The number 12 would be 0x0c, since the digits a-f correspond to the numbers 10-15.  16-bit numbers are represented with 4 digits, such as 0x14da.  Many values in the MSP430 are 16-bit, so hexadecimal is very convenient here.  (I apologize for the change in notation from the previous tutorial; in the TI documentation they use the notation 14DAh for hex values, but here we're using 0x14da instead.  The 0x notation is used in the programming, and I will stick to that notation unless I'm citing from a TI document directly that uses the h notation.)

We could also use an octal notation (base 8), with the preface 0o.  I've not seen this in practice, however.

We'll start using some actual code in this post, so I want to establish a convention.  Anything written in the Courier font is a code snippet or example.  The coloring in the code matches the color scheme I usually see when I look at a .c file in a text editor, and for now doesn't make a difference.  You may have other color schemes that you see.  I'll try to use the colors that are used in CCS as best I can.

Binary notation is obviously the one that makes it clear what bits we're using and what they're set to.  Unfortunately, it also takes lots of characters to write them out.  When we write C programs for the MSP430, we can include a header file with information and shortcuts specific to the device we're using (such as #include <msp430g2001.h>).  These header files include some shortcut names for the binary values where each digit is 0 except for a specific bit; the header file allows us to use the name BIT2 to represent 0b00000100.  There is a BIT0 through BIT7 included in each header file, which makes for a nice shortcut and less typing.  In the discussion below, however, I'll try to keep it to the full 8 digit binary values to make it clear what is happening in the operations described.  Now, on to the fiddling!

For our LED example, we'll need to first make P1.4 an output so that we can control the voltage above the LED.  We do this by changing bit 4 in P1DIR to 1, for output mode.

1. Direct Assignment
If we know exactly what the binary (or hex, or even decimal) value corresponding to the configuration we need is, we can just set it directly:  P1DIR = 0b00010000; would set all of the bits in P1DIR to 0 except bit 4.  This method works pretty well for initializing the processor, but later in the program can be problematic when we might not know for certain what state bits we don't want to change are in.  Turning off the bit is easy, just set it to the value with bit 4 set at 0: P1DIR = 0b00000000, or just as easily for this particular case, P1DIR = 0.  (Using the BITx notation, we would write P1DIR = BIT4.)

2. Addition and Subtraction
If we don't know exactly the value needed for the configuration, or if we're just trying to turn on one bit, we could just add the bit's value to P1DIR (I'm using the colon character : to represent unknown digit values):  0b:::0:::: + 0b:::1:::: = 0b:::1::::, so we could turn on bit 4 by doing P1DIR += 0b00010000.  *(Confused by the +=?  See the footnote below!)  The problem with this method is if we accidentally turn it on twice: 0b:::1:::: + 0b00010000 is going to cause a carry over into the next bits, changing I/O directions where we don't want to!  This method should be used with caution.  Note that the equivalent to turn the bit off would be to subtract the value, of course.  (BITx notation: P1DIR += BIT4 or P1DIR -= BIT4.)

3. Logic Operators & and |
To avoid the problems with addition and subtraction, we can use logic operations.  Let's say we have a bit with the value x.  (x could be 0 or 1, we'll just look at this generally.)  The operations and (&) and or (|) can be used to change the value of the bit to be specifically 1 or 0.  Note that x & 0 = 0 no matter what value x is.  Similarly, x | 1 = 1 regardless of the value of x.  Also, x & 1 = x and x | 0 = x, so the value of x is unchanged. for these operations.  So what would be the result of the operation P1DIR | 0b00010000?  Bits 0-3 and 5-7 would be unchanged (remember, | 0 doesn't change the value) while bit 4 is set to 1.  (It may have been 1 before, but is definitely 1 after the operation!)  On the other hand, P1DIR &= 0b11101111 would have the effect of setting bit 4 to zero and leaving the others unchanged.  Note that 0b11101111 is the not operation (~) applied to the original 0b00010000, so we could write this as P1DIR &= ~0b00010000.  (In BITx notation: P1DIR |= BIT4 turns bit 4 on, and P1DIR &= ~BIT4 turns it off.)

Reader Exercise:  Sometimes you'll see example code that uses the notation a + b; and sometimes a | b; to do the same thing.  Convince yourself that these are equivalent in particular circumstances; when would you not want to use one or the other?

4.  Toggling with ^
Ok, I said there were three choices, and there really are only three.  This fourth option is similar to the third choice, but is an effective way if we just want to toggle the value, not set it to be specifically 0 or 1.  The exclusive or operator (^) has this effect:  x^0 = 1 if x is 1, and 0 if x is 0.  x^1 = 1 if x is 0, and 0 if x is 1.  So x^0 leaves the bit unchanged, and x^1 changes the value of x to its opposite.  P1DIR ^= 0b00010000 flips bit 4 (to 1 if it was 0, to 0 if it was 1) just like toggling a switch.  (In BITx notation: P1DIR ^= BIT4.)

Now, in our program we need to initialize the pin to be an output:
P1DIR = BIT4;  
(An equivalent way to do this is to use a logic operator rather than an assignment:  P1DIR |= BIT4;)
The value in P1OUT could be either 0 or 1, so if we care what state the LED starts in we should set that:
P1OUT = 0;
(A better practice is to initialize the output state before we change the pin to an output.)
Now we have an output pin set at 0, keeping the LED off.  To turn it on, we give the command:
P1OUT |= BIT4;
To turn it off, we give:
P1OUT &= ~BIT4;
To toggle its state (off if on, on if off):
P1OUT ^= BIT4;

As a final example, demonstrating some power in the other assignment methods, let's put another LED on P1.6.

First, let's configure the two pins as outputs with an initial state off:
P1OUT = 0;
P1DIR = BIT4 + BIT6;
(adding the two values together is easily verified to be 0b01010000).
We can turn each one on and off individually:
P1OUT |= BIT4;    // P1.4 on
P1OUT &= ~BIT4;   // P1.4 off
P1OUT |= BIT6;    // P1.6 on
P1OUT &= ~BIT6;   // P1.6 off
Or we can turn them on and off together:
P1OUT |= BIT4 + BIT6;     // both on
P1OUT &= ~(BIT4 + BIT6);  // both off
And finally, toggle them simultaneously:
P1OUT ^= BIT4 + BIT6;     // toggle both

Reader Exercise:  Write down the necessary code to use LEDs on pins 3 and 7 of port 1, with pin 3 initially off and pin 7 initially on.  Then toggle the LEDs so that 3 is on and 7 is off.


*  += is a shorthand operator in C.  If I say x += 1;, the command adds one to x and reassigns the result to x.  In other words, it's the same as saying x = x + 1;.  While algebraically that statement makes no sense, in programming it's very common.  Don't think of = as meaning the two sides are equal, read it as "x is now equal to the value currently in x plus 1".

21 comments:

OCY said...

I have some comments about LEDs.

1) Usually, LEDs need to have a resistor in series to limit the amount of current.

2) In order to be able to turn on/off a LED, the LED can be either connected between an output pin and ground or between an output pin and Vcc. The voltage level at the output pin has opposite effect depending on which way the LED is connected.

3) The LaunchPad has a Red LED controlled by P1.6 and a Green LED controlled by P1.0.

plazma said...

Bit manipulation is a good thing to learn in the beginning. It is used a lot when programming microcontrollers. Do the math with logic operators on papers and it's learned quite fast. Shifting << or >> is also good to learn.
http://en.wikipedia.org/wiki/Bitwise_operation
http://en.wikipedia.org/wiki/Bit_manipulation

Unknown said...

I agree, which is why I brought it up so early in the tutorial. Thanks for the wikipedia links!

Another note on the LEDs, many LEDs can handle the currents from directly connecting to Vcc, but the MSP430 might not. In general, always limit the currents for LEDs in a design. Expect something around a few hundred ohms for the voltages we use to power these chips.

Unknown said...

One other point... the LaunchPads I received have the red LED on P1.0 and the green LED on P1.6-- opposite what was expected from the release announcement.

m.Alin said...

I'm very curious as to what are the circumstances in which one should use the a + b or the a | b notations

Anonymous said...

Under the Direct Assignment section:

What does the following mean:
(Using the BITx notation, we would write P1DIR = BIT4.)

What does equating P1DIR to BIT4 achieve?

Unknown said...

Keep in mind that in C a single = is not equating, but assigning. The statement P1DIR = BIT4; assigns the value BIT4 to the P1DIR register. BIT4 is a shorthand notation for an 8 bit value where all bits are 0 except bit 4 (counting from 0-7). So:

BIT4 is 0b00010000, which is the same as 0x10. (If you look in the header file, you'll see a line that says #define BIT4 0x10.)

The effect of the line P1DIR = BIT4; is to set the direction flags for each GIO in P1 to 0 (making them inputs) except for P1.4, which is set to 1 (making it an output).

Keep in mind this is different from P1DIR |= BIT4;. This line is different in that it leaves all bits unchanged (be they 0's or 1's) except for bit 4--this line ensures that bit is set (to 1) without changing any other bits. P1DIR = BIT4; will set bit 4 and clear all others. You'll have to choose the assignment operator used according to the needs in the program.

The whole point of the notation is that the port registers can be viewed as individual switches for each port pin-- BITx in each register controls each respective pin, eg. BITx in the P1 registers control P1.x.

Hope that helps! Feel free to ask for any other clarification.

Anonymous said...

Thanks for the earlier clarification regarding P1DIR= BIT4.
In light of the dangers involved in accidentally clearing bits using the above notation, wouldn't it be better if we always use logical operators | and & to manipulate bits?

Just a thought..

Unknown said...

I agree, but with one exception: initialization. When your program starts, it can be helpful to leave no ambiguity as to the initial state of some peripherals. In the end, they both get you there, but I do tend to only use the direct assignment method at the beginning of my code. Everywhere else I'll use logic operators.

Thanks for helping to make that point!

billabott said...

Me again. on another site I stumbled across the missing file. (REv. E) and I quote:
BigglesPiP said ...

Coming from the Microchip PIC family of uCs it's nice to have real interrupts, I miss the RAM being flash a little.

But one thing I'm finding hard to forgive is TI's diabolical datasheets, there's nothing immediately useful in either the MSP430 family datasheet or the datasheet speific to the MCU.

After days of searching I came across a rumour that Revision E of something generic to MSP430 told me what I wanted to know (what every bit in every control register does and how to operate features). But the document is a 404 on TI's site. Eventually I found it, I shall host it while TI get their act together: http://iamtheb.org/me/MSP430x2xx_Family_Users_Guide_Rev_E.pdf

TI, can we please have good datasheets, Microchip's are the business.

--BigglesPiP 07:38, 18 January 2011 (CST)

Unknown said...

Those are interesting points; I do think I need to come in TI's defense on this one, however.

First off, there's nothing magical about Rev. E itself, it's the Family User's Guide that's key. Rev. F is just as good, possibly better. Rev. C or D will also work, however later revisions will have corrections, additions for newer devices and technologies, etc.

Second, I personally think the datasheets are very useful. As I've been learning to use the MSP430, I've found that I use both the Family Guide and the Datasheet extensively as I figure out how something works, how it's implemented on my specific device, and how to code it up.

As a disclaimer, I do not work for TI at all... I'm simply an MSP430 user. I started using this uC as opposed to one of the others on the market simply because the chief electrical engineer on my project said to use it. As time has gone on, I've found there are some great features and advantages in this uC as opposed to some of the others, and I really enjoy using it. I'm not paid by TI in any way.

NKT said...

Hi, just working through this again.

Firstly, can I input a binary number rather than using the BITx system?

Also, if I use your code and make P1DIR = BIT6 + BIT0; then if I toggle P1DIR both LEDs flash together.

However, could I toggle the whole of P1DIR rather than the BITs, to do the same thing? (And, save a line or two by only setting BIT6 and toggling the entire register to get alternate LED flashing?

Or is there also an "undefined" state as well as 0 and 1?

Unknown said...

NKT,

You certainly can use binary directly; P1OUT = 0b01000001 is equivalent to P1OUT = BIT6 + BIT0.

Perhaps it was a typo, but I think it would make more sense to toggle P1DIR rather than P1OUT. Change P1OUT only if you really want to switch to inputs. However, you should be able to toggle all of P1OUT. Any pins configured as inputs are unaffected by changes to P1OUT. So P1OUT ^= P1OUT should toggle everything at once.

There are potentially undefined states when pins are configured as inputs; TI recommends unused inputs be tied to pull-up or down resistors, which can be done internally. Another options is to make all of them outputs and ground the unused ones. Of course, that makes toggling P1OUT less useful.

Hope these thoughts help some!

metaone said...

When you want to toggle many bit in the same operation it is better to use | then + because

P1OUT = BIT1 + BIT1

makes P1OUT to be equal to BIT2 and

P1OUT = BIT1 | BIT1

makes P1OUT to be equal to BIT1

Personally, I would banish the use of + except if you really want an addition (which is often not the case when doing bits operations).

Also, many thanks for these great tutos.

Unknown said...

I agree; though I have to admit I prefer using + in one situation: initializing peripherals. I think it makes more sense in my head (visually, at least) to say P1DIR = BIT0 + BIT2 rather than P1DIR = BIT0 | BIT2, even though they have the exact same result. It just makes the code more reasonable, in my opinion.

Your comment made me go back and read the other comments, and I realized that I made a type too.. in my previous comment I intended to say it's easier to toggle P1OUT rather than P1DIR. Hopefully that was more obvious from the context. I wish there was a way to edit comments here!

Unknown said...

Oh, and now that I think about it, my suggestion of toggling P1OUT ^= P1OUT won't work; that will always return 0. P1OUT = ~P1OUT would toggle it, however. Looks like I've learned a lot since I wrote this tutorial... it's probably time to go back and edit/improve everything.

Ulric said...

Hello David,

"P1DIR = BIT4 + BIT6;
(adding the two values together is easily verified to be 0b01010000)"

How come that? I thought it would be 0x00010100.

As well as:
"You certainly can use binary directly; P1OUT = 0b01000001 is equivalent to P1OUT = BIT6 + BIT0"

Isn't it BIT2 + BIT8?

thank you very much

Unknown said...

The bit notation can be a bit confusing if you're not familiar with programming. There are 8 bits, numbered 0-7, and counted from right to left. So BIT0 is the least significant bit. The name comes from the fact that when this bit is set, it represents a value of 2^0. Likewise, BIT3 represents 2^3, and so on.

So when we say something like BIT4, it's not the 4th bit in, but rather the 5th bit from the right: 0b00010000.

Just remember that the order always looks like this:
0b(7)(6)(5)(4)(3)(2)(1)(0)
where the values in parentheses represent the bit number.

Anonymous said...

@billabot,

the documentation on TI devices is generally divided into

* datasheets, containing hard number on one or a few microcontrollers properties such as maximum power supply voltage, sink current etc, as well as what peripherals are in that specific mcu (eg X timers, Y USCI etc etc)

* the FUG/family user guide, that tells you how to use that family of mcu's, what bitfields are in what registers etc

* application notes and white papers, outlining how to solve some specific task or use some peripherals etc.

They are usually very, very easy to find. Just google for your device, eg msp430g2553, and on the TI page for that, there are links that are easy to find.

Good luck.

SB said...

I got lost somewhere. I can't make sense of the statement:

"(A better practice is to initialize the output state before we change the pin to an output.)"

If we haven't set a pin to an output first, how do we change its state?

Unknown said...

Thanks for pointing out the confusing statement; exactly the kind of thing that will be fixed in the new website I'm working on.

What you are changing is the register that holds the values of the output. Until the pin is configured as an output, it does nothing externally as it's not connected. Once the pin is configured, it takes on the value that is held in the output state register. Setting that value before making the pin an output guarantees that the pin starts in the state you want it to have.