Jump to content

    

XMEGA прерывания

В IdleProc нельзя вызывать ни sleep(), ни другие сервисы оси, на то она и IdleProc :-)

Ну чудес-то не бывает. Простым изменением участка кода программы нельзя запретить/разрешить прерывания. Где-то вы их запрещаете. При переключении процесса происходит сохранение контекста одного процесса, и восстановление другого. Раз в одном процессе прерывания работают, а в другом - нет, то запрет происходит именно при переключении контекста. Вот и всё.

 

Share this post


Link to post
Share on other sites
On 2/20/2020 at 1:23 PM, AHTOXA said:

Раз в одном процессе прерывания работают, а в другом - нет, то запрет происходит именно при переключении контекста.

Нашел причину. Попробую объяснить. Проект настроен на прямую передачу управления, т.е. #define scmRTOS_CONTEXT_SWITCH_SCHEME 0. Для примера запускаем проект с одним процессом.

template<> void TProc1::exec()
{
  for(;;)
  {
    sleep(10);
    delay_ms(500);
  }
}

1. Заходим в sleep(10), выставляем timeout, сбрасываем флаг готовности процесса и выполняем перепланировку Kernel.scheduler(), т.к. рабочий процесс один и он ушел в спячку, система переключится на процесс IdleProc.

2. Периодически через заданный интервал времени от системного таймера возникают прерывания, в обработчике функция Kernel.system_timer() проверяет флаг готовности процесса Proc1. Если готовности нет, прерывание завершается без перепланировки и система продолжает оставаться в IdleProc. Тут отмечу, что выход из обработчика прерывания без перепланировки выполняется командой RETI, контроллер прерываний при этом сбрасывает флаг в PMIC.STATUS. Далее контроллер готов к выполнению других прерываний, если они есть в очереди или когда возникнут новые.

3. Если флаг готовности процесса Proc1 установлен, в обработчике прерывания системного таймера произойдет перепланировка процессов в функции os_context_switcher. Тут немного подробнее, при вызове этой функции в RStаck процесса IdleProc запишется адрес возврата, в CStack сохранится SP, сохранятся состояние регистров, далее для выполнения Proc1, из стека Proc1 восстановится SP и регистры, т.е. все готово для продолжения выполнения этого процесса. В конце функции os_context_switcher выполняется команда RET, в результате которой попадаем сразу в Proc1 и продолжаем его выполнение. В итоге получается, что обработка прерывания осталась не завершена, команды RETI не было, флаг в PMIC.STATUS = 1, прерывания одного уровня работать не будут даже при SREG = 0x80. 

4. Далее по коду в Proc1, функция delay_ms(500) отработает без прерываний, зайдет в sleep(10), в которой произойдет перепланировка, восстановится процесс IdleProc, а т.к. он был ранее сохранен в обработчике прерывания, завершит его код с командой выхода RETI, и прерывания снова будут выполняться.

Подскажите, пожалуйста, может есть какие мысли? Пока думаю над таким вариантом: в конце функции os_context_switcher сделать проверку флага PMIC.STATUS, если флаг установлен, то выполнять выход командой RETI, если нет, то RET. Но тут есть один момент, IdleProc при возобновлении в обработчике прерывания будет завершать его командой RETI, т.е. прерывание уже было завершено ранее командой RETI, и тут снова RETI. 

Share this post


Link to post
Share on other sites

Хм. Очень интересно. Неужели это косяк в порте под AVR? Или всё же это особенность работы XMEGA...

К сожалению, я не знаком с АВР-ками, поэтому не знаю, что посоветовать. Возможно, @dxp что-то подскажет. Если вспомнит, конечно :-)

 

Share this post


Link to post
Share on other sites
9 часов назад, AHTOXA сказал:

Возможно, @dxp что-то подскажет. Если вспомнит, конечно :-)

Почти всё забыл (17 лет уж тому), но насколько ещё что-то помню, в тех AVR не было никиких PMIC и система прерываний была одноуровневая. Потом портом под AVR занимался другой человек, может он бы что-то мог сказать, но, к сожалению, он давно не выходит на связь. Я даже не в курсе, что включает поддержку XMEGA и есть ли она там.

 

P.S. Насколько помню, прямую передачу управления использовать не рекомендуется, этот способ только если по-другому уже никак. Неужели в xmega нельзя найти свободное прерывание? В примерах даже обычные AVR через прерывание передают управление.

Share this post


Link to post
Share on other sites

У меня есть стабильно работающий порт ScmRTOS 4.0 на Xmega/IAR и нестабильный порт ScmRTOS 5.1 (бросил разбирательства когда проект с 4.0 заработал). Также, если поискать, были чужие порты на Xmega/GCC. Могу выложить, если кому-то нужно. Отличий от портов на обычные AVR там много.

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

Выкладываю фрагмент из одного из текущих проектов. Внутри 4.00 рабочая и 5.1.0 - не очень.

scmrtos4xmega.zip

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now