mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-06-29 13:17:58 +08:00
feat(esp8266): Add new "ets_vprintf" to save stack
It is better for interrupt and NMI functions to output information.
This commit is contained in:
@ -49,6 +49,26 @@ config ESP_FILENAME_MACRO_NULL
|
||||
bool "null"
|
||||
endchoice
|
||||
|
||||
config USING_NEW_ETS_VPRINTF
|
||||
bool "Using new ets_vprintf instead of rom code"
|
||||
default y
|
||||
help
|
||||
Enable this option, SDK will use new "ets_vprintf" function instead of old code "ets_vprintf" which is depend on ROM
|
||||
code "ets_io_vprintf".
|
||||
|
||||
Note: Bootloader can't use this function.
|
||||
|
||||
config LINK_ETS_PRINTF_TO_IRAM
|
||||
bool "Link ets_printf to IRAM"
|
||||
default n
|
||||
help
|
||||
Enable this option, SDK will link the old/new "ets_printf" and "ets_vprintf" to IRAM instead of flash.
|
||||
So although flash can't be access for SoC when reading to writing, the "ets_printf" and "ets_vprintf" also can be used by user.
|
||||
|
||||
Using new "ets_vprintf" should cost more 1.6KB IRAM.
|
||||
|
||||
Note: Bootloader can't use this function.
|
||||
|
||||
config SOC_FULL_ICACHE
|
||||
bool "Enable full cache mode"
|
||||
default n
|
||||
|
@ -129,6 +129,10 @@ SECTIONS
|
||||
*libfreertos.a:freertos_hooks.o(.bss .data .bss.* .data.* COMMON)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_LINK_ETS_PRINTF_TO_IRAM
|
||||
*libesp8266.a:ets_printf.o(.literal .text .literal.* .text.* .rodata.* .rodata)
|
||||
#endif
|
||||
|
||||
_text_end = ABSOLUTE(.);
|
||||
_etext = .;
|
||||
} >iram1_0_seg :iram1_0_phdr
|
||||
|
@ -13,6 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
@ -22,7 +23,7 @@
|
||||
#include "esp8266/uart_register.h"
|
||||
#include "esp8266/rom_functions.h"
|
||||
|
||||
int IRAM_ATTR ets_putc(int c)
|
||||
int ets_putc(int c)
|
||||
{
|
||||
while (1) {
|
||||
uint32_t fifo_cnt = READ_PERI_REG(UART_STATUS(CONFIG_CONSOLE_UART_NUM)) & (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S);
|
||||
@ -36,15 +37,240 @@ int IRAM_ATTR ets_putc(int c)
|
||||
return c;
|
||||
}
|
||||
|
||||
int IRAM_ATTR ets_vprintf(const char *fmt, va_list ap)
|
||||
#if defined(CONFIG_USING_NEW_ETS_VPRINTF) && !defined(BOOTLOADER_BUILD)
|
||||
|
||||
#define FILL_0 0x01
|
||||
#define FILL_LEFT 0x02
|
||||
#define POINTOR 0x04
|
||||
#define ALTERNATE 0x08
|
||||
#define OUPUT_INT 0x10
|
||||
#define START 0x20
|
||||
|
||||
#define VINT_STR_MAX 10
|
||||
|
||||
typedef union _val_cache {
|
||||
uint8_t val8;
|
||||
int32_t val32;
|
||||
uint32_t val32u;
|
||||
const char *valcp;
|
||||
} val_cache_t;
|
||||
|
||||
typedef struct _val_attr {
|
||||
int8_t type;
|
||||
uint8_t state;
|
||||
uint8_t fillbytes;
|
||||
uint8_t precision;
|
||||
|
||||
val_cache_t value;
|
||||
} val_attr_t;
|
||||
|
||||
#define isdigit(_c) ((_c <= '9') && (_c >= '0'))
|
||||
#define fill_num(_attr) ((attr)->fillbytes)
|
||||
#define isfill_0(_attr) (fill_num(_attr) && ((_attr)->state & FILL_0))
|
||||
#define isfill_left(_attr) (fill_num(_attr) && ((_attr)->state & FILL_LEFT))
|
||||
#define isstart(_attr) ((_attr)->state & START)
|
||||
|
||||
static inline void ets_printf_ch_mutlti(uint32_t c, uint32_t len)
|
||||
{
|
||||
while (len--)
|
||||
ets_putc(c);
|
||||
}
|
||||
|
||||
static inline void ets_printf_buf(const char *s, uint32_t len)
|
||||
{
|
||||
while (len--)
|
||||
ets_putc(*s++);
|
||||
}
|
||||
|
||||
static int ets_printf_str(const val_attr_t * const attr)
|
||||
{
|
||||
const char *s = attr->value.valcp;
|
||||
s = s == NULL ? "<null>" : s;
|
||||
|
||||
if (fill_num(attr)) {
|
||||
unsigned char left;
|
||||
unsigned char len;
|
||||
|
||||
while (*s != '\0')
|
||||
s++;
|
||||
len = s - attr->value.valcp;
|
||||
left = fill_num(attr) > len ? fill_num(attr) - len : 0;
|
||||
|
||||
if (!isfill_left(attr)) {
|
||||
ets_printf_ch_mutlti(' ', left);
|
||||
}
|
||||
|
||||
ets_printf_buf(attr->value.valcp, len);
|
||||
|
||||
if (isfill_left(attr)) {
|
||||
ets_printf_ch_mutlti(' ', left);
|
||||
}
|
||||
} else {
|
||||
while (*s != '\0')
|
||||
ets_putc(*s++);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ets_printf_int(val_attr_t * const attr, uint8_t hex)
|
||||
{
|
||||
char buf[VINT_STR_MAX];
|
||||
unsigned char offset = VINT_STR_MAX;
|
||||
|
||||
if (attr->value.val32u != 0) {
|
||||
for (; attr->value.val32u > 0; attr->value.val32u /= hex) {
|
||||
unsigned char c = attr->value.val32u % hex;
|
||||
if (c < 10)
|
||||
buf[--offset] = c + '0';
|
||||
else
|
||||
buf[--offset] = c + 'a' - 10;
|
||||
}
|
||||
} else
|
||||
buf[--offset] = '0';
|
||||
|
||||
if (fill_num(attr)) {
|
||||
char fill_data = isfill_0(attr) ? '0' : ' ';
|
||||
unsigned char len = fill_num(attr) - (VINT_STR_MAX - offset);
|
||||
unsigned char left = fill_num(attr) > (VINT_STR_MAX - offset) ? len : 0;
|
||||
|
||||
if (!isfill_left(attr)) {
|
||||
ets_printf_ch_mutlti(fill_data, left);
|
||||
}
|
||||
|
||||
ets_printf_buf(&buf[offset], VINT_STR_MAX - offset);
|
||||
|
||||
if (isfill_left(attr)) {
|
||||
ets_printf_ch_mutlti(fill_data, left);
|
||||
}
|
||||
} else {
|
||||
ets_printf_buf(&buf[offset], VINT_STR_MAX - offset);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ets_vprintf(const char *fmt, va_list va)
|
||||
{
|
||||
for (; ;) {
|
||||
const char *ps = fmt;
|
||||
val_attr_t attr;
|
||||
|
||||
while (*ps != '\0' && *ps != '%')
|
||||
ets_putc(*ps++);
|
||||
|
||||
if (*ps == '\0')
|
||||
break;
|
||||
|
||||
fmt = ps;
|
||||
|
||||
attr.state = 0;
|
||||
attr.type = -1;
|
||||
attr.fillbytes = 0;
|
||||
attr.precision = 0;
|
||||
|
||||
for (; ;) {
|
||||
switch (*++ps) {
|
||||
case 'd':
|
||||
case 'i':
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'c':
|
||||
case 's':
|
||||
case 'p':
|
||||
case '\0':
|
||||
attr.type = *ps++;
|
||||
break;
|
||||
case '#':
|
||||
attr.state |= ALTERNATE;
|
||||
ps++;
|
||||
break;
|
||||
case '0'...'9':
|
||||
if (!isstart(&attr) && *ps == '0') {
|
||||
attr.state |= FILL_0;
|
||||
} else {
|
||||
if (attr.state & POINTOR)
|
||||
attr.precision = attr.precision * 10 + *ps - '0';
|
||||
else
|
||||
attr.fillbytes = attr.fillbytes * 10 + *ps - '0';
|
||||
}
|
||||
break;
|
||||
case '.':
|
||||
attr.state |= POINTOR;
|
||||
break;
|
||||
case '-':
|
||||
attr.state |= FILL_LEFT;
|
||||
break;
|
||||
default:
|
||||
attr.type = -2;
|
||||
break;
|
||||
}
|
||||
|
||||
attr.state |= START;
|
||||
|
||||
if (attr.type != -1)
|
||||
break;
|
||||
}
|
||||
|
||||
switch (attr.type) {
|
||||
case 'c':
|
||||
attr.value.val8 = (char)va_arg(va, int);
|
||||
ets_putc(attr.value.val8);
|
||||
break;
|
||||
case 's':
|
||||
attr.value.valcp = va_arg(va, const char *);
|
||||
ets_printf_str(&attr);
|
||||
break;
|
||||
case 'i':
|
||||
case 'd':
|
||||
attr.value.val32 = va_arg(va, int);
|
||||
if (attr.value.val32 < 0) {
|
||||
ets_putc('-');
|
||||
attr.value.val32 = -attr.value.val32;
|
||||
}
|
||||
ets_printf_int(&attr, 10);
|
||||
break;
|
||||
case 'u':
|
||||
attr.value.val32u = va_arg(va, unsigned int);
|
||||
ets_printf_int(&attr, 10);
|
||||
break;
|
||||
case 'x':
|
||||
attr.value.val32u = va_arg(va, unsigned int);
|
||||
ets_printf_int(&attr, 16);
|
||||
break;
|
||||
case 'p':
|
||||
attr.value.valcp = va_arg(va, const char *);
|
||||
ets_printf_int(&attr, 16);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
fmt = ps;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* defined(CONFIG_USING_NEW_ETS_VPRINTF) && !defined(BOOTLOADER_BUILD) */
|
||||
|
||||
int ets_vprintf(const char *fmt, va_list ap)
|
||||
{
|
||||
return ets_io_vprintf(ets_putc, fmt, ap);
|
||||
}
|
||||
|
||||
/* Re-write ets_printf in SDK side, since ets_printf in ROM will use a global
|
||||
#endif /* defined(CONFIG_USING_NEW_ETS_VPRINTF) && !defined(BOOTLOADER_BUILD) */
|
||||
|
||||
/**
|
||||
* Re-write ets_printf in SDK side, since ets_printf in ROM will use a global
|
||||
* variable which address is in heap region of SDK side. If use ets_printf in ROM,
|
||||
* this variable maybe re-write when heap alloc and modification.*/
|
||||
int IRAM_ATTR ets_printf(const char* fmt, ...)
|
||||
* this variable maybe re-write when heap alloc and modification.
|
||||
*
|
||||
* Using new "ets_vprintf" costs stack without alignment and accuracy:
|
||||
* just "fmt": 136 Bytes
|
||||
* "%s": 172 Bytes
|
||||
* "%p", "%d, "%i, "%u", "%x": 215 Bytes
|
||||
*/
|
||||
int ets_printf(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
Reference in New Issue
Block a user