Removed INLINED (force inline) macro.

Progress towards #57.
This commit is contained in:
Angus Gratton 2015-11-28 18:01:03 +11:00
parent c58cc326dc
commit c0c3280d12
8 changed files with 55 additions and 110 deletions

View file

@ -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; }

View file

@ -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

View file

@ -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]);
} }

View file

@ -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));
} }

View file

@ -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

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

@ -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

View file

@ -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));