0% found this document useful (0 votes)
26 views20 pages

Gpio STM32

GPIO on STEM32

Uploaded by

idealabnovate
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
26 views20 pages

Gpio STM32

GPIO on STEM32

Uploaded by

idealabnovate
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 20

CHAPTER 4

GPIO
In this chapter, you’re going to use the libopencm3 library to build a blink program
from source code. This example program demonstrates the configuration and use of
GPIO (General Purpose Input/Output). The program presented is a slightly modified
version of a libopencm3 example program named miniblink. It has been modified to
provide a different timing so that it will be obvious that your newly flashed code is the
one executing. After building and running this program, we’ll discuss the GPIO API
(Application Programming Interface) that is provided by libopencm3.

B
 uilding miniblink
Change to the subdirectory miniblink as shown, and type make:

$ cd ~/stm32f103c8t6/miniblink
$ make
gmake: Nothing to be done for 'all'.

If you see the preceding message, it may be because you have already built all of
the projects from the top level (there is nothing wrong with that). If, however, you made
changes to the source-code files, make should automatically detect this and rebuild the
affected components. Here, we just want to force the rebuilding of the miniblink project.
To do this, type make clobber in the project directory, and then make afterward, as shown:

$ make clobber
rm -f *.o *.d generated.* miniblink.o miniblink.d
rm -f *.elf *.bin *.hex *.srec *.list *.map
$ make
...

39
© Warren Gay 2018
W. Gay, Beginning STM32, https://doi.org/10.1007/978-1-4842-3624-6_4
Chapter 4 GPIO

arm-none-eabi-size miniblink.elf
   text   data    bss    dec    hex    filename
    696      0      0    696    2b8    miniblink.elf
arm-none-eabi-objcopy -Obinary miniblink.elf miniblink.bin

When you do this, you will see a few long command lines executed to compile and
link your executable named miniblink.elf. To flash your device, however, we also need
an image file. The last step of the build shows how the ARM-specific objcopy utility is
used to convert miniblink.elf into the image file miniblink.bin.
Just prior to the last step, however, you can see that the ARM-specific size command
has dumped out the sizes of the data and text sections of your program. Our miniblink
program consists only of 696 bytes of flash (section text) and uses no allocated SRAM
(section data). While this is accurate, there is still SRAM being used for a call stack.

Flashing miniblink
Using the make framework again, we can now flash your device with the new program
image. Hook up your ST-Link V2 programmer, check the jumpers, and execute the
following:

$ make flash
/usr/local/bin/st-flash write miniblink.bin 0x8000000
st-flash 1.3.1-9-gc04df7f-dirty
2017-07-30T12:57:56 INFO src/common.c: Loading device parameters....
2017-07-30T12:57:56 INFO src/common.c: Device connected is: \
    F1 Medium-density device, id 0x20036410
2017-07-30T12:57:56 INFO src/common.c: SRAM size: 0x5000 bytes (20 KiB),\
    Flash: 0x20000 bytes (128 KiB) in pages of 1024 bytes
2017-07-30T12:57:56 INFO src/common.c: Attempting to write 696 (0x2b8) \
    bytes to stm32 address: 134217728 (0x8000000)
Flash page at addr: 0x08000000 erased
2017-07-30T12:57:56 INFO src/common.c: Finished erasing 1 pages of \
    1024 (0x400) bytes
...
2017-07-30T12:57:57 INFO src/common.c: Flash written and verified! \
    jolly good!

40
Chapter 4 GPIO

Once this is done, your device should automatically reset and start the flashed
miniblink program. With the modified time constants used, you should see it now
blinking frequently, with a mostly-on 70/30 duty cycle. Your supplied device blink
program likely used a slower 50/50 duty cycle instead. If your blink pattern varies
somewhat from what is described, don’t worry. The important point is that you’ve
flashed and run a different program.
This program does not use a crystal-controlled CPU clock. It uses the internal RC
clock (resistor/capacitor clock). For this reason, your unit may flash quite a bit faster or
slower than someone else’s unit.

miniblink.c Source Code


Let’s now examine the source code for the miniblink program you just ran. If not still in
the subdirectory miniblink, change to there now:

$ cd ~/stm32f103c8t6/miniblink

Within this subdirectory, you should find the source program file miniblink.c.
Listing 4-1 illustrates the program without comment boilerplate:

Listing 4-1. Listing of miniblink.c

0019: #include <libopencm3/stm32/rcc.h>


0020: #include <libopencm3/stm32/gpio.h>
0021:
0022: static void
0023: gpio_setup(void) {
0024:
0025:   /* Enable GPIOC clock. */
0026:   rcc_periph_clock_enable(RCC_GPIOC);
0027:
0028:   /* Set GPIO8 (in GPIO port C) to 'output push-pull'. */
0029:   gpio_set_mode(GPIOC,GPIO_MODE_OUTPUT_2_MHZ,
0030:                 GPIO_CNF_OUTPUT_PUSHPULL,GPIO13);
0031: }
0032:

41
Chapter 4 GPIO

0033: int
0034: main(void) {
0035:   int i;
0036:
0037:   gpio_setup();
0038:
0039:   for (;;) {
0040:       gpio_clear(GPIOC,GPIO13);      /* LED on */
0041:       for (i = 0; i < 1500000; i++)  /* Wait a bit. */
0042:           __asm__("nop");
0043:
0044:       gpio_set(GPIOC,GPIO13);        /* LED off */
0045:       for (i = 0; i < 500000; i++)   /* Wait a bit. */
0046:           __asm__("nop");
0047:   }
0048:
0049:   return 0;
0050: }

Note The line numbers appearing at the left in the listings are not part of the
source file. These are used for ease of reference only.

The structure of the program is rather simple. It consists of the following:

1. A main program function declared in lines 33–50. Note that unlike


a POSIX program, there are no argc or argv arguments to function
main.

2. Within the main program, function gpio_setup() is called to


perform some initialization.

3. Lines 39–47 form an infinite loop, where an LED is turned on and


off. Note that the return statement in line 49 is never executed
and is provided only to keep the compiler from complaining.

Even in this simple program there is much to discuss. As we will see later, this
example program runs at a default CPU frequency since none is defined. This will be
explored later.
42
Chapter 4 GPIO

Let’s drill down on the simple things first. Figure 4-1 illustrates how the LED that
we’re flashing is attached to the MCU on the Blue Pill PCB. In this schematic view, we
see that power enters the LED from the +3.3-volt supply through limiting resistor R1.
To complete the circuit, the GPIO PC13 must connect the LED to ground to allow the
current to flow. This is why the comment on line 40 says that the LED is being turned on,
even though the function call is gpio_clear(). Line 44 uses gpio_set() to turn the LED
off. This inverted logic is used simply because of the way the LED is wired.

Figure 4-1. LED connected to PC13 on the Blue Pill PCB

Look again at these function calls:

gpio_clear(GPIOC,GPIO13);    /* LED on */
...
gpio_set(GPIOC,GPIO13);      /* LED off */

Notice that these two calls require two arguments, as follows:

1. A GPIO port name

2. A GPIO pin number

If you are used to the Arduino environment, you are used to using something like the
following:

    int ledPin = 13;  // LED on digital pin 13

    digitalWrite(ledPin,HIGH);
    ...
    digitalWrite(ledPin,LOW);

43
Chapter 4 GPIO

In the non-Arduino world, you generally work directly with a port and a pin. Within
the libopencm3 library, you specify whether you are clearing or setting a bit based upon
the function name (gpio_clear() or gpio_set()). You can also toggle a bit with the
use of gpio_toggle(). Finally, it is possible to read and write the full set of pins by port
alone, using gpio_port_read() and gpio_port_write() respectively.

G
 PIO API
This is a good place to discuss the libopencm3 functions that are available for GPIO use.
The first thing you need to do is include the appropriate header files, as follows:

#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>

The rcc.h file is needed for definitions so as to enable the GPIO clock. The gpio.h
file is necessary for the remainder:

void gpio_set(uint32_t gpioport, uint16_t gpios);


void gpio_clear(uint32_t gpioport, uint16_t gpios);
uint16_t gpio_get(uint32_t gpioport, uint16_t gpios);
void gpio_toggle(uint32_t gpioport, uint16_t gpios);
uint16_t gpio_port_read(uint32_t gpioport);
void gpio_port_write(uint32_t gpioport, uint16_t data);
void gpio_port_config_lock(uint32_t gpioport, uint16_t gpios);   

