cancel
Showing results for 
Search instead for 
Did you mean: 

Why toggling LED4 USER doesn't work with this code ( Board nucleo G071RB) ? I know that problem is in my init function. But I don't know how to correct it because GPIOA base adress (which is also MODER register address) is right

JMalia.2
Associate II
,
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.0693W00000Y93XqQAJ.pngimage01:the bits corresponding to pin number 5 are not setted with the correct values. (It should be 01)

0693W00000Y93Y5QAJ.png

6 REPLIES 6
S.Ma
Principal

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.

gbm
Lead II

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.

JMalia.2
Associate II

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😊 )

JMalia.2
Associate II

I wrote all the registers definitions to have a better understanding of the functionement

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.

JMalia.2
Associate II

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;