Программирование DSP ADSP-BF538: таймеры Sun, November 10 2024  

Поделиться

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

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


ADSP-BF538: таймеры Печать
Добавил(а) microsin   

В процессоре Blackfin ADSP-BF538 есть 3 разновидности устройств, которые относятся к отсчету реального времени (привязанного к либо к частоте ядра, либо к частоте системной шины). Это сторожевой таймер (WatchDog Timer), счетчик тактов ядра (core timer) и обычные таймеры (так называемые программируемые таймеры общего назначения, general-purpose programmable timer). В этой статье приведен перевод раздела "Timers" из даташита [1]. Все непонятные термины и сокращения см. в разделе "Словарик", в конце статьи.

Сторожевой таймер [2] применяется для генерации события (или перезагрузки) процессора, если программа зависла.

Обычные таймеры (их 3 штуки) могут генерировать прерывания для процессора, чтобы создать периодические события для синхронизации, или могут генерировать тактовые частоты для электронного устройства, или могут использоваться для подсчета внешних импульсов. Обычные таймеры имеют внешний вывод на корпусе, который может быть сконфигурирован либо как модулятор ШИМ (PWM), либо как выход генерируемой частоты, либо как вход для тактовой частоты таймера, либо для работы механизма измерения длительности и периода внешних событий. Эти таймеры могут тактироваться либо от внешнего сигнала, поданного на вывод PF1 (TACLK), либо от внешнего сигнала, поданного на вывод PPI_CLK (TMRCLK), либо от внутреннего сигнала тактирования системной шины SCLK. Обычные таймеры также могут использоваться для функции автодетекта скорости UART0 - измеряются длительности импульсов потока данных последовательного канала.

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

[Таймеры общего назначения (General-Purpose Timers)]

В процессоре ADSP-BF538 имеются 3 таймера общего назначения (далее просто таймер), каждый из которых может быть индивидуально сконфигурирован в один из 3 режимов:

• Режим генерации ШИМ (Pulse-width modulation, PWM_OUT).
• Режим подсчета длительности импульса и захвата (WDTH_CAP).
• Режим подсчета внешних событий (External event, EXT_CLK).

В таблице ниже перечислены внешние сигналы таймеров.

Сигнал Тип Шарик Описание
TMR2 I/O K2 В зависимости от режима таймера может работать как выход (генерация ШИМ, тактовых частот) или как вход (измерение длительности и периода импульсов, подсчет внешних событий).
TMR1 L2
TMR0 M2
PF1 I E1 Альтернативный тактовый вход для счетчиков таймеров общего назначения.
PPI_CLK I A4 Внешняя опорная частота для таймеров.

У каждого из таймеров есть один выделенный двунаправленный вывод корпуса, TMRx. Этот вывод может работать либо как выход в режиме PWM_OUT, либо как вход в режимах WDTH_CAP и EXT_CLK. Для обеспечения этих функций каждый таймер имеет по 4 регистра MMR.

ADSP BF538 Timer Block Diagram fig16 1

Рис. 16-1. Блок-диаграмма таймера.

Вот полный список регистров таймера:

• Регистр конфигурации (TIMERx_CONFIG).
• Счетчик таймера (TIMERx_COUNTER).
• Период таймера (TIMERx_PERIOD).
• Ширина импульса таймера (TIMERx_WIDTH).

Для обеспечения диапазона счета и точности следующие регистры сделаны 32-битными (см. рис. 16-1): TIMERx_COUNTER, TIMERx_PERIOD и TIMERx_WIDTH.

Примечание: вместо x подставляется число 0, 1 или 2 - в зависимости от выбранного таймера.

Когда таймер тактируется от внутреннего сигнала, для то используется тактовая частота периферийных устройств процессора (она же частота системной шины SCLK). Предположим, что SCLK = 133 МГц, тогда максимальный период для счета таймера составит ((2^32-1) / 133 MHz) = 32.2 секунды.

Регистр разрешения таймеров (TIMER_ENABLE) может использоваться для разрешения работы всех 3 таймеров одновременно. В регистре содержится 3 бита управления, работающие по принципу "write-1-to-set" (записать лог. 1 для установки), по одному для каждого таймера. Соответственно, регистр запрещения таймеров (TIMER_DISABLE) содержит 3 бита управления типа "write-1-to-clear", которыми можно одновременно запретить все 3 таймера. Оба этих регистра могут быть прочитаны, чтобы определить текущее состояния разрешения таймеров: лог. 1 показывает, что соответствующий таймер разрешен. Таймер запускается по истечении 3 тактовых циклов SCLK после того, как установлен бит TIMENx. Все неиспользуемые биты читаются как 0.

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

ADSP BF538 TIMER ENABLE

Рис. 16-2. Регистр TIMER_ENABLE.

TIMEN2, TIMEN1, TIMEN0. Регистр TIMER_DISABLE содержит 3 бита запрета таймеров, работающие по принципу W1C ("write-1-to-clear", т. е. записать лог. 1 для очистки). Запись лог. 1 запрещает соответствующий таймер, запись лог. 0 не оказывает никакого действия. Каждый из битов может быть очищен индивидуально, или одновременно в любой комбинации. Чтение регистра TIMER_DISABLE возвратит тот же результат, что и чтение TIMER_ENABLE: лог. 1 показывает, что соответствующий таймер разрешен. Все неиспользуемые биты читаются как 0.

ADSP BF538 TIMER DISABLE

Рис. 16-3. Регистр TIMER_DISABLE.

TIMDIS2TIMDIS1TIMDIS0. В режиме PWM_OUT запись лог. 1 в биты регистра TIMER_DISABLE не остановит немедленно соответствующий таймер. Вместо этого таймер продолжит счет, и остановится по окончании текущего формируемого периода (если PERIOD_CNT = 1) или импульса (если PERIOD_CNT = 0). Если нужно, процессор может принудительно остановить таймер в режиме PWM_OUT путем первоначальной записи лог. 1 в соответствующий бит TIMER_DISABLE, и затем записью лог. 1 в соответствующий бит TRUNx регистра TIMER_STATUS. Подробнее см. раздел "Остановка таймера в режиме PWM_OUT".

В режимах WDTH_CAP и EXT_CLK запись лог. 1 в биты TIMER_DISABLE немедленно остановит соответствующий таймер.

Регистр состояния таймера (TIMER_STATUS) показывает состояние всех 3 таймеров, и используется для проверки статуса всех 3 таймеров за одну операцию чтения (см. рис. 16-4). Биты статуса являются "липкими" (sticky), и работают по принципу W1C ("Write 1 Clear", запись 1 очищает бит). Биты TRUNx могут очиститься самостоятельно, что происходит, когда таймер в режиме PWM_OUT mode останавливается по окончании периода. При доступе к регистру состояния на чтение все неиспользуемые биты читаются как 0.

Каждый таймер генерирует уникальный сигнал запроса на прерывание, который пропускается соответствующим битом IRQ_ENA в регистре TIMERx_CONFIG. Общий регистр состояния TIMER_STATUS защелкивает эти прерывания, так что пользователь может определить источник прерывания без ссылки на уникальный сигнал прерывания (например, в случае, если все 3 таймера назначены на одинаковый приоритет прерывания). Биты прерывания являются "липкими", и должны очищаться обработчиком прерывания (interrupt service routine, ISR), чтобы гарантировать, что прерывание не было выставлено заново.

Биты TIMILx работают вместе с битом IRQ_ENA регистра конфигурации TIMERx_CONFIG, показывая запросы прерывания. Если произошло условие прерывания или ошибка и бит IRQ_ENA установлен, то бит TIMILx установится и будет выставлено прерывание для ядра. Это прерывание может быть замаскировано системными контроллерами прерываний (system interrupt controller, SIC). Если произошло событие прерывания или ошибка, и бит IRQ_ENA очищен, то бит TIMILx не установится и прерывание не будет выставлено. Если бит TIMILx уже установлен, и в бит IRQ_ENA записан 0, то биты TIMILx останутся установленными, и прерывание останется выставленным. См. рис. 16-24.

ADSP BF538 TIMER STATUS

Рис. 16-4. Регистр TIMER_STATUS.

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

TRUN2, TRUN1, TRUN0. Это биты разрешения состояния Slave Enable, работающие по принципу W1C. Запись 1 немедленно остановит таймер в режиме PWM_OUT.

TOVF_ERR2, TOVF_ERR1, TOVF_ERR0. Это биты ошибки, сигнализирующие о переполнении счетчика таймера (Timer Counter Overflow), работающие по принципу W1C. Бит сигнализирует о переполнении счетчика таймера или о событии ошибки.

TIMIL2, TIMIL1, TIMIL0. Это флаги, сигнализирующие о запросе прерывания таймера, если бит IRQ_ENA установлен. Также работают по принципу W1C.

Прочитанное значение битов TRUNx отражает состояние timer slave enable во всех режимах — установленные TRUNx говорят о том, что режим запущен, и очищенное состояние TRUNx показывает остановленный режим. В то время как чтение битов TIMENx или TIMDISx биты в регистрах TIMER_ENABLE и TIMER_DISABLE отражает состояние таймера - разрешен он или нет, биты TRUNx показывают, считает таймер или нет. В режимах WDTH_CAP и EXT_CLK чтение из TIMENx и TRUNx всегда возвратят одинаковое значение.

Операция W1C для регистра TIMER_DISABLE запрещает соответствующий таймер во всех режимах. В режиме PWM_OUT запрещенный таймер продолжает считать, пока генерируемый период (PERIOD_CNT = 1) или импульс (PERIOD_CNT = 0) не будет сформирован до конца. Во время этого завершающего периода TIMENx читается как 0, но бит TRUNx все еще читается как 1. (см. рис. 16-10). Только в этом состоянии TRUNx становится битом W1C. Во время этого завершающего периода периода с запрещенным таймером запись лог. 1 в TRUNx очистит TRUNx и немедленно остановит таймер без ожидания завершения счета текущего цикла формирования периода или импульса.

Запись в биты TRUNx не дает никакого эффекта в других режимах, или когда таймер не разрешен. Запись битов TRUNx в 1 в режиме PWM_OUT не дает эффекта на таймере, который не был предварительно запрещен.