In all of the preceding functions, the argument gpioport can be one of the macros
from Table 4-1 (on other STM32 platforms, there can be additional ports). Only one port
can be specified at a time.

Table 4-1. libopencm3 GPIO Macros for STM32F103C8T6

Port Macro Description

GPIOA GPIO port A


GPIOB GPIO port B
GPIOC GPIO port C

44
Chapter 4 GPIO

In the libopencm3 GPIO functions, one or more GPIO bits may be set or cleared at
once. Table 4-2 lists the macro names supported. Note also the macro named GPIO_ALL.

Table 4-2. libopencm3 GPIO pin designation macros


Pin Macro Definition Description

GPIO0 (1 << 0) Bit 0


GPIO1 (1 << 1) Bit 1
GPIO2 (1 << 2) Bit 2
GPIO3 (1 << 3) Bit 3
GPIO4 (1 << 4) Bit 4
GPIO5 (1 << 5) Bit 5
GPIO6 (1 << 6) Bit 6
GPIO7 (1 << 7) Bit 7
GPIO8 (1 << 8) Bit 8
GPIO9 (1 << 9) Bit 9
GPIO10 (1 << 10) Bit 10
GPIO11 (1 << 11) Bit 11
GPIO12 (1 << 12) Bit 12
GPIO13 (1 << 13) Bit 13
GPIO14 (1 << 14) Bit 14
GPIO15 (1 << 15) Bit 15
GPIO_ALL 0xffff All bits 0 through 15

An example of GPIO_ALL might be the following:

gpio_clear(PORTB,GPIO_ALL); // clear all PORTB pins

A special feature of the STM32 series, which libopencm3 supports, is the ability to
lock a GPIO I/O definition, as follows:

void gpio_port_config_lock(uint32_t gpioport, uint16_t gpios);

45
Chapter 4 GPIO

After calling gpio_port_config_lock() on a port for the selected GPIO pins, the I/O
configuration is frozen until the next system reset. This can be helpful in safety-critical
systems where you don’t want an errant program to change these. When a selected GPIO
is made an input or an output, it is guaranteed to remain so.

G
 PIO Configuration
Let’s now examine how the GPIO was set up in function gpio_setup(). Line 26 of
Listing 4-1 has the following curious call:

rcc_periph_clock_enable(RCC_GPIOC);

You will discover throughout this book that the STM32 series is very configurable.
This includes the underlying clocks needed for the various GPIO ports and peripherals.
The shown libopencm3 function is used to turn on the system clock for GPIO port C. If
this clock were not enabled, GPIO port C wouldn’t function. Sometimes the affected
software will have operations ignored (visible result), while in other situations the system
can seize up. Consequently, this is one of those critical “ducks” that needs to be “in a row.”
The reason that clocks are disabled at all is to save on power consumption. This is
important for battery conservation.

Tip If your peripheral or GPIO is not functioning, check that you have enabled the
necessary clock(s).

The next call made is to gpio_set_mode() in line 29:

    gpio_set_mode(
        GPIOC,                      // Table 4-1
        GPIO_MODE_OUTPUT_2_MHZ,     // Table 4-3
        GPIO_CNF_OUTPUT_PUSHPULL,   // Table 4-4
        GPIO13                      // Table 4-2
    );

This function requires four arguments. The first argument specifies the affected
GPIO port (Table 4-1). The fourth argument specifies the GPIO pins affected (Table 4-2).
The third argument’s macro values are listed in Table 4-3 and define the general mode of
the GPIO port.

46
Chapter 4 GPIO

Table 4-3. GPIO Mode Definitions


Mode Macro Name Value Description

GPIO_MODE_INPUT 0x00 Input mode


GPIO_MODE_OUTPUT_2_MHZ 0x02 Output mode, at 2 MHz
GPIO_MODE_OUTPUT_10_MHZ 0x01 Output mode, at 10 MHz
GPIO_MODE_OUTPUT_50_MHZ 0x03 Output mode, at 50 MHz

