Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: SignalISR() в Blackfin
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > scmRTOS
sevstels
Собственно трудность заключается в медленном поднятии флага при вызове функции SignalISR().
Разместил флаги в секции "l2_var", функцию SignalISR() в секции "drivers_L1_code"
Но это не помогло решить проблему.

Принимаются блок данных по SPI, после корректного приёма заголовка должен устанвливаться флаг события. Если в коде обработчика прерывания от SPI по совпадению условий вызывается SignalISR() - то такое прерывание затягивается дольше чем принимается байт данных, в итоге весь блок портится, т к следующий байт повреждён. На фотографии красный луч показывает длительность нахождения в прерывании. Самый широкий импульс как раз и есть вызов функции SignalISR().
Если закомментировать строчку с вызовом - всё приходит в норму. Но только процесс ничего не знает о событии.




На фотографии ниже показана длительнось обработки SPI прерывания без подьёма флагов, примерно 400ns.
Вопрос - как победить неувязку? Пока не удаётся разогнать SPI даже до приемлимого уровня...

blackfin
Вы или неверно изложили суть проблемы, или выбрали неверную стратегию обработки данных SPI.

Т.е., если "принимается блок данных по SPI", то логично обрабатывать прерывание от канала DMA привязанного к SPI. В этом случае прерывание не может "в итоге испортить весь блок данных", т.к. весь блок данных уже принят и уже сохранен в памяти.

Если "такое прерывание" от канала DMA с вызовом функции SignalISR() "затягивается дольше чем принимается байт данных" следующего блока данных, то необходимо просто настроить канал DMA на работу с двумя буферами в памяти с использованием списка или массива дескрипторов. В этом случае, пока Ваше прерывание от первого блока данных вызывает в обработчике функцию SignalISR(), канал DMA уже принимает данные от второго блока и сохраняет эти данные во втором буфере в памяти.

Если же Вы вызываете прерывание после каждого принятого по SPI слова, то кроме уменьшения времени обработки в функции SignalISR(), других вариантов вроде как и нет.. Но это не путь Джедая..

Как-то так.. rolleyes.gif
sevstels
Цитата
весь блок данных уже принят и уже сохранен в памяти

Всё бы хорошо... если блок данных всегда одинаковой длины.
Но используются изменяемые длины блоков, в зависимости от ситуации. Ведь нет смысла гнать 2048 байт если надо передать всего 2.
Проще ловить заголовок, где сидит команда к дальнейшим действиям, а потом уже что то делать. Верно?
Например поднять пин или в этом же пакете выгрузить данные из sdram или flash.
Про стратегию - там всё давно продумано.
Очень актуален вопрос: "как ускорить поднятие флага события". Ведь за это время можно поднять пару сотен обычных bool флагов...

-----------
пс: Вопрос к модераторам.
Почему уведомления не отсылаются о новых сообщениях?
За последние 2 года ни одного не приходило. sad.gif

-
blackfin
Цитата(sevstels @ Feb 22 2010, 08:32) *
Очень актуален вопрос: "как ускорить поднятие флага события".

Речь идет о макросе VDK_ISR_SET_EVENTBIT_(..) или о чем-то другом?
sevstels
Речь о scmRTOS функции: void OS::TEventFlag::SignalISR()
Функция определена в файле OS_SERVICES_H как INLINE inline void SignalISR();
blackfin
Цитата(sevstels @ Feb 22 2010, 08:45) *
Речь о scmRTOS функции: void OS::TEventFlag::SignalISR()
Функция определена в файле OS_SERVICES_H как INLINE inline void SignalISR();

А.. Ну это не ко мне.. это к dxp.. rolleyes.gif
sevstels
Видимо вопрос к разработчикам scmRTOS, т к в такие тонкости мало кто вникает...
dxp
Цитата(sevstels @ Feb 22 2010, 10:19) *
Собственно трудность заключается в медленном поднятии флага при вызове функции SignalISR().
Разместил флаги в секции "l2_var", функцию SignalISR() в секции "drivers_L1_code"
Но это не помогло решить проблему.

