Перейти к содержанию
    

XMega-ми заинтересовался недавно. Имеется отладочная плата XMEGA-A3BU Xplained. Использую Atmel Studio 6 и ASF 3.5.0.

 

Появилось несколько вопросов. Может коллеги подскажут что-нибудь...

 

1. Во-первых, в ASF отсутствует функция для управления выходами аналогового компаратора AC. Хотя в драйверах для IAR она имеется. Я прописал установку битов AC1OUT ACOOUT записью в регистр CTRLA, но при отладке в дебаггере вижу, что реально биты не устанавливаются. Пытаюсь в окошке I/O View установить эти биты, тоже безрезультатно. Ни в симуляторе, ни в железе. Что я делаю не так?

На плате стоит чип ATxmega256A3BU.

 

2. Возможно ли одновременное использование одного аналогового входа компаратором и АЦП? Или в реальности вход будет отдан тому, кто проинициализировал его последним?

 

3. Хочу записать результаты АЦП в память через DMA. В ASF есть пример - ознакомился, настроил. Запуск АЦП происходит через систему событий циклически, DMA записывает данные в память, все ОК. Все это происходит в спящем режиме. Но мне нужно отловить некий уровень на входе АЦП и после этого выдать данные в USART. Я настраиваю компаратор на выходе АЦП, который генерирует прерывание, когда на входе АЦП значение первышает некий уровень. Как только разрешаю это прерывание - сразу перестает работать система событий после получения результата АЦП, соответственно не запускается новый цикл АЦП и запись DMA. Ок. Перевожу АЦП в режим freerun - компаратор отрабатывает как надо, прерывания генерятся, но теперь и события генерятся только вместе с прерываниями после срабатывания компаратора. Соответсвенно и DMA тоже работает только когда сработал компаратор. Как только компаратор выключается - пропадают прерывания и события. Почему?

Мне нужно чтобы события оставалсиь всегда, чтобы пока проц спит в фоне постоянно работал АЦП и велась запись в память через DMA. Проц должен просыпаться только если на входе компаратора есть требуемый уровень. А так работает или одно или другое. Т.е. либо тебе события без прерываний, либо события с прерываниями, но после срабатывание компаратора.

 

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

 

Отсюда вопрос 4.

Можно ли запараллелить два входа, позволяет ли это входное сопротивление или нужно сделать какую-то обвязку?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1. Не включено тактирование AC. Вот биты и не включаются.

2. Почему бы нет. Должно работать.

3. Без кода можно только гадать.....

У АЦп также есть прерывание по уровню..смотрите даташит.

4. Можно, но не нужно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

bob1, спасибо за ответы!

 

1. Не включено тактирование AC. Вот биты и не включаются.

Так и оказалось. Я устанавливал бит разрешения выхода компаратора до момента включения компаратора. Поменял две строчки кода местами - все заработало.

 

2. Почему бы нет. Должно работать.

Проверил - действительно работает.

 

3. Без кода можно только гадать.....

У АЦп также есть прерывание по уровню..смотрите даташит.

Я это прерываение как раз и использовал, но проблема была в том, что как только его включаешь, перестают происходить события EVSYS_CHMUX_ADCA_CH0_gc и DMA_CH_TRIGSRC_ADCA_CH0_gc до момента срабатывания компаратора. А мне нужно было все данные через DMA сохранить в буфер, независимо от того, выше они порога компаратора или нет. Прерывание по уровню по моему замыслу должно было только разбудить процессор и инициировать обработку сохраненных данных из циклического буфера.

 

Я нашел объяснение в даташите, почему так происходит

Interrupt requests and events can be generated when an ADC conversion is complete OR when an ADC measurements is above or below the ADC compare register value
Т.е. "или-или".

 

В итоге, учитвая то, что один вход может использоваться ADC и AC, я решил поставленную задачу без функции компаратора ADC.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Подскажите пожалуйста (дайте примерчик), как ХМегой считать импульсы? Т.е. как на ней делать то, что обычные Меги делали через входы T0 и T1?

 

В описаниях одни только слова, по которым код не сваришь. Смотрела документы:

AVR1001 : Getting Started With the XMEGA Event System

AVR1306 : Using the XMEGA Timer_Counter

AVR1307 : Using the XMEGA USART"

AVR1311 : Using the XMEGA Timer_Counter Extensions

AVR1313 : Using the XMEGA IO Pins and External Interrupts

AVR1617 : Frequency Measurement with Atmel AVR XMEGA Family Devices"

но толку чуть.

 

Поняла лишь одно: таймер нужно запрограммировать на счет не от делителя тактовой частоты, а от канала событий. Это сделать я смогу, например, как-то так:

TCC0.CTRLA = TC_CLKSEL_EVCH0_gc; // Clock Selection: Event Channel 0

А потом какой-то пин в порту запрограммировать в режиме сенсора. Это тоже вроде бы ясно:

PORTF.PIN7CTRL = PORT_ISC_RISING_gc; // Sense rising edge on PORTF7

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

 

В документе "AVR1001 : Getting Started With the XMEGA Event System" дан такой совет:

4.4 Event Counting

It is possible to use an event channel as a clock source for a Timer/Counter. This can be used to count the number of events on an event channel.

4.4.1 Configuration

In this example, TCC0 will be used to count the number of times a button connected to PD0 has been pressed.

1. Configure PD0 to trigger on rising or falling edge.

2. Select PD0 as event source for event channel 0.

3. Set the digital filter for event channel 0 to the highest possible value.

4. Configure event channel 0 as the clock source for TCC0.

TCC0 will now count the number of times the button connected to PD0 has been pressed.

Однако мне не ясно, как выполнять пунты 2 и 3, а подробности опущены. А про "digital filter for event channel" вообще не нашла даже упоминания, что такой существует.

 

Полагаю, что задаю не слишком тяжелый вопрос, т.к. не прошу вникать в мою задачу, а прошу лишь объяснить, как выкручиваться на ХМеге в тех задачах, которые на обычных Мегах решались через счетный вход таймеров T0 и T1. Например, на обычной Меге для этого было достаточно одной строки кода:

TCCR1B = 0x7; // external clock source, on rising edge

А дальше лишь присоединить сигнал к ножке T1 и дело в шляпе. А с ХМегой уже больше недели над этим вопросом бьюсь, голова распухла от чтения мануалов, а дело с мертвой точки не слезает. Вероятно, в интернете полно таких примеров, но найти их не смогла - видимо запрос не смогла правильно сформулировать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Досконально не разбирался и не экспериментировал, но думаю нужно указать "Системе событий" источник события (нужный пин порта) путём засписи в нужный рег. CHnMUX соотв. данных.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Досконально не разбирался и не экспериментировал, но думаю нужно указать "Системе событий" источник события (нужный пин порта) путём записи в нужный рег. CHnMUX соотв. данных.

 

Ваш ответ слишком абстрактный. Я и так догадываюсь, что для того, чтобы заработало, нужно записать в нужные регистры нужные значения :). Хотелось бы конкретнее - рабочий пример. Можно без объяснений - разберусь сама.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Считает с ноги через компаратор в режиме idle.

Если без AC, то EVSYS_CH3MUX=EVSYS_CHMUX_PORTA_PIN6_gc;

 

 

void main (void){
 EVSYS_CH2MUX=EVSYS_CHMUX_TCD0_OVF_gc;
 EVSYS_CH0MUX=EVSYS_CHMUX_TCC0_OVF_gc;
 TCE0.CTRLA=TC_CLKSEL_EVCH2_gc;
 TCC1.CTRLA=TC_CLKSEL_EVCH0_gc;

 TCD0.CTRLA=TC_CLKSEL_EVCH3_gc;
 ACA.AC0CTRL=0;

  ACA.CTRLB=35;
  ACA.AC0MUXCTRL=(uint8_t)(AC_MUXPOS_PIN6_gc|AC_MUXNEG_SCALER_gc);
  ACA.AC0CTRL=(uint8_t)(AC_INTMODE_RISING_gc|AC_HYSMODE_LARGE_gc|AC_ENABLE_bm);


 uint32_t Freq_cnt=F_t_cek(~(F_CPU/10));
}

uint32_t F_t_cek (uint32_t TT) {

  TCC0.PER=0xFFFF;
  TCC1.PER=0xFFFF;
  TCD0.PER=0xFFFF;
  TCE0.PER=0xFFFF;
  TCC0.CNT=TT;
  TCC1.CNT=TT>>16;
  TCD0.CNT=0;
  TCE0.CNT=0;

  TCC1.INTFLAGS=0xF3;
  TCC1.INTCTRLA=TC_OVFINTLVL_LO_gc; 
  TCC0.CTRLA=TC_CLKSEL_DIV1_gc;
  EVSYS_CH3MUX=EVSYS_CHMUX_ACA_CH0_gc;
  __sleep();
  EVSYS_CH3MUX=EVSYS_CHMUX_OFF_gc;
  TCC0.CTRLA=TC_CLKSEL_OFF_gc;
  TCC1.INTCTRLA=TC_OVFINTLVL_OFF_gc ;

  uint32_t Freq_cnt=0x10000*TCE0.CNT;
  return Freq_cnt+TCD0.CNT;
 };


Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если без AC, то EVSYS_CH3MUX=EVSYS_CHMUX_PORTA_PIN6_gc;

 

Спасибо! Вроде заработало. Действительно секрет состоял в использовании EVSYS.

Моей же ошибкой было то, что PDF-документы я читала (на них Google ссылки хорошо дает), но не видела к ним кодов. А они есть, хотя и в разделе мобилок:

http://www.atmel.com/applications/mobile_e...x?tab=documents

(справа от соответствующих PDF-документов).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А как в обратную сторону? Т.е. то, что все обычные Меги умеют делать через выход OC?

Это когда таймер генерит меандр (или PWM), который выводится на какую-то ножку Меги.

 

А как это реализуется на ХМеге? Тоже через EVSYS?

Документы занового прошерстила, но именно такого примера не нашла. А похожие работать у меня отказались.

 

Пробовала так:

 

TCD0.PER = 1000; // 32 MHz / 1000 = 32 KHz

TCD0.CTRLA = TC_CLKSEL_DIV1_gc;

TCD0.CTRLB = 0;

TCD0.INTCTRLA = 0;

TCD0.CTRLD = TC_EVACT_QDEC_gc | TC_EVSEL_CH5_gc;

 

PORTF_PIN0CTRL = PORT_ISC_LEVEL_gc;

EVSYS.CH5MUX = EVSYS_CHMUX_PORTF_PIN0_gc;

EVSYS.CH5CTRL = EVSYS_QDEN_bm | EVSYS_DIGFILT_2SAMPLES_gc;

Но ничего не вышло - на ножке PORTF0 стоит твердо нуль.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А они есть, хотя и в разделе мобилок:

http://www.atmel.com/applications/mobile_e...x?tab=documents

(справа от соответствующих PDF-документов).

Причём тут мобилки?

 

Appnotes с исходниками.

 

А как в обратную сторону? Т.е. то, что все обычные Меги умеют делать через выход OC?

Это когда таймер генерит меандр (или PWM), который выводится на какую-то ножку Меги.

Про ШИМ смотрите AVR1306 и AVR1306 code

Пункты про Single Slope PWM Mode и Dual Slope PWM Modes

А как это реализуется на ХМеге? Тоже через EVSYS?

Тактировать таймер можно и от системы событий, но зачем? Обычно от системного клока шим тактируют.

 

Такой шим не подойдёт:

{// настройка шима 

        /* Enable output  */
        PWM_PORT.DIR = 1<<PWM_PIN;
        TC0_ConfigClockSource( &TCF0, TC_CLKSEL_OFF_gc );


        /* Set the TC period. */
        TC_SetPeriod( &TCF0, PWM_PERIOD-1);

        /* Configure the TC for single slope mode. */
        TC0_ConfigWGM( &TCF0, TC_WGMODE_SS_gc );

        /* Enable Compare channel A. */
        TC0_EnableCCChannels( &TCF0, TC0_CCBEN_bm );

        TC_SetCompareB( &TCF0,  PWM_PERIOD>>1);
        TC_SetCount( &TCF0, 0);

        /* Start timer by selecting a clock source. */
        TC0_ConfigClockSource( &TCF0, TC_CLKSEL_DIV1_gc );
    }

?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Такой шим не подойдёт:

 

Меня не генерация шима волнует, а способ его передачи на пин! Т.е. во вне микроконтроллера.

В вашем же коде я вижу только то, то вы настроили один пин порта на вывод (PWM_PORT.PWM_PIN), но нигде не вижу его связи с таймером, т.к. его имя нигде больше не упоминается.

Откуда таймер знает, что надо выдавать меандр именно на этот пин? А если бы у меня на вывод было открыто много пинов у разных портов? Неужели таймер станет гнать меандр на все порты, сконфигурированные на вывод?

Думаю, что-то важное вы пропустили. А именно то, что меня волнует - перенаправление меандра на конкретный пин.

 

