1

I have a driver and code that works on IAR but does not work for Atmel Studio 7. I get an error ld returned 1 exit status and undefined reference to '_read' (or _write) when I try to assign a function to a pointer inside a struct.

In the driver that I need to use there are two pointers defined as follows:

#define BMM050_WR_FUNC_PTR \
    s8 (*bus_write)(u8, u8, \
    u8 *, u8)

#define BMM050_RD_FUNC_PTR \
    s8 (*bus_read)(u8, u8, \
    u8 *, u8)re

In the file they have a struct defined as follows:

struct bmm050_t {
    u8 company_id;/**<mag chip id*/
    u8 dev_addr;/**<mag device address*/

    BMM050_WR_FUNC_PTR;/**< bus write function pointer*/
    BMM050_RD_FUNC_PTR;/**< bus read function pointer*/
    void (*delay_msec)(BMM050_MDELAY_DATA_TYPE);/**< delay function pointer*/

    s8 dig_x1;/**< trim x1 data */
    s8 dig_y1;/**< trim y1 data */

    s8 dig_x2;/**< trim x2 data */
    s8 dig_y2;/**< trim y2 data */

    u16 dig_z1;/**< trim z1 data */
    s16 dig_z2;/**< trim z2 data */
    s16 dig_z3;/**< trim z3 data */
    s16 dig_z4;/**< trim z4 data */

    u8 dig_xy1;/**< trim xy1 data */
    s8 dig_xy2;/**< trim xy2 data */

    u16 dig_xyz1;/**< trim xyz1 data */
};

In my application I try to do:

bmm050.bus_write = i2c_write;
bmm050.bus_read = i2c_read;

My functions are defined as:

int8_t i2c_write(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data, uint8_t count);

int8_t i2c_read(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data, uint8_t count);

EDIT: I am attaching the error code as asked:

c:/program files (x86)/atmel/studio/7.0/toolchain/arm/arm-gnu-toolchain/bin/../lib/gcc/arm-none-eabi/5.3.1/../../../../arm-none-eabi/lib/armv6-m\libc.a(lib_a-writer.o): In function `_write_r':
C:\Users\aba\Documents\Atmel Studio\7.0\Project1\Project1\Debug\writer.c(1,1): error: undefined reference to `_write'
c:/program files (x86)/atmel/studio/7.0/toolchain/arm/arm-gnu-toolchain/bin/../lib/gcc/arm-none-eabi/5.3.1/../../../../arm-none-eabi/lib/armv6-m\libc.a(lib_a-readr.o): In function `_read_r':
C:\Users\aba\Documents\Atmel Studio\7.0\Project1\Project1\Debug\readr.c(1,1): error: undefined reference to `_read'
collect2.exe(0,0): error: ld returned 1 exit status
cxw
  • 16,685
  • 2
  • 45
  • 81
NitrogenAir
  • 63
  • 1
  • 8
  • use a debugger, get a dump, backtrace and all that, and have a look at what `BMM050_MDELAY_DATA_TYPE` actually is. – Elias Van Ootegem Oct 19 '16 at 13:45
  • 1
    None of the code you've shown has any mention of `_read` and `_write` (only `bus_read` or `i2c_read` etc.). What makes you think the linker is complaining about this code? – TripeHound Oct 19 '16 at 13:48
  • I commented those the two lines where I try to assign functions and errors disappear. `BMM050_MDELAY_DATA_TYPE` is a `uint_32t` and for some reason doing bmm050.delay_msec = delay_cycles_ms works fine – NitrogenAir Oct 19 '16 at 13:51
  • 1
    For the love of obfuscation, use `typedef` and not icky macros! – Lundin Oct 19 '16 at 13:59
  • You have a great point, but this comes from fully written driver which I would prefer not to change. I tried rewriting it using `typedef`, however, as they use these macros everywhere in the code I would need to change it everywhere as well... – NitrogenAir Oct 19 '16 at 14:04
  • Whilst looking online I found that many people associate this problem to linker. Is there a chance that is the case? – NitrogenAir Oct 19 '16 at 14:19
  • 1
    As far as I can see, to be complaining about `_read` (instead of, say, `bus_read`) then either there's a cut-and-paste error in the code you're showing (e.g. the 2nd macro definition has a trailing `re`) or some other macro-stuff is kicking in (you haven't got `i2c` defined as an empty string somewhere? ... stray spaces in your assignment statements?). – TripeHound Oct 19 '16 at 14:24
  • Please cut and paste the full "ld" and "undefined" error messages verbatim into the question (as code). – Jeff Y Oct 19 '16 at 15:23
  • Please find it added. – NitrogenAir Oct 20 '16 at 16:38
  • Your error messages and the snippets of code you posted here seem completely unrelated. – melpomene Oct 20 '16 at 17:11

1 Answers1

1

I am guessing that your i2c_write and i2c_read functions call printf, write, putc, puts, or a similar function. Yes?

The errors you are seeing are the wrappers _write_r and _read_r trying to invoke the underlying write and read functions, and not being able to find them. See, e.g., this discussion (sec. 6.4) of implementation of these functions in the newlib C library.

The errors disappear when you comment out the bmm050.bus_write = i2c_write and bmm050.bus_read = i2c_read lines because nothing else in your code calls read or write. If you don't reference i2c_read in your code, such as when those lines are commented out, the linker can remove i2c_read from the compiled object file. Without i2c_read, there is no need for _read_r or read, so you don't get the linker errors.

So what to do?

A few options, in the order I would try them.

  1. Call your board-support-package (BSP) vendor if you have a support contract.
  2. Search through the Atmel Studio source/libraries to see if they provide a _read or _write implementation for your particular hardware. If Atmel Studio includes a BSP for your board, that may include the functions. (I don't have Atmel Studio myself, and probably wouldn't have the same BSP even if I did, so I can't tell you more specifically than that where to look.)
  3. Modify your i2c_read and i2c_write so they access the device's I2C registers directly. If you can eliminate calls the C library's I/O routines from those functions, you will no longer need _read or _write.
  4. If you can't find an existing implementation or eliminate the need for one, look online for implementations. For example, this blog post (in German) includes a sample implementation of _write. That, plus the links below it in the thread, may help you (even if you don't speak German).
  5. Finally, if necessary, roll your own _read and _write that will do some meaningful input and output on your particular target. I gather that's I2C, but you might at some point want that to be UART, LCD, seven-segment display, Nixie, or something else — write whatever I/O routines you wish! Note that this basically involves the same type of work as #3, but in a different context.

See also:

  • this answer, which relates to a similar situation on a different platform
  • this discussion of implementing your own OS (effectively) in order for _write_r to have something to talk to!
Community
  • 1
  • 1
cxw
  • 16,685
  • 2
  • 45
  • 81