The macro GPIO_MODE_INPUT defines the GPIO pin as an input, as you would expect.
But there are three output mode macros listed.
Each output selection affects how quickly each output pin responds to a change.
In our example program, the 2 MHz option was selected. This was chosen because the
speed of an LED signal change is not going to be noticed by human eyes. By choosing 2
MHz, power is saved and EMI (electromagnetic interference) is reduced.
The third argument further specializes how the port should be configured. Table 4-4
lists the macro names provided.

Table 4-4. I/O Configuration Specializing Macros


Specialization Macro Name Value Description

GPIO_CNF_INPUT_ANALOG 0x00 Analog input mode


GPIO_CNF_INPUT_FLOAT 0x01 Digital input, floating (default)
GPIO_CNF_INPUT_PULL_UPDOWN 0x02 Digital input, pull up and down
GPIO_CNF_OUTPUT_PUSHPULL 0x00 Digital output, push/pull
GPIO_CNF_OUTPUT_OPENDRAIN 0x01 Digital output, open drain
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL 0x02 Alternate function output, push/pull
GPIO_CNF_OUTPUT_ALTFN_ 0x03 Alternate function output, open drain
OPENDRAIN

47
Chapter 4 GPIO

Input Ports
The macro names including INPUT only apply when the second argument implies an
input port. We see from Table 4-4 that inputs can be specialized three different ways:
• Analog
• Digital, floating input
• Digital, pull up and down

To make greater sense of the GPIO input and its configuration, examine the
simplified Figure 4-2.

Figure 4-2. Basic structure of the GPIO input

The MCU receiving side is on the left side, while the external input comes in from the
right. There are two protection diodes attached, which normally only come into play if
the static voltage goes negative or exceeds the supply.
When the input port is configured as an analog input, the switches connected to
resistors R1 and R2 are switched off. This is to avoid pulling the analog signal up or

48
Chapter 4 GPIO

down. With the resistors disconnected, the analog input is routed to the line labeled
“Analog Input” with no further signal effect for the ADC (analog-to-digital conversion)
peripheral. The Schmitt trigger is also disabled to save on power consumption.
When the input port is configured for digital input, resistors R1 or R2 are in operation
unless you select the “float” option GPIO_CNF_INPUT_FLOAT. For both digital input
modes, the Schmitt trigger is enabled to provide a cleaner signal with hystersis. The
output of the Schmitt trigger then goes to the “Alternate Function Input” and to the input
data (GPIO) register. More will be said about alternate functions later, but the simple
answer is that an input can act as a GPIO input or as a peripheral input.
The 5-volt-tolerant inputs are identical to the diagram shown in Figure 4-2, except that
the high side protective diode allows the voltage to rise above 3.3 volts to at least +5 volts.

Note When configuring a peripheral output, be sure to use one of the alternate
function macros. Otherwise, only GPIO signals will be configured.

O
 utput Ports
When the GPIO port is configured for output, you have four specializations to choose from:

• GPIO push/pull

• GPIO open drain

• Alternate function push/pull

• Alternate function open drain


For GPIO operation, you always choose the non-alternate function modes. For
peripheral use like the USART, you choose from the alternate function modes instead. A
common mistake is to configure for GPIO use, like GPIO_CNF_OUTPUT_PUSHPULL for the
TX output of the USART. The correct macro is GPIO_CNF_OUTPUT_ALTFN_PUSHPULL for the
peripheral. If you’re not seeing peripheral output, ask yourself if you chose from the one
of the alternate function values.
Figure 4-3 illustrates the block diagram for GPIO outputs. For 5-volt-tolerant outputs
(like the inputs), the only change to the circuit is that the high side protective diode is
capable of accepting voltages as high as +5 volts. For non-5-volt-tolerant ports, the high
side protective diode can only rise to +3.3 volts (actually, it can rise to one diode drop
above 3.3 volts).
49
Chapter 4 GPIO

The “output control” circuit determines if it is driving the P-MOS and N-MOS
transistors (in push/pull mode) or just the N-MOS (in open-drain mode). In open-drain
mode, the P-MOS transistor is always kept off. Only when you write a zero to the output
will the N-MOS transistor turn on and pull the output pin low. Writing a 1-bit to an open-­
drain port effectively disconnects the port since both transistors are put into the “off” state.
The weak input resistors shown in Figure 4-2 are disabled in output mode. For this
reason, they were omitted from Figure 4-3.
The output data bits are selected from either the output (GPIO) data register or
the alternate function source. GPIO outputs go to the output data register, which can
be written as an entire word or as individual bits. The bit set/reset register permits
individual GPIO bits to be altered as if they were one atomic operation. In other words,
an interrupt cannot occur in the middle of an “and/or” operation on a bit.
Because GPIO output data is captured in the output data register, it is possible to
read back what the current output settings are. This doesn’t work for alternate function
configurations, however.

