Перейти к содержанию
    

FreeRTOS, LPC2138 и менеджер памяти

Возникают проблемы с запуском ресурсоемких задач под FreeRTOS.

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

что происходит, когда память (SRAM) используется в больших количествах.

И сколько надо оставить глобального стека ( помимо стеков задач), чтобы планировщик чувствовал себя нормально.

Результаты разочаровывают пока.

 

 

Это прочитал http://www.freertos.org/FAQHelp.html

 

Это мой тестовый пример http://www.bipom.com/support/RtosDemo1.zip

Компилятор GCC.

Там есть две простые задачи вывода в последовательный порт

 

pt = (ULONG)malloc(1);

int2str(buf,pt, HEX);uart0Puts("\n\rfirst loc = ");uart0Puts(buf);

 

 

xReturn = xTaskCreate( vMessage_0, ( const signed portCHAR * const )"Message_0", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );

int2str(buf,xReturn, HEX);uart0Puts("\n\rMes0=");uart0Puts(buf);

 

xReturn = xTaskCreate( vMessage_1, ( const signed portCHAR * const )"Message_1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );

int2str(buf,xReturn, HEX);uart0Puts("\n\rMes1=");uart0Puts(buf);

 

pt = (ULONG)malloc(1);

int2str(buf,pt, HEX);uart0Puts("\n\rlast loc = ");uart0Puts(buf);

 

Примечание. int2str & uart0Puts использую вместо printf ("%8X", ,,,)

Поскольку стандартный форматтер "жрет" ресурсы памяти очень сильно.

 

Если декларирую большой массив памяти ( чтобы получить приграничное значение для используемой SRAM)

unsigned char myArray[1024*23+792],

то даже задачи не запускаются. Хотя создаются нормально с кодом завершения 1.

 

first loc = 0x40006980

Mes0=0x1

Mes1=0x1

last loc = 0x40006E40

 

7FFF - 6E40 = 11BFh = 4543

 

 

Вот теперь вопрос .

Почему имея 4543 байт к верхушке памяти это не работает ?

LPC2138 имеет 32K.

 

Если меняю к char myArray[1024*23+512]; ( разница в 280 байт),

то все работает.

 

 

first loc = 0x40006868

Mes0=0x1

Mes1=0x1

last loc = 0x40006D28

Message_0

Message_1

Message_0

 

7FFF - 6D28 = 12D7h = 4823

 

 

У меня 4.6.0 версия FreeRTOS.

Я кстати пробовал различные модели менеджера памяти.

http://www.freertos.org/a00111.html

В текущей версии heap_3.c

Пробовал heap_1 и heap_2. Там еще более напряженно с памятью

 

Это мои исследования FreeRTOS. Я не могу объяснить это.

Поэтому и не закладываю серьезные проекты на FreeRTOS пока.

 

Есть идеи как объяснить это ?

RtosDemo1.zip

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Есть идеи как объяснить это?

 

Загрузить в симулятор, расставить везде брикпоинтов, ассертов, отладочной печати и прошагать. heap_1 вообще память не освобождает, зато выделять должен с минимальными лишними расходами.

Изменено пользователем meister

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Мне кажется, что здесь проблема даже не в менеджере памяти.

Память уже выделена тем или иным образом. Почему 4.8K необходимо планировщику ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Есть идеи как объяснить это ?

По выданной информации - никак. Для начала, просто имейте ввиду, что Heap "сишный" и Неаp из которого берет память FreeRTOS это разные хипы и менеджеры. Для начала, по крайней мере я так сделал сразу, отдал под нужды FreeRTOS всю оставшуюся память. Дополнительно мой менеджер памяти хранит владельца выделенного блока, посему всегда можно посмотреть кто и на что память скушал. Из средств небольшой дополнительной экономии в самой системе объединены в один блок TCB и Stack задачи, и подчищен сам TCB. Подчитску TCB Автор FreeRTOS тихонечко (спустя пару лет :) )в последние версии внес, а объединение блоков памяти дважды предложенное проигнорировал...

