Chapter 2: Introduction to Interfacing

Jonathan Valvano and Ramesh Yerraballi

 

What makes this course so much fun is you will make your microcontroller interact with real physical devices. Input/output devices are critical components of an embedded system. In this chapter, you will learn how to connect switches and LEDs to the microcontroller. You will use switches to input data and use LEDs to output results.  The switch, LED, and LaunchPad components will then be combined to create a system. To interface the switches and LEDs, you will need a solid understanding of Ohm's Law. If you may need to review current, voltage, power, and resistance, please see Appendix: Electronics.


Table of Contents:

Return to book table of contents

 

Video 2.0. Circuit elements and Interfacing them to a Microcontroller

Reference material relative to this chapter: 

2.1. I/O Ports and Pins

The external devices attached to the microcontroller provide functionality for the system. A pin is a hardware connection between the chip and its external world. Most pins are used for input or output. A port is a collection of input/output pins. An input pin is hardware on the microcontroller that allows information about the external world to be entered into the computer. The microcontroller also has hardware called an output pin to send information out to the external world. Other than input/output pins, microcontrollers use some pins for power, clock, and debugging.

Figure 2.1.1. There are 60 I/O pins on the MSPM0G3507, grouped into two ports.

An interface is defined as the collection of the I/O port, external electronics, physical devices, and software, which combine to allow the computer to communicate with the external world. An example of an input interface is a switch, where the operator pushes or releases the switch, and the software can recognize the switch position. An example of an output interface is a light-emitting diode (LED), where the software can turn the light on and off, and the operator can see whether or not the light is shining. There is a wide range of possible inputs and outputs, which can exist in either digital or analog form. In general, we can classify I/O interfaces into four categories

       Parallel - binary data are available simultaneously on a group of pins

       Serial - binary data are available one bit at a time on a single pin

       Analog - data are encoded as an electrical voltage, current, or power on a single pin

       Time - data are encoded as a period, frequency, pulse width, or phase shift on a single pin

Video 2.1.1. Four categories of Input/Output Interfaces

 

The General Purpose Input Output (GPIO) port is a collection of input/output pins, and it allows the software to read data from input pins (Figure 2.1.2) and write data to output pins (Figure 2.1.3). Initialization software specifies whether a pin will be an input or output.

Figure 2.1.2. A GPIO input pins allows for input.

Video 2.1.2. A GPIO input pins allows for input.

Figure 2.1.3. A GPIO output pins allows for output.

Video 2.1.3. Software writes to DOUT register to perform output.

An I/O register is a location in memory with which software can interface with the I/O port, see Table 2.1.1. On most embedded microcontrollers, the I/O ports are memory mapped. This means the software can access an input/output port simply by reading from or writing to the appropriate address. It is important to realize that even though I/O operations "look" like reads and writes to memory variables, the I/O ports often DO NOT act like memory. For example, some bits are read-only, some are write-only, some can only be cleared, others can only be set, and some bits cannot be modified. There are include statements for both assembly and C that will define symbolic names for the I/O registers as their corresponding addresses. To make our software easier to understand we will use the symbolic definitions for the I/O ports, like GPIOA_DOUT31_0, and not the specific address, like 0x400A1280.

AddressAccess   31 ...   28  27 ...   1  0Name
0x400A1280  R/W DIO31  ...  DIO28  DIO27  ...  DIO1  DIO0 GPIOA_DOUT31_0
0x400A1380   R DIO31  ...  DIO28 DIO27 ...  DIO1  DIO0 GPIOA_DIN31_0
0x400A3280  R/W    -  -   -  DIO27  ...  DIO1  DIO0GPIOB_DOUT31_0
0x400A3380   R    -  -   -  DIO27  ...  DIO1 DIO0GPIOB_DIN31_0

Table 2.1.1. I/O registers to perform input/output to Ports A and B.

There are many more registers with which we could perform I/O, but we will begin with these simple interactions:


The DIN31_0 register is read only. Writing to DIN31_0 has no effect. The DOUT31_0 register is read/write. The register DOUT31_0 does behave like regular memory.

The DOUTSET31_0 DOUTCLR31_0 DOUTTGL31_0 registers are write only, see Table 2.1.2. Reading from these registers has no effect. Writing 0's to these registers have no effect. Writing 1's to bits in these registers will modify the corresponding output pins. We use these three registers when different unrelated software modules need to access the same GPIO port.

AddressAccess   31 ...   28  27 ...   1  0Name
0x400A1290  W DIO31  ...  DIO28  DIO27  ...  DIO1  DIO0 GPIOA_DOUTSET31_0
0x400A12A0   W DIO31  ...  DIO28 DIO27 ...  DIO1  DIO0 GPIOA_DOUTCLR31_0
0x400A12B0   W DIO31  ...  DIO28 DIO27 ...  DIO1  DIO0 GPIOA_DOUTTGL31_0
0x400A3290  W    -  -   -  DIO27  ...  DIO1  DIO0GPIOB_DOUTSET31_0
0x400A32A0   W    -  -   -  DIO27  ...  DIO1 DIO0GPIOB_DOUTCLR31_0
0x400A32B0   W    -  -   -  DIO27  ...  DIO1 DIO0GPIOB_DOUTTGL31_0

Table 2.1.2. I/O registers to perform friendly output.

The DOE31_0 register is configured once during initialization, see Table 2.1.3.

AddressAccess   31 ...   28  27 ...   1  0Name
0x400A12C0  R/W DIO31  ...  DIO28  DIO27  ...  DIO1  DIO0 GPIOA_DOE31_0
0x400A32C0  R/W    - -    - DIO27  ...  DIO1  DIO0GPIOB_DOE31_0

Table 2.1.3. We set bits in the Data output enable register make that GPIO pin an output.

Each of the 60 I/O pins on the MSPM0G3507 has a 32-bit Pin Control Management Register (PINCM). We write to this register once during initialization to configure the mode. Table 2.1.4 shows some of the bits we will configure.

Name Pin ...  18 17 18 ...  7 6 5-0
IOMUXPA0  PA0 ...  INENA  PIPU  PIPD   ...  PC  -  PF 
IOMUXPA1  PA1 ...  INENA  PIPU  PIPD   ...  PC  -  PF 
   ...
IOMUXPB26  PB26  ...  INENA  PIPU  PIPD   ...  PC  -  PF 
IOMUXPB27  PB27  ...  INENA  PIPU  PIPD   ...  PC  -  PF 

Table 2.1.4. Each port pin has a separate Pin Control Management Register, also called IOMUX.


: What do you suppose it means that PF is a 6-bit field?

Before we discuss hardware, let's develop a set of software functions that configure and use PB1 as an output and PB0 as an input. Program 2.1.1 shows software to initialize PB1 as an output. 0x81 is the magic code we write to the PINCM register to make the pin an output.

.include "../inc/msp.s"

PB1_Init: // PB1 output

  MOVS R1,#0x81   

  LDR  R0,=IOMUXPB1 // PINCM

  STR  R1,[R0]   // PB1 is GPIO

  LDR  R0,=GPIOB_DOE31_0

  LDR  R1,[R0]   // previous

  MOVS R2,#0x02  // mask

  ORRS R1,R1,R2  // friendly

  STR  R1,[R0]   // enable out

  BX   LR

#include "msp.h"

void PB1_Init(void){

  IOMUX->SECCFG.PINCM[PB1INDEX] = 0x81;

  GPIOB->DOE31_0 |= 0x02; // PB1 output;

}

Program 2.1.1. Software that initializes PB1 as an output.

: Change the assembly code to initialize PB2 as output.

Video 2.1.4. Initialization PB1 as output.

Program 2.1.2 shows software to initialize PB0 as an input. Writing the value 0x00040081 to the PINCM register specifies the pin as GPIO input without internal pull up or pull down resistors.

PB0_Init: // PB0 input

  LDR  R1,=IOMUXPB0 // PINCM

  LDR  R0,=0x00040081   

  STR  R0,[R1] // GPIO input

  BX   LR

void PB0_Init(void){

  IOMUX->SECCFG.PINCM[PB0INDEX] = 0x00040081;

}

Program 2.1.2. Software that initializes PB0 as an input.

: Change the assembly code to initialize PB3 as input.

Video 2.1.5. Initialization PB0 as input.

Program 2.1.3 shows two functions that output to PB1. To change one bit in the port we read the previous values, modify the bit of interest, and then write the entire value back to the output register.

PB1_Set: // Make PB1 high

  LDR  R0,=GPIOB_DOUT31_0

  LDR  R1,[R0]   // previous

  MOVS R2,#0x02  // mask

  ORRS R1,R1,R2  // set bit

  STR  R1,[R0]   // output

  BX   LR


PB1_Clr: // Make PB1 low

  LDR  R0,=GPIOB_DOUT31_0

  LDR  R1,[R0]   // previous

  MOVS R2,#0x02  // mask

  BICS R1,R1,R2  // clear bit

  STR  R1,[R0]   // output

  BX   LR

void PB1_Set(void){ // Make PB1 high

  GPIOB->DOUT31_0 |= 0x02; // PB1=1;

}

 

 

void PB1_Clr(void){ // Make PB1 low

  GPIOB->DOUT31_0 &= ~0x02; // PB1=0;

}

Program 2.1.3. Software outputs to PB1.

: Change the assembly code so it outputs to PB2 instead of PB1.

Video 2.1.6. Software that outputs to PB1.

Program 2.1.4 presents a function that inputs from PB0. To read one bit in the port, we read the entire DIN31_0 register, and then we select the bit of interest using the logical AND operation.

// Return R0 with value of PB0

PB0_In: // read PB0

  LDR  R1,=GPIOB_DIN31_0

  LDR  R0,[R1]   // all bits

  MOVS R2,#0x01  // mask

  ANDS R0,R0,R2  // select bit

  BX   LR

uint32_t PB0_In(void){ // Read PB0

  return GPIOB->DIN31_0&0x01;

}

Program 2.1.4. Software inputs from to PB0.

: Change the assembly code so it inputs from PB3 instead of PB0.

Video 2.1.7. Software that inputs from PB0.

 

Quiz 2.1

 

2.2. MSPM0G3507 LaunchPad

The heart of the LaunchPad is the MSPM0G3507 microcontroller. The LaunchPad evaluation board (Figure 2.2.1) is a low-cost development board available as part number LP-MSPM0G3507. The microcontroller board provides an integrated In-Circuit Debug Interface (ICDI), which allows programming and debugging of the onboard MSPM0G3507 microcontroller. The USB cable is used by the debugger (ICDI), and it includes a serial port (UART) to send data to the PC.

 

Figure 2.2.1. LaunchPad based on the MSPM0G3507.

Video 2.2.1. Overview of MSPM0G3507 LaunchPad

Sometimes we run bad code on the MSPM0, and the code crashes hard. Other times we try a weird sequence of debugging commands and the debugger freezes. In both cases, we might put the MSPM0 in a state where it can not be programmed. We call this failure state bricked. A bricked MSPM0 shows red error messages when trying to program a project that used to work. We can unbrick the MSPM0 by forcing a physical reset of the bootstrap loader. The BSL_Invoke button is labelled S1 and is located near LED1. The reset button is on the same edge as the USB cable. To unbrick the MSPM0, we

  1. Press-and-hold S1
  2. Press and release the Reset button (while holding S1)
  3. Within the next 10secs, attempt to program the MSPM0, Debug command
  4. After download is complete, release S1.

Video 2.2.2. How to unbrick the MSPM0G3507.

We will begin by interacting with the switches and LEDs on the LaunchPad. For example, bit 0 of Port A is called PA0 and it controls the red LED on the LaunchPad. Figure 2.2.2 shows there are switches connected to PA18 and PB21. There is one 3-color LED connected to PB22-PB27-PB26. The MSPM0 LaunchPad evaluation board has two switches, one red LED1 and one 3-color LED2. See Figure 2.2.2. The S1 switch is positive logic. The S2 switch is negative logic and will require activation of the internal pull-up resistor. See the LaunchPad.c file for software to configure the LaunchPad I/O. Pins PA11-PA10 create a serial port, which is linked through the debugger cable to the PC. The serial link is a physical UART as seen by the MSPM0 and mapped to a virtual COM port on the PC.

Figure 2.2.2. Switch and LED interfaces on the MSPM0G3507 LaunchPad Evaluation Board. The jumpers J4 J5 J6 J7 J8 can be removed so the corresponding pin can be used for its regular purpose.

Video 2.2.3. MSPM0 LaunchPad Circuit***needs recording***

: How does the software input from Port A?

: How does the software output to Port B?

Interactive Tool 2.2.1

The following tool allows you to test your understanding of what happens when you WRITE to the DOUT register for Port A or Port B.
Note, writing to input pins has no effect. See what happens if you click on one of the two switches.



Enter 0 or 1 into the following fields and click run: 

   LDR  R0,=GPIOA_DOUT31_0
   MOVS R1,#
   STR  R1,[R0]


   LDR  R0,=GPIOB_DOUT31_0
   LDR  R1,=( <<27)|( <<26)|( <<22)
   STR  R1,[R0]


In most cases, a software module needs access to only some of the port pins. If two or more software modules access the same port, a conflict will occur if one module changes modes or output values set by another module. It is good software design to write friendly software, which only affects the individual pins as needed. Friendly software does not change the other bits in a shared register. Conversely, unfriendly software modifies more bits of a register than it needs to. The difficulty of unfriendly code is each module will run properly when tested by itself, but weird bugs result when two or more modules are combined.

Video 2.2.4. Writing friendly code