Figure 4-3. The output GPIO driver circuit

50
Chapter 4 GPIO

When the output is configured for a peripheral like the USART, the data comes from
the peripheral through the alternate function output line. Seeing how the data is steered
in Figure 4-3 should emphasize the fact that you must configure the port for GPIO or
alternate functions. I am harping on this so that you won’t waste your time having to
debug this kind of problem.

D
 ucks in a Row
While the origin of the saying “to have one’s ducks in a row” is unclear, the one possibility
that I like refers to the fairground amusement of shooting at a row of mechanical ducks.
This arrangement makes it easier for the shooter to get them all and win the prize.
Peripherals on the STM32 platform are highly configurable, which also leaves more
than the usual opportunity for mistakes. Consequently, I’ll refer often to this idea of
getting your ducks in a row, as a shorthand recipe for success. When your peripheral
configuration is not working as expected, review the ducks-in-a-row list.
Often, the problem is an omission or the use of an incorrect macro that failed to
raise a compiler warning. Sequence is also often important—you need to enable a clock
before configuring a device that needs that clock, for example.

G
 PIO Inputs
When configuring GPIO input pins, use the following procedure to configure it. This
applies to GPIO inputs only—not a peripheral input, like the USART. Peripherals require
other considerations, especially if alternate pin configurations are involved (they will be
covered later in the book).

1. Enable the GPIO port clock. For example, if the GPIO pin is on
port C, then enable the clock with a call to rcc_periph_clock_
enable(RCC_GPIOC). You must enable each port used individually,
using the RCC_GPIOx macros.

2. Set the mode of the input pin with gpio_set_mode(), specifying


the port in argument one, and the GPIO_MODE_INPUT macro in
argument two.

51
Chapter 4 GPIO

3. Within the gpio_set_mode() call, choose the appropriate


specialization macro GPIO_CNF_INPUT_ANALOG, GPIO_CNF_INPUT_
FLOAT, or GPIO_INPUT_PULL_UPDOWN as appropriate.

4. Finally, specify in the last argument in the gpio_set_mode()


call all pin numbers that apply. These are or-ed together, as in
GPIO12|GPIO15, for example.

Digital Output, Push/Pull


Normally, digital outputs are configured for push/pull mode. This ducks-in-a-row advice
is provided for this normal case:

1. Enable the GPIO port clock. For example, if the GPIO pin is on
port B, then enable the clock with a call to rcc_periph_clock_
enable(RCC_GPIOB). You must enable each port used individually,
using the RCC_GPIOx macros.

2. Set the mode of the output pin with gpio_set_mode(), specifying


the port in argument one and one of the GPIO_MODE_OUTPUT_*_MHZ
macros in argument two. For non-critical signal rates, choose the
lowest value GPIO_MODE_OUTPUT_2_MHZ to save power and to lower
EMI.

3. Specify GPIO_CNF_OUTPUT_PUSHPULL in argument three in the call


to gpio_set_mode(). Do not use any of the ALTFN macros for GPIO
use (those are for peripheral use only).

4. Finally, specify in the last argument in the gpio_set_mode()


call all pin numbers that apply. These are or-ed together, as in
GPIO12|GPIO15, for example.

52
Chapter 4 GPIO

Digital Output, Open Drain


When working with a bus, where more than one transistor may be used to pull down
a voltage, an open-drain output may be required. Examples are found in I2C or CAN
bus communications. The following procedure is recommended for GPIO open-drain
outputs only (do not use this procedure for peripherals):

1. Enable the GPIO port clock. For example, if the GPIO pin is on
port B, then enable the clock with a call to rcc_periph_clock_
enable(RCC_GPIOB). You must enable each port used individually,
using the RCC_GPIOx macros.

2. Set the mode of the output pin with gpio_set_mode(), specifying