Вот картинка распределения памяти в текущей поделке:

ARMSL RTKernel(ARM) V0.42.1(472) Feb 27 2008 13:17:31 ......
.....
Это при Heap при старте:
    Check CPU -LPC2138 
    RAM use:8704 Heap:40002200 Size:24064
......
Список процессов:
ps
R 2 Console       TCB=40002210:304/800
R 0 IDLE       TCB=40002578:272/320
B 3 LAP       TCB=400032E0:152/1200
B 4 SPItx       TCB=40002F78:144/800
B 1 Checker       TCB=400037D8:88/400
S 2 HDLCtx       TCB=40002860:144/400
......
Использование Heap:
memm
MCB00->40002210 Size=   856 TCB+Stack=800
MCB01->40002578 Size=   376 TCB+Stack=320
MCB02->40002700 Size=   336 QCB <-System
MCB03->40002860 Size=   456 TCB+Stack=400
MCB04->40002A38 Size=   848 QCB <-System
MCB05->40002D98 Size=   464 QCB <-System
MCB06->40002F78 Size=   856 TCB+Stack=800
MCB07->400032E0 Size=  1256 TCB+Stack=1200
MCB08->400037D8 Size=   456 TCB+Stack=400
MCB09->400039B0 Size= 17969 Free

Размеры стеков пока не поджимались, задач пока мало, все в процессе написания, но размеры выделленой и используемой памяти видны отлично.

 

то даже задачи не запускаются. Хотя создаются нормально с кодом завершения 1.

А с этим не просто, а очень просто :) У Вас Для самой ГЛАВНОЙ задачи IDLE памяти не хватило, вот создающей ее шедулер молча не запустился. Эту задачу надо создавать ПЕРВОЙ, я так и делаю в своей ветке FreeRTOS, кстати, это тоже одно из предложений не получившей никакой реакции от Автора FreeRTOS

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

По выданной информации - никак. Для начала, просто имейте ввиду, что Heap "сишный" и Неаp из которого берет память FreeRTOS это разные хипы и менеджеры.

Да, я думаю, что понимаю это. Например, sprintf (вызывая библиотечный malloc) возьмет из Heap "сишного", поскольку эта функция даже и не знает о существовании FreeRTOS. Это на мой взгляд очень слабое место FreeRTOS.

По сути ни о каком менеджменте памяти не может быть и речи. Просто FreeRTOS может позаботиться только, чтобы каждая задача вызывала функции, передавала параметры функций, и создавала локальные переменные в в своем (задачи) стеке.

Я правильно понимаю ?

 

 

 

Для начала, по крайней мере я так сделал сразу, отдал под нужды FreeRTOS всю оставшуюся память. Дополнительно мой менеджер памяти хранит владельца выделенного блока, посему всегда можно посмотреть кто и на что память скушал.

 

А если тот-же sprintf (или любая библиотечная функция ) вызовет malloc.

А памяти для кучи уже нету. Как это решается ?

 

А с этим не просто, а очень просто :) У Вас Для самой ГЛАВНОЙ задачи IDLE памяти не хватило, вот создающей ее шедулер молча не запустился. Эту задачу надо создавать ПЕРВОЙ, я так и делаю в своей ветке FreeRTOS, кстати, это тоже одно из предложений не получившей никакой реакции от Автора FreeRTOS

Пожалуйста с этого места поподробнее.

1. Как создать эту задачу ?

2. Этой задаче нужно 4.8K чтобы она была создана ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да, я думаю, что понимаю это. Например, sprintf (вызывая библиотечный malloc) возьмет из Heap "сишного", поскольку эта функция даже и не знает о существовании FreeRTOS. Это на мой взгляд очень слабое место FreeRTOS.

Ну так уберите вообще сишный Heap и не пользуйте такие функции, при попытке использования получите предупреждение от линкера. Я так и делаю - сишного Heap у меня нет, ну или максимум 16 байт для некоторых функций.

По сути ни о каком менеджменте памяти не может быть и речи.

Почему это? Весь контекст задач, очередей, создается в динамически выделяемой памяти и может быть освобожден. Это главное. Другое дело, что прилагаемые "менеджеры" исключительно для галочки, но это уже второй, автономно решаемый вопрос.

Пожалуйста с этого места поподробнее.

1. Как создать эту задачу ?

Смотрите, как она в оригинальном FreeRTOS создается - уберите ее отттуда и перенесите в main(). Для подстраховки можете организовать проверку ее наличия при старте шедулера и попытаться создать, если не существует.

2. Этой задаче нужно 4.8K чтобы она была создана ?

Разумеется нет - смотрите, сколько IDLE реально занимает на моей "картинке" и это при том, что у меня IDLE отнюдь не пустая задача. Для пустой задачи там прорядка 64-70 байт потребуется.

Естественно, память требуется не только для это задачи, вот например на что у меня еще память расходуется:

-D_CSTACK_SIZE=8         // Dummy System/User Stack Size (Not Used!)
-D_SVC_STACK_SIZE=200     // Supervisor Mode (Main Work Mode)
-D_IRQ_STACK_SIZE=200
-D_FIQ_STACK_SIZE=80            
-D_XXX_STACK_SIZE=20    // 32bytes Shared Stack for Abort/Undefined Instruction    and IAP Buffer    
-D_HEAP_RTOS_SIZE=1000  // 4Kb - Dummy minimal space for RTOS Memory Manager

-Z(DATA)SVC_STACK+_SVC_STACK_SIZE=RAMSTART-RAMEND      // System/User
-Z(DATA)CSTACK+_CSTACK_SIZE=RAMSTART-RAMEND            // Supervisor
-Z(DATA)FIQ_STACK+_FIQ_STACK_SIZE=RAMSTART-RAMEND     // FIQ
-Z(DATA)IRQ_STACK+_IRQ_STACK_SIZE=RAMSTART-RAMEND    // IRQ
-Z(DATA)HEAP_RTOS+_HEAP_RTOS_SIZE=RAMSTART-RAMEND     // Minimal size for RTOS memory manager
// All this space from start HEAP_RTOS to start XXX_STACK for RTOS Memory manager
-Z(DATA)XXX_STACK+_XXX_STACK_SIZE#RAMSTART-RAMEND    // Shared - Abort/Undefined and IAP buffer

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Смотрите, как она в оригинальном FreeRTOS создается - уберите ее отттуда и перенесите в main(). Для подстраховки можете организовать проверку ее наличия при старте шедулера и попытаться создать, если не существует.

 

Сделал. Разбил оригинальный void vTaskStartScheduler( void ) на две части:

CreateIdle и vTaskStartScheduler1

 

