1. GPIO_Init function analysis 1
1. Parameter GPIO_TypeDef 1
2. Parameter GPIO_InitStruct 2
3. Detailed explanation of function code 4
4. Note 6
1. GPIO_Init function analysis
First, let's look at the prototype of the GPIO_Init function void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct). This function is implemented in the Stm32f10x_gpio.c file. If you want to use this function, include the Stm32f10x_gpio.h header file in front of the corresponding application.
1. Parameter GPIO_TypeDef
The first parameter of this function is GPIO_TypeDef, which is a structure type defined in Stm32f10x.h. The prototype of the definition is:
typedef struct
{
__IO uint32_t CRL;
__IO uint32_t CRH;
__IO uint32_t IDR;
__IO uint32_t ODR;
__IO uint32_t BSRR;
__IO uint32_t BRR;
__IO uint32_t LCKR;
}GPIO_TypeDef;
There are 7 32 (8-byte) bit variables in this structure type, and the addresses of these variables in the storage space are adjacent. It is not difficult to see from the STM32 data sheet that each port corresponds to 16 pins, and 7 registers control the GPIO behavior, and the order of these 7 registers is also continuous. Each port has the same structure. The STM32 firmware library abstracts this structure into a type GPIO_TypeDef. Before operating the register, you must have a register mapping operation, otherwise you cannot access the specified register. Here we only need to map once instead of 7 times. Isn't it very convenient to do this? It also improves the readability of the code and makes the code standardized.
Since the first parameter of GPIO_Init is the pointer variable of GPIO_TypeDef, this pointer variable stores the first address of a certain port. The calling statement of a certain program is as follows GPIO_Init(GPIOD,&GPIO_InitStructure); //Initialize GPIOD
GPID is a macro defined in the firmware library. It will be expanded during compilation. The macro definitions related to the GPIOD port address mapping are listed as follows:
#define GPIOD ((GPIO_TypeDef *) GPIOD_BASE)
#define GPIOD_BASE (APB2PERIPH_BASE + 0x1400)
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
#define PERIPH_BASE ((uint32_t)0x40000000)
Are you familiar with the number 0x4000 0000? It is the first address of the peripheral. There are two STM32s inside the STM32 chip, one is called APB1 and the other is called APB2. Each APB bridge manages many peripherals. STM32F10x puts the peripheral register access addresses of these two APBs in different storage spaces. 0x10000 is the offset of the first address of the storage space of the APB2 peripheral relative to the entire peripheral. And 0x1400 is the offset of the first address of the GPIOD port peripheral relative to the first address of the storage space of the APB2 peripheral. In this way, the base address of the GPIOD peripheral is found! And ((GPIO_TypeDef *) GPIOD_BASE) can simultaneously realize the mapping of all 7 registers that control the GPIOD port. If you want to access a certain register, you only need to use a pointer to the GPIO_TypeDef variable.
2. Parameter GPIO_InitStruct
The second parameter is GPIO_InitTypeDef* GPIO_InitStruct. It is an address pointing to GPIO _InitTypeDef. The first parameter only finds the target register to be configured, and the second parameter is the data parameter for how to configure the corresponding port. These parameters are stored at the first address pointing to the GPIO_InitTypeDef variable. First, a piece of code from which this parameter comes
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitTypeDef is a structure variable, which is defined in the Stm32f10x_gpio.h header file. The prototype is as follows:
typedef struct
{
uint16_t GPIO_Pin;
GPIOSpeed_TypeDef GPIO_Speed;
GPIOMode_TypeDef GPIO_Mode;
}GPIO_InitTypeDef;
The first variable of GPIO_InitTypeDef is GPIO_Pin, which is a 16-bit unsigned number. This number has only 16 bits, and each bit represents a pin. To configure a pin of a port, you only need to set the corresponding bit to 1. The following pin number definitions are available in the STM32 firmware library:
#define GPIO_Pin_0 ((uint16_t)0x0001) /*!< Pin 0 selected */
#define GPIO_Pin_1 ((uint16_t)0x0002) /*!< Pin 1 selected */
#define GPIO_Pin_2 ((uint16_t)0x0004) /*!< Pin 2 selected */
#define GPIO_Pin_3 ((uint16_t)0x0008) /*!< Pin 3 selected */
#define GPIO_Pin_4 ((uint16_t)0x0010) /*!< Pin 4 selected */
#define GPIO_Pin_5 ((uint16_t)0x0020) /*!< Pin 5 selected */
#define GPIO_Pin_6 ((uint16_t)0x0040) /*!< Pin 6 selected */
#define GPIO_Pin_7 ((uint16_t)0x0080) /*!< Pin 7 selected */
#define GPIO_Pin_8 ((uint16_t)0x0100) /*!< Pin 8 selected */
#define GPIO_Pin_9 ((uint16_t)0x0200) /*!< Pin 9 selected */
#define GPIO_Pin_10 ((uint16_t)0x0400) /*!< Pin 10 selected */
#define GPIO_Pin_11 ((uint16_t)0x0800) /*!< Pin 11 selected */
#define GPIO_Pin_12 ((uint16_t)0x1000) /*!< Pin 12 selected */
#define GPIO_Pin_13 ((uint16_t)0x2000) /*!< Pin 13 selected */
#define GPIO_Pin_14 ((uint16_t)0x4000) /*!< Pin 14 selected */
#define GPIO_Pin_15 ((uint16_t)0x8000) /*!< Pin 15 selected */
#define GPIO_Pin_All ((uint16_t)0xFFFF) /*!< All pins selected */
It is much more convenient to use these defined macros. To configure some pins, you only need to OR the corresponding pins. If you want to configure all the bits of a certain port, you only need to use a macro GPIO_Pin_All. Simple, right? Haha!
GPIOSpeed_TypeDef is an enumeration variable that is used to store the parameters of GPIO speed. Its definition is as follows:
typedef enum
{
GPIO_Speed_10MHz = 1,
GPIO_Speed_2MHz,
GPIO_Speed_50MHz
}GPIOSpeed_TypeDef;
From the definition, we can know that the variable of GPIOSpeed_TypeDef has three values, so there are three GPIO speeds.
The value of the enumeration variable |
Corresponding speed |
1 |
10MHZ |
2 |
2MHZ |
3 |
50MHZ |
GPIOMode_TypeDef is also an enumeration variable, which is used to store the GPIO working mode. Its definition is as follows:
typedef enum
{GPIO_Mode_AIN = 0x0,
GPIO_Mode_IN_FLOATING = 0x04,
GPIO_Mode_IPD = 0x28,
GPIO_Mode_IPU = 0x48,
GPIO_Mode_Out_OD = 0x14,
GPIO_Mode_Out_PP = 0x10,
GPIO_Mode_AF_OD = 0x1C,
GPIO_Mode_AF_PP = 0x18
}GPIOMode_TypeDef;
The design of the possible values of this enumeration variable has a certain significance. In the fourth bit, only the upper two bits are used. These two bits are used to store the mode control bit MODEx[1:0] of a certain pin, while the upper four bits are used to mark certain flags.
The value of the upper four bits |
significance |
0 |
Input Mode |
1 |
Output Mode |
2 |
Pull-down input |
4 |
Pull-up input |
3. Detailed explanation of function code
The above is the explanation of the parameters of the GPIO_Init function. Now we can go inside the GPIO_Init function and take a look.
First, list the function code, and put the explanation of the code in the comments, as follows:
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
{
uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;
uint32_t tmpreg = 0x00, pinmask = 0x00;
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode));
assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin));
/*------------------------------- GPIO Mode Configuration ------------------ ------*/
currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F);
if ((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00) //If it is output pull-up, the GPIO speed will be configured
{
/* Check the parameters */
assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed));
/* Output mode */
currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;
}
/*------------------------------- GPIO CRL Configuration ------------------ -------*/
/* Configure the eight low port pins */
if (((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00)//If the eighth pin is configured, the pin will be configured if a bit of the value of GPIO_Pin is 1
{
tmpreg = GPIOx->CRL; //temporarily store the original value of the GPIO control register
for (pinpos = 0x00; pinpos < 0x08; pinpos++) //Scan 8 times to determine which pin needs to be configured. If //configuration is required, configure it
{
pos = ((uint32_t)0x01) << pinpos; //Get the value of 1 corresponding to a pin to be viewed
/* Get the port pins position */
currentpin = (GPIO_InitStruct->GPIO_Pin) & pos; //The value of currentpin is 0 or pos
if (currentpin == pos) //If it is pos, it means that this position needs to be configured
{
pos = pinpos << 2; //Multiply the value of pinpos by 4 to get the lowest bit number of a pin configuration bit: 0, 4, 8......28
/* Clear the corresponding low control register bits *///Used to mask the configuration bits of a certain pin and make these 4 bits 0
pinmask = ((uint32_t)0x0F) << pos;
tmpreg &= ~pinmask;
/* Write the mode configuration in the corresponding bits */
tmpreg |= (currentmode << pos); //Because the numbers corresponding to the mode are stored in the fourth bit, it is necessary to shift left to the lowest bit of the configuration bit corresponding to a pin, and then store it in tmpreg
/* Reset the corresponding ODR bit */
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD) //If it is input pull-down, you need to turn on the corresponding switch
{
GPIOx->BRR = (((uint32_t)0x01) << pinpos);
}
else
{
/* Set the corresponding ODR bit */
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU) //If it is input pull-down, you need to turn on the corresponding switch
{
GPIOx->BSRR = (((uint32_t)0x01) << pinpos);
}
}
}
}
GPIOx->CRL = tmpreg; // Assign values to the lower 8 pin configuration registers
}
/*------------------------------- GPIO CRH Configuration ------------------ -------*/
/* Configure the eight high port pins */
if (GPIO_InitStruct->GPIO_Pin > 0x00FF)
{
tmpreg = GPIOx->CRH;
for (pinpos = 0x00; pinpos < 0x08; pinpos++)
{
pos = (((uint32_t)0x01) << (pinpos + 0x08));
/* Get the port pins position */
currentpin = ((GPIO_InitStruct->GPIO_Pin) & pos);
if (currentpin == pos)
{
pos = pinpos << 2;
/* Clear the corresponding high control register bits */
pinmask = ((uint32_t)0x0F) << pos;
tmpreg &= ~pinmask;
/* Write the mode configuration in the corresponding bits */
tmpreg |= (currentmode << pos);
/* Reset the corresponding ODR bit */
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
{
GPIOx->BRR = (((uint32_t)0x01) << (pinpos + 0x08));
}
/* Set the corresponding ODR bit */
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
{
GPIOx->BSRR = (((uint32_t)0x01) << (pinpos + 0x08));
}
}
}
GPIOx->CRH = tmpreg;
}
}
4. Notes
The assert_param function is used to check the parameters. The parameters are either logical 0 or 1. IS_GPIO_ALL_PERIPH is also a macro, which is defined as:
#define IS_GPIO_ALL_PERIPH(PERIPH) (((PERIPH) == GPIOA) || \
((PERIPH) == GPIOB) || \
((PERIPH) == GPIOC) || \
((PERIPH) == GPIOD) || \
((PERIPH) == GPIOE) || \
((PERIPH) == GPIOF) || \
((PERIPH) == GPIOG))
The macros used in other parameter detection functions are similar. You can refer to the corresponding macro definitions for details. They are not listed here one by one.
The configuration principle of the lower 8 bits is the same as that of the upper 8 bits, so only the configuration of the lower 8 pins is explained here.
Previous article:I2C communication of STM32
Next article:Analysis and understanding of stm32f10x.h file
Recommended ReadingLatest update time:2024-11-17 03:45
- Popular Resources
- Popular amplifiers
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- Rambus Launches Industry's First HBM 4 Controller IP: What Are the Technical Details Behind It?
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- First release on the Internet! First-hand DDR5 simulation data (Part 1)
- MSP432P401R manually realizes the breathing light
- 【NXP Rapid IoT Review】 + WEB IDE usage experience and improvement suggestions
- Can you please help me analyze the principle of this circuit? Thank you.
- TI Solar Cell Charging Maximum Power Point Tracking Algorithm Reference Design
- [GD32L233C-START Review] 4. Serial port variable length data reception
- 【AD21】How to modify the shell display of PCB 3D packaging
- The weekly review information is here~~
- What is the difference between adding a conjugate inductor and a capacitor behind the rectifier bridge?
- MSP430 MCU Example 5-16 Pattern Light Control