Skip to main content
Susano
Associate II
January 29, 2023
Solved

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

  • January 29, 2023
  • 3 replies
  • 1547 views

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

This topic has been closed for replies.
Best answer by gbm

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.

3 replies

gbm
gbmBest answer
Super User
January 29, 2023

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.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
Susano
SusanoAuthor
Associate II
January 29, 2023

may I ask why using ODR is dangerous

gbm
Super User
January 29, 2023

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.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice