jcxz 166 29 марта, 2016 Опубликовано 29 марта, 2016 · Жалоба Вчера уткнулся ровно в ту же задачу. Кмк большинство отвечающих слишком привыкли к ртосам. Самому писать кусок с переключением контекстов при отсутсвии ртос - саму написать кусок ртос, непрактично. А что там непрактичного? Всё переключение контекста - пара десятков команд. Да и, если бы Вы внимательнее прочитали мой пост, как я писал - необязательно даже делать переключение контекста, достаточно задачу, обрабатывающую флаг, заключить в обработчик PendSV. Но с переключением контекста - правильнее, так как и стек для задачи будет свой и режим - непривилегированный. 1. Основной цикл перенести в SVC Вот это как раз непрактично. Или скорее даже невозможно. Насколько помню - у SVC приоритет выше чем у любого аппаратного прерывания (хотя может путаю), к тому же это - синхронное прерывание. Но самое главное - а что это Вам даст? Вы и WFI внутри SVC будете выполнять? А в чём тогда разница с фоновой задачей? А если Вы собираетесь возбуждать SVC внутри ISR аппаратного прерывания - это невозможно, ибо SVC - синхронное прерывание, это не PendSV, в ISR SVC будет вход сразу же, без ожидания выхода из ISR аппаратного прерывания, и последующие аппаратные прерывания будут заблокированы. Попытаетесь запретить - получите HardFault. 2. Пробуждающий обработчик прерываний меняет режим энергосбережения на слип и устанавливает таймер на ~20 тактов вперед. Даже если в это время сработает WFI, то произойдет быстрый выход из сна. Ничего не понял. Если он пробуждающий - почему тогда он sleep устанавливает??? Сами себе противоречите.... Не нравится PendSV по каким-то причинам, вместо него можно использовать программное возбуждение любого аппаратного прерывания с приоритетом ниже любого используемого в ПО аппаратного прерывания. Хотя это ничем не отличается от PendSV, которое как раз для таких целей и сделано. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Kabdim 0 29 марта, 2016 Опубликовано 29 марта, 2016 · Жалоба А что там непрактичного? Всё переключение контекста - пара десятков команд. Просто зачем? Если дошло до написания переключения контекста не проще ли взять готовую ртос? Вот только потом под это решение нужно переделывать всю остальную прошивку. Да и, если бы Вы внимательнее прочитали мой пост, как я писал - необязательно даже делать переключение контекста, достаточно задачу, обрабатывающую флаг, заключить в обработчик PendSV. Но с переключением контекста - правильнее, так как и стек для задачи будет свой и режим - непривилегированный. Тот пост был всё таки не ответом на ваш пост. :) Вот это как раз непрактично. Или скорее даже невозможно. Насколько помню - у SVC приоритет выше чем у любого аппаратного прерывания (хотя может путаю), к тому же это - синхронное прерывание. Но самое главное - а что это Вам даст? Вы и WFI внутри SVC будете выполнять? А в чём тогда разница с фоновой задачей? А если Вы собираетесь возбуждать SVC внутри ISR аппаратного прерывания - это невозможно, ибо SVC - синхронное прерывание, это не PendSV, в ISR SVC будет вход сразу же, без ожидания выхода из ISR аппаратного прерывания, и последующие аппаратные прерывания будут заблокированы. Попытаетесь запретить - получите HardFault. На моем камне приоритет - Configurable, но не суть важно. Это была мысль представленная на обсудить, а не конкретная реализация. Да, вы правы, PendSV уместей SVC для этой реализации этого решения. Ничего не понял. Если он пробуждающий - почему тогда он sleep устанавливает??? Сами себе противоречите.... Что б при если после выхода вывалились на команду WFI заснули не в какой-нибудь deep power down, а в более гуманный ко времени просыпа sleep. Впрочем решение не слишком удачное, с этим я не спорю. Не нравится PendSV по каким-то причинам, вместо него можно использовать программное возбуждение любого аппаратного прерывания с приоритетом ниже любого используемого в ПО аппаратного прерывания. Хотя это ничем не отличается от PendSV, которое как раз для таких целей и сделано. Нравится, нравится. :) Но решение с просыпанием с pend прерыванием нравится больше, чем возможность навелосипедить собственный кусочек ртос. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 166 29 марта, 2016 Опубликовано 29 марта, 2016 · Жалоба Нравится, нравится. :) Но решение с просыпанием с pend прерыванием нравится больше, чем возможность навелосипедить собственный кусочек ртос. Что там велосипедить? :rolleyes: OS_CPU_PendSVHandler: CPSID I ;Prevent interruption during context switch MRS R0, PSP ;PSP is process stack pointer LDR R1, =OSGlobalV CBZ R0, OS_CPU_PendSVHandler_pop ;Skip register save the first time STMFD R0!, {R4-R11} ;Save remaining regs r4-11 on process stack LDR R2, [R1, #OSTCBCur] ;OSTCBCur->OSTCBStkPtr = SP; STR R0, [R2] ;R0 is SP of process being switched out ;At this point, entire context of process has been saved OS_CPU_PendSVHandler_nosave: #if OS_CPU_HOOKS_EN > 0 && OS_TASK_SW_HOOK_EN > 0 PUSH {LR} ;Save LR exc_return value LDR R0, =OSTaskSwHook ;OSTaskSwHook(); BLX R0 POP {LR} LDR R1, =OSGlobalV #endif LDRB R0, [R1, #OSPrioHighRdy] ;OSPrioCur = OSPrioHighRdy; STRB R0, [R1, #OSPrioCur] LDR R0, [R1, #OSTCBHighRdy] ;OSTCBCur = OSTCBHighRdy; STR R0, [R1, #OSTCBCur] LDR R0, [R0] ;R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr; LDMFD R0!, {R4-R11} ;Restore r4-11 from new process stack MSR PSP, R0 ;Load PSP with new process SP ORR LR, LR, #0F4h ;;;#4 ;Ensure exception return uses process stack CPSIE I BX LR ;Exception return will restore remaining context OS_CPU_PendSVHandler_pop: ADDS SP, SP, #(8 * 4) B OS_CPU_PendSVHandler_nosave END Вот и всё. А если не нужно сохранять контекст FPU, то содержимое #if/#endif тоже можно опустить (если нужно - надо ещё добавить сохранение регистров FPU сюда). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AVI-crak 0 29 марта, 2016 Опубликовано 29 марта, 2016 · Жалоба Что там велосипедить? :rolleyes: Запрет прерываний CPSID I - это и есть большой глабля. Подобные грабли есть практически во всех мобильных ОС "реального времени". Но прикол в том что при запрете прерываний - перестаёт создаваться очередь этих самых прерываний согласно приоритетам, то-есть банально теряются прерывания. Шанс маленький, да и поймать его достаточно сложно - но сам факт накладывает ограничения на реальность. В идеале ос должна быть без запретов прерываний, а такой финт можно реализовать только через SVC. А если Вы собираетесь возбуждать SVC внутри ISR аппаратного прерывания - это невозможно, ибо SVC - синхронное прерывание, это не PendSV, в ISR SVC будет вход сразу же, без ожидания выхода из ISR аппаратного прерывания, и последующие аппаратные прерывания будут заблокированы. Попытаетесь запретить - получите HardFault. Без запретов прерываний - вызов SVC возможен из любого места, в любом режиме работы ядра. Живая очередь прерываний по приоритетам будет продолжать создаваться в фоне, без какого-либо лага. Собственно моя ос - http://forum.ixbt.com/topic.cgi?id=48:11735 репозиторий https://bitbucket.org/AVI-crak/rtos-cortex-m3-gcc/commits/ Тот самый кусок кода - который отправляет ядро в сон по условию единственной оставшийся в конвертере нулевой задачи, когда в нулевой нет задач на обработку. То-есть момент когда чип сделал всё что от него требуется, и ожидает внешнего события. sTask_nil_re: ldr r5, [r12, #12] // адрес задач на обработку памяти cbnz r5, sTask_nil_nw ldr r0, [r12] ldr r1, [r0] cmp r0, r1 // активная единственная нулевая ittt ne // то ждём физики movne r3, 0x10 svcne 0x0 // __switch 0x10 bne sTask_nil_re wfi b sTask_nil_re sTask_nil_nw: В линейном коде без ос - достаточно языка С. do { __WFI(); } while(флаг); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GetSmart 0 30 марта, 2016 Опубликовано 30 марта, 2016 · Жалоба Запрет прерываний CPSID I - это и есть большой глабля. Подобные грабли есть практически во всех мобильных ОС "реального времени". Но прикол в том что при запрете прерываний - перестаёт создаваться очередь этих самых прерываний согласно приоритетам, то-есть банально теряются прерывания. Шанс маленький, да и поймать его достаточно сложно - но сам факт накладывает ограничения на реальность. Что за источник это утверждает? Глобальный запрет прерываний флагом I регистра CPSR/PSR должен только запрещать их исполнение. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AVI-crak 0 30 марта, 2016 Опубликовано 30 марта, 2016 · Жалоба Что за источник это утверждает? Глобальный запрет прерываний флагом I регистра CPSR/PSR должен только запрещать их исполнение. Именно так. В дополнение - изначально Base priority mask register содержит 8 бит для определения приоритета, хотя в Cortex используется только 4 бита. При новом прерывании с более высоким уровнем внутри уже работающего - выставляется признак вложенного прерывания в Priority mask register. Это для управления возвратом из нового прерывания. При этом сравнение уровня прерывания происходит в момент его события. При запрете прерываний - и возникновении двух и более новых прерываний с разными уровнями - разрулить конечное состояние уже не получится. По этому запоминается первая регистрация нового прерывания, а всё остальное - игнорируется. В доках инфа на эту тему очень смутная. Проще проверить практически. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Alechek 0 30 марта, 2016 Опубликовано 30 марта, 2016 · Жалоба Дейсвтельно мутно. Как оно может ПОТЕРЯТСЯ? Особенно, если оно приходит от периферии и сбрасывается только после выполнения некоторых действий. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 166 30 марта, 2016 Опубликовано 30 марта, 2016 · Жалоба Но прикол в том что при запрете прерываний - перестаёт создаваться очередь этих самых прерываний согласно приоритетам, то-есть банально теряются прерывания. Шанс маленький, да и поймать его достаточно сложно - но сам факт накладывает ограничения на реальность. Бред! При запрете прерываний они не теряются, а копятся в регистре запросов ожидающих прерываний. Как только прерывания будут разрешены, будет выбрано одно из ожидающих прерываний с наивысшим приоритетом и перейдёт в стадию обслуживания. Любая периферия на МК Cortex_M выдаёт прерывания "по уровню", т.е. - держит запрос пока он не будет обслужен. И все эти страшилки про "грех запрета прерываний" - байки. Конечно запрет прерываний вносит задержку в обслуживание. Но система уже должна проектироваться с учётом этого и устойчивой к задержкам обработки прерываний, это особенности облуживания прерываний в любой системе на любом МК - всегда есть какая-то задержка, больше или меньше. В идеале ос должна быть без запретов прерываний, а такой финт можно реализовать только через SVC. SVC разработчиками ядра вообще не для этого задумывался. Соотвественно: такое использование его - неоптимально. Без запретов прерываний - вызов SVC возможен из любого места, в любом режиме работы ядра. Живая очередь прерываний по приоритетам будет продолжать создаваться в фоне, без какого-либо лага. Ну да - как же. Попробуйте вызвать SVC при запрещенных исключениях. Или изнутри ISR с более высоким приоритетом (точно не помню - можно ли перепрограммировать приоритет SVC, но кто-то выше утверждал что можно). Получите HardFault. Так как SVC - синхронное прерывание. А для задачи ТСа нужно асинхронное. Типа PendSV (или любого аппаратного, возбуждаемого программно через регистр запросов NVIC). В линейном коде без ос - достаточно языка С. do { __WFI(); } while(флаг); Вы даже не поняли исходного вопроса ТС и того, чего он боится. А именно - случаев ухода в сон при установленном флаге требования обработки, когда эта обработка делается в том же процессе, который вызывает WFI. Полностью устранить эту проблему, можно только вынеся обработку флага в отдельный ISR или процесс (также запускаемый по прерыванию). Именно так. В дополнение - изначально Base priority mask register содержит 8 бит для определения приоритета, хотя в Cortex используется только 4 бита. При новом прерывании с более высоким уровнем внутри уже работающего - выставляется признак вложенного прерывания в Priority mask register. Это для управления возвратом из нового прерывания. При этом сравнение уровня прерывания происходит в момент его события. При запрете прерываний - и возникновении двух и более новых прерываний с разными уровнями - разрулить конечное состояние уже не получится. По этому запоминается первая регистрация нового прерывания, а всё остальное - игнорируется. В доках инфа на эту тему очень смутная. Проще проверить практически. Регистр маски приоритетов очевидно используется для маскирования запросов с более низким приоритетом и влияет только на активацию нового прерывания, но никак не возврат. Для возврата используется регистр LR, который указывает из какого режима CPU был вход в ISR и по какому стеку осуществлять возврат. В доках всё описано кристалльно понятно. Прочитайте их! И про два и более прерываний - там всё есть. Опять-же - RTFM! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 30 марта, 2016 Опубликовано 30 марта, 2016 · Жалоба Не нашел, чтобы кто-то из участников данной дискуссии упомянул бит SLEEPONEXIT в SCR. Который для того и предназначен. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 166 30 марта, 2016 Опубликовано 30 марта, 2016 · Жалоба Не нашел, чтобы кто-то из участников данной дискуссии упомянул бит SLEEPONEXIT в SCR. Который для того и предназначен. Предназначен для чего? Для сна в фоновом процессе и работы только в ISR. Можно и его использовать вместо WFI в цикле, но разницы особой нет - мой вариант с обработкой флага внутри ISR PendSV будет работать и с этим битом и с простым циклом while (1) __WFI(); - разницы почти никакой, цикл просто заменится на просто while (1); Только ведь ТС хочет именно в фоновом процессе обслуживать свой флаг! а тогда этот бит не подходит. :( Ну не хочет он никак обслуживать свой флаг внутри ISR. Тут - хозяин - барин. :laughing: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AVI-crak 0 30 марта, 2016 Опубликовано 30 марта, 2016 · Жалоба Бред! При запрете прерываний они не теряются, а копятся в регистре запросов ожидающих прерываний. Как только прерывания будут разрешены, будет выбрано одно из ожидающих прерываний с наивысшим приоритетом и перейдёт в стадию обслуживания. Действительно бред, записать в один регистр сразу кучу прерываний. Вложенность прерываний организованна по подобию стека. Соответственно в один момент может быть доступно всего одно активное прерывание, при запрете оно и регистрируется. В момент регистрации определяется как будет осуществятся возврат из него. Для разных состояний ядра arm - это разные точки восстановления, их всего 4 штуки. Дык вот, в момент действующего прерывания - этот адрес поддержки ядра уже использован. По заложенному сценарию после снятия запрета - можно будет выполнить одно дополнительное вложенное прерывание. Потому-что невозможно прописать адрес возврата для прерывания которое ещё не исполнилось, но имеет иной уровень приоритета. Отсебятина в регистре возврата прерывания в режиме ос - типа 0xFFFFFFFD - это и есть указатель на этот регистр. Это значение lr пишется в стек при вложенном новом прерывании более высокого уровня. Всё пля, стек прерываний закрыт. Напомню - в ос вся система крутится на самом слабом прерывании. Это сделано для того чтобы всё содержимое стека прерываний было выгружено, и состоялся переход на стек потока. Время отведённое для определения приоритета прерывания, а так-же установки адреса для чтения вектора - равно одному такту. Там просто нет возможности сравнивать все 15 уровней. Аппаратная возможность сравнения приоритета работает только в одну сторону - между действующим прерыванием и новым/отложенным более низким. Сравнить отложенное более высокое с новым низким отложенным - просто невозможно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 166 30 марта, 2016 Опубликовано 30 марта, 2016 · Жалоба Действительно бред, записать в один регистр сразу кучу прерываний. В регистре находятся флаги запросов. Что в этом такого сверхъестественного? Каждый запрос - один бит. Что тут невозможного? А приоритеты для этих запросов - в другом регистре. Время отведённое для определения приоритета прерывания, а так-же установки адреса для чтения вектора - равно одному такту. Там просто нет возможности сравнивать все 15 уровней. Аппаратная возможность сравнения приоритета работает только в одну сторону - между действующим прерыванием и новым/отложенным более низким. Сравнить отложенное более высокое с новым низким отложенным - просто невозможно. Не понимаю - Вы чего доказать-то пытаетесь? Что аппаратно сравнить несколько уровней приоритета невозможно? Откройте любой учебник по цифровой электронике. Никаких проблем в этом нет, хоть за полтакта. Что процессор не сможет из двух ожидающих прерываний выбрать одно с наивысшим приоритетом и обслужить его первым, а затем - второе (если не пришло за это время более приоритетного)? Это противоречит здравому смыслу и докам на ядро, где это описывается. Если бы такое реально происходило, то после первого же запрета прерывания, во время которого успело прийти хотя-бы пару прерываний, происходила потеря прерываний и вообще нормальное функционирование было-бы невозможно. Миллионы устройств на Cortex-M работающих с кучей периферии с прерываниями и множественными запретами оных в коде - говорят об обратном. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ataradov 0 30 марта, 2016 Опубликовано 30 марта, 2016 · Жалоба Полностью устранить эту проблему, можно только вынеся обработку флага в отдельный ISR или процесс (также запускаемый по прерыванию). Полностью эту проблему устраняют 5 строчек кода на чистом Си приведенные выше. Все остальные - продолжайте переключать контексты, если сильно хочется, я этой фигней страдать не буду. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 166 30 марта, 2016 Опубликовано 30 марта, 2016 · Жалоба Все остальные - продолжайте переключать контексты, если сильно хочется, я этой фигней страдать не буду. Вы даже не прочитали, то что Вам советовали. Зачем тогда спрашивали? Просто чтобы "потрещать"? PS: И переключали и будет переключать, ибо не использовать ОС на ядрах класса Cortex имеет смысл только для очень простых задач, коих не имеем ;) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ataradov 0 30 марта, 2016 Опубликовано 30 марта, 2016 · Жалоба Вы даже не прочитали, то что Вам советовали. Прочитал. Зачем тогда спрашивали? Просто чтобы потрещать"? Чтобы получить разумный совет. Разумный совет как всегда нашелся на англоязычном форуме. К сожалению я успел задать вопрос тут. Это больше не повторится, а то опять придется выслушивать пиписькомеряние. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться