|
Выход из прерывания в требуемую точку |
|
|
3 страниц
1 2 3 >
|
 |
Ответов
(1 - 35)
|
May 17 2011, 14:04
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(Krom @ May 17 2011, 17:48)  Контроллер LPC1768. Задача: в определенный момент выйти из прерывания (UART) в требуемую точку, а уж оттуда потом продолжить выполнения с места, где возникло прерывание. Никаких ОС не используется. Прошу прощения за нескромный вопрос: зачем? Просто есть сильное подозрение, что Ваша задача на самом деле решается без привлечения таких извращений. Цитата(Krom @ May 17 2011, 17:48)  В контроллерах семейства 8051 это делалось элементарно: ; сохраняем регистр прерываний push IE ; запрещаем прерывания clr EA ; берем требуемый адрес mov DPTR,#PROCESS ; подсовываем в стек push DPH push DPL ; и выходим куда нужно reti А вот как сделать нечто подобное в Cortex M3? Точно так же. Подменяем адрес возврата. А ещё есть setjmp/longjmp. Перечитав условие задачи снова Цитата(Krom @ May 17 2011, 17:48)  Задача: в определенный момент выйти из прерывания (UART) в требуемую точку, а уж оттуда потом продолжить выполнения с места, где возникло прерывание. появилась мысль: если "требуемая точка" - это функция, то решение задачи сводится к вызову функции из прерывания и возврату из прерывания сразу после вызова. Но, опять же, есть сильное подозрение, что задача решается более "традиционными" средствами. Дополнение: Ещё вариант - использовать ещё одно вспомогательное прерывание с более низким приоритетом, чем UART. Устанавливаем флаг вызова этого прерывания из обработчика UART и выходим из обработчика.
|
|
|
|
|
May 17 2011, 16:04
|
Местный
  
Группа: Свой
Сообщений: 352
Регистрация: 29-10-06
Из: Тула
Пользователь №: 21 769

|
Цитата(kovigor @ May 17 2011, 19:18)  В правильно спроектированном ПО необходимости в таких действиях обычно не возникает. Продумайте структуру вашего проекта еще раз ... Зря вы так. Есть масса задач где прыжок по определенному адресу при обработке прерывания наиболее оптимальный вариант.
|
|
|
|
|
May 17 2011, 17:11
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(Krom @ May 17 2011, 19:48)  Контроллер LPC1768. Задача: в определенный момент выйти из прерывания (UART) в требуемую точку, а уж оттуда потом продолжить выполнения с места, где возникло прерывание. Никаких ОС не используется. В контроллерах семейства 8051 это делалось элементарно: В контроллерах семейства 8051 это делалось для того, чтобы изобразить "вложенные прерывания". В кортексах вложенные прерывания есть изначально, и так извращаться не требуется. То есть, ваш вариант "в определенный момент выйти из прерывания (UART) в требуемую точку, а уж оттуда потом продолжить выполнения с места, где возникло прерывание" практически полностью эквивалентен варианту "в конце прерывания вызвать нужную функцию".
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
May 17 2011, 18:15
|
Местный
  
Группа: Свой
Сообщений: 352
Регистрация: 29-10-06
Из: Тула
Пользователь №: 21 769

