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

dsp4us

Участник
  • Постов

    5
  • Зарегистрирован

  • Посещение

Репутация

0 Обычный

Посетители профиля

784 просмотра профиля
  • AlexG

  1. Обработчик прерывания для перключения задач является обычной С-callable функцией только написанной на ассембли и вызывается той же самой командой в диспечере прерываний как и обработчики других прерываний. В моем варианте (когда переключатель задач работает на прерывании самого низкого приоритета ) наличие переменной ISR_NestCount вобщем то не нужно. ISR_NestCount предохраняет от того чтобы во вложенных прерываниях не поднималось прерывание переключателя каждый раз когда заканчивается очередная функция обработчика. Но на самом деле контроллер прерываний не имеет памяти и одно и тоже прерывание произошедшее несколько раз до момента начала его обработки (когда контроллер сделал это прерывание текущим) зарегестрируется только один раз а остатьные просто теряются. По крайней мере так работают все контроллеры прерываний которыя я встречал. А реально "регистрация" прерывания переключателя произойдет только когда произойдет разрешение (уберется маска) для самого низкого уровня приоритева, то есть в самом конце всех вложений.
  2. Поясню, вероятно я не ясно изложил. В ядре ARM9 как в прочем и в ARM7 нет штатного контроллера прерывания. Там по спецификации сделано до безобразия просто - как только линия прерывания (IRQ например) дергается ядро перескакивает на адрес (0x18) глобально (в самом ядре) запретив при этом (IRQ) прерывания. А дальше все зависит от конкретного изготовителя процессора, какой контроллер прерываний он подцепил. В моем случае это векторный с 3 уровнями приорететов - чем то похожий на Atmel-ий. Наиболее распространненый вариант следующего шага - программа переходит в обработчик прерываний высокого уровня - что то на подобие диспечера прерываний/обертки - (как вариант IRQHandler в прортах). Там уже вычисляется конкреный адресс конкретного прерывания и передается управление (IRQ_SWITCH макро). В scm портах для ARM на данный момент прерывание в этом диспечере не разрешается (MSR CPSR_c, #(NIRQ | MODE_ххх). Я написал свой IRQHandler где в определенный момент разрешаю глобально прерывания при этом уже контроллер маскирует тот уровень приоретета который в данный момент обрабатывается. Таким образом если произойдет прерывание с большим приорететом то он дернет линию IRQ и все повториться (вложение прирываний). Полностью согласен. В моем варианте ContextSwitcher_ISR первым же делом я запрещаю глобольно все прерывания. Проблема которую я описал выше как раз происходит с момента когда в общем диспечере прерываний разрешаются прерывания высого уровня (переключатель задач имеет самый низкий приоретет) и до момента когда уже в ContextSwitcher_ISR происходит этот запрет (от силы 10-20 ассемблерных комманд). Для Xtensa диспечер проверял в самом начале если это прерывание переключателя и далее ответвлялся если да. Если нет то продолжал как обычно - разрешал прерывания и т.д. По окончании обработки прерывания глобально запрещались, опять проверялось если прерывание для переключения ждет.... Короче все было довольно коряво. Но это по большей части из-за "уникальности" процессора Xtensa (чтоб они побыстрее обанкротились уже и не морочили людям головы). Таким образом для выполнение КАЖДОГО прерывания это повторялось. Для ARM все наоборот - очень компактно и нет лишних комманд. А это очень важно для высоко скоростных систем где каждый цикл на счету и кстати иметь вложенные прерывания очень важно так как это уменьшает джиттер в обработке. К сожалению у меня нет под рукой ни одной платы с обычными распространнеными ARM9/ARM7 (есть только с AT91CAP9) для того чтобы доработать порт в scmRTOS для вложенных прерываний. Если кому интересно могу запостить код диспечера и переключателя задач.
  3. Недвно мы натолкнулись на проблему которую хотелось бы обсудить и услышать мнения других о нашем пути ее решения. Короткая предистория. Я портировал scmRTOS на ARM926 у которого есть векторный контроллер прерываний с несколькими уровнями приорететов. Для переключения задач выбрал прерывание с самым низким приоритетом (полностью поддерживаю Сергея Б в его аргументации об этом) для того чтобы избежать излишних переключений задач. Все замечательно работало до тех пор пока мы не начали стресс тест, продувая через систему много и быстро. Мы заметели что иногда одна высоко приорететная задача "как бы" теряла сигнал и пропускала критичное по времени действие. Это икание случалось пару раз за час интенсивной работы. После ползания на пузе с микроскопом оказалось что происходит следующее: Эта высоко приорететная задача в какой то момент начинала уходить в ожидание этого сигнала и вызывала scheduler. Процесс уже в критической секции входил в функцию и далее в if(NextPrty != CurProcPriority) void TKernel::Sched() { byte NextPrty = GetHighPriority(ReadyProcessMap); if(NextPrty != CurProcPriority) { SchedProcPriority = NextPrty; RaiseContextSwitch(); do { EnableContextSwitch(); DUMMY_INSTR(); DisableContextSwitch(); } while(!IsContextSwitchDone()); } } EnableContextSwitch() в моем случае реализован как разрешение всех прерываний. В тот же момент происходило прерывание которое и посылало этот ожидаемый сигнал. Процессор уходил в обработчик прерываний где это высоко приоритетное прерывание вызывало перепланировщик тоже void OS::TKernel::SchedISR() { byte NextPrty = GetHighPriority(ReadyProcessMap); if(NextPrty != CurProcPriority) { SchedProcPriority = NextPrty; RaiseContextSwitch(); } } но поскольку CurProcPriority еще оставался прежним то в if(NextPrty != CurProcPriority) ничего не происходило. А завершив это прерывание процессор попадал в прерывание переключения задач (мы его подняли только что сами) и благополучно уходил как правило в спячку игнорируя факт что мы должы бы были остаться в текущей задаче. Проблему решили просто заменив CurProcPriority на SchedProcPriority и добавив начальную инициализацию void TKernel::Sched() { byte NextPrty = GetHighPriority(ReadyProcessMap); if(NextPrty != SchedProcPriority) { SchedProcPriority = NextPrty; RaiseContextSwitch(); do { EnableContextSwitch(); __nop(); DisableContextSwitch(); } while(!IsContextSwitchDone()); } } и void OS::TKernel::SchedISR() { byte NextPrty = GetHighPriority(ReadyProcessMap); if(NextPrty != SchedProcPriority) { SchedProcPriority = NextPrty; RaiseContextSwitch(); } } конечно в этом случае теряется смысл в названии SchedProcPriority но проблема решена. Прерывание переключающее задачи как и прежде исполняется но там переключения не происходит так как текущая и следующая задачи - это одно и то же. Я не знаю как в других процессорах эта ситуация обыгрывается? В предыдущем проекте где мы использовали Xtensa был специальный обработчик прерывания для переключателя задач где другие прерывания не разрешались и такого шанса не возникало. Это довольно редкое стечение обстоятельств и трудно уловимый ведь следующий сигнал обработается без проблем. Спасибо и удачи.
  4. <Black Pahan> - Спасибо за инфу, подождем ... <solosh> - Вы правы "Сохраняется признак глобального состояния прерываний (разрешены/запрещены или текущий приоритет если есть таковой) плюс состояние флагов CPU.". Но дело то в том что "признак" я называю его маской прерываний запоминается в критической секции в стеке "старого/уходящего" процесса а новый признак востанавливается из стека "нового/приходящего" процесса. То есть все изменения сделанные в этой маске прерываний становяться не видными как только мы переключили процессы. <sergeeff> - тут вопрос не в том что я хочу чего то - Критическая секция и сделана с этой целью чтобы отменить все прерывания и сохранить всю информацию о тех которые были разрешены до этого что бы можно было востановить их состояния. Критическая секция выполнена как объект в конструкторе которого все это "сохранение" и происходит а в деструкторе востанавливается. Но при переключении процесса деструктор то выполняется в контексте другого процесса. тоесть StatusReg будет другой! Вот в чем загвоздка! //----------------------------------------------------------------------------- // // The Critital Section Wrapper // // class TCritSect { public: TCritSect () : StatusReg(_xtos_ints_off(0xFFFFFFFF)) { } ~TCritSect() { _xtos_ints_on(StatusReg); } private: TStatusReg StatusReg; }; Удачи всем.
  5. Мы благополучно спортировали scmRTOS на Xtensa процессор и эта штука худо бедно работает. Сейчас мы усиленно занимаемся тестированием. Вот входе этого тестирования возникла ситуация которую не совсем понятно как решить. Переключение процессов осуществляется по программному прерыванию - естественно в критической секции где мы запоминаем маску разрешенных прерываний и отключаем их, в новом процесс - востанавливаем маску их стека этого нового процесса и т.д. Все замечательно. Но что происходит когда в контексте какого либо процесса какое либо прерывание глобально маскируется или наоборот разрешается - в этом случае в контексте другого процесса об этом никто не знает и все сбрасывается в первоначальное состояние?! Тоесть олучается при нашей реализации мы можем изменять прерывания только в контексте процессов а не глобально. Что не есть хорошо. Кто то может меня просвятить на зту тему - как в принцыпе в scmRTOS можно управлять прерываниями глобально и возможно ли это в других портах на других процессорах? И еще небольшое замечание/просьба для тех кто поддерживает веб сайт scmRTOS - сайт на английском но когда кликаешь на линк документации вываливает описание на русском языке. Английская версия там тоже есть но нужно изголяться и шарить ручками. Я думаю это займет всго лишь 5 минут добавить/исправить линк в тексте - все мои коллеги кому я давал ссылки на эту ОС по русски не говорят. Спасибо.
×
×
  • Создать...