Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Резервирование RSTACK для AVRMega
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > FreeRTOS
Aeore
Здравствуйте.

Компилятор: IAR AVR
Контроллер: AVR ATMega128 + 64КБ внешней памяти
Менеджер памяти: heap_3.c

Описание проблемы:
Прошивка представляет собой связку из нескольких слоев: ОС + Самописный фреймворк + Пользовательская программа. Специфика фреймворка и программы такова, что глубина вызовов может быть достаточно большой - приблизительно 20-30 вызовов в глубину. Вся эта связка в режиме симуляции под win32 работает нормально, но при прошивке контроллера начинаются проблемы - происходит циклическая перезагрузка, при том не всегда с самого начала. После очередного запуска программа может запуститься откуда-то с середины. Это все я контроллирую по трейсам в терминале.
Вобщем искал я искал и нашел такую проблему: в конфигурационном файле FreeRTOSConfig.h есть макроопределение configCALL_STACK_SIZE, которое по умолчанию установлено в 20. Исследование исходников показало, что это 20 байт, которые ОС резервирует в стеке задачи под адреса возврата из функций. Так как у меня мега, то получается максимальная глубина всего 10 вызовов, а дальше RSTACK начинает перетирать уже сохраненные регистры и все прочее, от чего начинаются проблемы. Ну хорошо, увеличим размер этой области до, скажем, 128 байт (глубина до 64 вызовов), при этом всем общего размера стека хватает - я его устанавливаю с запасом, скажем 8 КБ. Результат: программа не работает. Глючит уже по другому, но с тем же результатом. Вобщем экспериментальным образом я нашел, что при размере 45 текущая программа работает стабильно, но всеравно при дальнейшем усложнении кода начинаются похожие проблемы.

Вопрос: Как установить большой размер для стека возвратов?

Очень надеюсь на вашу помощь.

PS: Да, еще была проблема - вместе с этим постоянно срабатывал каллбэк vApplicationStackOverflowHook(), пока я не увеличил стандартные значения макросов configTIMER_QUEUE_LENGTH и configTIMER_TASK_STACK_DEPTH. После этого каллбэк срабатывал только после большого количества этих перезагрузок при глючащей системе. Теперь же, после небольшого допиливания программы (дописал несколько пустых классов-тасок и запустил их), опять начал срабатывать, но уже без таких феерических циклов перезагрузок как раньше (всего лишь одна):

