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

Самый быстрый выход из цикла, учитывая время его работы

Здравствуйте.

Имеется критичный по времени работы кусочек кода, который работает в цикле и ему лучше не мешать :)

Однако этот кусок кода должен поработать минут 15-20 и прекратить работать.

МК -- AVR.

 

Сейчас я сделал так:

cli();   
//запустили таймер1 с делителем 1024 без прерываний. Будем следить за битом переполнения
//сработка равна ~ 4 секунды на 16 МГц

            TCCR1A = 0; TCCR1B = 0; TIMSK1 = 0;
            TCCR1B |= (1 << CS12); TCCR1B |= (1 << CS10);   

			uint8_t TOV1_cnt = 255; ~ 4 секунды

        do {

			////////тут критичный по времени код. Написан на ассемблере
			//....
			////////
              
        	// выход из цикла примерно через 15-20 минут
            if ((TIFR1) & (1 << TOV1)) {                    //таймер1 с предделителем работает в фоне. Сработка каждые 4 секунды
                TIFR1 = 0x01;        					//сброс бита переполнения. Пишем туда 1 для сброса
                TOV1_cnt--;                
            }                              
        } while (TOV1_cnt > 0);
sei();


Т.е. запустили Таймер1 в фоне и без прерываний, и опрашиваем бит его переполнения в критичном по времени работы цикле.

Если Таймер1 переполнился -- сбрасываем этот бит, и декрементируем счетчик времени работы цикла.

 

Этот код я дизассемблировал и он как бы во временном допуске получается. Но может как-то еще быстрее можно контролировать время работы цикла? Можно применять абсолютно любую периферию МК AVR, программные трюки в том числе и сторожевой таймер :)

Задача: максимально не мешать критично важному по времени куску кода и завершить его через 15-20 минут.

 

Спасибо!

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


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

20 минут назад, skilful сказал:

программные трюки в том числе и сторожевой таймер :)

Не знаю, реально ли. Лень заглядывать в доку. Но перед запуском критического цикла, настраиваете таймаут сторожевика на 15 минут. Запускаете код. Через 15 минут сторожевик аккуратно прерывает ваш цикл. Никаких проверок в самом цикле не нужно. А в секции .noinit располагаете переменную, которая будет хранить результат предыдущей работы программы. После сброса там будет, скорее всего, мусор. Т.к. в AVR вроде нет встроенных загрузчиков, которые могут занулить ОЗУ.

З.Ы. Понимаю, что фантастика, но вдруг, если даже и не сработает, то наведёт на мысль.

 

Стоп! А почему фантастика? Настраиваете таймер (не сторожевик) на прерывание через 15 минут (если делители позволят), в цикле никаких проверок. А в прерывании аккуратно выходите из цикла, подменив адрес в счётчике команд PC: адрес возврата же в стэке храниццца? Вот там его и покорябаете аккуратно)

 

Если таймер нельзя на такой таймаут настроить, то считаете RC-цепь или берёте 555-таймер, заводите выход цепи или таймера на ногу прерывания и в прерывании делаете то же самое, что я чуть выше описал. А сбрасываете 555-таймер или RC-цепь другой ножкой.

 

Просчитать время выполнения цикла, ведь он у вас на асме. В нём декрементировать переменную, в которую изначально занесено отношение времени работы цикла к длительности вашего критического кода. Тут, конечно, одна проверка понадобится.

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


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

1 час назад, MrBearManul сказал:

Стоп! А почему фантастика? Настраиваете таймер (не сторожевик) на прерывание через 15 минут (если делители позволят), в цикле никаких проверок. А в прерывании аккуратно выходите из цикла, подменив адрес в счётчике команд PC: адрес возврата же в стэке храниццца? Вот там его и покорябаете аккуратно)

Это всё называется - "задача вытесняющей ОС реального времени". Только врукопашную (закат солнца вручную)  ;)

ТС видимо никогда не имел дела с РТОС, раз задаёт такие вопросы. Совет: изучить работу под РТОС, а затем написать алгоритм в виде низкоприоритетной задачи, вытесняемой через 15-20 мин более приоритетной.

И всё.  :unknw:

А результат работы первой задачи, вторая может взять из сохранённого контекста задачи (который имеет фиксированный формат в РТОС-ах).

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


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

longjmp из прерывания по таймеру. Таймер нужно заводить на весь интервал времени. Если нет такой возможности, то лучше уже не сделать.

Изменено пользователем rkit

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


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

44 минуты назад, jcxz сказал:

Это всё называется - "задача вытесняющей ОС реального времени". Только врукопашную (закат солнца вручную)  ;)

Из переключалки контекста мне эта идея и пришла.

 

 

48 минут назад, jcxz сказал:

Совет: изучить работу под РТОС, а затем написать алгоритм в виде низкоприоритетной задачи, вытесняемой через 15-20 мин более приоритетной.

Возьму уже себе на заметку. Именно в контексте решения задачи автора.

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


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

1 hour ago, jcxz said:

Это всё называется - "задача вытесняющей ОС реального времени". Только врукопашную (закат солнца вручную)  ;)

Нет. Для ртос нужен таймер с постоянными прерываниями (100-1000Гц), что прямо противоречит условию "лучше не мешать".

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


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

9 минут назад, rkit сказал:

Нет. Для ртос нужен таймер с постоянными прерываниями (100-1000Гц), что прямо противоречит условию "лучше не мешать".

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

Кроме того - можно вообще без периодических прерываний. Читайте что такое tickless OS.

 

PS: А вот насчёт "longjmp из прерывания по таймеру" - это нужно ещё проверять, не уверен что это возможно на AVR-ах. Я не спец. в AVR-ах, но в ARM/Cortex-M например такое невозможно. Да и на многих других платформах. Возможно только с уровня приложений, но не из ISR.

В общем случае: если на платформе возможны вложенные прерывания - то будет не возможно. И по другим причинам.

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


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

1 hour ago, jcxz said:

Это всё называется - "задача вытесняющей ОС реального времени". Только врукопашную (закат солнца вручную)  ;)

ТС видимо никогда не имел дела с РТОС, раз задаёт такие вопросы. Совет: изучить работу под РТОС, а затем написать алгоритм в виде низкоприоритетной задачи, вытесняемой через 15-20 мин более приоритетной.

И всё.  :unknw:

А результат работы первой задачи, вторая может взять из сохранённого контекста задачи (который имеет фиксированный формат в РТОС-ах).

проведите немного ликбез: что поменяется при применении RTOS ? Таймеры в AVR выше этих 4 секунд не настроить на 16 МГц. Значит будут прерывания, которые будут прерывать мой код для проверки переключения задачи?

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

 

К сожалению, сторожевик в AVR только максимально 8 секунд может отсчитать. Так бы его применил как параллельный процесс и не парился бы :)

 

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


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

2 минуты назад, skilful сказал:

Так бы его применил как параллельный процесс и не парился бы :)

1. NE555)

2. RC-цепь. Это вообще дешёвый вариант. Тут, правда, с порогом срабатывания придётся всё внимательно посчитать.

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


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

3 minutes ago, MrBearManul said:

1. NE555)

2. RC-цепь. Это вообще дешёвый вариант. Тут, правда, с порогом срабатывания придётся всё внимательно посчитать.

да жаль, что столько еще неиспользуемой периферии на борту и внешние цепи/устройства ставить

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


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

5 минут назад, skilful сказал:

да жаль, что столько еще неиспользуемой периферии на борту и внешние цепи/устройства ставить

Вряд ли вы смените микроконтроллер на другой, с подходящей периферией) Но согласитесь, что резистор и конденсатор много места не займут. Если AVR не умеет открытый сток, то ещё внешний полевичок придётся добавить для сброса. В обще чем-то платить придётся)

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


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

Внешней дорожкой замкнуть выход одного таймера на вход другого (имитация Master-Slave), считать Slave-ом необходимые 20 минут.

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


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

Если абсолютно критично отсутствие прерываний - то да, аппаратно (внешними соединениями) каскадировать два-три таймера, по прерыванию подменить адрес PC в стеке. Если допустимы относительно редкие прерывания - отсчитать требуемое количество переполнений и сделать то же самое.

Изменено пользователем rx3apf

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


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

Очень долго не работал с AVR, память может подводить. В SREG есть пользовательский флаг T. Его устанавливать в прерывании и тестировать в конце цикла для выхода/повтора (команды BRTC, BRTS). Единственно, надо на 100% быть уверенным, что компилятор не использует этот флаг для иных целей.

Таймеры, как уже подсказали, можно каскадировать внешними межсоединениями чтобы не отвлекаться на промежуточные обработчики прерываний. Еще, вроде как, один из таймеров можно было тактировать от внешнего (часового) кварцевого резонатора.

upd вместо флага T лучше использовать флаг I (разрешение прерываний). Перед началом цикла I установлен, в единственном прерывании от таймер он сбрасывается, цикл анализируя флаг I завершает работу. Дальше I снова устанавливаем чтобы не страдали остальные прерывания системы и останавливаем интервальный таймер. На словах как всегда просто получается)

upd2 не пойдёт. SREG в прологе обработчика прерывания сохраняется, затем восстанавливается.

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


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

1 час назад, skilful сказал:

проведите немного ликбез: что поменяется при применении RTOS ? Таймеры в AVR выше этих 4 секунд не настроить на 16 МГц. Значит будут прерывания, которые будут прерывать мой код для проверки переключения задачи?

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

У Вас в цикле при каждом проходе цикла выполняется участок:

Цитата

if ((TIFR1) & (1 << TOV1)) {                    //таймер1 с предделителем работает в фоне. Сработка каждые 4 секунды
                TIFR1 = 0x01;        					//сброс бита переполнения. Пишем туда 1 для сброса
                TOV1_cnt--;                
            }            

и если остальное тело цикла достаточно мало, то этот участок контроля таймера может занимать значительную долю времени одного прохода цикла.

Если например полезная часть цикла == 90 тактов, а эта контрольная = 10 тактов, то значит она будет занимать целых 10% времени.

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

1 час назад, skilful сказал:

К сожалению, сторожевик в AVR только максимально 8 секунд может отсчитать. Так бы его применил как параллельный процесс и не парился бы :)

Придумываете проблему на ровном месте.

Всё просто: ISR вызываемый  с частотой 1/4 Гц в котором - декрементируемый счётчик. При обнулении счётчика - стоп фоновой задачи.

Суммарное время выполнения всех вызовов ISR думаю будет намного меньше, чем время затрачиваемое участком контроля сейчас.

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


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

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

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

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

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

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

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

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

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

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