2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* @file stepper.cpp
|
|
|
|
*
|
|
|
|
* http://rusefi.com/wiki/index.php?title=Hardware:Stepper_motor
|
|
|
|
*
|
|
|
|
* @date Dec 24, 2014
|
2018-01-20 17:55:31 -08:00
|
|
|
* @author Andrey Belomutskiy, (c) 2012-2018
|
2015-07-10 06:01:56 -07:00
|
|
|
*/
|
|
|
|
|
2019-01-03 20:51:29 -08:00
|
|
|
#include "engine.h"
|
|
|
|
|
|
|
|
// todo: EFI_STEPPER macro
|
|
|
|
#if EFI_PROD_CODE || EFI_SIMULATOR
|
2015-07-10 06:01:56 -07:00
|
|
|
#include "stepper.h"
|
|
|
|
#include "pin_repository.h"
|
2017-08-07 04:28:21 -07:00
|
|
|
#include "tps.h"
|
|
|
|
#include "engine_controller.h"
|
|
|
|
#include "adc_inputs.h"
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2017-06-12 15:31:55 -07:00
|
|
|
EXTERN_ENGINE;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2017-08-07 04:28:21 -07:00
|
|
|
static Logging *logger;
|
|
|
|
|
|
|
|
static void saveStepperPos(int pos) {
|
|
|
|
// use backup-power RTC registers to store the data
|
2018-11-02 10:18:47 -07:00
|
|
|
#if EFI_PROD_CODE || defined(__DOXYGEN__)
|
2017-12-22 05:49:03 -08:00
|
|
|
backupRamSave(BACKUP_STEPPER_POS, pos + 1);
|
2018-11-02 10:18:47 -07:00
|
|
|
#endif
|
2017-08-07 04:28:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static int loadStepperPos() {
|
2018-11-02 10:18:47 -07:00
|
|
|
#if EFI_PROD_CODE || defined(__DOXYGEN__)
|
2017-12-22 05:49:03 -08:00
|
|
|
return (int)backupRamLoad(BACKUP_STEPPER_POS) - 1;
|
2018-11-02 10:18:47 -07:00
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
2017-08-07 04:28:21 -07:00
|
|
|
}
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
static msg_t stThread(StepperMotor *motor) {
|
|
|
|
chRegSetThreadName("stepper");
|
|
|
|
|
2017-08-07 04:28:21 -07:00
|
|
|
// try to get saved stepper position (-1 for no data)
|
|
|
|
motor->currentPosition = loadStepperPos();
|
|
|
|
|
2019-01-31 08:57:15 -08:00
|
|
|
#if HAL_USE_ADC || defined(__DOXYGEN__)
|
2017-08-07 04:28:21 -07:00
|
|
|
// first wait until at least 1 slowADC sampling is complete
|
|
|
|
waitForSlowAdc();
|
2018-11-01 12:57:50 -07:00
|
|
|
#endif
|
2019-03-30 14:41:46 -07:00
|
|
|
#if EFI_SHAFT_POSITION_INPUT || defined(__DOXYGEN__)
|
|
|
|
bool isRunning = engine->rpmCalculator.isRunning(PASS_ENGINE_PARAMETER_SIGNATURE);
|
|
|
|
#else
|
|
|
|
bool isRunning = false;
|
|
|
|
#endif /* EFI_SHAFT_POSITION_INPUT */
|
2017-08-07 04:28:21 -07:00
|
|
|
// now check if stepper motor re-initialization is requested - if the throttle pedal is pressed at startup
|
2019-03-30 14:41:46 -07:00
|
|
|
bool forceStepperParking = !isRunning && getTPS(PASS_ENGINE_PARAMETER_SIGNATURE) > STEPPER_PARKING_TPS;
|
2019-01-09 19:16:30 -08:00
|
|
|
if (CONFIGB(stepperForceParkingEveryRestart))
|
2018-01-29 15:27:39 -08:00
|
|
|
forceStepperParking = true;
|
2018-01-23 09:05:14 -08:00
|
|
|
scheduleMsg(logger, "Stepper: savedStepperPos=%d forceStepperParking=%d (tps=%.2f)", motor->currentPosition, (forceStepperParking ? 1 : 0), getTPS(PASS_ENGINE_PARAMETER_SIGNATURE));
|
2017-08-07 04:28:21 -07:00
|
|
|
|
|
|
|
if (motor->currentPosition < 0 || forceStepperParking) {
|
|
|
|
// reset saved value
|
|
|
|
saveStepperPos(-1);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* let's park the motor in a known position to begin with
|
|
|
|
*
|
|
|
|
* I believe it's safer to retract the valve for parking - at least on a bench I've seen valves
|
|
|
|
* disassembling themselves while pushing too far out.
|
2018-01-28 11:44:01 -08:00
|
|
|
*
|
|
|
|
* Add extra steps to compensate step skipping by some old motors.
|
2017-08-07 04:28:21 -07:00
|
|
|
*/
|
2019-01-09 19:16:30 -08:00
|
|
|
int numParkingSteps = (int)efiRound((1.0f + (float)CONFIGB(stepperParkingExtraSteps) / PERCENT_MULT) * motor->totalSteps, 1.0f);
|
2018-01-28 11:44:01 -08:00
|
|
|
for (int i = 0; i < numParkingSteps; i++) {
|
2017-08-07 04:28:21 -07:00
|
|
|
motor->pulse();
|
|
|
|
}
|
|
|
|
|
|
|
|
// set & save zero stepper position after the parking completion
|
|
|
|
motor->currentPosition = 0;
|
|
|
|
saveStepperPos(motor->currentPosition);
|
2018-01-28 11:44:01 -08:00
|
|
|
} else {
|
|
|
|
// The initial target position should correspond to the saved stepper position.
|
|
|
|
// Idle thread starts later and sets a new target position.
|
|
|
|
motor->setTargetPosition(motor->currentPosition);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
int targetPosition = motor->getTargetPosition();
|
|
|
|
int currentPosition = motor->currentPosition;
|
|
|
|
|
|
|
|
if (targetPosition == currentPosition) {
|
2018-01-21 09:19:36 -08:00
|
|
|
chThdSleepMilliseconds(motor->reactionTime);
|
2015-07-10 06:01:56 -07:00
|
|
|
continue;
|
|
|
|
}
|
2016-01-11 16:02:19 -08:00
|
|
|
bool isIncrementing = targetPosition > currentPosition;
|
2018-01-28 11:44:01 -08:00
|
|
|
motor->setDirection(isIncrementing);
|
2015-07-10 06:01:56 -07:00
|
|
|
if (isIncrementing) {
|
|
|
|
motor->currentPosition++;
|
|
|
|
} else {
|
|
|
|
motor->currentPosition--;
|
|
|
|
}
|
|
|
|
motor->pulse();
|
2017-08-07 04:28:21 -07:00
|
|
|
// save position to backup RTC register
|
2018-11-02 10:18:47 -07:00
|
|
|
#if EFI_PROD_CODE || defined(__DOXYGEN__)
|
2017-08-07 04:28:21 -07:00
|
|
|
saveStepperPos(motor->currentPosition);
|
2018-11-02 10:18:47 -07:00
|
|
|
#endif
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// let's part the motor in a known position to begin with
|
|
|
|
// for (int i = 0; i < ST_COUNT / 2; i++) {
|
|
|
|
// motor->pulse();
|
|
|
|
// }
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
StepperMotor::StepperMotor() {
|
|
|
|
currentPosition = 0;
|
|
|
|
targetPosition = 0;
|
|
|
|
enablePort = NULL;
|
|
|
|
enablePin = 0;
|
|
|
|
stepPort = NULL;
|
|
|
|
stepPin = 0;
|
|
|
|
reactionTime = 0;
|
|
|
|
totalSteps = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int StepperMotor::getTargetPosition() {
|
|
|
|
return targetPosition;
|
|
|
|
}
|
|
|
|
|
|
|
|
void StepperMotor::setTargetPosition(int targetPosition) {
|
|
|
|
this->targetPosition = targetPosition;
|
|
|
|
}
|
|
|
|
|
2018-01-28 11:44:01 -08:00
|
|
|
void StepperMotor::setDirection(bool isIncrementing) {
|
|
|
|
if (isIncrementing != this->currentDirection) {
|
|
|
|
// compensate stepper motor inertia
|
|
|
|
chThdSleepMilliseconds(reactionTime);
|
|
|
|
this->currentDirection = isIncrementing;
|
|
|
|
}
|
|
|
|
|
|
|
|
directionPin.setValue(isIncrementing);
|
|
|
|
}
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
void StepperMotor::pulse() {
|
|
|
|
palWritePad(enablePort, enablePin, false); // ebable stepper
|
|
|
|
|
|
|
|
palWritePad(stepPort, stepPin, true);
|
2018-01-21 09:19:36 -08:00
|
|
|
chThdSleepMilliseconds(reactionTime);
|
2015-07-10 06:01:56 -07:00
|
|
|
palWritePad(stepPort, stepPin, false);
|
2018-01-21 09:19:36 -08:00
|
|
|
chThdSleepMilliseconds(reactionTime);
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
palWritePad(enablePort, enablePin, true); // disable stepper
|
|
|
|
}
|
|
|
|
|
2017-06-13 06:28:05 -07:00
|
|
|
void StepperMotor::initialize(brain_pin_e stepPin, brain_pin_e directionPin, pin_output_mode_e directionPinMode,
|
2019-03-28 23:44:52 -07:00
|
|
|
float reactionTime, int totalSteps,
|
|
|
|
brain_pin_e enablePin, pin_output_mode_e enablePinMode, Logging *sharedLogger) {
|
2015-07-10 06:01:56 -07:00
|
|
|
this->reactionTime = maxF(1, reactionTime);
|
|
|
|
this->totalSteps = maxI(3, totalSteps);
|
2017-08-07 04:28:21 -07:00
|
|
|
|
|
|
|
logger = sharedLogger;
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
if (stepPin == GPIO_UNASSIGNED || directionPin == GPIO_UNASSIGNED) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:57:50 -07:00
|
|
|
#if EFI_PROD_CODE || defined(__DOXYGEN__)
|
2017-07-28 11:27:37 -07:00
|
|
|
stepPort = getHwPort("step", stepPin);
|
|
|
|
this->stepPin = getHwPin("step", stepPin);
|
2018-11-01 12:57:50 -07:00
|
|
|
#endif /* EFI_PROD_CODE */
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2017-06-13 06:28:05 -07:00
|
|
|
this->directionPinMode = directionPinMode;
|
|
|
|
this->directionPin.initPin("stepper dir", directionPin, &this->directionPinMode);
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2018-11-01 12:57:50 -07:00
|
|
|
#if EFI_PROD_CODE || defined(__DOXYGEN__)
|
2017-07-28 11:27:37 -07:00
|
|
|
enablePort = getHwPort("enable", enablePin);
|
|
|
|
this->enablePin = getHwPin("enable", enablePin);
|
2018-11-01 12:57:50 -07:00
|
|
|
#endif /* EFI_PROD_CODE */
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2017-05-15 05:40:54 -07:00
|
|
|
efiSetPadMode("stepper step", stepPin, PAL_MODE_OUTPUT_PUSHPULL);
|
2019-03-28 23:44:52 -07:00
|
|
|
// todo: start using enablePinMode parameter here #718
|
2017-05-15 05:40:54 -07:00
|
|
|
efiSetPadMode("stepper enable", enablePin, PAL_MODE_OUTPUT_PUSHPULL);
|
2015-07-10 06:01:56 -07:00
|
|
|
palWritePad(this->enablePort, enablePin, true); // disable stepper
|
|
|
|
|
2018-01-22 14:48:12 -08:00
|
|
|
// All pins must be 0 for correct hardware startup (e.g. stepper auto-disabling circuit etc.).
|
|
|
|
palWritePad(this->stepPort, this->stepPin, false);
|
|
|
|
this->directionPin.setValue(false);
|
2018-01-28 11:44:01 -08:00
|
|
|
this->currentDirection = false;
|
2018-01-22 14:48:12 -08:00
|
|
|
|
2018-12-27 06:40:40 -08:00
|
|
|
chThdCreateStatic(stThreadStack, sizeof(stThreadStack), NORMALPRIO, (tfunc_t)(void*) stThread, this);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2019-01-03 20:51:29 -08:00
|
|
|
#endif
|