Вот пример трейсов, тут работа начинается с "Svc: LBKLogic started". Видно, что програма стартует нормально, но потом начинаются уже какие=-то глюки, после чего контроллер перезагружается (следующий "Svc: LBKLogic started") и дальше пока что все идет хорошо! (это до поры до времени)
Код
Svc: LBKLogic started
<!> Fatal: FreeRTOS stack overflow (Task: "J¤JјJНJСJ$%ҐJ", Stack ptr: 4acd, Stack base: 4ad1)
<!> Fatal: FreeRTOS stack overflow (Task: "J¤JјJНJСJ$%ҐJ", Stack ptr: 4a99, Stack base: bcf7)
<!> Fatal: FreeRTOS stack overflow (Task: "J¤JјJНJСJ$%ҐJ", Stack ptr: 4a65, Stack base: bcf7)
<!> Fatal: FreeRTOS stack overflow (Task: "J¤JјJНJСJ$%ҐJ", Stack ptr: 4a31, Stack base: bcf7)
<!> Fatal: FreeRTOS stack overflow (Task: "J¤JјJНJСJ$%ҐJ", Stack ptr: 49fd, Stack base: bcf7)
<!> Fatal: FreeRTOS stack overflow (Task: "J¤JјJНJСJ$%ҐJ", Stack ptr: 49c9, Stack base: bcf7)
<!> Fatal: FreeRTOS stack overflow (Task: "J¤JјJНJСJ$%ҐJ", Stack ptr: 4995, Stack base: bcf7)
<!> Fatal: FreeRTOS stack overflow (Task: "J¤JјJНJСJ$%6—6±1b0Л-µЗб"9дCлб"9дCлб"9дCлб"9дCлб"9дCлб"9дCлб"9дCлб"9дC%А&%i3"^›", Stack ptr: 4961, Stack base: bcf7)
<!> Fatal: FreeRTOS stack overflow (Task: "J¤J6—6±1b0Л-µЗб"9дCлб"9дCлб"9дCлб"9дCлб"9дCлб"9дCлб"9дCлб"9дCлб"9дC%А&%i3"^›", Stack ptr: 492d, Stack base: bcf7)
Svc: LBKLogic started
Svc: Platform started
Svc: HMILogic started
Svc: BeepMaster started
Svc: Controller started
Nothing more to run


PPS: Фрагмент текущей конфигурации из FreeRTOSConfig.h:
Код
#ifndef WIN32
# include <iom128.h>
#endif

#define configCALL_STACK_SIZE        45 // 20 by default

#define configUSE_PREEMPTION                1
#define configUSE_IDLE_HOOK                0
#define configUSE_TICK_HOOK                0
#define configCPU_CLOCK_HZ                ( ( unsigned long ) 16000000 )
#define configTICK_RATE_HZ                ( ( portTickType ) 1000 )
#define configMAX_PRIORITIES                ( ( unsigned portBASE_TYPE ) 9 )
#define configMINIMAL_STACK_SIZE            ( ( unsigned short ) 85 + configCALL_STACK_SIZE ) // 85 by default
#define configTOTAL_HEAP_SIZE                ( ( size_t ) ( 51200 ) )
#define configMAX_TASK_NAME_LEN                ( 16 )
#ifdef DEBUG // ygurin
#define configUSE_TRACE_FACILITY            1
#else
#define configUSE_TRACE_FACILITY            0
#endif
#define configUSE_16_BIT_TICKS                1
#define configIDLE_SHOULD_YIELD                1
#define configUSE_TIMERS                        1
#define configTIMER_TASK_PRIORITY               (configMAX_PRIORITIES - 1)
#define configTIMER_QUEUE_LENGTH                64 // 20 by default 64
#define configTIMER_TASK_STACK_DEPTH            92 // 64 by default 92

#define configUSE_CO_ROUTINES                 0
#define configMAX_CO_ROUTINE_PRIORITIES       ( 2 )

#define INCLUDE_vTaskPrioritySet        1
#define INCLUDE_uxTaskPriorityGet        1
#define INCLUDE_vTaskDelete            1
#define INCLUDE_vTaskCleanUpResources            0
#define INCLUDE_vTaskSuspend            1
#define INCLUDE_vTaskDelayUntil            1
#define INCLUDE_vTaskDelay            1



А это MAP файл с сегментами, который сгенерировал компилятор:

Имя Пространство Адрес Размер Тип Выравнивание
NEAR_I DATA 00001100 - 00001309 20A Relative 0
NEAR_Z DATA 0000130A - 00001390 87 Relative 0
RSTACK DATA 00001391 - 00001790 400 Predefined 0
CSTACK DATA 00001791 - 00001B90 400 Predefined 0
NEAR_HEAP DATA 00001B91 - 0000E68A CAFA Predefined 0
desh
Возможно Ваша проблемма не в FreeRTOS, а в прикладной задаче. Переполнение буфера, ошибка в математике указателей, доступ к общей памяти из нескольких задач без блокировок и т.п.
Использую FreeRTOS c ATmega2561 как с внешней памятью так и без нее. За несколько лет работы в этой связке все проблемы возникали только из-за ошибок прикладного кода.
Сейчас стек вызовов 100 байт (глубина порядка 30). Для себя доработал ядро так, что кроме переполнения CStack я отслеживаю еще и переполнение RStack.

Протестируйте внешнюю память на предмет ошибок. Очень может быть у Вас проблемма с железом.
Я использую вот такой тест. Попробуйте доработать его под себя.

CODE

#include "types.h"
#include <stdio.h>
#include <stdlib.h>

#define MEMORY_START 0x1100
#define MEMORY_SIZE 32768

USHORT Errors;
ULONG Tests;
ULONG Total;

void Delay(USHORT Ms)
{
TCCR1B_WGM12 = 1; // СTС
OCR1A = (F_CPU / (2 * 8 * 1000)) - 1;
TCNT1 = 0;
TCCR1B_CS11 = 1; // Прескаллер 8
while (Ms--)
{
#ifdef NDEBUG
while (!TIFR_OCF1A); // Ждем флаг 1мс
TIFR_OCF1A = 1; // Сброс флага
#endif
}
TCCR1B_CS11 = 0; // Таймер отключен
}

void SetLedGreen(bool State)
{
DDRF_DDF2 = 1;
PORTF_PORTF2 = State ? 0 : 1;
}

void SetLedRed(bool State)
{
#if defined(_MA_301_)
DDRE_DDE7 = 1;
PORTE_PORTE7 = State ? 0 : 1;
#else
DDRB_DDB4 = 1;
PORTB_PORTB4 = State ? 0 : 1;
#endif
}

void UartInit(ULONG Baud)
{
USHORT Reg = (F_CPU / (Baud * 16)) - 1;

#if defined(_MA_301_)
UBRR1H = Reg >> 8;
UBRR1L = Reg;
UCSR1C = (1 << UCSZ11)|(1 << UCSZ10); // 8-N-1
UCSR1B = (1 << RXEN1)|(1 << TXEN1);
#elif defined(_M_320_)
UBRR1H = Reg >> 8;
UBRR1L = Reg;
UCSR1C = (1 << UCSZ11)|(1 << UCSZ10); // 8-N-1
UCSR1B = (1 << RXEN1)|(1 << TXEN1);
DDRD_DDD6 = 1;
PORTD_PORTD6 = 1;
#else
UBRR0H = Reg >> 8;
UBRR0L = Reg;
UCSR0C = (1 << UCSZ01)|(1 << UCSZ00); // 8-N-1
UCSR0B = (1 << RXEN0)|(1 << TXEN0);
DDRD_DDD7 = 1;
PORTD_PORTD7 = 0;
#endif
}

#ifdef NDEBUG
int putchar(int Char)
{
#if defined(_MA_301_)
while (!UCSR1A_UDRE1);
UDR1 = Char;
#elif defined(_M_320_)
while (!UCSR1A_UDRE1);
UDR1 = Char;
#else
while (!UCSR0A_UDRE0);
UDR0 = Char;
#endif
return Char;
}
#endif

void MemoryEnable()
{
DDRF_DDF3 = 1;
MCUCR_SRE = 1;
}

void MemoryInit(UCHAR InitVal)
{
UCHAR *ExtMem = (UCHAR*)MEMORY_START;

for (ULONG Index = 0; Index < MEMORY_SIZE; Index++)
{
ExtMem[Index] = InitVal ^ Index;
}
}

void MemoryTest(UCHAR InitVal)
{
UCHAR ReadVal;
UCHAR *ExtMem = (UCHAR*)MEMORY_START;

for (ULONG Index = 0; Index < MEMORY_SIZE; Index++)
{
ReadVal = ExtMem[Index] ^ Index;
if (ReadVal != InitVal) Errors++;
}
}

int main( void )
{
bool State = false;

UartInit(115200);
printf("Memory test\r\n");
MemoryEnable();
for (;;)
{
UCHAR InitVal = rand();

SetLedGreen(State ^= true);
MemoryInit(InitVal);
MemoryTest(InitVal);
Total += Errors;
SetLedRed(Total ? true : false);
printf("Test %lu, Init 0x%02X, Errors %hu, Total %lu\r\n", Tests, InitVal, Errors, Total);
Errors = 0;
Tests++;
}
}
Aeore
Переполнение буфера, очевидно, происходит, но по не совсем понятным причинам. Математика указателей, а тем более доступ без блокировок вообще исключены. Внешнюю память я уже тестировал когда-то, проблем там небыло. Но протестирую еще раз, возможно я что-то упустил. Спасибо за наводку.

PS: Я сейчас нашел немного другой порт под мегу128, но под GCC (старый я сам дорабатывал из 323меги, что идет в комплекте). Попробую адаптировать его под иар и посмотрю что получится
desh
Да не спешите Вы. Там от 323 до 128 один регистр сохранять надо.

CODE


portSAVE_CONTEXT MACRO
st -y, r0 ; First save the r0 register - we need to use this.
in r0, SREG ; Obtain the SREG value so we can disable interrupts...
cli ; ... as soon as possible.
st -y, r0 ; Store the SREG as it was before we disabled interrupts.

in r0, SPL ; Next store the hardware stack pointer. The IAR...
st -y, r0 ; ... compiler uses the hardware stack as a call stack ...
in r0, SPH ; ... only.
st -y, r0

st -y, r1 ; Now store the rest of the registers. Dont store the ...
st -y, r2 ; ... the Y register here as it is used as the software
st -y, r3 ; stack pointer and will get saved into the TCB.
st -y, r4
...
st -y, r30
st -y, r31

in r0, RAMPZ ; Вот этот регистр
st -y, r0 ; надо сохранить

lds r0, uxCriticalNesting
st -y, r0 ; Store the critical nesting counter.

lds r26, pxCurrentTCB ; Finally save the software stack pointer (Y ...
lds r27, pxCurrentTCB + 1 ; ... register) into the TCB.
st x+, r28
st x+, r29

ENDM


portRESTORE_CONTEXT MACRO
lds r26, pxCurrentTCB
lds r27, pxCurrentTCB + 1 ; Restore the software stack pointer from ...
ld r28, x+ ; the TCB into the software stack pointer (...
ld r29, x+ ; ... the Y register).

ld r0, y+
sts uxCriticalNesting, r0

ld r0, y+ ; А здесь
out RAMPZ, r0 ; вернуть как был

ld r31, y+ ; Restore the registers down to R0. The Y
ld r30, y+ ; register is missing from this list as it
ld r27, y+ ; has already been restored.
...
ld r2, y+
ld r1, y+

ld r0, y+ ; The next thing on the stack is the ...
out SPH, r0 ; ... hardware stack pointer.
ld r0, y+
out SPL, r0

ld r0, y+ ; Next there is the SREG register.
out SREG, r0

ld r0, y+ ; Finally we have finished with r0, so restore r0.

ENDM

framer
А может еще зависит от размера стека для конкретной задачи. В этом случае, это не только количество вызовов функции в глубину но и размеры локальных переменных в этих фунциях. Чтобы точно знать, что переполняеться стек задач надо использовать функцию http://www.freertos.org/uxTaskGetStackHighWaterMark.html
Aeore
desh, RAMPZ у меня не сохранялся, спасибо. Я сейчас добавил ваши изменения, а так же добавил строчку в функцию pxPortInitialiseStack:
Код
...
    *pxTopOfStack = ( portSTACK_TYPE ) 0x30;    /* R30 Z */
    pxTopOfStack--;
    *pxTopOfStack = ( portSTACK_TYPE ) 0x31;    /* R31 */

        pxTopOfStack--;      // вот эти две
        *pxTopOfStack = ( portSTACK_TYPE ) 0x3B;    /* RAMPZ */
        
    pxTopOfStack--;
    *pxTopOfStack = portNO_CRITICAL_NESTING;    /* Critical nesting is zero when the task starts. */
..


Программа запустилась, но сходу упала в stack overfow. Вот на всякий случай показыаю как выглядит участок фреймворка, который собственно и запускает таски:

До старта операциооной системы вызываются эти функции. Все эти классы являются наследниками класса CServiceBase и пока что не содержат интересного кода:

static_cast<void>(CPBeepMasterService::run());
static_cast<void>(CPControllerService::run());
static_cast<void>(CPPlatformService::run());
static_cast<void>(CPHMILogicService::run());
static_cast<void>(CPAuxADCService::run());



В аттаче прикреплены файлы, описанные в диаграмме

PS: Дам ссылку на эту тему в теме про __interrupt
desh
Цитата(Aeore @ Jun 2 2013, 12:31) *
а так же добавил строчку в функцию pxPortInitialiseStack:

Все правильно. Забыл про нее.

Что мешает вам запустить и отладить задачи по очереди? Похоже архитектура приложения позволяет это сделать.
Что у вас происходит при переполнении стека? У вас отрабатывает ловушка переполнения стека FreeRTOS?
Поставте в ней бесконечный цикл. При попадании изучите содержимое стека и pxCurrentTCB.
На время отладки отключите сторожевой таймер.
В чем смысл использования фреймворка? На разных платформах вы используете разные операционки?
Обратите внимание на scmRTOS. Она изначально на плюсах.

Какое у вас значение configMINIMAL_STACK_SIZE? Увеличте его. Оно влияет на размер стека задачи IDLE.
В IDLE переполнение стека могут вызывать прерывания.
_Артём_
Цитата(Aeore @ Jun 2 2013, 11:31) *
Программа запустилась, но сходу упала в stack overfow.

Это хорошо, если программа сразу падает - ошибку найти гораздо легче.
Пройдитесь по шагам до места падения.
Aeore
Цитата(desh @ Jun 2 2013, 12:33) *
Что мешает вам запустить и отладить задачи по очереди? Похоже архитектура приложения позволяет это сделать.

Мешает неопределенное поведение системы. На работоспособность влияют совершенно несвязанные изменения. Вот к примеру :

Стартует первая таска и тут же валится все по переполнению стека:
CODE

Svc: LBKLogic started
<!> Fatal: FreeRTOS stack overflow (Task: "ОJжJцJыJ$%6ПJ", Stack ptr: 4af6, Stack base: 4afb)
<!> Fatal: FreeRTOS stack overflow (Task: "ОJжJцJыJ$%6ПJ", Stack ptr: 4ac1, Stack base: 4ae6)
<!> Fatal: FreeRTOS stack overflow (Task: "ОJжJцJыJ$%6ПJ", Stack ptr: 4a8c, Stack base: 4ae6)
<!> Fatal: FreeRTOS stack overflow (Task: "ОJжJцJыJ$%6ПJ", Stack ptr: 4a57, Stack base: 4ae6)
<!> Fatal: FreeRTOS stack overflow (Task: "ОJжJцJыJ$%6ПJ", Stack ptr: 4a22, Stack base: 4ae6)
<!> Fatal: FreeRTOS stack overflow (Task: "ОJжJцJыJ$%6ПJ", Stack ptr: 49ed, Stack base: 4ae6)
<!> Fatal: FreeRTOS stack overflow (Task: "ОJжJцJыJ$%6ПJ", Stack ptr: 49b8, Stack base: 4ae6)
<!> Fatal: FreeRTOS stack overflow (Task: "ОJжJцJыJ$%67A7[2
1u._
^"ВВ/^"ВВ/^"ВВ/^"ВВ/^"ВВ/^"ВВ/^"ВВ/^"ВВ&j&»&3"^›", Stack ptr: 4983, Stack base: 4ae6)
<!> Fatal: FreeRTOS stack overflow (Task: "ОJ7A7[2
1u._
^"ВВ/^"ВВ/^"ВВ/^"ВВ/^"ВВ/^"ВВ/^"ВВ/^"ВВ/^"ВВ&j&»&3"^›", Stack ptr: 494e, Stack base: 4ae6)
<!>


А теперь внимание! Добавляем проверочный код в эту таску (который ничего не делает и ни с чем не связан) и вуалля - все начинает работать хорошо:

CODE

void o(string s)
{
TRACE(const_cast<char*>(s.c_str()));
}

void m(string s)
{
o(s);
}

void l(string s)
{
m(s);
}

void k(string s)
{
l(s);
}

void g(string s)
{
k(s);
}

void f(string s)
{
g(s);
}

void e(string s)
{
f(s);
}

void d(string s)
{
e(s);
}

void c(string s)
{
d(s);
}

void b(string s)
{
c(s);
}

void a(string s)
{
b(s);
}

// --------------------------------------------------------------------------
void CPLBKLogicService::taskStart( void* const pContext )
// --------------------------------------------------------------------------
{
uint32_t q[500];
q[300] = 5;
if (q[300] == 5)
{
a("affected!");
}
TRACE( "Svc: LBKLogic started" );
}


И вот что полияло на результат? O_o

Цитата(desh @ Jun 2 2013, 12:33) *
Что у вас происходит при переполнении стека? У вас отрабатывает ловушка переполнения стека FreeRTOS?

да

Цитата(desh @ Jun 2 2013, 12:33) *
Поставте в ней бесконечный цикл.

Цикл есть. Перезагружается всеравно. Возможно из-за преемптивного планировщика

Цитата(desh @ Jun 2 2013, 12:33) *
При попадании изучите содержимое стека и pxCurrentTCB.

Попробую, правда сильно внутринности ОС я пока что не изучал

Цитата(desh @ Jun 2 2013, 12:33) *
На время отладки отключите сторожевой таймер.

Таймер не включен

Цитата(desh @ Jun 2 2013, 12:33) *
В чем смысл использования фреймворка? На разных платформах вы используете разные операционки?
Обратите внимание на scmRTOS. Она изначально на плюсах.

Идея фреймворка - предоставить расширенное и удобное, полностью асинхронное event-driven окружение для разработки ПО. FreeRTOS используется в качестве ядра и так же дает дополнительные плюшки в виде возможности поднимать независимые потоки.
На scmRTOS я смотрел и даже использовал, но его возможности ограниченны по сравнению с FreeRTOS, к примеру там невозможно удалить таску.

Цитата(desh @ Jun 2 2013, 12:33) *
Какое у вас значение configMINIMAL_STACK_SIZE? Увеличте его. Оно влияет на размер стека задачи IDLE.
В IDLE переполнение стека могут вызывать прерывания.

Я написал так:
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 85 + configCALL_STACK_SIZE )

Самм IDLE я пока что не использую, прерывания так же - лишь один таймер работает для функционированния вытесняющего планировщика
desh
Так. ЧуднО у вас все.

Цитата
Цикл есть. Перезагружается всеравно. Возможно из-за преемптивного планировщика

Запретите еще и прерывания.

Пробовали запускать и отлаживать в симуляторе IAR? Прерываний у вас мало, так что проблемм с запуском минимиум.
Отладку перенаправьте в стандартный вывод. Можно следить за происходящим прямо в симуляторе.
Какой уровень оптимизации у вас стоит?

Поофтоплю чуток.
Цитата
полностью асинхронное event-driven окружени

ИМХО, не распологает выбранная платформа и среда к подобному программированию.
Код получается размазанным и сложным в сопровождении. Ресурсов опять таки не хватает постоянно.
Мне не понравилось так писать. Хотя, все зависит от задачи.
Aeore
Цитата(desh @ Jun 3 2013, 23:01) *
Запретите еще и прерывания.

Запрещал

Цитата(desh @ Jun 3 2013, 23:01) *
Пробовали запускать и отлаживать в симуляторе IAR? Прерываний у вас мало, так что проблемм с запуском минимиум.
Отладку перенаправьте в стандартный вывод. Можно следить за происходящим прямо в симуляторе.
Какой уровень оптимизации у вас стоит?


Пробовал. Симулятор вел себя не вполне адекватно - перепрыгивал через целые участки кода. Уровень оптимизации установлен максимальный, но такое поведение наблюдалось и при минимальной оптимизации. Вот сейчас по какой-то причине код заработал нормально, и симуляция на первый взгляд тоже. Подожду глюка и попробую проверить, а то я был не уверен в его адекватности

Цитата(desh @ Jun 3 2013, 23:01) *
Поофтоплю чуток.
ИМХО, не распологает выбранная платформа и среда к подобному программированию.
Код получается размазанным и сложным в сопровождении. Ресурсов опять таки не хватает постоянно.
Мне не понравилось так писать. Хотя, все зависит от задачи.

Ну в целом получается достаточно не плохо, главное уделить внимание архитектуре. А то действительно получится паутина. По поводу производительности - вот это я и хочу проверить) Пишу достаточно свободно и пока мега справляется очень хорошо (если не обращать внимание на глюки стека, что другое дело), а вытесняющий планировщик и приоритеты позволяют весьма шустро реагировать на все события. В основном программу можно написать так, что бы лишь малая ее часть была чувствительна к скорости работы и реакции - ее можно выделить в отдельные таски. А основная логика может быть громоздкой и работать относительно медленно - этого вообще не чувствуется. Именно поэтому я без страха использую полиморфизм.
framer
Цитата(Aeore @ Jun 3 2013, 21:15) *
А теперь внимание! Добавляем проверочный код в эту таску (который ничего не делает и ни с чем не связан) и вуалля - все начинает работать хорошо:

