Use this forum to chat about hardware specific topics for the ESP8266 (peripherals, memory, clocks, JTAG, programming)

User avatar
By dkinzer
#24771 After looking at the hw_timer.c example code, it occurred to me that the second timer of the RTC could be used to get better resolution for timing application events. Normally, it appears that Timer2 is configured to divide the CPU frequency by 256 but if the app calls system_timer_reinit() the divisor gets changed to 16. That means that when running at the default 80MHz speed, the Timer2 COUNT register changes at a 5MHz rate. Consequently, by determining the change in the Timer2 COUNT register between one event and another your app can compute the elapsed time with 200nS resolution.

The sample application below gives a simple example of using the Timer2 COUNT register to determine elapsed time.
Code: Select all#include <stdint.h>
#include "ets_sys.h"
#include "osapi.h"
#include "os_type.h"
#include "user_config.h"

#if !defined(FRC2_COUNT_ADDRESS)
  #define FRC2_COUNT_ADDRESS       0x24
#endif

os_event_t    user_procTaskQueue;
static void user_procTask(os_event_t *events);

uint32_t lastTick;
uint8_t firstTime = 1;
uint16_t state;

static void ICACHE_FLASH_ATTR
myTask(os_event_t *events)
{
    if (state == 0)
    {
        uint32_t curTick = RTC_REG_READ(FRC2_COUNT_ADDRESS);
        if (firstTime)
            firstTime = 0;
        else
        {
            // the RTC Timer2 is running at 1/16th of the main clock frequency, i.e. 5MHz
            uint32_t delta = curTick - lastTick;
            os_printf("current tick is %u, elapsed time is %u microseconds\r\n", curTick, delta / 5);
        }
        lastTick = curTick;
    }
    if (++state >= 1000)
        state = 0;

    // delay 1mS
    os_delay_us(1000);
    system_os_post(0, 0, 0);
}

void ICACHE_FLASH_ATTR
user_rf_pre_init(void)
{
}

void ICACHE_FLASH_ATTR
user_init()
{
    state = 0;

    // reset the RTC Timer2 for 200nS resolution
    system_timer_reinit();

    // set the baud rate
    uart_div_modify(0, UART_CLK_FREQ / 115200);

    // arrange to run the user task
    system_os_task(myTask, 0, &user_procTaskQueue, 1);
    system_os_post(0, 0, 0);
}

It should be noted that the Timer2 COUNT register wraps to zero approximately every 859 seconds when using the divide-by-16 prescaler. The code above works correctly across a wrap boundary due to the characteristics of two's complement arithmetic. However, there may be use cases where your code will need to detect wraparound and handle it specially.