parent
2d6eeb83ea
commit
812c2fef21
8 changed files with 55 additions and 110 deletions
|
@ -7,14 +7,15 @@
|
||||||
#include "esp/iomux.h"
|
#include "esp/iomux.h"
|
||||||
#include "common_macros.h"
|
#include "common_macros.h"
|
||||||
|
|
||||||
/* These are non-static versions of the GPIO mapping tables in
|
const static IRAM_DATA uint32_t IOMUX_TO_GPIO[] = { 12, 13, 14, 15, 3, 1, 6, 7, 8, 9, 10, 11, 0, 2, 4, 5 };
|
||||||
iomux.h, so if they need to be linked only one copy is linked for
|
const static IRAM_DATA uint32_t GPIO_TO_IOMUX[] = { 12, 5, 13, 4, 14, 15, 6, 7, 8, 9, 10, 11, 0, 1, 2, 3 };
|
||||||
the entire program.
|
|
||||||
|
|
||||||
These are only ever linked in if the arguments to gpio_to_ionum
|
uint8_t IRAM gpio_to_iomux(const uint8_t gpio_number)
|
||||||
or ionum_to_gpio are not known at compile time.
|
{
|
||||||
|
return GPIO_TO_IOMUX[gpio_number];
|
||||||
|
}
|
||||||
|
|
||||||
Arrays are declared as 32-bit integers in IROM to save RAM.
|
uint8_t IRAM iomux_to_gpio(const uint8_t iomux_number)
|
||||||
*/
|
{
|
||||||
const IROM uint32_t GPIO_TO_IOMUX_MAP[] = _GPIO_TO_IOMUX;
|
return IOMUX_TO_GPIO[iomux_number];
|
||||||
const IROM uint32_t IOMUX_TO_GPIO_MAP[] = _IOMUX_TO_GPIO;
|
}
|
||||||
|
|
|
@ -53,8 +53,30 @@
|
||||||
#define IROM __attribute__((section(".irom0.literal"))) const
|
#define IROM __attribute__((section(".irom0.literal"))) const
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define INLINED inline static __attribute__((always_inline)) __attribute__((unused))
|
/* Use this macro to place functions into Instruction RAM (IRAM)
|
||||||
|
instead of flash memory (IROM).
|
||||||
|
|
||||||
|
This is useful for functions which are called when the flash may
|
||||||
|
not be available (for example during NMI exceptions), or for
|
||||||
|
functions which are called very frequently and need high
|
||||||
|
performance.
|
||||||
|
|
||||||
|
Bear in mind IRAM is limited (32KB), compared to up to 1MB of flash.
|
||||||
|
*/
|
||||||
#define IRAM __attribute__((section(".iram1.text")))
|
#define IRAM __attribute__((section(".iram1.text")))
|
||||||
|
|
||||||
|
/* Use this macro to place read-only data into Instruction RAM (IRAM)
|
||||||
|
instead of loaded into rodata which resides in DRAM.
|
||||||
|
|
||||||
|
This may be useful to free up data RAM. However all data read from
|
||||||
|
the instruction space must be 32-bit aligned word reads
|
||||||
|
(non-aligned reads will use an interrupt routine to "fix" them and
|
||||||
|
still work, but are very slow..
|
||||||
|
*/
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define IRAM_DATA __attribute__((section(".iram1.rodata")))
|
||||||
|
#else
|
||||||
|
#define IRAM_DATA __attribute__((section(".iram1.rodata"))) const
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -23,41 +23,14 @@ typedef enum {
|
||||||
/* Enable GPIO on the specified pin, and set it to input/output/ with
|
/* Enable GPIO on the specified pin, and set it to input/output/ with
|
||||||
* pullup as needed
|
* pullup as needed
|
||||||
*/
|
*/
|
||||||
INLINED void gpio_enable(const uint8_t gpio_num, const gpio_direction_t direction)
|
void gpio_enable(const uint8_t gpio_num, const gpio_direction_t direction);
|
||||||
{
|
|
||||||
uint32_t iomux_flags;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Disable GPIO on the specified pin, and set it Hi-Z.
|
/* Disable GPIO on the specified pin, and set it Hi-Z.
|
||||||
*
|
*
|
||||||
* If later muxing this pin to a different function, make sure to set
|
* If later muxing this pin to a different function, make sure to set
|
||||||
* IOMUX_PIN_OUTPUT_ENABLE if necessary to enable the output buffer.
|
* 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.ENABLE_OUT_CLEAR = BIT(gpio_num);
|
||||||
*gpio_iomux_reg(gpio_num) &= ~IOMUX_PIN_OUTPUT_ENABLE;
|
*gpio_iomux_reg(gpio_num) &= ~IOMUX_PIN_OUTPUT_ENABLE;
|
||||||
|
@ -67,7 +40,7 @@ INLINED void gpio_disable(const uint8_t gpio_num)
|
||||||
*
|
*
|
||||||
* Only works if pin has been set to GPIO_OUTPUT via gpio_enable()
|
* Only works if pin has been set to GPIO_OUTPUT via gpio_enable()
|
||||||
*/
|
*/
|
||||||
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);
|
GPIO.OUT_SET = BIT(gpio_num);
|
||||||
|
@ -79,7 +52,7 @@ INLINED void gpio_write(const uint8_t gpio_num, const bool set)
|
||||||
*
|
*
|
||||||
* Only works if pin has been set to GPIO_OUTPUT via gpio_enable()
|
* Only works if pin has been set to GPIO_OUTPUT via gpio_enable()
|
||||||
*/
|
*/
|
||||||
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?
|
/* Why implement like this instead of GPIO_OUT_REG ^= xxx?
|
||||||
Concurrency. If an interrupt or higher priority task writes to
|
Concurrency. If an interrupt or higher priority task writes to
|
||||||
|
@ -98,7 +71,7 @@ INLINED void gpio_toggle(const uint8_t gpio_num)
|
||||||
* If pin is set as an input, this reads the value on the 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 as an output, this reads the last value written to the pin.
|
||||||
*/
|
*/
|
||||||
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);
|
return GPIO.IN & BIT(gpio_num);
|
||||||
}
|
}
|
||||||
|
@ -109,7 +82,7 @@ extern void gpio_interrupt_handler(void);
|
||||||
*
|
*
|
||||||
* 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);
|
GPIO.CONF[gpio_num] = SET_FIELD(GPIO.CONF[gpio_num], GPIO_CONF_INTTYPE, int_type);
|
||||||
if(int_type != GPIO_INTTYPE_NONE) {
|
if(int_type != GPIO_INTTYPE_NONE) {
|
||||||
|
@ -119,7 +92,7 @@ INLINED void gpio_set_interrupt(const uint8_t gpio_num, const gpio_inttype_t int
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the interrupt type set for a pin */
|
/* 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]);
|
return (gpio_inttype_t)FIELD2VAL(GPIO_CONF_INTTYPE, GPIO.CONF[gpio_num]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ void sdk__xt_tick_timer_init (void);
|
||||||
void sdk__xt_timer_int(void);
|
void sdk__xt_timer_int(void);
|
||||||
void sdk__xt_timer_int1(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;
|
uint32_t level;
|
||||||
__asm__ volatile("rsr %0, intlevel" : "=a"(level));
|
__asm__ volatile("rsr %0, intlevel" : "=a"(level));
|
||||||
|
@ -53,7 +53,7 @@ INLINED uint32_t _xt_get_intlevel(void)
|
||||||
portDISABLE_INTERRUPTS/portENABLE_INTERRUPTS for
|
portDISABLE_INTERRUPTS/portENABLE_INTERRUPTS for
|
||||||
non-FreeRTOS & non-portable code.
|
non-FreeRTOS & non-portable code.
|
||||||
*/
|
*/
|
||||||
INLINED uint32_t _xt_disable_interrupts(void)
|
static inline uint32_t _xt_disable_interrupts(void)
|
||||||
{
|
{
|
||||||
uint32_t old_level;
|
uint32_t old_level;
|
||||||
__asm__ volatile ("rsil %0, " XTSTR(XCHAL_EXCM_LEVEL) : "=a" (old_level));
|
__asm__ volatile ("rsil %0, " XTSTR(XCHAL_EXCM_LEVEL) : "=a" (old_level));
|
||||||
|
@ -61,14 +61,14 @@ INLINED uint32_t _xt_disable_interrupts(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Restore PS level. Intended to be used with _xt_disable_interrupts */
|
/* 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));
|
__asm__ volatile ("wsr %0, ps; rsync" :: "a" (new_ps));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ESPTODO: the mask/unmask functions aren't thread safe */
|
/* 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;
|
uint32_t intenable;
|
||||||
asm volatile ("rsr %0, intenable" : "=a" (intenable));
|
asm volatile ("rsr %0, intenable" : "=a" (intenable));
|
||||||
|
@ -76,7 +76,7 @@ INLINED void _xt_isr_unmask(uint32_t unmask)
|
||||||
asm volatile ("wsr %0, intenable; esync" :: "a" (intenable));
|
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;
|
uint32_t intenable;
|
||||||
asm volatile ("rsr %0, intenable" : "=a" (intenable));
|
asm volatile ("rsr %0, intenable" : "=a" (intenable));
|
||||||
|
@ -84,14 +84,14 @@ INLINED void _xt_isr_mask (uint32_t mask)
|
||||||
asm volatile ("wsr %0, intenable; esync" :: "a" (intenable));
|
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;
|
uint32_t interrupt;
|
||||||
asm volatile ("rsr %0, interrupt" : "=a" (interrupt));
|
asm volatile ("rsr %0, interrupt" : "=a" (interrupt));
|
||||||
return 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));
|
asm volatile ("wsr %0, intclear; esync" :: "a" (mask));
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ extern "C" {
|
||||||
* known at compile time, or return the result from a lookup table if not.
|
* 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.
|
* 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.
|
* 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
|
* Directly get the IOMUX register for a particular gpio number
|
||||||
|
@ -64,10 +64,6 @@ inline static void iomux_set_gpio_function(const uint8_t gpio_number, const uint
|
||||||
IOMUX.PIN[reg_idx] = func | flags;
|
IOMUX.PIN[reg_idx] = func | flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* esp_iomux_private contains implementation parts of the inline functions
|
|
||||||
declared above */
|
|
||||||
#include "esp/iomux_private.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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
|
|
|
@ -12,9 +12,6 @@ const int gpio = 14;
|
||||||
|
|
||||||
/* This task uses the high level GPIO API (esp_gpio.h) to blink an LED.
|
/* This task uses the high level GPIO API (esp_gpio.h) to blink an LED.
|
||||||
*
|
*
|
||||||
* Even though it reads better than the register-level version in blinkenRegisterTask,
|
|
||||||
* they compile to the exact same instructions (except gpio_enable also set the output type in
|
|
||||||
* the GPIO control register).
|
|
||||||
*/
|
*/
|
||||||
void blinkenTask(void *pvParameters)
|
void blinkenTask(void *pvParameters)
|
||||||
{
|
{
|
||||||
|
@ -28,10 +25,12 @@ void blinkenTask(void *pvParameters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* This task uses all raw register operations to set the pins.
|
/* This task demonstrates an alternative way to use raw register
|
||||||
|
operations to blink an LED.
|
||||||
|
|
||||||
It's not fully parameterised, as the IOMUX_GPIO# macros involve a non-linear
|
The step that sets the iomux register can't be automatically
|
||||||
mapping from GPIO to IOMUX ports.
|
updated from the 'gpio' constant variable, so you need to change
|
||||||
|
the line that sets IOMUX_GPIO14 if you change 'gpio'.
|
||||||
|
|
||||||
There is no significant performance benefit to this way over the
|
There is no significant performance benefit to this way over the
|
||||||
blinkenTask version, so it's probably better to use the blinkenTask
|
blinkenTask version, so it's probably better to use the blinkenTask
|
||||||
|
|
|
@ -17,7 +17,7 @@ const char *dramtest = TESTSTRING;
|
||||||
const __attribute__((section(".iram1.notrodata"))) char iramtest[] = TESTSTRING;
|
const __attribute__((section(".iram1.notrodata"))) char iramtest[] = TESTSTRING;
|
||||||
const __attribute__((section(".text.notrodata"))) char iromtest[] = TESTSTRING;
|
const __attribute__((section(".text.notrodata"))) char iromtest[] = TESTSTRING;
|
||||||
|
|
||||||
INLINED uint32_t get_ccount (void)
|
static inline uint32_t get_ccount (void)
|
||||||
{
|
{
|
||||||
uint32_t ccount;
|
uint32_t ccount;
|
||||||
asm volatile ("rsr.ccount %0" : "=a" (ccount));
|
asm volatile ("rsr.ccount %0" : "=a" (ccount));
|
||||||
|
|
Loading…
Reference in a new issue