/* esp/timer_regs.h * * ESP8266 Timer register definitions * * Not compatible with ESP SDK register access code. */ #ifndef _ESP_TIMER_REGS_H #define _ESP_TIMER_REGS_H #include "esp/types.h" #include "common_macros.h" #define TIMER_BASE 0x60000600 #define TIMER(i) (*(struct TIMER_REGS *)(TIMER_BASE + (i)*0x20)) #define TIMER_FRC1 TIMER(0) #define TIMER_FRC2 TIMER(1) /* TIMER registers * * ESP8266 has two hardware timer counters, FRC1 and FRC2. * * FRC1 is a 24-bit countdown timer, triggers interrupt when reaches zero. * FRC2 is a 32-bit countup timer, can set a variable match value to trigger an interrupt. * * FreeRTOS tick timer appears to come from XTensa core tick timer0, * not either of these. FRC2 is used in the FreeRTOS SDK however. It * is set to free-run, interrupting periodically via updates to the * ALARM register. sdk_ets_timer_init configures FRC2 and assigns FRC2 * interrupt handler at sdk_vApplicationTickHook+0x68 */ struct TIMER_REGS { // FRC1 FRC2 uint32_t volatile LOAD; // 0x00 0x20 uint32_t volatile COUNT; // 0x04 0x24 uint32_t volatile CTRL; // 0x08 0x28 uint32_t volatile STATUS; // 0x0c 0x2c uint32_t volatile ALARM; // 0x30 }; _Static_assert(sizeof(struct TIMER_REGS) == 0x14, "TIMER_REGS is the wrong size"); #define TIMER_FRC1_MAX_LOAD 0x7fffff /* Details for LOAD registers */ /* Behavior for FRC1: * * When TIMER_CTRL_RELOAD is cleared in TIMER(0).CTRL, FRC1 will * reload to its max value once underflowed (unless the load * value is rewritten in the interrupt handler.) * * When TIMER_CTRL_RELOAD is set in TIMER(0).CTRL, FRC1 will reload * from the load register value once underflowed. * * Behavior for FRC2: * * If TIMER_CTRL_RELOAD is cleared in TIMER(1).CTRL, writing to * this register will update the FRC2 COUNT value. * * If TIMER_CTRL_RELOAD is set in TIMER(1).CTRL, the behaviour * appears to be the same except that writing 0 to the load register * both sets the COUNT register to 0 and disables the timer, even if * the TIMER_CTRL_RUN bit is set. * * Offsets 0x34, 0x38, 0x3c all seem to read back the LOAD_REG value * also (but have no known function.) */ /* Details for CTRL registers */ /* Observed behaviour is like this: * * * When TIMER_CTRL_INT_HOLD is set, the interrupt status bit * TIMER_CTRL_INT_STATUS remains set when the timer interrupt * triggers, unless manually cleared by writing 0 to * TIMER(x).STATUS. While the interrupt status bit stays set * the timer will continue to run normally, but the interrupt * (INUM_TIMER_FRC1 or INUM_TIMER_FRC2) won't trigger again. * * * When TIMER_CTRL_INT_HOLD is cleared (default), there's no need to * manually write to TIMER(x).STATUS. The interrupt status bit * TIMER_CTRL_INT_STATUS automatically clears after the interrupt * triggers, and the interrupt handler will run again * automatically. */ /* The values for TIMER_CTRL_CLKDIV control how many CPU clock cycles amount to * one timer clock cycle. For valid values, see the timer_clkdiv_t enum below. */ /* TIMER_CTRL_INT_STATUS gets set when interrupt fires, and cleared on a write * to TIMER(x).STATUS (or cleared automatically if TIMER_CTRL_INT_HOLD is not * set). */ #define TIMER_CTRL_INT_HOLD BIT(0) #define TIMER_CTRL_CLKDIV_M 0x00000003 #define TIMER_CTRL_CLKDIV_S 2 #define TIMER_CTRL_RELOAD BIT(6) #define TIMER_CTRL_RUN BIT(7) #define TIMER_CTRL_INT_STATUS BIT(8) typedef enum { TIMER_CLKDIV_1 = 0, TIMER_CLKDIV_16 = 1, TIMER_CLKDIV_256 = 2, } timer_clkdiv_t; /* Details for STATUS registers */ /* Reading this register always returns the value in * TIMER(x).LOAD * * Writing zero to this register clears the FRC1 * interrupt status. */ /* Details for FRC2.ALARM register */ /* Interrupt match value for FRC2. When COUNT == ALARM, the interrupt fires. */ #endif /* _ESP_TIMER_REGS_H */