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

Вчера уткнулся ровно в ту же задачу. Кмк большинство отвечающих слишком привыкли к ртосам. Самому писать кусок с переключением контекстов при отсутсвии ртос - саму написать кусок ртос, непрактично.

А что там непрактичного? Всё переключение контекста - пара десятков команд.

Да и, если бы Вы внимательнее прочитали мой пост, как я писал - необязательно даже делать переключение контекста, достаточно задачу, обрабатывающую флаг, заключить в обработчик PendSV.

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

 

1. Основной цикл перенести в SVC

Вот это как раз непрактично. Или скорее даже невозможно. Насколько помню - у SVC приоритет выше чем у любого аппаратного прерывания (хотя может путаю), к тому же это - синхронное прерывание.

Но самое главное - а что это Вам даст? Вы и WFI внутри SVC будете выполнять? А в чём тогда разница с фоновой задачей?

А если Вы собираетесь возбуждать SVC внутри ISR аппаратного прерывания - это невозможно, ибо SVC - синхронное прерывание, это не PendSV, в ISR SVC будет вход сразу же, без ожидания выхода из ISR аппаратного прерывания, и последующие аппаратные прерывания будут заблокированы. Попытаетесь запретить - получите HardFault.

 

2. Пробуждающий обработчик прерываний меняет режим энергосбережения на слип и устанавливает таймер на ~20 тактов вперед. Даже если в это время сработает WFI, то произойдет быстрый выход из сна.

Ничего не понял. Если он пробуждающий - почему тогда он sleep устанавливает??? Сами себе противоречите....

 

Не нравится PendSV по каким-то причинам, вместо него можно использовать программное возбуждение любого аппаратного прерывания с приоритетом ниже любого используемого в ПО аппаратного прерывания. Хотя это ничем не отличается от PendSV, которое как раз для таких целей и сделано.

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


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

А что там непрактичного? Всё переключение контекста - пара десятков команд.

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

Да и, если бы Вы внимательнее прочитали мой пост, как я писал - необязательно даже делать переключение контекста, достаточно задачу, обрабатывающую флаг, заключить в обработчик PendSV.

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

Тот пост был всё таки не ответом на ваш пост. :)

Вот это как раз непрактично. Или скорее даже невозможно. Насколько помню - у SVC приоритет выше чем у любого аппаратного прерывания (хотя может путаю), к тому же это - синхронное прерывание.

Но самое главное - а что это Вам даст? Вы и WFI внутри SVC будете выполнять? А в чём тогда разница с фоновой задачей?

А если Вы собираетесь возбуждать SVC внутри ISR аппаратного прерывания - это невозможно, ибо SVC - синхронное прерывание, это не PendSV, в ISR SVC будет вход сразу же, без ожидания выхода из ISR аппаратного прерывания, и последующие аппаратные прерывания будут заблокированы. Попытаетесь запретить - получите HardFault.

На моем камне приоритет - Configurable, но не суть важно. Это была мысль представленная на обсудить, а не конкретная реализация. Да, вы правы, PendSV уместей SVC для этой реализации этого решения.

Ничего не понял. Если он пробуждающий - почему тогда он sleep устанавливает??? Сами себе противоречите....

Что б при если после выхода вывалились на команду WFI заснули не в какой-нибудь deep power down, а в более гуманный ко времени просыпа sleep. Впрочем решение не слишком удачное, с этим я не спорю.

Не нравится PendSV по каким-то причинам, вместо него можно использовать программное возбуждение любого аппаратного прерывания с приоритетом ниже любого используемого в ПО аппаратного прерывания. Хотя это ничем не отличается от PendSV, которое как раз для таких целей и сделано.

Нравится, нравится. :) Но решение с просыпанием с pend прерыванием нравится больше, чем возможность навелосипедить собственный кусочек ртос.

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


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

Нравится, нравится. :) Но решение с просыпанием с 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 сюда).

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


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

Что там велосипедить? :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(флаг);

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


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

Запрет прерываний CPSID I - это и есть большой глабля. Подобные грабли есть практически во всех мобильных ОС "реального времени". Но прикол в том что при запрете прерываний - перестаёт создаваться очередь этих самых прерываний согласно приоритетам, то-есть банально теряются прерывания. Шанс маленький, да и поймать его достаточно сложно - но сам факт накладывает ограничения на реальность.

Что за источник это утверждает? Глобальный запрет прерываний флагом I регистра CPSR/PSR должен только запрещать их исполнение.

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


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

Что за источник это утверждает? Глобальный запрет прерываний флагом I регистра CPSR/PSR должен только запрещать их исполнение.

Именно так.

В дополнение - изначально Base priority mask register содержит 8 бит для определения приоритета, хотя в Cortex используется только 4 бита. При новом прерывании с более высоким уровнем внутри уже работающего - выставляется признак вложенного прерывания в Priority mask register. Это для управления возвратом из нового прерывания. При этом сравнение уровня прерывания происходит в момент его события.

При запрете прерываний - и возникновении двух и более новых прерываний с разными уровнями - разрулить конечное состояние уже не получится.

По этому запоминается первая регистрация нового прерывания, а всё остальное - игнорируется.

В доках инфа на эту тему очень смутная. Проще проверить практически.

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


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

Дейсвтельно мутно. Как оно может ПОТЕРЯТСЯ?

Особенно, если оно приходит от периферии и сбрасывается только после выполнения некоторых действий.

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


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

