Merge branch 'master' into open-libmain

Conflicts:
	core/include/esp/rtc_regs.h
	include/espressif/spi_flash.h
This commit is contained in:
Alex Stewart 2016-03-22 16:24:50 -07:00
commit 769ca0d8f8
89 changed files with 4766 additions and 634 deletions

View file

@ -13,63 +13,74 @@
#include "esp/iomux.h"
#include "esp/interrupts.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
GPIO_INPUT,
GPIO_OUTPUT, /* "Standard" push-pull output */
GPIO_OUT_OPEN_DRAIN, /* Open drain output */
GPIO_INPUT_PULLUP,
} gpio_direction_t;
/* Enable GPIO on the specified pin, and set it to input/output/ with
* pullup as needed
/* Enable GPIO on the specified pin, and set it to input or output mode
*/
INLINED void gpio_enable(const uint8_t gpio_num, const gpio_direction_t direction)
{
uint32_t iomux_flags;
void gpio_enable(const uint8_t gpio_num, const gpio_direction_t direction);
switch(direction) {
case GPIO_INPUT:
iomux_flags = 0;
break;
case GPIO_OUTPUT:
iomux_flags = IOMUX_PIN_OUTPUT_ENABLE;
break;
case GPIO_OUT_OPEN_DRAIN:
iomux_flags = IOMUX_PIN_OUTPUT_ENABLE;
break;
case GPIO_INPUT_PULLUP:
iomux_flags = IOMUX_PIN_PULLUP;
break;
}
iomux_set_gpio_function(gpio_num, iomux_flags);
if(direction == GPIO_OUT_OPEN_DRAIN)
GPIO.CONF[gpio_num] |= GPIO_CONF_OPEN_DRAIN;
else
GPIO.CONF[gpio_num] &= ~GPIO_CONF_OPEN_DRAIN;
if (iomux_flags & IOMUX_PIN_OUTPUT_ENABLE)
GPIO.ENABLE_OUT_SET = BIT(gpio_num);
else
GPIO.ENABLE_OUT_CLEAR = BIT(gpio_num);
}
/* Enable/disable internal pullup resistor for a particular GPIO
*
* Note: According to Espressif, pullup resistor values are between 30K and
* 100K ohms (see http://bbs.espressif.com/viewtopic.php?t=1079#p4097)
* However, measured values suggest that the actual value is likely to be close
* to 47K in reality.
*
* NOTE: The enabled_during_sleep setting is currently untested (please send
* feedback if you give it a try)
*/
void gpio_set_pullup(uint8_t gpio_num, bool enabled, bool enabled_during_sleep);
/* Disable GPIO on the specified pin, and set it Hi-Z.
*
* If later muxing this pin to a different function, make sure to set
* IOMUX_PIN_OUTPUT_ENABLE if necessary to enable the output buffer.
*/
INLINED void gpio_disable(const uint8_t gpio_num)
static inline void gpio_disable(const uint8_t gpio_num)
{
GPIO.ENABLE_OUT_CLEAR = BIT(gpio_num);
*gpio_iomux_reg(gpio_num) &= ~IOMUX_PIN_OUTPUT_ENABLE;
}
/* Set whether the specified pin continues to drive its output when the ESP8266
* goes into sleep mode. Note that this setting is reset to off whenever
* gpio_enable is called, so this must be called after calling that function.
*
* NOTE: This functionality is currently untested (please send feedback if you
* give it a try)
*/
static inline void gpio_set_output_on_sleep(const uint8_t gpio_num, bool enabled)
{
if (enabled) {
IOMUX.PIN[gpio_to_iomux(gpio_num)] |= IOMUX_PIN_OUTPUT_ENABLE_SLEEP;
} else {
IOMUX.PIN[gpio_to_iomux(gpio_num)] &= ~IOMUX_PIN_OUTPUT_ENABLE_SLEEP;
}
}
/* Set output of a pin high or low.
*
* Only works if pin has been set to GPIO_OUTPUT via gpio_enable()
* Only works if pin has been set to GPIO_OUTPUT or GPIO_OUT_OPEN_DRAIN via
* gpio_enable()
*
* If the mode is GPIO_OUT_OPEN_DRAIN, setting it low (false) will pull the pin
* down to ground, but setting it high (true) will allow it to float. Note
* that even in GPIO_OUT_OPEN_DRAIN mode, the input gates are still physically
* connected to the pin, and can be damaged if the voltage is not in either the
* "low" or "high" range. Make sure there is some sort of pull-up resistor on
* the line to avoid floating logic lines!
*/
INLINED void gpio_write(const uint8_t gpio_num, const bool set)
static inline void gpio_write(const uint8_t gpio_num, const bool set)
{
if(set)
if (set)
GPIO.OUT_SET = BIT(gpio_num);
else
GPIO.OUT_CLEAR = BIT(gpio_num);
@ -77,9 +88,12 @@ INLINED void gpio_write(const uint8_t gpio_num, const bool set)
/* Toggle output of a pin
*
* Only works if pin has been set to GPIO_OUTPUT via gpio_enable()
* Only works if pin has been set to GPIO_OUTPUT or GPIO_OUT_OPEN_DRAIN via
* gpio_enable()
*
* See notes in gpio_write() about GPIO_OUT_OPEN_DRAIN mode.
*/
INLINED void gpio_toggle(const uint8_t gpio_num)
static inline void gpio_toggle(const uint8_t gpio_num)
{
/* Why implement like this instead of GPIO_OUT_REG ^= xxx?
Concurrency. If an interrupt or higher priority task writes to
@ -95,10 +109,14 @@ INLINED void gpio_toggle(const uint8_t gpio_num)
/* Read input value of a GPIO pin.
*
* If pin is set as an input, this reads the value on the pin.
* If pin is set as an output, this reads the last value written to the pin.
* If pin is set GPIO_INPUT, this reads the level on the pin.
* If pin is set GPIO_OUTPUT, this reads the level at which the pin is
* currently being driven (i.e. the last value written).
* If pin is set GPIO_OUT_OPEN_DRAIN, when the pin is written low, this will
* return low (false), when the pin is written high, this will behave like
* GPIO_INPUT.
*/
INLINED bool gpio_read(const uint8_t gpio_num)
static inline bool gpio_read(const uint8_t gpio_num)
{
return GPIO.IN & BIT(gpio_num);
}
@ -107,9 +125,10 @@ extern void gpio_interrupt_handler(void);
/* Set the interrupt type for a given pin
*
* If int_type is not GPIO_INTTYPE_NONE, the gpio_interrupt_handler will be attached and unmasked.
* If int_type is not GPIO_INTTYPE_NONE, the gpio_interrupt_handler will be
* attached and unmasked.
*/
INLINED void gpio_set_interrupt(const uint8_t gpio_num, const gpio_inttype_t int_type)
static inline void gpio_set_interrupt(const uint8_t gpio_num, const gpio_inttype_t int_type)
{
GPIO.CONF[gpio_num] = SET_FIELD(GPIO.CONF[gpio_num], GPIO_CONF_INTTYPE, int_type);
if(int_type != GPIO_INTTYPE_NONE) {
@ -119,9 +138,13 @@ INLINED void gpio_set_interrupt(const uint8_t gpio_num, const gpio_inttype_t int
}
/* Return the interrupt type set for a pin */
INLINED gpio_inttype_t gpio_get_interrupt(const uint8_t gpio_num)
static inline gpio_inttype_t gpio_get_interrupt(const uint8_t gpio_num)
{
return (gpio_inttype_t)FIELD2VAL(GPIO_CONF_INTTYPE, GPIO.CONF[gpio_num]);
}
#ifdef __cplusplus
}
#endif
#endif

137
core/include/esp/i2s_regs.h Normal file
View file

@ -0,0 +1,137 @@
/* esp/i2s_regs.h
*
* ESP8266 I2S register definitions
*
* Not compatible with ESP SDK register access code.
*/
#ifndef _ESP_I2S_REGS_H
#define _ESP_I2S_REGS_H
#include "esp/types.h"
#include "common_macros.h"
#define I2S_BASE 0x60000e00
#define I2S (*(struct I2S_REGS *)I2S_BASE)
struct I2S_REGS {
uint32_t volatile TXFIFO; // 0x00
uint32_t volatile RXFIFO; // 0x04
uint32_t volatile CONF; // 0x08
uint32_t volatile INT_RAW; // 0x0c
uint32_t volatile INT_STATUS; // 0x10
uint32_t volatile INT_ENABLE; // 0x14
uint32_t volatile INT_CLEAR; // 0x18
uint32_t volatile TIMING; // 0x1c
uint32_t volatile FIFO_CONF; // 0x20
uint32_t volatile RX_EOF_NUM; // 0x24
uint32_t volatile CONF_SINGLE_DATA; // 0x28
uint32_t volatile CONF_CHANNELS; // 0x2c
};
_Static_assert(sizeof(struct I2S_REGS) == 0x30, "I2S_REGS is the wrong size");
/* Details for CONF register */
#define I2S_CONF_BCK_DIV_M 0x0000003f
#define I2S_CONF_BCK_DIV_S 22
#define I2S_CONF_CLKM_DIV_M 0x0000003f
#define I2S_CONF_CLKM_DIV_S 16
#define I2S_CONF_BITS_MOD_M 0x0000000f
#define I2S_CONF_BITS_MOD_S 12
#define I2S_CONF_RX_MSB_SHIFT BIT(11)
#define I2S_CONF_TX_MSB_SHIFT BIT(10)
#define I2S_CONF_RX_START BIT(9)
#define I2S_CONF_TX_START BIT(8)
#define I2S_CONF_MSB_RIGHT BIT(7)
#define I2S_CONF_RIGHT_FIRST BIT(6)
#define I2S_CONF_RX_SLAVE_MOD BIT(5)
#define I2S_CONF_TX_SLAVE_MOD BIT(4)
#define I2S_CONF_RX_FIFO_RESET BIT(3)
#define I2S_CONF_TX_FIFO_RESET BIT(2)
#define I2S_CONF_RX_RESET BIT(1)
#define I2S_CONF_TX_RESET BIT(0)
#define I2S_CONF_RESET_MASK 0xf
/* Details for INT_RAW register */
#define I2S_INT_RAW_TX_REMPTY BIT(5)
#define I2S_INT_RAW_TX_WFULL BIT(4)
#define I2S_INT_RAW_RX_REMPTY BIT(3)
#define I2S_INT_RAW_RX_WFULL BIT(2)
#define I2S_INT_RAW_TX_PUT_DATA BIT(1)
#define I2S_INT_RAW_RX_TAKE_DATA BIT(0)
/* Details for INT_STATUS register */
#define I2S_INT_STATUS_TX_REMPTY BIT(5)
#define I2S_INT_STATUS_TX_WFULL BIT(4)
#define I2S_INT_STATUS_RX_REMPTY BIT(3)
#define I2S_INT_STATUS_RX_WFULL BIT(2)
#define I2S_INT_STATUS_TX_PUT_DATA BIT(1)
#define I2S_INT_STATUS_RX_TAKE_DATA BIT(0)
/* Details for INT_ENABLE register */
#define I2S_INT_ENABLE_TX_REMPTY BIT(5)
#define I2S_INT_ENABLE_TX_WFULL BIT(4)
#define I2S_INT_ENABLE_RX_REMPTY BIT(3)
#define I2S_INT_ENABLE_RX_WFULL BIT(2)
#define I2S_INT_ENABLE_TX_PUT_DATA BIT(1)
#define I2S_INT_ENABLE_RX_TAKE_DATA BIT(0)
/* Details for INT_CLEAR register */
#define I2S_INT_CLEAR_TX_REMPTY BIT(5)
#define I2S_INT_CLEAR_TX_WFULL BIT(4)
#define I2S_INT_CLEAR_RX_REMPTY BIT(3)
#define I2S_INT_CLEAR_RX_WFULL BIT(2)
#define I2S_INT_CLEAR_TX_PUT_DATA BIT(1)
#define I2S_INT_CLEAR_RX_TAKE_DATA BIT(0)
/* Details for TIMING register */
#define I2S_TIMING_TX_BCK_IN_INV BIT(22)
#define I2S_TIMING_RX_DSYNC_SW BIT(21)
#define I2S_TIMING_TX_DSYNC_SW BIT(20)
#define I2S_TIMING_RX_BCK_OUT_DELAY_M 0x00000003
#define I2S_TIMING_RX_BCK_OUT_DELAY_S 18
#define I2S_TIMING_RX_WS_OUT_DELAY_M 0x00000003
#define I2S_TIMING_RX_WS_OUT_DELAY_S 16
#define I2S_TIMING_TX_SD_OUT_DELAY_M 0x00000003
#define I2S_TIMING_TX_SD_OUT_DELAY_S 14
#define I2S_TIMING_TX_WS_OUT_DELAY_M 0x00000003
#define I2S_TIMING_TX_WS_OUT_DELAY_S 12
#define I2S_TIMING_TX_BCK_OUT_DELAY_M 0x00000003
#define I2S_TIMING_TX_BCK_OUT_DELAY_S 10
#define I2S_TIMING_RX_SD_IN_DELAY_M 0x00000003
#define I2S_TIMING_RX_SD_IN_DELAY_S 8
#define I2S_TIMING_RX_WS_IN_DELAY 0x00000003
#define I2S_TIMING_RX_WS_IN_DELAY_S 6
#define I2S_TIMING_RX_BCK_IN_DELAY_M 0x00000003
#define I2S_TIMING_RX_BCK_IN_DELAY_S 4
#define I2S_TIMING_TX_WS_IN_DELAY_M 0x00000003
#define I2S_TIMING_TX_WS_IN_DELAY_S 2
#define I2S_TIMING_TX_BCK_IN_DELAY_M 0x00000003
#define I2S_TIMING_TX_BCK_IN_DELAY_S 0
/* Details for FIFO_CONF register */
#define I2S_FIFO_CONF_RX_FIFO_MOD_M 0x00000007
#define I2S_FIFO_CONF_RX_FIFO_MOD_S 16
#define I2S_FIFO_CONF_TX_FIFO_MOD_M 0x00000007
#define I2S_FIFO_CONF_TX_FIFO_MOD_S 13
#define I2S_FIFO_CONF_DESCRIPTOR_ENABLE BIT(12)
#define I2S_FIFO_CONF_TX_DATA_NUM_M 0x0000003f
#define I2S_FIFO_CONF_TX_DATA_NUM_S 6
#define I2S_FIFO_CONF_RX_DATA_NUM_M 0x0000003f
#define I2S_FIFO_CONF_RX_DATA_NUM_S 0
/* Details for CONF_CHANNEL register */
#define I2S_CONF_CHANNELS_RX_CHANNEL_MOD_M 0x00000003
#define I2S_CONF_CHANNELS_RX_CHANNEL_MOD_S 3
#define I2S_CONF_CHANNELS_TX_CHANNEL_MOD_M 0x00000007
#define I2S_CONF_CHANNELS_TX_CHANNEL_MOD_S 0
#endif /* _ESP_I2S_REGS_H */

View file

@ -17,6 +17,7 @@
/* Interrupt numbers for level 1 exception handler. */
typedef enum {
INUM_SLC = 1,
INUM_SPI = 2,
INUM_GPIO = 4,
INUM_UART = 5,
@ -38,7 +39,7 @@ void sdk__xt_tick_timer_init (void);
void sdk__xt_timer_int(void);
void sdk__xt_timer_int1(void);
INLINED uint32_t _xt_get_intlevel(void)
static inline uint32_t _xt_get_intlevel(void)
{
uint32_t level;
__asm__ volatile("rsr %0, intlevel" : "=a"(level));
@ -52,7 +53,7 @@ INLINED uint32_t _xt_get_intlevel(void)
portDISABLE_INTERRUPTS/portENABLE_INTERRUPTS for
non-FreeRTOS & non-portable code.
*/
INLINED uint32_t _xt_disable_interrupts(void)
static inline uint32_t _xt_disable_interrupts(void)
{
uint32_t old_level;
__asm__ volatile ("rsil %0, " XTSTR(XCHAL_EXCM_LEVEL) : "=a" (old_level));
@ -60,14 +61,14 @@ INLINED uint32_t _xt_disable_interrupts(void)
}
/* Restore PS level. Intended to be used with _xt_disable_interrupts */
INLINED void _xt_restore_interrupts(uint32_t new_ps)
static inline void _xt_restore_interrupts(uint32_t new_ps)
{
__asm__ volatile ("wsr %0, ps; rsync" :: "a" (new_ps));
}
/* ESPTODO: the mask/unmask functions aren't thread safe */
INLINED void _xt_isr_unmask(uint32_t unmask)
static inline void _xt_isr_unmask(uint32_t unmask)
{
uint32_t intenable;
asm volatile ("rsr %0, intenable" : "=a" (intenable));
@ -75,7 +76,7 @@ INLINED void _xt_isr_unmask(uint32_t unmask)
asm volatile ("wsr %0, intenable; esync" :: "a" (intenable));
}
INLINED void _xt_isr_mask (uint32_t mask)
static inline void _xt_isr_mask (uint32_t mask)
{
uint32_t intenable;
asm volatile ("rsr %0, intenable" : "=a" (intenable));
@ -83,14 +84,14 @@ INLINED void _xt_isr_mask (uint32_t mask)
asm volatile ("wsr %0, intenable; esync" :: "a" (intenable));
}
INLINED uint32_t _xt_read_ints (void)
static inline uint32_t _xt_read_ints (void)
{
uint32_t interrupt;
asm volatile ("rsr %0, interrupt" : "=a" (interrupt));
return interrupt;
}
INLINED void _xt_clear_ints(uint32_t mask)
static inline void _xt_clear_ints(uint32_t mask)
{
asm volatile ("wsr %0, intclear; esync" :: "a" (mask));
}

View file

@ -22,7 +22,7 @@ extern "C" {
* known at compile time, or return the result from a lookup table if not.
*
*/
inline static uint8_t gpio_to_iomux(const uint8_t gpio_number);
uint8_t IRAM gpio_to_iomux(const uint8_t gpio_number);
/**
* Convert an iomux register index to a GPIO pin number.
@ -31,7 +31,7 @@ inline static uint8_t gpio_to_iomux(const uint8_t gpio_number);
* known at compile time, or return the result from a lookup table if not.
*
*/
inline static uint8_t iomux_to_gpio(const uint8_t iomux_num);
uint8_t IRAM iomux_to_gpio(const uint8_t iomux_num);
/**
* Directly get the IOMUX register for a particular gpio number
@ -43,31 +43,43 @@ inline static esp_reg_t gpio_iomux_reg(const uint8_t gpio_number)
return &(IOMUX.PIN[gpio_to_iomux(gpio_number)]);
}
inline static void iomux_set_function(uint8_t iomux_num, uint32_t func)
{
uint32_t prev = IOMUX.PIN[iomux_num] & ~IOMUX_PIN_FUNC_MASK;
IOMUX.PIN[iomux_num] = IOMUX_FUNC(func) | prev;
}
inline static void iomux_set_direction_flags(uint8_t iomux_num, uint32_t dir_flags)
{
uint32_t mask = IOMUX_PIN_OUTPUT_ENABLE | IOMUX_PIN_OUTPUT_ENABLE_SLEEP;
uint32_t prev = IOMUX.PIN[iomux_num] & ~mask;
IOMUX.PIN[iomux_num] = dir_flags | prev;
}
inline static void iomux_set_pullup_flags(uint8_t iomux_num, uint32_t pullup_flags)
{
uint32_t mask = IOMUX_PIN_PULLUP | IOMUX_PIN_PULLDOWN | IOMUX_PIN_PULLUP_SLEEP | IOMUX_PIN_PULLDOWN_SLEEP;
uint32_t prev = IOMUX.PIN[iomux_num] & ~mask;
IOMUX.PIN[iomux_num] = pullup_flags | prev;
}
/**
* Set a pin to the GPIO function.
*
* This allows you to set pins to GPIO without knowing in advance the
* exact register masks to use.
*
* flags can be any of IOMUX_PIN_OUTPUT_ENABLE, IOMUX_PIN_PULLUP, IOMUX_PIN_PULLDOWN, etc. Any other flags will be cleared.
*
* Equivalent to a direct register operation if gpio_number is known at compile time.
* ie the following are equivalent:
*
* iomux_set_gpio_function(12, IOMUX_PIN_OUTPUT_ENABLE);
* IOMUX_GPIO12 = IOMUX_GPIO12_FUNC_GPIO | IOMUX_PIN_OUTPUT_ENABLE;
* Sets the function and direction, but leaves the pullup configuration the
* same as before.
*/
inline static void iomux_set_gpio_function(const uint8_t gpio_number, const uint32_t flags)
inline static void iomux_set_gpio_function(uint8_t gpio_number, bool output_enable)
{
const uint8_t reg_idx = gpio_to_iomux(gpio_number);
const uint32_t func = (reg_idx > 11 ? IOMUX_FUNC(0) : IOMUX_FUNC(3)) | flags;
IOMUX.PIN[reg_idx] = func | flags;
const uint8_t iomux_num = gpio_to_iomux(gpio_number);
const uint32_t func = iomux_num > 11 ? 0 : 3;
iomux_set_function(iomux_num, func);
iomux_set_direction_flags(iomux_num, output_enable ? IOMUX_PIN_OUTPUT_ENABLE : 0);
}
/* esp_iomux_private contains implementation parts of the inline functions
declared above */
#include "esp/iomux_private.h"
#ifdef __cplusplus
}
#endif

View file

@ -1,46 +0,0 @@
/** esp/iomux_private.h
*
* Private implementation parts of iomux registers. In headers to
* allow compile-time optimisations.
*
* Part of esp-open-rtos
* Copyright (C) 2015 Superhouse Automation Pty Ltd
* BSD Licensed as described in the file LICENSE
*/
/* Mapping from register index to GPIO and from GPIO index to register
number. DO NOT USE THESE IN YOUR CODE, call gpio_to_iomux(xxx) or
iomux_to_gpio(xxx) instead.
*/
#ifndef _IOMUX_PRIVATE
#define _IOMUX_PRIVATE
#include "common_macros.h"
#define _IOMUX_TO_GPIO { 12, 13, 14, 15, 3, 1, 6, 7, 8, 9, 10, 11, 0, 2, 4, 5 }
#define _GPIO_TO_IOMUX { 12, 5, 13, 4, 14, 15, 6, 7, 8, 9, 10, 11, 0, 1, 2, 3 }
extern const IROM uint32_t GPIO_TO_IOMUX_MAP[];
extern const IROM uint32_t IOMUX_TO_GPIO_MAP[];
INLINED uint8_t gpio_to_iomux(const uint8_t gpio_number)
{
if(__builtin_constant_p(gpio_number)) {
static const uint8_t _regs[] = _GPIO_TO_IOMUX;
return _regs[gpio_number];
} else {
return GPIO_TO_IOMUX_MAP[gpio_number];
}
}
INLINED uint8_t iomux_to_gpio(const uint8_t iomux_number)
{
if(__builtin_constant_p(iomux_number)) {
static const uint8_t _regs[] = _IOMUX_TO_GPIO;
return _regs[iomux_number];
} else {
return IOMUX_TO_GPIO_MAP[iomux_number];
}
}
#endif

View file

@ -40,9 +40,9 @@ _Static_assert(sizeof(struct IOMUX_REGS) == 0x44, "IOMUX_REGS is the wrong size"
#define IOMUX_PIN_PULLDOWN BIT(6)
#define IOMUX_PIN_PULLUP BIT(7)
#define IOMUX_PIN_FUNC_HIGH_M 0x00000004
#define IOMUX_PIN_FUNC_HIGH_S 8
#define IOMUX_PIN_FUNC_HIGH_S 6
#define IOMUX_PIN_FUNC_MASK 0x00001030
#define IOMUX_PIN_FUNC_MASK 0x00000130
/* WARNING: Macro evaluates argument twice */
#define IOMUX_FUNC(val) (VAL2FIELD_M(IOMUX_PIN_FUNC_LOW, val) | VAL2FIELD_M(IOMUX_PIN_FUNC_HIGH, val))
@ -80,8 +80,8 @@ _Static_assert(sizeof(struct IOMUX_REGS) == 0x44, "IOMUX_REGS is the wrong size"
#define IOMUX_GPIO2_FUNC_GPIO IOMUX_FUNC(0)
#define IOMUX_GPIO2_FUNC_I2SO_WS IOMUX_FUNC(1)
#define IOMUX_GPIO2_FUNC_UART1_TXD_BLINK IOMUX_FUNC(2)
#define IOMUX_GPIO2_FUNC_UART0_TXD_BLINK IOMUX_FUNC(4)
#define IOMUX_GPIO2_FUNC_UART1_TXD IOMUX_FUNC(2)
#define IOMUX_GPIO2_FUNC_UART0_TXD IOMUX_FUNC(4)
#define IOMUX_GPIO3_FUNC_UART0_RXD IOMUX_FUNC(0)
#define IOMUX_GPIO3_FUNC_I2SO_DATA IOMUX_FUNC(1)

View file

@ -16,14 +16,17 @@
#include "common_macros.h"
#include "esp/types.h"
#include "esp/uart_regs.h"
#include "esp/spi_regs.h"
#include "esp/iomux_regs.h"
#include "esp/dport_regs.h"
#include "esp/gpio_regs.h"
#include "esp/i2s_regs.h"
#include "esp/iomux_regs.h"
#include "esp/rtc_regs.h"
#include "esp/rtcmem_regs.h"
#include "esp/slc_regs.h"
#include "esp/spi_regs.h"
#include "esp/timer_regs.h"
#include "esp/wdt_regs.h"
#include "esp/rtcmem_regs.h"
#include "esp/dport_regs.h"
#include "esp/uart_regs.h"
/* Register base addresses
@ -44,7 +47,7 @@
//#define SPI_BASE (MMIO_BASE + 0x0200)
//#define GPIO0_BASE (MMIO_BASE + 0x0300)
//#define TIMER_BASE (MMIO_BASE + 0x0600)
#define RTC_BASE (MMIO_BASE + 0x0700)
//#define RTC_BASE (MMIO_BASE + 0x0700)
//#define IOMUX_BASE (MMIO_BASE + 0x0800)
//#define WDT_BASE (MMIO_BASE + 0x0900)
#define I2C_BASE (MMIO_BASE + 0x0d00)

View file

@ -3,6 +3,16 @@
* ESP8266 RTC register definitions
*
* Not compatible with ESP SDK register access code.
*
* RTC peripheral remains powered during deep sleep, and RTC clock
* is used to wake from deep sleep when RTC.COUNTER == RTC.COUNTER_ALARM.
*
* "GPIO16" is a special GPIO pin connected to the RTC subsystem,
* GPIO16 must be connected to reset to allow wake from deep sleep.
*
* The contents of scratch registers RTC.SCRATCH[] are preserved
* across reset, including wake from sleep (unconfirmed). Contents of
* RTCMEM are also preserved.
*/
#ifndef _ESP_RTC_REGS_H
@ -18,7 +28,7 @@
// Note: GPIO_CFG[3] is also known as PAD_XPD_DCDC_CONF in eagle_soc.h
struct RTC_REGS {
uint32_t volatile _unknown0; // 0x00
uint32_t volatile CTRL0; // 0x00
uint32_t volatile COUNTER_ALARM; // 0x04
uint32_t volatile RESET_REASON0; // 0x08 //FIXME: need better name
uint32_t volatile _unknownc[2]; // 0x0c - 0x10
@ -42,6 +52,14 @@ struct RTC_REGS {
_Static_assert(sizeof(struct RTC_REGS) == 0xac, "RTC_REGS is the wrong size");
/* Details for CTRL0 register */
/* Writing this bit causes a software reset but
the device then fails in ets_main.c (needs other parameters set?) */
#define RTC_CTRL0_BIT31 BIT(31)
/* Details for RESET_REASONx registers */
/* The following are used in sdk_rtc_get_reset_reason(). Details are still a
* bit sketchy regarding exactly what they mean/do.. */
@ -51,6 +69,32 @@ _Static_assert(sizeof(struct RTC_REGS) == 0xac, "RTC_REGS is the wrong size");
#define RTC_RESET_REASON2_CODE_M 0x0000003f
#define RTC_RESET_REASON2_CODE_S 8
#define RTC_RESET_REASON0_SOMETHING BIT(21)
/* Writing this bit causes the ESP to go into some kind of unrecoverable boot loop */
#define RTC_RESET_REASON0_BIT20 BIT(20)
/* Both bits 20 & 21 can be set & cleared from software,
BIT21 appears to be checked inside sdk_rtc_get_reset_reason() */
#define RTC_RESET_REASON0_BIT21 BIT(21)
#define RTC_RESET_REASON0_BIT22 BIT(22)
/* Details for GPIO_CONF register */
#define RTC_GPIO_CONF_OUT_ENABLE BIT(0)
/* Details for GPIO_CFG[3] register controlling GPIO16 (possibly others?) */
#define RTC_GPIO_CFG3_PIN_PULLUP BIT(2)
#define RTC_GPIO_CFG3_PIN_PULLDOWN BIT(3)
#define RTC_GPIO_CFG3_PIN_PULLUP_SLEEP BIT(4)
#define RTC_GPIO_CFG3_PIN_PULLDOWN_SLEEP BIT(5)
/* The PIN_FUNC values here are probably similar to the
values used to set the iomux registers...? */
#define RTC_GPIO_CFG3_PIN_FUNC_M 0x00000043
#define RTC_GPIO_CFG3_PIN_FUNC_S 0
/* This should be the function value needed to have GPIO16 be the alarm
output from the RTC. FIXME: Needs to be validated. */
#define RTC_GPIO_CFG3_PIN_FUNC_RTC_GPIO0 BIT(0)
#endif /* _ESP_RTC_REGS_H */

37
core/include/esp/slc.h Normal file
View file

@ -0,0 +1,37 @@
/* esp/slc_regs.h
*
* ESP8266 SLC functions
*/
#ifndef _ESP_SLC_H
#define _ESP_SLC_H
#include "esp/slc_regs.h"
/* Memory layout for DMA transfer descriptors. */
struct SLCDescriptor
{
uint32_t flags;
uint32_t buf_ptr;
uint32_t next_link_ptr;
};
#define SLC_DESCRIPTOR_FLAGS_BLOCKSIZE_M 0x00000fff
#define SLC_DESCRIPTOR_FLAGS_BLOCKSIZE_S 0
#define SLC_DESCRIPTOR_FLAGS_DATA_LENGTH_M 0x00000fff
#define SLC_DESCRIPTOR_FLAGS_DATA_LENGTH_S 12
#define SLC_DESCRIPTOR_FLAGS_SUB_SOF BIT(29)
#define SLC_DESCRIPTOR_FLAGS_EOF BIT(30)
#define SLC_DESCRIPTOR_FLAGS_OWNER BIT(31)
#define SLC_DESCRIPTOR_FLAGS(blocksize,datalen,sub_sof,eof,owner) ( \
VAL2FIELD_M(SLC_DESCRIPTOR_FLAGS_BLOCKSIZE,blocksize)| \
VAL2FIELD_M(SLC_DESCRIPTOR_FLAGS_DATA_LENGTH,datalen)| \
((sub_sof)?SLC_DESCRIPTOR_FLAGS_SUB_SOF:0)| \
((eof)?SLC_DESCRIPTOR_FLAGS_EOF:0)| \
((owner)?SLC_DESCRIPTOR_FLAGS_OWNER:0) \
)
#endif /* _ESP_SLC_REGS_H */

289
core/include/esp/slc_regs.h Normal file
View file

@ -0,0 +1,289 @@
/* esp/slc_regs.h
*
* ESP8266 SLC register definitions
*
* Not compatible with ESP SDK register access code.
*/
#ifndef _ESP_SLC_REGS_H
#define _ESP_SLC_REGS_H
#include "esp/types.h"
#include "common_macros.h"
#define SLC_BASE 0x60000b00
#define SLC (*(struct SLC_REGS *)SLC_BASE)
struct SLC_REGS {
uint32_t volatile CONF0; // 0x00
uint32_t volatile INT_RAW; // 0x04
uint32_t volatile INT_STATUS; // 0x08
uint32_t volatile INT_ENABLE; // 0x0c
uint32_t volatile INT_CLEAR; // 0x10
uint32_t volatile RX_STATUS; // 0x14
uint32_t volatile RX_FIFO_PUSH; // 0x18
uint32_t volatile TX_STATUS; // 0x1c
uint32_t volatile TX_FIFO_POP; // 0x20
uint32_t volatile RX_LINK; // 0x24
uint32_t volatile TX_LINK; // 0x28
uint32_t volatile INTVEC_TO_HOST; // 0x2c
uint32_t volatile TOKEN0; // 0x30
uint32_t volatile TOKEN1; // 0x34
uint32_t volatile CONF1; // 0x38
uint32_t volatile STATE0; // 0x3c
uint32_t volatile STATE1; // 0x40
uint32_t volatile BRIDGE_CONF; // 0x44
uint32_t volatile RX_EOF_DESCRIPTOR_ADDR; // 0x48
uint32_t volatile TX_EOF_DESCRIPTOR_ADDR; // 0x4c
uint32_t volatile RX_EOF_BUFFER_DESCRIPTOR_ADDR; // 0x50 - Naming uncertain
uint32_t volatile AHB_TEST; // 0x54
uint32_t volatile SDIO_STATUS; // 0x58
uint32_t volatile RX_DESCRIPTOR_CONF; // 0x5c
uint32_t volatile TX_LINK_DESCRIPTOR; // 0x60
uint32_t volatile TX_LINK_DESCRIPTOR_BF0; // 0x64
uint32_t volatile TX_LINK_DESCRIPTOR_BF1; // 0x68
uint32_t volatile RX_LINK_DESCRIPTOR; // 0x6c
uint32_t volatile RX_LINK_DESCRIPTOR_BF0; // 0x70
uint32_t volatile RX_LINK_DESCRIPTOR_BF1; // 0x74
uint32_t volatile DATE; // 0x78
uint32_t volatile ID; // 0x7c
uint32_t volatile UNKNOWN_80; // 0x80
uint32_t volatile UNKNOWN_84; // 0x84
uint32_t volatile HOST_INT_RAW; // 0x88
uint32_t volatile UNKNOWN_8C; // 0x8c
uint32_t volatile UNKNOWN_90; // 0x90
uint32_t volatile HOST_CONF_W0; // 0x94
uint32_t volatile HOST_CONF_W1; // 0x98
uint32_t volatile HOST_INT_STATUS; // 0x9c
uint32_t volatile HOST_CONF_W2; // 0xa0
uint32_t volatile HOST_CONF_W3; // 0xa4
uint32_t volatile HOST_CONF_W4; // 0xa8
uint32_t volatile UNKNOWN_AC; // 0xac
uint32_t volatile HOST_INT_CLEAR; // 0xb0
uint32_t volatile HOST_INT_ENABLE; // 0xb4
uint32_t volatile UNKNOWN_B8; // 0xb8
uint32_t volatile HOST_CONF_W5; // 0xbc
};
_Static_assert(sizeof(struct SLC_REGS) == 0xc0, "SLC_REGS is the wrong size");
/* Details for CONF0 register */
#define SLC_CONF0_MODE_M 0x00000003
#define SLC_CONF0_MODE_S 12
#define SLC_CONF0_DATA_BURST_ENABLE BIT(9)
#define SLC_CONF0_DESCRIPTOR_BURST_ENABLE BIT(8)
#define SLC_CONF0_RX_NO_RESTART_CLEAR BIT(7)
#define SLC_CONF0_RX_AUTO_WRITE_BACK BIT(6)
#define SLC_CONF0_RX_LOOP_TEST BIT(5)
#define SLC_CONF0_TX_LOOP_TEST BIT(4)
#define SLC_CONF0_AHBM_RESET BIT(3)
#define SLC_CONF0_AHBM_FIFO_RESET BIT(2)
#define SLC_CONF0_RX_LINK_RESET BIT(1)
#define SLC_CONF0_TX_LINK_RESET BIT(0)
/* Details for INT_RAW register */
#define SLC_INT_RAW_TX_DSCR_EMPTY BIT(21)
#define SLC_INT_RAW_RX_DSCR_ERROR BIT(20)
#define SLC_INT_RAW_TX_DSCR_ERROR BIT(19)
#define SLC_INT_RAW_TO_HOST BIT(18)
#define SLC_INT_RAW_RX_EOF BIT(17)
#define SLC_INT_RAW_RX_DONE BIT(16)
#define SLC_INT_RAW_TX_EOF BIT(15)
#define SLC_INT_RAW_TX_DONE BIT(14)
#define SLC_INT_RAW_TOKEN1_1TO0 BIT(13)
#define SLC_INT_RAW_TOKEN0_1TO0 BIT(12)
#define SLC_INT_RAW_TX_OVERFLOW BIT(11)
#define SLC_INT_RAW_RX_UNDEFLOW BIT(10)
#define SLC_INT_RAW_TX_START BIT(9)
#define SLC_INT_RAW_RX_START BIT(8)
#define SLC_INT_RAW_FROM_HOST_BIT7 BIT(7)
#define SLC_INT_RAW_FROM_HOST_BIT6 BIT(6)
#define SLC_INT_RAW_FROM_HOST_BIT5 BIT(5)
#define SLC_INT_RAW_FROM_HOST_BIT4 BIT(4)
#define SLC_INT_RAW_FROM_HOST_BIT3 BIT(3)
#define SLC_INT_RAW_FROM_HOST_BIT2 BIT(2)
#define SLC_INT_RAW_FROM_HOST_BIT1 BIT(1)
#define SLC_INT_RAW_FROM_HOST_BIT0 BIT(0)
/* Details for INT_STATUS register */
#define SLC_INT_STATUS_TX_DSCR_EMPTY BIT(21)
#define SLC_INT_STATUS_RX_DSCR_ERROR BIT(20)
#define SLC_INT_STATUS_TX_DSCR_ERROR BIT(19)
#define SLC_INT_STATUS_TO_HOST BIT(18)
#define SLC_INT_STATUS_RX_EOF BIT(17)
#define SLC_INT_STATUS_RX_DONE BIT(16)
#define SLC_INT_STATUS_TX_EOF BIT(15)
#define SLC_INT_STATUS_TX_DONE BIT(14)
#define SLC_INT_STATUS_TOKEN1_1TO0 BIT(13)
#define SLC_INT_STATUS_TOKEN0_1TO0 BIT(12)
#define SLC_INT_STATUS_TX_OVERFLOW BIT(11)
#define SLC_INT_STATUS_RX_UNDEFLOW BIT(10)
#define SLC_INT_STATUS_TX_START BIT(9)
#define SLC_INT_STATUS_RX_START BIT(8)
#define SLC_INT_STATUS_FROM_HOST_BIT7 BIT(7)
#define SLC_INT_STATUS_FROM_HOST_BIT6 BIT(6)
#define SLC_INT_STATUS_FROM_HOST_BIT5 BIT(5)
#define SLC_INT_STATUS_FROM_HOST_BIT4 BIT(4)
#define SLC_INT_STATUS_FROM_HOST_BIT3 BIT(3)
#define SLC_INT_STATUS_FROM_HOST_BIT2 BIT(2)
#define SLC_INT_STATUS_FROM_HOST_BIT1 BIT(1)
#define SLC_INT_STATUS_FROM_HOST_BIT0 BIT(0)
/* Details for INT_ENABLE register */
#define SLC_INT_ENABLE_TX_DSCR_EMPTY BIT(21)
#define SLC_INT_ENABLE_RX_DSCR_ERROR BIT(20)
#define SLC_INT_ENABLE_TX_DSCR_ERROR BIT(19)
#define SLC_INT_ENABLE_TO_HOST BIT(18)
#define SLC_INT_ENABLE_RX_EOF BIT(17)
#define SLC_INT_ENABLE_RX_DONE BIT(16)
#define SLC_INT_ENABLE_TX_EOF BIT(15)
#define SLC_INT_ENABLE_TX_DONE BIT(14)
#define SLC_INT_ENABLE_TOKEN1_1TO0 BIT(13)
#define SLC_INT_ENABLE_TOKEN0_1TO0 BIT(12)
#define SLC_INT_ENABLE_TX_OVERFLOW BIT(11)
#define SLC_INT_ENABLE_RX_UNDEFLOW BIT(10)
#define SLC_INT_ENABLE_TX_START BIT(9)
#define SLC_INT_ENABLE_RX_START BIT(8)
#define SLC_INT_ENABLE_FROM_HOST_BIT7 BIT(7)
#define SLC_INT_ENABLE_FROM_HOST_BIT6 BIT(6)
#define SLC_INT_ENABLE_FROM_HOST_BIT5 BIT(5)
#define SLC_INT_ENABLE_FROM_HOST_BIT4 BIT(4)
#define SLC_INT_ENABLE_FROM_HOST_BIT3 BIT(3)
#define SLC_INT_ENABLE_FROM_HOST_BIT2 BIT(2)
#define SLC_INT_ENABLE_FROM_HOST_BIT1 BIT(1)
#define SLC_INT_ENABLE_FROM_HOST_BIT0 BIT(0)
#define SLC_INT_ENABLE_FROM_HOST_BIT_ALL 0xff
/* Details for INT_CLEAR register */
#define SLC_INT_CLEAR_TX_DSCR_EMPTY BIT(21)
#define SLC_INT_CLEAR_RX_DSCR_ERROR BIT(20)
#define SLC_INT_CLEAR_TX_DSCR_ERROR BIT(19)
#define SLC_INT_CLEAR_TO_HOST BIT(18)
#define SLC_INT_CLEAR_RX_EOF BIT(17)
#define SLC_INT_CLEAR_RX_DONE BIT(16)
#define SLC_INT_CLEAR_TX_EOF BIT(15)
#define SLC_INT_CLEAR_TX_DONE BIT(14)
#define SLC_INT_CLEAR_TOKEN1_1TO0 BIT(13)
#define SLC_INT_CLEAR_TOKEN0_1TO0 BIT(12)
#define SLC_INT_CLEAR_TX_OVERFLOW BIT(11)
#define SLC_INT_CLEAR_RX_UNDEFLOW BIT(10)
#define SLC_INT_CLEAR_TX_START BIT(9)
#define SLC_INT_CLEAR_RX_START BIT(8)
#define SLC_INT_CLEAR_FROM_HOST_BIT7 BIT(7)
#define SLC_INT_CLEAR_FROM_HOST_BIT6 BIT(6)
#define SLC_INT_CLEAR_FROM_HOST_BIT5 BIT(5)
#define SLC_INT_CLEAR_FROM_HOST_BIT4 BIT(4)
#define SLC_INT_CLEAR_FROM_HOST_BIT3 BIT(3)
#define SLC_INT_CLEAR_FROM_HOST_BIT2 BIT(2)
#define SLC_INT_CLEAR_FROM_HOST_BIT1 BIT(1)
#define SLC_INT_CLEAR_FROM_HOST_BIT0 BIT(0)
/* Details for RX_STATUS register */
#define SLC_RX_STATUS_EMPTY BIT(1)
#define SLC_RX_STATUS_FULL BIT(0)
/* Details for RX_FIFO_PUSH register */
#define SLC_RX_FIFO_PUSH_FLAG BIT(16)
#define SLC_RX_FIFO_PUSH_DATA_M 0x000001ff
#define SLC_RX_FIFO_PUSH_DATA_S 0
/* Details for TX_STATUS register */
#define SLC_TX_STATUS_EMPTY BIT(1)
#define SLC_TX_STATUS_FULL BIT(0)
/* Details for TX_FIFO_POP register */
#define SLC_TX_FIFO_POP_FLAG BIT(16)
#define SLC_TX_FIFO_POP_DATA_M 0x000007ff
#define SLC_TX_FIFO_POP_DATA_S 0
/* Details for RX_LINK register */
#define SLC_RX_LINK_PARK BIT(31)
#define SLC_RX_LINK_RESTART BIT(30)
#define SLC_RX_LINK_START BIT(29)
#define SLC_RX_LINK_STOP BIT(28)
#define SLC_RX_LINK_DESCRIPTOR_ADDR_M 0x000fffff
#define SLC_RX_LINK_DESCRIPTOR_ADDR_S 0
/* Details for TX_LINK register */
#define SLC_TX_LINK_PARK BIT(31)
#define SLC_TX_LINK_RESTART BIT(30)
#define SLC_TX_LINK_START BIT(29)
#define SLC_TX_LINK_STOP BIT(28)
#define SLC_TX_LINK_DESCRIPTOR_ADDR_M 0x000fffff
#define SLC_TX_LINK_DESCRIPTOR_ADDR_S 0
/* Details for INTVEC_TO_HOST register */
#define SLC_INTVEC_TO_HOST_INTVEC_M 0x000000ff
#define SLC_INTVEC_TO_HOST_INTVEC_S 0
/* Details for TOKEN0 register */
#define SLC_TOKEN0_M 0x00000fff
#define SLC_TOKEN0_S 16
#define SLC_TOKEN0_LOCAL_INC_MORE BIT(14)
#define SLC_TOKEN0_LOCAL_INC BIT(13)
#define SLC_TOKEN0_LOCAL_WRITE BIT(12)
#define SLC_TOKEN0_LOCAL_DATA_M 0x00000FFF
#define SLC_TOKEN0_LOCAL_DATA_S 0
/* Details for TOKEN1 register */
#define SLC_TOKEN1_MASK 0x00000fff
#define SLC_TOKEN1_S 16
#define SLC_TOKEN1_LOCAL_INC_MORE BIT(14)
#define SLC_TOKEN1_LOCAL_INC BIT(13)
#define SLC_TOKEN1_LOCAL_WRITE BIT(12)
#define SLC_TOKEN1_LOCAL_DATA_M 0x00000fff
#define SLC_TOKEN1_LOCAL_DATA_S 0
/* Details for BRIDGE_CONF register */
#define SLC_BRIDGE_CONF_TX_PUSH_IDLE_M 0x0000ffff
#define SLC_BRIDGE_CONF_TX_PUSH_IDLE_S 16
#define SLC_BRIDGE_CONF_TX_DUMMY_MODE BIT(12)
#define SLC_BRIDGE_CONF_FIFO_MAP_ENABLE_M 0x0000000f
#define SLC_BRIDGE_CONF_FIFO_MAP_ENABLE_S 8
#define SLC_BRIDGE_CONF_TX_EOF_ENABLE_M 0x0000003f
#define SLC_BRIDGE_CONF_TX_EOF_ENABLE_S 0
/* Details for AHB_TEST register */
#define SLC_AHB_TEST_ADDR_M 0x00000003
#define SLC_AHB_TEST_ADDR_S 4
#define SLC_AHB_TEST_MODE_M 0x00000007
#define SLC_AHB_TEST_MODE_S 0
/* Details for SDIO_STATUS register */
#define SLC_SDIO_STATUS_BUS_M 0x00000007
#define SLC_SDIO_STATUS_BUS_S 12
#define SLC_SDIO_STATUS_WAKEUP BIT(8)
#define SLC_SDIO_STATUS_FUNC_M 0x0000000f
#define SLC_SDIO_STATUS_FUNC_S 4
#define SLC_SDIO_STATUS_COMMAND_M 0x00000007
#define SLC_SDIO_STATUS_COMMAND_S 0
/* Details for RX_DESCRIPTOR_CONF register */
#define SLC_RX_DESCRIPTOR_CONF_RX_FILL_ENABLE BIT(20)
#define SLC_RX_DESCRIPTOR_CONF_RX_EOF_MODE BIT(19)
#define SLC_RX_DESCRIPTOR_CONF_RX_FILL_MODE BIT(18)
#define SLC_RX_DESCRIPTOR_CONF_INFOR_NO_REPLACE BIT(17)
#define SLC_RX_DESCRIPTOR_CONF_TOKEN_NO_REPLACE BIT(16)
#define SLC_RX_DESCRIPTOR_CONF_POP_IDLE_COUNT_M 0x0000ffff
#define SLC_RX_DESCRIPTOR_CONF_POP_IDLE_COUNT_S 0
#endif /* _ESP_SLC_REGS_H */

272
core/include/esp/spi.h Normal file
View file

@ -0,0 +1,272 @@
/**
* \file Hardware SPI master driver
*
* Part of esp-open-rtos
*
* \copyright Ruslan V. Uss, 2016
* BSD Licensed as described in the file LICENSE
*/
#ifndef _ESP_SPI_H_
#define _ESP_SPI_H_
#include <stdbool.h>
#include <stdint.h>
#include "esp/spi_regs.h"
#include "esp/clocks.h"
/**
* Macro for use with spi_init and spi_set_frequency_div.
* SPI frequency = 80000000 / divider / count
* dvider must be in 1..8192 and count in 1..64
*/
#define SPI_GET_FREQ_DIV(divider, count) (((count) << 16) | ((divider) & 0xffff))
/**
* Predefinded SPI frequency dividers
*/
#define SPI_FREQ_DIV_125K SPI_GET_FREQ_DIV(64, 10) ///< 125kHz
#define SPI_FREQ_DIV_250K SPI_GET_FREQ_DIV(32, 10) ///< 250kHz
#define SPI_FREQ_DIV_500K SPI_GET_FREQ_DIV(16, 10) ///< 500kHz
#define SPI_FREQ_DIV_1M SPI_GET_FREQ_DIV(8, 10) ///< 1MHz
#define SPI_FREQ_DIV_2M SPI_GET_FREQ_DIV(4, 10) ///< 2MHz
#define SPI_FREQ_DIV_4M SPI_GET_FREQ_DIV(2, 10) ///< 4MHz
#define SPI_FREQ_DIV_8M SPI_GET_FREQ_DIV(5, 2) ///< 8MHz
#define SPI_FREQ_DIV_10M SPI_GET_FREQ_DIV(4, 2) ///< 10MHz
#define SPI_FREQ_DIV_20M SPI_GET_FREQ_DIV(2, 2) ///< 20MHz
#define SPI_FREQ_DIV_40M SPI_GET_FREQ_DIV(1, 2) ///< 40MHz
#define SPI_FREQ_DIV_80M SPI_GET_FREQ_DIV(1, 1) ///< 80MHz
#ifdef __cplusplus
extern "C"
{
#endif
typedef enum _spi_mode_t {
SPI_MODE0 = 0, ///< CPOL = 0, CPHA = 0
SPI_MODE1, ///< CPOL = 0, CPHA = 1
SPI_MODE2, ///< CPOL = 1, CPHA = 0
SPI_MODE3 ///< CPOL = 1, CPHA = 1
} spi_mode_t;
typedef enum _spi_endianness_t {
SPI_LITTLE_ENDIAN = 0,
SPI_BIG_ENDIAN
} spi_endianness_t;
typedef enum _spi_word_size_t {
SPI_8BIT = 1, ///< 1 byte
SPI_16BIT = 2, ///< 2 bytes
SPI_32BIT = 4 ///< 4 bytes
} spi_word_size_t;
/**
* SPI bus settings
*/
typedef struct
{
spi_mode_t mode; ///< Bus mode
uint32_t freq_divider; ///< Bus frequency as a divider. See spi_init()
bool msb; ///< MSB first if true
spi_endianness_t endianness; ///< Bus byte order
bool minimal_pins; ///< Minimal set of pins if true. Spee spi_init()
} spi_settings_t;
/**
* \brief Initalize SPI bus
* Initalize specified SPI bus and setup appropriate pins:
* Bus 0:
* - MISO = GPIO 7
* - MOSI = GPIO 8
* - SCK = GPIO 6
* - CS0 = GPIO 11 (if minimal_pins is false)
* - HD = GPIO 9 (if minimal_pins is false)
* - WP = GPIO 10 (if minimal_pins is false)
* Bus 1:
* - MISO = GPIO 12
* - MOSI = GPIO 13
* - SCK = GPIO 14
* - CS0 = GPIO 15 (if minimal_pins is false)
* Note that system flash memory is on the bus 0!
* \param bus Bus ID: 0 - system, 1 - user
* \param mode Bus mode
* \param freq_divider SPI bus frequency divider, use SPI_GET_FREQ_DIV() or predefined value
* \param msb Bit order, MSB first if true
* \param endianness Byte order
* \param minimal_pins If true use the minimal set of pins: MISO, MOSI and SCK.
* \return false when error
*/
bool spi_init(uint8_t bus, spi_mode_t mode, uint32_t freq_divider, bool msb, spi_endianness_t endianness, bool minimal_pins);
/**
* \brief Initalize SPI bus
* spi_init() wrapper.
* Example:
*
* const spi_settings_t my_settings = {
* .mode = SPI_MODE0,
* .freq_divider = SPI_FREQ_DIV_4M,
* .msb = true,
* .endianness = SPI_LITTLE_ENDIAN,
* .minimal_pins = true
* }
* ....
* spi_settings_t old;
* spi_get_settings(1, &old); // save current settings
* //spi_init(1, SPI_MODE0, SPI_FREQ_DIV_4M, true, SPI_LITTLE_ENDIAN, true); // use own settings
* // or
* spi_set_settings(1, &my_settings);
* // some work with spi here
* ....
* spi_set_settings(1, &old); // restore saved settings
*
* \param s Pointer to the settings structure
* \return false when error
*/
static inline bool spi_set_settings(uint8_t bus, const spi_settings_t *s)
{
return spi_init(bus, s->mode, s->freq_divider, s->msb, s->endianness, s->minimal_pins);
}
/**
* \brief Get current settings of the SPI bus
* See spi_set_settings().
* \param bus Bus ID: 0 - system, 1 - user
* \param s Pointer to the structure that receives SPI bus settings
*/
void spi_get_settings(uint8_t bus, spi_settings_t *s);
/**
* \brief Set SPI bus mode
* \param bus Bus ID: 0 - system, 1 - user
* \param mode Bus mode
*/
void spi_set_mode(uint8_t bus, spi_mode_t mode);
/**
* \brief Get mode of the SPI bus
* \param bus Bus ID: 0 - system, 1 - user
* \return Bus mode
*/
spi_mode_t spi_get_mode(uint8_t bus);
/**
* \brief Set SPI bus frequency
* Examples:
*
* spi_set_frequency_div(1, SPI_FREQ_DIV_8M); // 8 MHz, predefined value
* ...
* spi_set_frequency_div(1, SPI_GET_FREQ_DIV(8, 10)); // divider = 8, count = 10,
* // frequency = 80000000 Hz / 8 / 10 = 1000000 Hz
*
* \param bus Bus ID: 0 - system, 1 - user
* \param divider Predivider of the system bus frequency (80MHz) in the 2 low
* bytes and period pulses count in the third byte. Please note that
* divider must be be in range 1..8192 and count in range 2..64. Use the
* macro SPI_GET_FREQ_DIV(divider, count) to get the correct parameter value.
*/
void spi_set_frequency_div(uint8_t bus, uint32_t divider);
/**
* \brief Get SPI bus frequency as a divider
* Example:
*
* uint32_t old_freq = spi_get_frequency_div(1);
* spi_set_frequency_div(1, SPI_FREQ_DIV_8M);
* ...
* spi_set_frequency_div(1, old_freq);
*
* \param bus Bus ID: 0 - system, 1 - user
* \return SPI frequency, as divider.
*/
inline uint32_t spi_get_frequency_div(uint8_t bus)
{
return (FIELD2VAL(SPI_CLOCK_DIV_PRE, SPI(bus).CLOCK) + 1) |
(FIELD2VAL(SPI_CLOCK_COUNT_NUM, SPI(bus).CLOCK) + 1);
}
/**
* \brief Get SPI bus frequency in Hz
* \param bus Bus ID: 0 - system, 1 - user
* \return SPI frequency, Hz
*/
inline uint32_t spi_get_frequency_hz(uint8_t bus)
{
return APB_CLK_FREQ /
(FIELD2VAL(SPI_CLOCK_DIV_PRE, SPI(bus).CLOCK) + 1) /
(FIELD2VAL(SPI_CLOCK_COUNT_NUM, SPI(bus).CLOCK) + 1);
}
/**
* \brief Set SPI bus bit order
* \param bus Bus ID: 0 - system, 1 - user
* \param msb Bit order, MSB first if true
*/
void spi_set_msb(uint8_t bus, bool msb);
/**
* \brief Get SPI bus bit order
* \param bus Bus ID: 0 - system, 1 - user
* \return msb Bit order, MSB first if true
*/
inline bool spi_get_msb(uint8_t bus)
{
return !(SPI(bus).CTRL0 & (SPI_CTRL0_WR_BIT_ORDER | SPI_CTRL0_RD_BIT_ORDER));
}
/**
* \brief Set SPI bus byte order
* \param bus Bus ID: 0 - system, 1 - user
* \param endianness Byte order
*/
void spi_set_endianness(uint8_t bus, spi_endianness_t endianness);
/**
* \brief Get SPI bus byte order
* \param bus Bus ID: 0 - system, 1 - user
* \return endianness Byte order
*/
inline spi_endianness_t spi_get_endianness(uint8_t bus)
{
return SPI(bus).USER0 & (SPI_USER0_WR_BYTE_ORDER | SPI_USER0_RD_BYTE_ORDER)
? SPI_BIG_ENDIAN
: SPI_LITTLE_ENDIAN;
}
/**
* \brief Transfer 8 bits over SPI
* \param bus Bus ID: 0 - system, 1 - user
* \param data Byte to send
* \return Received byte
*/
uint8_t spi_transfer_8(uint8_t bus, uint8_t data);
/**
* \brief Transfer 16 bits over SPI
* \param bus Bus ID: 0 - system, 1 - user
* \param data Word to send
* \return Received word
*/
uint16_t spi_transfer_16(uint8_t bus, uint16_t data);
/**
* \brief Transfer 32 bits over SPI
* \param bus Bus ID: 0 - system, 1 - user
* \param data dword to send
* \return Received dword
*/
uint32_t spi_transfer_32(uint8_t bus, uint32_t data);
/**
* \brief Transfer buffer of words over SPI
* Please note that the buffer size is in words, not in bytes!
* Example:
*
* const uint16_t out_buf[] = { 0xa0b0, 0xa1b1, 0xa2b2, 0xa3b3 };
* uint16_t in_buf[sizeof(out_buf)];
* spi_init(1, SPI_MODE1, SPI_FREQ_DIV_4M, true, SPI_BIG_ENDIAN, true);
* spi_transfer(1, out_buf, in_buf, sizeof(out_buf), SPI_16BIT); // len = 4 words * 2 bytes = 8 bytes
*
* \param bus Bus ID: 0 - system, 1 - user
* \param out_data Data to send.
* \param in_data Receive buffer. If NULL, received data will be lost.
* \param len Buffer size in words
* \param word_size Size of the word
* \return Transmitted/received words count
*/
size_t spi_transfer(uint8_t bus, const void *out_data, void *in_data, size_t len, spi_word_size_t word_size);
#ifdef __cplusplus
}
#endif
#endif /* _ESP_SPI_H_ */

View file

@ -150,6 +150,7 @@ _Static_assert(sizeof(struct SPI_REGS) == 0x100, "SPI_REGS is the wrong size");
#define SPI_USER0_CS_SETUP BIT(5)
#define SPI_USER0_CS_HOLD BIT(4)
#define SPI_USER0_FLASH_MODE BIT(2)
#define SPI_USER0_DUPLEX BIT(0)
/* Details for USER1 register */
@ -171,6 +172,7 @@ _Static_assert(sizeof(struct SPI_REGS) == 0x100, "SPI_REGS is the wrong size");
/* Details for PIN register */
#define SPI_PIN_IDLE_EDGE BIT(29) ///< CPOL
#define SPI_PIN_CS2_DISABLE BIT(2)
#define SPI_PIN_CS1_DISABLE BIT(1)
#define SPI_PIN_CS0_DISABLE BIT(0)

View file

@ -10,6 +10,7 @@
#define _ESP_TIMER_H
#include <stdbool.h>
#include <errno.h>
#include "esp/timer_regs.h"
#include "esp/interrupts.h"
@ -23,43 +24,73 @@ typedef enum {
} timer_frc_t;
/* Return current count value for timer. */
INLINED uint32_t timer_get_count(const timer_frc_t frc);
static inline uint32_t timer_get_count(const timer_frc_t frc)
{
return TIMER(frc).COUNT;
}
/* Return current load value for timer. */
INLINED uint32_t timer_get_load(const timer_frc_t frc);
static inline uint32_t timer_get_load(const timer_frc_t frc)
{
return TIMER(frc).LOAD;
}
/* Write load value for timer. */
INLINED void timer_set_load(const timer_frc_t frc, const uint32_t load);
static inline void timer_set_load(const timer_frc_t frc, const uint32_t load)
{
TIMER(frc).LOAD = load;
}
/* Returns maximum load value for timer. */
INLINED uint32_t timer_max_load(const timer_frc_t frc);
static inline uint32_t timer_max_load(const timer_frc_t frc)
{
return (frc == FRC1) ? TIMER_FRC1_MAX_LOAD : UINT32_MAX;
}
/* Set the timer divider value */
INLINED void timer_set_divider(const timer_frc_t frc, const timer_clkdiv_t div);
static inline void timer_set_divider(const timer_frc_t frc, const timer_clkdiv_t div)
{
if(div < TIMER_CLKDIV_1 || div > TIMER_CLKDIV_256)
return;
TIMER(frc).CTRL = SET_FIELD(TIMER(frc).CTRL, TIMER_CTRL_CLKDIV, 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);
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);
static inline void timer_set_run(const timer_frc_t frc, const bool run)
{
if (run)
TIMER(frc).CTRL |= TIMER_CTRL_RUN;
else
TIMER(frc).CTRL &= ~TIMER_CTRL_RUN;
}
/* Get the run state of the timer (on or off) */
INLINED bool timer_get_run(const timer_frc_t frc);
static inline bool timer_get_run(const timer_frc_t frc)
{
return TIMER(frc).CTRL & TIMER_CTRL_RUN;
}
/* Set timer auto-reload on or off */
INLINED void timer_set_reload(const timer_frc_t frc, const bool reload);
static inline void timer_set_reload(const timer_frc_t frc, const bool reload)
{
if (reload)
TIMER(frc).CTRL |= TIMER_CTRL_RELOAD;
else
TIMER(frc).CTRL &= ~TIMER_CTRL_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_clkdiv_t timer_freq_to_div(uint32_t freq);
static inline bool timer_get_reload(const timer_frc_t frc)
{
return TIMER(frc).CTRL & TIMER_CTRL_RELOAD;
}
/* Return the number of timer counts to achieve the specified
* frequency with the specified divisor.
@ -68,14 +99,41 @@ INLINED timer_clkdiv_t timer_freq_to_div(uint32_t freq);
*
* 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_clkdiv_t div);
uint32_t timer_freq_to_count(const timer_frc_t frc, uint32_t freq, const timer_clkdiv_t div);
/* Return a suitable timer divider for the specified frequency,
or -1 if none is found.
*/
static inline timer_clkdiv_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_CLKDIV_1;
else if(freq > 100)
return TIMER_CLKDIV_16;
else
return TIMER_CLKDIV_256;
}
/* Return a suitable timer divider for the specified duration in
microseconds or -1 if none is found.
*/
INLINED timer_clkdiv_t timer_time_to_div(uint32_t us);
static inline timer_clkdiv_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_CLKDIV_1;
else if(us < 10*1000)
return TIMER_CLKDIV_16;
else
return TIMER_CLKDIV_256;
}
/* Return the number of timer counts for the specified timer duration
* in microseconds, when using the specified divisor.
@ -84,9 +142,8 @@ INLINED timer_clkdiv_t timer_time_to_div(uint32_t us);
*
* 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_clkdiv_t div);
uint32_t timer_time_to_count(const timer_frc_t frc, uint32_t us, const timer_clkdiv_t div);
/* Set a target timer interrupt frequency in Hz.
@ -103,12 +160,9 @@ INLINED uint32_t timer_time_to_count(const timer_frc_t frc, uint32_t us, const t
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.
Returns 0 on success, or -EINVAL if given frequency could not be set.
*/
INLINED bool timer_set_frequency(const timer_frc_t frc, uint32_t freq);
int timer_set_frequency(const timer_frc_t frc, uint32_t freq);
/* Sets the timer for a oneshot interrupt in 'us' microseconds.
@ -123,14 +177,9 @@ INLINED bool timer_set_frequency(const timer_frc_t frc, uint32_t freq);
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.
Returns 0 on success, or -EINVAL if the given timeout could not be set.
*/
INLINED bool timer_set_timeout(const timer_frc_t frc, uint32_t us);
#include "timer_private.h"
int timer_set_timeout(const timer_frc_t frc, uint32_t us);
#ifdef __cplusplus
}

View file

@ -1,266 +0,0 @@
/* 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
#ifdef __cplusplus
extern "C" {
#endif
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include "esp/dport_regs.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 };
INLINED uint32_t timer_get_count(const timer_frc_t frc)
{
return TIMER(frc).COUNT;
}
INLINED uint32_t timer_get_load(const timer_frc_t frc)
{
return TIMER(frc).LOAD;
}
INLINED void timer_set_load(const timer_frc_t frc, const uint32_t load)
{
TIMER(frc).LOAD = load;
}
INLINED uint32_t timer_max_load(const timer_frc_t frc)
{
return (frc == FRC1) ? TIMER_FRC1_MAX_LOAD : UINT32_MAX;
}
INLINED void timer_set_divider(const timer_frc_t frc, const timer_clkdiv_t div)
{
if(div < TIMER_CLKDIV_1 || div > TIMER_CLKDIV_256)
return;
TIMER(frc).CTRL = SET_FIELD(TIMER(frc).CTRL, TIMER_CTRL_CLKDIV, div);
}
INLINED void timer_set_interrupts(const timer_frc_t frc, bool enable)
{
const uint32_t dp_bit = (frc == FRC1) ? DPORT_INT_ENABLE_FRC1 : DPORT_INT_ENABLE_FRC2;
const uint32_t int_mask = BIT((frc == FRC1) ? INUM_TIMER_FRC1 : INUM_TIMER_FRC2);
if(enable) {
DPORT.INT_ENABLE |= dp_bit;
_xt_isr_unmask(int_mask);
} else {
DPORT.INT_ENABLE &= ~dp_bit;
_xt_isr_mask(int_mask);
}
}
INLINED void timer_set_run(const timer_frc_t frc, const bool run)
{
if (run)
TIMER(frc).CTRL |= TIMER_CTRL_RUN;
else
TIMER(frc).CTRL &= ~TIMER_CTRL_RUN;
}
INLINED bool timer_get_run(const timer_frc_t frc)
{
return TIMER(frc).CTRL & TIMER_CTRL_RUN;
}
INLINED void timer_set_reload(const timer_frc_t frc, const bool reload)
{
if (reload)
TIMER(frc).CTRL |= TIMER_CTRL_RELOAD;
else
TIMER(frc).CTRL &= ~TIMER_CTRL_RELOAD;
}
INLINED bool timer_get_reload(const timer_frc_t frc)
{
return TIMER(frc).CTRL & TIMER_CTRL_RELOAD;
}
INLINED timer_clkdiv_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_CLKDIV_1;
else if(freq > 100)
return TIMER_CLKDIV_16;
else
return TIMER_CLKDIV_256;
}
/* 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_clkdiv_t div)
{
if(div < TIMER_CLKDIV_1 || div > TIMER_CLKDIV_256)
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_clkdiv_t div);
INLINED uint32_t timer_freq_to_count(const timer_frc_t frc, const uint32_t freq, const timer_clkdiv_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_clkdiv_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_CLKDIV_1;
else if(us < 10*1000)
return TIMER_CLKDIV_16;
else
return TIMER_CLKDIV_256;
}
/* 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_clkdiv_t div)
{
if(div < TIMER_CLKDIV_1 || div > TIMER_CLKDIV_256)
return 0; /* invalid divider */
const uint32_t TIMER_MAX = timer_max_load(frc);
if(div != TIMER_CLKDIV_256) /* 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_CLKDIV_1) ? _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_clkdiv_t div);
INLINED uint32_t timer_time_to_count(const timer_frc_t frc, uint32_t us, const timer_clkdiv_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_clkdiv_t div = timer_freq_to_div(freq);
counts = timer_freq_to_count(frc, freq, div);
if(counts == 0)
{
printf("ABORT: No counter for timer %u frequency %u\r\n", frc, freq);
abort();
}
timer_set_divider(frc, div);
if(frc == 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(1).ALARM = counts + TIMER(1).COUNT;
}
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_clkdiv_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 == FRC1)
{
timer_set_load(frc, counts);
}
else /* FRC2 */
{
TIMER(1).ALARM = counts + TIMER(1).COUNT;
}
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);
}
#ifdef __cplusplus
}
#endif
#endif