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

вообще, кто-нибудь пользует этот порт?

 

в переключалке задач

 

.....

[--sp] = lb1;

 

//--------------------------------------------------------------------------

//

// Switch stack pointers and manage interrupt enable status

//

p5.l = lo(IMASK); // save IMASK value

p5.h = hi(IMASK); // (global interrupts enable state)

r7 = [p5]; //

[--sp] = r7; //

r0 = sp;

 

call _OS_ContextSwitchHook;

 

......

 

на верхушку стека кладется содержимое IMASK и вызывается С-шная функция

 

TStackItem* OS_ContextSwitchHook(TStackItem* sp) { return OS::Kernel.ContextSwitchHook(sp); }

 

// "..\..\scmRTOS\Common\OS_Kernel.cpp" line 87 col 50

link 12;

 

._P2L2147483646:

[FP+ 8] = R0;

.LN12:

// "..\..\scmRTOS\Common\OS_Kernel.cpp" line 87 col 87

R1 = R0 ;

R0.L = _Kernel__2OS; R0.H = _Kernel__2OS;

CALL.X _ContextSwitchHook__Q2_2OS7TKernelFPUl;

 

.........

 

при этом link 12 и [FP+8] затирают значение IMASK на стеке

 

стек в блэкфине предекрементный, ну и вообще вроде бы соответствует соглашениям о вызовах (стр 1-255 40_ccblkfin_man.pdf) - там должно быть место для сохранения аргументов

 

--------------------------------

 

я вставил декремент стека

 

[--sp] = sp; //dummy stack decrement to prevent IMASK overwrite

call _OS_ContextSwitchHook;

 

после чего мои примерчики заработали

 

==============================

 

но не совсем понятно использование разных масок (то есть может эта сохранненная маска потом не нужна и я просто глючу) ?

но без этого исправления вообще нифига не работало...

 

------------------------------------------------------

 

собственно, кто-нибудь пользуется scmRTOS для blackfin-а?

 

==============================

 

у меня был некий проектик (BF532 без внешней памяти), на котором использовалась scmRTOS v2

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

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


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

вообще, кто-нибудь пользует этот порт?

 

Я использую. С самого начала. :)

 

в переключалке задач

 

.....

 

TStackItem* OS_ContextSwitchHook(TStackItem* sp) { return OS::Kernel.ContextSwitchHook(sp); }

 

// "..\..\scmRTOS\Common\OS_Kernel.cpp" line 87 col 50

link 12;

 

._P2L2147483646:

[FP+ 8] = R0;

.LN12:

// "..\..\scmRTOS\Common\OS_Kernel.cpp" line 87 col 87

R1 = R0 ;

R0.L = _Kernel__2OS; R0.H = _Kernel__2OS;

CALL.X _ContextSwitchHook__Q2_2OS7TKernelFPUl;

 

.........

 

при этом link 12 и [FP+8] затирают значение IMASK на стеке

 

стек в блэкфине предекрементный, ну и вообще вроде бы соответствует соглашениям о вызовах (стр 1-255 40_ccblkfin_man.pdf) - там должно быть место для сохранения аргументов

 

Вообще, функция OS_ContextSwitchHook является не более, чем оберткой для функции OS::TKernel::ContextSwitchHook и последняя объявлена как встраиваемая, т.е. ее тело подставляется в внутрь OS_ContextSwitchHook. В норме она и должна встраиваться и я не сталкивался с ситуацией, когда этого бы не происходило. Более того, это обстоятельство является таковым по замыслу - не нужен совершенно еще один лишний вызов и весь связанный с этим оверхед.

 

Очевидно, у вас какие-то другие опции оптимизации, что не происходит встраивания инлайновой функции. У меня оптимизация чаще всего -Ov 80 (но и при -Ov 20 поведение аналогичное - все встраивается).

 

 

--------------------------------

 

я вставил декремент стека

 

[--sp] = sp; //dummy stack decrement to prevent IMASK overwrite

call _OS_ContextSwitchHook;

 

после чего мои примерчики заработали

 

Наверное, более правильно было бы

 

SP += -12;

 

В любом случае спасибо за правильное и ценное замечание.

 

 

