|
Cortex и гонки при сне |
|
|
3 страниц
1 2 3 >
|
 |
Ответов
(1 - 36)
|
Mar 28 2016, 19:16
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(ataradov @ Mar 28 2016, 19:05)  while (1) цикл в основной программе. Флаг имеется в виду программный - переменная. Программу надо организовать таким образом, чтобы инструкция "спать" исполнялась условно только тогда, когда все необходимые действия уже исполнены. Предположим, что после сна в результате прерывания процессор проснулся и побежал исполнять инструкции после команды __WFI(). В прерывании, которое, по-видимому, и разбудило процессор, будут произведены некоторые короткие действия, после чего будет установлен флаг для синхронного цикла, завершить начатое. По крайней мере пока такой флаг установлен, исполнять инструкцию __WFI() нельзя. Когда же синхронный процесс всё сделает, флаг будет сброшен, и инструкция __WFI() будет исполнена. В более сложных системах, например с OS, можно послать некоторое сообщение всем участникам сабантуя на предмет готовности поспать. Если все ответили согласием, инструкция __WFI() исполняется. И т.д, и т.п.
|
|
|
|
|
Mar 28 2016, 19:23
|

Профессионал
    
Группа: Участник
Сообщений: 1 014
Регистрация: 8-01-07
Из: San Jose, CA
Пользователь №: 24 202

|
QUOTE (KnightIgor @ Mar 28 2016, 12:16)  Когда же синхронный процесс всё сделает, флаг будет сброшен, и инструкция __WFI() будет исполнена. И получили гонку. Так как внешнее прерывание от кнопки может произойти когда угодно. 1. Спим 2. Прерывание 3. Установили флаг 4. Работаем 5. Сбросили флаг 6. Готовимся ко сну 7. Спим Но теперь если произойдет 6a - Прерывание, то мы успешно установим флаг и уйдем в сон. Правильный способ: CODE if (flag == 0) { __disable_irq();
if (flag == 0) { // подготовка ко сну __WFI(); }
__enable_irq(); } Повторная проверка обязательная, иначе гонка все-равно будет.
Сообщение отредактировал ataradov - Mar 28 2016, 19:23
|
|
|
|
|
Mar 28 2016, 20:01
|
Частый гость
 
Группа: Участник
Сообщений: 182
Регистрация: 16-10-15
Пользователь №: 88 894

|
Цитата(ataradov @ Mar 29 2016, 00:12)  Что я пропустил? Как правильно обрабатывать такие ситуации? Само понятие сна - это ожидание прерывания без работы ядра мк. Допустим в коде без ос: прерывание связанное с точкой останова сбрасывает бинарный флаг, в точке сна в цикле проверяется флаг - профит, спим лишнее время. do { __WFI(); }while(флаг); сначала спим, а потом проверяем. В коде с ос всё немного сложнее. Тут простой запрет прерываний применять нельзя, их необходимо выключать по одному - в момент когда они полностью отработали. Иначе получится банальный сбой программы. Ведь прерывание по сути - это отложенное событие. После - все задачи должны быть переведены в зависимость от главного потока (вытолкнуть из диспетчера в ожидание). Ну а сам основной поток - просто обязан "переключаться диспетчером в холостом режиме", но теперь он будет всё время находится в бесконечном цикле проверки флага от важного внешнего прерывания ( его есно нужно оставить). Всё это происходит очень быстро, а паузы между активностью просто громадные. МК спит, хотя это и не 100% сон, получается где-то 99,99% от номинала.
Сообщение отредактировал AVI-crak - Mar 28 2016, 20:10
|
|
|
|
|
Mar 28 2016, 23:48
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(ataradov @ Mar 29 2016, 02:12)  Это все верно если ждем прерывания от внутренних источников, да и то не всегда. Вам тут уже ответили об общем принципе: WFI должна выполняться только тогда, когда выполнена вся запланированная работа и нет работы, которую надо выполнить. Т.е. (в случае наличия ОС) задача самого нижнего приоритета (фоновая) должна выполнять простой цикл с всего одной инструкцией: WFI (или WFE). Вся остальная работа - в ISR-ах или задачах ОС более высокого приоритета. Всё моё ПО именно так и построено, вне зависимости от того - надо экономить энергию или нет - выполнение WFI в фоновом процессе - это просто правило хорошего тона если хотите  Когда нужно установить Ваш флаг, ставите его (хоть в ISR, хоть в любой задаче) и какой-то объект синхронизации ОС (мэйлбокс например) переводите в состояние "готов'. Далее - у Вас есть задача, ожидающая этот мэйлбокс. Как только мэйлбокс перешёл в сост. "готов" и нет более приоритетных задач, задача получает управление и обрабатывает его. Любая установка готовности любому объекту синхронизации ОС - это вызов диспетчера ОС, который просмотрит список задач и переведёт те из них, которые готовы к выполнению, в состояние "готова". Если окажется, что текущая задача ОС имеет приоритет ниже, чем новая готовая задача, то будет вызван переключатель контекста ОС. Вызов переключателя контекста ОС - это собственно программное возбуждение прерывания PendSV, имеющего самый низший приоритет из всех прерываний (ниже любого аппаратного IRQ). Соответственно в ISR PendSV управление войдёт: а) или сразу, если выполняется какая-то задача ОС (с более низким приоритетом, чем активизируемая); б) или после завершения всех текущих ISR, если выполняется любой ISR. Даже если Вы не используете ОС и у Вас всего одна полезная задача, всё равно лучше построить ПО по тому-же принципу: процедура установки Вашего флага, после его установки, возбуждает PendSV, которое переключит контекст с фоновой на полезную задачу (если уже не выполняется полезная), которая, сделав всю работу (и проверив в конце что флаг опять не установился), вызовет переключатель контекста на фоновую задачу. Таким образом - как только возникает прерывание, ISR которого ставит флаг, управление находится в ISR-ах до тех пор, пока управление не получит полезная задача и не обработает флаг. И WFI может выполниться только тогда, когда флаг сброшен. И никакие гонки в принципе невозможны. Цитата(ataradov @ Mar 29 2016, 01:23)  1. Спим 2. Прерывание 3. Установили флаг 4. Работаем 5. Сбросили флаг 6. Готовимся ко сну 7. Спим Но теперь если произойдет 6a - Прерывание, то мы успешно установим флаг и уйдем в сон. 6а - прерывание, установившее флаг и мэйлбокс (либо просто активировавшее PendSV если без ОС). 6б - сразу после завершения ISR вход в ISR PendSV (если без ОС); если с ОС - вход в PendSV только если выполнялась менее приоритетная задача, если более приоритетная - вход в PendSV после перехода её в сост. ожидания. В любом случае после прерывания 6а и до пункта 7, будет выполнено PendSV (сразу или не сразу), которое переключит контекст на задачу обрабатывающую флаг. И управление дойдёт до пункта 7 только когда флаг уже будет обработан. Запрет прерываний тут нигде не нужен. Хотя можно и запретить если сильно хочется - WFI вроде игнорит маску PRIMASK. Можете, если без ОС, собственно сам обработчик PendSV сделать полезной задачей, обрабатывающей Ваш флаг. Тогда вся полезная работа у Вас всегда будет выполняться только в ISR-ах, установка Вашего флага будет всегда вызывать установку запроса PendSV.
|
|
|
|
|
Mar 29 2016, 08:22
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Kabdim @ Mar 29 2016, 12:30)  Вчера уткнулся ровно в ту же задачу. Кмк большинство отвечающих слишком привыкли к ртосам. Самому писать кусок с переключением контекстов при отсутсвии ртос - саму написать кусок ртос, непрактично. А что там непрактичного? Всё переключение контекста - пара десятков команд. Да и, если бы Вы внимательнее прочитали мой пост, как я писал - необязательно даже делать переключение контекста, достаточно задачу, обрабатывающую флаг, заключить в обработчик PendSV. Но с переключением контекста - правильнее, так как и стек для задачи будет свой и режим - непривилегированный. Цитата(Kabdim @ Mar 29 2016, 12:30)  1. Основной цикл перенести в SVC Вот это как раз непрактично. Или скорее даже невозможно. Насколько помню - у SVC приоритет выше чем у любого аппаратного прерывания (хотя может путаю), к тому же это - синхронное прерывание. Но самое главное - а что это Вам даст? Вы и WFI внутри SVC будете выполнять? А в чём тогда разница с фоновой задачей? А если Вы собираетесь возбуждать SVC внутри ISR аппаратного прерывания - это невозможно, ибо SVC - синхронное прерывание, это не PendSV, в ISR SVC будет вход сразу же, без ожидания выхода из ISR аппаратного прерывания, и последующие аппаратные прерывания будут заблокированы. Попытаетесь запретить - получите HardFault. Цитата(Kabdim @ Mar 29 2016, 12:30)  2. Пробуждающий обработчик прерываний меняет режим энергосбережения на слип и устанавливает таймер на ~20 тактов вперед. Даже если в это время сработает WFI, то произойдет быстрый выход из сна. Ничего не понял. Если он пробуждающий - почему тогда он sleep устанавливает??? Сами себе противоречите.... Не нравится PendSV по каким-то причинам, вместо него можно использовать программное возбуждение любого аппаратного прерывания с приоритетом ниже любого используемого в ПО аппаратного прерывания. Хотя это ничем не отличается от PendSV, которое как раз для таких целей и сделано.
|
|
|
|
|
Mar 29 2016, 11:21
|
Знающий
   
Группа: Свой
Сообщений: 558
Регистрация: 26-11-14
Из: Зеленоград
Пользователь №: 83 842

|
Цитата(jcxz @ Mar 29 2016, 11:22)  А что там непрактичного? Всё переключение контекста - пара десятков команд. Просто зачем? Если дошло до написания переключения контекста не проще ли взять готовую ртос? Вот только потом под это решение нужно переделывать всю остальную прошивку. Цитата(jcxz @ Mar 29 2016, 11:22)  Да и, если бы Вы внимательнее прочитали мой пост, как я писал - необязательно даже делать переключение контекста, достаточно задачу, обрабатывающую флаг, заключить в обработчик PendSV. Но с переключением контекста - правильнее, так как и стек для задачи будет свой и режим - непривилегированный. Тот пост был всё таки не ответом на ваш пост.  Цитата(jcxz @ Mar 29 2016, 11:22)  Вот это как раз непрактично. Или скорее даже невозможно. Насколько помню - у SVC приоритет выше чем у любого аппаратного прерывания (хотя может путаю), к тому же это - синхронное прерывание. Но самое главное - а что это Вам даст? Вы и WFI внутри SVC будете выполнять? А в чём тогда разница с фоновой задачей? А если Вы собираетесь возбуждать SVC внутри ISR аппаратного прерывания - это невозможно, ибо SVC - синхронное прерывание, это не PendSV, в ISR SVC будет вход сразу же, без ожидания выхода из ISR аппаратного прерывания, и последующие аппаратные прерывания будут заблокированы. Попытаетесь запретить - получите HardFault. На моем камне приоритет - Configurable, но не суть важно. Это была мысль представленная на обсудить, а не конкретная реализация. Да, вы правы, PendSV уместей SVC для этой реализации этого решения. Цитата(jcxz @ Mar 29 2016, 11:22)  Ничего не понял. Если он пробуждающий - почему тогда он sleep устанавливает??? Сами себе противоречите.... Что б при если после выхода вывалились на команду WFI заснули не в какой-нибудь deep power down, а в более гуманный ко времени просыпа sleep. Впрочем решение не слишком удачное, с этим я не спорю. Цитата(jcxz @ Mar 29 2016, 11:22)  Не нравится PendSV по каким-то причинам, вместо него можно использовать программное возбуждение любого аппаратного прерывания с приоритетом ниже любого используемого в ПО аппаратного прерывания. Хотя это ничем не отличается от PendSV, которое как раз для таких целей и сделано. Нравится, нравится.  Но решение с просыпанием с pend прерыванием нравится больше, чем возможность навелосипедить собственный кусочек ртос.
|
|
|
|
|
Mar 29 2016, 12:13
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Kabdim @ Mar 29 2016, 17:21)  Нравится, нравится.  Но решение с просыпанием с pend прерыванием нравится больше, чем возможность навелосипедить собственный кусочек ртос. Что там велосипедить? CODE 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 сюда).
|
|
|
|
|
Mar 29 2016, 23:31
|
Частый гость
 
Группа: Участник
Сообщений: 182
Регистрация: 16-10-15
Пользователь №: 88 894

|
Цитата(jcxz @ Mar 29 2016, 19:13)  Что там велосипедить?  Запрет прерываний CPSID I - это и есть большой глабля. Подобные грабли есть практически во всех мобильных ОС "реального времени". Но прикол в том что при запрете прерываний - перестаёт создаваться очередь этих самых прерываний согласно приоритетам, то-есть банально теряются прерывания. Шанс маленький, да и поймать его достаточно сложно - но сам факт накладывает ограничения на реальность. В идеале ос должна быть без запретов прерываний, а такой финт можно реализовать только через SVC. Цитата(jcxz @ Mar 29 2016, 15:22)  А если Вы собираетесь возбуждать 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(флаг);
|
|
|
|
|
Mar 30 2016, 03:30
|
Частый гость
 
Группа: Участник
Сообщений: 182
Регистрация: 16-10-15
Пользователь №: 88 894

|
Цитата(GetSmart @ Mar 30 2016, 08:59)  Что за источник это утверждает? Глобальный запрет прерываний флагом I регистра CPSR/PSR должен только запрещать их исполнение. Именно так. В дополнение - изначально Base priority mask register содержит 8 бит для определения приоритета, хотя в Cortex используется только 4 бита. При новом прерывании с более высоким уровнем внутри уже работающего - выставляется признак вложенного прерывания в Priority mask register. Это для управления возвратом из нового прерывания. При этом сравнение уровня прерывания происходит в момент его события. При запрете прерываний - и возникновении двух и более новых прерываний с разными уровнями - разрулить конечное состояние уже не получится. По этому запоминается первая регистрация нового прерывания, а всё остальное - игнорируется. В доках инфа на эту тему очень смутная. Проще проверить практически.
|
|
|
|
|
Mar 30 2016, 05:32
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(AVI-crak @ Mar 30 2016, 05:31)  Но прикол в том что при запрете прерываний - перестаёт создаваться очередь этих самых прерываний согласно приоритетам, то-есть банально теряются прерывания. Шанс маленький, да и поймать его достаточно сложно - но сам факт накладывает ограничения на реальность. Бред!При запрете прерываний они не теряются, а копятся в регистре запросов ожидающих прерываний. Как только прерывания будут разрешены, будет выбрано одно из ожидающих прерываний с наивысшим приоритетом и перейдёт в стадию обслуживания. Любая периферия на МК Cortex_M выдаёт прерывания "по уровню", т.е. - держит запрос пока он не будет обслужен. И все эти страшилки про "грех запрета прерываний" - байки. Конечно запрет прерываний вносит задержку в обслуживание. Но система уже должна проектироваться с учётом этого и устойчивой к задержкам обработки прерываний, это особенности облуживания прерываний в любой системе на любом МК - всегда есть какая-то задержка, больше или меньше. Цитата(AVI-crak @ Mar 30 2016, 05:31)  В идеале ос должна быть без запретов прерываний, а такой финт можно реализовать только через SVC. SVC разработчиками ядра вообще не для этого задумывался. Соотвественно: такое использование его - неоптимально. Цитата(AVI-crak @ Mar 30 2016, 05:31)  Без запретов прерываний - вызов SVC возможен из любого места, в любом режиме работы ядра. Живая очередь прерываний по приоритетам будет продолжать создаваться в фоне, без какого-либо лага. Ну да - как же. Попробуйте вызвать SVC при запрещенных исключениях. Или изнутри ISR с более высоким приоритетом (точно не помню - можно ли перепрограммировать приоритет SVC, но кто-то выше утверждал что можно). Получите HardFault. Так как SVC - синхронное прерывание. А для задачи ТСа нужно асинхронное. Типа PendSV (или любого аппаратного, возбуждаемого программно через регистр запросов NVIC). Цитата(AVI-crak @ Mar 30 2016, 05:31)  В линейном коде без ос - достаточно языка С. do { __WFI(); } while(флаг); Вы даже не поняли исходного вопроса ТС и того, чего он боится. А именно - случаев ухода в сон при установленном флаге требования обработки, когда эта обработка делается в том же процессе, который вызывает WFI. Полностью устранить эту проблему, можно только вынеся обработку флага в отдельный ISR или процесс (также запускаемый по прерыванию). Цитата(AVI-crak @ Mar 30 2016, 09:30)  Именно так. В дополнение - изначально Base priority mask register содержит 8 бит для определения приоритета, хотя в Cortex используется только 4 бита. При новом прерывании с более высоким уровнем внутри уже работающего - выставляется признак вложенного прерывания в Priority mask register. Это для управления возвратом из нового прерывания. При этом сравнение уровня прерывания происходит в момент его события. При запрете прерываний - и возникновении двух и более новых прерываний с разными уровнями - разрулить конечное состояние уже не получится. По этому запоминается первая регистрация нового прерывания, а всё остальное - игнорируется. В доках инфа на эту тему очень смутная. Проще проверить практически. Регистр маски приоритетов очевидно используется для маскирования запросов с более низким приоритетом и влияет только на активацию нового прерывания, но никак не возврат. Для возврата используется регистр LR, который указывает из какого режима CPU был вход в ISR и по какому стеку осуществлять возврат. В доках всё описано кристалльно понятно. Прочитайте их! И про два и более прерываний - там всё есть. Опять-же - RTFM!
|
|
|
|
|
Mar 30 2016, 06:20
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(ViKo @ Mar 30 2016, 12:07)  Не нашел, чтобы кто-то из участников данной дискуссии упомянул бит SLEEPONEXIT в SCR. Который для того и предназначен. Предназначен для чего? Для сна в фоновом процессе и работы только в ISR. Можно и его использовать вместо WFI в цикле, но разницы особой нет - мой вариант с обработкой флага внутри ISR PendSV будет работать и с этим битом и с простым циклом while (1) __WFI(); - разницы почти никакой, цикл просто заменится на просто while (1);Только ведь ТС хочет именно в фоновом процессе обслуживать свой флаг! а тогда этот бит не подходит.  Ну не хочет он никак обслуживать свой флаг внутри ISR. Тут - хозяин - барин.
|
|
|
|
|
Mar 30 2016, 06:38
|
Частый гость
 
Группа: Участник
Сообщений: 182
Регистрация: 16-10-15
Пользователь №: 88 894

|
Цитата(jcxz @ Mar 30 2016, 12:32)  Бред! При запрете прерываний они не теряются, а копятся в регистре запросов ожидающих прерываний. Как только прерывания будут разрешены, будет выбрано одно из ожидающих прерываний с наивысшим приоритетом и перейдёт в стадию обслуживания. Действительно бред, записать в один регистр сразу кучу прерываний. Вложенность прерываний организованна по подобию стека. Соответственно в один момент может быть доступно всего одно активное прерывание, при запрете оно и регистрируется. В момент регистрации определяется как будет осуществятся возврат из него. Для разных состояний ядра arm - это разные точки восстановления, их всего 4 штуки. Дык вот, в момент действующего прерывания - этот адрес поддержки ядра уже использован. По заложенному сценарию после снятия запрета - можно будет выполнить одно дополнительное вложенное прерывание. Потому-что невозможно прописать адрес возврата для прерывания которое ещё не исполнилось, но имеет иной уровень приоритета. Отсебятина в регистре возврата прерывания в режиме ос - типа 0xFFFFFFFD - это и есть указатель на этот регистр. Это значение lr пишется в стек при вложенном новом прерывании более высокого уровня. Всё пля, стек прерываний закрыт. Напомню - в ос вся система крутится на самом слабом прерывании. Это сделано для того чтобы всё содержимое стека прерываний было выгружено, и состоялся переход на стек потока. Время отведённое для определения приоритета прерывания, а так-же установки адреса для чтения вектора - равно одному такту. Там просто нет возможности сравнивать все 15 уровней. Аппаратная возможность сравнения приоритета работает только в одну сторону - между действующим прерыванием и новым/отложенным более низким. Сравнить отложенное более высокое с новым низким отложенным - просто невозможно.
|
|
|
|
|
Mar 30 2016, 07:41
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(AVI-crak @ Mar 30 2016, 12:38)  Действительно бред, записать в один регистр сразу кучу прерываний. В регистре находятся флаги запросов. Что в этом такого сверхъестественного? Каждый запрос - один бит. Что тут невозможного? А приоритеты для этих запросов - в другом регистре. Цитата(AVI-crak @ Mar 30 2016, 12:38)  Время отведённое для определения приоритета прерывания, а так-же установки адреса для чтения вектора - равно одному такту. Там просто нет возможности сравнивать все 15 уровней. Аппаратная возможность сравнения приоритета работает только в одну сторону - между действующим прерыванием и новым/отложенным более низким. Сравнить отложенное более высокое с новым низким отложенным - просто невозможно. Не понимаю - Вы чего доказать-то пытаетесь? Что аппаратно сравнить несколько уровней приоритета невозможно? Откройте любой учебник по цифровой электронике. Никаких проблем в этом нет, хоть за полтакта. Что процессор не сможет из двух ожидающих прерываний выбрать одно с наивысшим приоритетом и обслужить его первым, а затем - второе (если не пришло за это время более приоритетного)? Это противоречит здравому смыслу и докам на ядро, где это описывается. Если бы такое реально происходило, то после первого же запрета прерывания, во время которого успело прийти хотя-бы пару прерываний, происходила потеря прерываний и вообще нормальное функционирование было-бы невозможно. Миллионы устройств на Cortex-M работающих с кучей периферии с прерываниями и множественными запретами оных в коде - говорят об обратном.
|
|
|
|
|
Mar 30 2016, 08:23
|

Профессионал
    
Группа: Участник
Сообщений: 1 014
Регистрация: 8-01-07
Из: San Jose, CA
Пользователь №: 24 202

|
QUOTE (jcxz @ Mar 30 2016, 01:19)  Вы даже не прочитали, то что Вам советовали. Прочитал. QUOTE (jcxz @ Mar 30 2016, 01:19)  Зачем тогда спрашивали? Просто чтобы потрещать"? Чтобы получить разумный совет. Разумный совет как всегда нашелся на англоязычном форуме. К сожалению я успел задать вопрос тут. Это больше не повторится, а то опять придется выслушивать пиписькомеряние.
|
|
|
|
|
Mar 30 2016, 13:02
|
Частый гость
 
Группа: Участник
Сообщений: 182
Регистрация: 16-10-15
Пользователь №: 88 894

|
Цитата(ataradov @ Mar 30 2016, 15:23)  Разумный совет как всегда нашелся на англоязычном форуме. А как оно выглядит-то? ваше англоязычное решение. Цитата(jcxz @ Mar 30 2016, 14:41)  Не понимаю - Вы чего доказать-то пытаетесь? Чистый новый проект, три прерывания от кнопок с разными уровнями 2, 3, 4. Жму 4, запрет прерываний и цикл, жму 2 ,3 , Выхожу из цикла, снимается запрет - попадаю в 2 ( нормально), Выхожу из цикла 2 - попадаю в 4 и майн. Без запрета прерываний - попасть в 3 можно. Наверное я что-то делаю не так, может у меня камень с дефектом, но команда __disable_irq(); - мне не нравится.
|
|
|
|
|
Mar 30 2016, 15:32
|

