Migration from Arduino IDE to ESP-IDF

lmarmisa
Posts: 9
Joined: Tue Jun 27, 2017 12:20 pm

Migration from Arduino IDE to ESP-IDF

Postby lmarmisa » Thu Jul 27, 2017 9:24 am

Arduino IDE for ESP32 has some important limitations. So I decided to migrate to ESP-IDF.

I installed Arduino as ESP-IDF component as first step for this purpose:

https://github.com/espressif/arduino-es ... -component

But this solution was not completely successful. I got some troubles when I tried to define a custom partition table and with the integration of components written in C and C++ (for example, spiffs).

So, I would like to move my project to ESP-IDF with no Arduino components.

But this is easy so say but difficult to do. My main problem is the lack of documentation. A lot of time is lost trying to find useful information.

I need to develop a couple of routines for the measurement of microseconds and milliseconds similar to the Arduino functions micros() and millis(). I suppose that these functions are not available in ESP-IDF. Therefore, I have to write my own functions.

I believe that I have to use one or two hardware timers:

https://esp-idf.readthedocs.io/en/lates ... timer.html

But I ignore if some of those timers are being used by the ESP-IDF system ( RTOS, tick, etc). I would like to know which ESP32 hardware resources are assigned to ESP-IDF and which others are available for apps.

My particular question is simple: which timer(s) should I use for programing my functions millis() and micros()?.

My current problem is related to timers but probably this is not the only case where the system is allocating hardware resources that are not available for apps.

Thanks in advance for your help.

f.h-f.s.
Posts: 215
Joined: Thu Dec 08, 2016 2:53 pm

Re: Migration from Arduino IDE to ESP-IDF

Postby f.h-f.s. » Thu Jul 27, 2017 1:50 pm


ESP_igrr
Posts: 2072
Joined: Tue Dec 01, 2015 8:37 am

Re: Migration from Arduino IDE to ESP-IDF

Postby ESP_igrr » Thu Jul 27, 2017 1:53 pm

The suggested way of obtaining time is POSIX gettimeofday function (and you can set time using settimeofday).

Both Timer Group peripherals are also available for applications to use, ESP-IDF does not use them internally.

lmarmisa
Posts: 9
Joined: Tue Jun 27, 2017 12:20 pm

Re: Migration from Arduino IDE to ESP-IDF

Postby lmarmisa » Thu Jul 27, 2017 3:05 pm

f.h-f.s. wrote:Can you use the same implementation as arduino?
millis() https://github.com/espressif/arduino-es ... misc.c#L50
micros() https://github.com/espressif/arduino-es ... misc.c#L33
Hi f.h-f.s,

Hmmm. Your proposal seems interesting but it requires an important knowledge about the internal Xtensa microprocessor architecture and how it works.

Code: Select all

unsigned long IRAM_ATTR micros()
{
    static unsigned long lccount = 0;
    static unsigned long overflow = 0;
    unsigned long ccount;
    portENTER_CRITICAL_ISR(&microsMux);
    __asm__ __volatile__ ( "rsr     %0, ccount" : "=a" (ccount) );
    if(ccount < lccount){
        overflow += UINT32_MAX / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ;
    }
    lccount = ccount;
    portEXIT_CRITICAL_ISR(&microsMux);
    return overflow + (ccount / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ);
}
I love assembler languages :D . I worked with them many years ago. Unfortunately I have very few knoledge about the Xtensa LX6 microprocessor.

I am not sure if I understand this instruction:

Code: Select all

__asm__ __volatile__ ( "rsr     %0, ccount" : "=a" (ccount) );
rsr seems the mnemonic of "read special register". Apparently the special register %0 is read and assigned to the variable ccount (uint32_t). But, what is %0?. A register counting the cpu clock edges?. Is this a standard feature of the CPU or it have to be configured?.

Yes. I can copy the code and test if it works but I would like to know a little bit of theory before to start the test.

Thanks for your contribution.
Last edited by lmarmisa on Thu Jul 27, 2017 3:15 pm, edited 1 time in total.

f.h-f.s.
Posts: 215
Joined: Thu Dec 08, 2016 2:53 pm

Re: Migration from Arduino IDE to ESP-IDF

Postby f.h-f.s. » Thu Jul 27, 2017 3:12 pm

i think %0 is NULL

lmarmisa
Posts: 9
Joined: Tue Jun 27, 2017 12:20 pm