Странное поведение. Функция-то очень простая:

Код
void OS::TEventFlag::SignalISR()
{
    TCritSect cs;
    if(ProcessMap)                                          // if any process waits for event
    {
        TProcessMap Timeouted = Kernel.ReadyProcessMap;     // Process has its tag set in ReadyProcessMap if timeout
                                                            // expired, or it was waked up by OS::ForceWakeUpProcess()
        if( ProcessMap & ~Timeouted )                       // if any process has to be waked up
        {
            SetPrioTag(Kernel.ReadyProcessMap, ProcessMap); // place all waiting processes to the ready map
            ClrPrioTag(ProcessMap, ~Timeouted);             // remove all non-timeouted processes from the waiting map.
            return;
        }
    }
    Value = efOn;
}


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

CODE

_SignalISR__Q2_2OS10TEventFlagFv:
.LN_SignalISR__Q2_2OS10TEventFlagFv:
.LN12:
unsigned int __rval = __builtin_cli(); // line "D:\CAD\AD\VisualDSP5.0\Blackfin\include\builtins.h":1762
P1 = R0;
.LN13:
{ // line "scmRTOS\Common\OS_Services.h":237
LINK 0;
.LN14:
unsigned int __rval = __builtin_cli(); // line "D:\CAD\AD\VisualDSP5.0\Blackfin\include\builtins.h":1762
.MESSAGE/SUPPRESS 5515;
CLI R1;
I0 = R0;
.LN15:
TCritSect () : StatusReg(cli()) { } // line "scmRTOS\Blackfin\OS_Target.h":109
W[SP + 8] = R1;
.LN16:
if(ProcessMap) // if any process waits for event // line "scmRTOS\Common\OS_Services.h":239
R0 = W[P1] (Z);
CC = R0 == 0;
if CC jump .P41L27 ;

.P41L1:
P0.L = _Kernel__2OS+2;
P0.H = _Kernel__2OS+2;
NOP; // Inserted 2 instrs to fix anomaly w05_00_0245_with_boundaries.
NOP;
.LN17:
TProcessMap Timeouted = Kernel.ReadyProcessMap; // Process has its tag set in ReadyProcessMap if timeout // line 241
R2 = W[P0] (Z);
.LN18:
if( ProcessMap & ~Timeouted ) // if any process has to be waked up // line 243
R1 = -1;
R1 = R2 ^ R1;
R0 = R0 & R1;
CC = R0 == 0;
if !CC jump .P41L13 ;

.P41L27:
.LN19:
Value = efOn; // line 250
R0 = 1;
[P1 + 4] = R0;
.LN20:
~TCritSect() { sti(StatusReg); } // line "scmRTOS\Blackfin\OS_Target.h":110
R0 = W[SP + 8] (Z);
.LN21:
__builtin_sti(__a); // line "D:\CAD\AD\VisualDSP5.0\Blackfin\include\builtins.h":1777
.MESSAGE/RESTORE 5515;
STI R0;

.P41L7:
.LN22:
return; // line "scmRTOS\Common\OS_Services.h":247
P0 = [FP + 4];
UNLINK;
// -- 2 stalls --
JUMP (P0);

.P41L13:
.LN23:
SetPrioTag(Kernel.ReadyProcessMap, ProcessMap); // place all waiting processes to the ready map // line 245
R0.L = W[I0];
.LN24:
INLINE inline void SetPrioTag(TProcessMap& pm, const TProcessMap PrioTag) { pm |= PrioTag; } // line "scmRTOS\Common\OS_Kernel.h":81
R1.L = W[P0];
.LN25:
R0 = R0 | R1;
.LN26:
W[P0] = R0.L;
.LN27:
INLINE inline void ClrPrioTag(TProcessMap& pm, const TProcessMap PrioTag) { pm &= ~PrioTag; } // line 82
R0.L = W[I0];
.LN28:
R0 = R2 & R0;
.LN29:
W[I0] = R0.L;
.LN30:
~TCritSect() { sti(StatusReg); } // line "scmRTOS\Blackfin\OS_Target.h":110
R0 = W[SP + 8] (Z);
.LN31:
__builtin_sti(__a); // line "D:\CAD\AD\VisualDSP5.0\Blackfin\include\builtins.h":1777
.MESSAGE/RESTORE 5515;
STI R0;
jump .P41L7;



Провел замеры на текущем проекте.

1. Время выполнения самой функции SignalISR.

Код
            ...
            START_CYCLE_COUNT(start_count);
            GIFH_complete.SignalISR();
            STOP_CYCLE_COUNT(stop_count, start_count);
            print("cycles: %d\r", stop_count);
            ...


получил значение 62 цикла. Значение это, думаю, не очень точное, т.к. на такой малой величине сильно влияют накладные расходы на эти макросы.

2. Время от начала SignalISR до Wait.

Код
// fpga.cpp

            ...
            START_CYCLE_COUNT(start_count);
            GIFH_complete.SignalISR();
            ...

// video.cpp

            ...
        GIFH_complete.Wait();
        STOP_CYCLE_COUNT(stop_count, start_count);
        print("cycles: %d\r", stop_count);
            ...


Полученное значение - 363 цикла, что при тактовой 200 МГц составляет порядка 1.8 мкс, что похоже на время из примера - порядка 1.5-1.6 мкс (там у меня еще часть кода выполняется, поэтому время чуть больше).

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

Какая у вас тактовая частота? На какой скорости SPI гоняете?
sevstels
Цитата
Какая у вас тактовая частота? На какой скорости SPI гоняете?


core speed = 600mHz
system speed =(600mHz/8) = 75mHz
скорость SPI видно по осциллограмме, период тактовой ~1.8 mks
Это эмуляция spi протокола через USB FT232R на скорости 921600, реальная байтовая скорость = /8/2

Попробую померить.
sevstels
Перенёс флаги в L1. Измерил.
Непосредственно сама функция SignalISR выполняется около 320ns.

Код
CLR_LED;
flag_SPI_HeaderAccepted.SignalISR();
SET_LED;


Теперь от начала вход и до выхода из прерывания около 1.2us в самом худшем случае.


Спасибо за подсказку dxp, хорошая методика.
blackfin
Тоже сделал замеры при вызове макросов VDK на достаточно большом проекте:

VDK_ISR_POST_SEMAPHORE_() - 475 CYCLES,

VDK_ISR_SET_EVENTBIT_() - 540 CYCLES.
sevstels
Всё равно - нет в жизни счастья.
Звенит тактовый сигнал с FT232, не пойму почему. Видно пролазит где то внутри в чипе. Появляются лишние переходы и данные "плывут". Блок 2048 байт не удаётся передать правильно на полной скорости. sad.gif
blackfin
Цитата(sevstels @ Feb 22 2010, 16:29) *
Блок 2048 байт не удаётся передать правильно на полной скорости. sad.gif

Я же говорю, у Вас сомнительная стратегия.. Даже если Вам удастся "передать правильно на полной скорости" весь блок, и если Вы собираетесь делать это на регулярной основе, все МИПС-ы Вашего процессора будут растрачены на обработку прерываний от SPI. На собсно полезную работу сил ему уже не хватит.. ИМХО.. wink.gif
sevstels
Нет необходимости вообще что либо делать, кроме как переливать из НАНД по SPI-USB в компьютер. Это отдельный режим, используемый крайне редко. Поэтому все мипсы могут быть пущены в расход. Главный критерий тут - скорость. Маленькими блоками по 256 байт нормально работает. Но проблема, что приходится чаще дёргать USB, а там как минимум 20мс пауза между передачами. Задержка на файле 1МВ получается очень существенная.
sevstels
дел
sevstels
В общем - победил, всё идеально "летает" на максимальном битрейте 2000000 и блоками 2048.
Между входом SPI sck DSP и выходом sck FT232 надо LPF ставить, где то с полосой 4-5мгц. Иначе вход "звенит". smile.gif Всем спасибо за помощь.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.