HardwareSerial0.cpp.o (symbol from plugin): In function `Serial': (.text+0x0): multiple definition of `__vector_18'

Hi,

I'm trying to write my own serial module for a library that I'm working on. You can find it here:
(GitHub - jklarenbeek/protoduino).

I have created a .ino project file in the examples folder called 21-pt-serial-echo.ino, but I cannot get it to work. It breaks when linking the ISR implementation of the serial0.c module, but since I do not reference any Serial.begin or Serial.print, etc call in the .ino file it should not link the HardwareSerial0.cpp.o to begin with.

However, this appears to be happening. What am I doing wrong here?

Regards,

Joham

Not posting your code?

Actually I did, if you follow the links I included in the question.

You can find it here: protoduino/examples/21-pt-serial-echo/21-pt-serial-echo.ino at main · jklarenbeek/protoduino · GitHub

Actually, you didn't post your code, you posted a link to it. (Or I wouldn't have commented)
But, it seems you'd rather argue than get help, so I'll leave you to it.

I wasn't sure if just posting the ino file would be enough to understand the problem, anyhow, here it is:

in file: 21-pt-serial-echo.ino

#include <protoduino.h>
#include <sys/serial0.h>

void setup()
{
  serial0_open(SERIAL_BAUD_9600);
}

void loop()
{
  if (serial0_write8(65) == 0)
  {
    delay(1000);
    serial0_write8(66);
  }
}

in file protoduino.h:

#ifndef __PROTODUINO_H__
#define __PROTODUINO_H__

#include <stdbool.h>

#include "sys/cc.h"
#include "sys/pt.h"

#endif

in serial0.cpp

#ifndef __SERIAL0_H__
#define __SERIAL0_H__

#include "cc.h"
#include <stdbool.h>

#ifndef SERIAL_BUFFER_RX_SIZE
#define SERIAL_BUFFER_RX_SIZE 8
#endif
#ifndef SERIAL_BUFFER_TX_SIZE
#define SERIAL_BUFFER_TX_SIZE 8
#endif

#define SERIAL_BAUD_1200 1200
#define SERIAL_BAUD_2400 2400
#define SERIAL_BAUD_4800 4800
#define SERIAL_BAUD_9600 9600
#define SERIAL_BAUD_19200 19200
#define SERIAL_BAUD_38400 38400
#define SERIAL_BAUD_57600 57600
#define SERIAL_BAUD_115200 115200 

// send flowcontrol xoff message to sender (force sender to wait)
#define SERIAL_FLOWCONTROL_XOFF 0x13
// send flowcontrol xon to sender (tell sender to start transmitting again)
#define SERIAL_FLOWCONTROL_XON 0x11

CC_EXTERN void serial0_onrecieved(uint_fast8_t (*callback)(uint_fast8_t));
CC_EXTERN void serial0_ontransmitted(void (*callback)(void));

CC_EXTERN void serial0_open(uint32_t baud);
CC_EXTERN void serial0_openex(uint32_t baud, uint8_t options);
CC_EXTERN void serial0_close(void);
CC_EXTERN uint_fast32_t serial0_get_baudrate(void);

CC_EXTERN uint_fast8_t serial0_rx_available(void);
CC_EXTERN uint_fast8_t serial0_rx_error(void);
CC_EXTERN uint_fast8_t serial0_rx_read8(void);
CC_EXTERN uint_fast8_t serial0_tx_available(void);
CC_EXTERN void serial0_tx_write8(uint_fast8_t data);

CC_EXTERN uint_fast8_t serial0_read_available(void);
CC_EXTERN int_fast16_t serial0_read8();
CC_EXTERN int_fast32_t serial0_read16();
CC_EXTERN int_fast32_t serial0_read24();
CC_EXTERN int_fast32_t serial0_read32();

CC_EXTERN uint_fast8_t serial0_write_available();
CC_EXTERN uint_fast8_t serial0_write8(uint_fast8_t data);
CC_EXTERN uint_fast8_t serial0_write16(uint_fast16_t data);
CC_EXTERN uint_fast8_t serial0_write24(uint_fast32_t data);
CC_EXTERN uint_fast8_t serial0_write32(uint_fast32_t data);

#endif

I didn't include the cc.h file and the pt.h file since the first are only compiler helpers like CC_EXTERN and the other i very large and complex but doesnt include anything noteworthy outside of its own source tree other then stdbool.h or stdint.h. I hope this helps.

Now i think about it, cc.h does include <avr/pgmspace.h>. I should probably investigate that further.