Re: Migration from Arduino IDE to ESP-IDF

Postby lmarmisa » Thu Jul 27, 2017 3:32 pm

ESP_igrr wrote:The suggested way of obtaining time is POSIX gettimeofday function (and you can set time using settimeofday).

Both Timer Group peripherals are also available for applications to use, ESP-IDF does not use them internally.
Hi ESP_igrr,

thanks for your information.

At this time my interest is related to a function similar to micros(). I need such function for the measurement of the duration of very short events.

The hardware timers look a very promising solution. They are 64-bit generic timers based on 16-bit pre-scalers and 64-bit auto-reload-capable up/down counters. Using the pre-scaler I wish to count with a frequency of 1 MHz (counting up from zero). 64 bit counter is great because there is no problem related to overflow during a half million years. :lol:

ESP_igrr
Posts: 2072
Joined: Tue Dec 01, 2015 8:37 am

Re: Migration from Arduino IDE to ESP-IDF

Postby ESP_igrr » Thu Jul 27, 2017 10:29 pm

In the inline assembly block, %0 is the reference to the first register in the capture list (given after the assembly statement); and count is the name of the special register. The whole thing looks a bit confusing because both the special register and the variable have the same name.

f.h-f.s.
Posts: 215
Joined: Thu Dec 08, 2016 2:53 pm

Re: Migration from Arduino IDE to ESP-IDF

Postby f.h-f.s. » Fri Jul 28, 2017 6:11 am

oeh ok, xD good to know

lmarmisa
Posts: 9
Joined: Tue Jun 27, 2017 12:20 pm

Re: Migration from Arduino IDE to ESP-IDF

Postby lmarmisa » Fri Jul 28, 2017 8:19 am

ESP_igrr wrote:In the inline assembly block, %0 is the reference to the first register in the capture list (given after the assembly statement); and count is the name of the special register. The whole thing looks a bit confusing because both the special register and the variable have the same name.
Yes. I noticed that the name of the special register is ccount (cycle count register). The assembler statement uses a local variable with the same name for storing the read value. Not so confusing now.

Code: Select all

unsigned long IRAM_ATTR micros()
{
    static unsigned long lccount = 0;
    static unsigned long overflow = 0;
    unsigned long ccount;
    portENTER_CRITICAL_ISR(&microsMux);
    __asm__ __volatile__ ( "rsr     %0, ccount" : "=a" (ccount) );
    if(ccount < lccount){
        overflow += UINT32_MAX / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ;
    }
    lccount = ccount;
    portEXIT_CRITICAL_ISR(&microsMux);
    return overflow + (ccount / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ);
}
I have still a doubt. Why a critical section where the interrupts are disabled?. It's really necessary even in the case of nested ISRs?.

Rollover is a potential problem too. The rollover period is only 17 sec if the standard CPU frequency of 240 MHz is selected. Really a bit short time compared with a 64 bit hardware timer solution.

My first test of micros() was positive. Apparently it works just like in the Arduino environment.

I have to check the alternative solution base on a hardware timer. I have detected a little problem. The function timer_get_counter_value() (esp-idf/components/driver(timer.c) is not defined with the IRAM_ATTR option. Therefore a workaround will be necessary for calling the function millis64() from a interrupt handler routine. Nothing important, I guess.

ESP_igrr
Posts: 2072
Joined: Tue Dec 01, 2015 8:37 am

Re: Migration from Arduino IDE to ESP-IDF

Postby ESP_igrr » Fri Jul 28, 2017 8:40 am

I have still a doubt. Why a critical section where the interrupts are disabled?. It's really necessary even in the case of nested ISRs?.
This is because the code modifies static variables. If micros is called from two CPUs around the same time, or if an ISR could preempt a call to micros and call micros again, these variables could be set to inconsistent values. To prevent this, a critical section is used.
Therefore a workaround will be necessary for calling the function millis64() from a interrupt handler routine.
This is not the case in ESP-IDF, in general. The interrupt code needs to be in IRAM only if you use ESP_INTR_FLAG_IRAM flag when allocating an interrupt. If you don't use this flag, you can place your interrupt code into flash.

Also, it may not be the right solution for your case, but just for others who might be reading this later: gettimeofday returns time with microsecond precision, and handles wraparounds correctly, so it can be used in place of micros as well.

Who is online

Users browsing this forum: Bing [Bot] and 72 guests