The best way for microcontrollers to access individual port bits is to use read-modify-write software to change just the bits of interest. A read-or-write sequence can be used to set bits. Recall from Figure 2.2.2 there is a three color LED connected to PB27,PB26,PB22. Program 2.2.1 presents software that writes 1's to PB27,PB26,PB22 in a friendly manner, making the LED white.

TurnOnLED:

  LDR  R1, =GPIOB_DOUT31_0

  LDR  R0, [R1]    // previous

// R2 is the mask for bits 27,26,22

  LDR  R2,=((1<<27)|(1<<26)|(1<<22))

  ORRS R0, R0, R2  // set bits 27,26,22

  STR  R0, [R1]    // perform output

  BX   LR

// make PB27,PB26,PB22 high

void TurnOnLED(void){

  GPIOB->DOUT31_0 |=

   ((1<<27)|(1<<26)|(1<<22));

}

Program 2.2.1. Software to turn on the 3-color LED.

: What does (1<<27) mean?

A read-and-write sequence can also be used to clear one or more bits. Program 2.2.2 presents software that writes 0's to PB27,PB26,PB22 in a friendly manner, turning the LED off.

TurnOffLED:

  LDR  R1, =GPIOB_DOUT31_0

  LDR  R0, [R1]   // previous

// R2 is the mask for bits 27,26,22

  LDR  R2,=((1<<27)|(1<<26)|(1<<22))

  BICS R0, R0, R2 // clear bits

  STR  R0, [R1]   // perform output

  BX   LR

// make PB27,PB26,PB22 low

void TurnOffLED(void){

  GPIOB->DOUT31_0 &=

   ~((1<<27)|(1<<26)|(1<<22));

}

Program 2.2.2. Software to turn off the 3-color LED.


The red LED on the LaunchPad is negative logic, so in Program 2.2.3 we clear PA0 to turn on the LED, and in Program 2.2.4 we set PA0 to turn the LED off. In both cases, code is friendly because the software does not affect the other 31 bits of GPIOA_DOUT31_0.

LaunchPad_LED1on:

  LDR  R1, =GPIOA_DOUT31_0

  LDR  R0, [R1]   // previous

  MOVS R2,#0x01

  BICS R0, R0, R2 // clear bit 0

  STR  R0, [R1]   // perform output

  BX   LR

// make PA0 low

void LaunchPad_LED1on(void){

  GPIOA->DOUT31_0 &= ~0x01;

}

Program 2.2.3. Software to turn on the red LED.

LaunchPad_LED1off:

  LDR  R1, =GPIOA_DOUT31_0

  LDR  R0, [R1]    // previous

  MOVS R2,#0x01 // mask

  ORRS R0, R0, R2  // set bit 0

  STR  R0, [R1]    // perform output

  BX   LR

// make PA0 low

void LaunchPad_LED1off(void){

  GPIOA->DOUT31_0 |= 0x01;

}

Program 2.2.4. Software to turn off the red LED.

Maintenance Tip: When performing output to pins, remember to store a new value to the port. Actual output comes when we write to the DOUT register.


Quiz 2.2

 

2.3. Interfacing the Microcontroller to a solderless breadboard

To build circuits, we’ll use a solderless breadboard, also referred to as a protoboard. The holes in the protoboard are internally connected in a systematic manner, as shown in Figure 2.3.1. The long rows of holes along the outer sides of the protoboard are electrically connected. Some protoboards like the one in Figure 2.3.1 have four long rows (two on each side), while others have just two long rows (one on each side). We refer to the long rows as power buses. If your protoboard has long rows on the side, we will connect one long row to +3.3V and another long row to ground. In the middle of the protoboard, you’ll find two groups of holes placed in a 0.1 inch grid. Each adjacent row of five pins is electrically connected. We insert components like resistors, switches and LEDs into these holes. If integrated circuits (IC) are to be placed on the protoboard, it is done such that the two rows of pins straddle the center valley.

 

Video 2.3.1. Connecting PB0 and PB1 to a solderless breadboard.


Figure 2.3.1. The pins on each of the four long rows are connected. The 5 pins in each short row are connected. Place a +3.3V wire from the Launchpad to one long row. Place a ground wire from the LaunchPad to another long row.

To build a circuit and to connect the circuit to the microcontroller we will use 22-gauge or 24-gauge solid wires. We strip off about 1/4 to 1/2 inch of insulation so the bare wire can be pushed straight into a hole. We only push one wire into a hole keeping track of which rows are internally connected.


Figure 2.3.2. Solderless breadboard used in the following checkpoints.

: In Figure 2.3.2, the five colored lines represent wires plugged into the protoboard. All five wires are plugged into row 21. Which wires are connected via the protoboard?

: In Figure 2.3.2, what is the typical use of the long row of connections near the red line?

: In Figure 2.3.2, what is the typical use of the long row of connections near the blue line?


 

Quiz 2.3

 

2.4. Software Delay Loops

Time is one of the most important aspects of an embedded system. Throughout the course we will develop more complex, but more accurate methods for the software to control when events occur. We will begin with the most simple, a software delay loop. When performing Labs 2 and 3 with software delay loops, you will witness this method is inaccurate and hard to manage. Therefore for Labs 2 and 3 we expect the timing to be approximate. Lab 4 will introduce a hardware timer, and Lab 5 will introduce interrupts. Program 2.4.1 shows one possible way to create a software delay loop. With a bus clock of 80 MHz, this delay function is 12.5ns*count. The NOP instruction is added make 4 bus cycles each time through the loop. Subtracting 4 inside the loop creates the effect that the delay in bus cycles matches the input parameter in R0. For example, in Program 2.4.2 we call Delay with R0 equal to 40 million, it will wait 500 ms. To determine the actual delay you will have to run this code on your microcontroller and measure the delay with a scope or logic analyzer.

// Input: R0 is count, the amount to delay in bus cycles
       .align 2
Delay: SUBS R0,R0,#2
dloop: SUBS R0,R0,#4 // 4 cycles per loop
       NOP
       BHS  dloop
       BX   LR

Program 2.4.1. Software delay loop.

: In the Program 2.4.1, why do we subtract 2 once?

: In the Program 2.4.1, why do we subtract 4 each time through the loop?

Video 2.4.1. Using a software delay loop to toggle an LED.

main: MOVS R0,#0
      BL   Clock_Init80MHz
      BL   LaunchPad_Init
loop: BL   LaunchPad_LED1on
      LDR  R0,=40000000 // 1/2 sec
      BL   Delay
      BL   LaunchPad_LED1off
      LDR  R0,=40000000 // 1/2 sec
      BL   Delay
      B    loop

int main(void){
  Clock_Init80MHz(0);
  LaunchPad_Init();
  while(1){
    LaunchPad_LED1on();
    Delay(40000000); // 1/2 sec
    LaunchPad_LED1off();
    Delay(40000000); // 1/2 sec
  }
}

Program 2.4.2. LED toggles every 500ms. See Programs 2.2.3 and 2.2.4.

: Write assembly code to delay 1 second.


