Getting undefined reference error on union defined within a library function

jrdarrah

Well-known member
I'm trying to port my application from a teensy 3.2 to teensy 4.0. I used the built-in DAC in the 3.2 so I will need to use an external one with the 4.0. I found a library for the MAX5443 in an old github project. It will support moving data to the MAX5443 via SPI (when I get it working). Here is my sketch

Code:
#include <MAX5443.h>

#include <SPI.h>
#define CS_MAX5443  10
#define CLR_MAX5443 9
max5443 DAC1(CS_MAX5443);
uint16_t audioBuffer;
void setup() {
  SPI.begin();
  DAC1.pins_init();
  pinMode (CLR_MAX5443, OUTPUT);
  digitalWrite (CLR_MAX5443, HIGH);
  audioBuffer = 40000;
  DAC1.set_voltage(audioBuffer);
}

void loop() {


}

The library header:

Code:
/*///////////////////////////////////////*/
/*          DAC related class            */
/*///////////////////////////////////////*/

/*
 * Library for DAC pin initialization and voltage polarization. 
 */

#ifndef MAX5443_h
#define MAX5443_h
#include <Arduino.h>

class max5443{
  public:
    max5443(int Chip_Select);
    void pins_init(void);
    void set_voltage(uint16_t Voltage_index);
  private:
    int _pin;
    static union  {
      uint8_t ui8[2];
      uint16_t ui16;
    } _DAC_buffer;
};

#endif

and the library

Code:
/*///////////////////////////////////////*/
/*          DAC related class            */
/*///////////////////////////////////////*/
// max5443.cpp is a direct copy of max5443.cpp JD 7/31/22
#include <Arduino.h>
#include <MAX5443.h>
#include <SPI.h>

//SPI Object, 24 MHz, MSB, Mode 0
SPISettings SPI_max5443(25000000, MSBFIRST, SPI_MODE0);

max5443::max5443(int Chip_Select){
  _pin = Chip_Select;
}

void max5443::pins_init(){
  /*
     Purpose: DAC Chip select pin is set as output and turns it HIGH (i.e. chip is not selected)
     |----------------------|-------------------------------------------------|
     |Parameter             |Description                                      |
     |----------------------|-------------------------------------------------|
     |Chip_Select           |Pin where DAC is located                         |
     |----------------------|-------------------------------------------------|
  */
  pinMode(_pin, OUTPUT);
  digitalWrite(_pin, HIGH);
}

void max5443::set_voltage(uint16_t Voltage_index) {
  /*
     Puprpose: Sends the index value voltage to selected DAC
     |----------------------|-------------------------------------------------|
     |Parameter             |Description                                      |
     |----------------------|-------------------------------------------------|
     |Voltage_index         |DAC index value from 0 to 65535 (0 to ~3 volts)  |
     |----------------------|-------------------------------------------------|
  */

  //Impose limits to Voltage_index within 0 and 65535
  if(Voltage_index > 0xFFFF)
    Voltage_index = 0xFFFF;
  else if(Voltage_index < 0)
    Voltage_index = 0;  

  _DAC_buffer.ui16 = Voltage_index;

  //Transfer two bytes to selected DAC
  //SPI.beginTransaction(SPI_max5443);
  //digitalWrite(_pin, LOW);
  //SPI.transfer(_DAC_buffer.ui8[1]);
  //SPI.transfer(_DAC_buffer.ui8[0]);
  //digitalWrite(_pin, HIGH);
  //SPI.endTransaction();
}

I've commented out most of the extraneous code and still get this error

C:\Users\james\AppData\Local\Temp\arduino_build_534888\libraries\MAX5443\MAX5443.cpp.o: In function `max5443::set_voltage(unsigned short)':
C:\Users\james\Documents\Arduino\libraries\MAX5443/MAX5443.cpp:45: undefined reference to `max5443::_DAC_buffer'
collect2.exe: error: ld returned 1 exit status. I don't know how to define it within the set_voltage routine. I'm sure for someone with experience the fix is easy. I reached out to the original author but so far I haven't heard back? Any help would be greatly appreciated
 
Looks like 'private' is blocking that structure declaration internal item _DAC_buffer:
Code:
...
[B][U]  private:[/U][/B]
    int _pin;
    static union  {
      uint8_t ui8[2];
      uint16_t ui16;
    } _DAC_buffer;
};

Perhaps the value is to be passed in another way with just a unit16_t variable.
 
Thanks for the reply.

I tried commenting out the private; line so everything was public. I still get the same error. The _pin variable is private and doesn't cause any errors.

The reason for the union lies in some of the code that I commented out (see below). When the data come into set_voltage it gets moved to the ui16 variable in the union. My understanding of union is it uses one area of storage but defines it in multiple ways. In this case a uint8_t ui8[2] redefines the uint16 ui16 variable so that when it is loaded into that variable the data can be retrieved via the ui8 array. That seems to be needed to send the data in the correct order to the DAC over the SPI link.

Code:
_DAC_buffer.ui16 = Voltage_index;

  //Transfer two bytes to selected DAC
  SPI.beginTransaction(SPI_max5443);
  digitalWrite(_pin, LOW);
  SPI.transfer(_DAC_buffer.ui8[1]);
  SPI.transfer(_DAC_buffer.ui8[0]);
 
Yes, it just allows indexing each byte of the 2 byte number. So code should just suppl it with the desired 16 bit value and it deals with the transfer.
 
I tracked down the GitHub repo, and it looks a bit like a student project, lots in there which smells of inexperience! I also can’t see how the part you’ve borrowed could ever have worked, though I didn’t search for long.

TL;DR - put the private back, and remove the static, pretty sure that’ll do it.

The linker is complaining that the static union isn’t defined, because it isn’t. If you wanted one then it should be put in the cpp. I don’t think you do, because that means it’s shared between all devices. Also, as it’s only needed for the lifetime of set_voltage(), it could be moved out of the class definition altogether and put into set_voltage() as a temporary variable.
 
Back
Top