Write a driver to listen to button push event then blink led
Tool
Board STm32F411RE
Cube IDE
Datasheet
Reference manual
User manual
1. Open User manual to locate led and button pin
To confirm the port and pin, we check the board selector in CubeIDE
Now we know that LED is on PA15 (port A pin 5), button is on PC 13 (Port C pin 13). We go to block diagram to check the bus that connect to that port. We need to enable clock to the bus before communicating with the ports
To check the bus, go to Datasheet-> block diagram
Both ports are on bus AHB1
2. Download header file
Now go to ST website and download the STM32CubeF4. This contains the header for controlling the register so that we don't need to calculate the bit location manually.
Get the latest here
We will keep these folders and delete all the remaining
\STM32Cube_FW_F4_V1.28.0\Drivers\CMSIS\Include
\STM32Cube_FW_F4_V1.28.0\Drivers\CMSIS\Device\ST\STM32F4xx
3. Create new project
Create new project with STM32F411 component
Then import the header folder to Cube project
4. Source code
If we do not have stm32f4xx header, we will have to define the register location manually
In the code, we wil use structs provided by the header.
/*
#define PERIPH_BASE (0x40000000UL)
#define AHB1PERIPH_OFFSET (0x00020000UL)
#define AHB1PERIPH_BASE (PERIPH_BASE + AHB1PERIPH_OFFSET)
#define GPIOA_OFFSET (0x0000UL)
#define GPIOA_BASE (AHB1PERIPH_BASE + GPIOA_OFFSET)
#define RCC_OFFSET (0x3800UL)
#define RCC_BASE (AHB1PERIPH_BASE + RCC_OFFSET)
#define AHB1EN_R_OFFSET (0x30UL)
#define RCC_AHB1EN_R (*(volatile unsigned int*)(RCC_BASE + AHB1EN_R_OFFSET))
#define MODE_R_OFFSET (0x00UL)
#define GPIOA_MODE_R (*(volatile unsigned int*)(GPIOA_BASE + MODE_R_OFFSET))
#define OD_R_OFFSET (0x14UL)
#define GPIOA_OD_R (*(volatile unsigned int*)(GPIOA_BASE + OD_R_OFFSET))
*/
Using header
#include "stm32f4xx.h"
#define GPIOAEN (1U<<0)
#define GPIOCEN (1U<<2)
#define PIN5 (1U<<5)
#define PIN13 (1U<<13)
#define LED_PIN PIN5
#define BTN_PIN PIN13
int main(void){
// set clock for bus
RCC->AHB1ENR |= GPIOAEN;
RCC->AHB1ENR |= GPIOCEN;
//set mode register for port A and port C
GPIOA->MODER |= (1U<<10);
GPIOA->MODER&=~(1U<<11);
GPIOC->MODER &=~(1U<<26);
GPIOC->MODER &=~(1U<<27);
// reset led into off state
//GPIOA->ODR &= ~LED_PIN;
GPIOA->BSRR = (1U<<21);
// blink loop
while(1){
if(GPIOC->IDR & BTN_PIN){//if
GPIOA->BSRR |= (1U<<21);
}
else{
while (1){
//GPIOA->ODR|= LED_PIN;
GPIOA->BSRR |= LED_PIN;
for(int i = 0; i < 100000; i++){}//delay
//GPIOA->ODR &= ~LED_PIN;
GPIOA->BSRR |= (1U<<21);
for(int i = 0; i < 100000; i++){}//delay
if(GPIOC->IDR & BTN_PIN){
break;
}
}
}
}
}
Explain
1. Go to memory mapping in datasheet
We can see that AHB1 bus register starts at 0x4002 0000 and the root address of all registers starts at 0x4000 0000. From this, we will define all register that we need to control the ports.
2. Register needed
All information is in Reference manual document
- RCC AHB1: provide clock to AHB1 bus
Port A is at pin 0, port C is at pin 2.
- Mode register: to set operation mode for each port.
We use port A to set led, port C to receive button event so port A will be output mode, port C will be input mode
Set led at Port A pin 5, so bit 11 and 10 of mode register should be 01.
Receive button event at Port C pin 13 so bit 27 26 of mode register should be 00.
3. Set led
We have 2 ways to set led. One is to set data pin, the other is to set reset pin.
- Set data pin Find data register
Since led pin is in pin 5. We set led on off by setting bit 5 with 1 or 0
GPIOA->ODR|= LED_PIN;
GPIOA->ODR &= ~LED_PIN;
- Set/reset bit reset register
Set pin 5 bit 5 in reset in bit 21. So the code is
GPIOA->BSRR |= LED_PIN;
GPIOA->BSRR |= (1U<<21);
- To listen to button event, we will listen to pin 13 of input data register
GPIOC->IDR & BTN_PIN
if bit is 1, button is released, 0 button is pressed
Here we have pullup, pulldown transistor for button
- We need pullup transistor so that when button is not pressed, the state will be pulled up to HIGH
- We need pulldown transistor so that when button is pressed, the state will be pulled down to LOW