PIC24. C30 и прерывания

PIC
  Как и обещалось, сегодня посмотрим что такое прерывания в PIC24 и с чем их есть на C30. Утащеная на допиливание статья по АЦП тоже когда-нибудь вернется, ибо отключение света и отсутствие автосохранений отбили желание писать все заново.

  По сравнению с 18 и младшими пиками тут у нас уже не 1 и не 2 вектора прерываний, а целых 2 таблицы по 126 штук каждая. Причем для каждого из прерываний можно установить приоритет, а вход и выход из прерывания осуществляется за 4 и 2 инструкции соответственно.

Содержимое таблиц
  Две таблицы это основная и альтернативная таблицы. Расположены в начале памяти. Какую таблицу использовать указывается старшим битом ALTIVT(ALTernate Interrupt Vector Table) регистра INTCON2. Если установить этот бит то будет использоваться альтернативная таблица. Каждая из таблиц имеет идентичные набор прерываний, которые лучше смотреть в даташите на ваш контроллер, т.к. периферия может быть разной, тогда и наполнение этих таблиц будет отличаться.
Есть и системные прерывания, их 8 штук, используемых только 4, происходящих при ошибках. Это(в скобках указаны их приоритеты)
  • Ошибка тактового генератора(14)
  • Ошибка адреса()
  • Ошибка стека(12)
  • Ошибка математических операций(11)

  Если эти прерывания не описать, то при возникновении какой либо из этих ошибок контроллер будет сброшен.

  Есть еще такая штука как вложенность прерываний. Если это разрешено, то прерывание может быть так же прервано прерыванием более высокого уровня. Управляется битом NSTDIS. Если же запрещено, то приоритет процессора устанавливается равным 7. Т.е. на время выполнения прерывания все другие запрещаются до выполнения retfie(выход из прерывания). Отключение вложенных прерываний заставит их выполняться по очереди в порядке приоритета.
бит 15 NSTDIS: Запрет вложенных прерывания
  1 = Запрещены
  0 = Разрешены
биты 14-5 не используются
бит 4 MATHERR: Математическая ошибка
  1 = Произошло
  0 = Не произошло
бит 3 ADDRERR: Ошибка адресации
  1 = Произошло
  0 = Не произошло
бит 2 STKERR: Ошибка стека
  1 = Произошло
  0 = Не произошло
бит 1 OSCFAIL: Ошибка генератора
  1 = Произошло
  0 = Не произошло

Приоритеты
  Для кажного из прерываний указывается приоритет. Так же приоритет есть и у самого процессора.
Если приоритет прерывания 0 то это тоже самое, если бы оно было запрещено. Так же нельзя чтобы приоритет прерывания был выше приоритета процессора. И если для обычного прерывания доступно 7 уровней приоритета, то для процессора их 16. Это сделано для того чтобы процессор мог иметь высший приоритет чем прерывания ошибок, так как они имеют значения от 8 до 15. Чем выше число приоритета, тем выше соответственно приоритет прерывания. По умолчанию все приоритеты равны 4. Когда происходит конфликт: два прерывания равного приоритета, то больший приоритет имеет то, которое расположено выше в таблице.

  Существует специальная функция DISI, запрещающая прерывания максимум на 16384 цикла. Пригодится для запрещения прерываний на время выполнения участков, прерывать которые нельзя. Но действует это только на прерывания с приоритетами 1-6. 7 и выше будут выполнены даже если инструкция активна. DISICNT — счетчик, доступный для записи. С каждой инструкцией уменьшается на 1 и как только там оказывается 0, то прерывания снова разрешаются. Функция активизируется соответствубщим битом в регистре INTCON2

C30. Прерывания на практике
  Очевидно что работа с таким модулем прерываний вручную может вылиться в большой гемор в виде ручного указывания адресов обработчиков разных прерываний. Благо разработчики компилятора позаботились и сделали нашу жизнь проще.

  Чтобы запрограммировать прерывание нам необходимо его включить. Сделать это можно двумя способами(выполняется одно и тоже, но описывается по разному):
  • Самостоятельная установка бита. Открываем даташит, находим нужный бит из регистров IEC и устанавливаем его. Наример для нашего примерного PIC24FJ64GB002 мы включим прерывание таймера 1:
    IEC0bits.T1IE=1;
  • С помошью макросов. В заголовочном файле на контроллер можно найти много интересного. И благодаря этому же файлу можно написать просто
    _T1IE=1
    . Так гораздо удобней ибо просто по абревиатуре все включается и не надо искать в каком регистре что у нас есть.

  Аналогично можно постопить и с приоритетами. Можно найти в даташите нужный регистр, установить нужное значение полубайта вручную. Установим приоритет 4 для таймера1:
  • IPC0=(IPC0&0x0FFF)|0x4000;
  • Или просто
    _T1IP=4;

