Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: FreeRTOS, LPC2138 и менеджер памяти
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > FreeRTOS
MiniMax
Возникают проблемы с запуском ресурсоемких задач под 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 пока.

Есть идеи как объяснить это ?
meister
Цитата(MiniMax @ Feb 27 2008, 12:29) *
Есть идеи как объяснить это?


Загрузить в симулятор, расставить везде брикпоинтов, ассертов, отладочной печати и прошагать. heap_1 вообще память не освобождает, зато выделять должен с минимальными лишними расходами.
MiniMax
Мне кажется, что здесь проблема даже не в менеджере памяти.
Память уже выделена тем или иным образом. Почему 4.8K необходимо планировщику ?
zltigo
Цитата(MiniMax @ Feb 27 2008, 12:29) *
Есть идеи как объяснить это ?

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

А с этим не просто, а очень просто smile.gif У Вас Для самой ГЛАВНОЙ задачи IDLE памяти не хватило, вот создающей ее шедулер молча не запустился. Эту задачу надо создавать ПЕРВОЙ, я так и делаю в своей ветке FreeRTOS, кстати, это тоже одно из предложений не получившей никакой реакции от Автора FreeRTOS
MiniMax
Цитата
По выданной информации - никак. Для начала, просто имейте ввиду, что Heap "сишный" и Неаp из которого берет память FreeRTOS это разные хипы и менеджеры.

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



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


А если тот-же sprintf (или любая библиотечная функция ) вызовет malloc.
А памяти для кучи уже нету. Как это решается ?

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

Пожалуйста с этого места поподробнее.
1. Как создать эту задачу ?
2. Этой задаче нужно 4.8K чтобы она была создана ?
zltigo
Цитата(MiniMax @ Feb 27 2008, 15:04) *
Да, я думаю, что понимаю это. Например, 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
MiniMax
Цитата
Смотрите, как она в оригинальном 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.
zltigo
Цитата(MiniMax @ Feb 27 2008, 17:57) *
Какой кусок отрезается в конце под стек ?

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

Менеджер памяти нужно делать свой, ибо фиксированное задание heap для контроллеров крайне не разумно и неудобно - надо задавать какой-то минимальный размер, дабы в случае фатально маленького heap линкер выругался, а реально отдавать всю оставшуюся память.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.