[esp32] How to disable, reset and again enable timer
Hardware Timer ESP32 Dev Module
How to delete and restart hw timer (for interrupts) on demand for esp32 arduino (stepper motor controller application) - Stack Overflow
ESP32 Timer Interrupt
Videos
The word 'restart' had me thinking that it would just immediately start the timer again, but it turns out that is not the case. If the reload was set false previously, the timer has to be set again before it will actually execute - which works perfectly for my use case. Below is my new code (figured I would include the wifi and mqtt stuff to help anyone else as well):
#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include "VCDevices.h"
hw_timer_t * motorTimer = NULL;
Motor linMotor2 = Motor(pulsePin, directionPin);
int d = 0;
bool nextRun = false;
const char* ssid = "SSID";
const char* password = "PASSWORD_HERE";
const char* mqtt_server = "MQTT_SERVER_HERE";
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char topArr[50];
char msgArr[100];
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
//Timer ISR
void IRAM_ATTR motorInterrupt(void)
{
portENTER_CRITICAL(&timerMux);
noInterrupts();
//check if the motor is in motion still
if (!linMotor2.getMotorStatus())
{
d = linMotor2.Update();
//give timer different delay, dependent on its current speed
timerAlarmWrite(motorTimer, d, true);
timerAlarmEnable(motorTimer);
}
//kill the timer and interrupt if not
else
{
nextRun = true;
//set the 'reload' boolean to false, to get it to only trigger one more time
timerAlarmWrite(motorTimer, 10, false);
// Serial.println("POSITION REACHED!");
}
interrupts();
portEXIT_CRITICAL(&timerMux);
}
void reconnect()
{
// Loop until we're reconnected
while (!client.connected())
{
Serial.print("Attempting MQTT connection...");
Serial.println(mqtt_server);
// Attempt to connect
if (client.connect("ESP8266Client"))
{
client.subscribe(motorControlTopic);
Serial.println("connected");
}
else
{
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setup_wifi()
{
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void callback(char* topic, byte* message, unsigned int length)
{
Serial.print("Message arrived on topic: ");
Serial.print(topic);
Serial.print(". Message: ");
String messageTemp;
String response;
for (int i = 0; i < length; i++) {
Serial.print((char)message[i]);
messageTemp += (char)message[i];
}
Serial.println();
if (String(topic) == String(motorControlTopic))
{
if (messageTemp.toInt() > 0)
{
//check if motor is available to run
if (linMotor2.getMotorStatus())
{
linMotor2.MoveTo(messageTemp.toInt());
//set the motor timer and enable it
timerAlarmWrite(motorTimer, 1, true);
timerAlarmEnable(motorTimer);
response = "moving to " + String(messageTemp.toInt()) + " mm position";
}
else
{
response = "motor is busy - wait for movement to end!";
}
Serial.println(response);
}
}
}
void setup()
{
//Start serial connection
Serial.begin(115200);
//Setup wifi and mqtt stuff
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
//Fix up motor settings
pinMode(pulsePin, OUTPUT);
linMotor2.SetSpeed(200);
linMotor2.SetAcceleration(10);
//Initialize timer here for later use!
motorTimer = timerBegin(1, 80, true);
timerAttachInterrupt(motorTimer, &motorInterrupt, true);
Serial.println("TIMER SET!!");
digitalWrite(pulsePin, LOW);
}
void loop()
{
if (!client.connected()) reconnect();
client.loop();
portENTER_CRITICAL(&timerMux);
vTaskDelay(500);
count = linMotor2.GetPosition();
Serial.println("POSITION: " + String(count));
if (nextRun)
{
noInterrupts();
timerRestart(motorTimer);
Serial.println("*********TIMER RESTARTED!******");
nextRun = false;
interrupts();
}
portEXIT_CRITICAL(&timerMux);
}
I found this question to be very similar to an issue I am experiencing, also in a stepper application I need to set a pin HIGH fo the stepper to run and then, after 2ms, need to set the pin back to LOW. To do that I am firing a second timer form inside the ISR of the first timer, but no matter what I try/set, the second timer always fires 23us later. To illustrate that I made the below barebone example so one can see that the interval between to two ISR is always 22/23us no matter what. This routine/strategy is part of the very popular TeensyStep library (ESP32 Fork) and the very short pulse length is not really appreciated by the large DRIVERS. What am I doing wrong?
hw_timer_t *timerA = NULL;
hw_timer_t *timerB = NULL;
void IRAM_ATTR onTimerA()
{
digitalWrite(13, 1);
Serial.print("HI ");
Serial.println(micros());
timerAlarmEnable(timerB);
}
void IRAM_ATTR onTimerB()
{
digitalWrite(13, 0);
Serial.print("LO ");
Serial.println(micros());
}
void setup()
{
Serial.begin(115200);
while (!Serial);
timerA = timerBegin(0, 80, true);
timerAttachInterrupt(timerA, &onTimerA, true);
timerAlarmWrite(timerA, 1000000, true);
timerB = timerBegin(1, 80, true);
timerAttachInterrupt(timerB, &onTimerB, true);
timerAlarmWrite(timerB, 200000, false);
timerAlarmEnable(timerA);
}
void loop(){}
I want a delay to be triggered every time a DS3231 RTC interrupts. The RTC interrupt happens every 30 minutes which will turn on a motor. I want the motor on for 5 minutes. I need to figure out how to use a ESP32 timer to start when it sees the RTC interrupt and send its own interrupt trigger after 5 minutes is up so the code knows when to turn the motor off again. The RTC interrupts works great but I'm not understanding the timer operation for the 5 minute delay.
The code I enclosed is a failed test that used a switch as the trigger and a LED that lights for 100 seconds. Why does this code flash the led every 200ms without even triggering with the input switch on i/o 35? What needs to to done to allow the above described functionality?
#include <Arduino.h>
#define LED_PIN 38 // Pin connected to the LED
#define INPUT_PIN 35 // Pin connected to the input
volatile uint8_t led_state = 0;
hw_timer_t * timer = NULL;
void IRAM_ATTR timer_isr()
{
led_state = !led_state; // Toggle the LED state
digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // Toggle the LED state
Serial.println("Timer interrupt triggered!"); // Print a message to the serial monitor
delay(200);
}
void setup()
{
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
pinMode(INPUT_PIN, INPUT); // Set the input pin as input
uint8_t timer_id = 0;
uint16_t prescaler = 8000; // Between 0 and 65535
int threshold = 1000000; // 64 bits value (limited to int size of 32bits)
timer = timerBegin(timer_id, prescaler, true); //Timer #, prescaler, count up
timerAttachInterrupt(timer, &timer_isr, true); //Timer object, isr, rising edge trigger
timerAlarmWrite(timer, threshold, false); //Timer object, Value to reach /trigger at, No Auto reload
//timerAlarmEnable(timer);
}
void loop()
{
if (digitalRead(INPUT_PIN) == LOW) // Check if the input pin is LOW
{
//timerRestart(timer);
timerAlarmEnable(timer);
}
}Guys
I have a DevKitC dev board, and I'm trying to set up a HW timer that I want to re-use under certain conditions. In other words, I don't want it to reload automatically, it should run once and then remain dormant until I enable it again. It seems to work the first time, but when I enable the timer a second time it fires immediately, without any delay. It seems I'm not resetting it properly, so that the counter starts from 0 again (?).
What I've tried is this:
initialize timer 0 in setup(), with a prescaler for 80MHz.
myTimer = timerBegin (0, 80, true); timerAttachInterrupt (myTimer, &isrMyTimer, true);
then when I want to use the timer I enable it as follows (for a duration of 3 seconds):
timerAlarmWrite(myTimer, 3000000), false); timerAlarmEnable(myTimer);
I am also trying to confirm the frequency to use for the timer, whether it is indeed 80MHz. I get the values as shown below for the different functions. Any thoughts on what they mean?
getCpuFrequencyMhz() 240 getXtalFrequencyMhz() 40 getApbFrequency() 80000000