/*
LAB: 25
Name: ESP32 Timer Interrupt Example
Author: Khaled Magdy
For More Info Visit: www.DeepBlueMbedded.com
from https://deepbluembedded.com/esp32-timers-timer-interrupt-tutorial-arduino-ide/
Adapted to modify the timer on the fly using hints from
https://espressif-docs.readthedocs-hosted.com/projects/arduino-esp32/en/latest/api/timer.html
*/
#define CLOCK_FREQ (80000000L)
#define MAX_COUNTER (0ULL -1)
#define VERBOSE 1
#define LED 21
hw_timer_t *Timer0_Cfg = NULL;
unsigned int step_loops;
void IRAM_ATTR Timer0_ISR()
{
digitalWrite(LED, !digitalRead(LED));
}
void setup()
{
Serial.begin(115200);
pinMode(LED, OUTPUT);
Timer0_Cfg = timerBegin(0, 80, true);
timerAttachInterrupt(Timer0_Cfg, &Timer0_ISR, true);
timerAlarmWrite(Timer0_Cfg, 8000000, true);
timerAlarmEnable(Timer0_Cfg);
timer_set_frequency(5);
}
void loop()
{
modify_timer();
}
void modify_timer(void){
static unsigned long last = 0;
static float i = 1/3600.0/24/365/2;
unsigned long now = millis();
if (now - last < 2000 ) return; // too soon
last = now;
long n_freq = 1;
i *= 3.0/2;
timer_set_frequency(i);
if(i > 150000){
i = 1/3600.0/24/365;
}
}
void timer_set_frequency(double desired_freq_hz) {
// Source: http://letsmakerobots.com/node/28278
// Different clock sources can be selected for each timer independently.
// To calculate the timer frequency (for example 2Hz using timer1) you will need:
step_loops = 1;
// ESP32 64 bit, 80MHz timer per https://deepbluembedded.com/esp32-timers-timer-interrupt-tutorial-arduino-ide/
// TOUT = TimerTicks x (Prescaler/APB_CLK)
// FOUT = 1/TOUT = APB_CLK / prescaler / TimerTicks
// TimerTicks = APB_CLK / prescaler / FOUT
//
// CPU frequency 16Mhz for Arduino
// maximum timer counter value (256 for 8bit, 65536 for 16bit timer)
int prescaler_index = -1;
int prescalers[] = {2, 8, 64, 256, 1024};
unsigned long long counter_value = CLOCK_FREQ / 1ULL / desired_freq_hz;
do {
++prescaler_index;
// Divide CPU frequency through the choosen prescaler (16000000 / 256 = 62500)
counter_value = CLOCK_FREQ / prescalers[prescaler_index];
// Divide result through the desired frequency (62500 / 2Hz = 31250)
counter_value /= desired_freq_hz;
// Verify counter_value < maximum timer. if fail, choose bigger prescaler.
} while (counter_value > MAX_COUNTER && prescaler_index < 4) ;
if ( prescaler_index >= 5 ) {
Serial.println(F("Timer could not be set: Desired frequency out of bounds."));
return;
}
#ifdef VERBOSE
Serial.print(F("desired_freq_hz:")); Serial.println(desired_freq_hz,8);
Serial.print(F("counter_value:")); Serial.print(counter_value);
Serial.print(F(" counter_value%MAX:")); Serial.print(100.0*counter_value/MAX_COUNTER,8);
Serial.print(F(" prescaler_index:")); Serial.print(prescaler_index);
Serial.print(F(" = ")); Serial.print(((prescaler_index & 0x1) ));
Serial.print(F("/")); Serial.print(((prescaler_index & 0x2) >> 1));
Serial.print(F("/")); Serial.println(((prescaler_index & 0x4) >> 2));
Serial.print(F("prescaler:")); Serial.println((prescalers[prescaler_index]));
#endif
//Timer0_Cfg = timerBegin(0, prescalers[prescaler_index], true);
//timerAttachInterrupt(Timer0_Cfg, &Timer0_ISR, true);
timerAlarmWrite(Timer0_Cfg, counter_value, true);
timerSetDivider(Timer0_Cfg,prescalers[prescaler_index]);
//timerAlarmEnable(Timer0_Cfg);
//timerWrite(Timer0_Cfg,counter_value);
// // disable global interrupts
// noInterrupts();
// // set entire TCCR1A register to 0
// TCCR1A = 0;
// // set entire TCCR1B register to 0
// TCCR1B = 0;
// // set the overflow clock to 0
// TCNT1 = 0;
// // set compare match register to desired timer count
// OCR1A = counter_value;
// // turn on CTC mode
// TCCR1B |= (1 << WGM12);
// // Set CS10, CS11, and CS12 bits for prescaler
// TCCR1B |= ( (( prescaler_index&0x1 ) ) << CS10);
// TCCR1B |= ( (( prescaler_index&0x2 )>>1) << CS11);
// TCCR1B |= ( (( prescaler_index&0x4 )>>2) << CS12);
// // enable timer compare interrupt
// TIMSK1 |= (1 << OCIE1A);
//interrupts(); // enable global interrupts
}