cancel
Showing results for 
Search instead for 
Did you mean: 

How can I divide the driver file into two source files without having multiple definitions error?

Susano
Associate II

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

1 ACCEPTED SOLUTION

Accepted Solutions
gbm
Lead II

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.

View solution in original post

3 REPLIES 3
gbm
Lead II

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.

Susano
Associate II

may I ask why using ODR is dangerous

gbm
Lead II

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.