2.5. Switch/button Interfacing

Before interfacing switches, let's explain how an input port converts voltage into digital logic. Most pins on the MSPM0 microcontrollers are not 5V-tolerant, meaning an input voltage above 3.6 V will be damage the chip. Similiarly, input voltages below 0 will also damage the chip. Voltages from 2.31 to 3.3 V are considered high, and voltages from 0 to 0.99 V will be considered as low. Since the microcontroller is built with CMOS logic, the input current will be less than 50 nA. This is so small, for most situtations, we can assume the input current is 0.

The first input device we will interface is the switch. Once manipulated by a human, a toggle switch remains in its on or off position. In contrast, a tactile switch or button remains in the on position only when pressed by the human. The button returns to the off position when released by the human.

Figure 2.5.1. Two kinds of switches: toggle and tactile.

Switches allow the human to input binary information into the computer. Typically we define the asserted state, or logic true, when the switch is pressed. Contact switches can also be used in machines to detect mechanical contact (e.g., two parts touching, paper present in the printer, window open/closed, or wheels on the ground etc.) A single pole single throw (SPST) switch has two connections as shown in Figure 2.5.2. In a normally open switch (NO), the resistance between the connections is infinite (over 100 MΩ on the B3F tactile switch) if the switch is not pressed, and the resistance is zero (under 0.1 Ω on the B3F tactile switch) if the switch is pressed. 

Figure 2.5.2. Single Pole Single Throw (SPST) Switch interface. When not pressed, the switch is open (over 100MΩ). When pressed, the switch is closed (under 0.1Ω).

We encourage you to read the data sheet for your switch and find which pins connect to the switch. Data sheet for the B3F-1059

Video 2.5.1. B3F Switch Datasheet

To convert the 100MΩ/0.1Ω resistance into a digital signal, we can use a pull-down resistor to ground or a pull-up resistor to +3.3V as shown in Figure 2.5.3. Notice that 10 kΩ is 100,000 times larger than the on-resistance of the switch and 10,000 times smaller than its off-resistance. Another way to choose the pull-down or pull-up resistor is to consider the input current of the microcontroller input pin. The current into the microcontroller will be less than 50 nA (shown as IIL and IIH in the data sheet). So, if the current into microcontroller is 50 nA, then the voltage drop across the 10 kΩ resistor will be 0.0005 V, which is negligibly small. With a pull-down resistor shown on the right side of Figure 2.5.3, the digital signal will be low if the switch is not pressed and high if the switch is pressed. The signal being 3.3V when the switch is pressed is defined as positive logic, because the asserted switch state is a logic high. Conversely, with a pull-up resistor shown on the left side of Figure 2.5.3, the digital signal will be high if the switch is not pressed and low if the switch is pressed. The signal being 0V when the switch is pressed is defined as negative logic, because the asserted switch state is a logic low.

Figure 2.5.3. Two ways to interface a Single Pole Single Throw (SPST) Switch to the microcontroller.

: On the left side of Figure 2.5.2, when the switch is pressed, will the signal s be a logic 0 or logic 1?

: On the right side of Figure 2.5.2, when the switch is pressed, will the signal t be a logic 0 or logic 1?

Video 2.5.2. Circuit for Switch Interface (note: input current is 50nA, not 2uA)

To interface a switch we connect it to a pin, and we initialize the pin as an input. Figure 2.5.4 connects the switch to PA8, but any microcontroller pin could have been used.

Figure 2.5.4. Interface of a switch to a microcomputer input.

Figure 2.5.5 shows how we could build this circuit with a protoboard and a LaunchPad. The brown-black-orange resistor is 10kΩ. The B3F switch should plug directly into the protoboard. The actual switch is across the pins that are closer to each other. The pins that are farther from each other will fit across the gap in the middle of the protoboard. It doesn't matter what color the wires are, but in this figure the wires are black, purple and blue. The two black wires are ground, the two purple wires are +3.3V, and the blue wire is the signal in, which connects the switch to pin PA8 of the microcontroller.


Figure 2.5.5. Construction of the interface of a B3F switch to a microcomputer input on PA8.

: Notice the switch in Figure 2.5.4 has four connections to the breadboard, but the switch in Figure 2.5.4 circuit only has two connections. What are the two extra connections on the actual switch?

The initialization function will set the direction register to input and enable the pin. This code assumes LaunchPad_Init() has been called. The function LaunchPad_Init() should be called exactly once at the start of the system, because it will reset all of Port A and Port B. Notice the software is friendly because it just affects PA8 without affecting the other bits in Port A. The input function reads Port A and returns a true (0x100) if the switch is pressed and returns a false (0) if the switch is not pressed. The software in Program 2.5.1 is called a driver, and it includes an initialization, which is called once, and a second function that can be called to read the current state of the switch. Writing software this way is called an abstraction, because it separates what the switch does (Init and Input) from how it works (PortA, bit 5, and MSPM0). The input function reads the entire port and selects bit 5 using a logical AND.

// Assembly version
Switch_Init:
  LDR  R1,=0x00040081
  LDR  R0,=IOMUXPA8
  STR  R1,[R0]  // PA8 is in
  BX   LR
Switch_Input:   // read PA8 input
  LDR  R1,=GPIOA_DIN31_0
  LDR  R3,=0x100
// mask for bit 8
  LDR  R0,[R1]  // all of GPIOA
  ANDS R0,R0,R3 // just bit 8
  BX   LR

// C version
// initialize PA8 as input
void Switch_Init(void){
  IOMUX->SECCFG.PINCM[PA8INDEX]
      = 0x00040081;
}

// return 0x100 if pressed
// 0x000 if not pressed
uint32_t Switch_Input(void){
  return GPIOA->DIN31_0&0x0100;
}

Program 2.5.1. Software interface for a switch on PA8.

Maintenance Tip: When interacting with just some of the bits of an I/O register it is better to modify just the bits of interest, leaving the other bits unchanged. In this way, the action of one piece of software does not undo the action of another piece. Modifying just the bits of interest is called friendly.

Observation: One of the complicating issues with mechanical switches is they can bounce (oscillate on and off) when touched and when released. The contact bounce varies from switch to switch and from time to time, but usually bouncing is a transient event lasting less than 5 ms. We can eliminate the effect of bounce if we design software that waits at least 10 ms between times we read the switch values.

: What does it mean to classify this switch interface as positive logic?

 

Quiz 2.5

 

2.6. LED Interfacing

Before interfacing LEDs, let's review how an output port converts digital logic into voltage. Pins PA31, PA28, PA11, and PA10 can be high drive outputs, sourcing/sinking up to 20mA. The remaining pins are standard drive and can source or sink up to 6mA as an output.

