Skip to content

Timer functions do not work at all in PlatformIO #5337

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
maxgerhardt opened this issue Jun 28, 2021 · 3 comments
Closed

Timer functions do not work at all in PlatformIO #5337

maxgerhardt opened this issue Jun 28, 2021 · 3 comments

Comments

@maxgerhardt
Copy link
Contributor

maxgerhardt commented Jun 28, 2021

Hardware:

Board: ESP32 Dev Module
Core Installation version: 1.0.6 as well as 2.0.0-alpha1 and current master 21947eb
IDE name: Platform.io
Flash Frequency: 40Mhz
PSRAM enabled: no
Upload Speed: 921600
Computer OS: Windows 10

Description:

I am attempting to replicate the tutorial Hardware Interrrupts here, specifically the code here. The sketch uses functions from esp32-hal-timer.c to setup timer 0 with an alarm that will trigger the execution of an ISR in which a pin is toggled at a rate of 1Hz.

When uploading this sketch in PlatformIO, using all default settings (meaning also core version 1.0.6), this does not work. There is no blinking going on the defined LED pin at all.

The following sketch was used, which additionally prints some debug information on the Serial. A LED is connected to IO2.

#include <Arduino.h>
// Settings
static const uint16_t timer_divider = 80;
static const uint64_t timer_max_count = 1000000;

// Pins (change this if your Arduino board does not have LED_BUILTIN defined)
static const int led_pin = 2;

// Globals
static hw_timer_t *timer = NULL;

//*****************************************************************************
// Interrupt Service Routines (ISRs)

// This function executes when timer reaches max (and resets)
void IRAM_ATTR onTimer() {
  // Toggle LED
  int pin_state = digitalRead(led_pin);
  digitalWrite(led_pin, !pin_state);
}

//*****************************************************************************
// Main (runs as its own task with priority 1 on core 1)

void setup() {
  Serial.begin(115200);
  Serial.println("Firmware start");

  // Configure LED pin
  pinMode(led_pin, OUTPUT);

  // Create and start timer (num, divider, countUp)
  timer = timerBegin(0, timer_divider, true);

  // Provide ISR to timer (timer, function, edge)
  timerAttachInterrupt(timer, &onTimer, true);

  // At what count should ISR trigger (timer, count, autoreload)
  timerAlarmWrite(timer, timer_max_count, true);

  // Allow ISR to trigger
  timerAlarmEnable(timer);
}

void loop() {
  Serial.println("Timer seconds: " + String(timerReadSeconds(timer)));
  Serial.println("Timer alarm seconds: " + String(timerAlarmReadSeconds(timer)));
  Serial.println("Timer is alarm enabled: " + String(timerAlarmEnabled(timer)));
  Serial.println("Timer is started: " + String(timerStarted(timer)));
  delay(250);
}

platformio.ini

[env:esp32] 
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
upload_speed = 921600

The serial output clearly shows the problem: The alarm in the timer is not enabled.

Firmware start
Timer seconds: 0.00
Timer alarm seconds: 1.00
Timer is alarm enabled: 0
Timer is started: 1
Timer seconds: 0.00
Timer alarm seconds: 1.00
Timer is alarm enabled: 0
Timer is started: 1
Timer seconds: 0.25

Time keeps advancing as expected for the timer though.

I was able to fix this issue by going into the C:\Users\<user>\.platformio\packages\framework-arduinoespressif32\cores\esp32\esp32-hal-timer-c file and adding volatile declaration to the timer registers struct.

typedef struct {
union {
struct {
uint32_t reserved0: 10;
uint32_t alarm_en: 1; /*When set alarm is enabled*/

to

typedef volatile struct {
  //...

Adding this single keyword immediately got the LED blinking.

So okay I think, the Arduino-ESP32 has a bug regarding compiler optimizations where a write to the alarm-enable register is not executed in order (or, at all) due to the developers forgetting that the registers need to be marked volatile. That fixes it for the 1.0.6 core.

Note that the same fixing effect can be achieved by not declaring the struct volatile but instead placing a call to function between timerAlarmWrite() and timerAlarmEnable() in setup(), e.g. a simple delayMicroseconds(0);. This strongly hints at me to the compiler optimizing (away) or reordering something in the sequence of writes to the timer registers.

However, I then also cross-checked with the latest master version of the core and compiler.

[env:esp32] 
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
upload_speed = 921600
platform_packages =
   toolchain-xtensa32 @ ~2.80400.0
   framework-arduinoespressif32@https://github.com/espressif/arduino-esp32.git#master
   platformio/tool-esptoolpy @ ~1.30100

Pulling the latest compiler and Arduino core (without any source code changes to the core or the sketch) and re-uploading showed again that the blinky was not working (kinda expected).

However, the behavior on the Serial monitor shows a different story.

Firmware start
Timer seconds: 0.00
Timer alarm seconds: 6.42
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 0.00
Timer alarm seconds: 6.42
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 0.25
Timer alarm seconds: 6.42
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 0.50
Timer alarm seconds: 6.42
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 0.75
Timer alarm seconds: 6.42
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 1.00
Timer alarm seconds: 6.42
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 1.25
Timer alarm seconds: 6.42
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 1.50
Timer alarm seconds: 6.42
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 1.75
Timer alarm seconds: 6.42
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 2.00
Timer alarm seconds: 6.42
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 2.25
Timer alarm seconds: 6.42
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 2.50
Timer alarm seconds: 6.42
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 2.75
Timer alarm seconds: 6.42
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 3.00
Timer alarm seconds: 6.42
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 3.25
Timer alarm seconds: 6.42
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 3.50
Timer alarm seconds: 6.42
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 3.75
Timer alarm seconds: 6.42
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 4.00
Timer alarm seconds: 6.42
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 4.25
Timer alarm seconds: 6.42
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 4.50
Timer alarm seconds: 6.42
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 4.75
Timer alarm seconds: 6.42
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 5.00
Timer alarm seconds: 6.42
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 5.25
Timer alarm seconds: 6.42
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 5.50
Timer alarm seconds: 6.42
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 5.75
Timer alarm seconds: 6.42
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 6.00
Timer alarm seconds: 6.42
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 6.25
Timer alarm seconds: 6.42
Timer is alarm enabled: 0
Timer is started: 1
Timer seconds: 0.08
Timer alarm seconds: 6.42
Timer is alarm enabled: 0
Timer is started: 1
Timer seconds: 0.33
Timer alarm seconds: 6.42
Timer is alarm enabled: 0

You can see that right off the bat, the alarm seconds value returns is suddenly.. 6.42? Which makes no sense since it should be 1.0. The timer seconds keep counting up until hitting 6.42, and then the alarm goes from enabled to disabled.

Adding the volatile keyword to the struct definition as shown above does change the output.

Timer seconds: 0.00
Timer alarm seconds: 1.00
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 0.25
Timer alarm seconds: 1.00
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 0.50
Timer alarm seconds: 1.00
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 0.75
Timer alarm seconds: 1.00
Timer is alarm enabled: 1
Timer is started: 1
Timer seconds: 0.00
Timer alarm seconds: 1.00
Timer is alarm enabled: 0
Timer is started: 1
Timer seconds: 0.25

Now the timer seconds to read correctly as 1.00 but after 1 elapsed second, the alarm is just disabled and never continues...

However from there, no matter where I add volatile in the register struct definition, I can not get it to function correctly. There might be additional issues somewhere else.

In any case, I see this is a bug. For 1.0.6 it's a bug reproducable with PlatformIO and also fixable as I've shown, As for 2.0.0-alpha1 and the current master version, I see the same bug source (still no volatile on timer regs) but that is not the only needed thing to keep it going.

Are you able to reproduce the issue in PlatformIO?

Magically per the linked video, Arduino IDE seems to work with some versions though? Can anyone test this with the latest master?

@me-no-dev
Copy link
Member

Hi @maxgerhardt ! Thanks for the detailed submission :)
Good hunch on the volatile as for the other issue, it seems that edge interrupt does not work on ESP32, so giving false for edge in timerBegin would have done the job. Anyway I will add a "fix" for this in just a sec :)

@maxgerhardt
Copy link
Contributor Author

maxgerhardt commented Jun 28, 2021

You are right, with volatile in the timer regs and calling timerAttachInterrupt(timer, &onTimer, false); instead of timerAttachInterrupt(timer, &onTimer, true); in the sketch, this now properly works on the latest core version, too :)

Thanks for the fix.

pedrominatel added a commit that referenced this issue Jul 5, 2021
Docs: Fixed typo

Docs: Boards tree fixed

Removed link from the getting started OS icons

Pin layout images updated and added the requirements file for sphinx extensions

Copy button extension enabled on conf.py

Added information on the Getting Started Guide

Removed pygments_style from conf.py

Added SoC and Module image

Added Windows install guide and boards manager images

Added OTA Web Update to the docs and removed from md files

Added DFU and ESPNOW files into the docs

Fixed Typo

Changes on the boards, getting started sections and menu order changed for Lib Builder

Added references on the boards to fix broken link

Added the basic tutorial as template

Fix hardware timers

Fixes: #5337
Fixes: #4743

Thanks to @maxgerhardt

Added code style reference and WIP on the libs template

Added peripherals tutorial

Added peripherals tutorial fix

Update on the WiFi lib docs and removed old md files

Update on the WiFi lib docs

Fixed the examples references for WiFi Lib

Fixed code-block on begin function - WiFi Docs

Updates on WiFi lib docs

Fixed the AP section on docs

Review in progress: API, boards and tutorials

Fixed typo on Strapping pins

Review done
@williamesp2015
Copy link

I was very frustrated with ESP32 RepeatTimer example (above example) but this solved the problem hanging on timer using PlatformIo.
volatile uint8_t InterruptFlag = 0;
hw_timer_t * timer = NULL;
void onTimer(){
// Serial.println(millis());
InterruptFlag = 1;
}
void startTimer(void){ //long Timerrus) {
InterruptFlag = 0;
timer = timerBegin(0, 80, true); // timer_id = 0; divider=80; countUp = true;
timerAttachInterrupt(timer, &onTimer, true); // edge = true
timerAlarmWrite(timer, 100000, true); //100 ms
timerAlarmEnable(timer);
delay(10);
}

void stopTimer() {
if(timer)
{
timerEnd(timer);
timer = NULL;
InterruptFlag = 0;
Serial.println("Timer Stopped");
}
}

gb-123-git added a commit to gb-123-git/arduino-esp32 that referenced this issue Jan 23, 2022
For fixing Hardware Timers:
Timer functions do not work at all in PlatformIO espressif#5337

espressif#5337
espressif@8f46bad?diff=split
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants