Использование прерываний в микроконтроллерах Xmega

    Данная статья просвещенна особенностям использования и настройке системы прерываний микропроцессора Xmega.
    Система прерываний в микроконтроллерах используется для распределения приоритета выполнения требуемых задач и гарантии быстрой обработки периферийных устройств. Также прерывания могут использоваться для уменьшения потребления энергии микропроцессором с помощью перевода процессора в режим низкого потребления и выходом из него по требуемому прерыванию.
    Микропроцессоры Xmega имеют программируемый контроллер многоуровневых прерываний (PMIC) с разделением на три уровня прерываний: высокий, средний и низкий. Прерывание среднего уровня может прервать работу по прерыванию низкого уровня, а прерывание высокого уровня может прервать работу по прерыванию низкого и среднего уровня. У прерываний низкого уровня есть дополнительная циклическая схема, позволяющая убедиться в том, что все прерывания начнутся в пределах определенного времени.
    Принцип работы
    Большинство периферийных устройств имеют флаги состояния или прерывания, которые могут быть использованы для захода в режим прерывания. Прерыванием является сигнал центральному процессору о том, что последовательное выполнение программного кода должно быть прервано и должен быть выполнен код программы обслуживания прерываний (ISR). Прерывание происходит при выполнении всех следующих условий:
    - Выполнено условие выставляющие флаг прерывания.
    - Прерывания разрешены для данного модуля.
    - Разрешены прерывания данного уровня в контроллере прерываний PMIC.
    - Разрешены глобальные прерывания в центральном процессоре.
    Вызов прерывания в первую очередь определен его уровнем и лишь затем приоритетом. Уровень прерывания может быть установлен независимо для каждого прерывания в PMIC, в то время как приоритет для прерывания неизменен и задан векторным адресом прерывания.
    Немаскируемое прерывание Non-Maskable (NMI) является специальным прерыванием и не может быть отключено, оно используется для критических прерываний системы, таких как отключение кварцевого генератора.
    Уровни прерываний и разрешения прерываний от устройства
    Если необходимо использовать прерывание по периферийному устройству, то необходимо установить уровень прерываний соответствующего прерывания отличный от нуля (отключено). Прерыванию можно присвоить 3 уровня: высокий, средний или низкий. Биты, управляющие включением прерывания от периферийного устройства и его уровнем находятся в регистрах INTCTRL.
    При использовании многоуровневых прерываний нужно понимать, что выполнение одного прерывания может быть прервано другим прерыванием с более высоким уровнем. В зависимости от количества используемых уровней прерываний в программе надо оценить и грамотно установить величину (глубину) стека, требуемого для нормального выполнения программы.
    Также необходимо предусмотреть защиту доступа к регистрам и переменным размерностью более 8 бит. Эта необходимость возникает в силу того, что шина данных процессоров AVR является 8-битной и доступ к переменным размером в несколько байт осуществляется не одной инструкцией, поэтому возможна ситуация, когда прерывание происходит между вызовом первого и второго байта 16-битной (или большей битности) переменной. Если эта 16-битная переменная используется в основном цикле программы, то вызванное прерывание может привести к искажению значения переменной. Аналогичная ситуация возможна при прерывании программы выполнения одного прерывания другим прерыванием, более высокого уровня. Искажение значения можно избежать несколькими вариантами: 1) отключение глобальных прерываний в моменты обработки переменной; 2) использование (сохранение значения с последующим восстановлением) временных регистров формируемых аппаратными средствами, например временный регистр таймера-счетчика.
    Немаскируемые прерывания (NMI)
    Немаскируемое прерывание имеет наивысший приоритет по сравнению с другими прерываниями. Если одновременно требуют выполнения два немаскируемых прерывания, то приоритет определятся согласно векторному адресу прерывания, где самый младший адрес имеет самый высокий приоритет.
    Микропроцессор Xmega A1 имеет только один источник NMI – неисправность кварцевого генератора.
    Если кварцевый генератора используется в качестве системных часов, то его состояние контролируется. Если по каким-либо причинам кварцевый генератор остановится (например из-за физического повреждения), то произойдет немаскируемое прерывание и системные часы переключаться на синхронизацию от внутреннего RC-генератора частотой 2 МГц.
    Так как немаскируемое прерывание не может быть отключено – не существует механизма программного отключения сработавшего немаскируемого прерывания. Единственным способом отключения сработавшего немаскируемого прерывания является перезагрузка микропроцессора.
    Разрешение работы уровней прерываний
    Разрешение работы каждого уровня прерываний может быть включено отдельно. Это может быть необходимо, например, для блокировки прерываний более высокого уровня при обработке 16-битных переменных (для исключения проблем описанных выше). Запись битов HILVLEN, MEDLVLEN и LOLVLEN в регистр PMICCTRL разрешает работу отдельных уровней.
    Важно учесть то, что бит глобального прерывания (в регистре SREG) не очищается при входе в прерывание, в отличие от микропроцессоров семейства megaAVR. Контроллер многоуровневых прерываний имеет механизм гарантирующий, что выполнение прерывания не может быть прервано другим прерыванием того же уровня.
    Разрешение работы глобальных прерываний
    Даже если разрешена работа конкретного уровня прерываний, и в устройстве и в PMIC, прерывания не будут выполняться если не установлен бит разрешения работы глобальных прерываний.
    Включение или отключение глобальных прерываний может быть выполнено как инструкциями ассемблера SEI и CLI, так и специальными командами С - __disable_interrupt() и __enable_interrupt().
    Время отклика прерывания
    Время отклика прерывания для всех разрешенных прерываний составляет 5 циклов часов центрального процессора. В течение 5 тактовых циклов программный счетчик помещается в стек, а по окончанию их запускается программный вектор прерывания. Переход к указателю на программу прерывания занимает 3 цикла.
    Если прерывание происходит при нахождении микропроцессора в спящем режиме, то время отклика прерывания увеличивается на 5 циклов и к нему еще добавляется время необходимое для пробуждения.
    Возвращение из процедуры обработки прерывания занимает 5 циклов, в течение которых программный счетчик возвращается из стека и указатель стека увеличивается.
    Векторы прерывания
    Расположение (адреса) векторов прерывания вызываются из памяти программ при срабатывании прерывания. По данному адресу, как правило, располагается команда JMP (или RJMP) к адресу памяти программ, где расположена соответствующая программа обработки прерывания (ISR). Адреса прерываний для каждого процессора указаны в его документации. Адреса векторов прерывания для процессора Xmega A1 показаны в следующей таблице:
 
 
    Не рекомендуется оставлять неиспользуемые незапрограммированные вектора прерываний, т.к. незапрограммированная память может содержать некорректный программный код, результат выполнения которого неизвестен. "Заполнение" неиспользованных векторов прерываний инструкциями RETI гарантирует вызов прерывания с отсутствующей процедурой обработки прерывания, что является неопасным. Необходимо чтобы фиктивное выполнение процедуры обработки прерываний, для всех неиспользуемых прерываний, было проверенно на возможность формирования ошибок в процессе разработки и отладки программы. 
    Если работа прерываний разрешена и используется загрузка разделов из памяти программ или запросы программ использующих разделы памяти программ, то необходимо переместить вектора прерываний в раздел загрузки. Если вектора не перемещены, то во время выполнения записи прикладного раздела, возникшее прерывание будет вызывать выполнение кода с адреса памяти программ, который не может быть прочитан (также как и записан). Вектора перемещаются в загрузочный раздел памяти программ установкой бита IVSEL в регистре PMIC.CTRL. 
    Приоритет прерываний 
    Приоритет прерывания определяется его векторным адресом (векторным номером). Векторные адреса постоянны. Приоритет прерывания определяет, какое из прерываний имеющих один и тот же уровень будет выполняться первым, при условии, что они произошли одновременно. 
    Однако при постоянном приоритете в низкоуровневых прерываниях может возникнуть проблема, когда их выполнение будет бесконечно задерживаться появлением других прерываний более высокого приоритета. Поэтому программируемый контроллер многоуровневых прерываний имеет дополнительную циклическую (круговую) Round-Robin схему для прерываний низкого уровня, работа которой разрешается установкой бита RREN в регистре PMIC.CTRL. Когда разрешена работа циклической схемы, центральный процессор будет обновлять регистр INTPRI автоматически так, что всегда равен номеру вектора прерывания произошедшего последним. Значение в INTPRI определяет, какое низкоуровневое прерывание имеет самый низкий приоритет. Таким образом, циклическая схема гарантирует, что низкоуровневые прерывания будут выполняться последовательно в соответствии с их возникновением. Другими словами прерывание низкого уровня произошедшие последним, всегда будет иметь самый низкий приоритет, что гарантирует выполнение других прерываний низкого уровня. 
    Отметим, что при отключении циклической схемы регистр INTPRI не будет возвращаться в начальное значение (0x00), а будет иметь значение номера последнего прерывания низкого уровня. Если необходимо, то вернуть значение по умолчанию можно записью 0x00 в регистр INTPRI после отключения работы циклической схемы. Значение в регистре INTPRI будет сохранять свой приоритет при вызове прерывания низкого уровня даже при отключенной циклической схеме. 
    Флаги прерываний 
    Флагами прерываний в микропроцессорах AVR называются биты в регистрах статуса различных устройств (модулей). Эти флаги предоставляют информацию об изменении состояний в устройстве, например окончание приема байта по SPI. Флаги прерывания устанавливаются, даже если работа соответствующего прерывания запрещена. Это позволяет учитывать флаги прерываний в основном цикле программы. Опрос может проводиться в разное время, но обычно происходит в момент выполнения процедуры обработки прерывания, при возникновении соответствующего события. Основным преимуществом учета при выполнении процедуры обработки прерывания является то, что необходимым устройствам можно уделить особое внимание, временно остановив работу мене важных задач. Другим преимуществом является то, что микропроцессор может войти в спящий режим для уменьшения энергопотребления и пробудиться по прерыванию. 
    Прерывания могут быть очищены вручную записью логической 1 в соответствующий флаг или автоматически при выполнении вектора прерывания. Другие флаги прерываний очищаются при получении доступа к определенным регистрам, например к регистру данных USART. 
    Также некоторые флаги могут не очищаться автоматически, более подробная информация об этом находится в документации на конкретный процессор. 
    Сравнение прерываний и системы событий 
    Отметим, что центральному процессору необязательно работать с прерываниями, так как система событий Xmega является альтернативным способом по работе с типичными условиями прерываний без вмешательства центрального процессора. Например, система событий может инициировать аналого-цифровое преобразование каждый раз по переполнению таймера. При необходимости это дает уникальные возможности по формированию временных интервалов при отсутствии возможности использования центрального процессора. 
    Ну и как обычно, напоследок парочку рабочих примеров для упрощения жизни начинающим программистам на микропроцессорах Xmega.
    Пример 1.
   Задача: Написать программу инвертирования одной ножки при появлении нарастающего фронта на другой с использованием прерываний.
   В качестве ножки формирующей прерывание по переднему фронту будем использовать PC0. Установим средний уровень прерывания по этой ножке. В качестве инвертирующиеся по прерыванию ножки используем PD0.
   Код работающей программы для процессора Xmega A1 имеет следующий вид:
#define ENABLE_BIT_DEFINITIONS // разрешение использования групповых битовых имен
#include <ioxm128a1.h>                      // Объявление используемых библиотек
#include <ina90.h>                              // Объявление используемых библиотек
int main(void)
{
   __disable_interrupt();                                 // Отключение прерываний
   PORTC.PIN0CTRL=PORT_ISC_RISING_gc;   // установка чувствительности ножки PC0 к переднему (нарастающему) фронту
   PORTC.INT0MASK=0x01;                           // установка маски прерываний 0 для порта C на прерывание по ножке 0
   PORTC.INTCTRL = PORT_INT0LVL_MED_gc; // установка уровня medium прерываний 0по ножке 0 порта С
   PORTD.DIR=0x01;                                     // Настройка ножки PD0 на выход
   PMIC.CTRL = PMIC_MEDLVLEN_bm;            // приоритет прерываний уровня medium
   __enable_interrupt();                                 // Разрешение прерываний
   while(1) { }                                              // Основной бесконечный цикл
}
ISR(PORTC_INT0_vect)                                 // обработка прерывания 0 по ножкам порта C
{
   PORTD.OUTTGL=0x01;                             // переключение уровня сигнала на выходе ножки PD0
}
   Пример 2.
   Задача: Написать программу пробуждения микропроцессора и выполнения какого то действия (например выдачи меандра) при подаче на определенную ножку логического ноля, а при отсутствие логического нуля на данной ножке, микропроцессор уходит в отключенные спящий режим (Power-down).
   В качестве основной системной частоты процессора будем использовать внутренний RC-генератор 2 МГц. В качестве входной подтянутой ножки будем использовать ножку PK1 и пробуждать процессор от прерывания по данной ножке. Таймер выполнения основной программы настроим на частоту 1кГц, в рабочем режиме на ножку PK0 выдается меандр частотой 500Гц.
  Код работающей программы для процессора Xmega A1 имеет следующий вид:
#define ENABLE_BIT_DEFINITIONS         // разрешение использования групповых битовых имен
#include <ioxm128a1.h>                      // Объявление используемых библиотек
#include <ina90.h>                              // Объявление используемых библиотек
void InitTimers(void)
{
   TCC0.CTRLA = 0x04;                         // N=8;
   TCC0.PER = 250-1;                           // частота таймера 1кГц при системной частоте 2МГц
   TCC0.INTCTRLA = 1;                         // уровень прерываний таймера low
}
int main(void)
{
   __disable_interrupt();                       // Отключение прерываний
   PORTK.DIRSET = 0x01;                     // Установка ножки 0 порта К как выход
   PORTK.PIN1CTRL = PORT_OPC_PULLUP_gc;// Установка подятнутого входа ножки 1 порта К
   InitTimers();                                   // Запуск процедуры инициализации таймеров
   PMIC.CTRL = 1;                               // приоритет прерываний уровня low
   PORTK.INTCTRL = 1;                       // установка уровня low прерываний по ножке 1 порта К
   PORTK.INT0MASK = 2;                     // установка маски прерываний для порта К
   __enable_interrupt();                       // Разрешение прерываний
   while(1)                                          // Основной бесконечный цикл
   {
      if (!(PORTK.IN & 0x02))                 // Если на ножке 1 порта К логический ноль, то
      {
         SLEEP.CTRL = SLEEP_SEN_bm + SLEEP_SMODE_PDOWN_gc; // установка отключенного режима в качестве спящего режима
         __sleep();                                 // переход в спящий режим
         SLEEP.CTRL = 0;                       // выход из спящего режима (по прерыванию ножки 1 порта К)
      }
   }
}
ISR(TCC0_OVF_vect)                         // обработка прерываний по переполнению таймера С0
{
   PORTK.OUTTGL = 0x01;                   // переключение уровня сигнала на выходе ножки 0 порта К
}
    Blogger Comment
    Facebook Comment

0 коммент.:

Отправить комментарий