Программирование DSP Blackfin: настройка обработчика прерывания Thu, June 29 2017  

Поделиться

нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.


Blackfin: настройка обработчика прерывания Печать
Добавил(а) microsin   

Прерывание обычно используется для быстрой обработки какого-либо асинхронного события в программе (отсчет интервала времени, поступление данных от интерфейса SPI или UART, завершение передачи блока DMA и т. п.). "Асинхронное событие" означает, что оно может произойти без привязки к действиям основной программы. Прерывание как раз может послужить такой привязкой, т. е. прерывание позволяет синхронизировать какие-то внешние события с ходом выполнения основной программы.

Альтернативой прерываниям может служить опрос флагов или регистров (так называемый polling), однако по сравнению с прерываниями это не такой эффективный способ, потому что приводит к загрузке процессора выполнением ненужных команд, и часто опрос не позволяет быстро, в реальном времени обработать произошедшее событие.

Настройка прерывания для процессоров Blackfin состоит из 5 основных шагов:

1. Очистка приоритетов по умолчанию (не обязательный шаг).
2. Написание обработчика прерывания.
3. Настройка приоритета прерывания.
4. Регистрация обработчика прерывания.
5. Разрешение прерывания.

Рассмотрим каждый шаг подробнее.

Шаг 1. Очистка приоритетов по умолчанию (не обязательный шаг). После сброса процессора все регистры SIC_IARx получает настройку приоритетов по умолчанию для всех периферийных устройств (подробнее см. таблицу 4-6 в статье [1]). Если такое назначение приоритетов Вас почему-то не устраивает, то можно очистить все настройки приоритетов. Это делается вот такой подпрограммой:

void ClearIVG (void)
{
   for(int i=0; i < 8; ++i)
   {
      // Очистка уровней приоритета IVG для всех периферийных устройств:
      *pSIC_IAR0 &= PX_IVG_CLR(i);
      *pSIC_IAR1 &= PX_IVG_CLR(i+8);
      *pSIC_IAR2 &= PX_IVG_CLR(i+16);
      *pSIC_IAR3 &= PX_IVG_CLR(i+24);
      *pSIC_IAR4 &= PX_IVG_CLR(i+32);
      *pSIC_IAR5 &= PX_IVG_CLR(i+40);
      *pSIC_IAR6 &= PX_IVG_CLR(i+48);
   }
}

После вызова ClearIVG Вы сможете назначать свои собственные уровни приоритетов прерывания различным устройствам, программируя содержимое регистров SIC_IARx (см. далее шаг 3).

Шаг 2. Написание обработчика прерывания (ISR, Interrupt Service Routine). Для каждого используемого прерывания должна быть написана специальная подпрограмма, которая будет вызвана при срабатывании прерывания, ISR. Пример ISR на языке C/C++:

EX_INTERRUPT_HANDLER(Timer_ISR)
{
   *pTIMER_STATUS = TIMIL0;
   TOGGLE_LED();
   long_time_counter++;
}

В этом примере для определения тела обработчика прерывания используется макрос EX_INTERRUPT_HANDLER. В качестве параметра макроса указан текстовый идентификатор, который и будет именем созданной подпрограммы обработчика. Можно также использовать макрос EX_REENTRANT_HANDLER, который в отличие от первого позволяет вложенность прерываний (макрос EX_REENTRANT_HANDLER сразу разрешает внутри себя прерывания, что позволяет выполниться прерываниям с более высоким приоритетом). Подробнее про обработчики прерывания и про вложенность прерываний см. [1].

Для завершения обработки прерывания простого вызова ISR недостаточно. Кроме обработки события, в ISR должен быть код для сбрасывания флага, который вызвал срабатывание прерывания. Если этот флаг не сбросить, то ISR будет вызываться бесконечно, не давая выполняться основному коду программы. В данном примере сброс флага прерывания делает первая строка обработчика, записывающая константу TIMIL0 в регистр состояния таймера TIMER_STATUS.

Примечание: для каждого аппаратного устройства сброс условия возникновения прерывания делается по-разному, за конкрентной информацией следует обратиться к даташиту на процессор. Но обычно это операция типа W1C, т. е. для сброса флага нужно по маске записать в него единицу. В данном примере как раз такой случай. Кроме того, на один обработчик ISR может быть навешена обработка нескольких событий, тогда обработчик должен выборочно делать проверку и сброс нужных флагов состояния.

