This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Undefined symbol XXX using a C++ function

Admittedly I am new to C++ and am much more comfortable in ANSI C, so this might be a simple problem:

I have some C++ files for my application that are running on top of the CubeMX HAL from ST. I am running bare metal.

My project all compiles cleanly with no warnings or errors. When it tries to link I get an undefined symbol error. My suspicions are it has something to do with name mangling from C++, but I'm not certain. I am using the extern "C" {} around the c++ header files to accommodate the mixed c/c++

Below is the definition of the functions (overloaded), the complete include file, and a snippet from the usage that is throwing the linkage error.

linking...
DiscBoard-Interm\DiscBoard-Interm.axf: Error: L6218E: Undefined symbol GPIO::RWGpio(GPIO::Pin_e) (referred from max31856.o).
DiscBoard-Interm\DiscBoard-Interm.axf: Error: L6218E: Undefined symbol GPIO::RWGpio(GPIO::Pin_e, GPIO::AbstractState_e) (referred from max31856.o).
Not enough information to list image symbols.
Finished: 1 information, 0 warning and 2 error messages.


/**
   @brief Read/Write GPIO

   This function will take the parameters and determine if the request is a read or write request.
   The index will be the particular IO to use, and the data passed is the set value.  If there is no
   set value passed in, the function will return the existing value.  If a value is passed, it will set
   the value and return.

   Global variables
      none

*/
GPIO::AbstractState_e RWPGpio(GPIO::Pin_e PinIdx)
{
   GPIO_PinState State;
   GPIO::AbstractState_e retval;

   if (GpioCfgTable[PinIdx].Idx == PinIdx)  //make sure table is consistent with request
   {
      State = HAL_GPIO_ReadPin(GpioCfgTable[PinIdx].Port,GpioCfgTable[PinIdx].Pin);
      if (GpioCfgTable[PinIdx].ActiveState == GPIO_PIN_SET)
      {
         //normal positive polarity so do nothing
         retval = (GPIO::AbstractState_e)State;
      }
      else
      {
         //we need to invert on/off
         retval = (GPIO::AbstractState_e)((State + 1)>>1);
      }
   }
   else
   {
      //inconsistent def, throw an error and do nothing
   }
   return retval;
}

/**
   @brief Read/Write GPIO

   This function will take the parameters and determine if the request is a read or write request.
   The index will be the particular IO to use, and the data passed is the set value.  If there is no
   set value passed in, the function will return the existing value.  If a value is passed, it will set
   the value and return.

   Global variables
      none

*/
void RWGpio(GPIO::Pin_e PinIdx, GPIO::AbstractState_e State)
{
   GPIO_PinState PinState;

   if (GpioCfgTable[PinIdx].ActiveState == GPIO_PIN_SET)
   {
      //normal positive polarity so do nothing
      PinState = (GPIO_PinState)State;
   }
   else
   {
      //we need to invert on/off
       PinState = (GPIO_PinState)((State + 1)>>1);
   }

   if (GpioCfgTable[PinIdx].Idx == PinIdx)  //make sure table is consistent with request
   {
      HAL_GPIO_WritePin(GpioCfgTable[PinIdx].Port,GpioCfgTable[PinIdx].Pin,PinState);

   }
   else
   {
      //inconsistent def, throw an error and do nothing
   }
   //return state;
}
#ifndef GPIO_H
#define GPIO_H