|
Цитата(aaarrr @ May 17 2011, 20:19)  Ну, хоть бы пример привели, а то так не интересно. Могу и пример, но только с тем же 51-м. Вот тот же UART. У нас есть сложный протокол по RS-485 где сидит много устройств. Протокол примерно такой. 1-й байт - номер устройства. Если номер наш, то обрабатываем дальше, иначе игнорируем всю посылку. 2-й байт номер протокола тут идут варианты. В зависимости от протокола мы либо принимаем, либо передаем, и количество байт разное. Но реакция должна быть мгновенной, т.е. обрабатывать мы должны на лету, это задано в ТЗ. Если всю эту хрень делать без прерываний по ожиданию приема/передачи, программа получается простой. Принимаем-сравниваем-переходим на нужную метку. Примерно так MOV A,SBUF M1: CJNE A,#1, M2 ;обработка протокола 1 JMP BEGIN M2: CJNE A,#2, M3 ;обработка протокола 2 JMP BEGIN
.... и.т.д. Но так нельзя - программа только и делает что висит-ждет очередной байт. А вот по прерываниям простота заканчивается. По любому приему происходит переход на один и тот же адрес обработчика и дальше надо заводить кучу дополнительных флагов чтоб помнить текущую фазу протокола, и оборачивается это кучей запутанных ветвлений. Вот здесь положение спасает переход по определенному адресу. После обработки очередного байта, мы заносим в переменную адрес следующего обработчика и при следующем прерывании прыгаем сразу в эту точку. При таком методе программа получается намного проще, а реакция на обработку быстрее. Поэтому лично я давно делаю обработку UARTа именно так. Другой более простой случай. Надо дождаться на пине например 1, и тут же среагировать на это. Если в лоб ждать то будет так: WAIT: JNB P1.0,WAIT ; обработка события
Но тогда цикл может висеть бесконечно долго, нужен выход по таймауту. Обычный метод - ввести в цикл счетчик, его инкрементировать, сравнивать и добавить дополнительный переход. Но цикл многократно удлинится, а с ним и время реакции. Выход - оставить цикл без счетчика, а ввести таймерное прерывание с возвратом на TIMEOUT: WAIT: JNB P1.0,WAIT ; обработка события TIMEOUT: ; идем дальше
Здесь немного другой случай, адресный переход идет не на обработку прерывания, а после возврата, но суть та же. А еще таким методом можно организовать многозадачность повесив на таймер такой обработчик, чтоб он запоминал адрес предыдущего вызова, а возвращал на адрес следующей, и так перебирал все задачи по кругу. Цитата(AHTOXA @ May 17 2011, 21:11)  В контроллерах семейства 8051 это делалось для того, чтобы изобразить "вложенные прерывания". В кортексах вложенные прерывания есть изначально, и так извращаться не требуется. То есть, ваш вариант "в определенный момент выйти из прерывания (UART) в требуемую точку, а уж оттуда потом продолжить выполнения с места, где возникло прерывание" практически полностью эквивалентен варианту "в конце прерывания вызвать нужную функцию". Вовсе нет. Во-первых в 51-х можно сделать вложенное прерывание. Во-вторых как я описал выше, вложенность тут ни при чем
|
|
|
|
|
May 17 2011, 18:51
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(paskal @ May 17 2011, 21:15)  А вот по прерываниям простота заканчивается. По любому приему происходит переход на один и тот же адрес обработчика и дальше надо заводить кучу дополнительных флагов чтоб помнить текущую фазу протокола, и оборачивается это кучей запутанных ветвлений. Вот здесь положение спасает переход по определенному адресу. После обработки очередного байта, мы заносим в переменную адрес следующего обработчика и при следующем прерывании прыгаем сразу в эту точку. Код // Компиляторо-зависимые атрибуты/прагмы опускаем void (*real_handler)() = initial_handler; // void interrupt_handler() { real_handler(); // внутри всех обработчиков при необходимости перезаносится переменная real_handler } Что-то мне кажется, что от возникновения прерывания до начала работы реального обработчика это будет быстрее, чем занесение в стек дополнительного адреса возврата для «возврата» в некий процесс. Быстрее этого будет только перемещение таблицы векторов в ОЗУ и замена вектора в той таблице.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
May 17 2011, 19:00
|
Участник

Группа: Участник
Сообщений: 19
Регистрация: 18-03-08
Пользователь №: 36 026

|
А кто вам мешает использовать указатель на функцию в прерывание.
|
|
|
|
|
May 17 2011, 19:05
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(paskal @ May 17 2011, 21:15)  Другой более простой случай. Надо дождаться на пине например 1, и тут же среагировать на это. Если в лоб ждать то будет так: WAIT: JNB P1.0,WAIT ; обработка события
Уменя в таких местах было Код WAIT: JBC TOUT_BIT, process_timeout JNB P1.0,WAIT а в прерывании таймаута SETB TOUT_BIT Оно было одинаковое для всех мест ожидания с таймаутом, в том числе более сложных, чем просто ожидание уровня на ножке. Да, это удлиннение реакции, но не такое больше, как со счётчиком. Не думайте, что я не подменял адреса возврата, не очищал уровень прерываний для повторного входа и т.п. Но в подавляющем большинстве случаев это просто не нужно. Хотя понятно это становится только когда наигрался в хакера.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
May 17 2011, 19:10
|

embarrassed systems engineer
    