Шаг 3. Установка приоритета прерывания. На этом шаге делается настройка регистра SIC_IARx с помощью макроса PX_IVG (ID_периферийного_устройства, приоритет), чем определенному устройству процессора назначается нужный приоритет прерывания. Пример:

#define Timer0_Peripheral  16       //Peripheral Interrupt ID
#define Timer0_Priority    ik_ivg7  //приоритет, который будет использоваться для ISR таймера 0
*pSIC_IAR2 |= PX_IVG (Timer0_Peripheral, Timer0_Priority);

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

Peripheral Interrupt ID. Первая строка в этом примере просто создает удобочитаемое имя для идентификатора аппаратуры TIMER0. Все эти идентификаторы жестко заданы, и это обычно целое число от 0 до 50. Привязка чисел определяется архитектурой (т. е. типом процессора, например для процессора ADSP-BF532 используется архитектура Edinburgh, у процессора ADSP-538 используется  Stirling и т. п.). Идентификаторы аппаратуры можно подсмотреть в даташите на процессор (для процессора ADSP-BF538 также см. таблицу 4-7 в статье [1]).

ik_ivg7. В нашем примере для таймера назначается уровень приоритета ik_ivg7. Это самый высокий приоритет для аппаратных устройств. Всего для аппаратуры обычно используют уровни прерываний от IVG7 до IVG13 (у IVG7 самый высокий приоритет, у IVG13 самый низкий). Имена для числовых уровней приоритетов прерываний, в том числе и ik_ivg7, определены в перечислении interrupt_kind заголовочного файла Blackfin\include\sys\exception.h (находится в каталоге установки VisualDSP). Подробнее про приоритеты прерываний см. [1].

SIC_IARx. Регистры SIC_IARx (вместо x может быть подставлена цифра от 0 до 6 включительно) определяют привязку прерываний периферии к набору прерываний общего назначения ядра (general-purpose core interrupts) IVG7 – IVG15. Привязка определяет приоритет обработки для Interrupt A (в зависимости от того к какому из IVG7 – IVG15 оно привязано). Подробнее про регистры SIC_IARx см. [1].

Почему используется именно регистр SIC_IAR2, а не какой-либо другой? Это потому, что все аппаратные устройства жестко распределены по тетрадам семи регистров SIC_IARx (x = 0 .. 6), и TIMER 0 привязан к младшей тетраде (биты 3..0) регистра SIC_IAR2. В тетраду записывается уровень приоритета прерывания. Так как есть всего 7 регистров SIC_IARx, в каждом из которых 8 тетрад, то всего может быть определено 8 * 7 = 56 привязок приоритетов прерываний для всех имеющихся аппаратных устройств.

PX_IVG. Это макрос, который поместит приоритет прерывания в нужную тетраду регистра SIC_IARx, и вернет маску, которую уже можно записать в регистр (операцией наложения по ИЛИ). Макрос PX_IVG определен в файле Blackfin\include\defBF532.h (находится в каталоге установки VisualDSP).

Шаг 4. Регистрация обработчика прерывания, который был написан на шаге 2. Пример:

register_handler(Timer0_Priority, Timer_ISR);

Здесь используется вызов функции register_handler, которая в качестве параметров принимает приоритет прерывания (Timer0_Priority) и адрес обработчика прерывания (Timer_ISR). Также можно использовать функцию register_handler_ex, подробнее см. [2].

Шаг 5. Разрешение прерывания. Это делается установкой нужного бита в одном из регистров маски SIC_IMASKx. Пример:

*pSIC_IMASK0 |= TIMER0_IRQ;

Всего имеется два регистра маски прерывания, SIC_IMASK0 и SIC_IMASK1. Отдельные биты этих регистров жестко привязаны к конкретным аппаратным устройствам, которые могут генерировать прерывания. Маски для этих бит для процессоров Blackfin определены в заголовочных файлах defBFxxx.h находящихся в каталоге Blackfin\include\. Например, для процессора ADSP-BF532 следует использовать заголовочный файл Blackfin\include\defBF532.h.

Подробнее про маски прерываний см. врезку с описанием регистров SIC_IMASKx в статье [1].

[Ссылки]

1. ADSP-BF538: обработка событий (прерывания, исключения).
2. VisualDSP: функции установки обработчиков прерываний Blackfin.

 

Добавить комментарий


Защитный код
Обновить

Top of Page