0% found this document useful (0 votes)
211 views7 pages

Lesson 2 - Basic Input and Output (GPIO)

The document discusses using GPIO (general purpose input/output) pins on a microcontroller to interact with external devices. It explains the four registers - IODIR, IOSET, IOCLR, and IOPIN - that control the GPIO pins and whether they are inputs or outputs. Examples are given to set pin directions and states using these registers. The document also provides an exercise to write a program toggling two LEDs based on the state of two buttons using the GPIO pins.
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
211 views7 pages

Lesson 2 - Basic Input and Output (GPIO)

The document discusses using GPIO (general purpose input/output) pins on a microcontroller to interact with external devices. It explains the four registers - IODIR, IOSET, IOCLR, and IOPIN - that control the GPIO pins and whether they are inputs or outputs. Examples are given to set pin directions and states using these registers. The document also provides an exercise to write a program toggling two LEDs based on the state of two buttons using the GPIO pins.
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 7

Lesson 2 - Basic Input and Output (GPIO)

Getting your microcontroller to talk to the outside world and vice-versa.


In our previous tutorial (Getting Started), we installed our development software (Crossworks for ARM), setup our JTAG
debugger (an Olimex ARM-USB-OCD), and ran our first program on the development board. As important as all of that is, it
isn't particularly fun or exciting. In this tutorial, we'll try to do something a bit more interesting and show you the most basic
method for actually making your microcontroller interact with the outside world via GPIO.
GPIO, or General Purpose Input/Output , is the easiest way for you to interact with basic peripherals like buttons, LEDs,
switches, and other components. It can also be used for more complex components like text and graphic LCDs, but for now
we'll start with a few basic components that are relatively ease to get working.
In order to get started with GPIO, you need to understand the four 'registers' that control
it: IODIR, IOSET, IOCLR andIOPIN.  Each of these registers is explained in detail below with some basic examples of
how they work.
IODIR

IODIR controls the 'direction' of the GPIO pin. You use this register to set a GPIO pin to either Input (0) or Output (1). For
example, if we want to use our GPIO pin to send signals 'out' from the microcontroller to some external device, we need to
set a pin (for example GPIO 0.10) to 'Output' (1).  We could do that with the following code:

GPIO0_IODIR |= (1 << 10);

If we wanted to use our GPIO pin to receive information from the outside world (reading it inside the microcontroller), we
would need to set GPIO 0.10 to 'Input' (0).  That could be accomplished the following code:

GPIO0_IODIR &= ~(1 << 10);

To set several pins to output at once we could do either of the following (which will produce identical code when compiled):

// Set GPIO 0.10, 0.11, and 0.15 to output

GPIO0_IODIR |= (1 << 10) | (1 << 11) | (1 << 15);

// Set GPIO 0.10, 0.11, and 0.15 to output using hexadecimal

GPIO0_IODIR |= 00008C00;

If you don't understand why these lines are equivalent, feel free to take a look at Understanding Hexadecimal Numbers. 
While ''(1 << 10) | (1 << 11) | (1 << 15)" is probably clearer to read and easier to understand, hexadecimal numbers are
(for better or for worse) the norm in embedded development and you'll need to come to terms with them sooner or later.

IOSET and IOCLR


If your GPIO pin is set as Output (using the IODIR register mentionned above), you can use IOSET to set your GPIO pin to
'high' (providing a small 3.3V electrical current) or IOCLR to set it to 'low' (providing a connection to GND).  You shouldn't
really think about high being 'on' and low being 'off', though, since ... as we'll see in the example below ... you can often
turn a device 'on' by setting it low and 'off' by setting it 'high', depending on how the components are connected.
Let's take the Olimex LPC-P2148 board as an example.  There are two LEDs provided on this board for testing purposes,
connected to GPIO pins 0.10 and 0.11.  Looking at the schematic for this board, we can see that these two LEDs
(located on the center right-hand side of the schematic) are connected to 3.3v on one side, and GPIO 0.10 and 0.11 on the
other side (with a 330 ohm resistor added to make sure the LEDs do not draw too much current and burn out).  What this
means is that if we want to turn the LEDs 'on', we need to complete the electrical circuit by setting GPIO pins 0.10 and 0.11
to GND, or 'low'.  This is accomplished with IOCLR.  So, if we wanted to turn both LEDs ON and then OFF we would use
the following code:

// Make sure GPIO 0.10 and 0.11 are set to output

GPIO0_IODIR |= (1 << 10) | (1 << 11);

// Turn the LEDs on using IOCLR (which gives a GND connection)

GPIO0_IOCLR |= (1 << 10) | (1 << 11);

// Turn the LEDs off using IOSET (which supplies 3.3V and breaks our circuit)

GPIO0_IOSET |= (1 << 10) | (1 << 11);

You might have noticed when running this code that as soon as you set the direction of the pins to 'Output' with IODIR (the
first line of code), the LEDs turned on! This is because the pins will default to being 'low' (meaning a connection to GND)
when you set them to output, which completes our circuit and turns the LEDs on before we even have time to try to clear
the pins ourselves in the second line of code. In this particular case, the second line of code (where we use IOCLR to 'clear'
the pins explicitly) won't actually do anything, since they are already 'low'. However, you should never depend on the
'default' value of a pin when writing your code since the pin's value may have been changed elsewhere (such as in an
interrupt).

IOPIN

Regardless of whether your GPIO pin's direction is set to Input or Output, you can use the IOPIN register to read the
current 'state' of every GPIO pin in the pin block (the collection of all 32 pins in GPIO0).  A 1 value means that the pin is
currently 'high', and a 0 value means the pin is currently 'low'.  (Please note that since IOPIN returns the current state of
ALL 32 pins in the pin block, you have to do a little bit of extra work to determine the value of one specific pin, but we'll
give you an example below.) 
You could read the IOPIN register, for example, to see if your LED was currently turned on or off, where IOPIN would
return 0 for pin 10 (LED1) if it was currently turned on (since setting the GPIO pin to low turns the LED on) and 1 if the LED
was off (since setting the GPIO pin high turns our LED off).  Here's a simple method showing how to do this, including one
way to read the value of a single pin from the 32-bit value returned by IOPIN. This method will return '1' if the supplied pin
is currently 'high', and '0' if it is currently low:

int getPinState(int pinNumber)

// Read the current state of all pins in GPIO block 0

int pinBlockState = GPIO0_IOPIN;

// Read the value of 'pinNumber'

int pinState = (pinBlockState & (1 << pinNumber)) ? 1 : 0;

// Return the value of pinState

return pinState;

Looking at this sample code, if the LED was currently turned on, "int state = getPinState(10);" should set 'state' to 0 since
pin 10 is set to low; if the LED was currently turned off, the same 'state' variable would equal 1 since pin 10 is set to high.
Sidenote: Sometimes smaller really is better!
In general, most experienced software developers try to keep their code as 'concise' as possible (without sacrificing
readability). The entire method above, for example, could be rewritten using one line that accomplishes exactly the same
thing:

return (GPIO0_IOPIN & (1 << pinNumber)) ? 1 : 0;

Your compiler would almost certainly compile the code identically in these two cases, but in the latter case you end up with
source code that isn't as sprawling and may be a bit quicker to analyse. Another good example in the above code is the "?",
called a conditional operator (sometimes called a 'ternary operator' as well). The conditional operator will return one of
two values, depending on whether the code it is 'evaluating' -- (GPIO0_IOPIN & (1 << pinNumber)) in this case -- is true
(1) or false (0). If it is true, the first value will be returned. If it is false, the second value (following the ":") will be returned.
You could just as easily write this code as:
if (GPIO0_IOPIN & (1 << pinNumber)) == "1"

return "1";

else

return 0;

but that's a complete waste of space, and takes more effort to write as well as to read it. Again, the compiled code would
almost certainly be identical in either case, but the aesthetic appeal and readability of your code can often be improved with
a bit of experience and conscious effort on your part.

Exercise: Toggling LEDs with a Button


If you take all of the information presented above, you should be able to put together a simple program that will turn an
LED on or off depending on whether a button is currently held down or released. Since there are two different LEDs and
two different buttons on Olimex's LPC-P2148 board, we will try to turn LED1 on when Button1 is pressed, and LED2
on when Button2 is pressed. To help you out if you're not really comfortable reading schematics, here is the basic
information you'll need to complete this exercise:

Device GPIO Pin 'On' State


LED1 0.10 Low / 0
LED2 0.11 Low / 0
Button1 0.15 Low / 0
Button2 0.16 Low / 0

I'm still lost ... what do I need to do?

Everything you need to know to do this exercise has already been explained in this article, and you'll probably get the most
benefit out of it by trying to find a solution yourself first. If you've already made an effort, though, or are having a hard
time, here are some basics steps that you could follow to finish this exercise:
1. Set the direction of your buttons to input with IODIR
2. Set the direction of your LEDs to output with IODIR
3. Turn your LEDs off by setting them 'High'
4. In an infinite loop ("while (1) { ... }"), do the following:
5. Read the current state of Button1 and Button2 with IOPIN
6. If either button is pressed (remember pressed = 'Low' or '0'), ...
7. ... turn the appropriate LED on by clearing it to 'Low'.
8. If a button is not pressed (released = 'High' or '1') ...
9. ... turn the appropriate LED off by setting it to 'High'

I'm HOPELESSLY lost .... can you just give me the answer?

For the sake of completeness, and just to have something to compare your own efforts against, here is one possible
solution for this exercise, building on some of the code we have already introduced.  In this particular example, when
Button1 is pressed, LED1 will be turned on, when Button1 is not pressed, LED1 will be turned off:

#include "lpc214x.h"

#define LED1 (1 << 10)

#define LED2 (1 << 11)

#define BUTTON1 (1 << 15)

#define BUTTON2 (1 << 16)

// Method prototypes

int getPinState(int pinNumber);

int main(void)

// Set buttons as input

GPIO0_IODIR &= ~(BUTTON1 | BUTTON2);


// Set LEDs as output

GPIO0_IODIR |= (LED1 | LED2);

// Turn both LEDS off (set them 'high')

GPIO0_IOSET |= (LED1 | LED2);

while (1)

// Check if button 1 is pressed

// Released = 'High' (1)

// Pressed = 'Low' (1)

if (getPinState(15))

// Button1 is currently 'high'

// Turn LED1 off

GPIO0_IOSET |= LED1;

else

// Button1 is currently 'Low'

// Turn LED1 on

GPIO0_IOCLR |= LED1;

}
}

int getPinState(int pinNumber)

// Read the current state of all pins in GPIO block 0

int pinBlockState = GPIO0_IOPIN;

// Read the value of 'pinNumber'

int pinState = (pinBlockState & (1 << pinNumber)) ? 1 : 0;

// Return the value of pinState

return pinState;

You might also like