About: Have enjoyed a mostly fun ride in an electronics and software career. Also enjoy latin dancing.


In a previous Instructable about learning ARM assembly using the Texas Instruments TI-RSLK (uses the MSP432 microcontroller), aka Lab 3 if you're doing the T.I. course, we went over some very basic instructions such as writing to a register, and conditional looping. We stepped through the the execution using the Eclipse IDE.

The teeny programs we executed did nothing to interact with the outside world.

Kind of boring.

Let's try to change that a bit today by learning a bit about the input/output ports, specifically, the digital GPIO pins.

It so happens that this MSP432 comes on a development board already has two push-button switches, an RGB LED, and a red LED, all which are tied to some GPIO ports.

This means that as we learn to setup and manipulate these pins via assembly, we can visually see those effects.

Much more interesting than just stepping through the debugger.

(We're still going to step - this will be our 'delay' function) :-D

Step 1: Let's Try Writing to / Reading From RAM

Before we jump to accessing and controlling the GPIO, we should take a small step.

Let's start by just reading and writing to a standard memory address. We know from the previous Instructable (see images there) that RAM starts at 0x2000 0000, so let's use that address.

We're going to move data between a core register (R0) and 0x2000 0000.

We begin with a basic file structure or contents of an assembly program. Please refer to this Instructable to create an assembly project using TI's Code Composer Studio (CCS), and some sample projects.

		.align  2
		.global main
		.thumbfunc main
main: .asmfunc

		; (our code will go here)


I want to add something new to the top section, were there are some declarations (directives). It will become clearer later.

ACONST	.set 0x20000000	; we will use this further down (it's a constant)

			; obviously, '0x' denotes what follows is a hex value.</p>

So our starting file contents now look like so:

		.align  2
ACONST	.set 0x20000000	; we will use this further down (it's a constant)

			; obviously, '0x' denotes what follows is a hex value.

		.global main
		.thumbfunc main
main: .asmfunc
		; (our code will go here)


Now that we have the above, let's add code in between the dashed lines.

We begin with writing to a RAM location. First we will establish the data pattern, a value, that we will be writing into the RAM. We use a core register to establish that value or data.

Note: remember that in the code, any line having a semi-colon (';') means it's all a comment after that semi-colon.


		MOV R0,#0x55		; core register R0 will contain the data we want to write to RAM location.
					; obviously, '0x' denotes what follows is a hex value.

Next, let's take a look at statements that DONT work.

;		MOV		MOV is not usable to write data to a RAM location.
;				MOV is only for immediate data into register,
;				or from one register to another; i.e, MOV R1,R0.
;		STR		must use STR.

;		STR R0,=ACONST		; Bad term in expression (the '=')
;		STR R0,0x20000000	; Illegal addressing mode for store instruction
;		STR R0,ACONST		; Illegal addressing mode for store instruction

Without explaining too much, we tried to use that 'ACONST' above. Essentially, it's a stand-in or constant instead of using a literal value like 0x20000000.

We were not able to write to write to the RAM location using the above. Let's try something else.

; seems we must use another register containing the RAM location in

; order to store to that RAM location

		MOV R1,#0x20000000	; set RAM location (not its contents, but location) into R1.
					; obviously, '0x' denotes what follows is a hex value.

		STR R0,[R1]		; write what's in R0 (0x55) into RAM (0x20000000) using R1.
					; we use another register (R1) that has RAM location address
					; in order to write TO that RAM location.

Another way of doing the above, but using 'ACONST' instead of the literal address value:

; let's do the above again, but let's use a symbol instead of a literal RAM location value.
; we want to use 'ACONST' as a stand-in for 0x20000000.
; we still have to do the '#' to signify an immediate value,
; so (see at top), we had to use the  '.set' directive.

; in order to prove this, let's change the data pattern in R0.
		MOV R0,#0xAA; ok we are ready to write to RAM using the symbol instead of literal address value
		STR R0,[R1]

The video goes into some more detail, as well as stepping through reading from the memory location.

You can also view the attached source .asm file.


Step 2: Some Basic Port Information

Now that we have a good idea how to write to / read from a RAM location, this will help us better understand how to control and use the GPIO pin

So how do we interact with the GPIO pins? From our previous look at this microcontroller and its ARM instructions, we know how to deal with its internal registers, and we know how to interact with memory (RAM) addresses. But GPIO pins?

It so happens that those pins are memory-mapped, so we can treat them much the same as memory addresses.

This means we need to know what are those addresses.

Below are the port starting addresses. By the way, for the MSP432, a "port" is a collection of pins, and not just one pin. If you are familiar with the Raspberry Pi, I believe that is different than than the situation here.

The blue circles in the above image show the writing on the board for the two switches and LEDs. The blue lines point to the actual LEDs. We won't have to touch the header jumpers.

I made the ports we're concerned with in bold below.

  • GPIO P1 : 0x4000 4C00 + 0 (even addresses)
  • GPIO P2 : 0x4000 4C00 + 1 (odd addresses)
  • GPIO P3 : 0x4000 4C00 + 20 (even addresses)
  • GPIO P4 : 0x4000 4C00 + 21 (odd addresses)
  • GPIO P5 : 0x4000 4C00 + 40 (even addresses)
  • GPIO P6 : 0x4000 4C00 + 41 (odd addresses)
  • GPIO P7 : 0x4000 4C00 + 60 (even addresses)
  • GPIO P8 : 0x4000 4C00 + 61 (odd addresses)
  • GPIO P9 : 0x4000 4C00 + 80 (even addresses)
  • GPIO P10 : 0x4000 4C00 + 81 (odd addresses)

We're not done yet. We need more information.

In order to control a port, we need several addresses. That's why in the above list, we see "even addresses" or "odd addresses".

I/O Register Address Blocks

We will need other addresses, such as:

  • Port 1 Input Register address = 0x40004C00
  • Port 1 Output Register address = 0x40004C02
  • Port 1 Direction Register address = 0x40004C04
  • Port 1 Select 0 Register address = 0x40004C0A
  • Port 1 Select 1 Register address = 0x40004C0C

And we may need others.

Ok, we now know the range of GPIO register addresses to control the single red LED.

A very important note: Each I/O Port on the MSP432 LaunchPad board is a collection of several (usually 8) pins or lines, and each can be individually set as an input or output.

This means, for example, that if you are setting values for the "Port 1 Direction Register Address", you need to be concerned with which bit (or bits) you're setting or changing at that address. More on this later.

GPIO Port Programming Sequence

The finally piece that we need, is a process or algorithm to use, to control the LED.

One-time initialization:

  • Configure P1.0 (P1SEL1REG:P1SEL0REG Register) <--- 0x00, 0x00 for normal GPIO functionality.
  • Set the Direction register bit 1of P1DIRREG as output , or HIGH.


Write HIGH to bit 0 of P1OUTREG register to turn on the Red LED

  • Call a delay function
  • Write LOW to bit 0 of P1OUTREG register to turn off the Red LED
  • Call a delay function
  • Repeat Loop

Which Input / Output Function (Configure SEL0 and SEL1)

Many of the pins on the LaunchPad have multiple uses. Example, the same pin could be standard digital GPIO, or it can also be used in UART, or I2C serial communications.

In order to use any specific function for that pin, you need to select that function. You need to configure the pin's function.

There's an image above for this step that attempts to explain this concept in visual form.

The SEL0 and SEL1 addresses form a pair combination that act as some sort of function / feature selection.

For our purposes, we want standard digital GPIO for bit 0. That means we need bit 0 for SEL0 and SEL1 to be a LOW.

Port Programming Sequence (Again)

1. Write 0x00 to P1 SEL 0 Register (address 0x40004C0A). This sets a LOW for bit 0

2. Write 0x00 to P1 SEL 1 Register (address 0x40004C0C). This sets a LOW for bit 0, setting for GPIO.

3. Write 0x01 to P1 DIR Register (address 0x40004C04). This sets a HIGH for bit 0, meaning OUTPUT.

4. Turn on the LED by writing a 0x01 to P1 OUTPUT Register (address 0x40004C02)

5. Do some sort of delay (or just single-step through while debugging)

6. Turn off the LED by writing a 0x00 to P1 OUTPUT Register (address 0x40004C02)

7. Do some sort of delay (or just single-step through while debugging)

8. Repeat steps 4 through 7.

The associated video for this step takes us through the entire process in a live demo, as we single-step through and talk through every assembly instruction, and show the LED action. Please excuse the length of the video.


Step 3: Did You Catch the One Flaw in the Video?

In the video that walks through the entire process of programming and lighting the LED, there was an extra step in the main loop, that could have been moved up to the one-time initialization.

Thank you for taking the time to go through this Instructable.

The next one expands on what we've started here.

Be the First to Share


    • Rice & Grains Challenge

      Rice & Grains Challenge
    • CNC and 3D Printing Contest

      CNC and 3D Printing Contest
    • Lamps Challenge

      Lamps Challenge