"multiple definition of first defined here". STM32, AC6 Studio

Viewed 4794

Im facing a stupid problem, although everything have to be working fine. My Task is - to initialise I/O registers using datatypes of unions and structures. I have used solely my names for the initialisation, so that i could avoid errors caused by redefinition of system variables. However the compiler still shows me an errors for all my created variables, as they have been initialised elsewhere in project. There is my code for the initialisation of variables:

volatile SYSCFG_t* mysyscfg=(volatile SYSCFG_t*)MYSYSCFG;

volatile RCC_AHB2ENR_t* myrcc_ahb2enr=(volatile RCC_AHB2ENR_t*)(MYRCC|MYAHB2ENR_OFFS);

volatile RCC_APB2ENR_t* myrcc_apb2enr=(volatile RCC_APB2ENR_t*)(MYRCC|MYAPB2ENR_OFFS);

volatile GPIO_t* mygpiob=(volatile GPIO_t*)MYGPIOB;

volatile GPIO_t* mygpioe=(volatile GPIO_t*)MYGPIOE;

volatile GPIO_t* mygpioa=(volatile GPIO_t*)MYGPIOA;

The errrors that i become are the follwing:

src/main.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:262: multiple definition of `mysyscfg'
src/init.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:262: first defined here
src/main.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:263: multiple definition of `myrcc_ahb2enr'
src/init.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:263: first defined here
src/main.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:264: multiple definition of `myrcc_apb2enr'
src/init.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:264: first defined here
src/main.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:265: multiple definition of `mygpiob'
src/init.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:265: first defined here
src/main.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:266: multiple definition of `mygpioe'
src/init.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:266: first defined here
src/main.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:267: multiple definition of `mygpioa'
src/init.o:/home/bogdan/workspace/timers/Debug/../src/lib.h:267: first defined here
collect2: error: ld returned 1 exit status
make: *** [makefile:62: timers.elf] Error 1
3 Answers

Those are linker errors. You are probably doing something like this:

main.c:

#include "lib.h"

init.c:

#include "lib.h"

When the linker inspects the symbols and types in main.c and init.c, it finds that exact same symbols have been defined in each of them, therefore the error. Normally a header files only declare symbols, not define them, but there are some creative uses of conditional code that can get around this:

lib.h (please think of a more descriptive name for this file)

#if defined IN_INIT_C
  volatile SYSCFG_t* mysyscfg=(volatile SYSCFG_t*)MYSYSCFG; // Definition
#else
  extern volatile SYSCFG_T* mysyscfg; // Declaration
#endif

Now in init.c and only in that file:

#define IN_INIT_C
#include "lib.h"

Or you can simply place the definition in init.c and simplify your header by only placing declarations therein.

You should also read the Q&A's provided by this search:

https://stackoverflow.com/search?q=%5Bc%5Ddifference+between+declaration+and+definition

It's a bad idea to define variables in an include-file. The reason is that you won't be able to include that include-file in more than one c-file. If you do, you'll get the errors that you have now.

So the code you have posted shal be moved to a c-file and in the include-file you just put:

extern volatile SYSCFG_t* mysyscfg;

extern volatile RCC_AHB2ENR_t* myrcc_ahb2enr;

extern volatile RCC_APB2ENR_t* myrcc_apb2enr;

extern volatile GPIO_t* mygpiob;

extern volatile GPIO_t* mygpioe;

extern volatile GPIO_t* mygpioa;

Then the include-file can be included in multiple c-files without problems.

As other people already stated do not define object or functions (except static inline ones) in the header files.

You also try to reinvent the wheel - all the register definitions are already in the STM provide CMSIS files.

Your approach is also inefficient. It will generate unnecessary code when you access your variables.

#include <stdint.h>

#define __IO volatile

typedef struct
{
  __IO uint32_t MODER;    /*!< GPIO port mode register,               Address offset: 0x00      */
  __IO uint32_t OTYPER;   /*!< GPIO port output type register,        Address offset: 0x04      */
  __IO uint32_t OSPEEDR;  /*!< GPIO port output speed register,       Address offset: 0x08      */
  __IO uint32_t PUPDR;    /*!< GPIO port pull-up/pull-down register,  Address offset: 0x0C      */
  __IO uint32_t IDR;      /*!< GPIO port input data register,         Address offset: 0x10      */
  __IO uint32_t ODR;      /*!< GPIO port output data register,        Address offset: 0x14      */
  __IO uint32_t BSRR;     /*!< GPIO port bit set/reset register,      Address offset: 0x18      */
  __IO uint32_t LCKR;     /*!< GPIO port configuration lock register, Address offset: 0x1C      */
  __IO uint32_t AFR[2];   /*!< GPIO alternate function registers,     Address offset: 0x20-0x24 */
} GPIO_TypeDef;

volatile GPIO_TypeDef *MYGPIOA = (volatile GPIO_TypeDef *)0x40000000;

#define GPIOA ((GPIO_TypeDef *)0x40000000)

void foo(uint32_t val)
{
    MYGPIOA -> MODER = val;
}

void bar(uint32_t val)
{
    GPIOA -> MODER = val;
}

as you see the #define way generates less instructions. That is the reason why in the CMSIS headers it is done this way. You also unnecessary waste memory for the pointers.

foo:
        ldr     r3, .L3
        ldr     r3, [r3]
        str     r0, [r3]
        bx      lr
.L3:
        .word   .LANCHOR0
bar:
        mov     r3, #1073741824
        str     r0, [r3]
        bx      lr
MYGPIOA:
        .word   1073741824

https://godbolt.org/z/8K19js

Related