#ifdef __cplusplus extern "C" { #endif
#include "stm32f4xx_hal.h" // Keil::Device:STM32Cube HAL:Common #include <stdint.h> #include "stm32f4xx_hal_gpio.h" //GPIO defs
struct GPIOConfig { uint8_t Idx; GPIO_TypeDef* Port; uint16_t Pin; GPIO_PinState ActiveState; };
class GPIO {
public: enum AbstractState_e { OFF=0, ON }; enum Pin_e { UC_KICK_WDOG = 0, CONTACT_QUALITY_MON, CH4_TEMP_FAULT, CH4_RF_ENABLE, CH4_CAL_RELAY, FAN_TEMP_ALERT, CH4_RETURN_RELAY, UC_WKUP, CH4_RF_VOLTAGE_MON, CH4_RF_CURRENT_MON, CH3_RF_VOLTAGE_MON, CH3_RF_CURRENT_MON, CH2_RF_V_MON, CH2_RF_I_MON, CH1_RF_V_MON, CH1_RF_I_MON, CH4_TEMP_DATA_READY, CH4_DAC_SPI3_CS, CH4_TEMP_SPI6_CS, CH3_TEMP_FAULT, CH3_RF_ENABLE, CH3_CAL_RELAY, CH3_RETURN_RELAY, CH3_TEMP_DATA_READY, CH3_DAC_SPI3_CS, CH3_TEMP_SPI6_CS, CH2_TEMP_FAULT, CH2_RF_ENABLE, CH2_CAL_RELAY, CH2_RETURN_RELAY, CH2_TEMP_DATA_READY, CH2_DAC_SPI3_CS, CH2_TEMP_SPI6_CS, CH1_RF_ENABLE, CH1_TEMP_FAULT, CH1_CAL_RELAY, CH1_RETURN_RELAY, CH1_TEMP_DATA_READY, CH1_DAC_SPI3_CS, CH1_TEMP_SPI6_CS, STIM_NEG, STIM_POS, STIM_SELECT, DEBUG_OUTPUT_PC7, DEBUG_OUTPUT_PC8, DEBUG_INPUT_PC9, FAN_FLT_FULL_SPEED, OSC_460KHZ_ENABLE, FAN_OVERTEMP, H_LOCKOUT_RF_MONITOR, L_STANDBY_ACTIVE, L_UC_MASTER_DISABLE_RF, L_WDOG_TIMER_EXPIRED, UC_WDOG_REG_DAT, UC_WDOG_REG_CLK, LED3_PE0, LED4_PE1, MAX_PIN_CNT };
private: //TODO Come back and figure out how to make this a private const table //and where does it live in memory //static const GPIO_Config GpioCfgTable[];
public: GPIO_PinState RWGpio(Pin_e PinIdx); void RWGpio(Pin_e PinIdx,AbstractState_e State); }; //end class
#ifdef __cplusplus } #endif
#endif //GPIO_H


usage:

Thermocouple::TempTenths Thermocouple::ReadThermocouple (uint8_t Tidx)
{
uint8_t spiCommand[3];
uint8_t spiResp[3];
//HAL_StatusTypeDef retStatus;
GPIO_PinState State;
GPIO rwGPIO;
TempTenths temperature;

      State = rwGPIO.RWGpio(rwGPIO.CH2_TEMP_DATA_READY);

      if (State == GPIO_PIN_RESET)
      {
         //Read the temperature
         spiCommand[0] = 0x0c;

         rwGPIO.RWGpio(rwGPIO.CH2_DAC_SPI3_CS,rwGPIO.ON);
         //Transmitting 2 more bytes than configured.  Doesn't really matter, but will be garbage.
         HAL_SPI_TransmitReceive(&hspi6, (uint8_t*)&spiCommand,(uint8_t*)&spiResp,sizeof(spiCommand),1000);
         rwGPIO.RWGpio(rwGPIO.CH2_DAC_SPI3_CS,rwGPIO.OFF);

      }
      //TODO check this response for accuracy
      temperature = (spiResp[0]<<8) & spiResp[1];
      return temperature;
}

Parents
  • Additional info:

    I am using

    IDE-Version:
    µVision V5.23.0.0
    Copyright (C) 2017 ARM Ltd and ARM Germany GmbH. All rights reserved.

    Tool Version Numbers:
    Toolchain: MDK-ARM Standard Cortex-M only Version: 5.23
    Toolchain Path: C:\Keil_v5\ARM\ARMCC\Bin
    C Compiler: Armcc.exe V5.06 update 4 (build 422)
    Assembler: Armasm.exe V5.06 update 4 (build 422)
    Linker/Locator: ArmLink.exe V5.06 update 4 (build 422)

    Also the typo in the first function declaration is not real Cut and paste error.
    There is no "P" in the middle of the function name.

Reply
  • Additional info:

    I am using

    IDE-Version:
    µVision V5.23.0.0
    Copyright (C) 2017 ARM Ltd and ARM Germany GmbH. All rights reserved.

    Tool Version Numbers:
    Toolchain: MDK-ARM Standard Cortex-M only Version: 5.23
    Toolchain Path: C:\Keil_v5\ARM\ARMCC\Bin
    C Compiler: Armcc.exe V5.06 update 4 (build 422)
    Assembler: Armasm.exe V5.06 update 4 (build 422)
    Linker/Locator: ArmLink.exe V5.06 update 4 (build 422)

    Also the typo in the first function declaration is not real Cut and paste error.
    There is no "P" in the middle of the function name.

Children
No data