но не совсем понятно использование разных масок (то есть может эта сохранненная маска потом не нужна и я просто глючу) ?

но без этого исправления вообще нифига не работало...

 

Вы про IMASK, который сохраняется в стеке? Если про него, то тут все просто - с помощью этого запоминается состояние прерываний для каждого процесса.

 

 

у меня был некий проектик (BF532 без внешней памяти), на котором использовалась scmRTOS v2

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

 

v2 тоже не пропала - до нее можно добраться через сайт проекта, там где-то есть ссылка на Old, по которой лежит целиком весь старый (v2) сайт.

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


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

Спасибо.

 

при включенной оптимизации (скорее всего interprocedural или как там она называется) не сохраняет аргументы в стек

но хочется и подебажить :)

 

судя по примерам, включена еще "элиминация" в смысле выбрасывание неиспользуемых меток - в скрипте линкера если не объявлять и элиминация выключена - требует эти метки для линковки libc

ldf_heap_length

ldf_heap_space

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

 

==========

 

пропажа v2 - пропали мои исходники - у Вас все в порядке :)

но если переписывать, то лучше на v3

 

в работе RTOS никаких непонятностей не заметил.

 

------------------

 

а с использованием Scratch памяти в качестве стека задач, какие-нибудь проблемы возможны?

по DMA доступ не нужен, байтовый доступ ... можно сделать чтобы не было

а я почему-то не встречал использования Scratch

ни в каких примерах ldf, а тут проект без внешней памяти - каждый килобайт на счету ...

 

вот описание аномалии:

Reads from the scratchpad memory may return incorrect data under some conditions. The problem occurs when reads of scratchpad

memory are immediately followed by another read (of any location, including non-scratchpad locations), where the addresses being

accessed do not have the same least significant address bit. This means that one of the transfers has to be a byte access. The other access

has to be either a byte, 16-bit or 32-bit access on a different byte boundary than the first access. In addition, the instruction immediately

before the Scratchpad memory read has to generate a memory stall due to either a dual DAG bank collision, a non-L1 memory data fetch,

or a cache-line fill.

If an instruction does not perform a read immediately after the scratchpad read, no problems occur. Also, back to back non-byte reads

function properly.

WORKAROUND:

The simplest workaround for assembly programmers is to place any non-read instruction after each scratchpad read. For C programmers,

one solution is not to map any data to the scratchpad.

Alternatively the VisualDSP++ Blackfin compiler includes a workaround for this hardware anomaly. The compiler will automatically enable

the workaround for the appropriate silicon revisions and part numbers, or the workaround can be enabled manually by specifying the

compiler flag -workaround scratchpad-read' With the workaround enabled, when a sequence of three load instructions occurs (or occur

as parts of a multi-issue instruction), where at least one of (2) and (3) is a byte load, a nop will be inserted between (1) and (2) or (2) and (3):

A load instruction (1);

A load instruction (2);

A load instruction (3);

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


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

а с использованием Scratch памяти в качестве стека задач, какие-нибудь проблемы возможны?

по DMA доступ не нужен, байтовый доступ ... можно сделать чтобы не было

а я почему-то не встречал использования Scratch

ни в каких примерах ldf, а тут проект без внешней памяти - каждый килобайт на счету ...

 

вот описание аномалии:

Reads from the scratchpad memory may return incorrect data under some conditions. The problem occurs when reads of scratchpad

...

Вот именно из-за оной аномалии и не пробовал никогда туда ничего класть. На асме, видимо, можно пользоваться, но у меня почти весь код на С++. Память сильно не жмет, хотя проект тоже весь живет внутри процессора, поэтому не искал проблем. Можно посмотреть на новые ревизии, может в них уже пофиксили баг.

 

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

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


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

..

а с использованием Scratch памяти в качестве стека задач, какие-нибудь проблемы возможны?

по DMA доступ не нужен, байтовый доступ ... можно сделать чтобы не было

а я почему-то не встречал использования Scratch

ни в каких примерах ldf, а тут проект без внешней памяти - каждый килобайт на счету ...

Используется, посмотрите исходники ROM загрузчиков от analog.

Еще используется для сохранения стека при прерываниях - порт bfin для RTEMS (cpu_asm.S).

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


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

Используется, посмотрите исходники ROM загрузчиков от analog.

Еще используется для сохранения стека при прерываниях - порт bfin для RTEMS (cpu_asm.S).

 

спасибо за информацию

 

Вот именно из-за оной аномалии и не пробовал никогда туда ничего класть. На асме, видимо, можно пользоваться, но у меня почти весь код на С++. Память сильно не жмет, хотя проект тоже весь живет внутри процессора, поэтому не искал проблем. Можно посмотреть на новые ревизии, может в них уже пофиксили баг.

 

есть вопрос по С++ применительно к scmRTOS:

 

как правильнее вызывать Sleep из некоторой иерархии сишных функций внутри проекта?

TProc1::Exec() -> foo() -> boo() -> moo()

 

и внутри moo() я хочу передать управление

могу написать

TProc1::Sleep(10);

или

Proc1.Sleep(3);

 

как правильнее? я что-то смутно помню про статические члены и т.п. но С++ не настолько мне родной язык, чтобы такие тонкости различать :)

 

-------------------------------------------

 

видимо я понял "танцы с бубном" для прерываний BF - при сохранении контекста [--sp] = reti; разрешаются вложенные прерывания (GLBLDIS в IPEND очищается)

поэтому нужно замаскировать все прерывания выше 14

так?

 

вроде бы если изменить порядок регистров в контексте

[--sp] = r0;

r0=reti;

[--sp] = r0;

то прерывания разрешаться не будут

 

но с другой стороны - если работает существующий механизм, то лучше не трогать :)

 

------------------------------------

 

ну и еще :)

чего мне нехватает в сервисах scmRTOS - это секции на запрет шедулера, то есть, чтоб прерывания были разрешены (критическая секция нехорошо из-за увеличения латенси обработчика прерывания)

может это можно сделать какими-то простыми юзерскими средствами (без изменения кода scmRTOS)?

 

и наверно, "вращения приоритетов" тоже :)

дедлочится у меня код изредка... вроде стандартная конструкция - работало в VDSP и eCOS

пока не могу понять почему - решил вот отвлечься - пописать в форум

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


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

как правильнее вызывать Sleep из некоторой иерархии сишных функций внутри проекта?

TProc1::Exec() -> foo() -> boo() -> moo()

 

и внутри moo() я хочу передать управление

могу написать

TProc1::Sleep(10);

или

Proc1.Sleep(3);

Поскольку moo() может вызываться из любого процесса, вызывать в ней Proc1.Sleep(3) как-то некрасиво, хотя работать скорее всего будет. Посколько Sleep() - статическая функция-член, ее можно вызывать не указывая конкретный объект: OS::TBaseProcess::Sleep();

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


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

есть вопрос по С++ применительно к scmRTOS:

 

как правильнее вызывать Sleep из некоторой иерархии сишных функций внутри проекта?

TProc1::Exec() -> foo() -> boo() -> moo()

 

и внутри moo() я хочу передать управление

могу написать

TProc1::Sleep(10);

или

Proc1.Sleep(3);

 

как правильнее? я что-то смутно помню про статические члены и т.п. но С++ не настолько мне родной язык, чтобы такие тонкости различать :)

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

 

видимо я понял "танцы с бубном" для прерываний BF - при сохранении контекста [--sp] = reti; разрешаются вложенные прерывания (GLBLDIS в IPEND очищается)

поэтому нужно замаскировать все прерывания выше 14

так?

 

вроде бы если изменить порядок регистров в контексте

[--sp] = r0;

r0=reti;

[--sp] = r0;

то прерывания разрешаться не будут

 

но с другой стороны - если работает существующий механизм, то лучше не трогать :)

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

 

ну и еще :)

чего мне нехватает в сервисах scmRTOS - это секции на запрет шедулера, то есть, чтоб прерывания были разрешены (критическая секция нехорошо из-за увеличения латенси обработчика прерывания)

может это можно сделать какими-то простыми юзерскими средствами (без изменения кода scmRTOS)?

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

 

и наверно, "вращения приоритетов" тоже :)

дедлочится у меня код изредка... вроде стандартная конструкция - работало в VDSP и eCOS

