Hi everybody,
I have searched for code that can create high-pulses at high (=100 kHz) and very constant frequency to drive a stepper-motor with STEP/DIR-inputs.
I have found this demo-code who does start the timer and the timer runs infinetly.
// ESP32-Democode for a periodic TimerInterrupt
volatile int interruptCounter;
int totalInterruptCounter;
hw_timer_t * timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
void IRAM_ATTR onTimer() {
portENTER_CRITICAL_ISR(&timerMux);
interruptCounter++;
portEXIT_CRITICAL_ISR(&timerMux);
}
void setup() {
Serial.begin(115200);
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &onTimer, true);
timerAlarmWrite(timer, 1000000, true);
timerAlarmEnable(timer);
}
void loop() {
if (interruptCounter > 0) {
portENTER_CRITICAL(&timerMux);
interruptCounter--;
portEXIT_CRITICAL(&timerMux);
totalInterruptCounter++;
Serial.print("An interrupt as occurred. Total number: ");
Serial.println(totalInterruptCounter);
}
}
Me target is to have code that does this high-frequency high-pulses but can be stopped on one-step-accuracy
This means I setup a command "run stepper-motor for 200.001 steps" and the code is outputting exactly 200.001 steps and then stops the signal-train of high-pulses.
I guess at high frequencies like 200 kHz stopping the timer by software through if-conditions will take too much time to be one-step-accurate. So my basic idea is to use a second hardware-counter which is setup to the number of steps (200.001) and counts down each time the timer-interrupt occurs. If this second hardware-counter reaches zero this second hardware-counter immediately stops the timer-driven interrupt or the output-pin.
Can two hardware-timers of the ESP32 be configured in that way?
Do you have another idea how this functionality of a "set-and-forget"-rock-solid-constant-timing-step-accurate"-pulse-train-generator can be coded?
best regards Stefan
OK so I just tested the maximum possible frequency when using the code above and add step-output limitation
50 kHz is possible
here is a demo-code that demonstrates the set-and-forget step-output
You setup variable StepCounter to the amount of steps the stepper-motor should run
then set flag CreateStepSignal = true
then the exact number of steps is created by interrupt completely independent of what the main-code does
// ESP32-Democode for a periodic TimerInterrupt
// used for set-and-forget steppermotor-output
//nbt nonblockingtimer
boolean TimePeriodIsOver (unsigned long &expireTime, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - expireTime >= TimePeriod )
{
expireTime = currentMillis; // set new expireTime
return true; // more time than TimePeriod) has elapsed since last time if-condition was true
}
else return false; // not expired
}
unsigned long BlinkTimer = 0;
const int OnBoardLED = 2;
unsigned long TestTimer = 0;
volatile int HighCounter = 0;
volatile int StepCounter = 0;
volatile boolean CreateStepSignal = false;
volatile boolean PinHIGH = false;
unsigned long StepFreqHz = 50000;
unsigned long AlarmCount = 20000000 / StepFreqHz;
const int signalPIN = 4;
hw_timer_t * timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
void IRAM_ATTR onTimer() {
portENTER_CRITICAL_ISR(&timerMux);
if (CreateStepSignal)
{
if (StepCounter > 0)
{
if (PinHIGH)
{
digitalWrite(signalPIN,HIGH);
PinHIGH = false;
}
else
{
digitalWrite(signalPIN,LOW);
PinHIGH = true;
StepCounter--;
}
}
}
else // StepCounter was counted down to 0
{CreateStepSignal = false;}
portEXIT_CRITICAL_ISR(&timerMux);
}
void setup() {
Serial.begin(115200);
pinMode(OnBoardLED, OUTPUT);
pinMode(signalPIN, OUTPUT);
digitalWrite(signalPIN,LOW);
timer = timerBegin(0, 1, true);
timerAttachInterrupt(timer, &onTimer, true);
timerAlarmWrite(timer, AlarmCount, true);
//timerAlarmEnable(timer);
}
void loop() {
if ( TimePeriodIsOver(BlinkTimer,500) ) {
digitalWrite (OnBoardLED, !digitalRead(OnBoardLED) ); // Blink OnBoard-LED
Serial.print(StepFreqHz);
Serial.print(" ");
Serial.print(AlarmCount);
Serial.print(" ");
Serial.println(StepCounter);
}
if ( TimePeriodIsOver(TestTimer,8000) ) {
Serial.println("testing set and forget step-output");
if (StepCounter <= 0) {
if (StepFreqHz == 50000) { StepFreqHz = 25000; } else { StepFreqHz = 50000; }
// ESP32-CPU-freq is 80 MHz
// 4x calling the ISR creates one LOW/HIGH-pulse = 20 MHz
AlarmCount = 20000000 / StepFreqHz;
timerAlarmDisable(timer);
timerAlarmWrite(timer, AlarmCount, true);
StepCounter = 100000;
CreateStepSignal = true;
timerAlarmEnable(timer);
}
}
}
best regards Stefan