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

Собственно трудность заключается в медленном поднятии флага при вызове функции SignalISR().

Разместил флаги в секции "l2_var", функцию SignalISR() в секции "drivers_L1_code"

Но это не помогло решить проблему.

 

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

Если закомментировать строчку с вызовом - всё приходит в норму. Но только процесс ничего не знает о событии.

 

e7622750ec8c.jpg

 

 

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

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

 

b2eb685f3d77.jpg

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


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

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

 

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

 

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

 

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

 

Как-то так.. :rolleyes:

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


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

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

Всё бы хорошо... если блок данных всегда одинаковой длины.

Но используются изменяемые длины блоков, в зависимости от ситуации. Ведь нет смысла гнать 2048 байт если надо передать всего 2.

Проще ловить заголовок, где сидит команда к дальнейшим действиям, а потом уже что то делать. Верно?

Например поднять пин или в этом же пакете выгрузить данные из sdram или flash.

Про стратегию - там всё давно продумано.

Очень актуален вопрос: "как ускорить поднятие флага события". Ведь за это время можно поднять пару сотен обычных bool флагов...

 

-----------

пс: Вопрос к модераторам.

Почему уведомления не отсылаются о новых сообщениях?

За последние 2 года ни одного не приходило. :(

 

-

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


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

Очень актуален вопрос: "как ускорить поднятие флага события".

Речь идет о макросе VDK_ISR_SET_EVENTBIT_(..) или о чем-то другом?

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


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

Речь о scmRTOS функции: void OS::TEventFlag::SignalISR()

Функция определена в файле OS_SERVICES_H как INLINE inline void SignalISR();

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


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

Речь о scmRTOS функции: void OS::TEventFlag::SignalISR()

Функция определена в файле OS_SERVICES_H как INLINE inline void SignalISR();

А.. Ну это не ко мне.. это к dxp.. :rolleyes:

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


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

Собственно трудность заключается в медленном поднятии флага при вызове функции 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;
}

 

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

 

_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 гоняете?

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


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

Какая у вас тактовая частота? На какой скорости 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, хорошая методика.

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


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

Тоже сделал замеры при вызове макросов VDK на достаточно большом проекте:

 

VDK_ISR_POST_SEMAPHORE_() - 475 CYCLES,

 

VDK_ISR_SET_EVENTBIT_() - 540 CYCLES.

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


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

Всё равно - нет в жизни счастья.

Звенит тактовый сигнал с FT232, не пойму почему. Видно пролазит где то внутри в чипе. Появляются лишние переходы и данные "плывут". Блок 2048 байт не удаётся передать правильно на полной скорости. :(

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


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

Блок 2048 байт не удаётся передать правильно на полной скорости. :(

Я же говорю, у Вас сомнительная стратегия.. Даже если Вам удастся "передать правильно на полной скорости" весь блок, и если Вы собираетесь делать это на регулярной основе, все МИПС-ы Вашего процессора будут растрачены на обработку прерываний от SPI. На собсно полезную работу сил ему уже не хватит.. ИМХО.. ;)

Изменено пользователем blackfin

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


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

Нет необходимости вообще что либо делать, кроме как переливать из НАНД по SPI-USB в компьютер. Это отдельный режим, используемый крайне редко. Поэтому все мипсы могут быть пущены в расход. Главный критерий тут - скорость. Маленькими блоками по 256 байт нормально работает. Но проблема, что приходится чаще дёргать USB, а там как минимум 20мс пауза между передачами. Задержка на файле 1МВ получается очень существенная.

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


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

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

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

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

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

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

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

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

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

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