STM32 GNU ARM Linker: undefined reference to function() with eclipse

10,865

Solution 1

Doing #include stm32f1xx_hal_tim.h is not enough - it only causes your compiler not to complain, linker will still have a problem. Neither is adding a search path for the linker - this one you use mainly when you have static pre-compiled libraries that you explicitly link with the -l option. HAL is not a static library but rather a library you compile yourself.

To solve your problem, make sure you compile the corresponding source files - in this case stm32f1xx_hal_tim.c file and that it's later being linked. You mention that you use Eclipse and by default it generates a Makefile that causes all source files that you compiled in your project to also be linked. Therefore you mainly should check whether stm32f1xx_hal_tim.c is being compiled. One way to do that is to find the file in the Project Explorer, rightclick on it and select Resource Configurations -> Exclude from Build.... Make sure it's NOT checked. If it is, it is likely a whole directory is excluded from build which it should not be.

Another possibility is given function not being defined in any source file that is compiled or the function signature (name, return type and parameter types) don't match.

Yet another possibility (which in this case turned out to be the source of the issue) is that a portion of the file may not be compiled due to a #if/#ifdef preprocessor directive. In the OP's case this was caused by HAL_TIM_MODULE_ENABLED being undefined.

Solution 2

It is not relative to linker issue, but pre-processor.

As I mentioned, that I am building this code based on a project, which was generated from cubeMX. In the previous project, there is no timer used or configured. Than I started to write timer configuration. What I forgot is that to uncomment the #define HAL_TIM_MODULE_ENABLED in stm32f1xx_hal_conf.h. Which blocked all the implementation in stm32f1xx_hal_tim.c by pre-processor.

That is why eclipse shows all the function in stm32f1xx_hal_tim.c as gray color and not be able to be referenced.

And anyway, thanks Jacek Ślimok's effort!

Share:
10,865
MinShu Huang
Author by

MinShu Huang

Updated on June 05, 2022

Comments

  • MinShu Huang
    MinShu Huang almost 2 years

    I am currently learning STM32F103 with Eclipse. I am facing a problem in linker stage, that I got linker error : undefined reference to `HAL_TIM_Base_Init'

    Building target: TimerTest.elf
    Invoking: GNU ARM Cross C++ Linker
    arm-none-eabi-g++ -mcpu=cortex-m3 -mthumb -Og -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -ffreestanding -fno-move-loop-invariants -Wall -Wextra  -g3 -T "C:\Users\Gebruiker\Dropbox\CodeBase\Eclipse\TimerTest\SW4STM32\WS2812_TimerTest\STM32F103C8Tx_FLASH.ld" -Xlinker --gc-sections -L"C:\Users\Gebruiker\Dropbox\CodeBase\Eclipse\TimerTest\Src" -L"C:\Users\Gebruiker\Dropbox\CodeBase\Eclipse\TimerTest\Drivers\STM32F1xx_HAL_Driver\Src" -L"C:\Users\Gebruiker\Dropbox\CodeBase\Eclipse\TimerTest\Drivers\STM32F1xx_HAL_Driver\Inc" -L"C:\Users\Gebruiker\Dropbox\CodeBase\Eclipse\TimerTest\Inc" -Wl,-Map,"TimerTest.map" -Xlinker --cref --specs=nano.specs -o "TimerTest.elf"  ./Src/WS2812.o ./Src/main.o ./Src/stm32f1xx_hal_msp.o ./Src/stm32f1xx_hal_tim.o ./Src/stm32f1xx_it.o ./Src/system_stm32f1xx.o ./Src/usb_device.o ./Src/usbd_cdc_if.o ./Src/usbd_conf.o ./Src/usbd_desc.o  ./SW4STM32/startup_stm32f103xb.o  ./Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.o ./Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.o ./Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.o  ./Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.o  ./Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.o ./Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_cortex.o ./Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_dma.o ./Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_flash.o ./Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_flash_ex.o ./Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_gpio.o ./Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_gpio_ex.o ./Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_i2c.o ./Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_pcd.o ./Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_pcd_ex.o ./Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_pwr.o ./Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc.o ./Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc_ex.o ./Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_spi.o ./Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_spi_ex.o ./Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim.o ./Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim_ex.o ./Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_ll_usb.o   
    ./Src/WS2812.o: In function `WS2812Init':
    C:\Users\Gebruiker\Dropbox\CodeBase\Eclipse\TimerTest\Debug/../Src/WS2812.c:30: undefined reference to `HAL_TIM_Base_Init'
    collect2.exe: error: ld returned 1 exit status
    make: *** [makefile:64: TimerTest.elf] Error 1
    

    Here is my code:

    main.c

    #include "main.h"
    
    #include "WS2812.h"
    
    #include "stm32f1xx_hal.h"
    #include "usb_device.h"
    
    int main(void)
    {
    
      WS2812Init();
    
      while (1)
      {
    
      }
    
    }
    

    WS2812.h:

    #ifndef INC_WS2812_H_
    #define INC_WS2812_H_
    
    #include <stm32f1xx_hal_gpio.h>     // use gpio output
    #include <stm32f1xx_hal_rcc.h>
    #include <stm32f1xx_hal_tim.h>      // use timer
    
    // adopt gpio port & pin for following section
    #define WS2812_GPIO_PORT    GPIOB
    #define WS2812_GPIO_PIN     GPIO_PIN_12
    
    #define ENABLE_GPIO_RCC()   do{\
                                    if(!__HAL_RCC_GPIOB_IS_CLK_ENABLED())\
                                        __HAL_RCC_GPIOB_CLK_ENABLE();\
                                }while(0U)
    
    static GPIO_InitTypeDef SW2812Pin = {
            .Pin = WS2812_GPIO_PIN,
            .Speed = GPIO_SPEED_FREQ_LOW,
            .Mode = GPIO_MODE_OUTPUT_PP
    };
    #define SYS_CLOCK
    
    // adopt timer configuration for following section
    #define WS2812_SELECTED_TIMER TIM4
    
    static TIM_HandleTypeDef ws2812TimerConfig;
    
    void WS2812Init(void);
    
    #endif /* INC_WS2812_H_ */
    

    WS2812.c:

    #include "WS2812.h"
    
    void WS2812Init(void)
    {
    
        // init GPIO as output
        ENABLE_GPIO_RCC();
        HAL_GPIO_WritePin(WS2812_GPIO_PORT, WS2812_GPIO_PIN, GPIO_PIN_RESET);
        HAL_GPIO_Init(WS2812_GPIO_PORT, &SW2812Pin);
    
        // init timer
        uint16_t targetFrequency = 1000; // 1kHz
        const uint16_t preScaler = 360;
        const uint16_t period = SystemCoreClock / (preScaler*targetFrequency);
        // clear status register
        __HAL_RCC_TIM4_CLK_ENABLE();
    
        ws2812TimerConfig.Instance = WS2812_SELECTED_TIMER;
        ws2812TimerConfig.Init.Prescaler = preScaler - 1;
        ws2812TimerConfig.Init.Period = period;
        ws2812TimerConfig.Init.CounterMode = TIM_COUNTERMODE_UP;
    
        HAL_TIM_Base_Init(&ws2812TimerConfig); // <- linker can not find this function
    
        __HAL_TIM_ENABLE(&ws2812TimerConfig);
    
    }
    

    This is my include structure:

    main->

    • include"WS2812.h" ->
      • include stm32f1xx_hal_tim.h

    The stm32f1xx_hal_tim.h is in the STM32F1xxHAL_DRIVER->inc, which is also put in the include path.

    I also have added the include path in the project properties->C/C++ Build->Settings for

    • GNU ARM Cross Assembler
    • GNU ARM Cross C compiler
    • GNU ARM Cross C++ Compiler

    I searched in the internet found out this is a linker issue, that the linker can not find the proper source for linking.

    What I have found in internet and tried:

    • added the folder which contents stm32f1xx_hal_tim.h and WS2812.h to project properties-> C/C++ Build -> GNU ARM Cross C++ Linker -> Libraries -> (-L)

    • added the folder which contents stm32f1xx_hal_tim.c and WS2812.c to project properties-> C/C++ Build -> GNU ARM Cross C++ Linker -> Libraries -> (-L)

    • Checked "stm32f1xx_hal_tim.h" -> property-> Exclude resource from build is unchecked (some people in the internet solved the problem by this)

    • Added "--specs=nano.specs" to the Linker options

    All of above do not solve the problem.

    Some people suggest to modify the makefile. But the project generate the makefile automatically, so I don't know where to start.

    If anyone can provide a hint or solution, it will be very thanksful.

    UPDATE 1:

    Thanks Jacek Ślimok's input.

    I didn't know that, I also need to doe the "exclude from build" for .c files. And I check in the file browser. The .c files are not check in this configuration. Do you mean like this? excluded from Build

    The stm32f1xx_hal_tim.c is under project->Driver->STM32F1xxHAL_Driver->Src

    At this moment, the problem remains unsolved.

    Another thing I noticed is that, the Eclipse read my stm32f1xx_hal_tim.c differently. When I open the stm32f1xx_hal_tim.c in Eclipse, it just give me a plane text like in normal notepad:

    stm32f1xx_hal_tim.c

    But other .c file like stm32f1xx_hal_gpio.c looks like normal. stm32f1xx_hal_gpio.c

    They are in the same folder. I don't know where and why this difference came from. Does this relative to my problem.

    Update2

    @Jacek Ślimok, I found out why the eclipse see the stm32f1xx_hal_tim.c as plane text. I accidentally turned on the Scalability setting in Preference-> Editor, stm32f1xx_hal_tim.c has relatively large file size, 161kB. After I change it back to default, Eclipse shows the file as normal. But the linker problem is still there...

    In the main.c I also used HAL_GPIO_TogglePin() from stm32f1xx_hal_gpio.h/.c. The linker does not complain about that. Currently I can not tell the difference between these 2 files(stm32f1xx_hal_gpio and stm32f1xx_hal_tim) They are in the same folder, and included the same as well. But I can use the function for GPIO not for Timer.

    But one thing can be sure: I can use the macro in the stm32f1xx_hal_tim.h, so this is a linker problem.

    I start this project base on another project, which was generated from STM32CubeMX. To practice the timer function I added the timer config to it, this is the point I got problem with the linker.

    I hope these information can lead to more hints.

    Update 3

    I tried build the .c files separately

    For stm32f1xx_hal.h.c:

    00:09:16 **** Building Selected Files of configuration Release for project TimerTest ****
    Info: Internal Builder is used for build
    arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Os -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -ffreestanding -Wall -Wextra -g -DSTM32F103xB -DHSE_VALUE=8000000 "-IC:\\Users\\Gebruiker\\Dropbox\\CodeBase\\Eclipse\\TimerTest\\Drivers\\CMSIS\\Include" "-IC:\\Users\\Gebruiker\\Dropbox\\CodeBase\\Eclipse\\TimerTest\\Drivers\\CMSIS\\Device\\ST\\STM32F1xx\\Include" "-IC:\\Users\\Gebruiker\\Dropbox\\CodeBase\\Eclipse\\TimerTest\\Drivers\\STM32F1xx_HAL_Driver\\Inc" "-IC:\\Users\\Gebruiker\\Dropbox\\CodeBase\\Eclipse\\TimerTest\\Inc" "-IC:\\Users\\Gebruiker\\Dropbox\\CodeBase\\Eclipse\\TimerTest\\Middlewares\\ST\\STM32_USB_Device_Library\\Class\\CDC\\Inc" "-IC:\\Users\\Gebruiker\\Dropbox\\CodeBase\\Eclipse\\TimerTest\\Middlewares\\ST\\STM32_USB_Device_Library\\Core\\Inc" -std=gnu11 -c -o "Drivers\\STM32F1xx_HAL_Driver\\Src\\stm32f1xx_hal_tim.o" "..\\Drivers\\STM32F1xx_HAL_Driver\\Src\\stm32f1xx_hal_tim.c" 
    
    00:09:17 Build Finished (took 285ms)
    

    For WS2812.c:

    00:11:23 **** Building Selected Files of configuration Release for project TimerTest ****
    Info: Internal Builder is used for build
    arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Os -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -ffreestanding -Wall -Wextra -g -DSTM32F103xB -DHSE_VALUE=8000000 "-IC:\\Users\\Gebruiker\\Dropbox\\CodeBase\\Eclipse\\TimerTest\\Drivers\\CMSIS\\Include" "-IC:\\Users\\Gebruiker\\Dropbox\\CodeBase\\Eclipse\\TimerTest\\Drivers\\CMSIS\\Device\\ST\\STM32F1xx\\Include" "-IC:\\Users\\Gebruiker\\Dropbox\\CodeBase\\Eclipse\\TimerTest\\Drivers\\STM32F1xx_HAL_Driver\\Inc" "-IC:\\Users\\Gebruiker\\Dropbox\\CodeBase\\Eclipse\\TimerTest\\Inc" "-IC:\\Users\\Gebruiker\\Dropbox\\CodeBase\\Eclipse\\TimerTest\\Middlewares\\ST\\STM32_USB_Device_Library\\Class\\CDC\\Inc" "-IC:\\Users\\Gebruiker\\Dropbox\\CodeBase\\Eclipse\\TimerTest\\Middlewares\\ST\\STM32_USB_Device_Library\\Core\\Inc" -std=gnu11 -c -o "Src\\WS2812.o" "..\\Src\\WS2812.c" 
    
    00:11:23 Build Finished (took 275ms)
    

    And for Main.c:

    00:12:02 **** Building Selected Files of configuration Release for project TimerTest ****
    Info: Internal Builder is used for build
    arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Os -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -ffreestanding -Wall -Wextra -g -DSTM32F103xB -DHSE_VALUE=8000000 "-IC:\\Users\\Gebruiker\\Dropbox\\CodeBase\\Eclipse\\TimerTest\\Drivers\\CMSIS\\Include" "-IC:\\Users\\Gebruiker\\Dropbox\\CodeBase\\Eclipse\\TimerTest\\Drivers\\CMSIS\\Device\\ST\\STM32F1xx\\Include" "-IC:\\Users\\Gebruiker\\Dropbox\\CodeBase\\Eclipse\\TimerTest\\Drivers\\STM32F1xx_HAL_Driver\\Inc" "-IC:\\Users\\Gebruiker\\Dropbox\\CodeBase\\Eclipse\\TimerTest\\Inc" "-IC:\\Users\\Gebruiker\\Dropbox\\CodeBase\\Eclipse\\TimerTest\\Middlewares\\ST\\STM32_USB_Device_Library\\Class\\CDC\\Inc" "-IC:\\Users\\Gebruiker\\Dropbox\\CodeBase\\Eclipse\\TimerTest\\Middlewares\\ST\\STM32_USB_Device_Library\\Core\\Inc" -std=gnu11 -c -o "Src\\main.o" "..\\Src\\main.c" 
    ..\Src\main.c: In function '_Error_Handler':
    ..\Src\main.c:268:27: warning: unused parameter 'file' [-Wunused-parameter]
     void _Error_Handler(char *file, int line)
                               ^~~~
    ..\Src\main.c:268:37: warning: unused parameter 'line' [-Wunused-parameter]
     void _Error_Handler(char *file, int line)
                                         ^~~~
    In file included from ..\Src\main.c:55:0:
    At top level:
    C:\Users\Gebruiker\Dropbox\CodeBase\Eclipse\TimerTest\Inc/WS2812.h:36:26: warning: 'ws2812TimerConfig' defined but not used [-Wunused-variable]
     static TIM_HandleTypeDef ws2812TimerConfig;
                              ^~~~~~~~~~~~~~~~~
    C:\Users\Gebruiker\Dropbox\CodeBase\Eclipse\TimerTest\Inc/WS2812.h:26:25: warning: 'SW2812Pin' defined but not used [-Wunused-variable]
     static GPIO_InitTypeDef SW2812Pin = {
                             ^~~~~~~~~
    
    00:12:02 Build Finished (took 272ms)
    

    There are few warning in the main.c, but they are not crucial.

    Update4:

    Thanks for Jacek Ślimok's input:

    I found out that functions of stm32f1xx_hal_tim.c shows gray in file browser.

    functions seems like not usable

    But the functions in stm32f1xx_hal_gpio.c shows solid balck.

    function in gpio.c are usable

    Now the difference is there, just need to find out why.

    Thanks in advance. Best regards.

  • MinShu Huang
    MinShu Huang almost 6 years
    Thanks Jacek Slimok, I try what you recommended. But the file is already unchecked to "Excluded from Build". I added more information in my original post. If you can give me more hint, that will be greatful.
  • J_S
    J_S almost 6 years
    @MinShuHuang Yes the option should be unchecked as on the screenshot you included. As for Eclipse opening that file as a regular file - that almost definitely is related to your issue. Eclipse seems to not see that file as a source file and likely that's the reason it's not being compiled. Right now I'm not aware what could be causing the issue. Maybe try to remove this file and re-add it? Go to where it's located on disk -> remove it -> refresh project in Eclipse (file should disappear) -> copy it back in -> refresh project again. See if issue persists.
  • MinShu Huang
    MinShu Huang almost 6 years
    thanks again for your effort. I did an update in the original post. I found out why the eclipse see the file as plane text. But it is not relative to my problem.
  • J_S
    J_S almost 6 years
    @MinShuHuang In this case check the following: Can you compile this file alone (rightclick anywhere in the editor while in that file and select Build Selected File. In console you should see a line with your compiler in it - likely arm-none-eabi-gcc. If that works- which means file is not excluded from build - see if HAL_TIM_Base_Init` is in fact in that file and that its signature (return type, parameters..) are the same as expected in WS2812.c:30, aka same as in the header file.
  • MinShu Huang
    MinShu Huang almost 6 years
    Hi I tried what you said, and put result in the post update. main.c / ws2812.c and stm32f1xx_hal_tim.c can be build separately. As I press F3 on the HAL_TIM_Base_Init() in WS2812.c, eclipse did lead me to the function declaration of HAL_TIM_Base_Init() in stm32f1xx_hal_tim.h
  • J_S
    J_S almost 6 years
    @MinShuHuang And does doing F3 on the function in the header stm32f1xx_hal_tim.h file move you to the function in the stm32f1xx_hal_tim.c file?
  • MinShu Huang
    MinShu Huang almost 6 years
    No It doesn't. And I tried with functions in stm32f1xx_hal_gpio.h. It did lead me to stm32f1xx_hal_gpio.c. So there is definitely difference.
  • J_S
    J_S almost 6 years
    Manually search for it in the .c file and see if name, return and parameter types match the header file. If they do, that function is likely not compiled because of some precompiler #if/#ifdef directive. If so, Eclipse grays out such area in the editor. HAL_TIM_MODULE_ENABLED in particular seems to be the main suspect - make sure it's defined.
  • J_S
    J_S almost 6 years
    Congratulations. Edited answer for completeness.