You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
396 lines
12 KiB
396 lines
12 KiB
/*
|
|
* Copyright (c) 2019, Erich Styger
|
|
* All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include "McuULN2003config.h"
|
|
#include "McuULN2003.h"
|
|
#include "McuGPIO.h"
|
|
#include "McuWait.h"
|
|
#if McuLib_CONFIG_CPU_IS_KINETIS
|
|
#include "fsl_port.h"
|
|
#endif
|
|
#if MCUULN2003_CONFIG_USE_FREERTOS_HEAP
|
|
#include "McuRTOS.h"
|
|
#endif
|
|
|
|
#if McuULN2003_CONFIG_USE_ACCELERATION
|
|
static const uint8_t default_accel_delays[] = {2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 8, 8, 10, 10, 10};
|
|
static const McuULN2003_Accel_t McuULN2003_DefaultAccelTable =
|
|
{ /* list of delay values: the larger the value, the more delays between the step sequences. */
|
|
.nofEntries = sizeof(default_accel_delays),
|
|
.delays = default_accel_delays,
|
|
};
|
|
#endif
|
|
|
|
typedef struct McuULN2003_Motor_t {
|
|
int32_t pos; /* actual stepper motor position counter */
|
|
McuULN2003_StepMode stepMode; /* full or half stepping mode */
|
|
bool inverted; /* if motor direction is inverted */
|
|
uint8_t tablePos; /* current pos in the stepper logic table */
|
|
uint32_t id; /* optional ID */
|
|
bool noGPIO; /* if no GPIO handles shall be allocated */
|
|
#if McuULN2003_CONFIG_USE_ACCELERATION
|
|
struct {
|
|
const McuULN2003_Accel_t *table;
|
|
uint8_t accelIdx; /* current index into acceleration delay table, starting from the end of the table to index zero */
|
|
uint8_t subAccelCnt; /* sub-position acceleration counter, used to count down the delay */
|
|
} accel;
|
|
#endif
|
|
void (*stepCallback)(McuULN2003_Handle_t motor, const bool w[McuULN2003_NOF_MOTOR_GPIO_PINS]);
|
|
McuGPIO_Handle_t pin[McuULN2003_NOF_MOTOR_GPIO_PINS]; /* the 4 winding of the motor */
|
|
} McuULN2003_Motor_t;
|
|
|
|
#define McuULN2003_DELAY_HALF_STEP_MODE() McuWait_WaitOSms(2)
|
|
#define McuULN2003_DELAY_FULL_STEP_MODE() McuWait_WaitOSms(4)
|
|
|
|
typedef bool McuULN2003_PinStatus[McuULN2003_NOF_MOTOR_GPIO_PINS];
|
|
|
|
static const bool disableTable[McuULN2003_NOF_MOTOR_GPIO_PINS] = {false, false, false, false};
|
|
|
|
/* half stepping mode with 8 steps
|
|
* For the wire colors and stepper table, see https://leap.tardate.com/kinetics/steppermotors/28byj48/
|
|
*/
|
|
const bool McuULN2003_stepTableHalfStepsFw[McuULN2003_NOF_STEPS_HALF_STEP_MODE][McuULN2003_NOF_MOTOR_GPIO_PINS] = {
|
|
/* blue pink yellow orange */
|
|
{true, true, false, false},
|
|
{false, true, false, false},
|
|
{false, true, true, false},
|
|
{false, false, true, false},
|
|
{false, false, true, true },
|
|
{false, false, false, true },
|
|
{true, false, false, true },
|
|
{true, false, false, false},
|
|
};
|
|
|
|
const bool McuULN2003_stepTableHalfStepsBw[McuULN2003_NOF_STEPS_HALF_STEP_MODE][McuULN2003_NOF_MOTOR_GPIO_PINS] = {
|
|
/* blue pink yellow orange */
|
|
{true, false, false, false},
|
|
{true, false, false, true },
|
|
{false, false, false, true },
|
|
{false, false, true, true },
|
|
{false, false, true, false},
|
|
{false, true, true, false},
|
|
{false, true, false, false},
|
|
{true, true, false, false},
|
|
};
|
|
|
|
/* full stepping mode with 4 steps */
|
|
const bool McuULN2003_stepTableFullStepsFw[McuULN2003_NOF_STEPS_FULL_STEP_MODE][McuULN2003_NOF_MOTOR_GPIO_PINS] = {
|
|
/* blue pink yellow orange */
|
|
/* https://leap.tardate.com/kinetics/steppermotors/28byj48/ */
|
|
{true, true, false, false},
|
|
{false, true, true, false},
|
|
{false, false, true, true},
|
|
{true, false, false, true },
|
|
};
|
|
|
|
const bool McuULN2003_stepTableFullStepsBw[McuULN2003_NOF_STEPS_FULL_STEP_MODE][McuULN2003_NOF_MOTOR_GPIO_PINS] = {
|
|
/* blue pink yellow orange */
|
|
{true, false, false, true },
|
|
{false, false, true, true },
|
|
{false, true, true, false},
|
|
{true, true, false, false},
|
|
};
|
|
|
|
/* default configuration, used for initializing the config */
|
|
static const McuULN2003_Config_t defaultConfig =
|
|
{
|
|
.stepMode = McuULN2003_STEP_MODE_HALF,
|
|
.inverted = false,
|
|
.id = 0,
|
|
.stepCallback = NULL,
|
|
.noGPIO = false,
|
|
.hw[0] = {
|
|
#if McuLib_CONFIG_NXP_SDK_USED && !McuLib_CONFIG_IS_KINETIS_KE
|
|
.gpio = NULL,
|
|
#elif McuLib_CONFIG_CPU_IS_STM32
|
|
.gpio = NULL,
|
|
#endif
|
|
#if McuLib_CONFIG_CPU_IS_KINETIS
|
|
.port = NULL,
|
|
#elif McuLib_CONFIG_CPU_IS_LPC
|
|
.port = 0,
|
|
#endif
|
|
.pin = 0,
|
|
},
|
|
.hw[1] = {
|
|
#if McuLib_CONFIG_NXP_SDK_USED && !McuLib_CONFIG_IS_KINETIS_KE
|
|
.gpio = NULL,
|
|
#elif McuLib_CONFIG_CPU_IS_STM32
|
|
.gpio = NULL,
|
|
#endif
|
|
#if McuLib_CONFIG_CPU_IS_KINETIS
|
|
.port = NULL,
|
|
#elif McuLib_CONFIG_CPU_IS_LPC
|
|
.port = 0,
|
|
#endif
|
|
.pin = 0,
|
|
},
|
|
.hw[2] = {
|
|
#if McuLib_CONFIG_NXP_SDK_USED && !McuLib_CONFIG_IS_KINETIS_KE
|
|
.gpio = NULL,
|
|
#elif McuLib_CONFIG_CPU_IS_STM32
|
|
.gpio = NULL,
|
|
#endif
|
|
#if McuLib_CONFIG_CPU_IS_KINETIS
|
|
.port = NULL,
|
|
#elif McuLib_CONFIG_CPU_IS_LPC
|
|
.port = 0,
|
|
#endif
|
|
.pin = 0,
|
|
},
|
|
.hw[3] = {
|
|
#if McuLib_CONFIG_NXP_SDK_USED && !McuLib_CONFIG_IS_KINETIS_KE
|
|
.gpio = NULL,
|
|
#elif McuLib_CONFIG_CPU_IS_STM32
|
|
.gpio = NULL,
|
|
#endif
|
|
#if McuLib_CONFIG_CPU_IS_KINETIS
|
|
.port = NULL,
|
|
#elif McuLib_CONFIG_CPU_IS_LPC
|
|
.port = 0,
|
|
#endif
|
|
.pin = 0,
|
|
}
|
|
};
|
|
|
|
void McuULN2003_GetDefaultConfig(McuULN2003_Config_t *config) {
|
|
assert(config!=NULL);
|
|
memcpy(config, &defaultConfig, sizeof(*config));
|
|
}
|
|
|
|
uint32_t McuULN2003_GetID(McuULN2003_Handle_t motor) {
|
|
return ((McuULN2003_Motor_t *)motor)->id;
|
|
}
|
|
|
|
#if McuULN2003_CONFIG_USE_ACCELERATION
|
|
void McuULN2003_SetAccelerationTable(McuULN2003_Handle_t motor, const McuULN2003_Accel_t *table) {
|
|
McuULN2003_Motor_t *handle;
|
|
|
|
handle = (McuULN2003_Motor_t*)motor;
|
|
handle->accel.table = table;
|
|
handle->accel.accelIdx = 0;
|
|
handle->accel.subAccelCnt = 0;
|
|
}
|
|
#endif
|
|
|
|
static void SetStep(McuULN2003_Handle_t motor, const bool w[McuULN2003_NOF_MOTOR_GPIO_PINS]) {
|
|
for(int i=0; i<McuULN2003_NOF_MOTOR_GPIO_PINS; i++) { /* for all pins */
|
|
McuGPIO_SetValue(((McuULN2003_Motor_t *)motor)->pin[i], w[i]); /* change GPIO pins */
|
|
}
|
|
}
|
|
|
|
McuULN2003_Handle_t McuULN2003_InitMotor(McuULN2003_Config_t *config) {
|
|
McuGPIO_Config_t gpio_config; /* config for the SDK */
|
|
McuULN2003_Motor_t *handle;
|
|
|
|
assert(config!=NULL);
|
|
#if MCUULN2003_CONFIG_USE_FREERTOS_HEAP
|
|
handle = (McuULN2003_Motor_t*)pvPortMalloc(sizeof(McuULN2003_Motor_t)); /* get a new device descriptor */
|
|
#else
|
|
handle = (McuULN2003_Motor_t*)malloc(sizeof(McuULN2003_Motor_t)); /* get a new device descriptor */
|
|
#endif
|
|
assert(handle!=NULL);
|
|
if (handle!=NULL) { /* if malloc failed, will return NULL pointer */
|
|
memset(handle, 0, sizeof(McuULN2003_Motor_t)); /* init all fields */
|
|
#if McuULN2003_CONFIG_USE_ACCELERATION
|
|
McuULN2003_SetAccelerationTable((McuULN2003_Handle_t*)handle, &McuULN2003_DefaultAccelTable);
|
|
#endif
|
|
handle->id = config->id;
|
|
handle->pos = 0;
|
|
handle->stepMode = config->stepMode;
|
|
handle->inverted = config->inverted;
|
|
handle->tablePos = 0;
|
|
handle->noGPIO = config->noGPIO;
|
|
handle->stepCallback = config->stepCallback;
|
|
if (handle->stepCallback==NULL) {
|
|
handle->stepCallback = SetStep; /* assign default GPIO callback */
|
|
}
|
|
if (!config->noGPIO) {
|
|
McuGPIO_GetDefaultConfig(&gpio_config);
|
|
for(int i=0; i<McuULN2003_NOF_MOTOR_GPIO_PINS; i++) {
|
|
gpio_config.isInput = false; /* motor pin is output only */
|
|
memcpy(&gpio_config.hw, &config->hw[i], sizeof(gpio_config.hw)); /* copy hardware info */
|
|
gpio_config.isHighOnInit = false;
|
|
handle->pin[i] = McuGPIO_InitGPIO(&gpio_config); /* create gpio handle */
|
|
}
|
|
}
|
|
}
|
|
return handle;
|
|
}
|
|
|
|
McuULN2003_Handle_t McuULN2003_DeinitMotor(McuULN2003_Handle_t motor) {
|
|
McuULN2003_Motor_t *m = (McuULN2003_Motor_t*)motor;
|
|
assert(m!=NULL);
|
|
|
|
for(int i=0; i<McuULN2003_NOF_MOTOR_GPIO_PINS; i++) {
|
|
McuGPIO_DeinitGPIO(m->pin[i]);
|
|
}
|
|
#if MCUULN2003_CONFIG_USE_FREERTOS_HEAP
|
|
vPortFree(m);
|
|
#else
|
|
free(m);
|
|
#endif
|
|
return NULL;
|
|
}
|
|
|
|
void McuULN2003_SetStepMode(McuULN2003_Handle_t motor, McuULN2003_StepMode mode) {
|
|
((McuULN2003_Motor_t*)motor)->stepMode = mode;
|
|
}
|
|
|
|
McuULN2003_StepMode McuULN2003_GetStepMode(McuULN2003_Handle_t motor) {
|
|
return ((McuULN2003_Motor_t*)motor)->stepMode;
|
|
}
|
|
|
|
void McuULN2003_PowerOff(McuULN2003_Handle_t motor) {
|
|
McuULN2003_Motor_t *m = (McuULN2003_Motor_t*)motor;
|
|
|
|
m->stepCallback(motor, disableTable);
|
|
m->tablePos = 0;
|
|
}
|
|
|
|
static void McuULN2003_TableMakeStep(McuULN2003_Handle_t motor, bool forward) {
|
|
McuULN2003_Motor_t *m = (McuULN2003_Motor_t*)motor;
|
|
const McuULN2003_PinStatus *table;
|
|
size_t maxTableIndex;
|
|
|
|
if (m->stepMode==McuULN2003_STEP_MODE_HALF) {
|
|
if ((forward && !m->inverted) || (!forward && m->inverted)) {
|
|
table = McuULN2003_stepTableHalfStepsFw;
|
|
} else {
|
|
table = McuULN2003_stepTableHalfStepsBw;
|
|
}
|
|
maxTableIndex = McuULN2003_NOF_STEPS_HALF_STEP_MODE;
|
|
} else { /* McuULN2003_STEP_MODE_FULL */
|
|
if ((forward && !m->inverted) || (!forward && m->inverted)) {
|
|
table = McuULN2003_stepTableFullStepsFw;
|
|
} else {
|
|
table = McuULN2003_stepTableFullStepsBw;
|
|
}
|
|
maxTableIndex = McuULN2003_NOF_STEPS_FULL_STEP_MODE;
|
|
}
|
|
m->stepCallback(m, table[m->tablePos]);
|
|
m->tablePos++;
|
|
if (m->tablePos>=maxTableIndex) { /* full sequence reached */
|
|
m->tablePos = 0;
|
|
if (forward) {
|
|
m->pos++;
|
|
} else {
|
|
m->pos--;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool McuULN2003_StepCallback(McuULN2003_Handle_t motor, bool forward) {
|
|
McuULN2003_Motor_t *m = (McuULN2003_Motor_t*)motor;
|
|
|
|
#if McuULN2003_CONFIG_USE_ACCELERATION
|
|
if (m->accel.accelIdx>0) { /* only do it if not during acceleration */
|
|
if (m->accel.subAccelCnt>0) { /* sub-delay still going on? */
|
|
m->accel.subAccelCnt--; /* delay */
|
|
return false; /* not reached end of delay sequence */
|
|
} else { /* subAccelCnt reached zero: get to next table index value */
|
|
m->accel.accelIdx--;
|
|
m->accel.subAccelCnt = m->accel.table->delays[m->accel.accelIdx];
|
|
}
|
|
}
|
|
#endif
|
|
if (forward) {
|
|
McuULN2003_TableMakeStep(motor, true); /* forward */
|
|
} else {
|
|
McuULN2003_TableMakeStep(motor, false); /* backward */
|
|
}
|
|
return m->tablePos==0; /* reached position */
|
|
}
|
|
|
|
#if McuULN2003_CONFIG_USE_ACCELERATION
|
|
void McuULN2003_AccelerationStart(McuULN2003_Handle_t motor) {
|
|
McuULN2003_Motor_t *m = (McuULN2003_Motor_t*)motor;
|
|
m->accel.accelIdx = m->accel.table->nofEntries-1;
|
|
m->accel.subAccelCnt = m->accel.table->delays[m->accel.table->nofEntries-1];
|
|
}
|
|
#endif
|
|
|
|
#if McuULN2003_CONFIG_USE_ACCELERATION
|
|
void McuULN2003_AccelerationEnd(McuULN2003_Handle_t motor) {
|
|
McuULN2003_Motor_t *m = (McuULN2003_Motor_t*)motor;
|
|
m->accel.accelIdx = 0;
|
|
m->accel.subAccelCnt = 0;
|
|
}
|
|
#endif
|
|
|
|
bool McuULN2003_MoveCallback(McuULN2003_Handle_t motor, int32_t targetPos) {
|
|
McuULN2003_Motor_t *m = (McuULN2003_Motor_t*)motor;
|
|
|
|
if (m->pos < targetPos) {
|
|
McuULN2003_TableMakeStep(motor, true); /* forward */
|
|
return false;
|
|
} else if (m->pos > targetPos) {
|
|
McuULN2003_TableMakeStep(motor, false); /* backward */
|
|
return false;
|
|
}
|
|
McuULN2003_PowerOff(motor);
|
|
return true; /* reached position */
|
|
}
|
|
|
|
void McuULN2003_IncStep(McuULN2003_Handle_t motor) {
|
|
McuULN2003_Motor_t *m = (McuULN2003_Motor_t*)motor;
|
|
int32_t pos = m->pos+1;
|
|
|
|
do {
|
|
McuULN2003_TableMakeStep(motor, true);
|
|
if (m->stepMode==McuULN2003_STEP_MODE_HALF) {
|
|
McuULN2003_DELAY_HALF_STEP_MODE();
|
|
} else { /* McuULN2003_STEP_MODE_FULL */
|
|
McuULN2003_DELAY_FULL_STEP_MODE();
|
|
}
|
|
} while(m->pos!=pos);
|
|
}
|
|
|
|
void McuULN2003_DecStep(McuULN2003_Handle_t motor) {
|
|
McuULN2003_Motor_t *m = (McuULN2003_Motor_t*)motor;
|
|
int32_t pos = m->pos-1;
|
|
|
|
do {
|
|
McuULN2003_TableMakeStep(motor, false);
|
|
if (m->stepMode==McuULN2003_STEP_MODE_HALF) {
|
|
McuULN2003_DELAY_HALF_STEP_MODE();
|
|
} else { /* McuULN2003_STEP_MODE_FULL */
|
|
McuULN2003_DELAY_FULL_STEP_MODE();
|
|
}
|
|
} while(m->pos!=pos);
|
|
}
|
|
|
|
void McuULN2003_SetPos(McuULN2003_Handle_t motor, int32_t pos) {
|
|
McuULN2003_Motor_t *m = (McuULN2003_Motor_t*)motor;
|
|
m->pos = pos;
|
|
}
|
|
|
|
int32_t McuULN2003_GetPos(McuULN2003_Handle_t motor) {
|
|
return ((McuULN2003_Motor_t*)motor)->pos;
|
|
}
|
|
|
|
void McuULN2003_Step(McuULN2003_Handle_t motor, int32_t steps) {
|
|
if (steps>0) {
|
|
while(steps>0) {
|
|
McuULN2003_IncStep(motor);
|
|
steps--;
|
|
}
|
|
} else {
|
|
while(steps<0) {
|
|
McuULN2003_DecStep(motor);
|
|
steps++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void McuULN2003_Deinit(void) {
|
|
/* nothing needed */
|
|
}
|
|
|
|
void McuULN2003_Init(void) {
|
|
/* nothing needed */
|
|
}
|
|
|