2023-01-24 10:38 AM
,
void GPIO_Init(GPIO_Handle_t *pGPIOHandle)
{
uint32_t temp = 0;
//1.configure mode of gpio pin
if(pGPIOHandle->GPIO_PinConfig.GPIO_PinMode<=GPIO_MODE_ANALOG)
{
temp = (pGPIOHandle->GPIO_PinConfig.GPIO_PinMode<<(2 *pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber));
pGPIOHandle->pGPIOx->MODER &= ~(0x3<<pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber);//clear bit position before modification
pGPIOHandle->pGPIOx->MODER |= temp;
}
else
{
//later (interrruption)
}
temp = 0;
temp =( pGPIOHandle->GPIO_PinConfig.GPIO_PinSpeed<<(2*pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber));
pGPIOHandle->pGPIOx->OSPEEDR &= ~(0x3<<pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber);//clear bit position before modification
pGPIOHandle->pGPIOx->OSPEEDR |= temp;
temp = 0;
//3.configure pupd settings
temp =( pGPIOHandle->GPIO_PinConfig.GPIO_PinPuPdControl<<(2*pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber));
pGPIOHandle->pGPIOx->PUPDR &= ~(0x3<<pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber);//clear bit position before modification
pGPIOHandle->pGPIOx->PUPDR |= temp;
temp = 0;
//4.configure output type
temp =( pGPIOHandle->GPIO_PinConfig.GPIO_PinOPType<<(1*pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber));
pGPIOHandle->pGPIOx->OTYPER |= temp;
temp = 0;
//5.configure the alt functionality
if(pGPIOHandle->GPIO_PinConfig.GPIO_PinMode == GPIO_MODE_ALTFN)
{
uint32_t temp1, temp2;
temp1= pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber/8;
temp2= pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber%8;
pGPIOHandle->pGPIOx->AFR[temp1] &= ~(0xF<<(4*temp2));//clearing
pGPIOHandle->pGPIOx->AFR[temp1] |= (pGPIOHandle->GPIO_PinConfig.GPIO_PinAltFunMode<<(4*temp2));
}
}
/*
* stm32g0xx.h
*
*
* Author: admin
*/
#ifndef INC_STM32G0XX_H_
#define INC_STM32G0XX_H_
#include <stdint.h>
#if !defined(__SOFT_FP__) && defined(__ARM_FP)
#warning "FPU is not initialized, but the project is compiling for an FPU. Please initialize the FPU before use."
#endif
#define FLASH_BASEADDR 0x08000000U
#define SRAM1_BASEADDR 0x20000000U
#define SRAM SRAM1_BASEADDR
#define ROM_BASEADDR 0x1FFF0000U
#define PERIPH_BASE 0x40000000U
#define APBPERIPHBASE PERIPH_BASE
#define AHBPERIPHBASE 0x40020000U
#define IOPERIPHBASE 0x50000000U
#define GPIOA_BASEADDR 0x50000000U
#define GPIOB_BASEADDR 0x50000400U
#define GPIOC_BASEADDR 0x50000800U
#define GPIOD_BASEADDR 0x50000C00U
#define GPIOE_BASEADDR 0x50001000U
#define GPIOF_BASEADDR 0x50001400U
#define SYSCFG_BASEADDR 0x40010000U
#define RCC_BASEADDR 0x40021000U
typedef struct //registre gPIO, accessible grace à un pointeur par la suite
{
volatile uint32_t MODER; //Adress offset: 0x00
volatile uint32_t OTYPER;//Adress offset: 0x04
volatile uint32_t OSPEEDR;
volatile uint32_t PUPDR;
volatile uint32_t IDR;
volatile uint32_t ODR;
volatile uint32_t BSRR;
volatile uint32_t LCKR;
volatile uint32_t AFR[2];//High et Low registers
volatile uint32_t BRR;
}GPIO_RegDef_t;
typedef struct
{
volatile uint32_t RCC_CR;
volatile uint32_t RCC_ICSCR;
volatile uint32_t RCC_CFGR;
volatile uint32_t RCC_PLL_CFGR;
volatile uint32_t Reserved0;//0x10
volatile uint32_t RCC_CRRCR;
volatile uint32_t RCC_CIER;
volatile uint32_t RCC_CIFR;
volatile uint32_t RCC_CICR;
volatile uint32_t RCC_IOPRSTR;
volatile uint32_t AHBRSTR;
volatile uint32_t RCC_APBRSTR1;
volatile uint32_t RCC_APBRSTR2;
volatile uint32_t RCC_IOPENR;
volatile uint32_t RCC_AHBENR;
volatile uint32_t RCC_APBENR1;
volatile uint32_t RCC_APBENR2;
volatile uint32_t RCC_IOPSMENR;
volatile uint32_t RCC_AHBSMENR;
volatile uint32_t RCC_APBSMENR1;
volatile uint32_t RCC_APBSMENR2;
volatile uint32_t RCC_CCIPR;
volatile uint32_t RCC_CCIPR2;
volatile uint32_t RCC_BDCR;
volatile uint32_t RCC_CSR;
}RCC_RegDef_t;
#define GPIOA ((GPIO_RegDef_t*)GPIOA_BASEADDR)
#define GPIOB ((GPIO_RegDef_t*)GPIOB_BASEADDR)
#define GPIOC ((GPIO_RegDef_t*)GPIOC_BASEADDR)
#define GPIOD ((GPIO_RegDef_t*)GPIOD_BASEADDR)
#define GPIOE ((GPIO_RegDef_t*)GPIOE_BASEADDR)
#define GPIOF ((GPIO_RegDef_t*)GPIOF_BASEADDR)
#define RCC ((RCC_RegDef_t*)RCC_BASEADDR)
/*Clock enable Macros for Gpiox peripherals*/
#define GPIOA_PERI_CLOCK_EN() RCC->RCC_IOPENR |=(1<<0);
#define GPIOB_PERI_CLOCK_EN() RCC->RCC_IOPENR |=(1<<1);
#define GPIOC_PERI_CLOCK_EN() RCC->RCC_IOPENR |=(1<<2);
#define GPIOD_PERI_CLOCK_EN() RCC->RCC_IOPENR |=(1<<3);
#define GPIOE_PERI_CLOCK_EN() RCC->RCC_IOPENR |=(1<<4);
#define GPIOF_PERI_CLOCK_EN() RCC->RCC_IOPENR |=(1<<5);
//disable Macros for peripherals
#define GPIOA_PERI_CLOCK_DI()RCC->RCC_IOPENR &= ~(1<<0);
#define GPIOB_PERI_CLOCK_DI() RCC->RCC_IOPENR &= ~(1<<1);
#define GPIOC_PERI_CLOCK_DI() RCC->RCC_IOPENR &= ~(1<<2);
#define GPIOD_PERI_CLOCK_DI() RCC->RCC_IOPENR &= ~(1<<3);
#define GPIOE_PERI_CLOCK_DI() RCC->RCC_IOPENR &= ~(1<<4);
#define GPIOF_PERI_CLOCK_DI() RCC->RCC_IOPENR &= ~(1<<5);
/*Clock disable Macros for sysconf peripheral*/
#define SYSCF_PCLCK_DI() (RCC->APB2ENR &= ~(1<<0));
// to reset GPIOx peripherals
#define GPIOA_REG_RESET() do{(RCC ->AHBRSTR |=( 1<<0)); (RCC ->AHBRSTR &= ~(1<<0));}while(0)
#define GPIOB_REG_RESET() do{(RCC ->AHBRSTR |=( 1<<1)); (RCC ->AHBRSTR &= ~(1<<1));}while(0)
#define GPIOC_REG_RESET() do{(RCC ->AHBRSTR |=( 1<<2)); (RCC ->AHBRSTR &= ~(1<<2));}while(0)
#define GPIOD_REG_RESET() do{(RCC ->AHBRSTR |=( 1<<3)); (RCC ->AHBRSTR &= ~(1<<3));}while(0)
#define GPIOE_REG_RESET() do{(RCC ->AHBRSTR |=( 1<<4)); (RCC ->AHBRSTR &= ~(1<<4));}while(0)
#define GPIOF_REG_RESET() do{(RCC ->AHBRSTR |=( 1<<5)); (RCC ->AHBRSTR &= ~(1<<5));}while(0)
//some generic macros
#define ENABLE 1
#define DISABLE 0
#define SET ENABLE
#define RESET DISABLE
#define GPIO_PIN_SET SET
#define GPIO_PIN_RESET RESET
#endif /* INC_STM32G0XX_H_ */
/*
* stm32g0xx_gpio_driver.h
*
* Author: admin
*/
#ifndef INC_STM32G0XX_GPIO_DRIVER_H_
#define INC_STM32G0XX_GPIO_DRIVER_H_
#include "stm32g0xx.h"
typedef struct
{
uint8_t GPIO_PinNumber;
uint8_t GPIO_PinMode;//@GPIO_PIN_MODE
uint8_t GPIO_PinSpeed;//@GPIO_PIN_SPEED
uint8_t GPIO_PinPuPdControl;//@GPIO_PIN_PUPD
uint8_t GPIO_PinOPType;//@GPIO_PIN_OTYPE
uint8_t GPIO_PinAltFunMode;
} GPIO_PinConfig_t;
typedef struct
{
//pointer to hold the base address of the GPIO peripheral
GPIO_RegDef_t *pGPIOx; //hold the base address of the GPIO port to which the pin belongs
GPIO_PinConfig_t GPIO_PinConfig;//holds GPIO pin configuration settings
}GPIO_Handle_t;
//@GPIO_PIN_NUMBER
#define GPIO_PIN_NO_0 0
#define GPIO_PIN_NO_1 1
#define GPIO_PIN_NO_2 2
#define GPIO_PIN_NO_3 3
#define GPIO_PIN_NO_4 4
#define GPIO_PIN_NO_5 5
#define GPIO_PIN_NO_6 6
#define GPIO_PIN_NO_7 7
#define GPIO_PIN_NO_8 8
#define GPIO_PIN_NO_9 9
#define GPIO_PIN_NO_10 10
#define GPIO_PIN_NO_11 11
#define GPIO_PIN_NO_12 12
#define GPIO_PIN_NO_13 13
#define GPIO_PIN_NO_14 14
#define GPIO_PIN_NO_15 15
//@GPIO_PIN_MODES
//GPio possible modes, les 4 premier sont dans documentation (MODER)
#define GPIO_MODE_IN 0 //( sur moder)
#define GPIO_MODE_OUT 1 //( sur moder)
#define GPIO_MODE_ALTFN 2
#define GPIO_MODE_ANALOG 3
//modes en plus
#define GPIO_MODE_IT_FT 4 // Input falling edge pour une interruption
#define GPIO_MODE_IT_RT 5 //rising edge
#define GPIO_MODE_IT_RFT 6 //rising edge falling edge trigger
//possible output types(OTYPEMODER)
//@GPIO_PIN_OTYPE
#define GPIO_OP_TYPE_PP 0//push pull
#define GPIO_OP_TYPE_OD 1//open drain
//possible output speeds(OSPEEDR)
////@GPIO_PIN_SPEED
#define GPIO_SPEED_LOW 0
#define GPIO_SPEED_MEDIUM 1
#define GPIO_SPEED_FAST 2
#define GPIO_SPEED_HIGH 3
//GPIO pin pull up AAND pull down configuration macros
//@GPIO_PIN_PUPD
#define GPIO_NO_PUPD 0
#define GPIO_PU 1
#define GPIO_PD 2
/*
* main.c
*
*/
#include "stm32g0xx.h"
#include "stm32g0xx_gpio_driver.h"
void delay(void)
{
for(uint32_t i = 0; i<500000;i++);
}
int main(void)
{
GPIO_Handle_t GpioLed;
GpioLed.pGPIOx = GPIOA;
GpioLed.GPIO_PinConfig.GPIO_PinNumber = GPIO_PIN_NO_5;
GpioLed.GPIO_PinConfig.GPIO_PinSpeed =GPIO_SPEED_FAST;
GpioLed.GPIO_PinConfig.GPIO_PinOPType = GPIO_OP_TYPE_PP;
GpioLed.GPIO_PinConfig.GPIO_PinPuPdControl = GPIO_NO_PUPD;
GPIO_PeriClockControl(GPIOA,ENABLE);
GPIO_Init(&GpioLed);
while(1)
{
GPIO_ToggleOutputPin(GPIOA,GPIO_PIN_NO_5);
delay();
}
return 0;
}
image00 : When I try to clear GPIOA MODER register bits, only these one are setted with 0.image01:the bits corresponding to pin number 5 are not setted with the correct values. (It should be 01)
2023-01-24 11:11 AM
If you'd like to use a pin name / number, maybe have a look at this
As in Matlab/Simulink, each pin is an enumeration from PA_0 to PF_15 (for example).
4 lst bits are the bit position, the rest is the GPIO base retrieved from a simple const LUT.
Using one pin at a time simplify passing parameters and debug watch window readability.
The pin configuration is a bit field. Each pin config fits in 1 or 2 core registers, so configuring pin by pin is still decently code efficient.
Maybe this will provide some new concept and ideas. It works well and ASM generated code looks good. It's my third itteration on this topic.
2023-01-24 11:48 AM
Something I don't understand is: why do you write your own peripheral/register definitions if these definitions are ready, prepared and tested by ST - just get the stm32g0xx.h file.
And this looks ridiculous:
#define GPIO_PIN_NO_11 11
How about:
#define ONE 1
#define NUMBER_100 100
;)
Your delay() function may or may not delay anything.
The purpose of a high level language is to write short and easy to read program. GPIO_PIN_NO_11 is not a bit better than plain 11.
For pin config I sometimes use this:
union bf2_ {
struct {
uint32_t p0:2, p1:2, p2:2, p3:2, p4:2, p5:2, p6:2, p7:2,
p8:2, p9:2, p10:2, p11:2, p12:2, p13:2, p14:2, p15:2;
};
uint32_t w;
};
Then for single pin config I write:
(*(union bf2_ *)&GPIOA->MODER).p5 = GPIO_MODER_AF;
And for all pins at once:
GPIOA->MODER = (union bf2_) {
.p1 = GPIO_MODER_AF,
.p2 = GPIO_MODER_AN,
.p3 = GPIO_MODER_IN,
.p4 = GPIO_MODER_OUT,
...
}.w;
So that's how I would write your program:
#include "stm32g0xx.h"
int main(void)
{
RCC->IOPENR = RCC_IOPENR_GPIOAEN;
(*(union bf2_ *)&GPIOA->MODER).p5 = GPIO_MODER_OUT;
SysTick_Config(<put period here>);
for (;;)
__WFI();
}
// toggle the pin is SysTick_Handler...
Of course, the definitions of union bf2_ and GPIO_MODER_OUT need to be added.
2023-01-24 11:59 AM
Thank you for your answer :) But to be honnest with you, I am a total beginner in C as well as in Programming microcontrollers . My purpose is only to adapt the code of a tutorial I have watched in order to make it work on my board. When I will be more confident, I think I'll transform the code in order to make it more optimised (but your commentary on the pins made me laugh:smiling_face_with_smiling_eyes: )
2023-01-24 12:05 PM
I wrote all the registers definitions to have a better understanding of the functionement
2023-01-24 12:12 PM
Thank you for your answer. Yes it gives me more ideas. I think I should test them when I am more experienced with C. Currently I am following a tutorial. What is ASM generated code ? Is it the code generated by Stm32CubeIde (the one I use).You gave me an idea. I will try to compare this code with mine. Maybe I will get some hint.
2023-01-25 04:01 AM
I would like give som update before closing the subject. I have made few mistakes in my code. First of all in
void GPIO_Init
pGPIOHandle->pGPIOx->MODER &= ~(0x3<<pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber);
was not right. I had to write :
pGPIOHandle->pGPIOx->MODER &= ~(0x3<<(pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber*2));
and in my main()
I had forgotten
GpioLed.GPIO_PinConfig.GPIO_PinMode =GPIO_MODE_OUT;