Understanding Embedded Software: STM32 GPIO
Photo by Clint Patterson on Unsplash

Understanding Embedded Software: STM32 GPIO

An Introduction

This is a first in what I hope to be a series of articles written as a way for me to explain concepts as I understand them and hopefully to assist anyone starting out with microcontroller programming, whether you starting from zero or if you have some knowledge from working in a similar field like software or computer engineering.  

So how exactly does a microcontroller interact with the physical world? How does it sense change and how does it trigger actions? A peripheral would be responsible for that and the most basic one to learn about and use is the GPIO (General Purpose Input Output). 

It's often the first peripheral that people learn about and can be thought of as something that's configured as an input or output. There's more to it than that but in simple terms that's a pretty good way to think of it.

As an input the GPIO tells the microcontroller whether a binary voltage level is present or not. This could be used, for example, to see whether a button has been pressed or not. As an output the microcontroller tells the GPIO to activate or deactivate that binary voltage level on the pin. For example, that pin could be used to light up an LED or send a control signal to some other piece of circuitry. 

The focus here will be on the concepts around GPIO usage illustrated through the STM32 microcontroller family and ST's HAL software. You may have some IDE or other tool-chain setup up and running I'm not going into that stuff here. For generating HAL code, ST has provided it's CubeMX software which depending on your setup, requires quite a manual process to import into your project or it's all integrated and easy. In most cases you are not really going through the code that gets generated to understand it, even on such an abstracted level. That's an area that I'm hoping to provide more information on with this article. If you're new to CubeMX entirely I suggest you have a look at that, it's useful to know how to configure it for setting up your projects. 

What you need to know and understand

It would be best it you already had a project in mind as you go through this, that's often a better way to learn. Otherwise I also hope that this serves as something informative as you jump into things if you're feeling overwhelmed by datasheets and other large documents. 

One thing that needs to be understood is that a microcontroller is essentially made up of registers, memory and instructions. Perhaps it's appropriate to understand the basics of what a microcontroller contains you can quickly look that up here.

If you understand things on that level then you should be able to navigate your way around and figure out whatever you need to. 

This is certainly not a definitive way to describe the GPIO peripheral of microcontrollers in general but this is simply the way I've chosen to explain things according to my understanding.

Setting up the GPIO

No alt text provided for this image

 Figure 1: Bus Architecture for one of the STM32 microcontrollers


The GPIO is one of many peripherals connected to the CPU through an order of buses. You can see the bus network in the above figure. In order to better understand how to operate and configure the GPIO it's useful to know the names and which specific buses are connected to which memory location (Not specifically which address in memory but just to understand how each connects). These buses also link to different clock sources which determine how fast a peripheral will run and whether it will run at all which is of course important to know.

Now you know that peripherals are connected through buses, you should also know that the peripherals themselves are stored in physical memory locations each allocated a certain amount of memory with it's own address in what is called the peripheral memory space. This is illustrated in the following diagram.

No alt text provided for this image

  Figure 2: Memory Map for peripherals (representation of an STM32F030) 

The way that space is organized is specific to a given family of microcontrollers within the STM32 range. What's notable is that a peripheral has a starting address and then a range that it occupies. 

No alt text provided for this image

 Table 1: Peripheral Memory Space from the STM32F10xx reference manual 

The above table gives the address spaces for peripherals including the GPIO ports. It also shows that they are connected to the APB2 bus. I know these diagrams have not consistently been from a series of family but you may be able to see how the concepts follow through and how you would navigate this kind of information if you were looking into a specific device on your own.

The individual peripheral is further mapped down into it's own organization of registers. 

No alt text provided for this image

Figure 3: Register bits (from the STM32F10xx reference manual) 

The peripheral is controlled by reading from and writing to these registers. The way peripherals are mapped will differ among different families(F0, F1, L4 etc.) and even each member of a family (F103, F401 etc.) will implement peripherals differently. You would need to look for how these specific peripherals work for your device and how to configure them using the datasheet and reference manual but understanding how it all works together in general can go a long way in helping you navigate these kinds of documents.

That being said the ST HAL is there to abstract from the specific peripheral mappings that you would usually need to deal with. It does this by defining handlers which are simply just C structs whose reference points to the real address.  

When starting your own project and setting up your peripherals you would begin by setting up these handlers with the specific settings that you want use to configure your peripheral. You would also need to activate the clocks through the appropriate bus as was mentioned a bit earlier.

The ST HAL provides functions that configure the peripheral with those settings without you needing to know much about the registers address's or having to do any of the calculations using bitwise operations in writing to the bits in each register.

Once that's complete then you can simply make use of the API calls that the ST HAL provides you with in your application going further. 

Going through an example with a real board 

Let's go through the process of setting up two pins on an STM32F103 device. One as an input and one as an output. First you would want to look at which pins you would want to use on your board. They are usually labelled on the PCB. I'm going to use the pins labelled B7 and B9 for input and output respectively. Other devices may involve fewer or extra steps but for the most part it's very much the same. 

No alt text provided for this image

Figure 4: Pins B7 and B9 on an STM32F103 development board 