CODE

void o(string s)
{
TRACE(const_cast<char*>(s.c_str()));
}

void m(string s)
{
o(s);
}

void l(string s)
{
m(s);
}

void k(string s)
{
l(s);
}

void g(string s)
{
k(s);
}

void f(string s)
{
g(s);
}

void e(string s)
{
f(s);
}

void d(string s)
{
e(s);
}

void c(string s)
{
d(s);
}

void b(string s)
{
c(s);
}

void a(string s)
{
b(s);
}

// --------------------------------------------------------------------------
void CPLBKLogicService::taskStart( void* const pContext )
// --------------------------------------------------------------------------
{
uint32_t q[500];
q[300] = 5;
if (q[300] == 5)
{
a("affected!");
}
TRACE( "Svc: LBKLogic started" );
}


А проверяли использование стека сомой таской? Сколько выделяете стека на таск xTaskCreate(task, (signed char *)"task", ??? , 0,tskIDLE_PRIORITY + 2, NULL); ? Как я писал локалные переменные ложаться в стек задачи а у Вас локальная переменная во uint32_t q[500];. Попробуйте динамически выделить память, либо сделать глобальную переменную и посмотреть как себя ведет. А что возвращает uxTaskGetStackHighWaterMark( xTaskHandle xTask ); во вложеных функциях ?
desh
Цитата
Пробовал. Симулятор вел себя не вполне адекватно - перепрыгивал через целые участки кода. Уровень оптимизации установлен максимальный, но такое поведение наблюдалось и при минимальной оптимизации. Вот сейчас по какой-то причине код заработал нормально, и симуляция на первый взгляд тоже. Подожду глюка и попробую проверить, а то я был не уверен в его адекватности

