cancel
Showing results for 
Search instead for 
Did you mean: 

"undefined reference to custom function"

ESpra.1
Senior

I am unsure of why this function keeps triggering the "undefined reference to function" error, especially since it seems to be able to find it perfectly well when I deliberately leave out arguments.

The function in question is shown below:

dc_init(DC1, DC_IN_1_Pin, DC_IN_2_Pin, GPIOA, GPIOC);

Additionally, here are the relevant pieces from the .h and .cpp files

".h"

struct DC_Driver
{
	uint16_t  pos_pin;
	uint16_t  neg_pin;
	GPIO_TypeDef *pos_port;
	GPIO_TypeDef *neg_port;
}dc_driver;
 
void dc_init(struct DC_Driver driver, uint16_t Pos_Pin, uint16_t Neg_Pin, GPIO_TypeDef *Pos_Port, GPIO_TypeDef *Neg_Port);

".cpp"

void dc_init(struct DC_Driver driver, uint16_t Pos_Pin, uint16_t Neg_Pin, GPIO_TypeDef *Pos_Port, GPIO_TypeDef *Neg_Port) {
	driver.pos_pin = Pos_Pin;
	driver.neg_pin = Neg_Pin;
	driver.pos_port = Pos_Port;
	driver.neg_port = Neg_Port;
}

The dc_init function is meant to save the GPIO information for a motor driver, with a similar function stepper motors. The device is meant to control one DC motor and two stepper motors.

I'm sure it's probably something simple I'm missing, but I can't find it. I'll try to provide more information if needed.

8 REPLIES 8
gbm
Lead III

My guess: it's a C++ function and you are trying to call it from C module. Define the function in a .C file.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice

I tried that. Everything broke rather spectacularly, and I tried again after I found a possible error. The end result is practically everything in the HAL_Driver folder hitting me with a big red X. Also, all types (uint8_t, uint16_t, unsigned long, etc) are now considered undefined.

I'll keep experimenting with getting the code into a normal .c file and see what happens

Ever seen a break similar to this one before? 0693W00000StzkWQAR.pngIt happened when I moved the functions into a new .h and .c file, and I haven't even included the new .h file in my main.c yet. I'm still rather new to CubeIDE, if that wasn't obvious.

edit: it occurs to me that I should probably just include the whole of the two files. I'd also like to preface them with the fact that they're are mistakes/things guaranteed to make more experienced coders twitch because I was in the middle of making other corrections before "undefined reference" problem showed up, and before everything related to HAL broke.

 This is the .c file

#include "TR_L293D_V2.h"
#include "stm32l5xx_hal_gpio.h"
#include "stdio.h"
#include "main.h"
 
void testFunction()
{
	char testBuf[] = "";
	sprintf(testBuf, "Hello World!");
}
 
void dc_init(struct DC_Driver driver, uint16_t Pos_Pin, uint16_t Neg_Pin, GPIO_TypeDef *Pos_Port, GPIO_TypeDef *Neg_Port) {
	driver.pos_pin = Pos_Pin;
	driver.neg_pin = Neg_Pin;
	driver.pos_port = Pos_Port;
	driver.neg_port = Neg_Port;
}
 
void dc_EncoderInit(struct DC_Encoder encoder, uint16_t pin1, uint16_t pin2, GPIO_TypeDef *port1, GPIO_TypeDef *port2)
{
	encoder.HAL_A = pin1;
	encoder.HAL_B = pin2;
 
	encoder.Port_A = port1;
	encoder.Port_B = port2;
}
 
void L293D_DC_stop(struct DC_Driver driver) {
	HAL_GPIO_WritePin(driver.pos_port, driver.pos_pin, GPIO_PIN_RESET);
	HAL_GPIO_WritePin(driver.neg_port, driver.neg_pin, GPIO_PIN_RESET);
}
 
void L293D_DC_clockwise(struct DC_Driver driver) {
	HAL_GPIO_WritePin(driver.pos_port, driver.pos_pin, GPIO_PIN_SET);
	HAL_GPIO_WritePin(driver.neg_port, driver.neg_pin, GPIO_PIN_RESET);
}
 
void L293D_DC_counterClockwise(struct DC_Driver driver) {
	HAL_GPIO_WritePin(driver.pos_port, driver.pos_pin, GPIO_PIN_RESET);
	HAL_GPIO_WritePin(driver.neg_port, driver.neg_pin, GPIO_PIN_SET);
}
 
void stepper_init(struct Stepper_Driver driver, uint16_t pin1, uint16_t pin2, uint16_t pin3,
		uint16_t pin4, GPIO_TypeDef *port1, GPIO_TypeDef *port2, GPIO_TypeDef *port3, GPIO_TypeDef *port4) {
	driver.c1 = pin1;
	driver.c2 = pin2;
	driver.c3 = pin3;
	driver.c4 = pin4;
	driver.p1 = port1;
	driver.p2 = port2;
	driver.p3 = port3;
	driver.p4 = port4;
}
 
void L293D_stepperSetSpeed(long speed) {
	step_delay = 60L * 1000L * 1000L / number_of_steps / speed;
}
 
void L293D_step(int steps_to_move) {
	int steps_left = abs(steps_to_move);
	if (steps_to_move > 0) {
		direction = 1;
	}
	if (steps_to_move < 0) {
		direction = 0;
	}
	while (steps_left > 0) {
		unsigned long now = HAL_GetTick();
		if (now - last_step_time >= step_delay) {
			last_step_time = now;
 
			if (direction == 1) {
				step_number++;
				if (step_number == number_of_steps) {
					step_number = 0;
				}
			} else {
				if (step_number == 0) {
					step_number = number_of_steps;
					step_number--;
				}
			}
			steps_left--;
			stepMotor(step_number % 4);
		}
	}
}
/*
void L293D_stepMotor(int This_Step) {
	switch (This_Step) {
	case 0:	// 1010
		HAL_GPIO_WritePin(port_c1, c1, GPIO_PIN_SET);
		HAL_GPIO_WritePin(port_c2, c2, GPIO_PIN_RESET);
		HAL_GPIO_WritePin(port_c3, c3, GPIO_PIN_SET);
		HAL_GPIO_WritePin(port_c4, c4, GPIO_PIN_RESET);
		break;
	case 1:	// 0110
		HAL_GPIO_WritePin(port_c1, c1, GPIO_PIN_RESET);
		HAL_GPIO_WritePin(port_c2, c2, GPIO_PIN_SET);
		HAL_GPIO_WritePin(port_c3, c3, GPIO_PIN_SET);
		HAL_GPIO_WritePin(port_c4, c4, GPIO_PIN_RESET);
		break;
	case 2:	//0101
		HAL_GPIO_WritePin(port_c1, c1, GPIO_PIN_RESET);
		HAL_GPIO_WritePin(port_c2, c2, GPIO_PIN_SET);
		HAL_GPIO_WritePin(port_c3, c3, GPIO_PIN_RESET);
		HAL_GPIO_WritePin(port_c4, c4, GPIO_PIN_SET);
		break;
	case 3:	//1001
		HAL_GPIO_WritePin(port_c1, c1, GPIO_PIN_SET);
		HAL_GPIO_WritePin(port_c2, c2, GPIO_PIN_RESET);
		HAL_GPIO_WritePin(port_c3, c3, GPIO_PIN_RESET);
		HAL_GPIO_WritePin(port_c4, c4, GPIO_PIN_SET);
		break;
	}
}
*/

 this is the .h file

#ifndef INC_TR_L293D_V2_H_
#define INC_TR_L293D_V2_H_
 
typedef struct DC_Driver
{
	uint16_t  pos_pin;
	uint16_t  neg_pin;
	GPIO_TypeDef *pos_port;
	GPIO_TypeDef *neg_port;
}dc_driver;
 
struct Stepper_Driver
{
	uint16_t c1;
	uint16_t c2;
	uint16_t c3;
	uint16_t c4;
 
	GPIO_TypeDef *p1;
	GPIO_TypeDef *p2;
	GPIO_TypeDef *p3;
	GPIO_TypeDef *p4;
};
 
typedef struct DC_Encoder{
	uint16_t HAL_A;
	uint16_t HAL_B;
 
	GPIO_TypeDef Port_A;
	GPIO_TypeDef Port_B;
}dc_encoder;
 
void testFunction();
 
void dc_init(struct DC_Driver driver, uint16_t Pos_Pin, uint16_t Neg_Pin, GPIO_TypeDef *Pos_Port, GPIO_TypeDef *Neg_Port);
void dc_stop();
void dc_clockwise();
void dc_counterClockwise();
 
void stepper_init(struct Stepper_Driver driver, uint16_t pin1, uint16_t pin2, uint16_t pin3,
		uint16_t pin4, GPIO_TypeDef *port1, GPIO_TypeDef *port2, GPIO_TypeDef *port3, GPIO_TypeDef *port4);
void Stepper(uint8_t number_of_steps, int motor_pin_1, int motor_pin_2, int motor_pin_3, int motor_pin_4);
void setSpeed(long speed);
 
 
uint8_t direction;
unsigned long step_delay;
uint8_t number_of_steps;
uint8_t step_number;
unsigned long last_step_time;
 
void stepMotor(int this_step);
 
#endif /* INC_TR_L293D_V2_H_ */

Okay, I found my silly error. Or at least, I think I did.

I reordered my includes in my .c file to be:

#include "stdio.h"
#include "main.h"
#include "stm32l5xx_hal_gpio.h"
#include "TR_L293D_V2.h"

That's stopped all the HAL_Driver errors at least.

And, after a bit of testing, it's compiling the included code without issue! Many thanks!

Piranha
Chief II

You are passing a structure in a function parameter, which is a bad practice. The call makes a local copy of the structure and the function modifies the local copy. The the original structure will be left intact. To do what is typically necessary and recommended, look there:

https://stackoverflow.com/questions/10370047/passing-struct-to-function

Pass structures (objects) as a POINTER, especially as a means of keeping everything the function might want to access together, and reducing stacked/register parameters, and copying.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Would that apply to all the functions, or just the initializers? Most of the functions just read the contents of the structs to know what GPIO ports and pins to write to

Passing just a pointer to the structure is more efficient than making a copy of the whole structure. Therefore this principle applies to 99,9% of the cases.