Error trying to init different GPIOS - STM32 - Page 1
Forum section: electronics / general

author: ppTRN
author_rank: Regular Contributor
timestamp: December 11, 2024, 10:39:38 am
content: Hi everyone,I am writing some function to handle GPIOS for an STM32F303 using Keil. The functions implemented allow to initialize a GPIO (enabling its clock), setting a pin direction and an output value.Let me show you the code:Code:int main(void){portInit(PORTB);pinMode(GPIOB, 3, OUTPUT_PUSHPULL, OUTPUT_SLOW);digitalWrite(GPIOB, 3, HIGH);portInit(PORTA);pinMode(GPIOA, 0, INPUT_FLOATING, OUTPUT_SLOW);while(TRUE){;}}Everything fine and working up until I try to mess with the field of another GPIO (the GPIOA in this case, mind that it allows me to enable its clock widouth any problem).When I try to set the direction by writing on GPIOA->MODER everithing crashes.Now, I do not think that all this is about the pinMode function, because it works fine the first time and it is not like it's doing much. I think this is a problem regarding the access to the correct GPIO struct. This is just a speculation, I have no idea how to verify this or how to fix it. Here's the functions that I implemented:Code:void portInit(uint8_t _port){switch (_port){case PORTA:RCC->AHBENR |= 1<<17;break;case PORTB:RCC->AHBENR |= 1<<18;break;case PORTC:RCC->AHBENR |= 1<<19;break;case PORTD:RCC->AHBENR |= 1<<20;break;case PORTE:RCC->AHBENR |= 1<<21;break;case PORTF:RCC->AHBENR |= 1<<22;break;case PORTG:RCC->AHBENR |= 1<<23;break;case PORTH:RCC->AHBENR |= 1<<16;break;default:/* GENERATE ERROR */break;}}void pinMode(GPIO_TypeDef *_gpio, uint32_t _pin, uint32_t _mode, uint32_t _speed){switch (_mode){case INPUT_FLOATING:_gpio->MODER &= !((uint32_t)1<<PINPOS_DOUBLE_LOW);_gpio->MODER &= !((uint32_t)1<<PINPOS_DOUBLE_HIGH);_gpio->PUPDR &= !((uint32_t)1<<PINPOS_DOUBLE_LOW);_gpio->PUPDR &= !((uint32_t)1<<PINPOS_DOUBLE_HIGH);break;case INPUT_ANALOG:_gpio->MODER |= 1<<PINPOS_DOUBLE_HIGH | 1<<PINPOS_DOUBLE_LOW;_gpio->PUPDR &= !((uint32_t)1<<PINPOS_DOUBLE_LOW);_gpio->PUPDR &= !((uint32_t)1<<PINPOS_DOUBLE_HIGH);break;case INPUT_PULLUP:_gpio->MODER &= !(1<<PINPOS_DOUBLE_HIGH | 1<<PINPOS_DOUBLE_LOW);_gpio->PUPDR |= 1<<PINPOS_DOUBLE_LOW;_gpio->PUPDR &= !((uint32_t)1<<PINPOS_DOUBLE_HIGH);break;case INPUT_PULLDOWN:_gpio->MODER &= !((uint32_t)1<<PINPOS_DOUBLE_LOW);_gpio->MODER &= !((uint32_t)1<<PINPOS_DOUBLE_HIGH);_gpio->PUPDR &= !((uint32_t)1<<PINPOS_DOUBLE_LOW);_gpio->PUPDR |= 1<<PINPOS_DOUBLE_HIGH;break;case OUTPUT_PUSHPULL:_gpio->MODER &= !((uint32_t)1<<PINPOS_DOUBLE_HIGH);_gpio->MODER |= 1<<PINPOS_DOUBLE_LOW;_gpio->PUPDR &= !((uint32_t)1<<PINPOS_DOUBLE_LOW);_gpio->PUPDR &= !((uint32_t)1<<PINPOS_DOUBLE_HIGH);_gpio->OTYPER &= !((uint32_t)1<<PINPOS_SINGLE);break;case OUTPUT_OPENDRAIN:_gpio->MODER &= !((uint32_t)1<<PINPOS_DOUBLE_HIGH);_gpio->MODER |= 1<<PINPOS_DOUBLE_LOW;_gpio->PUPDR &= !((uint32_t)1<<PINPOS_DOUBLE_LOW);_gpio->PUPDR &= !((uint32_t)1<<PINPOS_DOUBLE_HIGH);_gpio->OTYPER |= 1<<PINPOS_SINGLE;break;default:/*GENERATE ERROR*/break;}if(_mode == OUTPUT_PUSHPULL || _mode == OUTPUT_OPENDRAIN){switch (_speed){case OUTPUT_SLOW:_gpio->OSPEEDR &= !(1<<PINPOS_DOUBLE_LOW);break;case OUTPUT_MID:_gpio->OSPEEDR &= !(1<<PINPOS_DOUBLE_HIGH);_gpio->OSPEEDR |= 1<<PINPOS_DOUBLE_LOW;break;case OUTPUT_FAST:_gpio->OSPEEDR |= 1<<PINPOS_DOUBLE_LOW;_gpio->OSPEEDR |= 1<<PINPOS_DOUBLE_HIGH;break;}}else{/*GENERATE ERROR*/}}void setSpeed(GPIO_TypeDef *_gpio, uint32_t _pin, uint32_t _speed){switch (_speed){case OUTPUT_SLOW:_gpio->OSPEEDR &= !(1<<PINPOS_DOUBLE_LOW);break;case OUTPUT_MID:_gpio->OSPEEDR &= !(1<<PINPOS_DOUBLE_HIGH);_gpio->OSPEEDR |= 1<<PINPOS_DOUBLE_LOW;break;case OUTPUT_FAST:_gpio->OSPEEDR |= 1<<PINPOS_DOUBLE_LOW;_gpio->OSPEEDR |= 1<<PINPOS_DOUBLE_HIGH;break;}}void digitalWrite(GPIO_TypeDef *_gpio, uint32_t _pin, uint32_t _val){/*TODO: add check for pin in output mode (also check if needed in the first place)*/if(_val == HIGH)_gpio->BSRR = 1<<PINPOS_SET;else if(_val == LOW) _gpio->BSRR = 1<<PINPOS_RESET;else{/* GENERATE ERROR */}}uint8_t digitalRead(GPIO_TypeDef *_gpio, uint32_t _pin){return (_gpio->IDR & PINPOS_SINGLE);}All the defines are correctly decalred and no errors or warnings are present. PINPOS arrays just allows an easyer acces to the register fields.I am just now noticing that there are some problems even when I act on the same GPIO. When i set the first bit (PB3) everithing works, but when I try to set another pin, the pinMode CLEARS the MODER register regarding of what the actual code is telling it to do.Still think that the pinMode implementation is correct tho.Any ideas? Thanks!

author: ppTRN
author_rank: Regular Contributor
timestamp: December 11, 2024, 11:32:10 am
content: Oopsie, it was all about using "!" instead of "~" when clearing a bit in my functions!

author: ocelot
author_rank: Contributor
timestamp: December 22, 2024, 08:43:19 am
content: oops !This sort of problem is why it is easier to use the Hardware Abstraction Layer code (HAL) to operate GPIOS.It does not matter much for a single project but for instance if you decide to switch family of STM32 microcontrollers, the different GPIO register layouts can be a problem. - switch from a 32F1xx to a 32L1xx for instance .