A light emitting diode (LED) emits light when an electric current passes through it. LEDs have polarity, meaning current must pass from anode to cathode to activate, see Figure 2.6.1. The anode is labelled a or + , and cathode is labelled k or -. The cathode is the short lead and there may be a slight flat spot on the body of round LEDs. Thus, the anode is the longer lead. The brightness of an LED depends on the applied electrical power (P=Vd*Id). Notice in  the LED operating range of 5 to 40 mA, the voltage only changes from 1.8 to 2.2V. For this reason, we will establish the desired brightness by setting the LED current rather than trying to set the LED voltage.

Figure 2.6.1. Positive logic LED interface (Lite-On LTL-10223W).

: Notice black dot in Figure 2.9 shows Vd=1.9V and Id=10mA for a power of 19mW. What would be the LED power if the LED voltage were to increase just a little bit toVd=2V?

We encourage you to open up the data sheet for your LED and find the curve similar to Figure 2.6.1. Data sheet for HLMP-4700.

Video 2.6.1. LED Datasheet

Video 2.6.2. Circuit for LED Interface

When the LED current is less than 6 mA, we can interface it directly to an output pin without using any integrated circuits. The LED shown in Figure 2.6.2a has an operating point of 1.6 V and 1 mA.

Figure 2.6.2. Interface of a low current LED


For the positive logic interface (Figure 2.6.2b) we calculate the resistor value based on the desired LED voltage and current


    R = (VOH - Vd) / Id = (3.1 - 1.6) /0.001 = 1500Ω

where VOH is the output high voltage of the microcontroller output pin, which will be about 3.1V when sourcing 1mA of current. Since VOH can vary from 2.4 to 3.3 V, it makes sense to choose a resistor from a measured value of VOH, rather than the minimum value of 2.4 V. Negative logic means the LED is activated when the software outputs a zero. For the negative logic interface (Figure 2.6.2c) we use a similar equation to determine the resistor value


    R = (3.3 - Vd  - VOL ) / Id = (3.3 - 1.6 - 0.2) /0.001 = 1500Ω  

where VOL is the output low voltage of the microcontroller output pin, which will be about 0.2V when sinking 1mA of current. Since VOL can vary from 0 to 0.4 V, it makes sense to choose a resistor from a measured value of VOL, rather than the maximum value of 0.4 V.

Figure 2.6.3 shows how we could build this circuit with a protoboard and a LaunchPad. The brown-green-red resistor is 1.5kΩ. The LED should plug directly into the protoboard. The longer lead on the LED is the positive or anode. It doesn't matter what color the wires are, but in this figure the wires are black, red and green. The two black wires are ground, and the green wire is the signal out, which connects the LED anode to pin PB1 of the microcontroller.


Figure 2.6.3. Construction of the interface of an LED to the PB1 output.

: What resistor value in of Figure 2.6.2 is needed if the desired LED operating point is 1.8V and 5 mA? Use the positive logic interface and, VOH of 3.2V.

: What resistor value in of Figure 2.6.2 is needed if the desired LED operating point is 1.7V and 2 mA? Use the negative logic interface and, VOL of 0.2V.


A driver or firmware is a set of software functions to facilitate the use of an input/output port. Program 2.6.1 is an simple example of driver because it encapulates everything we might wish to do with an LED. Drivers will include an initialization, e.g., LED_Init, which is called once at the beginning. The other functions in the driver can be called to turn on and off the LED as needed. Writing software this way is called an abstraction, because it separates what the LED does (Init, On, Off) from how it works (PortB, bit 1, MSPM0). Program 2.6.1 shows two ways to change PB1. Both ways are friendly, but using the DOUTSET and DOUTCLR registers is faster and simpler. This code assumes LaunchPad_Init has been called.

// Assembly version
LED_Init: // PB1 output
  LDR  R1,=0x00000081
  LDR  R0,=IOMUXPB1
  STR  R1,[R0] // PB1 is out
  LDR  R0,=GPIOB_DOE31_0
  LDR  R1,[R0]
  MOVS R2,#0x02 // PB1
  ORRS R1,R1,R2
  STR  R1,[R0]  // enable out
  BX   LR
LED_OffSlow:
  MOVS R2,#0x02 // mask for bit 1
  LDR  R1,=GPIOB_DOUT31_0
  LDR  R0,[R1]
  BICS R0,R0,R2 // clear bit 1
  STR  R0,[R1]  // PB1=0
  BX   LR
LED_Off:
  MOVS R2,#0x02 // mask for bit 1
  LDR  R1,=GPIOB_DOUTCLR31_0
  STR  R0,[R1]  // PB1=0
  BX   LR
LED_OnSlow:
  MOVS R2,#0x02 // mask for bit 1
  LDR  R1,=GPIOB_DOUT31_0
  LDR  R0,[R1]
  ORRS R0,R0,R2 // set bit 1
  STR  R0,[R1]  // PB1=1
  BX   LR
LED_On:
  MOVS R2,#0x02 // mask for bit 1
  LDR  R1,=GPIOB_DOUTSET31_0
  STR  R0,[R1]  // PB1=1
  BX   LR

// C version
void LED_Init(void){
  IOMUX->SECCFG.PINCM[PB1INDEX]
= 0x00000081; // regular output
  GPIOB->DOE31_0 |= 0x02;
// enable
}

void LED_OffSlow(void){
  GPIOB->DOUT31_0 &= ~0x02;
}

void LED_Off(void){
  GPIOB->DOUTCLR31_0 = 0x02;
}

void LED_OnSlow(void){
  GPIOB->DOUT31_0 |= 0x02;
}

void LED_On(void){
  GPIOB->DOUTSET31_0 = 0x02;
}

Program 2.6.1. Software driver for an LED on PB1

: What does it mean to classify this LED interface as positive logic?

Observation: One of the advantages of using DOUTSET and DOUTCLR is the software becomes thread-safe, meaning it will operate properly when executed in a system with interrupts. Programs LED_OnSlow and LED_OffSlow have critical sections, meaning they will not operate properly when executed in a system with interrupts. We will learn more about critical sections in Chapter 8.

If the LED current is above 6 mA, we cannot connect it directly to the microcontroller because the high currents may damage the chip. There are many possible solutions to interface an LED needing more than 8 mA of current. Examples include 7405, 7406 or PN2222. We have chosen the ULN2003B because it has 7 drivers in each package. The ULN2003B comes in a DIP package with 7 base (B) signals, 7 collector (C) signals and one emitter (E) pin. Figure 2.6.4 shows one driver in the ULN2003B.The B signals are the inputs, the C signals are the outputs, and the E pin will be grounded. If the base input is high, the collector output will be low (0.5V). If the base input is low, the collector output will float (neither high nor low).

Figure 2.6.4. The ULN2003B LED driver.


For high current LEDs we typically use the 5V supply rather than the 3.3V, because the available current at 5V is often much more than the available current at 3.3V. Figure 2.6.5 shows how to interface a 10 mA 1.9V LED using the ULN2003B. When the software writes a logic 1 to the output port, the input to the ULN2003B becomes high, output from the ULN2003B becomes low, 10 mA travels through the LED, and the LED is on. When the software writes a logic 0 to the output port, the input to the ULN2003B becomes low, output from the ULN2003B floats (neither high nor low), no current travels through the LED, and the LED is dark.


