Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Работа с таймерами в Xmega
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Nosaer
Добрый день.
Помогите пожалуйста с настройкой таймеров Xmega32A4.
Что то я в этих регистрах настройки совсем запутался... wacko.gif
По задумке, 3 таймера счетчика активированы на PC0, PD0, PE0.
Настроены на захват длительности импульса по падающему фронту.
Ну и соответственно при запуске все три ничего не считают.

Работоспособность проверяю в AVR Studio 6.

Надеюсь на вашу помощь. Спасибо)
CODE
void StartTimers(void) // Запускаем режим захвата по трем каналам таймера
{
TCC0.CTRLA = TC_CLKSEL_EVCH0_gc; // Выбираем источником тактов нулевой канал порта
TCD0.CTRLA = TC_CLKSEL_EVCH0_gc;
TCE0.CTRLA = TC_CLKSEL_EVCH0_gc;
}

void StopTimers(void) // Останавливаем работу таймеров
{
TCC0.CTRLA = TC_CLKSEL_OFF_gc;
TCD0.CTRLA = TC_CLKSEL_OFF_gc;
TCE0.CTRLA = TC_CLKSEL_OFF_gc;
}

int main(void)
{
// Настройка работы от внешнего кварца в 4МГц
cli(); // Отключение прерываний
OSC.XOSCCTRL = 0x4B; // 2-9 МГц без режима сбережения и со стабильной частотой во время запуска (01001011)
OSC.CTRL = 0x08; // Разрешение работы внешнего генератора
while((OSC.STATUS & 0x08) == 0); // Ожидание сигнала о включении внешнего генератора

// Настройка портов
PORTC.DIR = 0x1C; // PC0 - T/C-X
PORTD.DIR = 0x00; // PD0 - T/C-Y
PORTE.DIR = 0x00; // PE0 - T/C-Z

PORTC.PIN0CTRL = PORT_OPC_WIREDORPULL_gc | PORT_ISC_FALLING_gc; // Установка чувствительности по заднему фронту
PORTD.PIN0CTRL = PORT_OPC_WIREDORPULL_gc | PORT_ISC_FALLING_gc;
PORTE.PIN0CTRL = PORT_OPC_WIREDORPULL_gc | PORT_ISC_FALLING_gc;

PORTC.INTCTRL = PORT_INT0LVL_HI_gc; // Настройка высокого уровня прерываний
PORTD.INTCTRL = PORT_INT0LVL_HI_gc;
PORTE.INTCTRL = PORT_INT0LVL_HI_gc;
PORTR.INTCTRL = PORT_INT0LVL_HI_gc;
PMIC.CTRL|=PMIC_HILVLEN_bm|PMIC_MEDLVLEN_bm|PMIC_LOLVLEN_bm; // Разрешаем все уровни прерываний

//Единоразовая настройка таймеров
TCC0.CTRLB = 0x00; // Выбрали режим: Normal
TCD0.CTRLB = 0x00;
TCE0.CTRLB = 0x00;
TCC0.CTRLD = 0xC8; // Захват длительности импульса по 0 каналу
TCD0.CTRLD = 0xC8; // EVACT = 110 - захват длительности; 001 - входной захват
TCE0.CTRLD = 0xC8; // EVSEL = 1000 - выбор 0 канала для захвата
TCC0.INTCTRLA = 0x01; // Разрешаем прерывания низкого уровня по переполнению
TCD0.INTCTRLA = 0x01; // 0x01 - низкий уровень; 0x02 - средний; 0x03- высокий уровень...
TCE0.INTCTRLA = 0x01;

sei(); // Включение прерываний
Xenia
Цитата(Nosaer @ Feb 8 2015, 06:37) *
По задумке, 3 таймера счетчика активированы на PC0, PD0, PE0.
Настроены на захват длительности импульса по падающему фронту.
Ну и соответственно при запуске все три ничего не считают.


Счетные пины портов с входом таймера жестко не связаны, а соединяются через систему событий. А вот выход генерации у таймеров (PWM) уже связан жестко с конкретным пином.

Например, выход частоты с таймера TCC0 поступает на пин PС0 жестко, его никак нельзя поменять на какой-то другой пин (правда в описании упоминается возможность выхода на область PС0-PC3, но лично мне этого сделать не удалось). Поэтому, если вы рассчитываете вывести наружу частоту, генерируемую таймером, то должны позаботиться, чтобы пин PС0 под другие цели не был занят.

Напротив, если вы расчитываете использовать таймер не для генерации сигнала, а исключительно для счета внешних сигналов, то вход для такого сигнала можно подключить не только на порт PС, но и на любой из пинов портов PС, PD, PE, PF.

А связь между конкретным пином и таймером производится через систему событий, имеющую 8 каналов.

Делается это так:
1) выбираете нужный вам пин среди портов С,D,E,F. Пусть это будет PF3. Устанавливаете ему чувствительность:
PORTF.PIN3CTRL = PORT_OPC_PULLDOWN_gc | PORT_ISC_FALLING_gc; // Pull-down, sense falling edge PF3

2) Выбираете канал передачи события, пусть это будет канал 0. Направляете на него импульс с PF3
EVSYS.CH0MUX = EVSYS_CHMUX_PORTF_PIN3_gc; // EV channel 0 <- PF3 (sensor)

3) Выбирате таймер, пусть это будет таймер TCC0. Устанавливаете ему источником счета канал 0 событий.
TCC0.CTRLD = TC_EVACT_CAPT_gc | TC_EVSEL_CH0_gc; // external capture <- EV channel 0
(насчет TC_EVACT_CAPT_gc не уверена, что он тут необходим)

Всё остальное не описываю, т.к. главная логика здесь такая:
PF3 ---> CH0 ---> TCC0
Пин PF3 можно заменить на другой (менять на PC0 я бы остереглась). При этом изменятся команды 1 и 2.
EV-канал CH0 тоже можно заменить на любой от CH0 до CH7 (они все одинаковые). При этом изменятся команды 2 и 3.
Таймер TCC0 можно заменить на любой другой. При этом изменится команда 3.

Никакие прерывания в этом механизме передачи возбуждения с пина порта на счет таймера не используются. Сама система событий EVSYS тоже вроде бы ни в какой предварительной инициализации не нуждается. А таймеры программируются общим порядком, с тем лишь единственным исключением, что в CTRLD подставляется нетипичный источник.

P.S. От одного EV-канала можно запускать на счет (или сброс) сразу несколько таймеров, если им указать этот канал в виде источника счета (или сброса), но вход EV-канала всегда может быть только один.
P.P.S. Выход с EV-канала может быть (параллельно) использован и для других целей - возбуждения прерывания или DMA. Или можно соединить два таймера в каскад, если передавать по каналу переполнение от одного из них на счетный вход другого. К моему большому сожалению его нельзя использовать для дрыгания другими ножками портов, а то бы этой системе просто цены не было! sm.gif
Nosaer
Извините за долгий ответ, работа.
Спасибо большое. Очень доступно объяснили, так скажем расставили все точки над i.
С первого раза все заработало.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.