Группа: Свой
Сообщений: 1 083
Регистрация: 24-10-05
Из: Осокорки
Пользователь №: 10 038

|
Цитата(aaarrr @ May 17 2011, 19:19)  Ну, хоть бы пример привели, а то так не интересно. У меня есть такой случай, при котором надо сбросить контекст прерывания и выйти в конкретную точку. АЦП работает обычно в режиме free-running, один из каналов следит за внешним питающим напряжением (часто там аккумулятор). Непрерывный анализ этого напряжения производится в прерывании. Можно было бы отдельную высокоприоритетную задачу завести, но жаль времени на постоянное переключение контекста и место под стек, к тому же там есть ряд нюансов с критическими секциями. И вот когда это напряжение становится ниже порога и нет критической секции, то надо выключить всех потребителей и перевести изделие в режим микропотребления. При этом RTOS уже не нужна - работает специальная процедура - вот тут то и потребовалось сделать возврат из прерывания в особую точку. Еще вариант - критическая ошибка в прерывании, когда надо выдать аналог BSOD - тут тоже желательно выйти (для некоторых архитектур) из режима прерывания. Ну а вообще, да - осознанный возврат "налево" при штатной работе (особенно если еще есть RTOS) то как бы "не камильфо". Нужно только в критических случаях, RTOS после этого уже не живет, а изделие в целом выходит в останов/спячку.
|
|
|
|
|
May 17 2011, 19:14
|
Местный
  
Группа: Свой
Сообщений: 352
Регистрация: 29-10-06
Из: Тула
Пользователь №: 21 769

|
Цитата(ReAl @ May 17 2011, 22:51)  Что-то мне кажется, что от возникновения прерывания до начала работы реального обработчика это будет быстрее, чем занесение в стек дополнительного адреса возврата для «возврата» в некий процесс. Напомню что пример был по обработке сложного протокола с большим количеством вариантов. Переход по адресу хоть и требует дополнительных действий, но происходит СРАЗУ в нужное место. А альтернатива этому методу - долго лазить по дереву state_machine с помощью флагов и ветвлений. Цитата(KnightIgor @ May 17 2011, 22:55)  Что Вы тут описали, это одна из возможных реализаций state machine - давно известная и наглядная штука для ветвлящихся алгоритмов. Конечно известная. Речь не о стэйтмашине вообще, а о том что реализовать ее можно либо адресами переходов, либо набором флагов и переменных состояния с последующими ветвлениями по этим флагам. И первый способ и нагляднее и быстрее.
|
|
|
|
|
May 17 2011, 20:04
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(paskal @ May 18 2011, 01:14)  Конечно известная. Речь не о стэйтмашине вообще, а о том что реализовать ее можно либо адресами переходов, либо набором флагов и переменных состояния с последующими ветвлениями по этим флагам. И первый способ и нагляднее и быстрее. Дело в том, что вызов функции - это тоже "переход по адресу":) И вместо "адреса перехода" вы можете хранить в переменной "адрес функции", соответствующей текущему состоянию. О чём вам и написал ReAl. Разница же между "вызовом функции"(он же "переход по адресу") и "подменой адреса возврата из прерывания", о которой спрашивал топикстартер, заключается в том, что во втором случае перед переходом по адресу происходит окончание прерывания. Вопрос в том, нужно ли это топикстартеру, и что ему это даст. В 8051 это давало разрешение прерываний (о чём написал я). А в кортексах - не даёт ничего. (Вернее, кое что конечно меняется, но не так радикально).
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
May 17 2011, 21:09
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(Krom @ May 17 2011, 16:48)  ; сохраняем регистр прерываний push IE ; запрещаем прерывания clr EA ; берем требуемый адрес mov DPTR,#PROCESS ; подсовываем в стек push DPH push DPL ; и выходим куда нужно reti Кстати, если уж на то пошло, именно в таком варианте (с одной конкретной «подпрограммой завершения», в стек заносится фиксированный адрес) на 51-ых это решалось короче: Код tf0_isr: _push <PSW, ACC, AR0> ... breq @@PROCESS; ну к примеру так решили, что надо проджолжать на низком приоритете _pop <AR0, ACC, PSW> @@reti: ; в очередной раз спасибо VslavX за утилтику «локальных меток» reti
@@PROCESS: acall @@reti ; а вот тут и начинается код того PROCESS -- тут уже уровень прерывания очищен ; выполнение продолжается на уровне приоритета основной программы ... ... _pop <AR0, ACC, PSW> ret Т.е. вместо занесения в DPTR константы и заталкивания её в стек (или через аккумулятор -- на байт длиннее, но не нужно DPTR трогать) -- одна команда acall. reti есть что там, что там. Помнить про пушнутое и попать его -- тоже. Цитата(VslavX @ May 17 2011, 22:10)  При этом RTOS уже не нужна - работает специальная процедура - вот тут то и потребовалось сделать возврат из прерывания в особую точку. Знакомо, хотя и с «суперциклом», а не с нормальной ОС. Один из тех исключительных случаев, когда это действительно нужно.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
May 18 2011, 05:15
|
Частый гость
 
Группа: Свой
Сообщений: 107
Регистрация: 27-06-05
Из: Россия
Пользователь №: 6 324

|
Цитата(aaarrr @ May 17 2011, 20:19)  Ну, хоть бы пример привели, а то так не интересно. Пример: прерывание UART принимает пакет определенного формата (скажем, команду устройству, которая должна выполняться в фоновом режиме), которая должна быть обработана. Команда может выполняться долго, и обрабатываеть ее прямо в прерывании скажем так - не комильфо.
|
|
|
|
|
May 18 2011, 05:26
|
Частый гость
 
Группа: Свой
Сообщений: 107
Регистрация: 27-06-05
Из: Россия
Пользователь №: 6 324

|
Цитата(AHTOXA @ May 17 2011, 21:11)  практически полностью эквивалентен варианту "в конце прерывания вызвать нужную функцию". В моем варианте это не подходит. Команды могут выполняться подолгу, до нескольких секунд, а прерывание UART должно жить и отвечать мастеру, что в случае выполнения обработки этой команды в прерывании невозможно.
|
|
|
|
|
May 18 2011, 05:47
|
Частый гость
 
Группа: Свой
Сообщений: 107
Регистрация: 27-06-05
Из: Россия
Пользователь №: 6 324

|
Цитата(scifi @ May 18 2011, 09:22)  Некрасиво обрабатывать команды в прерывании. Обычно в прерывании реализуют приёмный буфер, а разбор и обработку команды - в главном цикле (это если без ОС) или в отдельном потоке (с ОС). А фокусы с модификацией адреса возврата и прочее - это излишняя экзотика. ОСи нет, а главный цикл очень сложный, с вводами с клавиатуры и т.д., и когда дойдет очередь до обработки команды - хз. В 51х все работало на ура, и здесь будет  , просто нигде не могу найти детального описания - что происходит при передаче управления обработчику прерывания и при выходе из него. Например, в поисании указано, что при передаче управления обработчику прерывания в стек автоматически помещается 8 регистров: R0-R3,LR,PC,xPSR. Смотрю в листингах: При входе в обработчик SysTick: 64:M1504/lpc17xx_it.c **** void SysTick_Handler(void) 65:M1504/lpc17xx_it.c **** { 200 .loc 1 65 0 201 .cfi_startproc 202 @ args = 0, pretend = 0, frame = 0 203 @ frame_needed = 1, uses_anonymous_args = 0 204 @ link register save eliminated. 205 0000 80B4 push {r7} 206 .LCFI14: 207 .cfi_def_cfa_offset 4 208 .cfi_offset 7, -4 209 0002 00AF add r7, sp, #0При выходе: 248 .loc 1 74 0 249 0068 BD46 mov sp, r7 250 006a 80BC pop {r7} 251 006c 7047 bx lr 252 .cfi_endprocНигде нет обработки этих самых 8 регистров в стеке. Они отрабатываюся автомачически самим контроллером или? Мне бы мануал детальный найти...
|
|
|
|
|
May 18 2011, 06:17
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(Krom @ May 18 2011, 09:47)  а главный цикл очень сложный, с вводами с клавиатуры и т.д., и когда дойдет очередь до обработки команды - хз Вот это и есть корень проблемы. И костыли с подменой адреса возврата из прерывания не сильно помогут, IMHO. Цитата(Krom @ May 18 2011, 09:47)  В 51х все работало на ура, и здесь будет  А что же сподвигло уйти от 51-го? Cortex тем и хорош, что с ним не нужны все эти уловки, чтобы выжать последние соки из хилого процессора. Для Cortex можно программировать на нормальном Си, ведь это нормальный 32-разрядный процессор с приличной производительностью. Переносить на него грязные хаки из 51-го выглядит неприличным. Цитата(Krom @ May 18 2011, 09:47)  Мне бы мануал детальный найти... Гугл пробовали? cortex-m3 manual
|
|
|
|
|
May 18 2011, 06:50
|
Частый гость
 
Группа: Свой
Сообщений: 107
Регистрация: 27-06-05
Из: Россия
Пользователь №: 6 324

|
Цитата(scifi @ May 18 2011, 10:17)  И костыли с подменой адреса Ну так и сразу костыли... Программерский трюк это не костыль  . В любом боле-менее сносном программно-аппаратном комплексе защиты ПО таких "костылей" тьма-тьмущая, и без них вообще никак, так что-же? Цитата(scifi @ May 18 2011, 10:17)  А что же сподвигло уйти от 51-го? Ну я не это предлагал обсудить... Цитата(scifi @ May 18 2011, 10:17)  Переносить на него грязные хаки из 51-го выглядит неприличным. Грязные? Хаки? Чем они грязные и почему хаки? Цитата(scifi @ May 18 2011, 10:17)  Гугл пробовали? Пробовал. Хотелось бы найти хорошую диаграммку с детальным описанием, как в мануале Филипса для 51х контроллеров. А то что в гугле по Кортексам разобраться конечно можно, но проштудировав много-много разных мануалов. Просто вопрос времени. Ведь мог кто-то уже сталкиваться с подобной задачей и решить ее? Мог. Почему бы мне не спросить? Вроде для того и форум.
|
|
|
|
|
May 18 2011, 07:01
|
Участник

Группа: Участник
Сообщений: 19
Регистрация: 18-03-08
Пользователь №: 36 026

|
Переключаться на другую задачю всегда надо через PendSV_Handler, так как прерывания могут быть вложеные.
|
|
|
|
|
May 18 2011, 07:14
|
Частый гость
 
Группа: Свой
Сообщений: 107
Регистрация: 27-06-05
Из: Россия
Пользователь №: 6 324

|
Цитата(Александр_С @ May 18 2011, 11:01)  Переключаться на другую задачю всегда надо через PendSV_Handler, так как прерывания могут быть вложеные. Я за советом и обратился  Задача собственно в том и стоит, чтобы по определенному событию (получен пакет с командой) как-то переключится на обработчик этой команды (может, программное прерывание?), а уж потом из обработчика вернуться туда, откуда попали в прерывание. Вероятно, я не совсем точно сформулировал проблему, сорри...
|
|
|
|
|
May 18 2011, 07:15
|
Участник

Группа: Участник
Сообщений: 19
Регистрация: 18-03-08
Пользователь №: 36 026

|
//Формирование прерывания "PendSV_Handler" *(volatile unsigned *)0xE000ED04 = 0x10000000;
|
|
|
|
|
May 18 2011, 12:24
|
Профессионал
    
Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046

|
Цитата То есть, ваш вариант "в определенный момент выйти из прерывания (UART) в требуемую точку, а уж оттуда потом продолжить выполнения с места, где возникло прерывание" практически полностью эквивалентен варианту "в конце прерывания вызвать нужную функцию". да нет, выпав с прерывания в определенную точку то же самое прерывание может выполнится еще раз, вернувшись опять в ту точку и так рекурсивно  Скорее рекурсивный глюк выйдет  Хотя для кортексов это все не нужно, там есть svc,pendsv,systick, все с настраиваемыми приоритетами, все с tail-chaining, те все быстро и красиво,
|
|
|
|
|
May 20 2011, 11:59
|

Участник

Группа: Участник
Сообщений: 17
Регистрация: 3-04-09
Из: УССР
Пользователь №: 47 140

|
Правильно ли сделал запись по формированию и вызову программного прерывания? Keil (LPC2468) Код . . #define SoftwareInterrupt asm (" swi #1") . . void SWI_ISR(void) __attribute__ ((interrupt("SWI"))); main { SoftwareInterrupt; while(1); } . . .
void SWI_ISR(void) { бла-бла-бла }
--------------------
Многие вещи нам непонятны не потому, что наши понятия слабы, а лишь потому, что сии вещи не входят в круг наших понятий.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|