STM32 GPIO - EPFL-MICRO-315/TPs-Wiki GitHub Wiki

⚠ wiki page used in TP1

GPIO configuration

  • In this example we configure pin 11 of port GPIOD, which is connected to LED7
  • To be able to use the GPIOD peripheral we need to enable its clock
  • All GPIOs are on the AHB1 bus
    • 💡 You can find this information in the Reference Manual or in the datasheet in chapter Memory map
  • Here, we enable GPIOD clock by setting GPIODEN bit in the AHB1ENR register, which is shown in the figure below
  • The peripheral registers and bit masks are conveniently defined in stm32f407xx.h as shown in listing below
    #define RCC_AHB1ENR_GPIODEN_Pos            (3U)
    #define RCC_AHB1ENR_GPIODEN_Msk            (0x1U << RCC_AHB1ENR_GPIODEN_Pos)   /*!< 0x00000008 */
    #define RCC_AHB1ENR_GPIODEN                RCC_AHB1ENR_GPIODEN_Msk
    
  • Register access happens through C structures which are grouped by peripheral
  • The RCC struct groups the Reset and clock control and contains the AHB1EN
    typedef struct
    {
      __IO uint32_t CR;
      __IO uint32_t PLLCFGR;
      __IO uint32_t CFGR;
      __IO uint32_t CIR;
      __IO uint32_t AHB1RSTR;
      __IO uint32_t AHB2RSTR;
      __IO uint32_t AHB3RSTR;
      uint32_t      RESERVED0;
      __IO uint32_t APB1RSTR;
      __IO uint32_t APB2RSTR;
      uint32_t      RESERVED1[2];
      __IO uint32_t AHB1ENR;
      __IO uint32_t AHB2ENR;
      __IO uint32_t AHB3ENR;
      uint32_t      RESERVED2;
      __IO uint32_t APB1ENR;
      __IO uint32_t APB2ENR;
      uint32_t      RESERVED3[2];
      __IO uint32_t AHB1LPENR;
      __IO uint32_t AHB2LPENR;
      __IO uint32_t AHB3LPENR;
      uint32_t      RESERVED4;
      __IO uint32_t APB1LPENR;
      __IO uint32_t APB2LPENR;
      uint32_t      RESERVED5[2];
      __IO uint32_t BDCR;
      __IO uint32_t CSR;
      uint32_t      RESERVED6[2];
      __IO uint32_t SSCGR;
      __IO uint32_t PLLI2SCFGR;
    } RCC_TypeDef;
    #define RCC                 ((RCC_TypeDef *) RCC_BASE) //Here RCC_BASE is just an address
    
  • Below is the code to enable the clock
    // enable GPIOD clock
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;
    

GPIO Peripheral

  • A General-purpose I/O (GPIO) port has up to 16 I/O pins which can be configured individually
  • The figure below shows the basic GPIO structure for one port bit
  • Study the schema to get an understanding of the peripheral functions
  • A GPIO pin has 4 configuration registers:
    • MODER: Mode configuration (input, output, alternate function or analog)
    • OTYPER: Output type (push-pull or open-drain)
    • PUPDR: pull type (pull-up, pull-down or floating)
    • OSPEEDR: output speed (4 levels)

WARNING

  1. If you configure the wrong GPIO as output you can damage the robot!
    So double check that the configurations are correctly done before running your code
  2. GPIOs managing the drivers of the motors (A3901) must be use with caution. Consult EPuck2 Motor for more details.

  • Go through chapter 8.4 GPIO registers on page 283 of the Reference Manual to find out which bits to set to configure a GPIO pin as open-drain output
  • Below is the code to configure LED7 - GPIOD 11 as an open-drain output
    // LED7 - GPIOD 11
    #define LED7_PORT	GPIOD
    #define LED7_PIN	11
    
    // Enable GPIOD peripheral clock
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;
    
    // Output mode : MODERy = 01
    LED7_PORT->MODER = (LED7_PORT->MODER & ~(3 << (LED7_PIN * 2))) | (1 << (LED7_PIN * 2));
    // Output type open-drain : OTy = 1
    LED7_PORT->OTYPER |= (1 << LED7_PIN);
    // Output data low : ODRy = 0
    LED7_PORT->ODR &= ~(1 << LED7_PIN);
    // Floating, no pull-up/down : PUPDRy = 00
    LED7_PORT->PUPDR &= ~(3 << (LED7_PIN * 2));
    // Output highest speed : OSPEEDRy = 11
    LED7_PORT->OSPEEDR |= (3 << (LED7_PIN * 2));
    

GPIO data access

  • There are 3 registers to access the GPIO input and output data:
    • GPIO->IDR Input data register: allows reading GPIO input state and
    • GPIO->ODR Output data register: allows writing GPIO output state
    • GPIO->BSRR Bit set/reset register
  • To change the output state of a pin you have to read the register value, apply a bit mask and write it back to the register
  • ⚠ This can be problematic because between read and write an interrupt can occur and the same register might be accessed form the interrupt service routine
  • In this case the change from the interrupt will be overwritten by the write back of the base program
  • 💡 To address this problem there is a third 32bit register, the BSRR, which is write-only
  • It allows setting and resetting ODR bits by one write access
  • Writing a one to the upper 16 bits will reset the corresponding bit in ODR to 0, while writing a one to the lower 16 bits will set the corresponding bit to 1