Рабочий режим для каждого таймера указывается его регистром конфигурации (timer configuration register, TIMERx_CONFIG), как показано на рис. 16-5. Регистр TIMERx_CONFIG может быть записан только когда таймер не считает. После запрета таймера в режиме PWM_OUT убедитесь, что таймер на самом деле остановлен путем проверки его бита TRUNx в регистре TIMER_STATUS, перед попыткой перепрограммировать TIMERx_CONFIG. Регистры TIMERx_CONFIG могут быть прочитаны в любое время. Поле ERR_TYP работает только на чтение. Оно очищается и сбрасывается, когда таймер разрешается. Каждый раз, когда устанавливается TOVF_ERRx, поле ERR_TYP[1:0] загружается кодом, который идентифицирует код детектированной ошибки. Это значение удерживается до появления следующей ошибки или разрешения таймера. Обзор условий ошибки см. в таблице 16-1. Регистр TIMERx_CONFIG также управляет поведением вывода TMRx, который становится выходом в режиме PWM_OUT (TMODE = 01), когда очищен бит OUT_DIS.

ADSP BF538 TIMERx CONFIG

Рис. 16-5. Регистры TIMERx_CONFIG.

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

ERR_TYP[0:1]. Биты типа ошибки, предназначенные только для чтения. 00: нет ошибки, 01: ошибка переполнения счетчика таймера, 10: ошибка программирования регистра периода, 11: ошибка программирования регистра ширины импульса.

EMU_RUN. Бит выбора поведения таймера при работе процессора в режиме эмуляции (отладки). Если 0, то в режиме эмуляции таймер останавливает счет (состояние по умолчанию). Если 1, то в режиме эмуляции таймер не останавливает счет.

TOGGLE_HI. Бит выбора режима переключения PULSE_HI режима PWM_OUT. Если 0, то эффективное состояние PULSE_HI будет запрограммированным. Если 1, то эффективное состояние PULSE_HI меняется с каждым периодом.

CLK_SEL. Бит выбора тактирования счетчика таймера. 0: для тактирования используется SCLK, 1: для тактирования используется вывод PWM_CLK.

OUT_DIS. Бит запрета выхода. 0: в режиме PWM_OUT выход таймера разрешен, 1: запрещен.

TIN_SEL. Бит выбора входа таймера. 0: оцифровывается сигнал с вывода TMRx или PF1, 1: оцифровывается сигнал UART RX или PPI_CLK.

IRQ_ENA. Бит разрешения запроса прерывания (Interrupt Request Enable). 0: запрос на прерывания запрещен, 1: разрешен.

PERIOD_CNT. Бит выбора окончания счета. 0: счетчик считает до конца ширины импульса. 1: счетчик считает до конца периода импульса, этот вариант в режиме формирования PWM (ШИМ) позволяет формировать на выходе TMRx непрерывную частоту аппаратно, без всякого вмешательства ядра процессора.

PULSE_HI. Бит выбора активного перепада импульса. Если PULSE_HI=0: активный отрицательный импульс, таймер начинает период счета с TMRx=0, и заканчивает период счета с TMRx=1. 1: положительный. Если PULSE_HI=1: активный положительный импульс, таймер начинает период счета с TMRx=1, и заканчивает период счета с TMRx=0.

TMODE[1:0]. Биты выбора режима работы таймера. 00: состояние после сброса (таймер не используется), 01: режим PWM_OUT, 10: режим WDTH_CAP, 11: режим EXT_CLK.

Эти регистры, предназначенные только для чтения, содержат значение счетчика, когда таймер запрещен (см. рис. 16-6). Когда таймер разрешен, регистр TIMERx_COUNTER реинициализируется аппаратно по принципу, основанному на конфигурации и режиме. Регистр TIMERx_COUNTER может быть прочитан в любой момент времени (независимо от того, считает таймер или остановлен), и чтение вернет когерентное 32-битное значение. В зависимости от режима работы инкремент счетчика может тактироваться от 4 разных источников: SCLK, вывода TMRx, вывод GPIO-порта PF1, или такты параллельного порта PPI_CLK.

Когда к ядру процессора осуществляется доступ со стороны внешнего эмулятора-отладчика (через JTAG), выполнение кода останавливается. По умолчанию TIMERx_COUNTER также приостанавливает счет во время доступа эмуляции, чтобы оставаться синхронным с программным обеспечением. Будучи остановленным, счетчик не достигает пределов счета — в режиме PWM_OUT сигнал на выводе TMRx получается "растянутым"; в режиме WDTH_CAP измеренные величины длительностей оказываются некорректными; в режиме EXT_CLK могут быть пропущены события по входу на выводе TMRx. Все другие функции таймера, такие как чтение и запись регистров, ранее выставленные прерывания (если они не были очищены), и загрузка TIMERx_PERIOD и TIMERx_WIDTH в режиме WDTH_CAP остаются активными при остановке во время эмуляции.

Некоторые приложения могут требовать асинхронного продолжения счета таймера при остановке ядра из-за отладки. Такое поведение будет разрешено установкой бита EMU_RUN в регистре TIMERx_CONFIG.

ADSP BF538 TIMERx COUNTER

Рис. 16-6. Регистры TIMERx_COUNTER.

Timer Counter[31:0]. Регистр, отражающий содержимое счетчика таймера.

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

Использование регистров TIMERx_PERIOD и TIMERx_WIDTH (см. рисунки 16-7 и Figure 16-8) меняется в зависимости от режима работы таймера:

• В режиме ШИМ (PWM_OUT) значения обоих регистров, TIMERx_PERIOD и TIMERx_WIDTH, могут быть обновлены "на лету", так что регистры периода таймера и ширины импульса таймера (скважность, duty cycle) изменяются одновременно.

• В режиме захвата ширины импульса и периода (WDTH_CAP), буферизованные значения периода таймера и ширины импульса таймера захватываются в подходящее время. Тогда регистры TIMERx_PERIOD и TIMERx_WIDTH обновляются одновременно из своих соответствующих буферов. В этом режиме оба регистра предназначены только для чтения.

• В режиме захвата события (EXT_CLK), регистр TIMERx_PERIOD можно записывать, и он может быть обновлен "на лету". Регистр TIMERx_WIDTH не используется.

Если новые значения не записаны в регистр TIMERx_PERIOD или TIMERx_WIDTH, то заново используются значения из предыдущего периода. Записи в 32-битные регистры TIMERx_PERIOD и TIMERx_WIDTH являются атомарными; невозможна ситуация, когда старшее слово записано без записи младшего слова.

Значения, записанные в регистры TIMERx_PERIOD или TIMERx_WIDTH, всегда сохраняются в буферные регистры. Чтения из регистров TIMERx_PERIOD или TIMERx_WIDTH всегда вернут текущее, активное значение периода или ширины импульса. Записанные значения не будут прочитаны обратно, пока они не станут активными. Когда таймер разрешен, они не станут активными, пока не будут обновлены регистры TIMERx_PERIOD и TIMERx_WIDTH из соответствующих буферов в момент окончания текущего периода (см. рис. 16-1).

Когда таймер запрещен, записи в буферные регистры немедленно копируются через регистр TIMERx_PERIOD или TIMERx_WIDTH, так что они будут готовы для использования в первый период таймера. Например, для изменения значений для регистров TIMERx_PERIOD и/или TIMERx_WIDTH в порядке использования различных установок для каждых первых 3 периодов после того, как таймер разрешен, процедура должна быть следующей:

1. Запрограммируйте первый набор значений регистров.
2. Разрешите таймер.
3. Немедленно запрограммируйте второй набор значений регистров.
4. Подождите первое прерывание таймера.
5. Запрограммируйте третий набор значений регистров.

Каждая новая установка будет тогда запрограммирована, когда произойдет прерывание таймера.

В режиме PWM_OUT с очень малыми периодами (меньше чем 10 отсчетов), может не хватить времени для записи обоих регистров TIMERx_PERIOD и TIMERx_WIDTH между обновлением из буферных регистров. Следующий период может использовать одно старое значение и одно новое значение. Чтобы предотвратить ошибки, что ширина импульса будет >= периода, записывайте регистр TIMERx_WIDTH перед регистром TIMERx_PERIOD, когда значения уменьшаются, и записывайте регистр TIMERx_PERIOD перед регистром TIMERx_WIDTH, когда значения увеличиваются.

ADSP BF538 TIMERx PERIOD

Рис. 16-7. Регистры TIMERx_PERIOD.

Timer Period[31:0]. Регистр программирования периода таймера.

ADSP BF538 TIMERx WIDTH

Рис. 16-8. Регистры TIMERx_WIDTH.

Timer Width[31:0]. Регистр программирования ширины импульса таймера.

[Как использовать таймеры общего назначения]

Чтобы разрешить отдельный таймер, установите бит TIMEN таймера в регистре TIMER_ENABLE. Чтобы запретить отдельный таймер, установите бит TIMDIS в регистре TIMER_DISABLE. Чтобы разрешить все 3 таймера параллельно, установите все 3 бита TIMEN в регистре TIMER_ENABLE.

Перед разрешением таймера всегда программируйте соответствующий регистр конфигурации таймера (TIMERx_CONFIG). Этот регистр определяет режим работы таймера, полярность вывода TMRx и поведение прерывания таймера. Не меняйте рабочий режим, пока таймер считает.

Примеры интервалов времени разрешения и запрещения таймеров имеются на рисунках 16-9, 16-10 и 16-11.

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

ADSP BF538 Timer Enable Timing fig16 9

Рис. 16-9. Пример диаграммы времени разрешения таймера (PWM_OUT MODE, PERIOD_CNT = 1).

ADSP BF538 Timer Disable Timing fig16 10

Рис. 16-10. Пример диаграммы времени запрещения таймера (PWM_OUT MODE, PERIOD_CNT = 1).

ADSP BF538 Timer Enable and AutoDisable Timing fig16 11

Рис. 16-11. Пример диаграммы времени разрешения и автозапрещения таймера (PWM_OUT MODE, PERIOD_CNT = 0).