С этим труднее - эта штука дается совсем небесплатно, тут придется заводить регистрацию сервисов и делать проход по ним каждый раз при инверсии приоритетов. Это будет длинный кусок кода в критической секции (что может не понравиться любителям быстрой реакции на прерывание) и дополнительные торомза и накладные расходы. Учитывая калибр обсуждаемой системы, может статься, что сама процедура инверсии приоритетов может оказаться толще и тяжелее, чем тот код, который надо пихнуть в высокоприроритетное выполнение.

 

Для достижения похожей функциональности можно применить один простой прием, я им пользуюсь (собираюсь написать типа апноты, как руки дойдут), правда, все больше для background задач. Идея простая и ее можно обозвать "делегирование выполнения кода": заводим процесс с низким (если background задачи) или высоким (если foreground) приоритетом. Заводим абстрактный класс типа:

 

class TJob
{
public:
    virtual void run() = 0;
};

 

от него заводим нужное количество конкретных классов-заданий:

 

class TJob1 : public TJob { ... } Job1;
class TJob2 : public TJob { ... } Job2;
class TJob3 : public TJob { ... } Job3;
...
class TJobN : public TJob { ... } JobN;

 

в каждом из которых виртуальная фукнция run выполняет нужный для данного задания код.

 

Далее, заводим очередь:

 

OS::channel<TJob*, M> Jobs;

 

где М - размер очереди, мне обычно хватает от 4 до 8. :)

 

Теперь в заведенном с нужным приоритетом процессе пишем такой код:

 

OS_PROCESS void TBackGroundProc::Exec()
{
    for(;;)
    {
        TJob *job;
        Jobs.pop(job);
        job->run();
    }
}

 

А в процессе, где надо "делегировать" выполнение, пишем:

 

    TJob *job = &Job1;  // или Job2/Job3.../JobN
    Jobs.push(job);

 

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

 

Конечно, этот прием не заменяет полностью инверсию приоритетов, но в ряде случаев вполне решает задачу - например, обращение к совместно используемому ресурсу, чтобы оно не вызвало тормозов в приоритетом процессе из-за того, что менее приоритетный процесс вытеснил еще менее приоритетный, захвативший ресурс, можно выполнить через описаный Job, делегировав работу в высокоприоритетный процесс - так гарантируется максимально возможная скорость обращения к ресурсу и освобождение процессорного времени сразу по завершении. Любые процессы (или обработчики прерывний) могут кидать в очередь задания - те будут выполняться по мере возможности (в фоне) или сразу (в приоритетном процессе).

 

Писанины, кстати, имхо, тоже немного. И все безопасно и автоматизировано - на этапе компиляции все ошибки будут выловлены. Ну, лично мне кажется такой прием достаточно красивым, в духе С++. :) Широко использую для запуска заданий в фоне.

 

P.S. Вспомнил, что именно этот подход реализован в примере, который идет с портом - про OS::channel. Реально работающий пример.

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


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

спасибо еще раз за детальный ответ :

 

по поводу предложений "чего не хватает" - ну я смайлики поставил, что дескать шучу, в соответствующей весовой категории scmRTOS очень хорошо выделяется, а ее утяжеление приведет к стиранию уникальных достоинств

 

теоретически (я не силен в практике писания OS) кажется что запрет шедулера может свестись к добавлению члена Kernel(?) shed_disabled :), который устанавливается при входе в секцию запрета шедулера, приводит к возврату из вызовов всех семафоров и т.п. в текущий процесс (например, проверять там, где сравнивается текущий процесс с зашедулированым), а по выходу из этой секции (в деструкторе) вызывается перепланировщик

вроде и при обработке прерывания этот подход должен сработать

 

про приоритеты и каналы - зря я, наверно, отверг каналы

тут как всегда с использованием более высокоуровнего механизма - теряется "контролируемость" низкого уровня - в этом конкретном случае передачи вызовов, мне кажется, что стеки труднее будет контролировать (а у меня памяти мало)

но попробую

 

---------------------------------------------------------------------------------

 

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

 

INLINE inline TStatusReg GetInterruptState( ) { return cli(); }

INLINE inline void SetInterruptState(TStatusReg sr) { sti(sr); }

 

INLINE inline void EnableInterrupts() { sti( 0xffe0 ); }

INLINE inline void DisableInterrupts() { }

 

INLINE inline void EnableContextSwitch() { sti( 0xc000 ); }

INLINE inline void DisableContextSwitch() { cli( ); }

 

------------------------------------------------------------------------------------

 

про вызов Sleep:

TProc1::Sleep(10); и Proc1.Sleep(3); работают (код вроде одинаковый получается)

но использовать базовый класс лучше

 

собственно ситуация стандартная - есть С библиотека foo() boo(), в которой в boo() стоит задержка либо полинг какого-то флага

вместо задержки вызывается функция extern C moo(), описанная внутри "ядра" (в main, где собирается и ОС)

вроде бы вполне удобный механизм управления проектом

 

-----------------------------------------------------------------------------------

 

 

также, что я еще добавил - cбор статистики :

TStackItem* OS::TKernel::ContextSwitchHook(TStackItem* sp)

{

ProcessTable[CurProcPriority]->StackPointer = sp;

sp = ProcessTable[schedProcPriority]->StackPointer;

 

#if scmRTOS_CONTEXTSHITCH_HOOK_ENABLE == 1

ContextSwitchUserHook(CurProcPriority,SchedProcPriority);

#endif

 

CurProcPriority = SchedProcPriority;

return sp;

}

 

//////

#define _GET_CYCLE_COUNT( _CURR_COUNT ) asm volatile \

("r2 = CYCLES; \n" \

"r1 = CYCLES2; \n" \

"[%0] = r2; \n" \

"[%0+4] = r1; \n" \

: : "p" (&(_CURR_COUNT)) \

: "r1", "r2" );

 

extern "C" void ContextSwitchUserHook(byte, byte);

 

struct statunit {

unsigned long long t;

unsigned long n;

};

 

 

statunit StatTable[scmRTOS_PROCESS_COUNT+1];

 

static unsigned long long sct;

 

void ContextSwitchUserHook(byte cur, byte next)

{

unsigned long long ct;

_GET_CYCLE_COUNT(ct)

StatTable[cur].n++;

StatTable[cur].t+=ct-sct;

sct=ct;

}

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


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

теоретически (я не силен в практике писания OS) кажется что запрет шедулера может свестись к добавлению члена Kernel(?) shed_disabled :), который устанавливается при входе в секцию запрета шедулера, приводит к возврату из вызовов всех семафоров и т.п. в текущий процесс (например, проверять там, где сравнивается текущий процесс с зашедулированым), а по выходу из этой секции (в деструкторе) вызывается перепланировщик

вроде и при обработке прерывания этот подход должен сработать

Хм, думаю, тут не все просто. Именно в случае запрета перепланировки. Заблокировать планировку несложно - это на самом деле и делается при вызове функций сервисов в прерываниях, но вот делать это на уровне процессов может привести к нарушению целостности работы программы. Ведь вызывая ту или иную функцию средств межпроцессного взаимодействия, мы предполагаем вполне определенное поведение. А оно тут будет совсем другим. Например, встаем на ожидание события (flag.Wait()), при этом процесс впадает в спячку и отдает управление ядру, вызывая планировщик, и обратно этот процесс получит управление (будет разбужен) только когда ожидаемый флаг будет просигнален (что соответствует тому, что событие произошло). Но если заблокировать планировщик, то управление сразу вернется в этот же процесс и дальнейший код будет "полагать", что ожидаемое событие произошло. В случае с сервисами OS::message и OS::channel последствия будет еще более тяжелыми. Вряд ли это то, что мы бы хотели.

 

Другое дело, если блокировать не планировщик, а вытеснение. Т.е чтобы быть уверенным, что данные процесс не будет вытеснен никаким другим на указанном участке. Это другое дело и это, очевидно, правильное и достижимое желание. Возможно, вы имели в виду именно это (мне почему-то так кажется). :)

 

про приоритеты и каналы - зря я, наверно, отверг каналы

Где вы их отвергли? :)

 