Figure 2.6.5. Interface a high current LED using a ULN2003B driver.

The value of the resistor is selected to establish the proper LED current. When active, the LED voltage will be between 1.8 and 2.2 V, and the power delivered to the LED will be controlled by its current. If the desired brightness requires an operating point of 1.9 V at 10 mA, then the resistor value should be


    R = (5 - Vd - VCE) / Id = (5 - 1.9- 0.5) /0.01 = 260Ω

     

where Vd, Id is the desired LED operating point, and VCE is the output low voltage of the LED driver. If we use a standard resistor value of 270Ω in place of the 260Ω, then the current will be (5-1.9-0.5V)/270Ω, which is about 9.6 mA. This slightly lower current is usually acceptable.


: What resistor value in Figure 2.6.5 is needed if the desired LED operating point is Vd=1.7V and Id=11 mA?

 

Quiz 2.6

 

2.7. Pulse width modulation

Controlling time is an important function of an embedded system. One of the methods software can perform to set the delivered power to an external device is pulse width modulation (PWM). The basic idea is to oscillate an output so fast the external device does not respond to the individual on and off events. Rather, the delivered power will be a function of the average, called duty cycle. Let H be the time the output is high, and L the time the output is low. For PWM we will set P=H+L as a constant, and adjust H and L. The duty cycle is defined as

  Duty Cycle = H/(H+L)

The human eye can see a flashing LED up to about 10 Hz. If we flash the LED at 100 Hz, our eyes will see a constant light, but the brightness of the LED will depend linearly on the duty cycle. In particular if the LED operating point is Vd, Id, the LED power will be

  Power = Vd*Id*H/(H+L)

Video 2.7.1. Pulse Width Modulation ***needs recording.

Program 2.7.1 presents a simple PWM output. Notice that this implementation uses all the processor time. H can vary from 4 to 799996 bus cycles, while L varies from 799996 to 4. H+L should be constant, in this example 800,000*12.5ns = 10ms.

main: MOVS R0,#0
      BL   Clock_Init80MHz
      BL   LaunchPad_Init
      BL   LED_Init // PB1 output
// R4 is H, the time the LED is on
      LDR  R4,=600000
// R5 is L, the time the LED is off
      LDR  R5,=200000
PWM:  BL   LED_On  // PB1=1
      MOVS R0,R4   // H
      BL   Delay
      BL   LED_Off // PB1=0
      MOVS R0,R5   // L
      BL   Delay
      B    PWM

int main(void){
  Clock_Init80MHz(0);
  LaunchPad_Init();
  LED_Init(); // PB1 output
  while(1){
    LED_On(); // PB1=1
    Delay(600000);
    LED_Off(); // PB1=0
    Delay(200000);
  }
}

Program 2.7.1. Software implementation of 75% PWM (see also Program 2.6.1).

: If H+L=100000, creating a 100 Hz wave in Program 2.7.1, how many different duty cycles can be created? How bits of precision does this represent?

 

Interactive Tool 2.7.1

The following tool allows you see the effect of Period and DutyCycle in Program 2.7.1. Dragging the slider bars sets H+L to Period, and set H to Period*DutyCycle.

: Drag the handle to set the period to be about 500ms. At what rate should the LED be flashing?

: What do your eyes observe if the period is less than 50ms?

: As you drag just the duty cycle bar left and right, does the period change?

Observation: Using PWM we can create virtually any color on the 3-color LED. For example, the burnt orange color code for the Texas Longhorns logo is Pantone: PMS 159 C, Hex Color: #BF5700, RGB: (191, 87, 0). To make burnt orange we oscillate the red signal at a duty cycle of 191/255, oscillate green at a duty cycle at 87/255, and set the blue signal to 0.

 

Quiz 2.7

 

2.8. Designing a Security System

Some problems are so unique that they require the engineer to invent completely original solutions. Most of the time, however, the engineer can solve even complex problems by building the system from components that already exist. Creativity will still be required in selecting the proper components, making small changes in their behavior (tweaking), arranging them in an effective and efficient manner, and then verifying the system satisfies both the requirements and constraints. When young engineers begin their first job, they are sometimes surprised to see that education does not stop with college graduation, but rather is a life-long activity. In fact, it is the educational goal of all engineers to continue to learn both processes (rules about how to solve problems) and products (hardware and software components). As the engineer becomes more experienced, he or she has a larger toolbox from which processes and components can be selected.

The hardest step for most new engineers is the first one: where to begin? We begin by analyzing the problem to create a set of specifications and constraints in the form of a requirements document. Next, we look for components, in the form of previously debugged solutions, which are similar to our needs. Often during the design process, additional questions or concerns arise. We at that point consult with our clients to clarify the problem. Next we rewrite the requirements document and get it reapproved by the clients.

It is often difficult to distinguish whether a parameter is a specification or a constraint. In actuality, when designing a system it often doesn’t matter into which category a parameter falls, because the system must satisfy all specifications and constraints. Nevertheless, when documenting the device it is better to categorize parameters properly. Specifications generally define in a quantitative manner the overall system objectives as given to us by our customers.

Constraints, on the other hand, generally define the boundary space within which we must search for a solution to the problem. If we must use a particular component, it is often considered a constraint. In this class, we constrain most designs to include a MSPM0 LaunchPad. Constraints also are often defined as an inequality, such as the cost must be less than $50, or the battery must last for at least one week. Specifications on the other hand are often defined as a quantitative number, and the system satisfies the requirement if the system operates within a specified tolerance of that parameter. Tolerance can be defined as a percentage error or as a range with minimum and maximum values.

In engineering everything is either a system or an interface between systems. For example a switch can be considered a system. When we interface it to the LaunchPad the switch-LaunchPad combination is a new system. Therefore, we begin by collecting the components required to build the system. We then combine the components and debug the system. As the components are combined we create new more powerful components. When writing software, we can use flowcharts to develop new algorithms. The more we can simulate the system, the more design possibilities we can evaluate, and the quicker we can make changes. Debugging involves both making sure it works, together with satisfying all requirements and constraints.

2.8.1. Requirements

First, lets develop a requirements document. The main purpose of a requirements document is to serve as an agreement between you and your clients describing what the system will do. This agreement can become a legally binding contract. Write the document so that it is easy to read and understand by others. It should be unambiguous, complete, verifiable, and modifiable.

The requirements document should not include how the system will be designed. This allows the engineer to make choices during the design to minimize cost and maximize performance. Rather it should describe the problem being solved and what the system actually does. It can include some constraints placed on the development process. Ideally, it is co-written by both the engineers and the non-technical clients. However, it is imperative that both the engineers and the clients understand and agree on the specifics in the document.

Video 2.8.1. Requirments Document

Requirements document for the security system

    1. Overview
      1. Objectives: Design a security system with two sensors and one alarm. Contact switches will be used for the sensors. If the window is secure the switch will be pressed, and if the window is open, the switch will be released. The alarm condition will be a flashing LED. The system can be activated/deactivated with a toggle switch.
      2. Process: We will first prototype it on a breadboard using a LaunchPad, two momentary switches, a toggle switch, and an LED. Hardware and software designs will be developed and tested. Once the prototype is tested, the momentary switches can be replaced with switches that fit into the windows and doors, and the flashing LED can be replaced with an audio alarm. The number of sensors will need to be increased to allow one sensor to be placed in each window and door of the house.
      3. Roles and Responsibilities: Dr. Yerraballi will develop the hardware and Dr. Valvano will develop the software, both will test.
      4. Interactions with Existing Systems: We will use a LaunchPad. It will be powered through the USB cable either with AC outlet or stand-alone battery. The components of the prototype will be selected, if possible, from the parts in the lab kit.
      5. Terminology: A momentary switch has a spring, such that if no force is applied the contact will be open. Applying force continuously will close the contact on the momentary switch. A toggle switch can be placed in either the open or closed state, and force is required to change from open to closed or from closed to open. 
      6. Security: The wires between the sensors and the microcontroller will need to be hidden. However, cutting the wires should constitute a breach, setting off the alarm.
    2. Function Description
      1. Functionality: There are two contact switches that measure the status of your home. Each contact switch is positioned in the frame of a window or a door. If the switch is closed or pressed the window is secure, but if either switch is open it means the window is open and the home is unsecure.
      2. Scope: The scope of this design will involve hardware/software prototype design, but will not include legal, marketing, or financial aspects.
      3. Prototypes: We will use a breadboard and LaunchPad.
      4. Performance: If either sensor shows the window is insecure and the system is activated the alarm should occur. The performance is defined as functionally correct. There is no particular specification for the minimum response time between the arrival of an insecure state and the alarm signal.
      5. Usability: There is also a toggle switch with which the user can use to activate or deactivate the alarm. If the alarm is activated, the LED will flash at 5 Hz if either switch is not pressed.
      6. Safety: No concerns
    3. Deliverables
      1. Reports: Videos will be recorded and converted to a design chapter in the MOOC Embedded Systems – Shape the World.
      2. Audits: None
      3. Outcomes: We will create a prototype system

2.8.2. Components

Before we get into the actual design of the Security system, lets take stock of the components we will use in building the prototype.

Video 2.8.2. Components

Video 2.8.3. Building the circuit

2.8.3. Hardware Design

A data flow graph is a block diagram of the system, showing the flow of information. Arrows point from source to destination. Notice that a data flow graph looks like a block diagram of the system. In fact we draw a data flow graph by showing how the components are connected together. By visualizing the flow of data we are able to identify the components of the system and the nature of the data they work with.

Figure 2.8.1. Data Flow Graph for Security System

The data-flow diagram gives us a blueprint for both the hardware circuit we are going to build and the software we are going to write. Lets first build the circuit:

Figure 2.8.2. Hardware circuit

: Describe the similarities between a data flow graph and a hardware circuit.

2.8.4 Software Design

Programs themselves are written in a linear or one-dimensional fashion. In other words, we type one line of software after another in a sequential fashion. Writing programs this way is a natural process, because the computer itself usually executes the program in a top-to-bottom sequential fashion. This one-dimensional format is fine for simple programs, but conditional branching and function calls may create complex behaviors that are not easily observed in a linear fashion. Even the simple systems have multiple software tasks. Furthermore, a complex application will require multiple microcontrollers. Therefore, we need a multi-dimensional way to visualize software behavior. Flowcharts are one way to describe software in a two-dimensional format, specifically providing convenient mechanisms to visualize multi-tasking, branching, and function calls. Flowcharts are very useful in the initial design stage of a software system to define complex algorithms. As an added benefit, flowcharts can be used in the final documentation stage of a project in order to assist in its use or modification.

Figure 2.8.3. Flowchart for the Software

Video 2.8.4. Flowchart design


The code that implements the flowchart design described above is given below. This solution uses a friendly approach to accessing Port B. Which implies that we could use the other pins in Port B without changing this code.

Init: // PB4 output, PB2,PB1,PB0 input
  LDR  R1,=0x00040081
  LDR  R0,=IOMUXPB0
  STR  R1,[R0] // PB0 is in
  LDR  R0,=IOMUXPB1
  STR  R1,[R0] // PB1 is in
  LDR  R0,=IOMUXPB2
  STR  R1,[R0] // PB2 is in
  LDR  R1,=0x00000081
  LDR  R0,=IOMUXPB4
  STR  R1,[R0] // PB4 is out
  LDR  R0,=GPIOB_DOE31_0
  LDR  R1,[R0]
  MOVS R2,#0x10 // PB4
  ORRS R1,R1,R2
  STR  R1,[R0]  // enable out
  BX   LR
main: MOVS R0,#0
      BL   Clock_Init80MHz
      BL   LaunchPad_Init
      BL   Init
      LDR  R4,=GPIOB_DIN31_0
      LDR  R5,=GPIOB_DOUTTGL31_0
      LDR  R6,=GPIOB_DOUTCLR31_0
      MOVS R7,#0x10
loop: LDR  R0,[R4] // all input pins
      MOVS R1,#0x04
      ANDS R1,R1,R0 // arm
      BEQ  off
      MOVS R2,#0x03
      ANDS R2,R2,R0 // sensor
      CMP  R2,#3
      BEQ  off
      STR  R7,[R5] // LED toggle
      LDR  R0,=8000000
      BL   Delay  // 100ms
      B    loop
off:  STR  R7,[R6] // LED off
      B    loop

// PB4 output, PB2,PB1,PB0 input
uint8_t TExaS_Logic(void){
  return (0x80|
   GPIOB_DOUT31_0&0x10|
   GPIOB->DIN31_0&0x07);
}
void Init(void){
  IOMUX->SECCFG.PINCM[PB0INDEX]
     = 0x00040081;
  IOMUX->SECCFG.PINCM[PB1INDEX]
     = 0x00040081;
  IOMUX->SECCFG.PINCM[PB2INDEX]
     = 0x00040081;
  IOMUX->SECCFG.PINCM[PB4INDEX]
     = 0x00000081;
  GPIOB->DOE31_0 |= 0x10;
}
int main(void){
uint32_t arm,sensor;
  __disable_irq();
  Clock_Init80MHz(0);
  LaunchPad_Init();
  TExaS_Init(0,0,&TExaS_Logic);
  Init();
  __enable_irq();
  while(1){
    arm = GPIOB->DIN31_0&0x04;
// 0=deactivated; 1=activated
    sensor=GPIOB->DIN31_0&0x03;
// 3=ok; 0,1,2 = break in
    if((arm == 0x04)&&
      (sensor != 0x03)){
      GPIOB->DOUTTGL31_0 = 0x10; // toggle output for alarm
      Delay(8000000);
// 100ms makes a 5Hz period
    }else{
      GPIOB->DOUTCLR31_0 = 0x10;
// LED off if deactivated
    }
  }
}

