Timer error building infinity cube. New syntax?
How to delete and restart hw timer (for interrupts) on demand for esp32 arduino (stepper motor controller application) - Stack Overflow
Hardware timer, how to run once and restart again?
timerBegin () / timerAlarmWrite () do not work with frequencies higher than 500 khz. (IDFGH-812)
Building, https://github.com/mecharms/Infinity-LED-CUBE/tree/main
I believe the problem is the timer is written under old format so does not work with new version in IDE.
Does anyone know if this is just a syntax fix?
//-------------------------------- // Configure Prescaler to 80, as our timer runs @ 80Mhz // Giving an output of 80,000,000 / 80 = 1,000,000 ticks / second timer = timerBegin(0, 80, true); timerAttachInterrupt(timer, &onTime, true); // Fire Interrupt every 1m ticks, so 1s timerAlarmWrite(timer, 5000000, true); timerAlarmEnable(timer); //-------------------------------- C:\Users\Jason\Downloads\Infinity-LED-CUBE-main\Infinity-LED-CUBE-main\code\cube_led\cube_led.ino: In function 'void setup()':
C:\Users\Jason\Downloads\Infinity-LED-CUBE-main\Infinity-LED-CUBE-main\code\cube_led\cube_led.ino:3829:21: error: too many arguments to function 'hw_timer_t* timerBegin(uint32_t)'
3829 | timer = timerBegin(0, 80, true);
| ~~~~~~~~~~^~~~~~~~~~~~~
In file included from C:\Users\Jason\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.2.0\cores\esp32/esp32-hal.h:98,
from C:\Users\Jason\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.2.0\libraries\Wire\src/Wire.h:33,
from C:\Users\Jason\Downloads\Infinity-LED-CUBE-main\Infinity-LED-CUBE-main\code\cube_led\cube_led.ino:2:
C:\Users\Jason\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.2.0\cores\esp32/esp32-hal-timer.h:35:13: note: declared here
35 | hw_timer_t *timerBegin(uint32_t frequency);
| ^~~~~~~~~~
C:\Users\Jason\Downloads\Infinity-LED-CUBE-main\Infinity-LED-CUBE-main\code\cube_led\cube_led.ino:3830:23: error: too many arguments to function 'void timerAttachInterrupt(hw_timer_t*, void (*)())'
3830 | timerAttachInterrupt(timer, &onTime, true);
| ~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~
C:\Users\Jason\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.2.0\cores\esp32/esp32-hal-timer.h:50:6: note: declared here
50 | void timerAttachInterrupt(hw_timer_t *timer, void (*userFunc)(void));
| ^~~~~~~~~~~~~~~~~~~~
C:\Users\Jason\Downloads\Infinity-LED-CUBE-main\Infinity-LED-CUBE-main\code\cube_led\cube_led.ino:3832:3: error: 'timerAlarmWrite' was not declared in this scope; did you mean 'timerWrite'?
3832 | timerAlarmWrite(timer, 5000000, true);
| ^~~~~~~~~~~~~~~
| timerWrite
C:\Users\Jason\Downloads\Infinity-LED-CUBE-main\Infinity-LED-CUBE-main\code\cube_led\cube_led.ino:3833:3: error: 'timerAlarmEnable' was not declared in this scope; did you mean 'timerAlarm'?
3833 | timerAlarmEnable(timer);
| ^~~~~~~~~~~~~~~~
| timerAlarm
exit status 1
Compilation error: too many arguments to function 'hw_timer_t* timerBegin(uint32_t)'
Thank you!
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(){}
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