2023-01-29 09:20 AM
I wrote a simple GPIO driver for Nucleo-l432kc board I used one GPIO.c file and multiple headers for RCC GPIO ..etc
I added the main method in the same file GPIO.c and it worked fine
now I moved the main function to another file main.c (to isolate the example and the driver code) but now I got multiple definitions linker error when trying to link main.o and GPIO.o so how I can compile multiple source files and avoid this linker error ?
GPIO.c:
#include <GPIO.h>
uint8_t gpio_read_pin(GPIO_TypeDef *GPIOx, uint8_t pin){
return ((GPIOx->IDR & (1 << pin)) ? 1 : 0);
}
void gpio_write_pin(GPIO_TypeDef *GPIOx, uint8_t pin, uint8_t value){
if(value) GPIOx->ODR |= (1 << pin) ;
else GPIOx->ODR &= ~(1 << pin);
}
void gpio_set_alt_func(GPIO_TypeDef *GPIOx, uint8_t pin, uint8_t alt_fun){
uint8_t baseBit = (pin * 4) % 32;
uint8_t reg = pin < 8 ? 0 : 1;
GPIOx->AFR[reg] &= ~(0b1111 << baseBit);
GPIOx->AFR[reg] |= (alt_fun << baseBit);
}
static void gpio_configure_pin_mode(GPIO_TypeDef *GPIOx, uint8_t pin, uint32_t mode){
GPIOx->MODER &= ~(3 << (pin * 2));
GPIOx->MODER |= (mode << (pin * 2));
}
static void gpio_configure_pin_otype(GPIO_TypeDef *GPIOx, uint8_t pin, uint32_t op_type){
GPIOx->OTYPER &= ~(1 << pin);
GPIOx->OTYPER |= (op_type << pin);
}
static void gpio_configure_pin_ospeed(GPIO_TypeDef *GPIOx, uint8_t pin, uint32_t ospeed){
GPIOx->OSPEEDR &= ~(3 << (pin * 2));
GPIOx->OSPEEDR |= (ospeed << (pin * 2));
}
static void gpio_configure_pin_pupd(GPIO_TypeDef *GPIOx, uint8_t pin, uint32_t pupd){
GPIOx->PUPDR &= ~(3 << (pin * 2));
GPIOx->PUPDR |= (pupd << (pin * 2));
}
void gpio_init(GPIO_TypeDef* GPIOx, gpio_pin_conf_t* pin_conf){
//first configure the mode
gpio_configure_pin_mode(GPIOx, pin_conf->pin, pin_conf->mode);
//configure the output type
gpio_configure_pin_otype(GPIOx, pin_conf->pin, pin_conf->op_type);
//configure the ospeed
gpio_configure_pin_ospeed(GPIOx, pin_conf->pin, pin_conf->speed);
//configure the alternate function
if(pin_conf->alternate_function != -1)
gpio_set_alt_func(GPIOx, pin_conf->pin, pin_conf->alternate_function);
}
main.c:
#include <GPIO.h>
#include <RCC.h>
int main(){
gpio_pin_conf_t led;
led.pin = A1;
led.mode = GPIO_PIN_OUTPUT_MODE;
led.op_type = GPIO_PIN_OP_TYPE_PUSH_PULL;
led.speed = GPIO_PIN_OSPEED_LOW;
led.alternate_function = -1;
RCC_GPIOA_CLK_ENABLE();
gpio_init(GPIOA, &led);
uint32_t state = GPIO_OUTPUT_LOW;
while(1){
for(int i = 0; i < 100000; i++);
gpio_write_pin(GPIOA, led.pin, state);
state = !state;
}
return 0;
}
Makfile:
projectName = GPIO
TOOLCHAIN = /home/mahmoud/arm-gnu-toolchain-12.2.rel1-x86_64-arm-none-eabi/bin
all: compile link upload
compile: src/$(projectName).c
$(TOOLCHAIN)/arm-none-eabi-gcc -g -c -mcpu=cortex-m4 -mthumb src/main.c -o Build/main.o -I ../include/
$(TOOLCHAIN)/arm-none-eabi-gcc -g -c -mcpu=cortex-m4 -mthumb src/$(projectName).c -o Build/$(projectName).o -I ../include/
assemble:
$(TOOLCHAIN)/arm-none-eabi-as -g -mcpu=cortex-m4 -mthumb ../startup/startup_stm32l432xx.s -o Build/startup_stm32l432xx.o
link: compile assemble
$(TOOLCHAIN)/arm-none-eabi-ld Build/*.o -o Build/$(projectName).elf -T ../linker/STM32L432KCUx_FLASH.ld
upload: link
openocd -f interface/stlink.cfg -f target/stm32l4x.cfg -c "program Build/$(projectName).elf verify reset exit"
errors:
/home/mahmoud/arm-gnu-toolchain-12.2.rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-ld: Build/main.o:/home/mahmoud/code/Nucleo-L432kc/GPIO/../include/stm32l432kc.h:280: multiple definition of `RCC'; Build/GPIO.o:/home/mahmoud/code/Nucleo-L432kc/GPIO/../include/stm32l432kc.h:280: first defined here
Solved! Go to Solution.
2023-01-29 09:35 AM
Include stm32l4xx.h instead of stm32l432kc., which, from the above, looks like it is missing multiple inclusion protection.
Your gpio_pin_write functin is dangerous - use BSRR, not ODR.
2023-01-29 09:35 AM
Include stm32l4xx.h instead of stm32l432kc., which, from the above, looks like it is missing multiple inclusion protection.
Your gpio_pin_write functin is dangerous - use BSRR, not ODR.
2023-01-29 09:42 AM
may I ask why using ODR is dangerous
2023-01-29 10:12 AM
It can't be safely used from the main loop and interrupt service routines simultaneously. BSRR and BRR registers allow for atomic, safe changes of port outputs without a need for read-modify-write operations.