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

Как загнать строки в irom.text

pvvx

Активный участник сообщества
SHERTS - какие надо давать директивы компилятору СИ и т.д, чтобы загнать строки и константы в section ".irom.text" (в кешируемую область flash)?
os_printf в SDK 0.9.5 переписали и он кладет строки в .irom.text.
Код:
#ifdef USE_OPTIMIZE_PRINTF
#define os_printf(fmt, ...) do {    \
    static const char flash_str[] ICACHE_RODATA_ATTR = fmt;    \
    os_printf_plus(flash_str, ##__VA_ARGS__);    \
    } while(0)
#else
#define os_printf    os_printf_plus
#endif
Но, при переносе туда других констант, почему-то возникает "протектед" при обращении к ним...
Я не проф.программер и не знаю что там надо приписать, чтобы загнать в область .irom.text к примеру const char *HTTPCacheControl = "Cache-Control: "; и это потом не вызывало "протектед" при обращении к строке любыми стандартными процедурами... :)
Возможно это связано со спецификой "кеширования" flash. (Типа os_printf сидит в iram, а от туда можно лезть в область "кеширования" flash, а из процедуры с атрибутом ICACHE_FLASH_ATTR нельзя?)
К С++ это тоже теперь относится, т.к. укладка переменных в область "кеширования" flash высвобождает heap и другую RAM память, и так малую. (Иначе у вас вырастет "data" и "rodata" отъев от "bss" и "heap".)
И в SDK 0.9.5 новые загрузчики flash и esp_init_data_default.bin c ещё неизвестными "котовасиями"... И в следующем SDK они опять будут новыми :) Т.е. распределение по по памяти сегментов и их загрузка с распределением не предсказуема.
 
Последнее редактирование:

CHERTS

Moderator
Команда форума
SHERTS - какие надо давать директивы компилятору СИ и т.д, чтобы загнать строки и константы в section ".irom.text" (в кешируемую область flash)?
Возможно так, но я тоже не спец по Си, это кусок из nodemcu-firmware

