This tutorial shows how to configure and use the GPIO pins of the STM32F407. The example switches around the LEDs by setting and resetting I/O pins according to the number of button presses.
Again the comments should explain the procedure pretty well. If the code view is to bad on this site, please hop over to GitHub, where you can have a better look at the code.
#include <stm32f4xx.h>
#include <stm32f4xx_gpio.h>
void Delay(__IO uint32_t nCount) {
while(nCount--) {
}
}
/* This funcion shows how to initialize
* the GPIO pins on GPIOD and how to configure
* them as inputs and outputs
*/
void init_GPIO(void){
/* This TypeDef is a structure defined in the
* ST's library and it contains all the properties
* the corresponding peripheral has, such as output mode,
* pullup / pulldown resistors etc.
*
* These structures are defined for every peripheral so
* every peripheral has it's own TypeDef. The good news is
* they always work the same so once you've got a hang
* of it you can initialize any peripheral.
*
* The properties of the periperals can be found in the corresponding
* header file e.g. stm32f4xx_gpio.h and the source file stm32f4xx_gpio.c
*/
GPIO_InitTypeDef GPIO_InitStruct;
/* This enables the peripheral clock to the GPIOD IO module
* Every peripheral's clock has to be enabled
*
* The STM32F4 Discovery's User Manual and the STM32F407VGT6's
* datasheet contain the information which peripheral clock has to be used.
*
* It is also mentioned at the beginning of the peripheral library's
* source file, e.g. stm32f4xx_gpio.c
*/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
/* In this block of instructions all the properties
* of the peripheral, the GPIO port in this case,
* are filled with actual information and then
* given to the Init function which takes care of
* the low level stuff (setting the correct bits in the
* peripheral's control register)
*
*
* The LEDs on the STM324F Discovery are connected to the
* pins PD12 thru PD15
*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_15 | GPIO_Pin_14 | GPIO_Pin_13 | GPIO_Pin_12; // we want to configure all LED GPIO pins
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; // we want the pins to be an output
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // this sets the GPIO modules clock speed
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; // this sets the pin type to push / pull (as opposed to open drain)
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; // this sets the pullup / pulldown resistors to be inactive
GPIO_Init(GPIOD, &GPIO_InitStruct); // this finally passes all the values to the GPIO_Init function which takes care of setting the corresponding bits.
/* This enables the peripheral clock to
* the GPIOA IO module
*/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
/* Here the GPIOA module is initialized.
* We want to use PA0 as an input because
* the USER button on the board is connected
* between this pin and VCC.
*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; // we want to configure PA0
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN; // we want it to be an input
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;//this sets the GPIO modules clock speed
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; // this sets the pin type to push / pull (as opposed to open drain)
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN; // this enables the pulldown resistor --> we want to detect a high level
GPIO_Init(GPIOA, &GPIO_InitStruct); // this passes the configuration to the Init function which takes care of the low level stuff
}
int main(void){
// initialize the GPIO pins we need
init_GPIO();
/* This flashed the LEDs on the board once
* Two registers are used to set the pins (pin level is VCC)
* or to reset the pins (pin level is GND)
*
* BSRR stands for bit set/reset register
* it is seperated into a high and a low word (each of 16 bit size)
*
* A logical 1 in BSRRL will set the pin and a logical 1 in BSRRH will
* reset the pin. A logical 0 in either register has no effect
*/
GPIOD->BSRRL = 0xF000; // set PD12 thru PD15
Delay(1000000L); // wait a short period of time
GPIOD->BSRRH = 0xF000; // reset PD12 thru PD15
// this counter is used to count the number of button presses
uint8_t i = 0;
while (1){
/* Every GPIO port has an input and
* output data register, ODR and IDR
* respectively, which hold the status of the pin
*
* Here the IDR of GPIOA is checked whether bit 0 is
* set or not. If it's set the button is pressed
*/
if(GPIOA->IDR & 0x0001){
// if the number of button presses is greater than 4, reset the counter (we start counting from 0!)
if(i > 3){
i = 0;
}
else{ // if it's smaller than 4, switch the LEDs
switch(i){
case 0:
GPIOD->BSRRL = 0x1000; // this sets LED1 (green)
GPIOD->BSRRH = 0x8000; // this resets LED4 (blue)
break;
case 1:
GPIOD->BSRRL = 0x2000; // this sets LED2 (orange)
GPIOD->BSRRH = 0x1000; // this resets LED1
break;
case 2:
GPIOD->BSRRL = 0x4000; // this sets LED3 (red)
GPIOD->BSRRH = 0x2000; // this resets LED2
break;
case 3:
GPIOD->BSRRL = 0x8000; // this sets LED4
GPIOD->BSRRH = 0x4000; // this resets LED3
break;
}
i++; // increase the counter every time the switch is pressed
}
Delay(3000000L); // add a small delay to debounce the switch
}
}
}

thanks alot for this code, it is wonderful and helpful.
i want to ask about the “Delay function”, like: Delay(3000000L);
3000000L : how much does is it ?and which unit? us or msec
and do we have any other forms for the delay function
It basically is 3000000 instruction cycles, because comparing the value with 0 takes 1 cycle, decrementing the variable takes another. I am not entirely sure because I’m not familiar with the internal instruction set and workings but that’s pretty much how it would work for an 8 bit micro.
So for short, I don’t know
Correction to my comment re: time delay…I have tested my clock speed using led blinking and oscilloscope and I’m actually running at about 83MHz, around half of the max 168MHz. Thus, one clock tick was (1/83) 10^(-6) seconds, and on my device that x your delay of 3e6 gives you seconds of delay. Actually, I extended it more.
In fact, TIM2 also same frequency without prescale(well, set by me for 0 which defaults to 1 according to Ref Manual).
A late correction: I discovered that in fact my system clock is running at 11.4Mz….I tested this by using the Delay function to toggle bits(no interrupt) and monitored on oscilloscope.
Research shows that in fact after reset(or startup I guess) the F4 chip is set to select the HSI clock which has a maximum of 16Mhz.
An Excel based configuration tool is available from STM, but does not work under Excel 2010 no matter what I do to allow Macros to run, including “Trust Center” modifications.
In my brief experience with AVR timers, I would guess that since every count takes a clock cycle, that, at 50MHz one count would then take the inverse of that frequency(period), so multiplying by 1000000 would give you how many seconds delay. Thus: .02 sec or 20msec.
Someone please correct me if I’m wrong.
Question: I have seen other LED examples in which pupd was set for Pullup.
What’s diff in this case?
Well the pull up or pull down resistors pull the GPIO pin high or low (respectively) when not driven by the GPIO driver circuitry.
I have disabled the pull up / down resistors because in this case it doesn’t really matter because we are using the GPIO pins connected to the LEDs as outputs.
The internal pull up / down resistors are intended for use when the GPIO pin is set to be an input. In that case you might only want to detect a low level on a button for example. You will use the internal pull up resistor in order to set the input pin to a defined level.
Elia,
Thank you.
How did you decide on 50MHz for I/O ?
That is more of a random setting
For this simple task any I/O speed would suffice.
The STM32F4 allows us to choose from 2, 25, 50 and 100 MHz GPIO speed.
Hey man
i have trouble with
“cannot open source input file “stm32f4xx_gpio.h”"
eventhough i include file in the running system
Im new to this program
can you explain how to avoid that error?
NIce tutorial! I was wondering if the GPIO pins could be connected to an amplifier like a LM386. I am trying to amplify an audio signal but instead of sending the amplified signal out to a speaker I want to send it back to the F4 board, go through an ADC, and be able to transfer the data. I know it sounds pointless but is it possible?
This is great work! I have done mostly arduino in the past and have been really wanting to get into ARM but there seems to be not a lot of resources on that basics such as toggling GPIO pins. I really appreciate you taking the time to do this, it helped me break through that initial mental block and get started.
That’s why I put the information up! I have had several problems with this when I started off using the STM32 micros
Hi,
Great tut! What does __IO mean?
I am currently using Keil uVision 4 Lite Edition. How do I use the tutorial code with inc and src files in uVision? I am confused on how to structure it out and get it to build and load.
Yep I had problems with that as well. It’s a tricky one to figure out as there are alot of options you have to set exactly right to get it to work (mostly because Keil is a general IDE for ARM core based controllers by all manufacturers or at least tries to be).
The easiest way to set up a workspace is downloading the STM32F4 Discovery Firmware package from the STM32F4 Discovery product page, extracting it and opening the Master Workspace project with Keil (located in the Mater Workspace folder).
Cheers,
Elia
Update: Here is a dedicated page on that
if anybody can tell me how to configure the core processor frequency ??
Can I use two different pins on the same port as Output and AF??
Do I have to write a separate initialisation block each time???
Yes, you can use other pins on the same port as output.
You can configure each pin individually to be either AF or output.
Cheers,
Elia
Really your blog has been wonderful….Good luck to you…Evn though i just got a BEng in electronics, i couldn’t figure some stuff in the discovery board and read your blog to get through…. You should be really proud of yourself….. Good luck for your future endeavours!!!! …..Lahiru from Sri Lanka
hi, i am extreme new to this, can i know where to get #include header files
This was extremely helpful to me getting started. To make it easier to prototype new code I put together a small library that handles the pins much like the arduino platform. It also allows you to set up serial ports quickly. The library still has a ways to go to get the serial ports fully functional but the basic uses are there. I posted the library and a quick guide on my site. anyone is free to use it and add to it if they wish Girshwin.com/pinsandports
Pingback: Blink for stm32f4-discovery board on Linux with Makefile | Liviu's blog
Good working example for newbie’s…