Установка поля TMODE в значение 01 в регистре конфигурации таймера (TIMERx_CONFIG) разрешает режим PWM_OUT. В режиме PWM_OUT вывод TMRx таймера становится выходом. Выход может быть запрещен путем установки бита OUT_DIS в регистре конфигурации таймера.

В режиме PWM_OUT биты PULSE_HI, PERIOD_CNT, IRQ_ENA, OUT_DIS, CLK_SEL, EMU_RUN и TOGGLE_HI разрешают ортогональную функциональность. Они могут быть установлены индивидуально или в любой комбинации, хотя некоторые комбинации являются бесполезными (такие как TOGGLE_HI = 1 с OUT_DIS = 1 или PERIOD_CNT = 0), см. рис. 16-12.

Как только таймер разрешен, регистр счетчика таймера загружается стартовым значением. Если CLK_SEL = 0, то счетчик таймера начнет счет с 0x1. Если CLK_SEL = 1, счетчик сбросится в 0x0 как в режиме EXT_CLK. Счетчик считает вверх до значения в регистре TIMERx_PERIOD. Для любой установки бита CLK_SEL, когда счетчик таймера равен периоду таймера, счетчик таймера сбросится в 0x1 на следующем такте.

ADSP BF538 Timer Flow Diagram PWM OUT fig16 12

Рис. 16-12. Алгоритм работы таймера в режиме PWM_OUT.

В режиме PWM_OUT бит PERIOD_CNT управляет, генерирует ли таймер один импульс или много импульсов. Когда PERIOD_CNT очищен (режим одиночного импульса PWM_OUT), таймер использует регистр TIMERx_WIDTH, генерирует один положительный и один отрицательный перепад, затем генерирует прерывание (если оно разрешено) и останавливается. Когда PERIOD_CNT установлен (режим продолжающихся импульсов PWM_OUT), таймер использует оба регистра TIMERx_PERIOD и TIMERx_WIDTH и генерирует повторяющиеся (и возможно модулированные) периоды сигнала. Таймер генерирует прерывание (если оно разрешено) по окончании каждого периода и останавливается только после того, как таймер будет запрещен. Установка PERIOD_CNT = 0 задает счет до конца ширины; установка PERIOD_CNT = 1 задает счет до конца периода.

В некоторых режимах регистры TIMERx_PERIOD и TIMERx_WIDTH работают только на чтение. Убедитесь, что поле TMODE регистра TIMERx_CONFIG установлено в значение b#01 перед записью в эти регистры.

Запрет выхода ШИМ (Output Pad Disable). Выходная ножка ШИМ может быть запрещена в режиме PWM_OUT установкой бита OUT_DIS в регистре конфигурации таймера. Тогда вывод TMRx переходит в третье (отключенное) состояние независимо от установки PULSE_HI и TOGGLE_HI. Это может уменьшить энергопотребление, когда выходной сигнал не используется.

Генерация одиночного импульса (Single Pulse Generation). Если очищен бит PERIOD_CNT, режим PWM_OUT генерирует одиночный импульс на выводе TMRx. Этот режим может использоваться также для реализации точной задержки. Ширина импульса задается регистром TIMERx_WIDTH, и регистр TIMERx_PERIOD при этом не используется.

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

Генерация сигналов с помощью ШИМ (Pulse-Width Modulation Waveform Generation). Если бит PERIOD_CNT установлен, тактируемый внутренне таймер генерирует прямоугольные сигналы с четко определенным периодом и скважностью. Этот режим также генерирует периодические прерывания для обработки сигналов в реальном времени.

32-битные регистры (TIMERx_PERIOD) и (TIMERx_WIDTH) программируются значениями периода счета таймера и шириной импульса с модулированной шириной импульса.

Когда таймер разрешен в этом режиме, вывод TMRx притягивается к 0 каждый раз, когда счетчик таймера становится равным регистру TIMERx_WIDTH, и вывод переходит в 1, когда период истечет (или когда стартует таймер).

Чтобы управлять полярностью установки вывода TMRx, используется бит PULSE_HI в соответствующем регистре TIMERx_CONFIG. Для низкого устанавливаемого уровня очистите этот бит. Для высокого устанавливаемого уровня установите этот бит. Когда таймер в режиме PWM_OUT запрещен, вывод TMRx переходит в не установленное состояние.

Если таймер разрешен, то генерируется прерывание таймера по окончании каждого периода. ISR должен очистить бит защелки прерывания (TIMILx) и может изменить значения периода и/или ширины импульса. В приложениях ШИМ (pulse-width modulation, PWM) программное обеспечение должно обновлять значения периода и ширины импульса во время счета таймера. Когда программа обновляет регистры периода или ширины импульса, новые значения удерживаются до момента окончания текущего периода. После этого новые значения периода и ширины импульса немедленно становятся активными. Новые значения регистров TIMERx_PERIOD и TIMERx_WIDTH записываются, когда используются старые значения. Новые значения загружаются для использования, когда значение счетчика становится равным текущему значению периода. Чтения из регистров TIMERx_PERIOD и TIMERx_WIDTH возвратят старые значения, пока не истечет текущий период.

Бит состояния TOVF_ERRx обозначает событие ошибки в режиме PWM_OUT. Бит TOVF_ERRx устанавливается, если при запуске TIMERx_PERIOD = 0 или TIMERx_PERIOD = 1, или когда переполняется регистр счетчика таймера. Бит также устанавливается, когда регистр счетчика таймера переполняется, если регистр TIMERx_WIDTH больше или равен регистру TIMERx_PERIOD. Биты ERR_TYP устанавливаются, когда устанавливается бит TOVF_ERRx.

Для генерации максимальной частоты на выводе выхода TMRx установите значение периода 2 и ширину импульса в 1. В результате TMRx будет переключаться с каждым тактом SCLK, скважность импульсов (duty cycle) составит 50%. Период можно программировать на любое значение от 2 до (2^32 – 1) включительно. Ширина импульса может быть запрограммирована в диапазоне от 1 до (период – 1) включительно. Когда PERIOD_CNT = 0, ширина импульса может быть запрограммирована в любое значение от 1 до (2^32 – 1) включительно.

Хотя аппаратура сообщит об ошибке, если значение TIMERx_WIDTH станет равным значению TIMERx_PERIOD, это все равно допустимое функционирование для реализации ШИМ со скважностью цикла 100%. В этом случае программа должна просто игнорировать флаги TOVL_ERRx. Значения ширины импульса больше чем значение периода не рекомендуются. Точно так же TIMERx_WIDTH = 0 не допустимая операция. Скважности 0% не поддерживаются.

Остановка таймера в режиме PWM_OUT. Во всех вариантах режима PWM_OUT, таймер обрабатывает операцию запрета (W1C для регистра TIMER_DISABLE) как условие "запроса на остановку". Когда таймер запрещен в режиме PWM_OUT, он автоматически завершит формирование текущей формы сигнала и корректно остановится. Это предотвратит обрезку текущего импульса и нежелательные формы сигнала ШИМ на выводе TMRx. Процессор может определить, когда таймер остановил счет, путем опроса соответствующего бита TRUNx в регистре TIMER_STATUS, когда он стал равен 0, или ожиданием последнего прерывания (если прерывания разрешены). Обратите внимание, что таймер не может быть реконфигурирован (в регистр TIMERx_CONFIG нельзя записать новое значение), пока таймер не остановит счет, и TRUNx не будет читаться как 0.

В режиме PWM_OUT с одиночным импульсом (PERIOD_CNT = 0), не требуется записать регистр TIMER_DISABLE для остановки таймера. По окончании импульса таймер остановится автоматически, соответствующий бит в регистре TIMER_ENABLE (и конечно TIMER_DISABLE) очистится, и соответствующий бит TRUNx также очистится, см. рис. 16-11. Чтобы генерировать несколько импульсов, запишите 1 в регистр TIMER_ENABLE, ждите остановки таймера, затем запишите другую 1 в регистр TIMER_ENABLE.

Если это необходимо, процессор может выполнить принудительную остановку таймера в режиме PWM_OUT. Чтобы сделать это, нужно сначала записать 1 в соответствующий бит регистра TIMER_DISABLE, и затем записать 1 в соответствующий бит TRUNx регистра TIMER_STATUS. Это остановит таймер в любом случае - независимо от того, было ли ожидание конца текущего периода (PERIOD_CNT = 1) или конца текущей ширины импульса (PERIOD_CNT = 0). Эта возможность может использоваться, чтобы вернуть непосредственный контроль над таймером во время последовательности восстановления из состояния ошибки.

Используйте эту возможность с осторожностью, потому что она может нарушить формирование сигнала ШИМ, генерируемого на выводе TMRx.

В режиме продолжения генерации импульсов PWM_OUT (PERIOD_CNT = 1) каждый таймер опрашивает бит TIMENx по окончании каждого периода. Таймер остановится чисто, по окончании первого периода, когда TIMENx окажется в лог. 0. Это подразумевает (при запрещении любых W1C в TRUNx), что таймер, который запрещается и затем заново разрешается перед окончанием текущего периода, продолжит счет, если ничего не случится. Обычно программа должна запретить таймер в режиме PWM_OUT и затем ждать, пока он сам не остановится. Таймер всегда останавливается по окончании первого импульса, когда PERIOD_CNT = 0.

PWM_OUT, тактируемый внешне. По умолчанию таймер тактируется от внутренней частоты шины SCLK. Альтернативно, если установлен бит CLK_SEL в регистре конфигурации (TIMERx_CONFIG), то таймер тактируется от PWM_CLK. Сигнал PWM_CLK нормально является входом, совмещенным с выводом порта PF1, однако также может получать сигнал от вывода PPI_CLK, когда таймеры сконфигурированы для работы с PPI. Различные таймеры могут получать различные сигналы от своих входов PWM_CLK, в зависимости от настроенной конфигурации. Как выбирается битом PERIOD_CNT, режим PWM_OUT либо генерирует сигнал ШИМ, либо генерирует одиночный импульс шириной, определяемой регистром TIMERx_WIDTH.

Когда установлен CLK_SEL, счетчик сбрасывается в 0x0 при старте и инкрементируется по каждому фронту PWM_CLK. Переходы на выводе TMRx происходят по фронтам PWM_CLK. Нет никакого способа выбрать спады сигнала PWM_CLK. В этом режиме бит PULSE_HI управляет только полярностью генерируемых импульсов.