the port in argument one, and one of the GPIO_MODE_OUTPUT_*_
MHZ macros in argument two. For non-critical signal rates, choose
the lowest value GPIO_MODE_OUTPUT_2_MHZ to save power and to
lower EMI.

3. Specify GPIO_CNF_OUTPUT_OPENDRAIN in argument three in the call


to gpio_set_mode(). Do not use any of the ALTFN macros for GPIO
use (those are for peripheral use).

4. Finally, specify in the last argument in the gpio_set_mode()


call all pin numbers that apply (one or more). These are or-ed
together, as in GPIO12|GPIO15, for example.

G
 PIO Characteristics
This is a good place to summarize the capabilities of the STM32 GPIO pins. Many are
5-volt tolerant as inputs, while a few others are current limited for output. Using the
STM32 documentation convention, ports are often referenced as PB5, for example,
to refer to GPIO port B pin GPIO5. I’ll be using this convention throughout this book.
Table 4-5 summarizes these important GPIO characteristics as they apply to the Blue Pill
device.

53
Chapter 4 GPIO

Table 4-5. GPIO Capabilities: Except Where Noted, All GPIO Pins Can Source or
Sink a Maximum of 25 mA of Current
Pin GPIO_PORTA GPIO_PORTB GPIO_PORTC
3V/5V Reset Alt 3V/5V Reset Alt 3V/5V Reset Alt
GPIO0 3V PA0 Yes 3V PB0 Yes
GPIO1 3V PA1 Yes 3V PB1 Yes
GPIO2 3V PA2 Yes 5V PB2/BOOT1 No
GPIO3 3V PA3 Yes 5V JTDO Yes
GPIO4 3V PA4 Yes 5V JNTRST Yes
GPIO5 3V PA5 Yes 3V PB5 Yes
GPIO6 3V PA6 Yes 5V PB6 Yes
GPIO7 3V PA7 Yes 5V PB7 Yes
GPIO8 5V PA8 No 5V PB8 Yes
GPIO9 5V PA9 No 5V PB9 Yes
GPIO10 5V PA10 No 5V PB10 Yes
GPIO11 5V PA11 No 5V PB11 Yes
GPIO12 5V PA12 No 5V PB12 No
GPIO13 5V JTMS/SWDIO Yes 5V PB13 No 3V 3 mA @ 2 MHz Yes
GPIO14 5V JTCK/SWCLK Yes 5V PB14 No 3V 3 mA @ 2 MHz Yes
GPIO15 5V JTDI Yes 5V PB15 No 3V 3 mA @ 2 MHz Yes

The column ALT in Table 4-5 indicates where alternate functions can apply. Input
GPIOs marked with “5V” can safely tolerate a 5-volt signal, whereas the others marked
“3V” can only accept signals up to +3.3 volts. The column labeled Reset indicates the
state of the GPIO configuration after an MCU reset has occurred.
GPIO pins PC13, PC14, and PC15 are current limited. These can sink a maximum
of 3 mA and should never be used to source a current. Additionally, the documentation
indicates that these should never be configured for operations of more than 2 MHz when
configured as outputs.

54
Chapter 4 GPIO

Input Voltage Thresholds


Given that the STM32F103C8T6 can operate over a range of voltages, the GPIO input-­
threshold voltages follow a formula. Table 4-6 documents what you can expect for the
Blue Pill device, operating at +3.3 volts.

Table 4-6. Input-Voltage Thresholds Based Upon VDD  3.3volts


Symbol Description Range

Standard low-input voltage 0 to 1.164 volts


VIL
5-volt-tolerant inputs 0 to 1.166 volts
High-input voltage 1.155 to 3.3/5.0 volts
VIH

You may have noticed that there is a small overlap between the high end of the VIL
and the low end of the VIH range. The STM32 documentation indicates that there is
about 200 mV of hysterisis between these input states.

O
 utput-Voltage Thresholds
The output GPIO thresholds are documented in Table 4-7, based upon the Blue Pill
device operating at +3.3 volts. Note that the ranges degrade as current increases.

Table 4-7. GPIO Output-Voltage Levels with Current <= 20 mA


Symbol Description Range

Output voltage low 0.4 to 1.3 volts


VOL
Output voltage high 2 to 3.3 volts
VOH

55
Chapter 4 GPIO

P
 rogrammed Delays
Returning now to the program illustrated in Listing 4-1, let’s examine the timing aspect
of that program, repeated here for convenience:

0039:   for (;;) {
0040:       gpio_clear(GPIOC,GPIO13);      /* LED on */
0041:       for (i = 0; i < 1500000; i++)  /* Wait a bit. */
0042:           __asm__("nop");
0043:
0044:       gpio_set(GPIOC,GPIO13);        /* LED off */
0045:       for (i = 0; i < 500000; i++)   /* Wait a bit. */
0046:           __asm__("nop");
0047:   }

The first thing to notice about this segment is that the loop counts differ: 1,500,000 in
line 41 and 500,000 in line 45. This causes the LED to remain on 75 percent of the time
and turn off for 25 percent.
The __asm__("nop") statement forces the compiler to emit the ARM assembler
instruction nop as the body of both loops. Why is this necessary? Why not code an empty
loop like the following?

0041:       for (i = 0; i < 1500000; i++)    /* Wait a bit. */


0042:           ;  /* empty loop */

The problem with an empty loop is that the compiler may optimize it away.
Compiler optimization is always being improved, and this type of construct could
be seen as redundant and be removed from the compiled result. This feature is also
sensitive to the optimize options used for the compile. This __asm__ trick is one
way to force the compiler to always produce the loop code and perform the nop (no
operation) instruction.

56
Chapter 4 GPIO

The Problem with Programmed Delay


The good thing about programmed delays is that they are easy to code. But, beyond that,
there are problems:

• How many iterations do I need for a timed delay?

• Poor source code portability:

• the delay will vary for different platforms

• the delay will vary by CPU clock rate

• the delay will vary by different execution contexts

• Wastes CPU, which could be used by other tasks in a multi-tasking


environment

• The delays are unreliable when preemptive multi-tasking is used

The first problem is the difficulty of computing the number of iterations needed to
achieve a delay. This loop count depends upon several factors, as follows:

• The CPU clock rate

• The instruction cycle times used

• Single or multi-tasking environment

In the miniblink program, there was no CPU clock rate established. Consequently,
this code is at the mercy of the default used. By experiment, loop counts that “seem to
work” can be derived. But if you run the same loops from SRAM instead of flash, the
delays will be shorter. This is because there are no wait cycles necessary to fetch the
instruction words from SRAM. Fetching instructions from flash, on the other hand, may
involve wait cycles, depending upon the CPU clock rate chosen.
In a multi-tasking environment, like FreeRTOS, programmed delays are a poor choice.
One reason is because you don’t know how much time is consumed by the other tasks.
Finally, programmed delays are not portable to other platforms. Perhaps the source
code will be reused on an STM32F4 device, where the execution efficiency is different.
The code will need manual intervention to correct the timing deficiency.
All of these reasons are why FreeRTOS provides an API for timing and delay. This will
be examined later when we apply FreeRTOS in our demo programs.

57
Chapter 4 GPIO

Summary
This chapter has necessarily covered a lot of ground, even though we’re just getting started.
You’ve exercised the st-flash utility and programmed your device with the miniblink
program, which was a different blink program than the one supplied with your unit.
More interestingly, the libopencm3 GPIO API was discussed, and the miniblink
program was examined in detail. This explained GPIO configuration and operations.
Finally, the problems of programmed delays were discussed.

EXERCISES

1. What GPIO port does the built-in LED on the Blue Pill PCB use? Specify the
libopencm3 macro name for the port.

2. What GPIO pin does the built-in LED on the Blue Pill PCB use? Specify the
libopencm3 macro name.

3. What level is required to turn the built-in LED on for the Blue Pill PCB?

4. What are two factors affecting the chosen loop count in a programmed delay in
non-multi-tasking environments?

5. Why are programmed delays not used in a multi-tasking environment?

6. What three factors affect instruction timing?

7. What are the three modes of an input GPIO port?


8. Do the weak pull-up and pull-down resistors participate in an analog input?

9. When is the Schmitt trigger enabled for input ports?

10. Do the weak pull-up and pull-down resistors participate for output GPIO ports?

11. When configuring a USART TX (transmit) output for push/pull operation, which
specialization macro should be used?

12. When configuring a pin for LED use, which GPIO mode macro is preferred for
low EMI?

58

You might also like