GPIO is one of the first things that people want to use when they start with a microcontroller.

The GPIO on the STM32F103 is very similar to other systems though the implementation in C is more complicated than the Arduino WiringC implementation.

stm32f103c8cb-pinlayout-wp01

Initial Defines

For the purpose of this example code a few items will be defined to simplify reading and writing of code.

In the below code, the two pins used, input and output, are defined. As all of the functions used later on refer to the pins by the 'Channel' and the pin number. We define OUT_A0 and IN_A1 as the combination of both of these values. The comma separation allows them to be used as function inputs.

//Define GPIO pins
#define OUT_A0       GPIOA, GPIO_Pin_0
#define IN_A1       GPIOA, GPIO_Pin_1

We additionally redefine the GPIO_WriteBit and GPIO_ReadInputDataBit functions as GPIO_Read and GPIO_Write for ease of reading and writing.

//Reading and writing bits can be simplified by redefining the functions
#define GPIO_Write(pin, value)  GPIO_WriteBit(pin, value)
#define GPIO_Read(pin)          GPIO_ReadInputDataBit(pin)

General Pin Setup

The setup of the GPIO takes place through use of a GPIO_InitStruct which contains all of the confuguration details for a given pin. The contents of this struct will be discussed later. The contents of the Struct are applied through the use of the GPIO_Init function.

In addition, the peripheral clock for the GPIO channel has to be enabled. This enables the passthrough of the system clock to the GPIO peripheral.

GPIO_InitTypeDef GPIO_InitStruct;

// Enable clock for GPIOA
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
...
//Initialize GPIOX
GPIO_Init(GPIOX, &GPIO_InitStruct);

GPIO Speed Configuration

In the Configuration of the GPIO pins a GPIO_Speed parameter has to be chosen which defines the rise and fall time of the output. This should generally be chosen to be as low as possible for the application as an increased speed comes with increased noise. Which, depending on the application, can cause crosstalk between channels.

The speeds available for the STM32F103 are:

GPIO_Speed_10MHz
GPIO_Speed_2MHz
GPIO_Speed_50MHz

GPIO Mode Configuration

The GPIO mode must be defined in order to determine the function of the pins. The mode determines parameters like Input and Output but also how the pin behaves when this function is used.

The pin modes available on the STM32F103 are as follow:

GPIO_Mode_IN_FLOATING

The floating input mode configures the pin as an input where no pull up or pull down resistors are connected. This means that when a floating input is connected, the measured value will be undefined. This can be used when there is an external pull down resistor or voltage divider.

It is very important to make sure that the voltage input is known in this situation.

GPIO_Mode_IPD

The input pull-down mode includes a pull down resistor so that the voltage on the pin will approach ground when no input is given, This mode is good for active high signals.

GPIO_Mode_IPU

The Input pull-up mode is the reverse of the IPD mode where the pin approaches vcc when no input is given. This mode is useful when the signal pulls to ground, for example, a pushbutton linked to ground.

GPIO_Mode_Out_OD

Output open-drain mode sets the pin as an output but only actively pulls the pin to ground through a single transistor. When the pin is high, the voltage is floating.

GPIO_Mode_Out_PP

Output push-pull mode sets the pin as an output where the pin is actively pulled to ground or to vcc by two transistors.

GPIO_Mode_AF_OD and GPIO_Mode_AF_PP

The alternate function modes of OD and PP are used for when other peripherals like UART are used on the pins. This is limited to the pins where these peripherals are available.

GPIO_Mode_AIN

The analog-in mode is used, suprisingly, to set the pin as an analog input. The configuration for analog inputs will be visited in another post.

Output pin A0 Setup

Here we have an example for the configuration of an output pin which could be used in a simple circuit for lighting a LED.

// Configure Pin 0
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
    //Set Pin rise/fall time, should be set as low as possible for the application to avoid noise
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
    //set pin to output push/pull to be actively raised or lowered
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
    //initialize GPIOA with settings in &GPIO_InitStruct
    GPIO_Init(GPIOA, &GPIO_InitStruct);

Input pin A1 Setup

Here, an input pin is configured as a pull-up input for a pushbutton that links to ground when pressed.

// Configure pin 1
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
    //Set speed to 2mhz
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
    //Set mode to input with a pull-up resistor
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
    //Initialize gpio pin A1 with above settings
    GPIO_Init(GPIOA, &GPIO_InitStruct);

GPIO Read and Write Methods

Various methods are available for reading and writing bits, the simplest of which are used here for the demonstration of function.

while (1)
    {
        // If button on PA1 is pressed (button circuit is active low)
        if (!(GPIO_Read(IN_A1)))
        {
        	// Turn on output on PA0
            GPIO_Write(OUT_A0,1);
        }
        else
        {
            // Turn off output on PA0
        	GPIO_Write(OUT_A0,0);
        }
    }

Read Methods

The various read methods are:

GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)              //Read a single bit 
GPIO_ReadInputData(GPIO_TypeDef* GPIOx)                                    //Read all inputs
GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)             //Read output bit
GPIO_ReadOutputData(GPIO_TypeDef* GPIOx)                                   //Read all outputs

Write Methods

The various write methods are:

GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)                      //Sets bit to 1
GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)                    //Sets bit to 0
GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal)   //Writes bit as val
GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal)                         //writes all bits

Full Example Code

Here is a section of example code for controlling an LED with a pushbutton using the code discussed above.

#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"

/*
 * The content of this script has been written by Eric Falcon based on:
 *  https://sites.google.com/site/learningeclipsearm/5-using-stm32-std-lib/b-digital-io-pins
 *  No attribution is necessary when using this code as it's all very easy :D
 */

//Define GPIO pins
#define OUT_A0       GPIOA, GPIO_Pin_0
#define IN_A1       GPIOA, GPIO_Pin_1

//Reading and writing bits can be simplified by redefining the functions
#define GPIO_Write(pin, value)  GPIO_WriteBit(pin, value)
#define GPIO_Read(pin)          GPIO_ReadInputDataBit(pin)

GPIO_InitTypeDef GPIO_InitStruct;

int main(void)
{
    // Enable clock for GPIOA
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    // Configure Pin 0
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
    //Set Pin rise/fall time, should be set as low as possible for the application to avoid noise
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
    //set pin to output push/pull to be actively raised or lowered
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
    //initialize GPIOA with settings in &GPIO_InitStruct
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    // Configure pin 1
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
    //Set speed to 2mhz
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
    //Set mode to input with a pull-up resistor
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
    //Initialize gpio pin A1 with above settings
    GPIO_Init(GPIOA, &GPIO_InitStruct);



    while (1)
    {
        // If button on PA1 is pressed (button circuit is active low)
        if (!(GPIO_Read(IN_A1)))
        {
        	// Turn on output on PA0
            GPIO_Write(OUT_A0,1);
        }
        else
        {
            // Turn off output on PA0
        	GPIO_Write(OUT_A0,0);
        }
    }
}