/**
 * @file cc.h
 * @brief Common definitions and macros for Protoduino
 * 
 * This file provides common definitions and macros used in the Protoduino library. 
 * It includes various macros for attribute handling, inlining functions, concatenating
 * strings/identifiers, defining constant arrays and strings stored in program memory, 
 * declaring externally defined constant arrays and strings, and determining the number 
 * of elements in an array.
 * 
 */


#ifndef __CC_H__
#define __CC_H__

#include <avr/pgmspace.h>

/**
 * @def CC_UNUSED
 * @brief Macro to mark a variable as unused
 */
#define CC_UNUSED __attribute__ ((unused))

/**
 * @def CC_INLINE
 * @brief Macro to inline a function or code snippet
 */
#define CC_INLINE inline

/**
 * @def CC_ALWAYS_INLINE
 * @brief Macro to define an inline function with the given attribute
 * @param f The function definition
 */
#ifndef CC_ALWAYS_INLINE
#if defined(__GNUC__) && !defined(__MINGW32__)
#define CC_ALWAYS_INLINE __attribute__((__always_inline__)) inline
#elif defined(_MSC_VER)
#define CC_ALWAYS_INLINE __forceinline
#else
#define CC_ALWAYS_INLINE inline
#endif
#endif

/**
 * 
*/
#define CC_FLATTEN __attribute__((flatten)) 

/**
 * 
*/
#define CC_NO_INLINE __attribute__((noinline))

/**
 * @def CC_EXTERN
 * @brief Macro to define an extern c function
*/
#ifdef __cplusplus
#define CC_EXTERN extern "C"
#else
#define CC_EXTERN
#endif

/**
 * @def CC_WEAKFN(f)
 * @brief Macro to define a weak function
 * @param f The function definition
 */
#define CC_WEAKFN(f) f __attribute__((weak))

/**
 * @def CC_CONCAT2EXT(s1, s2)
 * @brief Macro to concatenate two strings or identifiers
 * @param s1 The first string or identifier
 * @param s2 The second string or identifier
 */
#define CC_CONCAT2EXT(s1, s2) s1##s2

/**
 * @def CC_CONCAT2(s1, s2)
 * @brief Macro to concatenate two strings or identifiers
 * @param s1 The first string or identifier
 * @param s2 The second string or identifier
 */
#define CC_CONCAT2(s1, s2) CC_CONCAT2EXT(s1, s2)

/**
 * @def CC_CONST_PTYPE_ARRAY(type, varname)
 * @brief Macro to define a constant array stored in program memory
 * @param type The data type of the array elements
 * @param varname The name of the variable representing the array
 */
#define CC_CONST_PTYPE_ARRAY(type, varname) const type varname[] PROGMEM

/**
 * @def CC_EXPORT_CONST_PTYPE_ARRAY(type, varname)
 * @brief Macro to declare an externally defined constant array stored in program memory
 * @param type The data type of the array elements
 * @param varname The name of the variable representing the array
 */
#define CC_EXPORT_CONST_PTYPE_ARRAY(type, varname) extern const type varname[]

/**
 * @def CC_CONST_PSTR(varname, value)
 * @brief Macro to define a constant string stored in program memory
 * @param varname The name of the variable representing the string
 * @param value The value of the string
 */
#define CC_CONST_PSTR(varname, value) CC_CONST_PTYPE_ARRAY(char, varname) = value;
//#define CC_CONST_PSTR(var, val) const char var[] PROGMEM = val

/**
 * @def CC_EXPORT_CONST_PSTR(varname)
 * @brief Macro to declare an externally defined constant string stored in program memory
 * @param varname The name of the variable representing the string
 */
#define CC_EXPORT_CONST_PSTR(varname) CC_EXPORT_CONST_PTYPE_ARRAY(char, varname)

/**
 * @def CC_CONST_PSTRUCT_ARR(type, varname)
 * @brief Macro to define a constant array of structures stored in program memory
 * @param type The data type of the structures in the array
 * @param varname The name of the variable representing the array
 */
#define CC_CONST_PSTRUCT_ARR(type, varname) CC_CONST_PTYPE_ARRAY(struct type, varname)
//#define CC_CONST_PSTRUCT_ARR(type, varname) const struct type varname[] PROGMEM

/**
 * @def CC_NELEM(x)
 * @brief Macro to determine the number of elements in an array
 * @param x The array
 * @return The number of elements in the array
 */
#define CC_NELEM(x) (sizeof (x)/sizeof (x)[0])

#define CC_ALIGN(n) __attribute__((__aligned__(n)))