Но прикол в том что при запрете прерываний - перестаёт создаваться очередь этих самых прерываний согласно приоритетам, то-есть банально теряются прерывания. Шанс маленький, да и поймать его достаточно сложно - но сам факт накладывает ограничения на реальность.

Бред!

При запрете прерываний они не теряются, а копятся в регистре запросов ожидающих прерываний. Как только прерывания будут разрешены, будет выбрано одно из ожидающих прерываний с наивысшим приоритетом и перейдёт в стадию обслуживания. Любая периферия на МК 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!

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


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

Не нашел, чтобы кто-то из участников данной дискуссии упомянул бит SLEEPONEXIT в SCR. Который для того и предназначен.

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


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

Не нашел, чтобы кто-то из участников данной дискуссии упомянул бит SLEEPONEXIT в SCR. Который для того и предназначен.

Предназначен для чего? Для сна в фоновом процессе и работы только в ISR. Можно и его использовать вместо WFI в цикле, но разницы особой нет - мой вариант с обработкой флага внутри ISR PendSV будет работать и с этим битом и с простым циклом while (1) __WFI(); - разницы почти никакой, цикл просто заменится на просто while (1);

Только ведь ТС хочет именно в фоновом процессе обслуживать свой флаг! а тогда этот бит не подходит. :(

Ну не хочет он никак обслуживать свой флаг внутри ISR. Тут - хозяин - барин. :laughing:

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


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

Бред!

При запрете прерываний они не теряются, а копятся в регистре запросов ожидающих прерываний. Как только прерывания будут разрешены, будет выбрано одно из ожидающих прерываний с наивысшим приоритетом и перейдёт в стадию обслуживания.

Действительно бред, записать в один регистр сразу кучу прерываний.

 

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

Для разных состояний ядра arm - это разные точки восстановления, их всего 4 штуки. Дык вот, в момент действующего прерывания - этот адрес поддержки ядра уже использован. По заложенному сценарию после снятия запрета - можно будет выполнить одно дополнительное вложенное прерывание. Потому-что невозможно прописать адрес возврата для прерывания которое ещё не исполнилось, но имеет иной уровень приоритета.

Отсебятина в регистре возврата прерывания в режиме ос - типа 0xFFFFFFFD - это и есть указатель на этот регистр. Это значение lr пишется в стек при вложенном новом прерывании более высокого уровня. Всё пля, стек прерываний закрыт. Напомню - в ос вся система крутится на самом слабом прерывании. Это сделано для того чтобы всё содержимое стека прерываний было выгружено, и состоялся переход на стек потока.

 

Время отведённое для определения приоритета прерывания, а так-же установки адреса для чтения вектора - равно одному такту. Там просто нет возможности сравнивать все 15 уровней. Аппаратная возможность сравнения приоритета работает только в одну сторону - между действующим прерыванием и новым/отложенным более низким. Сравнить отложенное более высокое с новым низким отложенным - просто невозможно.

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


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

Действительно бред, записать в один регистр сразу кучу прерываний.

В регистре находятся флаги запросов. Что в этом такого сверхъестественного? Каждый запрос - один бит. Что тут невозможного? А приоритеты для этих запросов - в другом регистре.

 

Время отведённое для определения приоритета прерывания, а так-же установки адреса для чтения вектора - равно одному такту. Там просто нет возможности сравнивать все 15 уровней. Аппаратная возможность сравнения приоритета работает только в одну сторону - между действующим прерыванием и новым/отложенным более низким. Сравнить отложенное более высокое с новым низким отложенным - просто невозможно.

Не понимаю - Вы чего доказать-то пытаетесь?

Что аппаратно сравнить несколько уровней приоритета невозможно? Откройте любой учебник по цифровой электронике. Никаких проблем в этом нет, хоть за полтакта.

Что процессор не сможет из двух ожидающих прерываний выбрать одно с наивысшим приоритетом и обслужить его первым, а затем - второе (если не пришло за это время более приоритетного)? Это противоречит здравому смыслу и докам на ядро, где это описывается. Если бы такое реально происходило, то после первого же запрета прерывания, во время которого успело прийти хотя-бы пару прерываний, происходила потеря прерываний и вообще нормальное функционирование было-бы невозможно. Миллионы устройств на Cortex-M работающих с кучей периферии с прерываниями и множественными запретами оных в коде - говорят об обратном.

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


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

Полностью устранить эту проблему, можно только вынеся обработку флага в отдельный ISR или процесс (также запускаемый по прерыванию).
Полностью эту проблему устраняют 5 строчек кода на чистом Си приведенные выше.

 

Все остальные - продолжайте переключать контексты, если сильно хочется, я этой фигней страдать не буду.

 

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


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

Все остальные - продолжайте переключать контексты, если сильно хочется, я этой фигней страдать не буду.

Вы даже не прочитали, то что Вам советовали. Зачем тогда спрашивали? Просто чтобы "потрещать"?

 

PS: И переключали и будет переключать, ибо не использовать ОС на ядрах класса Cortex имеет смысл только для очень простых задач, коих не имеем ;)

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


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

Вы даже не прочитали, то что Вам советовали.

 

Прочитал.

 

Зачем тогда спрашивали? Просто чтобы потрещать"?

Чтобы получить разумный совет. Разумный совет как всегда нашелся на англоязычном форуме. К сожалению я успел задать вопрос тут. Это больше не повторится, а то опять придется выслушивать пиписькомеряние.

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


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

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

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

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

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

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

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

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

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

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