Симулятор адекватен. Нужно разобраться со скриптами и у вас в руках будет серьезный инструмент для отладки и тестирования.
Еще я стараюсь не пользоваться максимальной оптимизацией без необходимости. При максимальной оптимизации проявляются неточности программирования (например, забытые volatile),
которые незаметны при низкой оптимизации. Уровень medium вполне себе неплохо жмет.
При отладке оптимизированного кода прыжки - нормальное дело.
Кстати, в среде IAR есть возможность разный уровень оптимизации для разных файлов. Рекомендую.

Aeore
Цитата(framer @ Jun 6 2013, 11:33) *
А проверяли использование стека сомой таской? Сколько выделяете стека на таск xTaskCreate(task, (signed char *)"task", ??? , 0,tskIDLE_PRIORITY + 2, NULL); ? Как я писал локалные переменные ложаться в стек задачи а у Вас локальная переменная во uint32_t q[500];. Попробуйте динамически выделить память, либо сделать глобальную переменную и посмотреть как себя ведет. А что возвращает uxTaskGetStackHighWaterMark( xTaskHandle xTask ); во вложеных функциях ?


Извиняюсь за то что долго не писал. Стека под каждую задачу выделяется с очень больши запасом. Вот только что застабил и перенес проект на WIN32 и тут появились такие новости с uxTaskGetStackHighWaterMark:

На данный момент есть такие таски:
CPLBKLogicService: 1024
CPPlatformService: 2048
CPHMILogicService: 2048
CPControllerService: 4096

Цифры это размер стеков этих задач. taskStart - это то место, где они запускаются.

Вот кусок трейсов с платформы avr (цифры это результат работы функции uxTaskGetStackHighWaterMark в различных местах):
CODE

P45G Broadband Radio Controller
2013, YGurin
----------------------------------------
[SS]: LBKLogic
SHW CPLBKLogicService::taskStart 54
[SS]: Platform
[SS]: HMI
SHW CPHMILogicService::taskStart 54
SHW CPPlatformService::taskStart 54
[SS]: BeepMaster
[SS]: Controller
SHW CPControllerService::taskStart 52
SHW CPControllerService::onQueueCommandActioned 7
SHW CPStrategyPOSTCommand::start 246
SHW CPControllerService::onQueueCommandActioned 246
SHW CPControllerService::onQueueCommandActioned 236
SHW CPControllerService::onQueueCommandActioned 234
Nothing more to run


А вот то же самое, но с WIN32. Как видно, на avr uxTaskGetStackHighWaterMark() возвращает всего ничего, а на win32 все нормально:


Т.е. все очень сильно зависит от платформы. Это уже что-то.
desh
У вас как на АВР-е определен базовый тип portBASE_TYPE как unsigned char.
В принципе функция uxTaskGetStackHighWaterMark больше 255 вернуть не сможет.
Тут же и ограничение на размер очереди в элементах.
framer
Цитата(Aeore @ Jun 13 2013, 00:09) *
CODE

