This inconsistency and delays you are showing is not a problem of ESP32, it's a problem of Arduino porting for ESP32. Just use ESP-IDF directly and redo the experiments - results will be completely different ;)
How lucky we all are that these super well-produced, interesting and informative videos are available to view at our leisure. What a world we all live in! Thank You Andress!
Truly. I am able to pursue a life passion project through stitching together knowledge from a collection of great youtubers, with Andreas a shining example. You make the world a better place :)
This is the second video I've watched by Andreas, and I subscribed after watching the first few minutes of this. With so much bad information out there, this channel is a breath of fresh air. So much to unpack in this video. I'll be watching it again and again, thank you Andreas.
Thanks Andreas, you ever find the way to make it clear and easy to understand. The two channel osciloscope trick is really interesting, but this is part of your very high end workshop...
Brilliant video. Exactly what I wanted. And excellent overview for the beginner or even the experienced. I worked on embedded systems 15 years ago - we used microcontrollers, GPS, cellular comms, and used this to create telematics devices installed on John Deere and Liebherr equipment (and others). We read the CAN bus, and used interrupts for things like movement, engines turning on and other interrupts. Since then I've been doing product management, and now I'm getting back into this level of coding... and was depressed that Arduinos don't have good interrupts and sleep. Your video has brought me back up to speed SUPER quickly, helping me restore my memory from tape, and quickly jumpstarting me with a new microcontroller board.
As always a pleasure to watch. I like that you are not only focusing on hardware, but also explains how to utilize software to make project simple and easy to make
Thank you ! Perfect timing ! We were just running into random crashes yesterday with our encoders running off ESP 8266. Cleaning up the interrupt functions based on your advises solved our issue ! For the little story, We are building a 4DOF motion platform using salvaged standing desk electric pistons and ESPs. Such a great content every time ! Thanks again !
Great Topic, The ESP32 has so many new features, performance advantages and value over the Arduino. For the hobbyist, one platform can serve many projects . Your post make the transition worth attempting. Keep them coming!
Great job of using the KISS principle, Keep It Simple S.... Silly. This is the most straight for explanation of ISRs, aka, AST as we know them on our beloved VAX-32s. Thanks for showing us all your amazing "scope" work! I'm REALLY enjoying your 2020 video's along with all the others, VERY HELPFUL!!!
Glad you like my stuff! I only sold VAX computers, I never programmed them :-( At least the biggest I sold was a VAX9000 for 10 million Swiss Francs. At that time maybe 25 million dollars...
It would be interesting to see a video on using the ULP core for running code without waking up the ESP32. Would be nice to explore the possibilities and limitations of the ULP core.
Greetings from Turkey Andreas, I just wanted to thank you for all the great videos you have put out here on the channel. I can't imagine what I would do without you. Loved the cat btw :)
Andreas, perhaps a followup comparing the interrupt coding and latency on other 'Arduinos' like STM32, SAMD21, ATMega, ATTiny, ESP8266, MK20DX (Teensy), SiFive E31 (HiFive1), etc.
@@ripper121 Ah yes, datasheets to find out about interrupts and how they affect everything... let me just quickly read for dozens of hours to compare a few µC... Just seeing that a ESP32 is pretty much useless if you go into deep sleep is enough information.
@@leocurious9919 Really, that's a very specialized problem and different for each individual case, as Andreas said. Think about changing just one clock cycle in your application code changing the complete timing that is at issue here. It is best to simulate this for each individual case, better to test it as an experimental setup. If something is important for a preliminary decision, it is the limiting/rating values and the clock behavior that can be found in the data sheet. So @Ripper121's remark is far more helpful than displaying one's own laziness. Stay healthy:)
Mr Spiess, I enjoy your presentations and like this one too. Thank you for all your effort and shared knowledge. There are several reasons why CPU like this one may have long interrupt latency. One of them (and it is a Real Time limitations of large processors like multicore Intel and ARM) is cache coherency. Simple, interrupt code maybe not present in cache and other current content of the cache need to be saved before reloading new one to/from RAM. For vary fast approach, user need to instruct compiler (I dont know how to do it at ESP32 yet) to keep interrupt service routine (if short) permanently in cache. This is typical approach for RT Linux for example.
Thank you for pointing me towards the Otii. Now have one and it is becoming an essential piece of kit. Especially now I’m investigating why my new custom board is using 1mA more than it should be
Thank you for another interesting and instructive video Andreas. >edit: went through the comments and found this was already reported, sorry I just wanted to add that RTOS seems indeed to be a culprit for the interrupt response latency and jitter. I think that attachInterrupt actually hooks up not to the interrupt controller but to an RTOS callback function. This function is entered the queue of RTOS tasks, and get executed after the completion of all the previous tasks only. Apparently it is possible to get a fast interrupt response when programming using noOS SDK from Espressif but I did not try this yet.
@@Quemedices684 ESP32 Arduino calls various functions that are built around Espresif's SDK that in turn uses RTOS for WiFi operations. If one does not need WiFi or software timers then no RTOS is involved indeed.
A great part of the inaccuracy in the interrupt code (at 7:13 in video) is caused by your own loop code: { frequency = count; display(0, "frequency=", frequency); lastEntry=millis(); count=0 } You use count but reset it only after displaying on the pretty slow LCD. That means, all events that occur during the LCD operation are not counted, but lost. Also, if the duration of LCD output varies, it worsens the count precision. You could improve it if you first completed the job of count handling: { frequency = count; count=0; display(0, "frequency=", frequency); lastEntry=millis(); } BTW, your polling loop (at 3:54 in video) would be more elegant if you replaced lastentry= millis(); while (millis() < lastEntry + 1000) {...} with endTime=millis()+1000; while (millis() < endTime) {...} This way the addition would be done only once. However a good compiler might catch this and produce the same binary code.
The compiler will figure out the optimization you mentioned at the end automatically. There will be no difference in performance. However, your hint about doing count=0; just after reading frequency is a valid one. In fact if you have mutexes used, you can wrap read and reset of the count, into critical block and be even safer. There are other approaches (like not resetting count at all, and remembering the last count, and subtracting it from current count to get new frequency (might require a special handling of overflows tho; but it will not need mutexes).
it is perfectly fine how he did it. even if the displaying took multiple seconds it wouldnt change anything since the lastEntry variable is changed just before resetting the counter. so it doesnt matter how many counts there were while communicating with the lcd. correct me if i miss something though
@Andreas, I detach the interrupt at the beginning of the ISR on my Dimmer control, it's only 60Hz and an ESP8266 (today) but it did resolve the flickering I was facing at the edges turning on the off the light completely (and smoothly). Wifi has to be on and there is intense MQTT to keep dashboard as real time as possible, so if I miss a trigger at the edges I just complete the cycle one way or another. With this I could literally get the entire 1% to 99% (in a logarithm scale for real light scale) without bugs. Another great video from you. Cheers.
I agree with your idea of being the RTOS influencing the interrupt latency. The RTOS itself (which seems to mee FreeRTOS reading the definitions you wrote to allow ISRs to be safely called) has surely some routines to schedule our loop() function with its own tasks, which can be in turn the communications module handlers (Wifi and/or Bluetooth). Even though you disable them, they could be still working for some reason. In addition the scheduler itself can use an interrupt to switch internal tasks, and this can be another jitter cause.
@@AndreasSpiess In god old NEBRASKA, we had a minimal closedown and even the mall open last Friday! I hope governments get smart and reopen everything ASAP! People will not go, if they are in the risk group, like me and my wife, since we don't want to get sick! People are much smarter than government thinks! I think we OVERDID this, but now is time to reopen everything and let business control everything they know how! I hope your finger gets well soon and you are also being able to do whatever you did before this crappy virus! Good luck and stay safe!
Thanks a lot for your effort, your experiments, the video and the explanations. And we are now back to the same question we discussed when the ESP32 became availabe: How to use the different cores for different tasks in Arduino IDE , e.g. to decouple WiFi. Up to now I did not find a solution. This is why my counter at the water meter still uses 2 pcs ESP8266. One just for counting and tranferring data via HW-serial without any WiFi output and the second for analyzing the data and communication with my home automation system. Not very elegant, but runs very stable, uptime 657 days since the last blackout caused by road construction works.
This video helped a lot! I wanted to monitor my PV panel energy harvesting using an ESP8266 and an arduino DUE (i know, not ebergy efficient but thats what I had lying around). Before th is video they were consuming 210mA and up to 250mA when publishing the measurements. Now i modified the sketch so that the DUE is always asleep (by pull down resistor on reset) and only wakes up for 3 sec (by the ESP) to measure and transmit the data to the ESP then go to sleep again. The ESP then (after connecting) publishes the data and goes to sleep for 20 sec or so. The result is that during sleep they both consume on 38mA and only 100mA when the ESP is awake. Only 3 seconds of 200mA now which easily runs this 24/7 on a single 18650 cell and for several days! Thanks for the insight!
There is no difference when used standalone, both result in the same value. It only matters if you're evaluating the result in the same instruction, in which case counter++ will evaluate to the value before it's incremented, while ++counter will evaluate to the value after it's incremented.
@@dwmorris In C++ (that the Arduino IDE uses), as opposed to C, there is a potential significant difference between the post and prefix ++ and -- operators. This is partly due to operator overloading. This mostly affects performance, but the prefix operator is always guaranteed to be at least as fast as the postfix equivalent, assuming they are implemented semantically the same of course. It is therefore recommended to use the prefix variant unless one actually uses the pre-change value for something.
There is no difference. Even in C++. It is the same. Don't scratch your code about it unless you use C++ STL iterators (and even then it often will result in the same code, because compiler is smart enough), which you probably shouldn't on microcontroller anyway.
Thank you Mr. Spiess for the interesting video. Having started programming Microcontrollers with Arduinos and ESPs, and now programming Controllers on a professional level, the DIY embedded system community is filled with lack of skills: poor code because no real programming knowledge, lack of understanding of what is actually going on under the hood, ... . For example, one thing i noticed in professionally, is that i had to always master the controllers' documentations, i had to work on. This lead to the fact that most issues that you mentioned in the video simply can't happen (like polling the digitalread and delaying). I therefore really appreciate deep videos like yours, that aren't simply about repeating examples found online, but analyse and go behind the curtains.
Your videos are always excellent. By the way, If you want a low latency ISR on the ESP32, consider placing it in IRAM. (There is a flag you can put on the ISR definition to do this).
He already did that. I think the issue with ISR is due to arduino code, not ESP32. Also I don't think you really need the mutexes in ISR unless you manipulate more complex data structures from ISR. doing read-modify-write (like count++) from ISR, while rest of the code only do reads (so you might need to have two variables to track how much count you already processed, not reset it back to zero), is safe and doesn't require a mutex.
@@AndreasSpiess The main core is running many background tasks, I believe the second core is completely idle, If RTOS is handling the interrupts (which it shouldn't) that's another story
@@AndreasSpiess I think the delay is due to other FreeRTOS tasks taking over. Running it on another code could help. You need to create a very high priority task on that core and disable the watchdog timer.
Ali Devrim OGUZ FreeRTOS seems to have a make menuconfig option to lock it to only the first core? would this assist after your interrupt suggestion? also interested in other versions. wroom, wrover, (solo can’t be real-time), S2. Would love to have time to test them. Probably goes for all of us. Also need to invest in oscilloscope / dsi.
@@jrgalyen yeah that'll probably work too, however it may not let you run your program on the other core. I haven't tried that. I only saw the menu option to "not run the freertos on a single core"
Andreas, nice video! Regarding start-up time: the ESP32 supports deep sleep wake stubs that are executed before any normal initialization. It can send the ESP back to sleep if for example the voltage of a connected battery is too low. I use this feature for undervoltage detection of a connected lipo battery (saving on an additional hardware component). Best
@@AndreasSpiess Sorry, missed that part! It is easy to implement in Arduino, as the default wake up stub function is weakly coupled and can be overwritten directly: RTC_DATA_ATTR int bootCount = 0; void RTC_IRAM_ATTR esp_wake_deep_sleep(void) { esp_default_wake_deep_sleep(); bootCount++; } This increments the counter before the bootloader starts. Greetings from Germany
Always a pleasure to watch your videos. Thanks for this on. I ran into some trubble appling the irq approach to a 100Hz signal with not as perfect steep flanks as in your given example. The isr gets triggered multiple times during rising and falling flanks. The RISING statemend seems to have no effect in the allocation of the irq. The esp32 seems to have problems with shallow flanked and slow signals. In such cases additional HW and Code is needed...
It is always good to have a Schmitt trigger in front of the interrupt input. Maybe you can disable the interrupt for a few ms in the ISR as a work around.
I'm currently using the ESP32 for a fft application on net voltage and load current signals (2 analogue channels, 50Hz), where I trigger a timer interrupt up to 1024 times per period, so ~ 100k samples/s on RTOS using both cores. In my case I'm working with hardware interrupt each ~20ms which calculates a timer value for the real period time divided by 1024. This timer or counter calls another ISR every ~ 20µs. In my opinion the ESP32 is fast enough for similar applications. But I'm totally agree with your point of the delay of hardware interrupts. Thanks for your research!
I have an issue with ESP8266 in my weather and fertilization station where ESP8266 must exchange data with ATMEGA328 via I2C. What I found very strange is that ATMEGA328 can receive data from ESP8266 without any loss but ESP cannot receive any data from ATMEGA328 even if it runs at 80MHz which is 5 times faster than ATMEGA328. Is ESP8266 Interrup latency much slower than ATMEGA328's or is it due to Wifi and multitasking in ESP8266?. I tried sending data using Wire.write(), ATMEGA Master ESP Slave, and also tried I2C request mode where ESP is Master and ATMEGA is Slave. I also tried to reduce I2C frequency to the minimum (like 30 Khz) but nothing worked. Is "WIFI OFF" function available also in ESP8266? Can it solve the problem? Here a link to my web interface to my weather station: www.abrobotics.be/siliconceptsarl/METEO/meteoframe.php
I cannot do remote debugging. But you can switch Wi-Fi off on the ESP8266. Maybe you use a logic analyzer for debugging? I once made a video about that.
@@AndreasSpiess Thanks Andreas for your reply. I tried switching off Wifi using WIFI_OFF at the beginning of ISR then WIFI_RESUME at the end of ISR but also it doesn't work. I will try to send from ATMEGA328 to ESP8266 using hardware Serial and Software Serial. As you suggested I will debug I2C using logic analogic. Unfortunatly I have it in my lab and I am now stuck in another city due to Corona virus.
Yes, the display() routine is slow. That is why the last two lines have to be together. You also ca n put it in front of this routine. It will give the same result.
@@AndreasSpiess Maybe I’m not understanding the code correctly. Please correct me if I’m wrong, but if an event happens during the display() routine, the counter would be incremented, and then later the counter would be reset, so those events would be lost?
@@AndreasSpiess Ok, I think I get it now. Some events might be “lost” but because the lastEntry is also reset at the same time, those lost events wouldn’t change the frequency measurement, it would just be a “gap”.
I'm trying to make a simple project to count pulse of a water meter based reed switch. But the EMI causing issue when connect direct long wire to ESP32.
Hello, your videos help me a lot, as I´m working with ESP32 for my Bachelor's thesis and there is not a lot of documentation out there. So thank you. :)
What tool did you use to accurately measure the milliamp current consuption at 15:30? it does not appear in you link with the equipment you are using...
This is why I still rely on 8 bit / 16 bit PIC MCUs, they do a very good job at handling interrupts and have a simple way to hook a internal timer to an input pin so you can count very fast signals. It makes easier to implement control loops like PIDs. Only if I need a web server or something to do with WiFi I go for the ESP32. The ESP32 is not a Jack of all Trades.
I think that right now the ESP32 is the most complete microcontroller when it comes to stay connected and also have massive processing power. But if you don't need connectivity there are better options out there than the ESP32. In the end we choose what we feel comfortable using...
If your running an RTOS then there will always be issues with when you get to see the interrupt. so i can see why the latency is changing, it depends where you interrupt arrives in the the background processes. Not sure if the ESP32 RTOS has variable time slots or fixed time slots so there could be issues there. In the embedded world there is a lot of effort to get an RTOS working correctly. Spent many a happy week on embedded RTOS courses, just to decide that if you don't need all that an RTOS offers then it best not to use one. Also interrupts are a pain for proving the code is safe, as how do you check all the possible places in your main code where it can get interrupted, don't get issues when interrupted at the point. Nice thought provoking video as usual, thanks
You can process interrupts at higher priority (i.e. level 5, just before NMI level). By default ISR will be lowest priority (level 1), so it will be preempted and/or delayed by other routines like a task scheduler. It is possible to have stable latency and minimal jitter using FreeRTOS.
Very interesting and informative video as always. I don't know how to disable interrupts in arduino mode, but in bare-bone C/C++ or w/o rtos it is possible. I think that it would be quite interesting to compare the behavior / timing in bare-bone / arduino program.
Hi. What a great video. I think you may have just solved my esp32 interrupt crashing issues. I will test your code tomorrow. FYI I'll be using it for a speedometer.
Update: the Frequency_Counter_with_Interrupt.ino seems to run fine. A little inaccurate at really low rpm (60rpm for example) but good at high rpm. Maybe some smoothing required. Now trying to use time between pulses so work out rpm. Not going to plan yet ;)
I have a question at 10:50 you defined timerMUX, if I have 3 different interrupts i need to have 3 different lines like this one portMUX_TYPE synch = portMUX_INITIALIZER_UNLOCKED; ??
@@AndreasSpiess Thanks! I have found this great article, but still no answer for this question techtutorialsx.com/2017/09/30/esp32-arduino-external-interrupts/
@@AndreasSpiess I used one of your codes to test if it is needed to declare multiple portMUX_TYPE variables, one for each ISR when you use multiple external interrupts. I found out that using 2 or only 1 portMUX_TYPE variable the sketch worked fine, so I still don't know if it is needed. Here is the code:
/* Test code for ISR function I used and modify this code:github.com/SensorsIot/ESP32-Interrupts-deepsleep/blob/master/Frequency_Counterr_with_Interrupt/Frequency_Counterr_with_Interrupt.ino I am using an ESP32 thing from adafruit Test 1 create one portMUX_TYPE variable for each ISRs Feed signals and see the outputs Test 2 use only one portMUX_TYPE variable for the 2 ISRs Feed signals and see the outputs Results: It did not matter if I use synch1 and synch2 or if I only use synch1 The 2 test showed the 2 interrupts seem to be working fine Notes: I don't have a signal generator or oscilloscope to check the signals The 2 inputs were a floating cable on INPUTPIN2 and a mechanical water flow meter (hall effect sensor) INPUTPIN2 The code for each test compiled without problems */ volatile int count1 = 0; volatile int count2 = 0; unsigned long lastEntry; int frequency1, frequency2; #define INPUTPIN1 15 #define INPUTPIN2 16 portMUX_TYPE synch1 = portMUX_INITIALIZER_UNLOCKED; portMUX_TYPE synch2 = portMUX_INITIALIZER_UNLOCKED; void IRAM_ATTR isr1() { portENTER_CRITICAL(&synch1); count1++; portEXIT_CRITICAL(&synch1); } void IRAM_ATTR isr2() { // uncomment for first test portENTER_CRITICAL(&synch2); count2++; portEXIT_CRITICAL(&synch2); } //void IRAM_ATTR isr2() { // uncomment for second test // portENTER_CRITICAL(&synch1); // count2++; // portEXIT_CRITICAL(&synch1); //} void setup() { Serial.begin(115200); Serial.print("setup() running on core "); Serial.println(xPortGetCoreID()); pinMode(INPUTPIN1, INPUT_PULLUP); pinMode(INPUTPIN2, INPUT_PULLUP); attachInterrupt(INPUTPIN1, isr1, RISING); attachInterrupt(INPUTPIN2, isr2, RISING); lastEntry = millis(); } void loop() { if (millis() > lastEntry + 1000) { frequency1 = count1; frequency2 = count2; Serial.print("frec1: "); Serial.println(frequency1); Serial.print("frec12 "); Serial.println(frequency2); lastEntry = millis(); count1 = 0; count2 = 0; } }
GREAT VIDEO!!!! Yes, it´s a penny that ESP32 is not good for Real Time applications. I´ve noticed the high Jitter on interrupts (Varying from 2 to 45us). It would be good if someone finds how to program the interrupt with *high Priority* even on assembler.
@@AndreasSpiess yes i have read. Normaly if you learn interrupt programming, the first command in the ISR is that you mask the interrupts, that no other can block you. Only die NMI is allowed
At 9:20 Andreas says interrupts cannot be disabled in ESP32. Is this still true? I have been inserting cli() and sei() into my code to disable and enable interrupts and the compiler does not complain, although I have not conducted any experiments to confirm interrupts are indeed disabled. noInterrupts() and Interrupts() is also accepted by the compiler. (I am using platformio)
hello good video thank you very much it helped me a lot but I have a question I have a set of multiple gpio as an interrupt pointing to the same ISR function, the question is how can I know which GPIO was activated by interrupt? Or are there special methods to do this type of query?
I would add different ISRs for each interrupt and call a common function inside each one. Maybe there is also a register to find out which interrupt was triggered. But I do not know it.
Nice. To be fair, the ESP32 is running a very high level OS, FreeRTOS with changes. It doesn't have to run FreeRTOS, but you'll experience a great deal of trouble using Arduino or PlatformIO if you eliminate the OS. (You'd have to write a new core library) Something that might make a difference is to set the affinity of the ISR to the second core, which is unused by any code unless you explicitly force tasks over to it. I've never tried it, but it should be produce measurable improvement.
You are right. I usually just take what I have and check it out. I would probably use a different processor for real-time applications before I would start to mess around with the underlying infrastructure ;-)
@@AndreasSpiess I believe you'll have much better results w/ interrupt driven ESP32 tasks, working from Espressif's development environment. And you might have some limited success just forcing your loop function onto the unused core via xTaskCreatePinnedToCore(myLoop, ...). There's no reason why an ESP32's Xtensa cores can't handle what you were trying to do in this example, but the Arduino program model could be a limiting factor. I know...target audience. You're right, but the ESP32 is an AMAZING development board. I don't use it much, but only because I never need that much processing power. :o)
Hi Andreas. Please show example of a USB interrupt routine. The Arduino command "serialEvent()" dosent work with the ESP32? Im using windows and the Arduino software.
I think that Timer0 is used by the underlaying FreeRtos as internal Tick source (behind the Arduino Sketch). Due to this, you are getting an "oversized" ISR and a long response time. You might try with timer 1 and check again the response time? ISR TIMER0( .... SystemTick (with context switch) .... your ISR routine( with its context saving) .... (context restore) ) ISR TIMER1( .... context saving ....your ISR routine .... context restore ) greetings from Argentina!
Nice video you have! I have a question for you if you can to help me. Can I make a wake up event with a touch sensor and in the same time I have timer wake up? I want to use this method to send the data through Wi-Fi(at every one hour) and touch sensor to wake up to see the values via Bluetooth? Or it's too much?
Maybe somebody has it already mentioned. You can shorten the interrupt reaction time by using high level interrupts. But you must implement it in assembly. LX instruction set is a little bit tricky and commonly not the right approach for people living in the Arduino world. But in generall it is pollible to improve the performance with this way.
Great video! Question 🙋♂️ could you count frequency with an internal hardware counter? Are they cascadable so that you could at least use them for HF? Thanks 😊 73…
You are right. You can use the internal counters either to count or to divide the frequency of the input signal. Here I did not want to build a fast counter, I only used it as a simple to understand example for interrupts.
You have a huge latency because your inrerrupt routine is actually a callback function. The real interrupt routine is hidden behind the assignInterrupt() finctionality. So there is a long execution chain: interrupt - lookup of assigned callback - callback execution
Doesn't page 38 section 2.3.3 of The ESP32 Technical Reference Manual document how to use the Interrupt Matrix Controller to disable CPU interrupts? Another interesting video, by the way.
@@AndreasSpiess Ah, ok, I use Platform IO. I'll try and have a look using it in Arduino IDE and see if I can find Ivans blog. Haven't found Ivans blog but have a look at "Assembly via Arduino (parts 1 and 2) - Introduction" you tube videos.
You did measured delay of interrupt. But is it really delay of interrupt or did you measure how long does it takes to evaluate portENTER_CRITICAL? Also - volatile - should be used on shared variables - not on all variables in interrupt function (not sure if it is different for ESP32 - but just standard c++)
1. You are probably right with the volatile. But because it does not cost a lot I do it for all used in the ISR ;-) 2. I do not know where the delay is coming from. But it is not very important for me because I have to use this statement (at least this is my knowledge)
@@AndreasSpiess I'm more oriented on software development - and I have only ~2 years experience with raspberries or esp's :) At work I'm working on application used by tens of millions - so I know what threading issues are (any small chance to happen - it will happen :) ) So I just wonder if portENTER_CRITICAL is not just going "safe" when interrupt and main program do things on same ports - it is ok for "counters" or so but not for quick reaction - like frequency counting ... If it does not cause crash, lost of dat or so - it may be ok to omit that I'm going to use this method for weather station - as counter of revelations caused by wind - so for me it would be ok :) But one think I also understand - if manufacturer wrote it in manual - it may be wise to use it anyway because later changes may break my program (after using new chip or recompiling with some new libraries) - and then it is hard to find problem
I want to use the esp32 to read CSV values and push out pixels led data. I'm using castles library. I Can't go above 1000 pixels , the esp crashes 😢. Please help me out.
I'm using the dual core feature of the esp. One task reads the data from micro SD card. The other task waits till the whole frame is loaded and then pushes the data to pixels. Some times watchdog error occurs , ( task gets starvation).I'm also utilising sema fore for the task syncing.
Mr Andreas, thanks for the video. I have a project that extensively uses interrupts. It uses 8 water flow meters to measure water consumption. I have always used portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; in my code without actually understanding its function. I saw you are using portMUX_TYPE sync = portMUX_INITIALIZER_UNLOCKED; Tried to search for the differences but failed to find relevant explanations. Why MUX or SYNC and when to use one or the other? Thanks in advance.
That is just a variable name, you could use portMUX_TYPE potato = portMUX_INITIALIZER_UNLOCKED; just refer to the same variable name in your ISR's portENTER_CRITICAL(&potato) and portEXIT_CRITICAL(&potato) calls.
Andreas, I think your interrupt latency problem is caused by using the straightjacket and rubber room of the Arduino attachInterrupt() instead of using the ESP IDF's esp_intr_alloc(). Finding the definition of the attachInterrupt was a real pain-- google failed, but I finally found github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-gpio.c . I think by default, you are getting a level 1 (lowest) interrupt, so other interrupts will interfere. You can get level 3 with some flags in the esp_intr_alloc(), but to reduce latency you'd need to use level 5 (Timer.2 uses level 5) and this level requires an assembly ISR (not C callable). If you only modify the counter in the ISR and it is word-aligned, then you shouldn't need to worry about portEnter (but you can use esp_intr_disable()), and you can run the ISR in the other CPU. In assembly, your ISR only needs to increment the counter and return from interrupt. Perhaps having a low-level interrupt wouldn't matter running on the second core. It would be interesting to see your latency on the scope running on the second CPU. I assume it's not used by the RTOS except maybe timers? It would be interesting for you to make a followup video demonstrating how to use a high priority (level 5) interrupt with a short assembly handler running in the second CPU, and see how high of a frequency you can get. Also, I came across this: github.com/MacLeod-D/ESp32-Fast-external-IRQs where he uses dedicated polling on core 1 and claims >3MHz counting.
Verv interesting Video. The main difference i normally do on similar Programs i don't reset the counter Variable, but use the difference to the Value of this Variable from the last read. This only works when the difference is smaller then half of the maximum value possible with this variable ( 2^31 with 32 Bit Systems ), so wraparounds are always result in differences in this Range. Resetting the Variable is only safely possible when the changing of the Count-Variable can not be interrupted ( this is true when changing this Value is a single command on the Processor, The Processor has some means of binding more commands together in an non-Interruptible way - even across multiple Processors, or you can use for example critical sections ) Otherwise the ISR might be interrupted in between reading the Variable and writing it back after changing it - so the reset Variable will be overwritten.
Howdy Andreas, Thanks for your videos. I needed better than 200khz latency so I used HLI's and that got me better than 2MHZ latency. So the ESP32 can do better than 200khz. I've tried to provide a link to source code and write up on my Medium page but seems youtube deletes it. Thanks for all your great content.
Good to know. But probably not for everybody (I think I saw your issues on the Expressif page ;-) Links, unfortunately, are removed by TH-cam. They changed their policy :-(
This may be a dumb request, but I went to buy a couple of ESP32 boards, so as to get some basic familiarity with them for future development work, but ... well, hundreds of different models are available - and I was overcome with analysis paralysis, and had no idea what to order. So, I closed the tab and did other things. Would it be possible to get some kind of basic guide / idea of what to look for when purchasing as an ESP32 n00b?
Sir have you tried measuring domestic AC supply with 50Hz ? I guess ESP32 interrupts are unable to work at slower frequencies and gave false triggers... Please provide your opinion.
You have to condition the signal before you feed it to an ESP or any other microchip (zero-crossing). It expects a steep rise or fall of the signal which is not the case for a sine wave. The ESP has no problems with slow signals.
@@AndreasSpiess I had used an Optocoupler for zero crossing and it seems to work fine for arduino with interrupt and also for esp32 it works with your state machine code but when using esp interrupt code.. It shows false triggers.
A little off topic but... When using the ext1 deep sleep wake, is it possible to use an IF statement to perform tasks based on which of the buttons woke the esp?
@@AndreasSpiess thank you for the quick response, definitely an option, but I was only using a single pulse as not to cause multiple wake ups. As the esp prints the GPIO I thought it may be an option to do something like below: IF(GPIO_WAKE_REASON==GPIO2){ TASK ONE } ELSE IF(GPIO_WAKE_REASON==GPIO15){ TASK TWO } ELSE{ esp sleep enable ext1 Esp deep sleep start }
Hi, I'm I the only one having a problem with the ESP32 on a LoRa TTGO T3 board ? I use interrups to count pulses coming from an anemometer and a rain sensor. So quite slow. No matter what I do, the ESP counts FALLING AND RISING edges, despite that I asked to detect only FALLING edges. I debounced the input signal, but I clearly see that it counts twice ! Any advice ? BTW, nice tutorial as usual ! Do you sleep sometimes ? 😁
I am not good in remote debugging, particularly in such difficult situations :-( If not already done, I would create a simple example that moves one pin in the interrupt and watch the interrupt as well as this pin with the oscilloscope.
At 15:20 I mixed micro with milliseconds. As you can see on the oscilloscope it is milliseconds
No big deal. It takes me an even longer time to wake up : )
Can you do a video on CAN bus? Also check out my channel if you want to see me build a two-legged walking robot. Enjoy
This inconsistency and delays you are showing is not a problem of ESP32, it's a problem of Arduino porting for ESP32. Just use ESP-IDF directly and redo the experiments - results will be completely different ;)
@@techfuture9846 The 150ms of delay after wakeup to actual code running is probably issue with bootloader.
@@movax20h, I'm talking about the pure interrupt response time, jitter, etc. The wakeup time is different beer.
How lucky we all are that these super well-produced, interesting and informative videos are available to view at our leisure. What a world we all live in! Thank You Andress!
Thank you for your nice words!
Truly. I am able to pursue a life passion project through stitching together knowledge from a collection of great youtubers, with Andreas a shining example. You make the world a better place :)
Agreed, great video!
This is the second video I've watched by Andreas, and I subscribed after watching the first few minutes of this. With so much bad information out there, this channel is a breath of fresh air. So much to unpack in this video. I'll be watching it again and again, thank you Andreas.
Welcome aboard the channel!
@@AndreasSpiess thanks Andreas, I have my seat in the front row
Thanks Andreas, you ever find the way to make it clear and easy to understand. The two channel osciloscope trick is really interesting, but this is part of your very high end workshop...
You could use a logic analyser, you can pick them up for cheap these days 👍
And 2 channel oscilloscopes are also quite cheap these days. No need for the one I have...
Brilliant video. Exactly what I wanted.
And excellent overview for the beginner or even the experienced.
I worked on embedded systems 15 years ago - we used microcontrollers, GPS, cellular comms, and used this to create telematics devices installed on John Deere and Liebherr equipment (and others). We read the CAN bus, and used interrupts for things like movement, engines turning on and other interrupts. Since then I've been doing product management, and now I'm getting back into this level of coding... and was depressed that Arduinos don't have good interrupts and sleep.
Your video has brought me back up to speed SUPER quickly, helping me restore my memory from tape, and quickly jumpstarting me with a new microcontroller board.
So have fun with your future projects!
As always a pleasure to watch. I like that you are not only focusing on hardware, but also explains how to utilize software to make project simple and easy to make
My pleasure!
Thank you ! Perfect timing ! We were just running into random crashes yesterday with our encoders running off ESP 8266. Cleaning up the interrupt functions based on your advises solved our issue ! For the little story, We are building a 4DOF motion platform using salvaged standing desk electric pistons and ESPs. Such a great content every time ! Thanks again !
Glad the video helped! Enjoy your project!
Great Topic, The ESP32 has so many new features, performance advantages and value over the Arduino. For the hobbyist, one platform can serve many projects . Your post make the transition worth attempting. Keep them coming!
And it has Wi-Fi, which the most important difference for me.
Great job of using the KISS principle, Keep It Simple S.... Silly. This is the most straight for explanation of ISRs, aka, AST as we know them on our beloved VAX-32s. Thanks for showing us all your amazing "scope" work! I'm REALLY enjoying your 2020 video's along with all the others, VERY HELPFUL!!!
Glad you like my stuff! I only sold VAX computers, I never programmed them :-(
At least the biggest I sold was a VAX9000 for 10 million Swiss Francs. At that time maybe 25 million dollars...
It would be interesting to see a video on using the ULP core for running code without waking up the ESP32. Would be nice to explore the possibilities and limitations of the ULP core.
Silly me, of course you have already made such a video! th-cam.com/video/-QIcUTBB7Ww/w-d-xo.html
Greetings from Turkey Andreas, I just wanted to thank you for all the great videos you have put out here on the channel. I can't imagine what I would do without you. Loved the cat btw :)
Thank you for your kind words!
Andreas, perhaps a followup comparing the interrupt coding and latency on other 'Arduinos' like STM32, SAMD21, ATMega, ATTiny, ESP8266, MK20DX (Teensy), SiFive E31 (HiFive1), etc.
This is a very special topic. So blogs are probably a better place for such comparisons.
Take a look into there datasheet and you can compare by your own.
@@ripper121 Ah yes, datasheets to find out about interrupts and how they affect everything... let me just quickly read for dozens of hours to compare a few µC...
Just seeing that a ESP32 is pretty much useless if you go into deep sleep is enough information.
@@leocurious9919 Really, that's a very specialized problem and different for each individual case, as Andreas said. Think about changing just one clock cycle in your application code changing the complete timing that is at issue here. It is best to simulate this for each individual case, better to test it as an experimental setup. If something is important for a preliminary decision, it is the limiting/rating values and the clock behavior that can be found in the data sheet.
So @Ripper121's remark is far more helpful than displaying one's own laziness.
Stay healthy:)
@@dieSpinnt It would be a perfect followup to this video. And for which videos does this not apply?
"displaying one's own laziness"
Thank you for the explanation... You are really making a valuable content. I'm already sitting in the first row waiting a next video.
Than) you!
Advanced topic explained with just enough info for practical use. Great job Andreas!
Thank you!, Hari.
Mr Spiess, I enjoy your presentations and like this one too. Thank you for all your effort and shared knowledge. There are several reasons why CPU like this one may have long interrupt latency. One of them (and it is a Real Time limitations of large processors like multicore Intel and ARM) is cache coherency. Simple, interrupt code maybe not present in cache and other current content of the cache need to be saved before reloading new one to/from RAM. For vary fast approach, user need to instruct compiler (I dont know how to do it at ESP32 yet) to keep interrupt service routine (if short) permanently in cache. This is typical approach for RT Linux for example.
You are right. There are a few other comments pointing in your direction,. too
Well done ! Indeed interesting, again I've learned something new.
That is my hope for every video. I also learned something unexpected about the ESP32
To experiment with measuring a higher frequency a (simple) hardware frequency divider could be added.
The frequency counter was just my example to demonstrate the two interrupts in one example.It was not meant to be useful...
Thank you for pointing me towards the Otii. Now have one and it is becoming an essential piece of kit. Especially now I’m investigating why my new custom board is using 1mA more than it should be
Glad I was helpful!
Thank you for another interesting and instructive video Andreas.
>edit: went through the comments and found this was already reported, sorry
I just wanted to add that RTOS seems indeed to be a culprit for the interrupt response latency and jitter. I think that attachInterrupt actually hooks up not to the interrupt controller but to an RTOS callback function. This function is entered the queue of RTOS tasks, and get executed after the completion of all the previous tasks only. Apparently it is possible to get a fast interrupt response when programming using noOS SDK from Espressif but I did not try this yet.
That's a mistake then. It's an interrupt and should have a higher priority than a normal task.
@Alexander: Maybe I will have once a closer look into RTOS...
I don’t get it… Arduino is by no means RTOS, and it has no callbacks or other real time capabilities
@@Quemedices684 ESP32 Arduino calls various functions that are built around Espresif's SDK that in turn uses RTOS for WiFi operations. If one does not need WiFi or software timers then no RTOS is involved indeed.
Ok, one thing: thank you for identing your code in a proper way!
I use ctrl-T ;-)
A great part of the inaccuracy in the interrupt code (at 7:13 in video) is caused by your own loop code:
{ frequency = count; display(0, "frequency=", frequency); lastEntry=millis(); count=0 }
You use count but reset it only after displaying on the pretty slow LCD. That means, all events that occur during the LCD operation are not counted, but lost. Also, if the duration of LCD output varies, it worsens the count precision. You could improve it if you first completed the job of count handling:
{ frequency = count; count=0; display(0, "frequency=", frequency); lastEntry=millis(); }
BTW, your polling loop (at 3:54 in video) would be more elegant if you replaced
lastentry= millis(); while (millis() < lastEntry + 1000) {...}
with
endTime=millis()+1000; while (millis() < endTime) {...}
This way the addition would be done only once. However a good compiler might catch this and produce the same binary code.
The compiler will figure out the optimization you mentioned at the end automatically. There will be no difference in performance. However, your hint about doing count=0; just after reading frequency is a valid one. In fact if you have mutexes used, you can wrap read and reset of the count, into critical block and be even safer. There are other approaches (like not resetting count at all, and remembering the last count, and subtracting it from current count to get new frequency (might require a special handling of overflows tho; but it will not need mutexes).
it is perfectly fine how he did it. even if the displaying took multiple seconds it wouldnt change anything since the lastEntry variable is changed just before resetting the counter. so it doesnt matter how many counts there were while communicating with the lcd.
correct me if i miss something though
@Andreas, I detach the interrupt at the beginning of the ISR on my Dimmer control, it's only 60Hz and an ESP8266 (today) but it did resolve the flickering I was facing at the edges turning on the off the light completely (and smoothly). Wifi has to be on and there is intense MQTT to keep dashboard as real time as possible, so if I miss a trigger at the edges I just complete the cycle one way or another. With this I could literally get the entire 1% to 99% (in a logarithm scale for real light scale) without bugs. Another great video from you. Cheers.
Interesting. I thought 60 Hz would be possible, especially on the non-Wi-Fi core.
I agree with your idea of being the RTOS influencing the interrupt latency. The RTOS itself (which seems to mee FreeRTOS reading the definitions you wrote to allow ISRs to be safely called) has surely some routines to schedule our loop() function with its own tasks, which can be in turn the communications module handlers (Wifi and/or Bluetooth). Even though you disable them, they could be still working for some reason. In addition the scheduler itself can use an interrupt to switch internal tasks, and this can be another jitter cause.
Many other commenters support this theory.
You are right again! But the main think is that the rest is perfect! My friend Hari is gonna love this - I love this sample also! Thank you Andreas!
You are welcome! I hope your lockdown also will end soon...
@@AndreasSpiess In god old NEBRASKA, we had a minimal closedown and even the mall open last Friday! I hope governments get smart and reopen everything ASAP! People will not go, if they are in the risk group, like me and my wife, since we don't want to get sick! People are much smarter than government thinks! I think we OVERDID this, but now is time to reopen everything and let business control everything they know how! I hope your finger gets well soon and you are also being able to do whatever you did before this crappy virus! Good luck and stay safe!
Love how you used Tishka in the video to illustrate the deep sleep example.
It was not hard to convince her to help in this project ;-)
Thanks a lot for your effort, your experiments, the video and the explanations. And we are now back to the same question we discussed when the ESP32 became availabe: How to use the different cores for different tasks in Arduino IDE , e.g. to decouple WiFi. Up to now I did not find a solution. This is why my counter at the water meter still uses 2 pcs ESP8266. One just for counting and tranferring data via HW-serial without any WiFi output and the second for analyzing the data and communication with my home automation system. Not very elegant, but runs very stable, uptime 657 days since the last blackout caused by road construction works.
I think this is a good concept. Or use a little HW for time critical tasks.
I did a great discovery when I found your channel with such professional analysis!
Welcome aboard the channel!
This video helped a lot! I wanted to monitor my PV panel energy harvesting using an ESP8266 and an arduino DUE (i know, not ebergy efficient but thats what I had lying around). Before th is video they were consuming 210mA and up to 250mA when publishing the measurements. Now i modified the sketch so that the DUE is always asleep (by pull down resistor on reset) and only wakes up for 3 sec (by the ESP) to measure and transmit the data to the ESP then go to sleep again. The ESP then (after connecting) publishes the data and goes to sleep for 20 sec or so. The result is that during sleep they both consume on 38mA and only 100mA when the ESP is awake. Only 3 seconds of 200mA now which easily runs this 24/7 on a single 18650 cell and for several days! Thanks for the insight!
Nice project!
Informative videos AND kitties!? What a combo!
Thank you! 😊
Just got my adafruit esp32 feather in the mail today first video I find is this and what a great video!
Enjoy your journey. You find a lot of ESP32 videos on this channel...
12:56 Why ++counter when previously counter++ was used ?
the processer shall not think he can predict programmers behavior ^v^
No particular reason other than to show it is possible for the non-programmer.
There is no difference when used standalone, both result in the same value. It only matters if you're evaluating the result in the same instruction, in which case counter++ will evaluate to the value before it's incremented, while ++counter will evaluate to the value after it's incremented.
@@dwmorris In C++ (that the Arduino IDE uses), as opposed to C, there is a potential significant difference between the post and prefix ++ and -- operators. This is partly due to operator overloading. This mostly affects performance, but the prefix operator is always guaranteed to be at least as fast as the postfix equivalent, assuming they are implemented semantically the same of course. It is therefore recommended to use the prefix variant unless one actually uses the pre-change value for something.
There is no difference. Even in C++. It is the same. Don't scratch your code about it unless you use C++ STL iterators (and even then it often will result in the same code, because compiler is smart enough), which you probably shouldn't on microcontroller anyway.
Very informative, thanks!! I will need this in near future, so it is just on time :)
Glad it was helpful!
Thank you Mr. Spiess for the interesting video.
Having started programming Microcontrollers with Arduinos and ESPs, and now programming Controllers on a professional level, the DIY embedded system community is filled with lack of skills: poor code because no real programming knowledge, lack of understanding of what is actually going on under the hood, ... . For example, one thing i noticed in professionally, is that i had to always master the controllers' documentations, i had to work on. This lead to the fact that most issues that you mentioned in the video simply can't happen (like polling the digitalread and delaying). I therefore really appreciate deep videos like yours, that aren't simply about repeating examples found online, but analyse and go behind the curtains.
He didn't delay, he used millis(). Take another look.
@Jules: Glad you like them.
Your videos are always excellent. By the way, If you want a low latency ISR on the ESP32, consider placing it in IRAM. (There is a flag you can put on the ISR definition to do this).
He already did that. I think the issue with ISR is due to arduino code, not ESP32. Also I don't think you really need the mutexes in ISR unless you manipulate more complex data structures from ISR. doing read-modify-write (like count++) from ISR, while rest of the code only do reads (so you might need to have two variables to track how much count you already processed, not reset it back to zero), is safe and doesn't require a mutex.
Is it possible to handle the interrupts with the second core?
maybe this fixes the high jitter on EXTI
It is possible, but I do not know why it would change. Maybe somebody tries?
@@AndreasSpiess The main core is running many background tasks, I believe the second core is completely idle, If RTOS is handling the interrupts (which it shouldn't) that's another story
@@AndreasSpiess I think the delay is due to other FreeRTOS tasks taking over. Running it on another code could help. You need to create a very high priority task on that core and disable the watchdog timer.
Ali Devrim OGUZ FreeRTOS seems to have a make menuconfig option to lock it to only the first core? would this assist after your interrupt suggestion?
also interested in other versions. wroom, wrover, (solo can’t be real-time), S2. Would love to have time to test them. Probably goes for all of us. Also need to invest in oscilloscope / dsi.
@@jrgalyen yeah that'll probably work too, however it may not let you run your program on the other core. I haven't tried that. I only saw the menu option to "not run the freertos on a single core"
Geat work Andeas, just purchased my first esp32 and I have a lot of catching up to do : )
Indeed. Enjoy!
Amazing, Herr Spiess! We can not thank you enough!
Glad you like it!
Very helpful video. I liked it
Glad to hear that
Andreas, nice video! Regarding start-up time: the ESP32 supports deep sleep wake stubs that are executed before any normal initialization. It can send the ESP back to sleep if for example the voltage of a connected battery is too low. I use this feature for undervoltage detection of a connected lipo battery (saving on an additional hardware component). Best
I mention that in the summary. Do you have an example for the Arduino IDE?
@@AndreasSpiess Sorry, missed that part! It is easy to implement in Arduino, as the default wake up stub function is weakly coupled and can be overwritten directly:
RTC_DATA_ATTR int bootCount = 0;
void RTC_IRAM_ATTR esp_wake_deep_sleep(void) {
esp_default_wake_deep_sleep();
bootCount++;
}
This increments the counter before the bootloader starts.
Greetings from Germany
Always a pleasure to watch your videos. Thanks for this on. I ran into some trubble appling the irq approach to a 100Hz signal with not as perfect steep flanks as in your given example. The isr gets triggered multiple times during rising and falling flanks. The RISING statemend seems to have no effect in the allocation of the irq. The esp32 seems to have problems with shallow flanked and slow signals. In such cases additional HW and Code is needed...
It is always good to have a Schmitt trigger in front of the interrupt input. Maybe you can disable the interrupt for a few ms in the ISR as a work around.
Great video, very informative. Thank you for all the work you put in to producing this.
My pleasure! Glad you liked it.
Andreas you are a treasure bro, thanks a lot
Thank you!
I'm currently using the ESP32 for a fft application on net voltage and load current signals (2 analogue channels, 50Hz), where I trigger a timer interrupt up to 1024 times per period, so ~ 100k samples/s on RTOS using both cores.
In my case I'm working with hardware interrupt each ~20ms which calculates a timer value for the real period time divided by 1024. This timer or counter calls another ISR every ~ 20µs.
In my opinion the ESP32 is fast enough for similar applications. But I'm totally agree with your point of the delay of hardware interrupts. Thanks for your research!
Quite a sophisticated application ;-) I use now a second RTOS task with a delay for my morsetrainer. Works fine (ms)
Very good summary Andreas, thanks.
Glad you liked it!
Amazingly presented, Just as I received my first ESP32 in the mail!
Enjoy!
Thank you for sharing your knowledge with community!
My pleasure!
I have an issue with ESP8266 in my weather and fertilization station where ESP8266 must exchange data with ATMEGA328 via I2C. What I found very strange is that ATMEGA328 can receive data from ESP8266 without any loss but ESP cannot receive any data from ATMEGA328 even if it runs at 80MHz which is 5 times faster than ATMEGA328. Is ESP8266 Interrup latency much slower than ATMEGA328's or is it due to Wifi and multitasking in ESP8266?. I tried sending data using Wire.write(), ATMEGA Master ESP Slave, and also tried I2C request mode where ESP is Master and ATMEGA is Slave. I also tried to reduce I2C frequency to the minimum (like 30 Khz) but nothing worked. Is "WIFI OFF" function available also in ESP8266? Can it solve the problem? Here a link to my web interface to my weather station:
www.abrobotics.be/siliconceptsarl/METEO/meteoframe.php
I cannot do remote debugging. But you can switch Wi-Fi off on the ESP8266. Maybe you use a logic analyzer for debugging? I once made a video about that.
@@AndreasSpiess Thanks Andreas for your reply. I tried switching off Wifi using WIFI_OFF at the beginning of ISR then WIFI_RESUME at the end of ISR but also it doesn't work. I will try to send from ATMEGA328 to ESP8266 using hardware Serial and Software Serial. As you suggested I will debug I2C using logic analogic. Unfortunatly I have it in my lab and I am now stuck in another city due to Corona virus.
At 7:08, I would recommend resetting count=0 right away, to improve accuracy.
The display() routine is time consuming, so events could be lost.
Yes, the display() routine is slow. That is why the last two lines have to be together. You also ca n put it in front of this routine. It will give the same result.
@@AndreasSpiess
Maybe I’m not understanding the code correctly. Please correct me if I’m wrong, but if an event happens during the display() routine, the counter would be incremented, and then later the counter would be reset, so those events would be lost?
@@AndreasSpiess
Ok, I think I get it now. Some events might be “lost” but because the lastEntry is also reset at the same time, those lost events wouldn’t change the frequency measurement, it would just be a “gap”.
I'm trying to make a simple project to count pulse of a water meter based reed switch. But the EMI causing issue when connect direct long wire to ESP32.
I can imagine. The ESP32 has a built-in radio transmitter. I put my ESPs close to the sensors and use Wi-Fi to bridge the distance.
Hello, your videos help me a lot, as I´m working with ESP32 for my Bachelor's thesis and there is not a lot of documentation out there. So thank you. :)
Are you using IDF or Arduino for developement ?
You are welcome!
What tool did you use to accurately measure the milliamp current consuption at 15:30? it does not appear in you link with the equipment you are using...
I made a few videos about current measurement and deep sleep. This is an OTII and sometimes I use a current ranger or microcurrent gold or Joulescope.
This is why I still rely on 8 bit / 16 bit PIC MCUs, they do a very good job at handling interrupts and have a simple way to hook a internal timer to an input pin so you can count very fast signals. It makes easier to implement control loops like PIDs. Only if I need a web server or something to do with WiFi I go for the ESP32. The ESP32 is not a Jack of all Trades.
The more I learn about the ESP32 the more I want to just stay away.
Most of my projects are connected these days. This is why I like the ESP32. But sometimes I also use an Arduino...
I think that right now the ESP32 is the most complete microcontroller when it comes to stay connected and also have massive processing power. But if you don't need connectivity there are better options out there than the ESP32. In the end we choose what we feel comfortable using...
If your running an RTOS then there will always be issues with when you get to see the interrupt. so i can see why the latency is changing, it depends where you interrupt arrives in the the background processes. Not sure if the ESP32 RTOS has variable time slots or fixed time slots so there could be issues there. In the embedded world there is a lot of effort to get an RTOS working correctly. Spent many a happy week on embedded RTOS courses, just to decide that if you don't need all that an RTOS offers then it best not to use one. Also interrupts are a pain for proving the code is safe, as how do you check all the possible places in your main code where it can get interrupted, don't get issues when interrupted at the point.
Nice thought provoking video as usual, thanks
You can process interrupts at higher priority (i.e. level 5, just before NMI level). By default ISR will be lowest priority (level 1), so it will be preempted and/or delayed by other routines like a task scheduler. It is possible to have stable latency and minimal jitter using FreeRTOS.
@8:00 In regards to a real time MCU, have you looked at the Ti CC3220/MSP430 and Ti RTOS?
No. I stick with my few MCUs because it is a lot of effort to add another one.
Very interesting and informative video as always. I don't know how to disable interrupts in arduino mode, but in bare-bone C/C++ or w/o rtos it is possible. I think that it would be quite interesting to compare the behavior / timing in bare-bone / arduino program.
For the moment I have no project with the need of those fast interrupts. So I will not follow up.
Hi. What a great video. I think you may have just solved my esp32 interrupt crashing issues. I will test your code tomorrow. FYI I'll be using it for a speedometer.
Update: the Frequency_Counter_with_Interrupt.ino seems to run fine. A little inaccurate at really low rpm (60rpm for example) but good at high rpm. Maybe some smoothing required. Now trying to use time between pulses so work out rpm. Not going to plan yet ;)
Your video is both useful and interesting. Great job!
Glad you think so!
Much appreciated by this guy with the Afrikaans accent!
You are welcome!
Another outstanding video, many thanks for your efforts
My pleasure!
I have a question at 10:50 you defined timerMUX, if I have 3 different interrupts i need to have 3 different lines like this one
portMUX_TYPE synch = portMUX_INITIALIZER_UNLOCKED; ??
I do not know, I only have very basic knowledge here. You have to ask somebody with more knowledge. I only used examples
@@AndreasSpiess Thanks! I have found this great article, but still no answer for this question
techtutorialsx.com/2017/09/30/esp32-arduino-external-interrupts/
@@AndreasSpiess I`m gonna do some tests and share my findings here
@@AndreasSpiess I used one of your codes to test if it is needed to declare multiple portMUX_TYPE variables, one for each ISR when you use multiple external interrupts.
I found out that using 2 or only 1 portMUX_TYPE variable the sketch worked fine, so I still don't know if it is needed. Here is the code:
/*
Test code for ISR function
I used and modify this code:github.com/SensorsIot/ESP32-Interrupts-deepsleep/blob/master/Frequency_Counterr_with_Interrupt/Frequency_Counterr_with_Interrupt.ino
I am using an ESP32 thing from adafruit
Test 1
create one portMUX_TYPE variable for each ISRs
Feed signals and see the outputs
Test 2
use only one portMUX_TYPE variable for the 2 ISRs
Feed signals and see the outputs
Results:
It did not matter if I use synch1 and synch2 or if I only use synch1
The 2 test showed the 2 interrupts seem to be working fine
Notes:
I don't have a signal generator or oscilloscope to check the signals
The 2 inputs were a floating cable on INPUTPIN2 and a
mechanical water flow meter (hall effect sensor) INPUTPIN2
The code for each test compiled without problems
*/
volatile int count1 = 0;
volatile int count2 = 0;
unsigned long lastEntry;
int frequency1, frequency2;
#define INPUTPIN1 15
#define INPUTPIN2 16
portMUX_TYPE synch1 = portMUX_INITIALIZER_UNLOCKED;
portMUX_TYPE synch2 = portMUX_INITIALIZER_UNLOCKED;
void IRAM_ATTR isr1() {
portENTER_CRITICAL(&synch1);
count1++;
portEXIT_CRITICAL(&synch1);
}
void IRAM_ATTR isr2() { // uncomment for first test
portENTER_CRITICAL(&synch2);
count2++;
portEXIT_CRITICAL(&synch2);
}
//void IRAM_ATTR isr2() { // uncomment for second test
// portENTER_CRITICAL(&synch1);
// count2++;
// portEXIT_CRITICAL(&synch1);
//}
void setup() {
Serial.begin(115200);
Serial.print("setup() running on core ");
Serial.println(xPortGetCoreID());
pinMode(INPUTPIN1, INPUT_PULLUP);
pinMode(INPUTPIN2, INPUT_PULLUP);
attachInterrupt(INPUTPIN1, isr1, RISING);
attachInterrupt(INPUTPIN2, isr2, RISING);
lastEntry = millis();
}
void loop() {
if (millis() > lastEntry + 1000) {
frequency1 = count1;
frequency2 = count2;
Serial.print("frec1: ");
Serial.println(frequency1);
Serial.print("frec12 ");
Serial.println(frequency2);
lastEntry = millis();
count1 = 0;
count2 = 0;
}
}
GREAT VIDEO!!!! Yes, it´s a penny that ESP32 is not good for Real Time applications. I´ve noticed the high Jitter on interrupts (Varying from 2 to 45us). It would be good if someone finds how to program the interrupt with *high Priority* even on assembler.
So far I do not know of such a project :-(
Very nice work! You should be quarantined more often.
Not a lot of change here. I am anyway living in my lab ;-)
Great overview of IRQ usage on esp32, thank you!
You are welcome!
Great video! Most of the programmers don't know that they should use more interrupts! It seems that you can't block the interrupts inside the isr.
There are some discussions going in other comments around "disable interrrupt" ;-)
@@AndreasSpiess yes i have read. Normaly if you learn interrupt programming, the first command in the ISR is that you mask the interrupts, that no other can block you. Only die NMI is allowed
Nice idea with the output pin debugging.
Thanks!
At 9:20 Andreas says interrupts cannot be disabled in ESP32. Is this still true? I have been inserting cli() and sei() into my code to disable and enable interrupts and the compiler does not complain, although I have not conducted any experiments to confirm interrupts are indeed disabled. noInterrupts() and Interrupts() is also accepted by the compiler. (I am using platformio)
I do not know for sure. I only found Ivan‘s answer.
It’s worth mentioning that the Wifi runs only on one core. If you run your app on the other core, it will not be affected
Interesting to know how you allocate cores to processes John. Will try and look that up.
@@Bennyboy-dog Andreas had mentioned it in his esp32 dual core video
hello good video thank you very much it helped me a lot
but I have a question
I have a set of multiple gpio as an interrupt pointing to the same ISR function, the question is how can I know which GPIO was activated by interrupt?
Or are there special methods to do this type of query?
I would add different ISRs for each interrupt and call a common function inside each one. Maybe there is also a register to find out which interrupt was triggered. But I do not know it.
Nice. To be fair, the ESP32 is running a very high level OS, FreeRTOS with changes. It doesn't have to run FreeRTOS, but you'll experience a great deal of trouble using Arduino or PlatformIO if you eliminate the OS. (You'd have to write a new core library) Something that might make a difference is to set the affinity of the ISR to the second core, which is unused by any code unless you explicitly force tasks over to it. I've never tried it, but it should be produce measurable improvement.
See esp32.com/viewtopic.php?f=2&t=10006
You are right. I usually just take what I have and check it out. I would probably use a different processor for real-time applications before I would start to mess around with the underlying infrastructure ;-)
@@AndreasSpiess I believe you'll have much better results w/ interrupt driven ESP32 tasks, working from Espressif's development environment. And you might have some limited success just forcing your loop function onto the unused core via xTaskCreatePinnedToCore(myLoop, ...). There's no reason why an ESP32's Xtensa cores can't handle what you were trying to do in this example, but the Arduino program model could be a limiting factor. I know...target audience. You're right, but the ESP32 is an AMAZING development board. I don't use it much, but only because I never need that much processing power. :o)
Hi Andreas. Please show example of a USB interrupt routine. The Arduino command "serialEvent()" dosent work with the ESP32? Im using windows and the Arduino software.
The standard ESP32 does not support USB. And serialEvent() has nothing to do with USB. So I do not understand your comment :-(
Another great video ❤
Thank you! I am glad you liked it.
I think that Timer0 is used by the underlaying FreeRtos as internal Tick source (behind the Arduino Sketch). Due to this, you are getting an "oversized" ISR and a long response time. You might try with timer 1 and check again the response time?
ISR TIMER0(
.... SystemTick (with context switch)
.... your ISR routine( with its context saving)
.... (context restore)
)
ISR TIMER1(
.... context saving
....your ISR routine
.... context restore
)
greetings from Argentina!
Thanks for the tip. For the moment I have no fast application. Maybe somebody else tries it?
at smt32 controllers existing interrupt priorities(interrupt in interrupts), maybe that helps with counting edges, when the EXTI is the most highest.
That is what most other CPUs have.
Can you do a video comparing interrupts, timers and tasks? how to use them, in which situation and speed limitation?
I do not know. I am not into video.
Andreas Spiess hehehe sorry I meant an episode ;)
Nice video you have!
I have a question for you if you can to help me. Can I make a wake up event with a touch sensor and in the same time I have timer wake up? I want to use this method to send the data through Wi-Fi(at every one hour) and touch sensor to wake up to see the values via Bluetooth? Or it's too much?
Here you find some info: randomnerdtutorials.com/esp32-touch-wake-up-deep-sleep/randomnerdtutorials.com/esp32-touch-wake-up-deep-sleep/
Maybe somebody has it already mentioned. You can shorten the interrupt reaction time by using high level interrupts. But you must implement it in assembly. LX instruction set is a little bit tricky and commonly not the right approach for people living in the Arduino world. But in generall it is pollible to improve the performance with this way.
Thank you for the additional info. You are the first mentioning it.
super nice Andreas, as usual: idea stolen for my next project: rpm of my noctua fan counted using your example ;-)
Sounds great!
Great video!
Question 🙋♂️ could you count frequency with an internal hardware counter? Are they cascadable so that you could at least use them for HF?
Thanks 😊 73…
You are right. You can use the internal counters either to count or to divide the frequency of the input signal. Here I did not want to build a fast counter, I only used it as a simple to understand example for interrupts.
@@AndreasSpiess Thanks for your replies; much appreciated 😃
Great video. One question: Do you have a schematic of how you hooked up the input signal and LCD display to the ESP32 as demonstrated in your video?
I do no more remember. But I am sure Google knows...
It would be lovely to have chapters in your videos!
They are probably too short and are made to be watched till the end (except mailbags which have chapters)
@@AndreasSpiess Andreas, for me your videos turn very quickly into references, and the chapters are excelent to go and check something again
You have a huge latency because your inrerrupt routine is actually a callback function. The real interrupt routine is hidden behind the assignInterrupt() finctionality. So there is a long execution chain: interrupt - lookup of assigned callback - callback execution
Is it possible to avoid this latency by using the ESP-IDF maybe?
Thanks for clarification!
Doesn't page 38 section 2.3.3 of The ESP32 Technical Reference Manual document how to use the Interrupt Matrix Controller to disable CPU interrupts? Another interesting video, by the way.
You are right. But I do not know how to do it in Arduino and also not the consequences (as Ivan points out in his blog entry)
@@AndreasSpiess Ah, ok, I use Platform IO. I'll try and have a look using it in Arduino IDE and see if I can find Ivans blog. Haven't found Ivans blog but have a look at "Assembly via Arduino (parts 1 and 2) - Introduction" you tube videos.
You did measured delay of interrupt. But is it really delay of interrupt or did you measure how long does it takes to evaluate portENTER_CRITICAL?
Also - volatile - should be used on shared variables - not on all variables in interrupt function (not sure if it is different for ESP32 - but just standard c++)
1. You are probably right with the volatile. But because it does not cost a lot I do it for all used in the ISR ;-)
2. I do not know where the delay is coming from. But it is not very important for me because I have to use this statement (at least this is my knowledge)
@@AndreasSpiess I'm more oriented on software development - and I have only ~2 years experience with raspberries or esp's :) At work I'm working on application used by tens of millions - so I know what threading issues are (any small chance to happen - it will happen :) )
So I just wonder if portENTER_CRITICAL is not just going "safe" when interrupt and main program do things on same ports - it is ok for "counters" or so but not for quick reaction - like frequency counting ... If it does not cause crash, lost of dat or so - it may be ok to omit that
I'm going to use this method for weather station - as counter of revelations caused by wind - so for me it would be ok :)
But one think I also understand - if manufacturer wrote it in manual - it may be wise to use it anyway because later changes may break my program (after using new chip or recompiling with some new libraries) - and then it is hard to find problem
Bravo ! Another wonderful video.
Many thanks!
I want to use the esp32 to read CSV values and push out pixels led data. I'm using castles library. I Can't go above 1000 pixels , the esp crashes 😢. Please help me out.
I'm using the dual core feature of the esp. One task reads the data from micro SD card. The other task waits till the whole frame is loaded and then pushes the data to pixels. Some times watchdog error occurs , ( task gets starvation).I'm also utilising sema fore for the task syncing.
I never did this, so I have no knowledge.
@@AndreasSpiess can u try it
Mr Andreas, thanks for the video.
I have a project that extensively uses interrupts. It uses 8 water flow meters to measure water consumption. I have always used portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; in my code without actually understanding its function.
I saw you are using portMUX_TYPE sync = portMUX_INITIALIZER_UNLOCKED; Tried to search for the differences but failed to find relevant explanations. Why MUX or SYNC and when to use one or the other? Thanks in advance.
That is just a variable name, you could use portMUX_TYPE potato = portMUX_INITIALIZER_UNLOCKED; just refer to the same variable name in your ISR's portENTER_CRITICAL(&potato) and portEXIT_CRITICAL(&potato) calls.
How long is the maximum time the timer can sleep?
Very long (days, if I remember right)
Great info! thank you. I'll def use this next time.
Glad it was helpful!
Andreas, I think your interrupt latency problem is caused by using the straightjacket and rubber room of the Arduino attachInterrupt() instead of using the ESP IDF's esp_intr_alloc(). Finding the definition of the attachInterrupt was a real pain-- google failed, but I finally found github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-gpio.c .
I think by default, you are getting a level 1 (lowest) interrupt, so other interrupts will interfere. You can get level 3 with some flags in the esp_intr_alloc(), but to reduce latency you'd need to use level 5 (Timer.2 uses level 5) and this level requires an assembly ISR (not C callable). If you only modify the counter in the ISR and it is word-aligned, then you shouldn't need to worry about portEnter (but you can use esp_intr_disable()), and you can run the ISR in the other CPU. In assembly, your ISR only needs to increment the counter and return from interrupt.
Perhaps having a low-level interrupt wouldn't matter running on the second core. It would be interesting to see your latency on the scope running on the second CPU. I assume it's not used by the RTOS except maybe timers?
It would be interesting for you to make a followup video demonstrating how to use a high priority (level 5) interrupt with a short assembly handler running in the second CPU, and see how high of a frequency you can get.
Also, I came across this: github.com/MacLeod-D/ESp32-Fast-external-IRQs where he uses dedicated polling on core 1 and claims >3MHz counting.
Thank you for the links. I just was surprised, I have no particular project for eh moment...
Very well explained in detail
Glad it was helpful!
@1:50 I don't know Mr. Spiess... Dishka's face doesn't look like she wants to be used as example.
She has to earn her food just as everybody else in the family. Tough times ;-)
Verv interesting Video.
The main difference i normally do on similar Programs i don't reset the counter Variable, but use the difference to the Value of this Variable from the last read. This only works when the difference is smaller then half of the maximum value possible with this variable ( 2^31 with 32 Bit Systems ), so wraparounds are always result in differences in this Range.
Resetting the Variable is only safely possible when the changing of the Count-Variable can not be interrupted ( this is true when changing this Value is a single command on the Processor, The Processor has some means of binding more commands together in an non-Interruptible way - even across multiple Processors, or you can use for example critical sections ) Otherwise the ISR might be interrupted in between reading the Variable and writing it back after changing it - so the reset Variable will be overwritten.
Thank you for the tip!
What competitors to the ESP32 are optimised for a fast wake up?
There are not many other MPUs with WiFi. Without WiFi you can watch my videos about STM32
Howdy Andreas, Thanks for your videos. I needed better than 200khz latency so I used HLI's and that got me better than 2MHZ latency. So the ESP32 can do better than 200khz. I've tried to provide a link to source code and write up on my Medium page but seems youtube deletes it. Thanks for all your great content.
Good to know. But probably not for everybody (I think I saw your issues on the Expressif page ;-)
Links, unfortunately, are removed by TH-cam. They changed their policy :-(
This may be a dumb request, but I went to buy a couple of ESP32 boards, so as to get some basic familiarity with them for future development work, but ... well, hundreds of different models are available - and I was overcome with analysis paralysis, and had no idea what to order. So, I closed the tab and did other things. Would it be possible to get some kind of basic guide / idea of what to look for when purchasing as an ESP32 n00b?
I made some ESP32 comparison videos in the past
@@AndreasSpiess Oh, cool, thank you. I will have a look through your back catalogue. Keep safe. :-)
Sir have you tried measuring domestic AC supply with 50Hz ? I guess ESP32 interrupts are unable to work at slower frequencies and gave false triggers... Please provide your opinion.
You have to condition the signal before you feed it to an ESP or any other microchip (zero-crossing). It expects a steep rise or fall of the signal which is not the case for a sine wave. The ESP has no problems with slow signals.
@@AndreasSpiess I had used an Optocoupler for zero crossing and it seems to work fine for arduino with interrupt and also for esp32 it works with your state machine code but when using esp interrupt code.. It shows false triggers.
A little off topic but... When using the ext1 deep sleep wake, is it possible to use an IF statement to perform tasks based on which of the buttons woke the esp?
It should be possible to read the pins with digital read as one of the first actions after wake-up
@@AndreasSpiess thank you for the quick response, definitely an option, but I was only using a single pulse as not to cause multiple wake ups.
As the esp prints the GPIO I thought it may be an option to do something like below:
IF(GPIO_WAKE_REASON==GPIO2){
TASK ONE
}
ELSE IF(GPIO_WAKE_REASON==GPIO15){
TASK TWO
}
ELSE{
esp sleep enable ext1
Esp deep sleep start
}
Can the ESP32 store data if there is a loss of connection? In other words, can I configure it as an MQTT client with QoS 1?
🤔
Yes. It has EEPROM functionality for longtime storage.
@@AndreasSpiess thank you so much
🤩
Hi, I'm I the only one having a problem with the ESP32 on a LoRa TTGO T3 board ?
I use interrups to count pulses coming from an anemometer and a rain sensor. So quite slow.
No matter what I do, the ESP counts FALLING AND RISING edges, despite that I asked to detect only FALLING edges.
I debounced the input signal, but I clearly see that it counts twice !
Any advice ?
BTW, nice tutorial as usual ! Do you sleep sometimes ? 😁
I am not good in remote debugging, particularly in such difficult situations :-( If not already done, I would create a simple example that moves one pin in the interrupt and watch the interrupt as well as this pin with the oscilloscope.
I wonder how precise the ESP32 timer interrupt is?
Very precise. The delay and jitter is due to software issues with the code really.