Skip to content

Instantly share code, notes, and snippets.

@devyte
Last active August 28, 2020 03:17
Show Gist options
  • Save devyte/ed3fa167d6a3b4296d2e074bdc865074 to your computer and use it in GitHub Desktop.
Save devyte/ed3fa167d6a3b4296d2e074bdc865074 to your computer and use it in GitHub Desktop.
Multichannel Stepper speed api based on waveform generator
#include "stepperapi.h"
#include "Arduino.h"
#include "core_esp8266_waveform.h"
static bool
stepperStartCore(int pinPulse, uint32_t analogFreq)
{
if (analogFreq == 0)
return stopWaveform(pinPulse); //for frequency = 0, stop the pulse train
if (analogFreq > 40000)
analogFreq = 40000; //clamp to 40KHz at the high end
uint32_t analogPeriod = microsecondsToClockCycles(1000000UL) / analogFreq;
constexpr uint32_t analogScale = 1023; //set up in setup(), 255 default if not set up
uint32_t high = analogPeriod / (2 * analogScale);
uint32_t low = analogPeriod - high;
pinMode(pinPulse, OUTPUT);
if ((low == 0) || (high == 0))
return false; //error
return startWaveformClockCycles(pinPulse, high, low, 0); //return whether start succeeded
}
bool
stepperStart(int pinEn, int pinPulse, uint32_t analogFreq)
{
//enable stepper
pinMode(pinEn, OUTPUT);
digitalWrite(pinEn, HIGH);
return stepperStartCore(pinPulse, analogFreq);
}
bool
stepperStop(int pinEn, int pinPulse)
{
if(!stopWaveform(pinPulse))
return false;
//Disable stepper
pinMode(pinEn, OUTPUT);
digitalWrite(pinEn, LOW);
return true;
}
bool
stepperUpdateSpeed(int pinPulse, uint32_t newAnalogFreq)
{
//update directly, no need to stop (see analogWrite() function body)
return stepperStartCore(pinPulse, newAnalogFreq);
}
#ifndef __STEPPERAPI_H__
#define __STEPPERAPI_H__
#include <cstdint>
bool
stepperStart(int pinEn, int pinPulse, uint32_t analogFreq);
bool
stepperStop(int pinEn, int pinPulse);
bool
stepperUpdateSpeed(int pinPulse, uint32_t newAnalogFreq);
#endif
#ifndef __STEPPERCLASS_H__
#define __STEPPERCLASS_H__
#include "stepperapi.h"
class Stepper
{
private:
int pinEn;
int pinPulse;
bool running;
public:
Stepper(int pinEn, int pinPulse)
: pinEn(pinEn),
pinPulse(pinPulse),
running(false)
{}
//disables the pins
~Stepper()
{
if(running)
{
stepperStop(pinEn, pinPulse);
releasePins();
}
}
//Enables the pins for OUTPUT
bool start(uint32_t speed)
{
if(stepperStart(pinEn, pinPulse, speed))
{
running = true;
return true;
}
return false;
}
//disables the stepper (En=false)
//Does not release the pins, i.e.: they remain in OUTPUT mode
bool stop()
{
if(stepperStop(pinEn, pinPulse)
{
running = false;
return true;
}
return false;
}
//speed=0 stops the pulse without doing EN=false
bool updateSpeed(uint32_t speed)
{
return stepperUpdateSpeed(pinPulse, speed);
}
//Disables the pins, i.e. they go back to INPUT mode and therefore float
void releasePins()
{
pinMode(pinEn, INPUT);
pinMode(pinPulse, INPUT);
}
bool isRunning()
{
return running;
}
};
#endif
#include "Arduino.h"
#include "stepperclass.h"
namespace
{
constexpr int pinEnS1 = 5;
constexpr int pinPulseS1 = 4;
constexpr int pinEnS2 = 0;
constexpr int pinPulseS2 = 2;
constexpr int pinEnS3 = 16;
constexpr int pinPulseS3 = 13;
constexpr int pinAlarm = 12;
constexpr int pinLinkageSensor = 14;
constexpr int pinRelay = 15;
Stepper stepper1(pinEnS1, pinPulseS1);
Stepper stepper2(pinEnS2, pinPulseS2);
Stepper stepper3(pinEnS3, pinPulseS3);
bool startFlag1 = false;
bool startFlag2 = false;
bool startFlag3 = false;
bool stopFlag1 = false;
bool stopFlag2 = false;
bool stopFlag3 = false;
bool updateFlag1 = false;
bool updateFlag2 = false;
bool updateFlag3 = false;
//The unit of these speeds is Hz, i.e.: pulses/second
uint32 speed1;
uint32 speed2;
uint32 speed3;
}
void
handleStepper(Stepper &stepper, bool &startFlag, bool &stopFlag, bool &updateFlag, uint32_t speed)
{
if(startFlag) //from ui
{
if(!stepper.start(speed))
{
//error starting
}
startFlag = false;
}
if(stopFlag) //from ui
{
if(!stepper.stop())
{
//error stopping
}
stopFlag = false;
}
if(updateFlag) //from ui
{
if(!stepper.updateSpeed(speed))
{
//error updating speed
}
updateFlag = false;
}
}
void
setup()
{
//set up wifi, webserver, etc
}
void
loop()
{
//startFlag, stopFlag, speed would be initially set from a webserver handler
//updateFlag and speed would then be set whenever a speed update is available,
//e.g.: gps gives new position => calculate speed set point in Hz (speedX = setPointVariableX / 10) => updateFlag = true
handleStepper(stepper1, startFlag1, stopFlag1, updateFlag1, speed1);
handleStepper(stepper2, startFlag2, stopFlag2, updateFlag2, speed2);
handleStepper(stepper3, startFlag3, stopFlag3, updateFlag3, speed3);
}
@devyte
Copy link
Author

devyte commented Aug 26, 2020

code is updated

@moose4621
Copy link

Latest errors.

Arduino: 1.8.12 (Linux), Board: "LOLIN(WEMOS) D1 R2 & mini, 80 MHz, Flash, Legacy (new can return nullptr), All SSL ciphers (most compatible), 4MB (FS:3MB OTA:~512KB), v2 Lower Memory, Disabled, None, Only Sketch, 921600"

/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:2:32: error: 'uint32_t' has not been declared
stepperStartCore(int pinPulse, uint32_t analogFreq)
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp: In function 'void stepperStartCore(int, int)':
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:11:3: error: 'uint32_t' was not declared in this scope
uint32_t analogPeriod = microsecondsToClockCycles(1000000UL) / analogFreq;
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:11:12: error: expected ';' before 'analogPeriod'
uint32_t analogPeriod = microsecondsToClockCycles(1000000UL) / analogFreq;
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:13:12: error: expected ';' before 'analogScale'
uint32_t analogScale = 1023; //set up in setup(), 255 default if not set up
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:15:12: error: expected ';' before 'high'
uint32_t high = (analogPeriod / 2) / analogScale;
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:16:12: error: expected ';' before 'low'
uint32_t low = analogPeriod - high;
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:17:21: error: 'OUTPUT' was not declared in this scope
pinMode(pinPulse, OUTPUT);
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:17:27: error: 'pinMode' was not declared in this scope
pinMode(pinPulse, OUTPUT);
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:18:7: error: 'low' was not declared in this scope
if (low == 0) {
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:21:7: error: 'high' was not declared in this scope
if (high == 0) {
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:24:42: error: 'high' was not declared in this scope
if (startWaveformClockCycles(pinPulse, high, low, 0)) {
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:24:48: error: 'low' was not declared in this scope
if (startWaveformClockCycles(pinPulse, high, low, 0)) {
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:24:54: error: 'startWaveformClockCycles' was not declared in this scope
if (startWaveformClockCycles(pinPulse, high, low, 0)) {
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp: At global scope:
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:30:39: error: 'uint32_t' has not been declared
stepperStart(int pinEn, int pinPulse, uint32_t analogFreq)
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp: In function 'void stepperStart(int, int, int)':
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:33:18: error: 'OUTPUT' was not declared in this scope
pinMode(pinEn, OUTPUT);
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:33:24: error: 'pinMode' was not declared in this scope
pinMode(pinEn, OUTPUT);
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:34:23: error: 'HIGH' was not declared in this scope
digitalWrite(pinEn, HIGH);
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:34:27: error: 'digitalWrite' was not declared in this scope
digitalWrite(pinEn, HIGH);
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:36:41: error: 'stepperStartPulse' was not declared in this scope
stepperStartPulse(pinPulse, analogFreq);
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp: In function 'void stepperStop(int, int)':
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:42:24: error: 'stopWaveForm' was not declared in this scope
stopWaveForm(pinPulse);
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:45:18: error: 'OUTPUT' was not declared in this scope
pinMode(pinEn, OUTPUT);
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:45:24: error: 'pinMode' was not declared in this scope
pinMode(pinEn, OUTPUT);
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:46:23: error: 'LOW' was not declared in this scope
digitalWrite(pinEn, LOW);
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:46:26: error: 'digitalWrite' was not declared in this scope
digitalWrite(pinEn, LOW);
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp: At global scope:
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:50:34: error: 'uint32_t' has not been declared
stepperUpdateSpeed(int pinPulse, uint32_t newAnalogFreq)
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp: In function 'void stepperUpdateSpeed(int, int)':
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:52:24: error: 'stopWaveForm' was not declared in this scope
stopWaveForm(pinPulse);
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:53:44: error: 'stepperStartPulse' was not declared in this scope
stepperStartPulse(pinPulse, newAnalogFreq);
^
exit status 1
Error compiling for board LOLIN(WEMOS) D1 R2 & mini.

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

@devyte
Copy link
Author

devyte commented Aug 26, 2020

updated

@moose4621
Copy link

Errors as of revision 14

Arduino: 1.8.12 (Linux), Board: "LOLIN(WEMOS) D1 R2 & mini, 80 MHz, Flash, Legacy (new can return nullptr), All SSL ciphers (most compatible), 4MB (FS:3MB OTA:~512KB), v2 Lower Memory, Disabled, None, Only Sketch, 921600"

/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp: In function 'void stepperStartCore(int, uint32_t)':
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:27:54: error: 'startWaveformClockCycles' was not declared in this scope
if (startWaveformClockCycles(pinPulse, high, low, 0)) {
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp: In function 'void stepperStart(int, int, uint32_t)':
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:39:41: error: 'stepperStartPulse' was not declared in this scope
stepperStartPulse(pinPulse, analogFreq);
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp: In function 'void stepperStop(int, int)':
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:45:24: error: 'stopWaveForm' was not declared in this scope
stopWaveForm(pinPulse);
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp: In function 'void stepperUpdateSpeed(int, uint32_t)':
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:55:24: error: 'stopWaveForm' was not declared in this scope
stopWaveForm(pinPulse);
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:56:44: error: 'stepperStartPulse' was not declared in this scope
stepperStartPulse(pinPulse, newAnalogFreq);
^
exit status 1
Error compiling for board LOLIN(WEMOS) D1 R2 & mini.

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

@devyte
Copy link
Author

devyte commented Aug 27, 2020

updated

@moose4621
Copy link

Added:
stepperapi.ccp line 1. removed space.
stepperapi.h line 7. added ;

then got these errors.
Arduino: 1.8.12 (Linux), Board: "LOLIN(WEMOS) D1 R2 & mini, 80 MHz, Flash, Legacy (new can return nullptr), All SSL ciphers (most compatible), 4MB (FS:3MB OTA:~512KB), v2 Lower Memory, Disabled, None, Only Sketch, 921600"

/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp: In function 'void stepperStop(int, int)':
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:46:24: error: 'stopWaveForm' was not declared in this scope
stopWaveForm(pinPulse);
^
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp: In function 'void stepperUpdateSpeed(int, uint32_t)':
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:56:24: error: 'stopWaveForm' was not declared in this scope
stopWaveForm(pinPulse);
^
exit status 1
Error compiling for board LOLIN(WEMOS) D1 R2 & mini.

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

@devyte
Copy link
Author

devyte commented Aug 27, 2020

fixed the two lines and the F

@moose4621
Copy link

Revision 18 compiles. Yay.

@devyte
Copy link
Author

devyte commented Aug 27, 2020

Updated:

  • to stop a stepper from moving, call stepper.updateSpeed(0)
  • to stop using a stepper, call stepper.stop(), this sets pinEn LOW
  • calling stepper.updateSpeed() should now have the pulse train change smoothly on the next low->high transition

@moose4621
Copy link

Found a coupkle of typo's but this one is out of my league.

Arduino: 1.8.12 (Linux), Board: "LOLIN(WEMOS) D1 R2 & mini, 80 MHz, Flash, Legacy (new can return nullptr), All SSL ciphers (most compatible), 4MB (FS:3MB OTA:~512KB), v2 Lower Memory, Disabled, None, Only Sketch, 921600"

/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp: In function 'bool stepperStartCore(int, uint32_t)':
/home/chris/Arduino/libraries/stepperapi/stepperapi.cpp:10:33: error: 'stopWaveForm' was not declared in this scope
return stopWaveForm(pinPulse); //for frequency = 0, stop the pulse train
^
exit status 1
Error compiling for board LOLIN(WEMOS) D1 R2 & mini.

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

@devyte
Copy link
Author

devyte commented Aug 27, 2020

also a typo: F->f
what are the others?

@moose4621
Copy link

line 43 in .ino needs another )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment