ESE101: Building an Assembly Language Playground
Today I’ll show you how to create a simple assembly language project in Code Composer Studio to give you the tools to explore the MSP430 and its assembly language on your own. We’ll use this basic assembly language project to explore the MSP430 in future posts.
Why bother learning assembly? Isn’t it a dead or useless skill? It’s true that I spend 99% of my professional life writing C or C++ code for embedded systems. Assembly is rare, and plenty of embedded software jobs don’t require any assembly language. But as I said back in the ESE101 introduction, I’m a fundamentals kind of guy. If you understand assembly language you’ll have a fundamental understanding of how a microcontroller works. You might be able to get by in embedded systems without understanding assembly, but you won’t be great without it.
So let’s get continue getting great.
Note: Andrei has a good post about knowing assembly over here.
Open CCS and select File->New->Project, then under the “Code Composer Studio” folder select “CCS Project”, like this:
Then click “Next” and then:
- Fill in the “Target:” field with “MSP430F5529”. (Remember this is the chip that comes with the MSP430 dev kit we’re using.)
- Fill in the “Project name:”
- And select the “Empty Assembly-only Project” in the lower left pane.
The three fields you need to change are circled in red in this image:
Click “Finish” and you should see a bare-bones assembly file appear, like this:
This is our assembly language playground for the next few weeks. CCS automatically generated a main.asm file with the minimum startup code so you can add assembly instructions where it says “Main loop here”.
Let’s recreate the C blinky example from last week using assembly language instead of C.
Paste these lines:
; Set GPIO P1.0 to be an output BIS.B#1, &PADIR_L ; Set output on GPIO P1.0 to high voltage BIS.B#1, &PAOUT_L ; Set output on GPIO P1.0 to low voltage BIC.B#1, &PAOUT_L ; And repeat. BIS.B#1, &PAOUT_L BIC.B#1, &PAOUT_L
below “Main loop here” comment, like this:
Note: Code must be indented at least one space from the far left edge of the page. Labels (which we'll talk about in a future post) must start on the far left edge. If you forget to indent code at least one space CCS will fail compilation with a message like "Illegal mnemonic specified".
This code might look familiar from last week’s dive into the code that turned the light on and off. Let’s walk through the instructions.
The first instruction sets bit 0 in the PADIR register to configure the GPIO P1.0 as an output:
BIS.B #1, &PADIR_L
BIS is the “bit set” instruction. It doesn’t exactly roll off the tongue; I pronounce it as its full name: “bit set.”
BIS sets all the bits that are set in its first operand in its second operand. Let’s see what that means starting with the second operand, also known as the instruction’s destination.
PADIR_L is the symbol that means the address of the PADIR_L register that controls where Port A pins are inputs or outputs. Remember that Port A refers to the combination of GPIO ports 1 and 2.
TI’s assembly language uses the ampersand (‘&’) to say “this operand is the memory location specified by the symbol after the &.” So the second operand is PADIR_L’s memory location.
The first operand is the immediate value 1. ‘1’ has one bit, bit 0, set, and so the BIS instruction sets bit 0 in PADIR_L’s memory location.
So if the value in PADIR_L started as 0, after the BIS instruction runs it should be 1. This configures GPIO pin Port 1.0 as an output.
That explains the BIS instruction, but what about the “.B” suffix?
By default most MSP430 instructions operate on 16-bit operands. Adding the “.B” suffix tells the MSP430 that this BIS.B instructions is byte-wide: it only operates on 1 byte (8-bits).
The next BIS instruction turns on the LED:
BIS.B #1, &PAOUT_L
This is just like the previous BIS instruction, except the destination argument is the PAOUT_L memory location, which controls the output voltage of the GPIO port A and B pins. This BIS instruction sets bit 0 in the PAOUT_L memory location, which is the output value for the GPIO P1.0 pin. Running this line of code should turn on the LED on your dev kit.
The next instruction turns off the LED:
BIC.B #1, &PAOUT_L
The “bit clear” instruction BIC is similar to the BIS instruction, except the source operand 1 is used to clear bits in the destination operand. In this case bit 0 of the memory location PAOUT_L is set to 0, which turns off the LED.
The final two instructions are a BIS and BIC to turn on and off the LED one more time.
If you single step through the program using Run->Step Over you should see the light turn on and off twice. You should also see the values change in the Registers window and the Memory Browser window exactly as they did in the previous post.
If you run the program past the final BIC.B instruction you added, you’ll see something funny:
The MSP430 is running some code called __TI_ISR_TRAP: this happened because the TI sample project we started with puts the __TI_ISR_TRAP code after any code you added. Since the MSP430 already ran the five instructions you added it went into this __TI_ISR_TRAP code next.
As a small challenge see if you can figure out how to put a loop around the instructions you added so that the light keeps blinking on and off instead of ending up in the __TI_ISR_TRAP code. Check out the blinky project Disassembly view from last time for hints. I’ll post an answer later in the week.
To continue using the assembly language playground we created today, check out Wikipedia’s MSP430 article, it has a great summary of the MSP430’s instructions. For even more information, check out section 6.5 of the MSP430 user’s guide.
Next time we’ll either do more with assembly, or I’ll start to explain binary numbers. Tune in next week to find out which!
This post is part of a series. Check out the complete Embedded Software Engineering 101 series here.
Playground cover image by Christopher White and Aaron Loar: