From the documentation of this library:
The library use no interupts of the hardware timers and works with the micros() / millis() function.
This library implements timers in software by polling the micros() and millis() functions. It requires the update() method to be called in loop().
So the start of loop() should be:
void loop()
{
tickerObject.update();
if(s == true)
I'm trying to use a Ticker.h to sample an analog input consistently at a frequency of 10khz
It is worth a go but this is a software based solution that is prone to jitter depending on how often the event loop can be called.
Answer from Ben T on Stack OverflowFractional Microsecond Delay;
I want to use microseconds in timer interrupt like in timerone.h for ESP8266
How to use Ticker correctly
Sub milisecond timer for ESP8266 in Lua - Internet of Things Stack Exchange
Hey all, possess any of you managed to get fractional microsecond delay on the ESP8266/ESP32? I need to delay about 5.33 microseconds between setting a pin high and then back to low. I understand that delayMicroseconds mightbe close, but wanted to see if there might be something with a bit more resolution. Thanks!
I think you might struggle to get a microsecond delay that is both accurate and non-blocking with the ESP8266.
According to the NodeMCU documentation:
If you look at the
app/modules/tmr.ccode for this function, then you will see that it executes a low level ets_delay_us(delay). This function isn't part of the NodeMCU code or the SDK; it's actually part of thextensa-lx106boot ROM, and is a simple timing loop which polls against the internal CPU clock. It does this with interrupts disabled, because if they are enabled then there is no guarantee that the delay will be as requested.
tmr.delay()is really intended to be used where you need to have more precise timing control on an external hardware I/O (e.g. lifting a GPIO pin high for 20 μSec). It will achieve no functional purpose in pretty much every other usecase, as any other system code-based activity will be blocked from execution; at worst it will break your application and create hard-to-diagnose timeout errors.
It seems that interrupts have to be disabled in this case simply because if an interrupt did occur mid-delay with a short interval (on the order of a few microseconds), the interrupt handler would take up far more time than the whole delay was supposed to be.
Let's say you wanted a timer for 20 microseconds, and an interrupt occurred at about 10 μs. If the handler takes more than 10 μs, you will have already passed the 20 μs delay that you intended.
So, we can rule out tmr.delay() if you do need interrupts working.
I did a bit more digging, and apparently the ESP8266 does support microsecond timers through ets_timer_arm_new() where the last parameter is zero. NodeMCU, however, sets this value to 1 which uses the millisecond precision. This post seems to support that idea:
If you need to get the interval between two gpio interrupt, use the system api system_get_time() to calculate the relative time.(us) If you want to use a os_timer api to arrange a us timer event, use system_timer_reinit at the beginning of user_init and call os_timer_arm_us.
If you're willing to try editing and rebuilding the firmware, it might be worth a shot. Although, there was a feature request for this, which was declined as:
So I tested nanosecond timers, and cannot establish intervals less than 1000us (with compiled and stripped code and in 160MHz CPU mode I got something like 800us). Is this a case to provide new (mostly unusable) functionality?
- djphoenixNot feasible ATM -> closing.
- marcelstoer
I have managed to recompile the NodeMCU firmware with us timer enabled:
Install docker build environment of Marcel Stör: https://hub.docker.com/r/marcelstoer/nodemcu-build/
change firmware files in your firmware directory (e.g.
./user/nodemcu-firmware)./app/user/user_main.cvoid user_init(void) {
add right here the line: system_timer_reinit();
./sdk-overrides/osapi.hadd above the line#include_next "osapi.h": #define USE_US_TIMER./app/modules/tmr.c->static int tmr_start(lua_State* L){change:os_timer_arm->os_timer_arm_us./app/modules/tmr.c->static int tmr_interval(lua_State* L){change:os_timer_arm->os_timer_arm_us./app/modules/tmr.c:leaveos_timer_arminint luaopen_tmr( lua_State *L ){as is, otherwise you will get a watchdog reset upon start-up- recompile firmware, and flash your ESP8266
With CPU running at 160MHz, I have managed to sample ADC with 8.3kHz (timer delay of 125uS). If I go faster, the watchdog kicks in.
Code:
local mytimer2 = tmr.create()
local count = 0
local count2 = 0
local adc_read = adc.read
mytimer2:register(125, 1, function (t2)
count = count + 1; count2 = count2 + 1
local adc_v = adc_read(0)
if (count2 == 500) then
count2 = 0
end
if count == 100000 then
mytimer2:stop()
print("Time at end: "..tmr.time())
print("Counter: "..count)
end
end)
print("Time at start: "..tmr.time())
mytimer2:start()
Output:
Time at start: 1
Time at end: 13
Counter: 100000
100.000 reads in 12 sec.