тут как всегда с использованием более высокоуровнего механизма - теряется "контролируемость" низкого уровня - в этом конкретном случае передачи вызовов, мне кажется, что стеки труднее будет контролировать (а у меня памяти мало)

но попробую

Каналы живут не в стеках, а глобально. Иначе я не представляю, как получить от них реальную пользу. :) Т.е. не нужно учитывать их размер при оценке размера стеков.

 

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

 

INLINE inline TStatusReg GetInterruptState( ) { return cli(); }

INLINE inline void SetInterruptState(TStatusReg sr) { sti(sr); }

 

INLINE inline void EnableInterrupts() { sti( 0xffe0 ); }

INLINE inline void DisableInterrupts() { }

 

INLINE inline void EnableContextSwitch() { sti( 0xc000 ); }

INLINE inline void DisableContextSwitch() { cli( ); }

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

 

собственно ситуация стандартная - есть С библиотека foo() boo(), в которой в boo() стоит задержка либо полинг какого-то флага

вместо задержки вызывается функция extern C moo(), описанная внутри "ядра" (в main, где собирается и ОС)

вроде бы вполне удобный механизм управления проектом

Тут не понял, что имеется в виду. Sleep() чем-то не устраивает?

 

 

также, что я еще добавил - cбор статистики :

TStackItem* OS::TKernel::ContextSwitchHook(TStackItem* sp)

{

ProcessTable[CurProcPriority]->StackPointer = sp;

}

...

Да, это хорошее предложение, мы уже как-то думали над этим - статистика и отладочный код, но до реализации пока не дошло. Конечно, полезно иметь такой код, равно как и код для оценки потребления стеков, это все в планах, правда, не в самых срочных. :) Тут надо продумать, как это реализовать так, чтобы это одинаково легко было во всех портах - тут ваш вариант вполне, вроде, на высоте - все логично, наверное, его имеет смысл взять за основу. Еще надо продумать, как эту статистику сливать для обозрения, хотя это уже частности. :) Спасибо за дельное предложение. :a14:

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


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

Каналы живут не в стеках, а глобально.

 

-----------------

 

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

 

с каналами поторопился - буду разбираться

 

про стеки - вызов метода из объекта переданного по каналу осуществляется на стеке принимающего процесса (вряд ли иначе). поэтому мне показалось, что труднее отследить расход стеков

 

--------------------

 

в BF я сливаю буфер по DMA UART-у

можно сливать через дебажный порт (называется BTC у аналога - есть соотв. библиотека)

 

ну или после останова посмотреть - тоже хлеб :)

 

про многоплатформенность - можно на приложение переложить :)

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


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

Обнаружил конкретную проблему:

 

для передачи управления из сишной библиотеки используется функция wait_irq,

ну и ожидается сообщение от обработчика прерывания

 

EX_INTERRUPT_HANDLER(SPI_ISR)

{

OS::TISRW ISR;

 

//stop SPI

*pSPI_CTL=0x400;

ssync();

//read RXBUF

spi_read=(char)*pSPI_RDBR;

spi_read.sendISR();

}

 

char is_waiting;

short err_cnt;

char wait_irq(void)

{

is_waiting=1;

if (!spi_read.wait(10))

err_cnt++;

is_waiting=0;

return spi_read;

}

 

в оригинале было так - пока не начал выяснять ошибку

char wait_irq(void)

{

spi_read.wait();

return spi_read;

}

 

-----------------------------------

 

вызывается wait_irq из процеса с высшим приоритетом pr0 (в данном случае третий)

 

при этом наблюдаю потерю передачи управления в этот процесс, то есть процесс подвисает в ожидании сообщения, при этом ни таймаут не срабатывает, да и из обработчика прерывания сообщение послано - spi_read NonEmpty=1 и ProcessMap=8

 

в OS::Kernel Timeout для соответствующего процесса =0

 

при этом is_waiting==1, err_cnt==0

 

то есть при 10^6 переключений - практически не происходит потери управления,

а в 10^7 происходит практически всегда

 

скорее всего - взаимодействие с другими асинхронными прерываниями - в системе еще 4 источника (пока)

 

-----------------------------------

 

я попытаюсь разобраться, но может быть подскажете чего-нибудь, куда можно посмотреть

 