Прерывание таймера может произойти немного перед соответствующим перепадом на выводе TMRx (прерывание происходит по перепаду SCLK, в то время как переходы происходят позже, по перепаду фронта PWM_CLK). Можно все еще безопасно запрограммировать новый период и ширину импульса, как только произойдет прерывание. После того, как период истечет, счетчик переваливает через значение 0x1.

Форма сигнала тактов PWM_CLK не обязательно должна иметь скважность 50%, однако минимально время низкого уровня PWM_CLK должно быть не менее одного периода SCLK, и минимальное время высокого уровня PWM_CLK должно быть не менее одного периода SCLK. Таким образом, максимальная частота тактов PWM_CLK не может быть выше SCLK/2.

Вывод PF1 может тактировать таймер только тогда, когда PF1 работает как вход. Когда любой таймер находится в режиме PWM_OUT с CLK_SEL = 1 и TIN_SEL = 0, то бит PF1 в регистре FIO_DIR игнорируется и PF1 принудительно становится входом.

Форма сигнала режима PWM_OUT с PERIOD_CNT = 1 обычно имеет фиксированное время лог. 1 и программируемое (через регистр TIMERx_WIDTH) время лог. 0. Когда 2 таймера считают синхронно с одним и тем же установленным периодом, импульсы выровнены по фронту установки, как это показано на рис. 16-13.

Режим TOGGLE_HI разрешает управление временем перепада лог. 1 и лог. 0 для генерируемого периода выходного сигнала. Фаза между фронтом двух выходов таймера программируется. Эффективное состояние бита PULSE_HI меняется каждый период. Смежные активные импульсы лог. 0 и лог. 1, взятые вместе, составляют две половины сигнала полностью произвольной (однако прямоугольной) формы. Эффективная форма сигнала остается активной в лог. 1, когда PULSE_HI установлен, и активной в лог. 0, когда PULSE_HI очищен. Значение TOGGLE_HI не дает никакого эффекта за исключением случая, когда PWM_OUT и PERIOD_CNT = 1.

В режиме TOGGLE_HI, когда PULSE_HI установлен, активный импульс лог. 0 генерируется в первом, третьем, и во всех нечетных периодах, и активный импульс лог. 1 генерируется во втором, четвертом и всех четных периодах. Когда PULSE_HI очищен, активный импульс лог. 1 генерируется в первом, третьем и всех нечетных периодах, и активный импульс лог. 0 генерируется во втором, четвертом и всех четных периодах.

ADSP BF538 PWM Pulses Aligned Assert Edge fig16 13

Рис. 16-13. Таймеры с импульсами, выровненными по установленному перепаду.

Состояние лог. 0 по окончании одного периода соответствует состоянию лог. 1 на начале следующего периода, так что выходной сигнал меняется только при Count = Pulse Width (значение счетчика равно ширине импульса). Конечный результат - импульс выходного сигнала, который повторяется каждые 2 периода счетчика, и центрируется вокруг конца первого периода (или начала второго периода).

На рис. 16-14 показан пример 3 таймеров, считающих с одинаковой настройкой периода. Когда программа не меняет настройки PWM во время выполнения, скважность будет 50%. Значения регистров TIMERx_WIDTH управляют фазой между сигналами.

ADSP BF538 3Timers Same Period fig16 14

Рис. 16-14. Три таймера с одинаково установленным периодом.

Аналогично, 2 таймера могут генерировать не перекрывающиеся такты, путем выравнивания центров импульсов с инверсией полярности сигналов для одного из таймеров (см. рис. 16-15).

ADSP BF538 2Timers Non Overlapping Clocks fig16 15

Рис. 16-15. Два таймера с не перекрывающимися тактами.

Когда TOGGLE_HI = 0, программа обновляет регистры TIMERx_PERIOD и TIMERx_WIDTH один раз на период сигнала. Когда TOGGLE_HI = 1, программа обновляет регистры TIMERx_PERIOD и TIMERx_WIDTH дважды на период сигнала, который получается половинной длины. В нечетных периодах для получения выровненных по центру импульсов нужна запись (Period – Width) вместо Width в регистр TIMERx_WIDTH.

Например, когда TOGGLE_HI = 0, в псевдокоде это будет происходить так:

int period, width;
 
for (;;)
{
   period = generate_period(...);
   width = generate_width(...);
 
   waitfor (interrupt);
 
   write(TIMERx_PERIOD, period);
   write(TIMERx_WIDTH, width);
}

Тогда при TOGGLE_HI = 1 псевдокод был бы таким:

int period, width;
int per1, per2, wid1, wid2;
 
for (;;)
{
   period = generate_period(...);
   width = generate_width(...);
   
   per1 = period/2;
   wid1 = width/2;
   
   per2 = period/2;
   wid2 = width/2;
   
   waitfor (interrupt);
   
   write(TIMERx_PERIOD, per1);
   write(TIMERx_WIDTH, per1 - wid1);
   
   waitfor (interrupt);
   
   write(TIMERx_PERIOD, per2);
   write(TIMERx_WIDTH, wid2);
}

Как показано в этом примере, генерируемые импульсы не нуждаются в том, чтобы быть симметричными (переменная wid1 не обязательно должна быть равна wid2). Период может иметь смещение для подстройки фазы генерируемых импульсов (переменная per1 не обязательно должна быть равной per2).

Бит timer slave enable (бит TRUNx в регистре TIMER_STATUS) обновляется только по окончании четных периодов режима TOGGLE_HI. Когда TIMER_DISABLE записан в 1, текущая пара периодов счетчика (один период сигнала) завершается перед запретом таймера.

Как и при TOGGLE_HI = 0, будет сообщение об ошибках если: TIMERx_WIDTH >= TIMERx_PERIOD, TIMERx_PERIOD = 0, или TIMERx_PERIOD = 1.

В режиме WDTH_CAP вывод TMRx является входом (см. рис. 16-16). Таймер, тактируемый внутренней частотой шины, используется для определения периода и ширины импульса внешнего поступающего на TMRx прямоугольного сигнала. Установка поля TMODE в значение b#10 регистра TIMERx_CONFIG разрешает работу этого режима.

Когда таймер разрешен в режиме WDTH_CAP, таймер сбрасывает значение счетчика в регистре TIMERx_COUNTER на 0x00000001, и не стартует, пока не будет детектирован начальный перепад на выводе TMRx.   

ADSP BF538 Timer Flow Diagram WDTH CAP fig16 16

Рис. 16-16. Алгоритм работы таймера в режиме WDTH_CAP.

Когда таймер детектирует первый перепад, он начинает инкрементироваться. Когда детектирован завершающий перепад, таймер захватывает текущее 32-битное значение регистра TIMERx_COUNTER в регистр буфера ширины. На следующем начальном перепаде таймер передает текущее 32-битное значение регистра TIMERx_COUNTER в регистр буфера периода. Регистр счетчика снова сбрасывается в значение 0x00000001, и таймер продолжает счет и захват, пока не будет запрещен.

В этом режиме программа может измерить как ширину импульса, так и период входного сигнала. Чтобы управлять определением начального перепада и конечного перепада на выводе TMRx, устанавливается или очищается бит PULSE_HI в регистре TIMERx_CONFIG. Если бит PULSE_HI = 0, то измерение начинается по спаду уровня (переход 1 -> 0), регистр счетчика захватывается в буфер ширины импульса по нарастанию уровня (0 -> 1), и период захватывается по следующему спаду уровня. Когда PULSE_HI = 1, то все наоборот: измерение начинается по нарастанию уровня (переход 0 -> 1), регистр счетчика захватывается в буфер ширины импульса по спаду уровня (1 -> 0), и период захватывается по следующему нарастанию уровня. Таким образом, бит PULSE_HI в регистре TIMERx_CONFIG управляет полярностью входа TMRx.

В режиме WDTH_CAP одновременно возникают сразу 3 следующие события на одном из таймеров:

1. Регистр TIMERx_PERIOD обновляется из регистра буфера периода.
2. Регистр TIMERx_WIDTH обновляется из регистра буфера ширины импульса.
3. Бит защелкивания прерывания (TIMILx) будет установлен (если прерывание разрешено), но не будет генерировать ошибку.

Бит PERIOD_CNT в регистре TIMERx_CONFIG управляет моментом времени, в котором будет выполнен этот набор транзакций. Взятые вместе, эти три события называются измерительным отчетом (measurement report). Бит ошибки переполнения счетчика таймера (TOVF_ERRx) не будет установленным в момент наступления измерительного отчета. Измерительный отчет происходит самое большее 1 раз за 1 период входного сигнала.

Текущее значение счетчика таймера всегда копируется в регистры буфера ширины и периода соответственно в момент завершающего и начального перепадов входного сигнала, но эти значение невидимы со стороны программного обеспечения. Выборки события измерительного отчета попадают в видимые регистры и в этот момент устанавливается прерывание таймера, что сигнализирует о готовности новых значений в регистрах TIMERx_PERIOD м TIMERx_WIDTH. Когда установлен PERIOD_CNT, измерительный отчет происходит сразу после того, как регистр буфера периода захватит свое значение (в момент начального перепада сигнала). Когда PERIOD_CNT сброшен, измерительный отчет происходит сразу после того, как регистр буфера ширины импульса захватит свое значение (в момент конечного перепада сигнала).

Если бит PERIOD_CNT установлен, и произошел начальный перепад (см. рис. 16-17), то регистры TIMERx_PERIOD и TIMERx_WIDTH сообщат о периоде импульса и ширине импульса, замеренные сразу после окончания периода. Если бит PERIOD_CNT сброшен, и произошел завершающий перепад (см. рис. 16-18), то регистр TIMERx_WIDTH сообщает о ширине импульса, измеренной сразу по окончании импульса, однако регистр TIMERx_PERIOD сообщает о периоде импульса, измеренном по окончании предыдущего периода.