portBASE_TYPE CreateIdle(void)
{
    /* Add the idle task at the lowest priority. */
    return xTaskCreate( prvIdleTask, ( signed portCHAR * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, tskIDLE_PRIORITY, ( xTaskHandle * ) NULL );
}
void vTaskStartScheduler1( void )
{
portBASE_TYPE xReturn;

    /* Add the idle task at the lowest priority. */
    xReturn =  pdPASS;

    if( xReturn == pdPASS )
    {
...

 

Теперь видно, что для последней задачи не хватает места.

 

first loc = 0x40006980

Idle=0x1

Mes0=0x1

Mes1=0xFFFFFFFF

last loc = 0x40006E40

 

Похоже, что мы приближаемся к решению проблемы.

 

Разумеется нет - смотрите, сколько IDLE реально занимает на моей "картинке" и это при том, что у меня IDLE отнюдь не пустая задача. Для пустой задачи там прорядка 64-70 байт потребуется.

 

 

Так почему при имеющемся свободном ОЗУ ( = 4.5K) возникает проблема с созданием последней задачи ?

 

Это строка компилятора

 

{TOOLKITDIR}\bin\arm-elf-gcc.exe -mcpu=arm7tdmi -I{ROOTDIR}\GCC\Common -I{ROOTDIR}\GCC\LPC2000\Include\ -c -O3 -DGCC_ARM7_LIB -msoft-float -shared -Wformat=2 -g {SOURCEFILE} -o {OBJFILE}

 

Это строка линкера

 

"{TOOLKITDIR}\bin\arm-elf-ld.exe" -v -T "{ROOTDIR}\GCC\LPC2000\cstartup\lpc2138.ld" -nostartfiles -nostdlib -o {TMPFILE} "{ROOTDIR}\GCC\LPC2000\cstartup\bootos.o" {OBJFILES} -lfrtos -ldrv -lcommon -lc -lgcc -Map map.txt

 

map.txt (zip) подсоединил.

 

 

 

 

 

 

Так почему при имеющемся свободном ОЗУ ( = 4.5K) возникает проблема с созданием последней задачи ?

 

Это проблема больше GCC и линкера. Понятно что malloc не выделяет памяти. Поэтому и задача не создается.

Не могу понять, где определен размер heap для линкера. Почему он не видит этого куска памяти в конце. Похоже, что просто тупо зарезервировал этот кусок для стека.

 

Это скрипт линкера.

 

 
MEMORY 
{
    flash    : ORIGIN = 0, LENGTH = 512K
    ram    : ORIGIN = 0x40000000, LENGTH = 32K
}

__stack_end__ = 0x40000000 + 32K - 4;

SECTIONS 
{
    . = 0;
    startup : { *(.startup)} >flash

    prog : 
    {
        *(.text)
        *(.rodata)
        *(.rodata*)
        *(.glue_7)
        *(.glue_7t)
        *(.gcc_except_table)
    } >flash
    
  . = ALIGN(4);
  
    /* .ctors .dtors are used for c++ constructors/destructors */
    .ctors :
    {
        PROVIDE(__ctors_start__ = .);
        KEEP(*(SORT(.ctors.*)))
        KEEP(*(.ctors))
        PROVIDE(__ctors_end__ = .);
    } >flash
    
    .dtors :
    {
        PROVIDE(__dtors_start__ = .); 
        KEEP(*(SORT(.dtors.*)))
        KEEP(*(.dtors))
        PROVIDE(__dtors_end__ = .);
    } >flash
  
    . = ALIGN(4);

    __end_of_text__ = .;

    .data : 
    {
        __data_beg__ = .;
        __data_beg_src__ = __end_of_text__;
        *(.data)
        __data_end__ = .;
    } >ram AT>flash

    .bss : 
    {
        __bss_beg__ = .;
        *(.bss)
    } >ram

    /* Align here to ensure that the .bss section occupies space up to
    _end.  Align after .bss to ensure correct alignment even if the
    .bss section disappears because there are no input sections.  */
    . = ALIGN(32 / 8);
}
    . = ALIGN(32 / 8);
    _end = .;
    _bss_end__ = .; __bss_end__ = .; __end__ = .;
    PROVIDE (end = .);

 

Heap должен быть в bss. Какой кусок отрезается в конце под стек ?

Можно использовать --heap ( или другую директиву) , чтобы нарезать меньше памяти под стек в конце?

Получается, что эта память просто выпадает при работе в FreeRTOS.

map.zip

Изменено пользователем MiniMax

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Какой кусок отрезается в конце под стек ?

Ну для начала стеков у ARM много. Возможностей их описания может быть несколько, часто их размеры просто в лоб задают в startup - там где собственно и инициализируют. Размещение стеков тоже произвольное - не "в конце".

Можно использовать --heap...

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...