по коду OS такого быть вроде бы не может, но пока не смог найти причину

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


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

EX_INTERRUPT_HANDLER(SPI_ISR)

{

OS::TISRW ISR;

 

//stop SPI

*pSPI_CTL=0x400;

ssync();

//read RXBUF

spi_read=(char)*pSPI_RDBR;

spi_read.sendISR();

}

 

Я понял, что spi_read - это OS::message. Как оно объявлено? И зачем приведение типов:

 

spi_read=(char)*pSPI_RDBR;

 

?

 

char is_waiting;

short err_cnt;

char wait_irq(void)

{

is_waiting=1;

if (!spi_read.wait(10))

err_cnt++;

is_waiting=0;

return spi_read;

}

 

Тоже не понял, как это объект spi_read возвращается как char - ведь это инстанс шаблона OS::message. И компилятор не ругается?

 

вызывается wait_irq из процеса с высшим приоритетом pr0 (в данном случае третий)

 

при этом наблюдаю потерю передачи управления в этот процесс, то есть процесс подвисает в ожидании сообщения, при этом ни таймаут не срабатывает, да и из обработчика прерывания сообщение послано - spi_read NonEmpty=1 и ProcessMap=8

 

в OS::Kernel Timeout для соответствующего процесса =0

 

при этом is_waiting==1, err_cnt==0

 

то есть при 10^6 переключений - практически не происходит потери управления,

а в 10^7 происходит практически всегда

 

скорее всего - взаимодействие с другими асинхронными прерываниями - в системе еще 4 источника (пока)

 

-----------------------------------

 

я попытаюсь разобраться, но может быть подскажете чего-нибудь, куда можно посмотреть

 

по коду OS такого быть вроде бы не может, но пока не смог найти причину

Хм, загадочно. Навскидку пока сказать ничего не могу за исключением тех непонятных моментов, которые описал выше. Если только spi_read инстанцирован с параметром char.

 

Попробуйте заблокировать все остальные источники прерываний, оставьте только это. Что получится? Т.е. надо как-то локализовать источник ошибки. Временно прикрыть все постороннее и поглядеть, что получается. Пока ничего другого в голову не приходит.

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


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

Я понял, что spi_read - это OS::message. Как оно объявлено? И зачем приведение типов:

 

spi_read=(char)*pSPI_RDBR;

 

?

Тоже не понял, как это объект spi_read возвращается как char - ведь это инстанс шаблона OS::message. И компилятор не ругается?

Хм, загадочно. Навскидку пока сказать ничего не могу за исключением тех непонятных моментов, которые описал выше. Если только spi_read инстанцирован с параметром char.

 

Попробуйте заблокировать все остальные источники прерываний, оставьте только это. Что получится? Т.е. надо как-то локализовать источник ошибки. Временно прикрыть все постороннее и поглядеть, что получается. Пока ничего другого в голову не приходит.

 

*pSPI_RDBR имеет тип short

а в темплэйте OS::message базовый тип <char>

OS::message<char> spi_read;

 

конструкция работала до тех пор пока не появились дополнительные прерывания

ну и вероятность сбоя зависит от интенсивности других источников (например, при активном обмене по UART - наступает быстрее)

 

сяду сейчас ассемблерный код разбирать - может ли там пролезть "левое" прерывание

непонятно, какой более конструктивный подход применить...

 

UPD:

еще при сборке в 4.5 VDSP всегда предупреждает (в 4.0 этого предупреждения нет)

"..\..\scmRTOS\BF533\OS_Target_cpp.cpp", line 61 (col. 5): cc1746: {D} warning:

Externally defined variable Kernel, possibly used in constructor

before it has been constructed

 

то есть важен порядок вызова конструкторов (?) - но так как это не влияет на работу - то я игнорирую

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


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

сяду сейчас ассемблерный код разбирать - может ли там пролезть "левое" прерывание

непонятно, какой более конструктивный подход применить...

А попробуйте взять OS_Services.h и OS_Services.cpp из этой ветки. Возможно это одно из проявлений правящегося там бага. Я надеюсь, что баг исправил, но может еще чего-то не заметил.

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


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

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

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

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

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

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

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

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

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

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