Program 2.8.1. Software system that flashes the LED if it is armed and if there is an intruder.

: Explain how the main program uses registers R0-R2 as compared to how is uses R4-R7.

: Why are the values in R4-R7 set once, before the loop?

2.8.5. Testing

Video 2.8.5. Testing the circuit

As a general practice embedded systems developers start with first testing their solutions in a simulated environment (if possible) before running it on the real board with real hardware. Note that, just because your testing proves successful in simulation it does not mean it will succeed on the real board. However, failure to run in simulation almost always guarantees that it will fail on the real board.

2.8.6 Conclusion

We have successfully designed, built and tested a Security system. As a last step, we'll look back at the requirements and see if we met the timing specifications. In particular, we will check to see if our calculations used for sizing the resistors in the switch and LED interfaces match actual observations.

2.9. Designing a NOT gate using a LaunchPad

In this section we will combine many of the concepts presented in this chapter to design, build and test a NOT gate using the MSPM0 microcontroller. Any two GPIO pins could have been used, but we chose PB0 as input and PB1 as output. The system will make the PB1 output the logic NOT of the input on PB0. We will test the NOT gate by using a switch on PB0 to generate an input signal, and use an LED on PB1 to visualize the output. Basically if we press the switch, the input on PB0 will be high. The system will make the output on PB1 low, and the LED will be off. Conversely, if we release the switch, the input on PB0 will be low. The system will make the output on PB1 high, and the LED will be on. Figure 2.9.1 shows the data flow graph and Figure 2.9.2 shows the circuit used to test the not gate.

Video 2.9.1 Designing a Not gate

 

Figure 2.9.1. Data flow graph for the NOT gate.

 

Figure 2.9.2. Circuit to test NOT gate.

To use GPIO pins we must first initialize the port. The pseudo code in Program 2.9.1 describes the NOT gate software. The initialization occurs once at the start, setting the two IOMUX registers and bit 1 of the DOE register. To read the state of the input, we read all the bits from DIN and use the AND operation to select just bit 0. We toggle the input data to implement the NOT operation and shift the result into position of bit 1. The shifting is required because the output pin exists in bit 1 position. The affect a change in just one output pin we: a) read all bits; b) clear the bit we wish to change; c) combine the 31 existing bits with the one new bit; and d) write the entire 32-bit value back to DOUT.

Video 2.9.2 Flow chart and Pseudo code

   1) Initialize input pin and output pin
       Set IOMUXPB1 to 0x00000081
       Set IOMUXPB0 to 0x00040081
       Set bit 1 in DOE
   2) Read input from switch
       Read all of DIN
       Select just bit 0
   3) Output = NOT(input)
       Toggle just bit 0
       Move bit 0 into bit 1
       a) Read all of DOUT
       b) Clear existing bit 1
       c) Combine existing bits with new bit 1
       d) Write to DOUT
   4) Repeat steps 2,3 over and over

Program 2.9.1. Pseudo code for NOT gate.

Video 2.9.3 Morph pseudo code to assembly, reverse type into CCS

The software shown in Program 2.9.2 implements the above pseudo code.

Init:
   MOVS R1,#0x81
   LDR  R0,=IOMUXPB1
   STR  R1,[R0]  // PB1 is out
   LDR  R1,=0x00040081
   LDR  R0,=IOMUXPB0
   STR  R1,[R0]  // PB0 is in
   LDR  R0,=GPIOB_DOE31_0
   LDR  R1,[R0]
   MOVS R2,#0x02 // PB1
   ORRS R1,R1,R2
   STR  R1,[R0]  // enable out
   BX   LR
main:
   BL   LaunchPad_Init
   BL   Init
   LDR  R6,=GPIOB_DIN31_0
   LDR  R7,=GPIOB_DOUT31_0
   MOVS R5,#1 // bit 0
   MOVS R4,#2 // bit 1
loop:
   LDR  R1,[R6]  // Read input
   ANDS R1,R1,R5 // bit 0
   EORS R1,R1,R5 // toggle
   LSLS R2,R1,#1 // move
   LDR  R3,[R7]  // a) read all
   BICS R3,R3,R4 // b) clear bit 1
   ORRS R3,R3,R2 // c) combine
   STR  R3,[R7]  // d) write
   B    loop

void Init(void){
  IOMUX->SECCFG.PINCM[PB1INDEX]
     = 0x00000081;
  IOMUX->SECCFG.PINCM[PB0INDEX]
     = 0x00040081;
  GPIOB->DOE31_0 |= 0x02;
}


int main(void){
uint32_t in,out,data;
  LaunchPad_Init();
  Init();
  while(1){
    in = GPIOB->DIN31_0&0x01;
    out = in^0x01;
    out = out<<1;
    data = GPIOB->DOUT31_0;
    data = data&(~0x02);
    data = data|out;
    GPIOB->DOUT31_0 = data;
  }
}

Program 2.9.1. NOT gate with PB1 as the output and PB0 as the input.

To test the system, we connect the switch to PB0 and LED to PB1, and single step through the code. We step through the loop with the switch not pressed to see the LED come on, and with the switch pressed to see the LED go off. If we connect a logic analyzer to PB1 and PB0, we test dynamic behavior of the system.

Video 2.9.4 Debug in CCS, debug with voltmeter and two-channel scope

: Why is 0x81 stored into IOMUXPB1?

: Why is 0x00040081 stored into IOMUXPB0?

: Why do we set bit 1 of GPIOB_DOE31_0?

: Within the loop, what is the purpose of the ANDS instruction?

: Within the loop, what is the purpose of the EORS instruction?

: Within the loop, what is the purpose of the LSLS instruction?

: Within the loop, what is the purpose of the BICS instruction?

: Within the loop, what is the purpose of the ORRS instruction?

: In Program 2.9.2 runs, we defined a function Init, even though it was called only once. Would it have been better to embed the code directly into the main program eliminating the function call/return?

: In Program 2.9.2, consider registers R1, R2, R3 inside the loop. Perform an equivalence mapping from these three registers to the local variables in, out, and data in the C code.

 

Quiz 2.9

2.10. Lab 2 Hardware Interfacing LED, Switch

The details of the labs can be found in GoogleDocs:
Lab 2. Hardware Interfacing of LED, Switch

Go to Chapter 3: Programming in C and Functional Debugging

This material was created to teach ECE319K at the University of Texas at Austin

Reprinted with approval from Introduction to Embedded Systems Using the MSPM0+, ISBN: 979-8852536594

  Creative Commons License
Embedded Systems - Shape the World by Jonathan Valvano and Ramesh Yerraballi is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
Based on a work at http://users.ece.utexas.edu/~valvano/mspm0/

.