Код:
#include "c_types.h"
#define ICACHE_STORE_ATTR __attribute__((aligned(4)))
static volatile const uint8_t flash_init_data[128] ICACHE_STORE_ATTR ICACHE_RODATA_ATTR =
{
  0x05, 0x00, 0x04, 0x02, 0x05, 0x05, 0x05, 0x02, 0x05, 0x00, 0x04, 0x05, 0x05, 0x04, 0x05, 0x05,
  0x04, 0xFE, 0xFD, 0xFF, 0xF0, 0xF0, 0xF0, 0xE0, 0xE0, 0xE0, 0xE1, 0x0A, 0xFF, 0xFF, 0xF8, 0x00,
  0xF8, 0xF8, 0x52, 0x4E, 0x4A, 0x44, 0x40, 0x38, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05,
  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0xE1, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x93, 0x43, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
рабоатет с SDK 0.9.5, с SDK 0.9.4 и ниже нужно определить

Код:
#define ICACHE_RODATA_ATTR __attribute__((section(".irom.text")))
 
Последнее редактирование:

pvvx

Активный участник сообщества
Не помогает :( "exception (3)"
exception (3):
epc1=0x4000df2f, epc2=0x00000000, epc3=0x00000000, excvaddr=0x40268e94, depc=0x00000000
static const char HTTPsfupload[] ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = "<html><body style='margin:100px'><form method='post' action='/fsupload' enctype='multipart/form-data'><b>File Upload</b><p><input type='file' name='file' size=40> <input type='submit' value='Upload'></form></body></html>";
0x4000df2f - это в теле memcmp() ROM
0x40268e94 - это в области к`эша Flash:
Код:
40268e90 3e 00 00 00 3c 68 74 6d 6c 3e 3c 62 6f 64 79 20 >...<html><body
40268ea0 73 74 79 6c 65 3d 27 6d 61 72 67 69 6e 3a 31 30 style='margin:10
40268eb0 30 70 78 27 3e 3c 66 6f 72 6d 20 6d 65 74 68 6f 0px'><form metho
40268ec0 64 3d 27 70 6f 73 74 27 20 61 63 74 69 6f 6e 3d d='post' action=
40268ed0 27 2f 66 73 75 70 6c 6f 61 64 27 20 65 6e 63 74 '/fsupload' enct
40268ee0 79 70 65 3d 27 6d 75 6c 74 69 70 61 72 74 2f 66 ype='multipart/f
40268ef0 6f 72 6d 2d 64 61 74 61 27 3e 3c 62 3e 46 69 6c orm-data'><b>Fil
40268f00 65 20 55 70 6c 6f 61 64 3c 2f 62 3e 3c 70 3e 3c e Upload</b><p><
40268f10 69 6e 70 75 74 20 74 79 70 65 3d 27 66 69 6c 65 input type='file
40268f20 27 20 6e 61 6d 65 3d 27 66 69 6c 65 27 20 73 69 ' name='file' si
40268f30 7a 65 3d 34 30 3e 20 3c 69 6e 70 75 74 20 74 79 ze=40> <input ty
40268f40 70 65 3d 27 73 75 62 6d 69 74 27 20 76 61 6c 75 pe='submit' valu
40268f50 65 3d 27 55 70 6c 6f 61 64 27 3e 3c 2f 66 6f 72 e='Upload'></for
40268f60 6d 3e 3c 2f 62 6f 64 79 3e 3c 2f 68 74 6d 6c 3e m></body></html>
40268f70 00 00 00 00
Строка напрямую отдается LwIP-у на передачу.
Без ICACHE_STORE_ATTR ICACHE_RODATA_ATTR работает, но строка помещена в rodata: 0x3ffe8aa0 ~ 0x3ffe9bb8, len: 4376. И выходит на неё меньше heap.
И aligned не требуется - используется указатель на байты.

При:
const char *xxxx ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = "....";
Ругается на ошибку уже компилятор.
Непонятно в каком месте приписывать атрибуты. В разных СИ, особенно для MCU это всё по разному :(
 
Последнее редактирование:

CHERTS

Moderator
Команда форума
Не помогает :( "exception (3)"
При:
const char *xxxx ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = "....";
Ругается на ошибку уже компилятор.
у меня все нормально:

в user_main.c

Код:
#include <c_types.h>
#include "user_config.h"
const char *HTTPCacheControl ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = "HelloWorld";
в user_config_h

Код:
#ifndef __USER_CONFIG_H__
#define __USER_CONFIG_H__

#define ICACHE_STORE_ATTR __attribute__((aligned(4)))

#endif
 

pvvx

Активный участник сообщества
у меня все нормально:
в user_main.c
Но там используется адаптированная os_printf.
Пустое объявление строки никуда нигде не использующееся? :)
И такое странслирует, без обращения к строке:
static const char * hello __attribute__((aligned(4))) __attribute__((section("xaxa"))) = "\nHello World!\n";
 
Последнее редактирование:

pvvx

Активный участник сообщества
CHERTS - перетусовка указателя через (void *) с копированием в os_memcpy() строки из "кэшируемой" области flash в память спасает дело. Похоже что не всегда отрабатывает кеш, при обращениях к section(".irom.text") из кода в section(".irom0.text").
Что-то похожее уже наблюдал - нельзя обращаться к области кэш за раз с длиной более килобайта с чем-то. Типа os_memcpy(ram, cache_flash, 2048) - вызовет "протектед" (есть ещё зависимость от положения копируемого буфера в секторе flash).
По тому давно уже написал при чтении памяти памяти в WEB переход к ограничению размеров блоков, когда попадаем в зону кеширования flash, что снижает скорость передачи по TCP (мельче блоки - меньше скорость).
if((web_conn->udata_start >= 0x40000000)&&(web_conn->udata_start < 0x50000000)&&(len > 1024)) len = 1024;
 
Последнее редактирование:

Andrey

New member
#define ICACHE_STORE_ATTR __attribute__((aligned(4)))
Ничего не понял. Эта запись означает что код будет располагаться с адреса кратного 4. Это выравнивание по 32 битам. И никакого отношения к секциям и кешированию не имеет. Это они так поменяли макрос? Раньше этот макрос располагал код в .irom0.text
Я просто 0.9.5 не ставил ещё.
 

pvvx

Активный участник сообщества
Ничего не понял. Эта запись означает что код будет располагаться с адреса кратного 4. Это выравнивание по 32 битам. И никакого отношения к секциям и кешированию не имеет. Это они так поменяли макрос? Раньше этот макрос располагал код в .irom0.text
Я просто 0.9.5 не ставил ещё.
Это так написано у любителей Lua, а define на .irom0.text другой. Без aligned(4) больше проблем, если читать из flash стандартной процедурой spi_flash_read() - будет "exception".
 

avn

New member
Неглубоко копаете :)

Во-первых, ICACHE_RODATA_ATTR определяется в файле c_types.h только в случае, если при компиляции задан ключ -DICACHE_FLASH
Во-вторых, если вы определяете указатель char *, а не массив char [], то в секцию rodata попадет только сам указатель - 32-битное целое число, а строка останется в секции data и будет загружена в оперативную память, которой очень мало.
В-третьих, функция os_printf_plus только первый аргумент может читать из rodata, а остальные из data, поэтому написать что-то типа console_printf( "XXX: %s\n", xxx ) не получится. Нужно писать аж три оператора:

C:
console_printf( "XXX: " ); os_printf_plus( xxx ); console_printf( "\n" );

Поэтому, описывать строки, которые вы хотите поместить в rodata нужно по образцу:
C:
const char xxx[] ICACHE_RODATA_ATTR STORE_ATTR = "xxx";

И проверьте, правильно ли у вас определена console_printf (в некоторых заголовочных файлах я встречал ошибки):

C:
#define USE_OPTIMIZE_PRINTF // можно вынести в ключ компиляции -DUSE_OPTIMIZE_PRINTF
#ifdef USE_OPTIMIZE_PRINTF
#ifdef console_printf
#undef console_printf
#endif
int os_printf_plus(const char *format, ...)  __attribute__ ((format (printf, 1, 2)));
#define console_printf(fmt, ...) do {   \
   static const char flash_str[] ICACHE_RODATA_ATTR STORE_ATTR = fmt; \
   os_printf_plus(flash_str, ##__VA_ARGS__); \
   } while(0)
#endif

А вот проблема, которую мне так и не удалось решить - это как запихнуть в rodata массив указателей и сами строки char *xxx[] . Указатели-то попадают куда надо, а вот строки остаются в оперативной памяти.

Т.е. писать приходится как-то так:

C:
const char FlashSizeMap[][32] ICACHE_RODATA_ATTR STORE_ATTR =
{
        "512 KB (256 KB + 256 KB)",   // 0x00
       "256 KB",           // 0x01
       "1024 KB (512 KB + 512 KB)",    // 0x02
       "2048 KB (512 KB + 512 KB)",   // 0x03
       "4096 KB (512 KB + 512 KB)",   // 0x04
       "2048 KB (1024 KB + 1024 KB)",   // 0x05
       "4096 KB (1024 KB + 1024 KB)"   // 0x06
};

Для вышепреведенного примера это небольшая проблема, но если строки существенно отличаются по длине, то память расходуется неэффективно.
 

pvvx

Активный участник сообщества
Неглубоко копаете :)
Всё уже перекопано и вывернуто через .. . :)

функция os_printf_plus только первый аргумент может читать из rodata, а остальные из data, поэтому написать что-то типа console_printf( "XXX: %s\n", xxx ) не получится. Нужно писать аж три оператора:
[inline]console_printf( "XXX: " ); os_printf_plus( xxx ); console_printf( "\n" );[/inline]
:) Это кому как -> esp8266web/os_printf.c at master · pvvx/esp8266web · GitHub

А вот проблема, которую мне так и не удалось решить - это как запихнуть в rodata массив указателей и сами строки char *xxx[] .
Ручками. Описываете каждую строчку отдельно, а указатели на них в другой массив... Примерно так esp8266web/web_srv.c at master · pvvx/esp8266web · GitHub
Или создаете отдельный файл и в obj производите замену секций...
PS: что вы ожидаете от недоделанного компилятора на экзотический процессор? :)
 
Последнее редактирование:

avn

New member
Всё уже перекопано и вывернуто через .. . :)
Уверен, но здесь это не получило отражения.

:) Это кому как -> esp8266web/os_printf.c at master · pvvx/esp8266web · GitHub

Это альтернативная реализация, я написал про стандартный SDK

Ручками. Описываете каждую строчку отдельно, а указатели на них в другой массив... Примерно так esp8266web/web_srv.c at master · pvvx/esp8266web · GitHub
Или создаете отдельный файл и в obj производите замену секций...

Понятно, что извратиться можно всегда, непонятно, почему штатно код генерится неверно.

PS: что вы ожидаете от недоделанного компилятора на экзотический процессор? :)
Ничего не ожидаю, просто описываю глюки.
 
Сверху Снизу