В рекомендованном вами документе AVR1306 очень много написано про разные варианты модуляции, но что мне от того толку, если эту модуляцию наружу вывести не могу?

Изменено пользователем IgorKossak
избыточное цитирование

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Меня не генерация шима волнует, а способ его передачи на пин! Т.е. во вне микроконтроллера.

В вашем же коде я вижу только то, то вы настроили один пин порта на вывод (PWM_PORT.PWM_PIN), но нигде не вижу его связи с таймером, т.к. его имя нигде больше не упоминается.

Упоминается:

TC0_EnableCCChannels( &TCF0, TC0_CCBEN_bm );

 

Откуда таймер знает, что надо выдавать меандр именно на этот пин?

Таймер узнаёт это из того, что разрешена Capture-compare функция на нужном канале таймера, а канал привязан к определённому пину порта.

 

Если у меня на вывод открыто много пинов у разных портов? Неужели таймер станет гнать меандр на все порты, сконфигурированные на вывод?

С чего бы таймеру это делать? Не будет он так работать (разве что с ума сойдёт).

 

Думаю, что-то важное вы пропустили.

Ничего я не пропустил - шим выдаётся куда нужно.

 

А именно то, что меня волнует - перенаправление меандра на конкретный пин.

Разрешив альтернативную функцию и включив порт на выход вы привязываете шим к нужному пину.

post-17322-1371053741_thumb.png

В рекомендованном вами документе AVR1306 очень много написано про разные варианты модуляции, но что мне от того толку, если эту модуляцию наружу вывести не могу?

Пример шима можете взять в коде к AVR1306:

/*!
*  This function implements example 4, "Using a Timer/Counter for PWM
*  Generation" from the "Getting Started" section of application note AVR1306.
*
*  This example shows how to configure TCC0 for pulse width modulation output
*  with varying duty cycle on channel A.
*/
void Example4(void)
{
 //Enable output on PC0.
 PORTC.DIR = 0x01;

 //Set the TC period.
 TC_SetPeriod(&TCC0, 0xffff);

 //Configure the TC for single slope mode.
 TC_ConfigWGM(&TCC0, TC_WGMODE_SS_gc);

 //Enable Compare channel A.
 TC_EnableCCChannels(&TCC0, TC_CCAEN_bm);

 //Start timer by selecting a clock source.
 TC_ConfigClockSource(&TCC0, TC_CLKSEL_DIV1_gc);

 uint16_t compareValue = 0x0000;
 for (;;) {
//Calculate new compare value.
compareValue += 32;

//Output new compare value.
TC_SetCompareA(&TCC0, compareValue);

//Wait for the new compare value to be latched from CCABUF[H:L] to CCA[H:L].
//This happens at TC overflow (UPDATE).
while( TC_GetOverflowFlag(&TCC0) == 0) {
}

//Clear overflow flag.
TC_ClearOverflowFlag(&TCC0);
 }
}

 

Этого не достаточно?

Изменено пользователем IgorKossak
[codebox] для длинного кода, [code] - для короткого!!!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Упоминается:

TC0_EnableCCChannels( &TCF0, TC0_CCBEN_bm );

 

TCF0 - это имя таймера, а не порта. Где у вас упоминается PWM_PORT, кроме того места, где вы его открыли на вывод?

 

В хидерое среди определений PWM_PIN не нашла. Это константа? А если мне нужно PWM выдать на другой пин, тогда что? Или место выдачи PWM в порту фиксировано?

Скажем, если мне нужен PWM на другой ножке, то какие измения в коде я должна провести, КРОМЕ открытия этого пина на вывод?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

TCF0 - это имя таймера, а не порта

Совершенно верно. TCF0 - таймер.

 

Где у вас упоминается PWM_PORT, кроме того места, где вы его открыли на вывод?

 

В определениях упоминается:

#define PWM_PORT PORTF
#define PWM_PIN 1
#define PWM_PERIOD (3686400UL*8/50000UL) // 3686400UL*8 - тактовая ядра

Больше нигде.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В определениях упоминается:

#define PWM_PORT PORTF
#define PWM_PIN 1
#define PWM_PERIOD (3686400UL*8/50000UL) // 3686400UL*8 - тактовая ядра

Больше нигде.

 

Так это, значит, ваши собственные определения?

А если я переопределю PWM_PIN на другое число, скажем на 2 вместо 1, то PWM начет выводиться на соседнюю ножку? Или нет?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...