Прежде чем включать прерывания следует сбросить флаг этого прерывания:
  • IFS0bits.T1IF=0;
  • _T1IF=0;

Описание самой процедуры прерывания происходит по такому вот шаблону:
void __attribute__((__interrupt__)) _T1Interrupt(void);

где T1 — имя нашего прерывания. Тут это таймер 1 в качестве примера. Если надо описать функцию прерывания для альтернативной таблицы то перед названием добавляем Alt. Функция прерывания не должна ничего возвращать или принимать как аргумент. Функцию прерывания нельзя вызывать из кода.
Это «класическое» определение прерывания в С30. Так же прерывание можно описать несколько проще, с помощью все тех же определений:
void _ISR _T1Interrupt(void);

В C30 есть быстрое сохранение контекста. Чтобы его использовать прерывание описывают так:
void __attribute__((__interrupt__, __shadow__)) _T1Interrupt(void);
или
void _ISRFAST _T1Interrupt(void); 

Можно сохранить только значения некоторых переменных v1 и v2. Для этого прерывание описывается так:
void __attribute__((__interrupt__(__save__(v1,v2)))) _T1Interrupt(void);
тут в скобочках список сохраняемых переменных. Определив прерывание дальше пишем выполняемый код, не забывая сбросить флаг прерывания, иначе прерывание сработает снова.

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

void _ISRFAST _T1Interrupt(void)
{
//это такой мини-шим, будет использован для регулировки яркости светодиодов
//с помощью сенсорного варианта потенциометра
//ll и lr - коэфициенты ШИМ, а LED1 и LED2 - пины на которых эти диоды
	_T1IF=0;  // сбрасываем флаг прерывания
	TMR1=0xFF00;
	pos++;
	if (ll<=pos)
	{LED2=0;} else
		{LED2=1;}

	if (lr<=pos)
	{LED1=0;} else
		{LED1=1;}
}

void init(void)
{
//...
T1CON=0x8000;  // просто включили таймер1
_T1IF=0;       // сбрасываем флаг прерывания на всякий случай
_T1IP=4;       // устанавливаем приоритет
_T1IE=1;       // разрешаем прерывание
//...
}
  • +2
  • 06 апреля 2012, 16:40
  • kest

Комментарии (9)

RSS свернуть / развернуть
Кест, спасибо за статью. Еще есть третий способ вкл. прерывания (инициализировать) — через встроенные в компилятор функции типа:
#int_timer0
  
 
void timer0interrupt()
 // #int_timer associates the following function with the
 
 
 // interrupt service routine that should be called
 
enable_interrupts(TIMER0);
 // enables the timer0 interrupt
 
disable_interrtups(TIMER0);
 // disables the timer0 interrupt
 
clear_interrupt(TIMER0);
 // clears the timer0 interrupt flag
 
0
  • avatar
  • Dmi
  • 07 апреля 2012, 12:46
Это по сути то же самое =) но все же.
0
хм… не знал:) В DS51284F в 7ой главе по прерываниям про эти функции ни слова
0
так в даташите их и не должно быть (функций) =) Это зависит от компилятора. Я Юзаю PIC C compiler. там оч хороший хелп, все читабельно. один момент: нужно только подключить библиотеку контроллера прошиваемого. НУ это и так понятно. так просто нагляднее… мы таки в C прогаем, а не в ASM…
0
  • avatar
  • Dmi
  • 07 апреля 2012, 13:59
А, так это в PIC C. А тут я про C30 говорил. Ясное дело что там могут быть свои функции и определения. А DS51284F это мануал к компилятору как раз микрочиповскому.
0
Извиняй за баламутство =D в общем советую PIC C. крутой компилятор… но есть там свои заморочки, однако
0
  • avatar
  • Dmi
  • 07 апреля 2012, 14:06
Поправь в статье, плиз…
C30. Перрывания на практике
… и…
дла наше примерного PIC24FJ64BG002
PIC24FJ64GB002…
0
готово
0
Есть и системные прерывания, их 8 штук, используемых только 4, происходящих при ошибках. Это
Ошибка тактового генератора
Ошибка адреса
Ошибка стека
Ошибка математических операций

Если эти прерывания не описать то при возникновении какой либо из этих ошибок контроллер будет сброшен. Запрещаются эти прерывания-ловушки ошибок и флаги этих событий в регистре INTCON1:
бит 15 NSTDIS: Запрет прерываний-ловушек

Если у pic24 система прерываний такая же как и у dsPIC30 (а похоже что это так), то эти 4 прерывания немаскируемые, и запретить их нельзя (физически они имеют приоритет > 8). А бит «NSTDIS» это запрет/разрешение вложенных прерываний (см. «6.2.4.2 Interrupt Nesting» в «dsPIC30F Family Reference Manual»)
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.