• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Существует ли с++ среда для esp8266?

Alex_S

New member
Продолжаем игры. Появились очередные вопросы )
1. При использовании стандартного вектора таки в некоторых случаях не хватает реализации `_sbrk_r':
Код:
c:/espressif/xtensa-lx106-elf/bin/../lib/gcc/xtensa-lx106-elf/4.8.2/../../../../xtensa-lx106-elf/lib\libc.a(lib_a-mallocr.o):(.literal+0x24): undefined reference to `_sbrk_r'
c:/espressif/xtensa-lx106-elf/bin/../lib/gcc/xtensa-lx106-elf/4.8.2/../../../../xtensa-lx106-elf/lib\libc.a(lib_a-mallocr.o): In function `malloc_extend_top':
d:\Neo\Project\ESP8266\DevKit\build\compiler\dl\esp-newlib\build\xtensa-lx106-elf\newlib\libc\stdlib/../../../../../newlib/libc/stdlib/mallocr.c:2165: undefined reference to `_sbrk_r'
d:\Neo\Project\ESP8266\DevKit\build\compiler\dl\esp-newlib\build\xtensa-lx106-elf\newlib\libc\stdlib/../../../../../newlib/libc/stdlib/mallocr.c:2202: undefined reference to `_sbrk_r'
c:/espressif/xtensa-lx106-elf/bin/../lib/gcc/xtensa-lx106-elf/4.8.2/../../../../xtensa-lx106-elf/lib\libc.a(lib_a-freer.o): In function `_malloc_trim_r':
d:\Neo\Project\ESP8266\DevKit\build\compiler\dl\esp-newlib\build\xtensa-lx106-elf\newlib\libc\stdlib/../../../../../newlib/libc/stdlib/mallocr.c:3325: undefined reference to `_sbrk_r'
d:\Neo\Project\ESP8266\DevKit\build\compiler\dl\esp-newlib\build\xtensa-lx106-elf\newlib\libc\stdlib/../../../../../newlib/libc/stdlib/mallocr.c:3332: undefined reference to `_sbrk_r'
c:/espressif/xtensa-lx106-elf/bin/../lib/gcc/xtensa-lx106-elf/4.8.2/../../../../xtensa-lx106-elf/lib\libc.a(lib_a-freer.o):d:\Neo\Project\ESP8266\DevKit\build\compiler\dl\esp-newlib\build\xtensa-lx106-elf\newlib\libc\stdlib/../../../../../newlib/libc/stdlib/mallocr.c:3340: more undefined references to `_sbrk_r' follow
Можно ли как-то его реализовать или убрать?

2. Линкер кидает все наши функции в секцию iram1_0_seg, которой всего 32кб. Чтобы положить их в rom, есть аттрибут ICACHE_FLASH_ATTR. Туда же кладутся и все строковые константы.
А есть ли способ класть их в rom по-умолчанию, и использовать их оттуда?
 

jcmvbkbc

New member
Продолжаем игры. Появились очередные вопросы )
1. При использовании стандартного вектора таки в некоторых случаях не хватает реализации `_sbrk_r':
Можно ли как-то его реализовать или убрать?
По идее надо заменить реализацию malloc в newlib на вызов os_malloc, а free -- на os_free. Я завтра наверно сделаю.

2. Линкер кидает все наши функции в секцию iram1_0_seg, которой всего 32кб. Чтобы положить их в rom, есть аттрибут ICACHE_FLASH_ATTR. Туда же кладутся и все строковые константы.
А есть ли способ класть их в rom по-умолчанию, и использовать их оттуда?
Я вот такой способ предложил в своё время: http://www.esp8266.com/viewtopic.php?f=9&t=224&start=80#p1385
Есть минимум одно "но" с кодом во FLASH: туда нельзя класть код, который может быть вызван из прерывания.
 

Alex_S

New member
С _sbrk_r разобрался - моя вина была. В одном месте вместо os_free использовал просто free.
Надо быть внимательным.
 

anakod

Moderator
Команда форума
Я вот такой способ предложил в своё время: http://www.esp8266.com/viewtopic.php?f=9&t=224&start=80#p1385
Есть минимум одно "но" с кодом во FLASH: туда нельзя класть код, который может быть вызван из прерывания.
Огромное спасибо, это как раз то чего мне не хватало. А почему нельзя класть код вызываемый из прерывания? У меня вроде работало (или это просто не гарантируется)?
Второй вопрос можно ли объявить обратную константу явно кладущую код в ROM? Чтобы полностью исключить всю библиотеку из основной памяти, но некоторые функции оставить там.
 

jcmvbkbc

New member
Огромное спасибо, это как раз то чего мне не хватало. А почему нельзя класть код вызываемый из прерывания? У меня вроде работало (или это просто не гарантируется)?
Надо уточнить: если программа пишет во FLASH. Потому что при записи мэппинг FLASH в адресное пространство CPU отключается а после включается снова. Если в этот период прийдёт прерывание всё сломается.
Второй вопрос можно ли объявить обратную константу явно кладущую код в ROM? Чтобы полностью исключить всю библиотеку из основной памяти, но некоторые функции оставить там.
В смысле, в IRAM? Ну да, идея в том, чтобы поместить код для IRAM и FLASH в разные секции, а в скрипте линковщика положить разные входные секции в разные выходные регионы.
 

anakod

Moderator
Команда форума
1. В таком случае, получается можно просто запретить обработку прерываний на время записи данных во флеш?

2. А Вы могли бы подсказать как сделать так, чтобы основной код лег во флеш (тут я думаю достаточно будет примера по ссылке), но определённые функции (требовательные к производительности/вызываемые в прерываниях и т.д.) клались в IRAM? Т.е примерно как встроенный макрос cache flash, но наоборот.
 

jcmvbkbc

New member
1. В таком случае, получается можно просто запретить обработку прерываний на время записи данных во флеш?
Вариант, конечно, но не уверен, что это просто, и вообще хорошо.
2. А Вы могли бы подсказать как сделать так, чтобы основной код лег во флеш (тут я думаю достаточно будет примера по ссылке), но определённые функции (требовательные к производительности/вызываемые в прерываниях и т.д.) клались в IRAM? Т.е примерно как встроенный макрос cache flash, но наоборот.
Например так можно сделать:
Код:
--- eagle.app.v6.ld.orig  2014-12-19 18:07:44.000000000 +0300
+++ eagle.app.v6.ld  2015-02-02 06:13:22.726822114 +0300
@@ -96,11 +96,14 @@
  *(.gnu.linkonce.e.*)
  *(.gnu.version_r)
  *(.eh_frame)
+  . = (. + 3) & ~ 3;
  /*  C++ constructor and destructor tables, properly ordered:  */
+  __init_array_start = ABSOLUTE(.);
  KEEP (*crtbegin.o(.ctors))
  KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
  KEEP (*(SORT(.ctors.*)))
  KEEP (*(.ctors))
+  __init_array_end = ABSOLUTE(.);
  KEEP (*crtbegin.o(.dtors))
  KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
  KEEP (*(SORT(.dtors.*)))
@@ -145,6 +148,14 @@
  } >dram0_0_seg :dram0_0_bss_phdr
/* __stack = 0x3ffc8000; */
+  .irom0.text : ALIGN(4)
+  {
+  _irom0_text_start = ABSOLUTE(.);
+  *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text)
+  build/app_app.a:*_flash.o(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
+  _irom0_text_end = ABSOLUTE(.);
+  } >irom0_0_seg :irom0_0_phdr
+
  .text : ALIGN(4)
  {
  _stext = .;
@@ -153,6 +164,7 @@
  *(.init.literal)
  *(.init)
  *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
+  build/app_app.a:*_flash.o(.iram.literal .iram.text.literal .iram.text)
  *(.fini.literal)
  *(.fini)
  *(.gnu.version)
@@ -169,12 +181,6 @@
  _lit4_end = ABSOLUTE(.);
  } >iram1_0_seg :iram1_0_phdr
-  .irom0.text : ALIGN(4)
-  {
-  _irom0_text_start = ABSOLUTE(.);
-  *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text)
-  _irom0_text_end = ABSOLUTE(.);
-  } >irom0_0_seg :irom0_0_phdr
}
/* get ROM code address */
Файлы, содержимое которых должно идти по умолчанию во FLASH называть *_flash.* а функции которые должны пойти в IRAM помечать следующим атрибутом:
#define IRAM_ATTR __attribute__((section(".iram.text")))

P.S. что-то у меня не работает EXCLUDE_FILE, и я теперь даже не уверен, что он работал с самого начала.
 

Alex_S

New member
Чем дальше в лес - тем толще партизаны )))
Продолжил игры с stl, попробовал добавить в проект использование типа string. Вроде бы должно быть не особо накладно, и вроде бы реализовано все в виде шаблона.
Но и тут ждут грабли. Шаблон string не работает без либы libstdc++. Подключение этой либы сразу же превосходит все возможности по памяти )))

Вроде бы - реализуй зависимости у себя, и будет счастье. Но гугление принесло мало результатов. Как правило все упираются в то, что неправильно подключена либа stdc++, и как это исправить.
До того stl на малых системах не применял (не было необходимости), а тут хочется поиграться и подучиться ). Да и по идее не должно быть особенно накладно на простых типах..
В общем - ошибки такие выдает линковщик:
Код:
LD build/app.out
G:\Proj\ESP8266\WebSensor/user/HTTPClient.cpp:520: undefined reference to `std::string::_Rep::_S_empty_rep_storage'
G:\Proj\ESP8266\WebSensor/user/HTTPClient.cpp:521: undefined reference to `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, unsigned int, std::allocator<char> const&)'
G:\Proj\ESP8266\WebSensor/user/HTTPClient.cpp:521: undefined reference to `std::string::assign(std::string const&)'
G:\Proj\ESP8266\WebSensor/user/HTTPClient.cpp:521: undefined reference to `std::string::_Rep::_M_destroy(std::allocator<char> const&)'
G:\Proj\ESP8266\WebSensor/user/HTTPClient.cpp:527: undefined reference to `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&)'
c:\espressif\xtensa-lx106-elf\xtensa-lx106-elf\include\c++\4.8.2\bits/basic_string.h:539: undefined reference to `std::string::_Rep::_M_destroy(std::allocator<char> const&)'
(.text._ZNSt6vectorI7tHeaderSaIS0_EE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPS0_S2_EERKS0_[_ZNSt6vectorI7tHeaderSaIS0_EE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPS0_S2_EERKS0_]+0x8): undefined reference to `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&)'
build/app_app.a(HTTPClient.o): In function `std::string::_Rep::_M_dispose(std::allocator<char> const&)':
c:\espressif\xtensa-lx106-elf\xtensa-lx106-elf\include\c++\4.8.2\bits/basic_string.h:240: undefined reference to `std::string::_Rep::_M_destroy(std::allocator<char> const&)'
Из того, что я понял: std::string::_Rep::_S_empty_rep_storage - это место в памяти, на которое ссылается пустая строка, чтобы не выделять для пустой строки память под каждый объект. Но в каком виде ее задать?
До остальных зависимостей я пока не дошел ))

И самый интересный вопрос - можно ли как-то сказать линкеру, чтобы он при включении какой-то либы не тянул ее всю, а выдергивал только нужные функции оттуда?
 

jcmvbkbc

New member
Чем дальше в лес - тем толще партизаны )))
Продолжил игры с stl, попробовал добавить в проект использование типа string. Вроде бы должно быть не особо накладно, и вроде бы реализовано все в виде шаблона.
Но и тут ждут грабли. Шаблон string не работает без либы libstdc++. Подключение этой либы сразу же превосходит все возможности по памяти )))

Вроде бы - реализуй зависимости у себя, и будет счастье.
Думаю, что тут счастья не найти.
Из того, что я понял: std::string::_Rep::_S_empty_rep_storage - это место в памяти, на которое ссылается пустая строка, чтобы не выделять для пустой строки память под каждый объект. Но в каком виде ее задать?
Проще всего было бы посмотреть в исходниках stl:
Код:
  template<typename _CharT, typename _Traits, typename _Alloc>
  typename basic_string<_CharT, _Traits, _Alloc>::size_type
  basic_string<_CharT, _Traits, _Alloc>::_Rep::_S_empty_rep_storage[
  (sizeof(_Rep_base) + sizeof(_CharT) + sizeof(size_type) - 1) /
  sizeof(size_type)];
И самый интересный вопрос - можно ли как-то сказать линкеру, чтобы он при включении какой-то либы не тянул ее всю, а выдергивал только нужные функции оттуда?
Обычно для этого компилируют с флагом -ffunction-sections и -fdata-sections, компилятор при этом заводит для каждой функции отдельную секцию. libstdc++ так и собрана. Потом линкуют с опцией --gc-sections и линкер выкидывает все секции (== функции и переменные) которые не были использованы явно или по зависимостям.
 

Alex_S

New member
Обычно для этого компилируют с флагом -ffunction-sections и -fdata-sections, компилятор при этом заводит для каждой функции отдельную секцию. libstdc++ так и собрана. Потом линкуют с опцией --gc-sections и линкер выкидывает все секции (== функции и переменные) которые не были использованы явно или по зависимостям.
Пробовал, но он все равно запихнул дофига всего (map в аттаче).
Флаги компиляции:
Код:
# libraries used in this project, mainly provided by the SDK
LIBS     = c gcc hal phy pp net80211 lwip wpa main stdc++

# compiler flags using during compilation of source files
CFLAGS     = -Os -g -O2 -Wpointer-arith -Wundef -Werror -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals  -D__ets__ -DICACHE_FLASH -ffunction-sections -fdata-sections
CXXFLAGS   = $(CFLAGS) -fno-rtti -fno-exceptions

# linker flags used to generate the main object file
LDFLAGS     = -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static -Wl,--gc-sections -Wl,-Map d:\map.txt
как видим - там есть и исключения, и маллок, и еще куча прочего..
Есть ли способ как-то уменьшить итоговый размер, выкинув лишнее?
 

Вложения

  • 47.7 KB Просмотры: 1

jcmvbkbc

New member
Пробовал, но он все равно запихнул дофига всего (map в аттаче).
как видим - там есть и исключения, и маллок, и еще куча прочего..
Есть ли способ как-то уменьшить итоговый размер, выкинув лишнее?
Если исключения пролезли -- пиши пропало :)
Мануал libstdc++ предлагает конфигурировать её с опцией --enable-cxx-flags=-fno-exceptions и другими интересными вариантами.
 

Alex_S

New member
А сконфигурировать либу под силу обычному человеку? Под виндой это можно сделать?
 

anakod

Moderator
Команда форума
Но и тут ждут грабли. Шаблон string не работает без либы libstdc++. Подключение этой либы сразу же превосходит все возможности по памяти )))
Я почти уверен что все вполне можно уместить, если грамотно все раскидать по разделам памяти. Но с этими разделами памяти просто какой-то ад. Вчера я честно достаточно упорно курил ман https://access.redhat.com/documenta..._GNU_Linker/sections.html#OUTPUT-SECTION-FILL но мало того что оно не делает того что нужно, там даже некоторые стандартные примеры собираться не хотят :( Может быть кто-нибудь посоветует что лучше почитать по этой теме?

Предложенный EXCLUDE_FILE тоже не заработал, я попробовал довольно много разных вариантов. Сегодня как только доберусь до железки попробую новый вариант с *_flash.* может быть он поможет.
Еще вчера я проводил любопытный тест - унес весь основной код в секцию FLAH. Компилируется нормально, запускается, размер получился просто восхитительный (примерно 9Кб из 32) но при запуске в UART сыпется какой-то треш :) Пробовал по-библиотечно переносить руками загрузочные модули обратно в IRAM но, к сожалению, тоже не помогло..

А есть ли возможность исключать не по файлам а по библиотекам целиком? Как-то в секциях описать какая либа должна упасть в ROM по умолчанию, чтобы не завязываться на множество отдельных классов/файлов. Это вдвойне актуально для сторонних библиотек.
 

jcmvbkbc

New member
А сконфигурировать либу под силу обычному человеку? Под виндой это можно сделать?
Проще всего это сделать при сборке компилятора, но по идее можно и просто отдельно собрать эту либу. Типичным процессом кросс-компиляции: configure - make - make install. configure надо дать опцию --host=xtensa-lx106-elf, а в качестве кросс-компилятора указать xtensa-lx106-elf-g++. configure конечно захочет шелл и другие плюшки...
 
Сверху Снизу