Hardware timer support
This commit is contained in:
parent
5151ccc3b2
commit
1d72ed3f70
8 changed files with 527 additions and 4 deletions
35
core/esp_timer.c
Normal file
35
core/esp_timer.c
Normal file
|
@ -0,0 +1,35 @@
|
|||
/* Timer peripheral management functions for esp/timer.h.
|
||||
*
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2015 Superhouse Automation Pty Ltd
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include <esp/timer.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
* These are the runtime implementations for functions that are linked in if any of
|
||||
* the arguments aren't known at compile time (values are evaluated at
|
||||
* compile time otherwise.)
|
||||
*/
|
||||
uint32_t _timer_freq_to_count_runtime(const timer_frc_t frc, const uint32_t freq, const timer_div_t div)
|
||||
{
|
||||
return _timer_freq_to_count_impl(frc, freq, div);
|
||||
}
|
||||
|
||||
uint32_t _timer_time_to_count_runtime(const timer_frc_t frc, uint32_t us, const timer_div_t div)
|
||||
{
|
||||
return _timer_time_to_count_runtime(frc, us, div);
|
||||
}
|
||||
|
||||
bool _timer_set_frequency_runtime(const timer_frc_t frc, uint32_t freq)
|
||||
{
|
||||
return _timer_set_frequency_runtime(frc, freq);
|
||||
}
|
||||
|
||||
bool _timer_set_timeout_runtime(const timer_frc_t frc, uint32_t us)
|
||||
{
|
||||
return _timer_set_timeout_impl(frc, us);
|
||||
}
|
|
@ -117,6 +117,8 @@ typedef enum {
|
|||
extern void gpio_interrupt_handler(void);
|
||||
|
||||
/* Set the interrupt type for a given pin
|
||||
*
|
||||
* If int_type is not INT_NONE, the gpio_interrupt_handler will be attached and unmasked.
|
||||
*/
|
||||
INLINED void gpio_set_interrupt(const uint8_t gpio_num, const gpio_interrupt_t int_type)
|
||||
{
|
||||
|
@ -128,4 +130,10 @@ INLINED void gpio_set_interrupt(const uint8_t gpio_num, const gpio_interrupt_t i
|
|||
}
|
||||
}
|
||||
|
||||
/* Return the interrupt type set for a pin */
|
||||
INLINED gpio_interrupt_t gpio_get_interrupt(const uint8_t gpio_num)
|
||||
{
|
||||
return (gpio_interrupt_t)(GPIO_CTRL_REG(gpio_num) & GPIO_INT_MASK);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -159,15 +159,17 @@ typedef volatile uint32_t *esp_reg_t;
|
|||
|
||||
/* Load value for FRC1, read/write.
|
||||
|
||||
When TIMER_CTRL_RELOAD is cleared in TIMER_FRC1_CTRL_REG, FRC1
|
||||
will reload to 0x7fffff once overflowed (unless the load value is
|
||||
rewritten in the interrupt handler.)
|
||||
When TIMER_CTRL_RELOAD is cleared in TIMER_FRC1_CTRL_REG, FRC1 will
|
||||
reload to TIMER_FRC1_MAX_LOAD once overflowed (unless the load
|
||||
value is rewritten in the interrupt handler.)
|
||||
|
||||
When TIMER_CTRL_RELOAD is set in TIMER_FRC1_CTRL_REG, FRC1 will reload
|
||||
from the load register value once overflowed.
|
||||
*/
|
||||
#define TIMER_FRC1_LOAD_REG _REG(TIMER_BASE, 0x00)
|
||||
|
||||
#define TIMER_FRC1_MAX_LOAD 0x7fffff
|
||||
|
||||
/* Current count value for FRC1, read only? */
|
||||
#define TIMER_FRC1_COUNT_REG _REG(TIMER_BASE, 0x04)
|
||||
|
||||
|
@ -254,7 +256,7 @@ typedef volatile uint32_t *esp_reg_t;
|
|||
|
||||
/* Timer auto-reload bit
|
||||
|
||||
This bit interacts with TIMER_FCR1_LOAD_REG & TIMER_FCR2_LOAD_REG
|
||||
This bit interacts with TIMER_FRC1_LOAD_REG & TIMER_FRC2_LOAD_REG
|
||||
differently, see those registers for details.
|
||||
*/
|
||||
#define TIMER_CTRL_RELOAD BIT(6)
|
||||
|
|
138
core/include/esp/timer.h
Normal file
138
core/include/esp/timer.h
Normal file
|
@ -0,0 +1,138 @@
|
|||
/** esp/timer.h
|
||||
*
|
||||
* Timer (FRC1 & FRC2) functions.
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2015 Superhouse Automation Pty Ltd
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#ifndef _ESP_TIMER_H
|
||||
#define _ESP_TIMER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <xtensa_interrupts.h>
|
||||
#include "esp/registers.h"
|
||||
#include "esp/cpu.h"
|
||||
|
||||
typedef enum {
|
||||
TIMER_FRC1,
|
||||
TIMER_FRC2,
|
||||
} timer_frc_t;
|
||||
|
||||
/* Return current count value for timer. */
|
||||
INLINED uint32_t timer_get_count(const timer_frc_t frc);
|
||||
|
||||
/* Return current load value for timer. */
|
||||
INLINED uint32_t timer_get_load(const timer_frc_t frc);
|
||||
|
||||
/* Write load value for timer. */
|
||||
INLINED void timer_set_load(const timer_frc_t frc, const uint32_t load);
|
||||
|
||||
/* Returns maximum load value for timer. */
|
||||
INLINED uint32_t timer_max_load(const timer_frc_t frc);
|
||||
|
||||
typedef enum {
|
||||
TIMER_DIV1,
|
||||
TIMER_DIV16,
|
||||
TIMER_DIV256,
|
||||
} timer_div_t;
|
||||
|
||||
/* Set the timer divider value */
|
||||
INLINED void timer_set_divider(const timer_frc_t frc, const timer_div_t div);
|
||||
|
||||
/* Enable or disable timer interrupts
|
||||
|
||||
This both sets the xtensa interrupt mask and writes to the DPORT register
|
||||
that allows timer interrupts.
|
||||
*/
|
||||
INLINED void timer_set_interrupts(const timer_frc_t frc, bool enable);
|
||||
|
||||
/* Turn the timer on or off */
|
||||
INLINED void timer_set_run(const timer_frc_t frc, const bool run);
|
||||
|
||||
/* Get the run state of the timer (on or off) */
|
||||
INLINED bool timer_get_run(const timer_frc_t frc);
|
||||
|
||||
/* Set timer auto-reload on or off */
|
||||
INLINED void timer_set_reload(const timer_frc_t frc, const bool reload);
|
||||
|
||||
/* Get the auto-reload state of the timer (on or off) */
|
||||
INLINED bool timer_get_reload(const timer_frc_t frc);
|
||||
|
||||
/* Return a suitable timer divider for the specified frequency,
|
||||
or -1 if none is found.
|
||||
*/
|
||||
INLINED timer_div_t timer_freq_to_div(uint32_t freq);
|
||||
|
||||
/* Return the number of timer counts to achieve the specified
|
||||
* frequency with the specified divisor.
|
||||
*
|
||||
* frc parameter is used to check out-of-range values for timer size.
|
||||
*
|
||||
* Returns 0 if the given freq/divisor combo cannot be achieved.
|
||||
*
|
||||
* Compile-time evaluates if all arguments are available at compile time.
|
||||
*/
|
||||
INLINED uint32_t timer_freq_to_count(const timer_frc_t frc, uint32_t freq, const timer_div_t div);
|
||||
|
||||
/* Return a suitable timer divider for the specified duration in
|
||||
microseconds or -1 if none is found.
|
||||
*/
|
||||
INLINED timer_div_t timer_time_to_div(uint32_t us);
|
||||
|
||||
/* Return the number of timer counts for the specified timer duration
|
||||
* in microseconds, when using the specified divisor.
|
||||
*
|
||||
* frc paraemter is used to check out-of-range values for timer size.
|
||||
*
|
||||
* Returns 0 if the given time/divisor combo cannot be achieved.
|
||||
*
|
||||
* Compile-time evaluates if all arguments are available at compile time.
|
||||
*/
|
||||
INLINED uint32_t timer_time_to_count(const timer_frc_t frc, uint32_t us, const timer_div_t div);
|
||||
|
||||
/* Set a target timer interrupt frequency in Hz.
|
||||
|
||||
For FRC1 this sets the timer load value and enables autoreload so
|
||||
the interrupt will fire regularly with the target frequency.
|
||||
|
||||
For FRC2 this sets the timer match value so the next interrupt
|
||||
comes in line with the target frequency. However this won't repeat
|
||||
automatically, you have to call timer_set_frequency again when the
|
||||
timer interrupt runs.
|
||||
|
||||
Will change the timer divisor value to suit the target frequency.
|
||||
|
||||
Does not start/stop the timer, you have to do this manually via
|
||||
timer_set_run.
|
||||
|
||||
Returns true on success, false if given frequency could not be set.
|
||||
|
||||
Compile-time evaluates to simple register writes if all arguments
|
||||
are available at compile time.
|
||||
*/
|
||||
INLINED bool timer_set_frequency(const timer_frc_t frc, uint32_t freq);
|
||||
|
||||
/* Sets the timer for a oneshot interrupt in 'us' microseconds.
|
||||
|
||||
Will change the timer divisor value to suit the target time.
|
||||
|
||||
Does not change the autoreload setting.
|
||||
|
||||
For FRC2 this sets the timer match value relative to the current
|
||||
load value.
|
||||
|
||||
Note that for a true "one shot" timeout with FRC1 then you need to
|
||||
also disable FRC1 in the timer interrupt handler by calling
|
||||
timer_set_run(TIMER_FRC1, false);
|
||||
|
||||
Returns true if the timeout was successfully set.
|
||||
|
||||
Compile-time evaluates to simple register writes if all arguments
|
||||
are available at compile time.
|
||||
*/
|
||||
INLINED bool timer_set_timeout(const timer_frc_t frc, uint32_t us);
|
||||
|
||||
#include "timer_private.h"
|
||||
|
||||
#endif
|
273
core/include/esp/timer_private.h
Normal file
273
core/include/esp/timer_private.h
Normal file
|
@ -0,0 +1,273 @@
|
|||
/* Private header parts of the timer API implementation
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2015 Superhouse Automation Pty Ltd
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#ifndef _ESP_TIMER_PRIVATE_H
|
||||
#define _ESP_TIMER_PRIVATE_H
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Timer divisor index to max frequency */
|
||||
#define _FREQ_DIV1 (80*1000*1000)
|
||||
#define _FREQ_DIV16 (5*1000*1000)
|
||||
#define _FREQ_DIV256 312500
|
||||
const static uint32_t IROM _TIMER_FREQS[] = { _FREQ_DIV1, _FREQ_DIV16, _FREQ_DIV256 };
|
||||
|
||||
/* Timer divisor index to divisor value */
|
||||
const static uint32_t IROM _TIMER_DIV_VAL[] = { 1, 16, 256 };
|
||||
|
||||
/* Timer divisor to mask value */
|
||||
const static uint32_t IROM _TIMER_DIV_REG[] = { TIMER_CTRL_DIV_1, TIMER_CTRL_DIV_16, TIMER_CTRL_DIV_256 };
|
||||
|
||||
INLINED esp_reg_t _timer_ctrl_reg(const timer_frc_t frc)
|
||||
{
|
||||
return (frc == TIMER_FRC1) ? &TIMER_FRC1_CTRL_REG : &TIMER_FRC2_CTRL_REG;
|
||||
}
|
||||
|
||||
INLINED uint32_t timer_get_count(const timer_frc_t frc)
|
||||
{
|
||||
return (frc == TIMER_FRC1) ? TIMER_FRC1_COUNT_REG : TIMER_FRC2_COUNT_REG;
|
||||
}
|
||||
|
||||
INLINED uint32_t timer_get_load(const timer_frc_t frc)
|
||||
{
|
||||
return (frc == TIMER_FRC1) ? TIMER_FRC1_LOAD_REG : TIMER_FRC2_LOAD_REG;
|
||||
}
|
||||
|
||||
INLINED void timer_set_load(const timer_frc_t frc, const uint32_t load)
|
||||
{
|
||||
if(frc == TIMER_FRC1)
|
||||
TIMER_FRC1_LOAD_REG = load;
|
||||
else
|
||||
TIMER_FRC2_LOAD_REG = load;
|
||||
}
|
||||
|
||||
INLINED uint32_t timer_max_load(const timer_frc_t frc)
|
||||
{
|
||||
return (frc == TIMER_FRC1) ? TIMER_FRC1_MAX_LOAD : UINT32_MAX;
|
||||
}
|
||||
|
||||
INLINED void timer_set_divider(const timer_frc_t frc, const timer_div_t div)
|
||||
{
|
||||
if(div < TIMER_DIV1 || div > TIMER_DIV256)
|
||||
return;
|
||||
esp_reg_t ctrl = _timer_ctrl_reg(frc);
|
||||
*ctrl = (*ctrl & ~TIMER_CTRL_DIV_MASK) | (_TIMER_DIV_REG[div] & TIMER_CTRL_DIV_MASK);
|
||||
}
|
||||
|
||||
INLINED void timer_set_interrupts(const timer_frc_t frc, bool enable)
|
||||
{
|
||||
const uint32_t dp_bit = (frc == TIMER_FRC1) ? INT_ENABLE_FRC1 : INT_ENABLE_FRC2;
|
||||
const uint32_t int_mask = BIT((frc == TIMER_FRC1) ? INUM_TIMER_FRC1 : INUM_TIMER_FRC2);
|
||||
if(enable) {
|
||||
DP_INT_ENABLE_REG |= dp_bit;
|
||||
_xt_isr_unmask(int_mask);
|
||||
} else {
|
||||
DP_INT_ENABLE_REG &= ~dp_bit;
|
||||
_xt_isr_mask(int_mask);
|
||||
}
|
||||
}
|
||||
|
||||
INLINED void timer_set_run(const timer_frc_t frc, const bool run)
|
||||
{
|
||||
esp_reg_t ctrl = _timer_ctrl_reg(frc);
|
||||
if (run)
|
||||
*ctrl |= TIMER_CTRL_RUN;
|
||||
else
|
||||
*ctrl &= ~TIMER_CTRL_RUN;
|
||||
}
|
||||
|
||||
INLINED bool timer_get_run(const timer_frc_t frc)
|
||||
{
|
||||
return *_timer_ctrl_reg(frc) & TIMER_CTRL_RUN;
|
||||
}
|
||||
|
||||
INLINED void timer_set_reload(const timer_frc_t frc, const bool reload)
|
||||
{
|
||||
esp_reg_t ctrl = _timer_ctrl_reg(frc);
|
||||
if (reload)
|
||||
*ctrl |= TIMER_CTRL_RELOAD;
|
||||
else
|
||||
*ctrl &= ~TIMER_CTRL_RELOAD;
|
||||
}
|
||||
|
||||
INLINED bool timer_get_reload(const timer_frc_t frc)
|
||||
{
|
||||
return *_timer_ctrl_reg(frc) & TIMER_CTRL_RELOAD;
|
||||
}
|
||||
|
||||
INLINED timer_div_t timer_freq_to_div(uint32_t freq)
|
||||
{
|
||||
/*
|
||||
try to maintain resolution without risking overflows.
|
||||
these values are a bit arbitrary at the moment! */
|
||||
if(freq > 100*1000)
|
||||
return TIMER_DIV1;
|
||||
else if(freq > 100)
|
||||
return TIMER_DIV16;
|
||||
else
|
||||
return TIMER_DIV256;
|
||||
}
|
||||
|
||||
/* timer_timer_to_count implementation - inline if all args are constant, call normally otherwise */
|
||||
|
||||
INLINED uint32_t _timer_freq_to_count_impl(const timer_frc_t frc, const uint32_t freq, const timer_div_t div)
|
||||
{
|
||||
if(div < TIMER_DIV1 || div > TIMER_DIV256)
|
||||
return 0; /* invalid divider */
|
||||
|
||||
if(freq > _TIMER_FREQS[div])
|
||||
return 0; /* out of range for given divisor */
|
||||
|
||||
uint64_t counts = _TIMER_FREQS[div]/freq;
|
||||
return counts;
|
||||
}
|
||||
|
||||
uint32_t _timer_freq_to_count_runtime(const timer_frc_t frc, const uint32_t freq, const timer_div_t div);
|
||||
|
||||
INLINED uint32_t timer_freq_to_count(const timer_frc_t frc, const uint32_t freq, const timer_div_t div)
|
||||
{
|
||||
if(__builtin_constant_p(frc) && __builtin_constant_p(freq) && __builtin_constant_p(div))
|
||||
return _timer_freq_to_count_impl(frc, freq, div);
|
||||
else
|
||||
return _timer_freq_to_count_runtime(frc, freq, div);
|
||||
}
|
||||
|
||||
INLINED timer_div_t timer_time_to_div(uint32_t us)
|
||||
{
|
||||
/*
|
||||
try to maintain resolution without risking overflows. Similar to
|
||||
timer_freq_to_div, these values are a bit arbitrary at the
|
||||
moment! */
|
||||
if(us < 1000)
|
||||
return TIMER_DIV1;
|
||||
else if(us < 10*1000)
|
||||
return TIMER_DIV16;
|
||||
else
|
||||
return TIMER_DIV256;
|
||||
}
|
||||
|
||||
/* timer_timer_to_count implementation - inline if all args are constant, call normally otherwise */
|
||||
|
||||
INLINED uint32_t _timer_time_to_count_impl(const timer_frc_t frc, uint32_t us, const timer_div_t div)
|
||||
{
|
||||
if(div < TIMER_DIV1 || div > TIMER_DIV256)
|
||||
return 0; /* invalid divider */
|
||||
|
||||
const uint32_t TIMER_MAX = timer_max_load(frc);
|
||||
|
||||
if(div != TIMER_DIV256) /* timer tick in MHz */
|
||||
{
|
||||
/* timer is either 80MHz or 5MHz, so either 80 or 5 MHz counts per us */
|
||||
const uint32_t counts_per_us = ((div == TIMER_DIV1) ? _FREQ_DIV1 : _FREQ_DIV16)/1000/1000;
|
||||
if(us > TIMER_MAX/counts_per_us)
|
||||
return 0; /* Multiplying us by mhz_per_count will overflow TIMER_MAX */
|
||||
return us*counts_per_us;
|
||||
}
|
||||
else /* /256 divider, 312.5kHz freq so need to scale up */
|
||||
{
|
||||
/* derived from naive floating point equation that we can't use:
|
||||
counts = (us/1000/1000)*_FREQ_DIV256;
|
||||
counts = (us/2000)*(_FREQ_DIV256/500);
|
||||
counts = us*(_FREQ_DIV256/500)/2000;
|
||||
*/
|
||||
const uint32_t scalar = _FREQ_DIV256/500;
|
||||
if(us > 1+UINT32_MAX/scalar)
|
||||
return 0; /* Multiplying us by _FREQ_DIV256/500 will overflow uint32_t */
|
||||
|
||||
uint32_t counts = (us*scalar)/2000;
|
||||
if(counts > TIMER_MAX)
|
||||
return 0; /* counts value too high for timer type */
|
||||
return counts;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t _timer_time_to_count_runtime(const timer_frc_t frc, uint32_t us, const timer_div_t div);
|
||||
|
||||
INLINED uint32_t timer_time_to_count(const timer_frc_t frc, uint32_t us, const timer_div_t div)
|
||||
{
|
||||
if(__builtin_constant_p(frc) && __builtin_constant_p(us) && __builtin_constant_p(div))
|
||||
return _timer_time_to_count_impl(frc, us, div);
|
||||
else
|
||||
return _timer_time_to_count_runtime(frc, us, div);
|
||||
}
|
||||
|
||||
/* timer_set_frequency implementation - inline if all args are constant, call normally otherwise */
|
||||
|
||||
INLINED bool _timer_set_frequency_impl(const timer_frc_t frc, uint32_t freq)
|
||||
{
|
||||
uint32_t counts = 0;
|
||||
timer_div_t div = timer_freq_to_div(freq);
|
||||
|
||||
counts = timer_freq_to_count(frc, freq, div);
|
||||
if(counts == 0)
|
||||
{
|
||||
printf("ABORT: No counter for timer %d frequency %d\r\n", frc, freq);
|
||||
abort();
|
||||
}
|
||||
|
||||
timer_set_divider(frc, div);
|
||||
if(frc == TIMER_FRC1)
|
||||
{
|
||||
timer_set_load(frc, counts);
|
||||
timer_set_reload(frc, true);
|
||||
}
|
||||
else /* FRC2 */
|
||||
{
|
||||
/* assume that if this overflows it'll wrap, so we'll get desired behaviour */
|
||||
TIMER_FRC2_MATCH_REG = counts + TIMER_FRC2_COUNT_REG;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _timer_set_frequency_runtime(const timer_frc_t frc, uint32_t freq);
|
||||
|
||||
INLINED bool timer_set_frequency(const timer_frc_t frc, uint32_t freq)
|
||||
{
|
||||
if(__builtin_constant_p(frc) && __builtin_constant_p(freq))
|
||||
return _timer_set_frequency_impl(frc, freq);
|
||||
else
|
||||
return _timer_set_frequency_runtime(frc, freq);
|
||||
}
|
||||
|
||||
/* timer_set_timeout implementation - inline if all args are constant, call normally otherwise */
|
||||
|
||||
INLINED bool _timer_set_timeout_impl(const timer_frc_t frc, uint32_t us)
|
||||
{
|
||||
uint32_t counts = 0;
|
||||
timer_div_t div = timer_time_to_div(us);
|
||||
|
||||
counts = timer_time_to_count(frc, us, div);
|
||||
if(counts == 0)
|
||||
return false; /* can't set frequency */
|
||||
|
||||
timer_set_divider(frc, div);
|
||||
if(frc == TIMER_FRC1)
|
||||
{
|
||||
timer_set_load(frc, counts);
|
||||
}
|
||||
else /* FRC2 */
|
||||
{
|
||||
TIMER_FRC2_MATCH_REG = counts + TIMER_FRC2_COUNT_REG;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _timer_set_timeout_runtime(const timer_frc_t frc, uint32_t us);
|
||||
|
||||
INLINED bool timer_set_timeout(const timer_frc_t frc, uint32_t us)
|
||||
{
|
||||
if(__builtin_constant_p(frc) && __builtin_constant_p(us))
|
||||
return _timer_set_timeout_impl(frc, us);
|
||||
else
|
||||
return _timer_set_timeout_runtime(frc, us);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -16,5 +16,6 @@
|
|||
#include "esp/cpu.h"
|
||||
#include "esp/iomux.h"
|
||||
#include "esp/gpio.h"
|
||||
#include "esp/timer.h"
|
||||
|
||||
#endif
|
||||
|
|
2
examples/blink_timers/Makefile
Normal file
2
examples/blink_timers/Makefile
Normal file
|
@ -0,0 +1,2 @@
|
|||
PROGRAM=blink_timers
|
||||
include ../../common.mk
|
64
examples/blink_timers/blink_timers.c
Normal file
64
examples/blink_timers/blink_timers.c
Normal file
|
@ -0,0 +1,64 @@
|
|||
/* The "blink" example, but writing the LED from timer interrupts
|
||||
*
|
||||
* This sample code is in the public domain.
|
||||
*/
|
||||
#include "espressif/esp_common.h"
|
||||
#include "espressif/sdk_private.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "esp8266.h"
|
||||
|
||||
const int gpio_frc1 = 12;
|
||||
const int freq_frc1 = 1;
|
||||
|
||||
const int gpio_frc2 = 14;
|
||||
const int freq_frc2 = 10;
|
||||
|
||||
static volatile uint32_t frc1_count;
|
||||
static volatile uint32_t frc2_count;
|
||||
|
||||
void frc1_interrupt_handler(void)
|
||||
{
|
||||
frc1_count++;
|
||||
gpio_toggle(gpio_frc1);
|
||||
}
|
||||
|
||||
void frc2_interrupt_handler(void)
|
||||
{
|
||||
/* FRC2 needs the match register updated on each timer interrupt */
|
||||
timer_set_frequency(TIMER_FRC2, freq_frc2);
|
||||
frc2_count++;
|
||||
gpio_toggle(gpio_frc2);
|
||||
}
|
||||
|
||||
void user_init(void)
|
||||
{
|
||||
sdk_uart_div_modify(0, UART_CLK_FREQ / 115200);
|
||||
|
||||
/* configure GPIOs */
|
||||
gpio_enable(gpio_frc1, GPIO_OUTPUT);
|
||||
gpio_enable(gpio_frc2, GPIO_OUTPUT);
|
||||
gpio_write(gpio_frc1, 1);
|
||||
|
||||
/* stop both timers and mask their interrupts as a precaution */
|
||||
timer_set_interrupts(TIMER_FRC1, false);
|
||||
timer_set_run(TIMER_FRC1, false);
|
||||
timer_set_interrupts(TIMER_FRC2, false);
|
||||
timer_set_run(TIMER_FRC2, false);
|
||||
|
||||
/* set up ISRs */
|
||||
_xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler);
|
||||
_xt_isr_attach(INUM_TIMER_FRC2, frc2_interrupt_handler);
|
||||
|
||||
/* configure timer frequencies */
|
||||
timer_set_frequency(TIMER_FRC1, freq_frc1);
|
||||
timer_set_frequency(TIMER_FRC2, freq_frc2);
|
||||
|
||||
/* unmask interrupts and start timers */
|
||||
timer_set_interrupts(TIMER_FRC1, true);
|
||||
timer_set_run(TIMER_FRC1, true);
|
||||
timer_set_interrupts(TIMER_FRC2, true);
|
||||
timer_set_run(TIMER_FRC2, true);
|
||||
|
||||
gpio_write(gpio_frc1, 0);
|
||||
}
|
Loading…
Reference in a new issue