Если бит PERIOD_CNT очищен, и произошел первый завершающий перепад сигнала, то первое значение периода пока не было измерено при первом измерительном отчете, так что значение периода не будет верным. Чтение значения TIMERx_PERIOD в этом случае вернет 0, как это показано на рис. 16-18. Чтобы измерить ширину импульса сигнала, у которого только один начальный перепад и один завершающий перепад, установите PERIOD_CNT = 0. Если же в этом случае будет PERIOD_CNT = 1, то не будет захвачено значение периода в регистре буфера периода. Вместо этого будет сгенерировано прерывание сообщения об ошибке (если оно разрешено), когда диапазон счетчика будет превышен, и он перевалит через свое предельное значение. В этом случае оба регистра TIMERx_WIDTH и TIMERx_PERIOD будут читаться как 0 (потому что не произойдет измерительный отчет для копирования захваченного значения из регистра буфера ширины в регистр TIMERx_WIDTH). См. первое прерывание на рис. 16-19.

Когда используется режим с PERIOD_CNT = 0, описанный ранее для измерения ширины одиночного импульса, рекомендуется запретить таймер после получения прерывания, которым завершается интервал измерения. Если это нужно, таймер может быть заново разрешен подходящим образом для подготовки другого измерения. Эта процедура предотвратит таймер от продолжения свободного счета после измерения ширины, и от фиксируемых ошибок, генерируемых переполнением счетчика таймера.

Прерывание таймера (если оно разрешено) генерируется, если регистр счетчика таймера переваливает за значение 0xFFFFFFFF и становится 0 при отсутствии начального перепада входного сигнала. В этот момент устанавливается бит TOVF_ERRx в регистре TIMER_STATUS и биты ERR_TYP в регистре TIMERx_CONFIG, что показывает переполнение счетчика, потому что период оказался больше диапазона счетчика. Эта ситуация называется отчетом об ошибке. Когда таймер генерирует прерывание в режиме WDTH_CAP, то либо произошла ошибка (отчет об ошибке), либо готово новое измерение (измерительный отчет), но никогда не одновременно оба эти события. Регистры TIMERx_PERIOD и TIMERx_WIDTH никогда не обновляются, когда сигнализирует о себе отчет об ошибке. Дополнительную информацию см. на рис. 16-19 и 16-20.

ADSP BF538 Period Capture Measurement Report Timing fig16 17

Рис. 16-17. Пример диаграммы захвата измерения длительности периода (Period Capture Measurement Report Timing, режим WDTH_CAP, PERIOD_CNT = 1).

ADSP BF538 Width Capture Measurement Report Timing fig16 18

Рис. 16-18. Пример диаграммы захвата измерения ширины импульса (Width Capture Measurement Report Timing, режим WDTH_CAP, PERIOD_CNT = 0).

ADSP BF538 Timing Width Capture Followed by Period Overflow fig16 19

Рис. 16-19. Пример диаграммы захвата переполнения периода, за которым следует период (Period Overflow Followed by Period Capture, режим WDTH_CAP, PERIOD_CNT = 1).

Примечание: для упрощения на диаграммах рис. 16-17, 16-18 и 16-19 не показана синхронизационная задержка между перепадами TMRx и обновлениями буферного регистра.

Оба бита TIMILx и TOVF_ERRx являются sticky-битами, и программное обеспечение явно очищает их. Если таймер переполнился и PERIOD_CNT = 1, то не обновляются ни регистр TIMERx_PERIOD, ни регистр TIMERx_WIDTH. Если таймер переполнился и PERIOD_CNT = 0, то регистры TIMERx_PERIOD и TIMERx_WIDTH обновляются только если был детектирован завершающий перепад на предыдущем измерительном отчете.

Программа может подсчитать количество прерываний с отчетом об ошибке между прерываниями с измерительным отчетом, чтобы измерить периоды сигнала, которые дольше диапазона счета 0xFFFFFFFF. Каждый отчет об ошибке добавляет полные 2^32 отсчетов SCLK к общему периоду, но ширина импульса неоднозначна. Например, на рис. 16-19 период 0x100000004 (больше 0xFFFFFFFF), однако ширина импульса могла бы быть либо 0x000000002, либо 0x100000002.

Форма сигнала, поступающего на вывод TMRx, не обязательно должна иметь скважность 50%, однако минимальное время лог. 0 для TMRx составляет 1 период SCLK, и минимальное время лог. 1 для TMRx также составляет 1 период SCLK. Таким образом, входная частота сигнала на TMRx не может превышать SCLK/2 при 50% скважности. С такими условиями таймер в режиме WDTH_CAP измерил бы период = 2 и ширину импульса = 1.

Рис. 16-20. Пример диаграммы захвата ширины импульса, за которым следует переполнение периода (Width Capture Followed by Period Overflow, режим WDTH_CAP, PERIOD_CNT = 0).

Любой из трех таймеров может предоставить автодетектирование скорости на периферийном устройстве UART0 (universal asynchronous receiver/transmitter). Бит выбора входа таймера (TIN_SEL) в регистре TIMERx_CONFIG может побудить таймер делать выборки сигнала принимаемых данных UART0 (вывод RX0) вместо сигнала TMRx, когда разрешен режим WDTH_CAP.

Не разрешайте UART0, пока не будет завершено автодетектирование скорости.

Подпрограмма может определить ширину импульса в потоке бит последовательных данных. Из-за того, что база времени выборки таймеров синхронна с работой UART0 — все такты получаются от системы PLL — измеренная ширина импульса может использоваться для вычисления делителя в системе настройки скорости порта UART0 (регистр baud rate divider).

DIVISOR = ((TIMERx_WIDTH) / (16 x количество_захваченных_бит_UART0))

Чтобы увеличить количество отсчетов таймера, и таким образом повысить разрешение при захвате сигнала, не рекомендуется измерять ширину одного бита, лучше всего измерить длительность максимального количества бит во фрейме UART. По этой причине символ NULL (код ASCII 0x00) обычно используется для автодетектирования скорости, как это показано на рис. 16-21.

ADSP BF538 Autobaud Detection sym 0x00 fig16 21

Рис. 16-21. Автоопределение скорости на символе 0x00.

Из-за того, что пример импульса фрейма на рис. 16-21 состоит из 8 бит данных и 1 стартового бита, то в формулу подставляется 9 бит:

DIVISOR = TIMERx_WIDTH/(16 x 9)

Реальные сигналы RX порта UART0 имеют асимметричные перепады спада и фронта, и логические уровни не точно попадают в середину диапазона входных напряжений. На высоких скоростях детектирование скоростей на базе измерения ширины импульса может дать не адекватный результат без дополнительного аналогового улучшения формы сигнала. Измерение периода сигнала вместо длительности решает эту проблему, так что это настоятельно рекомендуемый принцип автодетекта скорости.

Например, можно использовать заранее обусловленный символ ASCII '@' (код 40h) при автодетектировании с измерением периода сигнала между двумя следующими друг за другом спадами. Как показано на рис. 16-22, происходит измерение периода между спадом сигнала стартового бита и спадом сигнала после бита 6. Поскольку этот период накрывает 8 бит, в формулу подставляется число 8:

DIVISOR = TIMERx_PERIOD/(16 x 8)

ADSP BF538 Autobaud Detection sym 0x40 fig16 22

Рис. 16-22. Автоопределение скорости на символе 0x40.

В режиме EXT_CLK также работает как вход (см. рис. 16-23). Таймер работает как счетчик, тактируемый от внешнего источника, который может быть асинхронным по отношению к внутренней системной тактовой частоте процессора. Текущее значение счетчика в регистре TIMERx_COUNTER представляет количество детектированных лидирующих перепадов. Установка поля TMODE регистра TIMERx_CONFIG в значение b#11 разрешает этот режим. Регистр периода TIMERx_PERIOD программируется значением максимального количества внешних отсчетов.

Форма сигнала, который поступает на вывод TMRx, не обязательно должна быть с 50% скважностью, однако минимальное время лог. 0 для TMRx составляет 1 период SCLK, и минимальное время лог. 1 для TMRx также составляет 1 период SCLK. Таким образом, входная частота сигнала на TMRx не может превышать SCLK/2 при 50% скважности.

Период может быть запрограммирован в любое значение от 1 до (2^32 – 1) включительно.

ADSP BF538 Timer Flow Diagram EXT CLK fig16 23

Рис. 16-23. Алгоритм работы таймера в режиме EXT_CLK.

После того, как таймер разрешен, это разрешение сбрасывает регистр счетчика в значение 0x0, и затем таймер ожидает поступления лидирующего перепада на выводе TMRx. Поступление этого перепада приводит к инкременту регистра счетчика, так что его значение становится равным 0x1. Каждое последующее поступление лидирующего перепада будет продолжать инкрементировать регистр счетчика. После достижения счетчиком значения периода установится бит TIMILx, и будет сгенерировано прерывание. Следующий лидирующий перепад перезагрузит регистр счетчика значением 0x1. Таймер продолжит подсчитывать поступающие лидирующие импульсы, пока не будет запрещен. Бит PULSE_HI определяет полярность лидирующего импульса: это будет нарастание сигнала (PULSE_HI установлен) или спад (PULSE_HI очищен).

Биты конфигурации TIN_SEL и PERIOD_CNT в этом режиме не оказывают никакого влияния. Биты TOVF_ERRx и ERR_TYP устанавливаются, если регистр счетчика переваливает через 0xFFFFFFFF и становится равным 0, или если при старте период = 0, или когда регистр счетчика переваливает через запрограммированный период (от Count = Period до Count = 0x1). Регистр TIMERx_WIDTH не используется.

До 2 таймеров используются для генерации сигналов синхронизации фрейма основных режимов PPI. Подробнее про функционирование таймеров для использования с PPI, обратитесь к разделу "Frame Synchronization in GP Modes" даташита [1] (часть даташита, где описывается периферийное устройство PPI).

[Прерывания]

Каждый из трех таймеров может генерировать одно прерывание. Три результирующих сигнала прерывания перенаправляются к блоку контролеров системных прерываний для организации приоритезации и маскирования. Регистр состояния таймера (TIMER_STATUS) защелкивает прерывания таймера, чтобы программное обеспечение могло определить источник прерывания. Эти биты работают по принципу W1C, и они должны быть очищены до RTI, чтобы гарантировать, что прерывание не будет выставлено повторно.

Чтобы разрешить генерацию прерывания, установите бит IRQ_ENA и демаскируйте источник прерывания в регистре маскирования прерываний системы (system interrupt mask register, SIC_IMASKx). Чтобы опрашивать бит TIMILx без генерации прерывания, установите бит IRQ_ENA, но оставьте при этом прерывание замаскированным. Если это разрешено IRQ_ENA, запросы прерывания также будут генерироваться при возникновении событий ошибки. См. рис. 16-24.

Контроллеры системных прерываний разрешают гибкую обработку прерываний. Все таймеры могут использовать общий канал прерывания, или использовать по индивидуальному каналу прерывания для каждого таймера. При использовании одного канала прерывания для нескольких таймеров обработчик прерывания (ISR) должен различать источник прерывания - какой таймер его вызвал. В режиме PWM несколько таймеров могут работать с одинаковым настроенным периодом, и могут выдавать свои запросы на прерывание одновременно. В этом случае ISR может очистить все биты защелки TIMILx за один раз, если запишет 0x07 в регистр TIMER_STATUS.

Если прерывания разрешены, убедитесь, что ISR очистил бит TIMILx в регистре TIMERx_STATUS перед выполнением инструкции RTI. Это гарантирует, что прерывание не будет выставлено повторно. Помните, что записи в системные регистры являются отложенными на некоторое время. Если только несколько инструкций отделяют команду очистки TIMILx от инструкции RTI, может быть вставлена дополнительная инструкция SSYNC. В режиме EXT_CLK сброс бита TIMILx регистра TIMERx_STATUS в самом начале кода ISR позволит избежать пропуска событий таймера.

ADSP BF538 Timers Interrupt Structure fig16 24

Рис. 16-24. Структура прерывания таймеров.

[Недопустимые состояния]

Для таблицы 16-1, используются следующие определения:

• Startup (запуск). Это первый тактовый период, при котором счетчик таймера начинает счет, когда таймер разрешен записью TIMER_ENABLE.

• Rollover (счет сначала после достижения пороговой величины). Момент времени, когда счетчик достиг значения в регистре TIMERx_PERIOD и счетчик перезагрузился значением 1.

• Overflow (переполнение). При инкременте счетчик таймера перевалил через свое максимально возможное значение 0xFFFFFFFF. Счетчик не настолько велик, чтобы учесть следующее поступающее событие, так что новое подсчитанное значение станет равным 0x00000000.

• Unchanged (ничего не поменялось). Нет новой ошибки.

• Когда поле ERR_TYP не изменилось, это покажет код предыдущей ошибки, или 00, если не было ошибки с момента разрешения таймера.
• Когда TOVF_ERR остался без изменений, то он будет читаться как 0 если не было ошибки с момента разрешения таймера, или если программа выполнила операцию W1C для очистки любой предыдущей ошибки. Если предыдущая ошибка не была подтверждена программной, то TOVF_ERR читается как 1.

Программа должна прочитать TOVF_ERR, чтобы проверить наличие ошибки. Если TOVF_ERR установлен, программа может прочитать поле ERR_TYP для получения дополнительной информации. Когда ошибка была детектирована, программа должна записать 1 для очистки TOVF_ERR, чтобы подтвердить ошибку.

Следующая таблица может быть прочитана следующим образом: "В режиме __ при событии __, если TIMERx_PERIOD равен __ TIMERx_WIDTH равен __, то ERR_TYP равен __ и значение TOVF_ERR __".

События ошибки при запуске (Startup) не предотвращают таймер от запуска. Аналогично, события ошибки overflow и rollover не останавливают таймер. Недопустимые случаи могут привести к нежелательному поведению вывода TMRx.

Таблица 16-1. Обзор недопустимых состояний.

Режим Событие TIMERx_PERIOD TIMERx_WIDTH ERR_TYP TOVF_ERR
PWM_OUT, PERIOD_CNT=1
Startup (при этом событии не выполняется проверок границ TIMERx_WIDTH) ==0 Любое b#10 Установится
==1 Любое b#10 Установится
>=2 Любое Без изменений Без изменений
Rollover ==0 Любое b#10 Установится
==1 Любое b#11 Установится
>=2 ==0 b#11 Установится
>=2 < TIMERx_PERIOD Без изменений Без изменений
>=2 >=TIMERx_PERIOD b#11 Установится
Overflow, событие не возможно, за исключением того, что тут также другая ошибка, такая как TIMERx_PERIOD==0. Любое Любое b#01 Установится
PWM_OUT, PERIOD_CNT=0 Startup Любое(1) ==0(1) b#01(1) Установится(1)
Примечание (1): этот случай не детектируется при startup, но приводит к ошибке переполнения, как только счетчик таймера пройдет весь диапазон.
Любое >=1 Без изменений Без изменений
Rollover Событие rollover не возможно в этом режиме.
Overflow, событие не возможно, за исключением того, что тут также другая ошибка, такая как TIMERx_WIDTH==0. Любое Любое b#01 Установится
WDTH_CAP Startup В этом режиме регистры TIMERx_PERIOD и TIMERx_WIDTH доступны только для чтения, ошибок быть не может.
Rollover В этом режиме регистры TIMERx_PERIOD и TIMERx_WIDTH доступны только для чтения, ошибок быть не может.
Overflow Любое Любое b#01 Установится
EXT_CLK Startup ==0 Любое b#01 Установится
>=1 Любое Без изменений Без изменений
Rollover ==0 Любое b#10 Установится
>=1 Любое Без изменений Без изменений
Overflow, событие не возможно, за исключением того, что тут также другая ошибка, такая как TIMERx_PERIOD==0. Любое Любое b#01 Установится

В таблице 16-2 приведен обзор использования битов управления и регистров для каждого режима таймера.

Таблица 16-2. Памятка по использованию битов управления и регистров.

Бит/регистр Режимы
PWM_OUT WDTH_CAP EXT_CLK
TIMER_ENABLE 1: разрешить таймер.
0: никакого эффекта.
TIMER_DISABLE 1: запретить таймер по окончании периода.
0: никакого эффекта.
1: запретить таймер.
0: никакого эффекта.
TMODE b#01 b#10 b#11
PULSE_HI 1: генерировать ширину лог. 1.
0: генерировать ширину лог. 0.
1: измерять ширину лог. 1.
0: измерять ширину лог. 0.
1: считать положительные перепады.
0: считать отрицательные перепады.
PERIOD_CNT 1: генерировать ШИМ (PWM).
0: генерировать одиночный импульс заданной ширины.
1: прерывание после измерения периода.
0: прерывание после измерения ширины импульса.
Не используется.
IRQ_ENA 1: разрешить прерывания.
0: запретить прерывания.
TIN_SEL В зависимости от CLK_SEL, если CLK_SEL=1, то:
1: подсчет импульсов PPI_CLK.
0: подсчет импульсов PF1.

Если CLK_SEL=0, то не используется.
1: выбор для анализа входа RX.
0: выбор для анализа входа TMRx.
Не используется.
OUT_DIS 1: запрет вывода TMRx.
0: разрешение вывода TMRx.
Не используется.
CLK_SEL 1: таймер тактируется от PWM_CLK.
0: таймер тактируется от SCLK.
Не используется.
TOGGLE_HI 1: один период сигнала за 2 периода счетчика.
0: один период сигнала за 1 период счетчика.
Не используется.
ERR_TYP Сообщает о соответствующих кодах ошибки b#00, b#01, b#10 или b#11. Сообщает о соответствующих кодах ошибки b#00 или b#01. Сообщает о соответствующих кодах ошибки b#00, b#01 или b#10.
EMU_RUN 0: остановка таймера во время эмуляции (отладки).
1: при эмуляции счет таймера не останавливается.
Ножка TMRx Зависит от OUT_DIS. Если OUT_DIS=1, то находится в третьем состоянии, иначе работает как выход. Зависит от TIN_SEL. Если TIN_SEL=1, то не используется, иначе работает как вход. Вход.
Period Чтение/запись: значение периода. Только чтение: значение периода. Чтение/запись: значение периода.
Width Чтение/запись: ширина импульса. Только чтение: ширина импульса. Не используется.
Counter Только чтение: считает такты SCLK или PWM_CLK. Только чтение: считает импульсы SCLK. Только чтение: считает импульсы внешних событий.
TRUNx Чтение: состояние timer slave enable. Запись: 1 останавливает таймер, если он запрещен, 0 не дает никакого эффекта. Чтение: состояние timer slave enable. Запись и 1, и 0 не дает никакого эффекта.
TOVF_ERR Устанавливается при событиях startup или rollover, если Period=0 или 1. Устанавливается при rollover, если Width>=Period. Устанавливается, если счетчик переваливает через предел счета. Устанавливается, если счетчик переваливает через предел счета. Устанавливается, если счетчик переваливает через предел счета, или происходит rollover при Period=0.
IRQ Зависит от IRQ_ENA: если IRQ_ENA=1, то устанавливается, когда устанавливается TOVF_ERR, или когда Counter становится равным Period и PERIOD_CNT=1, или когда Counter становится равным Width и PERIOD_CNT=0. Если IRQ_ENA=0, то не устанавливается. Зависит от IRQ_ENA: если IRQ_ENA=1, то устанавливается, когда устанавливается TOVF_ERR, или когда Counter захватывает Period и PERIOD_CNT=1, или когда Counter захватывает Width и PERIOD_CNT=0. Если IRQ_ENA=0, то не устанавливается. Зависит от IRQ_ENA: если IRQ_ENA=1, то устанавливается, когда устанавливается TOVF_ERR, или когда Counter становится равным Period. Если IRQ_ENA=0, то не устанавливается.

[Счетчик тактов ядра (Core Timer)]

Core Timer является программируемым интервальным таймером, который может генерировать периодические прерывания. Core Timer работает с частотой ядра (core clock, CCLK). Таймер включает в себя 4 отображенных на пространство памяти регистра (MMR): регистр управления таймером (timer control register, TCNTL), регистр счетчика (timer count register, TCOUNT), регистр периода (timer period register, TPERIOD), и регистр шкалы (timer scale register, TSCALE).

ADSP BF538 Core Timer Block Diagram fig16 25

