Krom 0 17 мая, 2011 Опубликовано 17 мая, 2011 · Жалоба Контроллер LPC1768. Задача: в определенный момент выйти из прерывания (UART) в требуемую точку, а уж оттуда потом продолжить выполнения с места, где возникло прерывание. Никаких ОС не используется. В контроллерах семейства 8051 это делалось элементарно: ; сохраняем регистр прерываний push IE ; запрещаем прерывания clr EA ; берем требуемый адрес mov DPTR,#PROCESS ; подсовываем в стек push DPH push DPL ; и выходим куда нужно reti А вот как сделать нечто подобное в Cortex M3? Как корректно передать управление нужному процессу из обработчика прерывания, да так, чтобы ничего не испортить,а затем уже из того процесса корректно вернуться в нужное место? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
scifi 1 17 мая, 2011 Опубликовано 17 мая, 2011 · Жалоба Контроллер LPC1768. Задача: в определенный момент выйти из прерывания (UART) в требуемую точку, а уж оттуда потом продолжить выполнения с места, где возникло прерывание. Никаких ОС не используется. Прошу прощения за нескромный вопрос: зачем? Просто есть сильное подозрение, что Ваша задача на самом деле решается без привлечения таких извращений. В контроллерах семейства 8051 это делалось элементарно: ; сохраняем регистр прерываний push IE ; запрещаем прерывания clr EA ; берем требуемый адрес mov DPTR,#PROCESS ; подсовываем в стек push DPH push DPL ; и выходим куда нужно reti А вот как сделать нечто подобное в Cortex M3? Точно так же. Подменяем адрес возврата. А ещё есть setjmp/longjmp. Перечитав условие задачи снова Задача: в определенный момент выйти из прерывания (UART) в требуемую точку, а уж оттуда потом продолжить выполнения с места, где возникло прерывание. появилась мысль: если "требуемая точка" - это функция, то решение задачи сводится к вызову функции из прерывания и возврату из прерывания сразу после вызова. Но, опять же, есть сильное подозрение, что задача решается более "традиционными" средствами. Дополнение: Ещё вариант - использовать ещё одно вспомогательное прерывание с более низким приоритетом, чем UART. Устанавливаем флаг вызова этого прерывания из обработчика UART и выходим из обработчика. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
kovigor 6 17 мая, 2011 Опубликовано 17 мая, 2011 (изменено) · Жалоба Как корректно передать управление нужному процессу из обработчика прерывания, да так, чтобы ничего не испортить,а затем уже из того процесса корректно вернуться в нужное место? В правильно спроектированном ПО необходимости в таких действиях обычно не возникает. Продумайте структуру вашего проекта еще раз ... Изменено 17 мая, 2011 пользователем kovigor Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 39 17 мая, 2011 Опубликовано 17 мая, 2011 · Жалоба Кусок кода, который используется и в прерывании, и в основном коде оформляете в виде функции. Озадачиваетесь вопросом что будет, если эта функция будет вызвана из прерывания во время её выполнения в основном коде. Ну и собственно всё. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
klen 1 17 мая, 2011 Опубликовано 17 мая, 2011 · Жалоба редизайн системы однозначно, и чем раньше тем меньше потом костылей будет. это конечно мое мнение но позволю напомнить что костыли плодятся по квадрату от времени. лучше не давать им начинать это делать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
paskal 1 17 мая, 2011 Опубликовано 17 мая, 2011 · Жалоба В правильно спроектированном ПО необходимости в таких действиях обычно не возникает. Продумайте структуру вашего проекта еще раз ... Зря вы так. Есть масса задач где прыжок по определенному адресу при обработке прерывания наиболее оптимальный вариант. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 69 17 мая, 2011 Опубликовано 17 мая, 2011 · Жалоба Зря вы так. Есть масса задач где прыжок по определенному адресу при обработке прерывания наиболее оптимальный вариант. Ну, хоть бы пример привели, а то так не интересно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
brag 0 17 мая, 2011 Опубликовано 17 мая, 2011 · Жалоба Сохранить адрес возврата (в регистре или в памяти,зависит от задачи), подменить адрес возврата в стеке, выйти. в вашей "точке" взять сохраненный ранее адрес возврата и BX на него. Костыль - не костыль, а иногда это довольно оптимально - все зависит от задачи... Но на кортексе есть PendSV и Systick. в моей оси Systick используется для обработки реквестов от прерываний - прерывание заносит в очередь реквест(всего 5 ldr/str инструкций и лок прерываний на 3 из них), и устанавливает PENDST. Systick выгребает очередь и выполняет в свободное время. без всяких локов. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 17 мая, 2011 Опубликовано 17 мая, 2011 · Жалоба Контроллер LPC1768. Задача: в определенный момент выйти из прерывания (UART) в требуемую точку, а уж оттуда потом продолжить выполнения с места, где возникло прерывание. Никаких ОС не используется. В контроллерах семейства 8051 это делалось элементарно: В контроллерах семейства 8051 это делалось для того, чтобы изобразить "вложенные прерывания". В кортексах вложенные прерывания есть изначально, и так извращаться не требуется. То есть, ваш вариант "в определенный момент выйти из прерывания (UART) в требуемую точку, а уж оттуда потом продолжить выполнения с места, где возникло прерывание" практически полностью эквивалентен варианту "в конце прерывания вызвать нужную функцию". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
paskal 1 17 мая, 2011 Опубликовано 17 мая, 2011 · Жалоба Ну, хоть бы пример привели, а то так не интересно. Могу и пример, но только с тем же 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: ; идем дальше Здесь немного другой случай, адресный переход идет не на обработку прерывания, а после возврата, но суть та же. А еще таким методом можно организовать многозадачность повесив на таймер такой обработчик, чтоб он запоминал адрес предыдущего вызова, а возвращал на адрес следующей, и так перебирал все задачи по кругу. В контроллерах семейства 8051 это делалось для того, чтобы изобразить "вложенные прерывания". В кортексах вложенные прерывания есть изначально, и так извращаться не требуется. То есть, ваш вариант "в определенный момент выйти из прерывания (UART) в требуемую точку, а уж оттуда потом продолжить выполнения с места, где возникло прерывание" практически полностью эквивалентен варианту "в конце прерывания вызвать нужную функцию". Вовсе нет. Во-первых в 51-х можно сделать вложенное прерывание. Во-вторых как я описал выше, вложенность тут ни при чем Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 17 мая, 2011 Опубликовано 17 мая, 2011 · Жалоба А вот по прерываниям простота заканчивается. По любому приему происходит переход на один и тот же адрес обработчика и дальше надо заводить кучу дополнительных флагов чтоб помнить текущую фазу протокола, и оборачивается это кучей запутанных ветвлений. Вот здесь положение спасает переход по определенному адресу. После обработки очередного байта, мы заносим в переменную адрес следующего обработчика и при следующем прерывании прыгаем сразу в эту точку. // Компиляторо-зависимые атрибуты/прагмы опускаем void (*real_handler)() = initial_handler; // void interrupt_handler() { real_handler(); // внутри всех обработчиков при необходимости перезаносится переменная real_handler } Что-то мне кажется, что от возникновения прерывания до начала работы реального обработчика это будет быстрее, чем занесение в стек дополнительного адреса возврата для «возврата» в некий процесс. Быстрее этого будет только перемещение таблицы векторов в ОЗУ и замена вектора в той таблице. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KnightIgor 2 17 мая, 2011 Опубликовано 17 мая, 2011 · Жалоба А вот по прерываниям простота заканчивается. По любому приему происходит переход на один и тот же адрес обработчика и дальше надо заводить кучу дополнительных флагов чтоб помнить текущую фазу протокола, и оборачивается это кучей запутанных ветвлений. Вот здесь положение спасает переход по определенному адресу. После обработки очередного байта, мы заносим в переменную адрес следующего обработчика и при следующем прерывании прыгаем сразу в эту точку. При таком методе программа получается намного проще, а реакция на обработку быстрее. Что Вы тут описали, это одна из возможных реализаций state machine - давно известная и наглядная штука для ветвлящихся алгоритмов. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
shnuric 0 17 мая, 2011 Опубликовано 17 мая, 2011 · Жалоба А кто вам мешает использовать указатель на функцию в прерывание. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 17 мая, 2011 Опубликовано 17 мая, 2011 · Жалоба Другой более простой случай. Надо дождаться на пине например 1, и тут же среагировать на это. Если в лоб ждать то будет так: WAIT: JNB P1.0,WAIT ; обработка события Уменя в таких местах было WAIT: JBC TOUT_BIT, process_timeout JNB P1.0,WAIT а в прерывании таймаута SETB TOUT_BIT Оно было одинаковое для всех мест ожидания с таймаутом, в том числе более сложных, чем просто ожидание уровня на ножке. Да, это удлиннение реакции, но не такое больше, как со счётчиком. Не думайте, что я не подменял адреса возврата, не очищал уровень прерываний для повторного входа и т.п. Но в подавляющем большинстве случаев это просто не нужно. Хотя понятно это становится только когда наигрался в хакера. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
scifi 1 17 мая, 2011 Опубликовано 17 мая, 2011 · Жалоба В дополнение к вышесказанному: "Преждевременная оптимизация - корень всех зол" (С) Дональд Кнут. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться