5. Simple GPIO
5.1. Purpose
This activity introduces two methods for interfacing with digital input and output pins within a MSPM0 program.
5.2. Hardware and Tools
[USB Test Device]: ADALM2000, Analog Discovery, or a multimeter (multimeter available in classroom)
LP-MSPM0G3507 Launchpad Development Board, OR RPI-RSLK Robotic Car
Breadboard
Components (provided):
2x Pushbuttons
1x Slide Switch
1x LEDs
1x BiColor LED (BiLED)
Various Resistors (1x 330Ω, 1x 510Ω, 3x 1kΩ)
Wire (available in classroom)
5.3. Description
The bridging of the physical world and a microcontroller’s program is completed through what are known as Registers. In a simplistic sense, registers are memory locations within the microcontroller, accessed through what looks like variables, that are tied to operational aspects of the various subsystems of the microcontroller. This includes but is not limited to: clock system configuration, entry/exit of low power modes, timers, and general purpose input and output (GPIO) configuration and interfacing.
The MSPM0G3507 has the GPIO pins grouped in sets of 32 pins, called Ports. There are only 2 ports on the device: Ports A and B. The pins within the ports are labeled with numbers 0-31. This allows the notation of Pn to refer to a port, where n is the port letter; for example, Port A is PA. Further, to refer to a pin within the port, we can use the notation Pnm, where m is the pin number; for example, PA16 is referring to Port A Pin 16. It should be noted that Port B does not have a full 32 pins: it only has 28 (PB0-PB27).
There are many registers that are associated with each port. These can be accessed through struct pointers, named either GPIOA for Port A or GPIOB for Port B. We will learn more about structs and pointers in the next activity. We will only focus on a small subset of the available registers for each port: those directly related to configuring and controlling pins as either inputs or outputs. The ones we are concerned with in this activity are:
DOE31_0: Enables/disables pin as an output: a value of 1 enables as an output
DOUT31_0: Sets the value of an output pin
DIN31_0: Reads the value of a pin (input or output)
To access any of these registers, prepend the name with the code GPIOA-> for Port A or GPIOB-> for Port B. For example, to configure output pins for Port B, use: GPIOB->DOE31_0 = ...;. For each of these registers, the bit number of the register is associated with the pin number. For example, PB5 may be configured as input by changing bit 5 within DOE31_0 and then its value can be read from bit 5 of DIN31_0. This process requires bitmasking. For example:
uint8_t val;
GPIOB->DOE31_0 &= ~0x20; // Set only bit 5 to 0, leaving rest as-is
val = (GPIOB->DIN31_0 & 0x20) != 0; // Check the value of PB5 and get either True or False
// Code first isolates bit 5 of the register DIN31_0 (sets other bits to 0 in a temporary variable)
// If bit 5 is 1 the number will be >0 (True,0x01). If bit 5 is 0 the number is 0 (False,0x00)
The above can be done in many ways, and what is shown is just one instance. Other helper registers allow for the bits in the listed registers to be manipulated without bitmasking, such as the register DOESET31_0, which can be used to set DOE31_0 bits high. To see all registers for GPIO interfacing, see the MSPM0G3507 Technical Reference Manual, specifically page 1018.
In most cases, the process for working with individual pins is cumbersome. There are more intuitive functions provided from the manufacturer (Texas Instruments) that we can use to make it simpler. These functions are part of what is known as the TI DriverLib. The DriverLib, which is also known as a Hardware Abstraction Layer, or HAL, allows for the interfacing to the GPIO (and other components) without having to understand the registers thoroughly. Again, however, many of the functions in the DriverLib are more complicated than this class requires; therefore, a more simplistic HAL was created for this class’s purpose: the EmCon HAL. Several EmCon HAL functions that operate on the GPIO registers listed above are:
void GPIO_initDigitalOutput(GPIO_Regs* gpio,uint32_t pins): Configure one or multiple pins on a port to be outputs.void GPIO_initDigitalInput(GPIO_Regs* gpio,uint32_t pins): Configure one or multiple pins on a port to be inputs.uint32_t GPIO_readPins(GPIO_Regs* gpio,uint32_t pins): Reads the value of the selected pins. Returns auint32_tvalue with bits corresponding to each requested pin having said pin’s value. All other bits are set to 0.void GPIO_writePins(GPIO_Regs* gpio,uint32_t pins): Write all pins on a port to a given value. Any pins specified bypinswill be set High with all others being set low.void GPIO_setPins(GPIO_Regs* gpio,uint32_t pins): Set one or multiple pins on a port to output High if configured as outputs.void GPIO_clearPins(GPIO_Regs* gpio,uint32_t pins): Set one or multiple pins on a port to output Low if configured as outputs.void GPIO_togglePins(GPIO_Regs* gpio,uint32_t pins): Invert the output level of one or multiple pins on a port if configured as outputs.
For each of the functions listed above, the value for the first argument, GPIO_Regs* port, is either GPIOA or GPIOB (same variables as above). The second argument, uint32_t pins, should use the predefined symbols GPIO_PINm, where m is the pin number. These functions will not work correctly if the pin number is directly given to the function.
For all the functions listed above: multiple pins can be interfaced at once. To do this, all desired pin symbols should be ‘bitwise or’ed together. For example, to set PA1 and PA6 to outputs, with the first Low and the second High, the following code can be used:
GPIO_initDigitalOutput( GPIOA , GPIO_PIN1 | GPIO_PIN6 ); // Set both pins as outputs
GPIO_clearPins( GPIOA , GPIO_PIN1 ); // Set PA1 to low
GPIO_setPins( GPIOA , GPIO_PIN6 ); // Set PA6 to high
5.4. Instructions
5.4.1. Build and Verify Hardware
This activity will use the Input and Output schematic as explored in the previous activity:
Warning
!!!READ THIS!!! A grade of 0 for the assignment will be assessed if the instructions in this warning block are not adhered to. It is imperative to follow this warning to avoid destroying laboratory hardware.
There are no 5V connections within the schematic above, only 3.3V! This is because the microcontroller pins are only 3.3V tolerant and will likely fail if 5V is applied to them. Ensure that you never use 5V when connecting to this microcontroller!
All power for circuits must be provided from the Launchpad Board or RSLK when using these devices. Do not, we repeat: !!DO NOT!!, use the power supplies from the ADALM2000 or Analog Discovery as they may damage the MSPM0G3507, especially if set to a voltage greater than 3.3V. Make sure to avoid the 5V pins.
To start, we are going to first verify that the Launchpad Board or RSLK is in good working condition for this activity to proceed. To do so, please download, import, and run the
IO_Test.zipproject, which is used to independently tests all pins on the device and reports failed pins. Please read the Note block below regardless of if a pin was reported failed or not. Note that you will have to have a terminal connected to control the test program and read the results!
Note
This discussion is not necessarily impactful for this Fall 2025 semester as all the hardware is now; however, pin failures will likely occur as the semester progresses
The laboratory Launchpad Board or RSLK components may have had hardware pin connections cut off or labelled. If so, this has been done to indicate that the MSPM0G3507 pin that the hardware pin is connected to has been burnt out by not following the warning block as above. For the RSLK, you will see these labels (if they exist) on the white motor blocks.
Further, a burnt out pin may not be labelled or cut (for example: a student in the previous section caused it to fail). It is strongly suggested to run the IO_Test.zip project on the Launchpad Board or RSLK to be used at the beginning of a development/debug session (e.g., at the beginning of class). This may save you a lot of time and frustration! If a pin is found to be defective, you may still use the hardware but please alert the staff if it has not been labelled or cut such that we can do so.
If a pin is labelled/cut or found to be defective, you can typically use an alternative pin. Please see the RPI-RSLK Pin Mapping identify a useable pin.
Assemble the circuit as shown on your personal protoboard (and not the protoboard on the RSLK) such that the components are wired to the Launchpad Board as specified in the table below. Do not plug the Launchpad Board into your computer while building the circuit. The 3.3V and GND connections are provided from the Launchpad Board.
Component
Pin(s)
slide1
PA9†
push1
PB2
push2
PB3
BiLED1
PA12,PA13
LED1
PB19
Note
† PA9 is labelled SW1 on the Launchpad Board. That pin is selectable to be either PB23 or PA9 via the jumper near the pin. The jumper should be set already set such that PA9 is selected.
With the circuit complete, plug the Launchpad Board into your computer. This will power the 3.3V supply on the Launchpad Board. When modifying any circuitry, always disable the power supply (unplug the Launchpad Board, turn off RSLK) to avoid unintended connections, such as when a wire is being moved, from breaking components.
Use the USB Test Device or a multimeter to verify the circuitry is built correctly. Make sure to connect the GND of the USB Test Device to GND of the Launchpad Board. It is suggested to check these points:
Check that the 3.3V supply on the Launchpad Board is active, either by checking the voltage directly on the Launchpad Board or from a point on the breadboard.
Check that each pushbutton produces an output change where the Launchpad Board pin is connected.
The LEDs cannot be tested with the USB Test Device or a multimeter. Do not use the power supply/waveform generators to test the LEDs. See the warning box above.
5.4.2. Register Level
We will first complete a program that interfaces with the hardware through registers. Start by downloading and importing the
activity_gpio.zip.Create three global variables prior to the main function, one for each input:
push1,push2, andslide1. These can all beuint8_ttypes and will be used to store the current value of the inputs.We need to complete the configuration of the inputs and outputs within the function definition for
GPIOInit()(initially line 62, below the main function). As we will complete this task with bitmasking, there is no need to know the final value for eitherGPIOA->DOE31_0orGPIOB->DOE31_0; simply bitmask the appropriate bits high and low.Remember that the assignment command
&=can only set bits low, while|=can only set bits high.
Note
Within
GPIOInit(), you will notice the use of additional registers:IOMUX->SECCFG.PINCM. These are needed to fully connect the GPIO to the pins; however, the functionality of these registers is not common in most microcontrollers. Because of this, the full code for these are given. This should be the only time that you will see these registers in this class.Finish the code to get the values for each input within the function definition for
GetInputs()(initially line 80).With the initialization and input code completed, it is good idea to test the system at this point prior to implementing any logic. A
printf()statement is included for this within thewhile(1). Run the program to see if it is successful.We can also test the outputs at this stage: uncomment the output test code within the
while(1). If the outputs are assembled and configured properly, the BiLED1 should blink GREEN-OFF-RED-OFF, with LED1 lighting for half that cycle. If the LEDs are not operating as specified, use the USB Test Device to check how the associated pins are behaving.Once this testing is completed, comment out all test code within the
while(1)and uncomment the function call toRegisterLogic().Within
RegisterLogic(), the logic to produce the logic table from the previous activity is mostly complete. Fix the issues noted in the comments marked// **ACTIVITY**using registers.Test the code.
- Reiterated requirements of the operation from the truth table (shortened):
Slideswitch ON, push1 pressed: BiLED1 RED (or GREEN), LED1 OFF
Slideswitch ON, push2 pressed: BiLED2 GREEN (or RED), LED1 ON
Slideswitch ON, push1 and push2 pressed: BiLED2 OFF, LED1 ON
All other cases: BiLED2 OFF, LED1 OFF.
5.4.3. EmCon HAL
Now, we’ll modify the program to use the EmCon HAL. First, comment out the register operations in
GPIOInit()(including those associated with theIOMUX) and replace withvoid GPIO_initDigitalInput()andvoid GPIO_initDigitalOutput(). You’ll need 4 statements at a minimum[1]. To test these changes, run the program and verify that it still operates appropriately.Next, modify the code within
GetInputs()to use the DriverLib and test again.Now comment out the call to
RegisterLogic()within thewhile(1)and uncomment the call toHALLogic().Within
HALLogic(), the same logic structure fromRegisterLogic()is copied with the same omissions; however, the register operations have been changed to equivalent HAL implementations. Fix the omissions again but instead use the HAL functions.Test the code again to ensure proper operation.
Submit a photo of your test circuit and your final code to the Gradescope assignment.
Footnotes