The labels format (i.e. B7, B8, B9 etc.) tells us two important things we need to know. Namely the Port we want to use and the particular pins we want to configure. So the pins I've chosen would be pins 7 and 9 on GPIOB. Since I want to set up B7 as an input pin so I would specify that mode of operation to the handler. There are other modes like alternate functions to choose but I won't go into detail here. Another important parameter to choose is the use of an internal pull-up or pull-down which determines which way you want to an input. For example if you had a button this input would make it so that a pressed button puts a low voltage on the pin or high voltage.   

The setup then goes as follows:

  • Create an instance of the GPIO_InitTypeDef. Call it GPIO_InitStruct if you like.
  • Enable the port clock. For GPIOB this would be: __HAL_RCC_GPIOB_CLK_ENABLE 
  • Set the parameters of the GPIO_InitStruct

      ex: GPIO_InitStruct.Pin = GPIO_PIN_9;        

GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

         GPIO_InitStruct.Pull = GPIO_NOPULL;

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

  • Pass those settings to the appropriate GPIO Port using the HAL setup function

         ex:  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

And that's it. Now your free to use the API function calls that the ST HAL provides to drive your active GPIO pins 

ST HAL for a GPIO application use

You'll notice going through the setup that you've completed most of the work and you won't need to deal with that much once you've gotten deep into your application code unless you need to change settings or setup another pin. You may need to debug the setup if it hasn't been done properly but since you now know how that all works you should have a little more confidence going into it. 

As far as driving the GPIO pins, it's much more simple and the ST HAL provides four main functions for doing this. You may only really care about two or three of these. They are:

  • GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)

This one accepts the GPIO Port and specific pin as parameters and then returns the pin state. So basically this is the way to read the pin state of a pin set as an input

  • void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)

This is the opposite routine which returns nothing and instead accepts an additional parameter which is the pin state as this function set the state. Therefore this function is used for pins set as an output. 

  • void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)

Similar to the previous function, however without needing to specify the state. This one conveniently inverts the pin state from whatever its current state is to the opposite. 

  • HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)

Finally the ST HAL gives you a function that allows you to lock the configuration of a GPIO pin. Any attempts to change it while this setting is on will fail until the device is reset. 

And for all that setup, for an application that just turns on a pin when you press a button you would only need something like this in you while loop in a project where b1State is a variable to hold the GPIO input state that we're reading. Of course your application would be much more complex but as for GPIO setup you'd be good to go from this point on. 

No alt text provided for this image

Figure 5: HAL API usage code snippet

In Conclusion

I hope that this article has been useful in relaying the most important aspects to know about the GPIO peripheral. There's lots more to know when it comes to the nitty-gritty details as well the other ways you can configure these things. Hopefully this has been enough to give a good idea of what you're dealing with and also a framework to move forward as you learn more things. If you've found this article useful in some way feel free to let me know. If you're an expert and notice some things missing or under-covered let me know as well, I appreciate the feedback.

Victor Grenke

Algorithms of Digital Signal & Image Processing, Embedded Software, Team leader of SW/FW/HW at SpecForge, Video Streaming technology specialist of Streamedian

4 年

for particle photon as on the picture?

回复

Well done Turyn!

要查看或添加评论,请登录

Turyn Lim Banda的更多文章

  • 3 Sales Lessons Engineers Can Learn from the Creation of Ethernet

    3 Sales Lessons Engineers Can Learn from the Creation of Ethernet

    Lessons from the inventor of ethernet Let me tell you a story about Bob. Bob invented ethernet and got rich.

  • RTOS vs OS: The predator’s perspective

    RTOS vs OS: The predator’s perspective

    What is a Real-Time Operating System? Have you ever heard the word Real-Time Operating System (RTOS) and then wondered…

  • AWS Well-Architected Labs Review: Security Pillar (First Attempt)

    AWS Well-Architected Labs Review: Security Pillar (First Attempt)

    In my last technical tutorial post, I recommended diving into some of the services used to build the project and the…

  • Cloud Project?-?Build a simple web application

    Cloud Project?-?Build a simple web application

    This is the first in a series of posts documenting simple AWS cloud projects. The idea is to create a list of projects…

  • Zero to One - the better way of Learning AWS?

    Zero to One - the better way of Learning AWS?

    So you’ve decided that you want to learn about AWS(or some other cloud ecosystem) but you don’t know how to start your…

    2 条评论
  • Sleep is for the week

    Sleep is for the week

    To sleep or not to sleep? If you could choose to have the ability to live life without needing to sleep would you do…

    2 条评论
  • The Terrifyingly Exciting Opportunity of a Blank Canvas

    The Terrifyingly Exciting Opportunity of a Blank Canvas

    Decisions and Painting We all face decisions in life, whether making big decisions such as choosing a career path or…

    4 条评论
  • Embedded Software with STM32: DMA

    Embedded Software with STM32: DMA

    What is it and why learn about DMA? DMA(Direct Memory Access) is an important concept in computer architecture and has…

  • Intro to MQTT

    Intro to MQTT

    MQTT: The basics There are plenty ways to move data around. Different use cases present different challenges.

  • In appreciation of Colour

    In appreciation of Colour

    Colours are great. They bring a wondrous joy into our lives and in many ways.

社区洞察

其他会员也浏览了