Рис. 16-25. Блок-диаграмма внутреннего устройства Core Timer.

Когда таймер разрешен установкой бита TMREN в регистре TCNTL, регистр TCOUNT декрементируется один раз за каждое количество TSCALE+1 тактовых циклов. Когда значение регистра TCOUNT достигнет 0, будет сгенерировано прерывание и установится бит TINT в регистре TCNTL. Если бит TAUTORLD в регистре TCNTL установлен, то регистр TCOUNT перезагружается содержимым регистра TPERIOD, и счет начинается сначала (см. рис. 16-26).

Бит TINT в регистре TCNTL показывает, что было сгенерировано прерывание. Обратите внимание, что этот бит работает не по принципу W1C. Запишите в него 0, чтобы очистить этот бит. Однако записывать 0 не обязательно. Это не требуется для очистки запроса на прерывание. Модуль Core Timer не предоставляет какой-либо еще бит разрешения прерывания. Когда таймер разрешен, прерывания могут быть замаскированы контроллером CEC.

Core Timer может быть переведен в режим пониженного энергопотребления (low power mode) путем очистки бита TMPWR в регистре TCNTL. Перед использованием таймера установите бит TMPWR, это восстановит тактирование блока таймера. Когда TMPWR установлен, Core Timer может быть затем разрешен установкой бита TMREN в регистре TCNTL.

Если TMREN установлен при TMPWR = 0, то поведение аппаратуры не определено.

ADSP BF538 TCNTL

Рис. 16-26. Регистр TCNTL.

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

TINT. Sticky-бит состояния таймера. 0: таймер не генерировал прерывание, 1: таймер генерировал прерывание.

TAUTORLD. Бит, управляющий автозагрузкой. 0: запрет функции автозагрузки -  когда TCOUNT достигает 0, таймер генерирует прерывание и останавливается. 1: разрешена автозагрузка - когда TCOUNT достиг 0 и таймер сгенерировал прерывание, TCOUNT автоматически перезагружается содержимым регистра TPERIOD, и дальше таймер продолжает счет.

TMREN. Бит разрешения таймера, который имеет значение только тогда, когда TMPWR = 1. Если TMREN = 0, то таймер запрещен, если 1 то разрешен.

TMPWR. Бит, выводящий таймер из состояния пониженного энергопотребления. 0: таймер обесточен (режим пониженного энергопотребления), 1: активное состояние таймера, в котором таймер может быть разрешен установкой бита TMREN.

Регистр счетчика (TCOUNT) декрементируется после каждых SCALE + 1 тактов ядра. Когда значение TCOUNT достигнет 0, генерируется прерывание и установится бит TINT регистра TCNTL (см. рис. 16-27).

ADSP BF538 TCOUNT

Рис. 16-27. Регистр TCOUNT.

Count Value[31:0]. Значение счетчика таймера.

Когда автозагрузка разрешена, регистр TCOUNT (рис. 16-28) перезагружается значением регистра периода (TPERIOD) всякий раз, когда TCOUNT достигает 0.

Чтобы гарантировать, что в регистре TPERIOD имеются допустимые данные, регистры TPERIOD и TCOUNT инициализируются одновременно на первой записи в любой из этих регистров. Если необходимо другое значение для первого периода счета, запишите данные в TCOUNT после записи TPERIOD.

ADSP BF538 TPERIOD

Рис. 16-28. Регистр TPERIOD.

Period Value[31:0]. Запрограммированное значение периода таймера.

Регистр шкалы (TSCALE), показанный на рис. 16-29, хранит в себе значение масштабирования, которое на 1 меньше количества циклов между декрементами TCOUNT. Например, если значение TSCALE равно 0, то регистр счетчика декрементируется каждый тактовый цикл. Если TSCALE равен 1, то счетчик декрементируется каждые 2 тактовых цикла.

ADSP BF538 TSCALE

Рис. 16-29. Регистр TSCALE.

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

Scale Value[7:0]. Запрограммированное значение масштабирования счета таймера.

[Сторожевой таймер (Watchdog Timer)]

Процессор имеет встроенный 32-разрядный таймер, который может использоваться для реализации сторожевой функции отслеживания работы программного обеспечения (software watchdog). Эта функция может улучшить надежность системы путем генерации события для ядра процессора, если таймер истек до того, как был обновлен программно. Другими словами, программа должна постоянно обновлять (сбрасывать) сторожевой таймер, и если это вдруг не произошло, значит произошло что-то непредвиденное или программа зависла, и необходимо предпринять какие-то аварийные действия (вплоть до перезагрузки системы). В зависимости от того, как запрограммирован сторожевой таймер, событие сторожевого таймера может генерировать сброс, не маскируемое прерывание, или обычное прерывание. Сторожевой таймер тактируется от системной частоты (SCLK).

Как работает Watchdog Timer. Чтобы использовать сторожевой таймер, выполните следующее:

1. Установите значение счетчика Watchdog Timer путем записи значения счетчика в регистр счетчика сторожевого таймера (watchdog count register, WDOG_CNT). Обратите внимание, что загрузка регистра WDOG_CNT, когда сторожевой таймер не разрешен, также приведет к предзагрузке регистра WDOG_STAT.

2. В регистре управления сторожевым таймером (watchdog control register, WDOG_CTL), выберите событие, которое будет сгенерировано при истечении таймаута сторожевого таймера.

3. Разрешите Watchdog Timer в регистре WDOG_CTL. После этого Watchdog Timer начнет счет вниз, декрементируя значение в регистре WDOG_STAT. Когда WDOG_STAT достигнет 0, будет сгенерировано запрограммированное событие. Чтобы предотвратить наступление этого события, программа должна перезагрузить значение счетчика регистра WDOG_CNT из регистра WDOG_STAT путем выполнения записи (любого значения) в регистр WDOG_STAT, или должна запретить Watchdog Timer в регистре WDOG_CTL до того, как истек таймаут.

Регистр счетчика сторожевого таймера (watchdog count register, WDOG_CNT) содержит 32-разрядное беззнаковое значение. К регистру WDOG_CNT должен осуществляться доступ только через 32-битные чтения/записи (см. рис. 16-30).

Регистр WDOG_CNT содержит программируемое значение счета. Допустимая запись в регистр WDOG_CNT также предзагружает счетчик сторожевого таймера. Для дополнительной безопасности регистр WDOG_CNT может обновляться только когда сторожевой таймер запрещен. Запись в регистр счетчика, когда таймер разрешен, не модифицирует содержимое этого регистра.

ADSP BF538 WDOG CNT

Рис. 16-30. Регистр WDOG_CNT.

Watchdog Count[31:0]. Значение счетчика сторожевого таймера.

32-разрядный регистр состояния сторожевого таймера (watchdog status register, WDOG_STAT) содержит текущее подсчитанное значение сторожевого таймера (см. рис. 16-31). Чтение WDOG_STAT возвратит текущее значение счетчика. Когда сторожевой таймер разрешен, WDOG_STAT декрементируется на 1 с каждым тактом SCLK. Когда WDOG_STAT достигает 0, сторожевой таймер останавливает счет и генерируется выбранное событие, которое запрограммировано в регистре управления сторожевым таймером (WDOG_CTL).

ADSP BF538 WDOG STAT

Рис. 16-31. Регистр WDOG_STAT.

Watchdog status[31:0]. Регистр текущего состояния счетчика сторожевого таймера.

Значения не могут быть напрямую сохранены в WDOG_STAT, вместо этого они копируются из регистра WDOG_CNT. Это может произойти двумя путями.

• Когда сторожевой таймер запрещен, запись регистра WDOG_CNT также предзагружает регистр WDOG_STAT.
• Когда сторожевой таймер разрешен, запись регистра WDOG_STAT загрузит значение из регистра WDOG_CNT.

Когда процессор выполняет запись (произвольного значения) в регистр WDOG_STAT, значение в регистре WDOG_CNT копируется в регистр WDOG_STAT. Обычно программа устанавливает значение WDOG_CNT при инициализации, затем периодически делаются записи в WDOG_STAT до истечения таймаута сторожевого таймера. Это перезагружает сторожевой таймер значением из WDOG_CNT, предотвратит генерацию выбранного события.

Регистр WDOG_STAT является 32-битным беззнаковым, отображенным на память регистром (MMR), к которому должно происходить обращение через 32-битные чтения и записи.

Если пользователь не перезагрузит счетчик перед прохождением SCLK * Count циклов, то будет сгенерировано событие - прерывание сторожевого таймера или сброс, и установится бит TRO в регистре управления сторожевого таймера (WDMOG_CTL). Когда это происходит, счетчик останавливает декрементирование и остается в нулевом значении.

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

Регистр управления сторожевым таймером (watchdog control register, WDOG_CTL) является 16-битным, отображенным на память регистром (MMR), используемым для управления сторожевым таймером (см. рис. 16-32).

ADSP BF538 WDOG CTL

Рис. 16-32. Регистр WDMOG_CTL.

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

TR0. Флаг, работающий по принципу W1C. 0: интервал таймаута сторожевого таймера не истек, 1: истек.

Программа может определить, достиг ли таймер нулевого значения, путем опроса бита состояния TRO в регистре управления сторожевого таймера. Этот бит является "липким" (sticky bit), который устанавливается всякий раз, когда таймер достигает 0, и его можно сбросить только путем запрета сторожевого таймера и записи в этот бит лог. 1.

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

TMR_EN[7:0]. Запись в это поле значения 0xAD запрещает работу сторожевого таймера, запись любого другого значения в это поле разрешает работу сторожевого таймера.

Поле TMR_EN используется для разрешения или запрета сторожевого таймера. Запись в это поле любого значения, кроме запрещающего, разрешит работу сторожевого таймера. Этот многобитный запрещающий ключ минимизирует шанс случайного (нежелательного) запрета сторожевого таймера.

ICTL[1:0]. Это поле выбирает генерируемое событие сторожевого таймера. 00: генерируется событие сброса, 01: генерация NMI, 10: генерация обычного прерывания, 11: запрет генерации события.

Поле ICTL используется для выбора события, которое будет сгенерировано, когда истечет таймаут сторожевого таймера. Обратите внимание, что если выбрана опция обычного прерывания (general-purpose interrupt), должен быть подходящим образом сконфигурирован регистр маски прерываний системы (system interrupt mask register, SIC_IMASKx), чтобы демаскировать (т. е. разрешить) это прерывание. Если запрещена генерация событий сторожевого таймера, то сторожевой таймер работает так, как было описано, за исключением того, что не будет сгенерировано никакого события, когда истечет интервал таймаута сторожевого таймера.

[Отличия таймеров и примеры применения]

Основные отличия таймера ядра (Core Timer) и обычных таймеров (таймеры общего назначения TIM0, TIM1, TIM2):

1. Таймер ядра тактируется от частоты CPU (CCLK), а таймеры общего назначения от частоты системной шины (SCLK). Также таймеры общего назначения можно тактировать и от PWM_CLK, но это используется довольно редко. Сторожевой таймер тактируется от частоты тактов системной шины (SCLK).

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

3. Таймер ядра жестко привязан к группе приоритетов IVG6 (EVT_IVTMR). По этой причине настройка прерывания для него заключается только в установке вектора прерывания, например (ik_timer это константа, определенная как 6 в перечислении interrupt_kind заголовочного файла exception.h):

register_handler(ik_timer, TimerPWM_ISR);

#define FREQ   100   // Частота срабатывания прерываний
#define PRESC  5     // Коэффициент для прескалера

#pragma optimize_for_speed EX_INTERRUPT_HANDLER(CoreTimer_ISR) { // Переключение уровня ножки порта, используется для отладки, // чтобы проверить частоту срабатывания прерываний: *pPORTDIO_TOGGLE = PD12; }
 
void InitCoreTimer (void)
{
   // Вычисление периода на основе частоты тактов CCLK, требуемой
   // частоты срабатывания прерываний и коэффициента прескалера:
   u32 tperiod = get_cclk_hz()/(FREQ * (PRESC+1));
   // Вывод таймера ядра из режима пониженного энергопотребления:
   *pTCNTL = TMPWR;
   // Установка периода срабатывания прерываний:
   *pTPERIOD = tperiod;
   // Установка прескалера и периода:
   *pTSCALE = PRESC;
   *pTCOUNT = tperiod;
   // Регистрация обработчика прерывания:
   register_handler(ik_timer, CoreTimer_ISR);
   // Настройка таймера и разрешение счета:
   *pTCNTL |= TMREN | TAUTORLD;
}

Этим системный таймер похож на сторожевой таймер, для него тоже не нужно настраивать группу прерывания.

#ifdef WDTPERIOD
 
// Обработчик прерывания сторожевого таймера:
EX_NMI_HANDLER(WatchDogInterrupt)
{
   *pWDOG_CTL = 0x0AD0;    // Остановка watchdog
   *pWDOG_CTL |= 0x8000;   // Очистка Sticky bit
   *pWDOG_CNT = WDTPERIOD; // Также предварительно загрузит
                           // WDOG_STAT, если сторожевой
                           // таймер остановлен.
LED(1);
   //WatchDogTimerFired = true; // Показать наличие проблемы
   //SOFTWARERESET();
asm ("\    P0.L = LO(0xFFC00104);\
    P0.H = HI(0xFFC00104);\
    R0.L = 0x0012;\    W[P0] = R0;\
    SSYNC;\
    /* Issue soft reset */\
    P0.L = LO(0xFFC00100);\
    P0.H = HI(0xFFC00100);\
    R0.L = 0x0007;\
    W[P0] = R0;\    SSYNC;\
    P1 = 75;\
    LSETUP(start, end) LC0 = P1;\
start:\
end:\
    NOP;\
    /* Clear soft reset */\
    P0.L = LO(0xFFC00100);\
    P0.H = HI(0xFFC00100);\
    R0.L = 0x0000;\
    W[P0] = R0;\
    SSYNC;\
    /* Core reset - forces reboot */\
    RAISE 1;\
    ");
}
 
// Функция настройки сторожевого таймера:
void WDOGinit (void)
{
   // Запрет сторожевого таймера:
   *pWDOG_CTL = WDDIS;
   ssync();
   // Инициализация счетчика:
   *pWDOG_CNT = WDTPERIOD;
   ssync();
   // Разрешение сторожевого таймера, генерировать сброс
   // при срабатывании сторожевого таймера:
   //*pWDOG_CTL = WDEN | WDEV_RESET;
   // Разрешение сторожевого таймера, с генерацией NMI
   // при срабатывании сторожевого таймера:
   register_handler(ik_nmi, WatchDogInterrupt);
   *pWDOG_CTL = WDEN | WDEV_NMI;
   ssync();
}
 
// Функция, которая откладывает срабатывание сторожевого таймера.
// Она должна вызываться в долго выполняющихся циклах и в главном
// цикле функции main.
void WDOGreload ()
{
   if (reloadwdt)
   {
      // Сброс watchdog:
      *pWDOG_STAT = 0;
   }
}
 
#endif

В отличие от таймера ядра, таймеры общего назначения требуют для себя настройки группы приоритета IVG. В примере настройки прерываний TIM0 константа ik_ivg8 может быть любой в диапазоне от ik_ivg7 до ik_ivg15 (см. перечисление interrupt_kind заголовочного файла exception.h):

// Сброс тетрады периферийного устройства TIMER0, куда записывается
// значение IVG:
*pSIC_IAR2 &= PX_IVG_CLR(ADI_INT_TIMER0);
// Запись нового значения IVG в тетраду периферийного устройства:
*pSIC_IAR2 |= PX_IVG(ADI_INT_TIMER0, ik_ivg8);
// Регистрация обработчика прерывания:
register_handler(ik_ivg8, Timer0_ISR);

#pragma optimize_for_speed
EX_INTERRUPT_HANDLER(Timer0_ISR)
{
   volatile u16 status = *pTIMER_STATUS;
   *pTIMER_STATUS = TIMIL0 | TIMIL1 | TIMIL2 | TOVF_ERR0 | TOVF_ERR1 | TOVF_ERR2;
}
 
void InitTimer0 (void)
{
   // Основная конфигурация таймера:
   *pTIMER0_CONFIG = PERIOD_CNT | PULSE_HI | PWM_OUT;
   // Сброс тетрады периферийного устройства TIMER0, куда
   // записывается значение IVG:
   *pSIC_IAR2 &= PX_IVG_CLR(ADI_INT_TIMER0);
   // Запись нового значения IVG в тетраду периферийного
   // устройства:
   *pSIC_IAR2 |= PX_IVG(ADI_INT_TIMER0, ik_ivg8);
   // Регистрация обработчика прерывания:
   register_handler(ik_ivg8, Timer0_ISR);
   // Вычисление периода прерывания для частоты запуска
   // ISR таймера 30 кГц. Здесь fsclk это частота
   // системных тактов SCLK в Герцах:
   *pTIMER0_PERIOD = fsclk/30000;
   // Настройка 50% скважности импульса на ножке TMR0:
   *pTIMER0_WIDTH = *pTIMER0_PERIOD / 2;
   // Разрешение прерываний:
   *pTIMER0_CONFIG |= IRQ_ENA;
   // Разрешение счета:
   *pTIMER_ENABLE  = 0x0001;
}

4. Как можно заметить из примеров обработчиков прерывания, которые были показаны во врезках выше, для таймера ядра никаких дополнительных действий в обработчике прерывания не требуется. Но для таймеров общего назначения обязательно нужно программно сбросить флаг, который вызвал прерывание, иначе обработчик прерывания будет вызываться бесконечно. Поскольку обработчик прерывания у таймеров общего назначения один и тот же, для выяснения причины прерывания требуется обработка состояния флагов в регистре TIMER_STATUS.

5. Обычное назначение таймеров в программе:

Таймер ядра: отслеживание реального времени, задержек, запуск планировщика VDK.
Таймеры общего назначения: генерация сигналов, ШИМ, подсчет внешних событий, автодетект скорости UART.
Сторожевой таймер: обеспечение автоматического перезапуска программы в случае зависания.

[Словарик]

CCLK core clock, тактовая частота ядра. Основной фактор быстродействия процессора.

CEC Core Event Controller, контроллер управления событиями ядра. Работает совместно с SIC, чтобы обеспечить приоритет обработки всех системных событий (прерываний).

duty cycle скважность, соотношение длительности импульса к длительности периода цифрового сигнала. У сигнала со скважностью 50% длительность лог. 0 равна длительности лог. 1.

ISR Interrupt Service Routine, подпрограмма обработки прерывания.

MMR Memory Mapped Register, встроенный в общее адресное пространство регистр.

NMI Non-Maskable Interrupt, не маскируемое прерывание. Это прерывание разрешено всегда, его нельзя запретить.

PAB Peripheral Access Bus, шина доступа к внутренним периферийным устройствам процессора.

PLL Phase Locked Loop, контур фазовой подстройки частоты. Специальная система процессора Blackfin, которая использует частоту кварца для формирования повышенных тактовых частот с помощью настраиваемых коэффициентов умножения и деления (могут генерироваться частоты, которые в десятки раз больше частоты кварца).

PWM Pulse-Width Modulation, широтно-импульсная модуляция, ШИМ.

RTI специальная инструкция для выхода из подпрограммы прерывания.

SCLK system clock, системная тактовая частота.

SIC System Interrupt Controller, системный контроллер прерываний. Служит для привязки и перенаправления событий прерываний от множества периферийных устройств на входы группы приоритетов прерываний CEC.

sticky bit дословно переводится как "липкий бит". Флаг состояния, который сам по себе не сбрасывается, и требует для этого неких действий процессора.

UART Universal asynchronous receiver/transmitter, универсальный асинхронный приемо-передатчик.

W1C Write-1-Clear, принцип очистки бита, когда бит (или биты) сбрасывается записью в него единицы.

W1S Write-1-Set, принцип установки бита, когда бит (или биты) устанавливается записью в него единицы.

[Ссылки]

1. ADSP-BF538/ADSP-BF538F Blackfin® Processor Hardware Reference site:analog.com.
2. Сторожевой таймер ADSP-BF538.
3. VDK: служба таймеров.

 

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


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

Top of Page