undefined reference to function I2C library and HMC5883L read function

Hello,

I’m developing my code to run HMC5883L module.

First I get this error while compiling my C code in Arduino IDE as I’m writing all my codes in C.

The error is:

Arduino: 1.8.0 (Windows 10), Board: “Arduino Nano, ATmega328”

C:\Users\wolfrose\AppData\Local\Temp\cc9f8iwd.ltrans0.ltrans.o: In function `setup’:

D:\microcontroller dev\Sketches, codes, measurements & configs\AVR C\Sensors\HMC5883L/HMC5883L.ino:33: undefined reference to `I2C_init()’

collect2.exe: error: ld returned 1 exit status

exit status 1
Error compiling for board Arduino Nano.

This report would have more information with
“Show verbose output during compilation”
option enabled in File → Preferences.

I attached my I2C library.

This is my application code in Arduino IDE:

#include <I2C.h>



//Output = [Mset – Mreset] / 2

#define HMC5883L_read   0x3D
#define HMC5883L_write  0x3C

#define Configuration_Register_A    0x00  //Read/Write
#define Configuration_Register_B    0x01  //Read/Write
#define Mode_Register               0x02  //Read/Write
#define Data_Output_X_MSB_Register  0x03  //Read
#define Data_Output_X_LSB_Register  0x04  //Read
#define Data_Output_Z_MSB_Register  0x05  //Read
#define Data_Output_Z_LSB_Register  0x06  //Read
#define Data_Output_Y_MSB_Register  0x07  //Read
#define Data_Output_Y_LSB_Register  0x08  //Read
#define Status_Register             0x09  //Read
#define Identification_Register_A   0x10  //Read
#define Identification_Register_B   0x11  //Read
#define Identification_Register_C   0x12  //Read


void HMC5883L_init (void);
int16_t data_read (void);
int16_t data;

//  I2C_start();
//  I2C_tx();
void setup() {
  // put your setup code here, to run once:
  I2C_init();
}

void loop() {
  // put your main code here, to run repeatedly:

}


void HMC5883L_init (void)
{
  I2C_start(HMC5883L_write);
  I2C_tx(Configuration_Register_A);
  I2C_tx(0x07);
  I2C_stop();
  I2C_tx(Configuration_Register_B);
  I2C_tx(0x01);
  I2C_stop(); 
  I2C_tx(Mode_Register);
  I2C_tx(0x02);
  I2C_stop();  
}

int16_t data_read (void)
{
  I2C_start(HMC5883L_write);
  I2C_tx(0x06);
  I2C_stop();
  I2C_start(HMC5883L_read);
  I2C_rx();
  data = TWDR << 8;
  I2C_stop();
  I2C_start(HMC5883L_read);
  I2C_rx();
  data = TWDR << 8;
  I2C_stop();  
}

Second, I want help with developing data_read function, is my way correct until now.

I know I have to read 6 bytes of data.

Regards,

I2C.c (783 Bytes)

I2C.h (461 Bytes)

The Arduino is programmed using C++, NOT C. That means that the .ino file is converted to a .cpp file before compilation. That means that the C++ compiler is invoked. Because C++ supports function overloading - several functions with the same name but different arguments - the compiler performs name mangling. That is, it creates a name for each function based on the function name and the types of all arguments.

When you call a function, like I2C_init(), it mangles the name to determine what function for the linker to actually link.

When you compile your C code, name mangling is NOT done, so the name for the linker to link in is I2C_init, which is NOT the name that the linker is looking for.

The simplest solution is to rename your c file to cpp. That way, the c++ compiler will be used to compile it, and will mangle the I2C_init name the same way that the sketch compilation mangled it, so the linker will find the function to link in.

The alternative involves the extern "C" { } wrapper, which Mr. Google will tell you all about.

PaulS:
The Arduino is programmed using C++, NOT C. That means that the .ino file is converted to a .cpp file before compilation. That means that the C++ compiler is invoked. Because C++ supports function overloading - several functions with the same name but different arguments - the compiler performs name mangling. That is, it creates a name for each function based on the function name and the types of all arguments.

When you call a function, like I2C_init(), it mangles the name to determine what function for the linker to actually link.

When you compile your C code, name mangling is NOT done, so the name for the linker to link in is I2C_init, which is NOT the name that the linker is looking for.

The simplest solution is to rename your c file to cpp. That way, the c++ compiler will be used to compile it, and will mangle the I2C_init name the same way that the sketch compilation mangled it, so the linker will find the function to link in.

The alternative involves the extern "C" { } wrapper, which Mr. Google will tell you all about.

OK but why I2C_init is the only function which has this problem?

I mean on my original configuration with including .h and .c files as my I2C library, it works when I comment only I2C_init, the rest functions work fine while copmiling them in Arduino IDE?!

I did your solution chanigng the file extention to .cpp, you absoluteyl right, it worked :slight_smile:

I need also to learn how to apply this alternative solution, extern "C" is something I don't have much experience about.

I also need to learn much more about C; like, vitual, inline, extern and other keywords.

OK so far so good, I just need to develop my HMC5883L read function.

Update:
I compiled the code with Atmel Studio 7, and it compiled OK.