[SS]: Controller
SHW CPControllerService::taskStart 52
SHW CPControllerService::onQueueCommandActioned 7 !!!!!
SHW CPStrategyPOSTCommand::start 246
SHW CPControllerService::onQueueCommandActioned 246


Видно, что в некоторых местах стек практически весь использован. Да размер стека выделяемый под задачи зависит от платформы так, что на эмуляторе может все работать.
Aeore
Цитата(desh @ Jun 14 2013, 09:52) *
У вас как на АВР-е определен базовый тип portBASE_TYPE как unsigned char.
В принципе функция uxTaskGetStackHighWaterMark больше 255 вернуть не сможет.
Тут же и ограничение на размер очереди в элементах.


Опс.. да, действительно. По поводу очереди - у меня в каждой очереди по 16 элементов, так что не страшно.

Цитата(framer @ Jun 14 2013, 15:06) *
Видно, что в некоторых местах стек практически весь использован. Да размер стека выделяемый под задачи зависит от платформы так, что на эмуляторе может все работать.


Как он может зависеть от платформы, если я сам указываю размеры стеков?
framer
Цитата(Aeore @ Jun 16 2013, 23:59) *
Как он может зависеть от платформы, если я сам указываю размеры стеков?


Ну а как обяснить показатели использования стека uxTaskGetStackHighWaterMark под Win32?

Цитата(Aeore @ Jun 13 2013, 00:09) *
А вот то же самое, но с WIN32. Как видно, на avr uxTaskGetStackHighWaterMark() возвращает всего ничего, а на win32 все нормально:


Т.е. все очень сильно зависит от платформы. Это уже что-то.



Заняло по 5 блоков(слов) и все. Видно, что стек в задачах не используется. Все зависит от того как перенесено на WIN32. Под win если посмотреть то таски симулитуютя использованием thread. Там нет переключения контекста с изменением указателей стека. Осуществляется это остановкой текущего thread и запуском следующего (можно посмотреть исходники в prvProcessSimulatedInterrupts ). В таком случае локальные перемнные не распологаються в стеке задачи FreeRtos, а используються механизмы win32. Поэтому отладка стека эфективна на конкретной платформе.
Aeore
Да, это так. Я недавно перевел систему из преемптивного в кооперативный режим - глюки исчезли полностью, хотя функция uxTaskGetStackHighWaterMark() в целом возвращает те же значения
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2024 Invision Power Services, Inc.