/**
 * @def CC_MAIN_CONSTRUCTOR(name)
 * @brief function called before the void main() entry point
*/
#define CC_MAIN_CONSTRUCTOR(name) void __attribute__((constructor)) name();

/**
 * @def CC_MAIN_DESTRUCTOR(name)
 * @brief function called after the void main() entry point
*/
#define CC_MAIN_DESTRUCTOR(name) void __attribute__((destructor)) name();

#endif

Doesn't a .ino have an implicit "#include <Arduino.h>"? (In "main.cpp")

Could that be a problem?

It should not if I compare it against libraries like DMXSerial or PicoSerial

However, clearly something is going wrong and something is making a reference to one off the HardwareSerial0.cpp members. But which...

Having checked avr-libc I couldn't find anything either that would reference any of these members... so I think I'm going to try to see if I can get some answers from the compiler process by including something like g++ -E -dI or g++ -MM to it.

Very likely :frowning:

Is it possible to use the IDE with a standard C++ main file?
If not then I'd try an alternative development system, like AVR Studio.

When I get home, I'll take a look at my bare-bones serial implementation.

I think I have found the problem.

Even though I do not use <dbg/examples.h> or <utf/utf8-stream.h> in the sketch 21-pt-serial-echo.ino it appears the linker just links the object files examples.cpp.o and utf8-stream.cpp.o from the protoduino library. These 2 object files do use the HardwareSerial0.cpp class members.

Using precompiled core: C:\Users\Joham\AppData\Local\Temp\arduino\cores\arduino_avr_uno_d6c764e2bcf7e67a2dc35614f0559439\core.a
Linking everything together...
"C:\\Users\\Joham\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-gcc" -Os -g -flto -fuse-linker-plugin -Wl,--gc-sections -mmcu=atmega328p -o "C:\\Users\\Joham\\AppData\\Local\\Temp\\arduino\\sketches\\5970F7816154BA60780503E78C3AD3E9/21-pt-serial-echo.ino.elf" "C:\\Users\\Joham\\AppData\\Local\\Temp\\arduino\\sketches\\5970F7816154BA60780503E78C3AD3E9\\sketch\\21-pt-serial-echo.ino.cpp.o" "C:\\Users\\Joham\\AppData\\Local\\Temp\\arduino\\sketches\\5970F7816154BA60780503E78C3AD3E9\\libraries\\protoduino\\dbg\\examples.cpp.o" "C:\\Users\\Joham\\AppData\\Local\\Temp\\arduino\\sketches\\5970F7816154BA60780503E78C3AD3E9\\libraries\\protoduino\\sys\\ringb8.c.o" "C:\\Users\\Joham\\AppData\\Local\\Temp\\arduino\\sketches\\5970F7816154BA60780503E78C3AD3E9\\libraries\\protoduino\\sys\\serial0.c.o" "C:\\Users\\Joham\\AppData\\Local\\Temp\\arduino\\sketches\\5970F7816154BA60780503E78C3AD3E9\\libraries\\protoduino\\utf\\rune16.c.o" "C:\\Users\\Joham\\AppData\\Local\\Temp\\arduino\\sketches\\5970F7816154BA60780503E78C3AD3E9\\libraries\\protoduino\\utf\\utf8-stream.cpp.o" "C:\\Users\\Joham\\AppData\\Local\\Temp\\arduino\\sketches\\5970F7816154BA60780503E78C3AD3E9\\libraries\\protoduino\\utf\\utf8.c.o" "C:\\Users\\Joham\\AppData\\Local\\Temp\\arduino\\sketches\\5970F7816154BA60780503E78C3AD3E9\\libraries\\protoduino\\utf\\vt100.c.o" "C:\\Users\\Joham\\AppData\\Local\\Temp\\arduino\\sketches\\5970F7816154BA60780503E78C3AD3E9/..\\..\\cores\\arduino_avr_uno_d6c764e2bcf7e67a2dc35614f0559439\\core.a" "-LC:\\Users\\Joham\\AppData\\Local\\Temp\\arduino\\sketches\\5970F7816154BA60780503E78C3AD3E9" -lm

Even though my sketch isn't using it, the linker isn't smart enough to figure that out. It would probably not have occurred when the arduino-cli would have created a static precompiled library of all object files first. But that is not what is happening...

That means I have a decision to make. Do I throw out these 2 classes or should I make a conditional build that filters them out when I use serial0.c. The first looks more promising though. But then I have to change the documentation and a lot of code.... brrrr.

Just before I go and make the decision, does anyone know how I add a global define to the compiler options? For vscode I can add it to the c_cpp_properties.json file, but I'm not sure how I should go about with the Arduino IDE.

Regards,

Joham

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.