Профессионал
    
Группа: Участник
Сообщений: 1 014
Регистрация: 8-01-07
Из: San Jose, CA
Пользователь №: 24 202

|
QUOTE (AVI-crak @ Mar 30 2016, 06:02)  А как оно выглядит-то? ваше англоязычное решение. http://electronix.ru/forum/index.php?showt...t&p=1415165QUOTE (AVI-crak @ Mar 30 2016, 06:02)  Чистый новый проект, три прерывания от кнопок с разными уровнями 2, 3, 4. Жму 4, запрет прерываний и цикл, жму 2 ,3 , Выхожу из цикла, снимается запрет - попадаю в 2 ( нормально), Выхожу из цикла 2 - попадаю в 4 и майн. Не поянл. QUOTE (AVI-crak @ Mar 30 2016, 06:02)  Без запрета прерываний - попасть в 3 можно. Наверное я что-то делаю не так, может у меня камень с дефектом, но команда __disable_irq(); - мне не нравится. Ну если не нравятся отдельные инструкции процессора, то это не ко мне. Выполнять все в прерывании не получится, так как обработка флага - это отправка кадра через радио, процесс, который может занять от нескольких мс до нескольких секунд. Перед сном радио усыпляется и перед отправкой кадра его тоже нужно разбудить. Это тоже решается элементарно кодом выше.
|
|
|
|
|
Mar 31 2016, 06:21
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(ataradov @ Mar 31 2016, 12:01)  Ну не могу я весь этот код засунуть в прерывание - это огромный беспроводный стек, который сам использует другие прерывания для работы. Я имею в виду не то прерывание, которое случается по аппаратному событию и по которому ставится флаг, а отдельное, возбуждаемое программно, из любого прерывания ставящего флаг и имеющее приоритет заведомо ниже любого аппаратного. И фоновый процесс, в котором очевидно работает Ваш огромный стек в виде суперцикла, как раз и должен выполняться внутри этого программного прерывания. Любое аппаратное прерывание прервёт это программное прерывание (для него это будет как фоновый процесс, только на стеке прерываний). Выход из этого программного прерывания - когда работа вся сделана и флаг не установлен заново - выход из ISR. Если между проверкой флага и выходом из ISR произойдёт новое аппаратное прерывание, устанавливающее флаг, но будет новый вход в ISR программного прерывания - так что потери события установки флага не будет даже если не запрещать прерывания. И даже фоновый процесс, крутящий WFI в цикле, можно не прописывать - можно воспользоваться флагом описанным Viko (всегда спать в фоне). Хотя можно конечно и как Вы писали - уходить в сон при запрещённых прерываниях в фоновом процессе и крутить весь суперцикл в нём-же. Судя по докам, Cortex-M должен прерывать состояние сна по любому незамаскированному прерыванию вне зависимости от состояния флага разрешения прерываний. Мне мой вариант кажется удобнее, так как позволяет в фоновый процесс крутящий WFI, более просто добавить какой-то дополнительный функционал, например - периодическое измерение загрузки процессора (периодически, вместо цикла while (1) WFI;, в течение фикс. времени выполнять цикл икрементирования некоего счётчика). Я именно так всегда и строю ПО, пусть даже там всего одна задача: знать насколько занят CPU - очень полезная вещь. Но дело Ваше.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|