Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
Me No Dev
@me-no-dev
sure thing ;) totally doable
Hagai Shatz
@hagai-shatz
How?
Me No Dev
@me-no-dev
timer0 or timer1
or Ticker
Michael Miller
@Makuna
@hagai-shatz how accurate do you need that 500us to be?
Hagai Shatz
@hagai-shatz
20% tolerance will be okay.
About 2000 executions per second.
@me-no-dev - but what if something else is handled in interrupt and it take time to finish? Does the AsyncServer is interrupt based?
Some SPIFFS calls takes >10ms to execute.
Me No Dev
@me-no-dev
@hagai-shatz using timer1 and it's regular ISR will not interrupt the network (that I have tested). Using NMI interrupt will, but I did not see any issues with that. I have not tested timer0 and Ticker, but Ticker should behave the same.
Hagai Shatz
@hagai-shatz
Can you point me to some examples please?
As for Ticker, I use it and it is not reliable even in 20ms intervals. It looks like when the ESP is busy with AsyncWebServer handlers it does not tick.
Me No Dev
@me-no-dev
analogWrite is an example with timer1, though it looks way more complicated than it is
gimme a minute to finish something and I'll try to put one up
Michael Miller
@Makuna
Same with the servo library, it uses both timer0 and timer1, but abstracts them thus making it look more complex than it is.
Me No Dev
@me-no-dev
@Makuna is ccompare running with higher prio than the network?
Michael Miller
@Makuna
Its been a year since I researched it and I have forgotten most of what I have learned; but I thought there was a way to set the level.
TIMERINT[0..NCCOMPARE-1]
Interrupt number for each comparator
Me No Dev
@me-no-dev
@hagai-shatz here is the code
Michael Miller
@Makuna
Its a strange interrupt, INTCLEAR doesn't work with it.
Me No Dev
@me-no-dev
#define TIMER_PERIOD 500 //us

void onTimer(){
  //do your thing
  // NO YIELD OR DELAY
}

void setup() {
  timer1_attachInterrupt(&onTimer);
  timer1_enable(TIM_DIV16, TIM_EDGE, TIM_LOOP);
  timer1_write(TIMER_PERIOD * 5);
}

void loop() {

}
@Makuna I digged myself a bit as well working on the ESP31B but forgot it all the same as you
Michael Miller
@Makuna
timer0 does not support scaling, it runs at instruction count speed always and doesn't auto reset. So you set the timer by calling timer0_write(count) giving it the instruction count to trigger on, once it fires you have to call write again to get it to fire again. To calculate the trigger count, call timer0_read() and add your count to it and pass this to write.
Me No Dev
@me-no-dev
count per microsecond depend on cpu speed and it's either 80 or 160
Michael Miller
@Makuna

Use something like this and avoid constants so you don't care about 80, 160.

    uint32_t usToTicks(uint32_t us) const
    {
        return (clockCyclesPerMicrosecond() * us);     // converts microseconds to tick
    }
    uint32_t ticksToUs(uint32_t ticks) const
    {
        return (ticks / clockCyclesPerMicrosecond()); // converts from ticks back to microseconds
    }

This is what the servo timer stuff uses when using timer0.

Me No Dev
@me-no-dev
static uint32_t ticksPeriod = 500;//still in us

void onTimer0(){
  uint32_t ticksAtEnter = timer0_read();
  //do your thing
  // NO YIELD OR DELAY
  timer0_write(ticksAtEnter + ticksPeriod);
}

void setup() {
  //convert period in us to ticks
  ticksPeriod *= clockCyclesPerMicrosecond();
  uint32_t ticksAtInit = timer0_read();
  timer0_attachInterrupt(&onTimer0);
  timer0_write(ticksAtInit + ticksPeriod);
}
@Makuna is this correct?
woops missed attachInterrupt
Hagai Shatz
@hagai-shatz
@Makuna, @me-no-dev - thanks for the examples, will give it a go.
Are there more differences between timer0 and timer1?
Can I break some other functionality by using them? For example, unable to use the servo library?
Me No Dev
@me-no-dev
above code does not run for timer0
I'm looking into why timer0_read is returning 0;
timer0 is used by the Servi lib
timer1 is used by analogWrite
so those will not work
Hagai Shatz
@hagai-shatz
Not good. But since I'm not planning on using Servi lib for now, this might be okay. As long as the timer0_read() works! :smile:
Me No Dev
@me-no-dev
ok I should have read @Makuna better and use ccount
also missed to init the interrupt
static uint32_t ticksPeriod = 500;//still in us

void onTimer0(){
  uint32_t ticksAtEnter = ESP.getCycleCount();
  //do your thing
  // NO YIELD OR DELAY
  timer0_write(ticksAtEnter + ticksPeriod);
}

void setup() {
  //convert period in us to ticks
  ticksPeriod *= clockCyclesPerMicrosecond();
  timer0_isr_init();
  timer0_attachInterrupt(&onTimer0);
  timer0_write(ESP.getCycleCount() + ticksPeriod);
}
both run with the same accuracy as far as I can tell
Hagai Shatz
@hagai-shatz
Thanks
Michael Miller
@Makuna
Last time I checked, timer0 was only used by servo library so in general it is open for use. Servo library can be told to use timer1 only also.
@me-no-dev esp.getcyclecount aND timer0_read should be the samething.
Me No Dev
@me-no-dev
@Makuna ccompare and ccount are not the same thing :)
Michael Miller
@Makuna
Sorry, my hands typed one thing and my mind was thinking something else, I meant they both use the same type, cycle counts.
Hagai Shatz
@hagai-shatz
Is there a similar interrupt I can setup on a specific pin? That is, instead of using timer, my ADC can set an external pin to high when data is ready to read (every 500us). How can I attach interrupt handler that will have good priority to ensure execution?
Me No Dev
@me-no-dev
use attachInterrupt(pin, fn, type);
Hagai Shatz
@hagai-shatz
Do I need to use attachInterrupt(digitalPinToInterrupt(pin), fn, type)?
Me No Dev
@me-no-dev
digitalPinToInterrupt no
pin and interrupt match here
Hagai Shatz
@hagai-shatz
Okay, thanks.
Ivan Grokhotkov
@igrr
regarding priority: the core inside esp8266 only has three interrupt levels. all "normal" interrupts are at level 1. Debug interrupt is level 2, and NMI is level 3.