MiniMax 0 27 февраля, 2008 Опубликовано 27 февраля, 2008 · Жалоба Возникают проблемы с запуском ресурсоемких задач под 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 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
meister 0 27 февраля, 2008 Опубликовано 27 февраля, 2008 (изменено) · Жалоба Есть идеи как объяснить это? Загрузить в симулятор, расставить везде брикпоинтов, ассертов, отладочной печати и прошагать. heap_1 вообще память не освобождает, зато выделять должен с минимальными лишними расходами. Изменено 27 февраля, 2008 пользователем meister Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MiniMax 0 27 февраля, 2008 Опубликовано 27 февраля, 2008 · Жалоба Мне кажется, что здесь проблема даже не в менеджере памяти. Память уже выделена тем или иным образом. Почему 4.8K необходимо планировщику ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 1 27 февраля, 2008 Опубликовано 27 февраля, 2008 · Жалоба Есть идеи как объяснить это ? По выданной информации - никак. Для начала, просто имейте ввиду, что 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 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MiniMax 0 27 февраля, 2008 Опубликовано 27 февраля, 2008 · Жалоба По выданной информации - никак. Для начала, просто имейте ввиду, что Heap "сишный" и Неаp из которого берет память FreeRTOS это разные хипы и менеджеры. Да, я думаю, что понимаю это. Например, sprintf (вызывая библиотечный malloc) возьмет из Heap "сишного", поскольку эта функция даже и не знает о существовании FreeRTOS. Это на мой взгляд очень слабое место FreeRTOS. По сути ни о каком менеджменте памяти не может быть и речи. Просто FreeRTOS может позаботиться только, чтобы каждая задача вызывала функции, передавала параметры функций, и создавала локальные переменные в в своем (задачи) стеке. Я правильно понимаю ? Для начала, по крайней мере я так сделал сразу, отдал под нужды FreeRTOS всю оставшуюся память. Дополнительно мой менеджер памяти хранит владельца выделенного блока, посему всегда можно посмотреть кто и на что память скушал. А если тот-же sprintf (или любая библиотечная функция ) вызовет malloc. А памяти для кучи уже нету. Как это решается ? А с этим не просто, а очень просто :) У Вас Для самой ГЛАВНОЙ задачи IDLE памяти не хватило, вот создающей ее шедулер молча не запустился. Эту задачу надо создавать ПЕРВОЙ, я так и делаю в своей ветке FreeRTOS, кстати, это тоже одно из предложений не получившей никакой реакции от Автора FreeRTOS Пожалуйста с этого места поподробнее. 1. Как создать эту задачу ? 2. Этой задаче нужно 4.8K чтобы она была создана ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 1 27 февраля, 2008 Опубликовано 27 февраля, 2008 · Жалоба Да, я думаю, что понимаю это. Например, 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 0 27 февраля, 2008 Опубликовано 27 февраля, 2008 (изменено) · Жалоба Смотрите, как она в оригинальном 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 Изменено 27 февраля, 2008 пользователем MiniMax Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 1 28 февраля, 2008 Опубликовано 28 февраля, 2008 · Жалоба Какой кусок отрезается в конце под стек ? Ну для начала стеков у ARM много. Возможностей их описания может быть несколько, часто их размеры просто в лоб задают в startup - там где собственно и инициализируют. Размещение стеков тоже произвольное - не "в конце". Можно использовать --heap... Менеджер памяти нужно делать свой, ибо фиксированное задание heap для контроллеров крайне не разумно и неудобно - надо задавать какой-то минимальный размер, дабы в случае фатально маленького heap линкер выругался, а реально отдавать всю оставшуюся память. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться