ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Четверг
25 апреля
416639 Топик полностью
Ксения (10.06.2013 14:37 - 15:50, просмотров: 755) ответил Ljutik1 на хочу перейти с ATmega на ATXmega. Нужны советы
Очарована ХМегой - красота, а не контроллер! Я хоть тут из себя гуру корчу :), но опыта работы с ХМегой у меня чуть больше недели. С начала месяца ушла в отпуск (у меня и ДР тоже в первых числах) и уехала отдыхать в Крым на море. Однако живу цивилизованно в городской квартире, интернет есть и ноутбук с собой. Вот и демо-плату с ATxmega128A1 с собой взяла, чтобы вечерами было чем приятным заняться, когда на улице уже стемнело и комары кусаются. Активный интерес к ХМеге появился, когда мне не хватило таймеров для счета импульсов. Эту свою проблему я здесь уже обсуждала в различных плоскостях. Сначала задавала вопрос о максимальном числе таймеров среди обычных Мег. Выяснилось, что таймеров может быть больше двух, но счетных входов обычно только два - T0 и T1, остальные внешнего ввода частоты не имеют. Порадовала только ATmega1284(P), у которой 4 таймера и наружу выведен еще вход T3 (хотя в даташитах разных версий на этот счет противоречивые данные). Впрочем, для меня это тоже не выход, т.к. требуются 4 счетных входа. Из-за этого принялась городить мультиплексор, переключающий пару входов T0 и T1 с одного источника сигналов на другой. Об этом тоже спрашивала, т.к. была проблема с быстродействием. В конце концов, сделала его на одном корпусе ЛА3. Заработало, но скоро выяснилось что все 4 результата счета требуются одновременно, а не по очереди. На протяжении всех этих перепетий мне неоднократно советовали применить ХМегу, но я упиралась, как могла, т.к. не хотела переходить на 3-х вольтовое питание, когда все остальная схема работает на 5-ти вольтах. И, тем не менее, интерес к ХМеге у меня рос, тем более что ее все чаще обсуждают на конференциях. Ну, а эта тема явилась последней каплей, склонившей меня к изучению ХМеги. Опять же стыдно мне, фанатке Атмела, бояться ХМег :). И так, докладываю о результатах (хотя и промежуточных). Первое впечатление ужасное – поначалу всё кажется очень сложным. Вот и топик-стартера я испугала, поделившись своим первым впечатлением. Между тем, ХМега, как контроллер просто замечательный! Верх совершенства! В отличие от обычных Мег, очень многие операции позволяет завести аппаратно, т.е. запрограммировать связь событий, после чего они начинают исполняться аппаратно, без каких-либо прерываний и исполнений кода. Теперь о самом главном - трудностях перехода о обычной Меги на ХМегу. Здесь ситуация такова. Если использовать ХМегу до краев ее возможностей, то действительно нужно познать очень много чего нового и довольно сложного. Уже только хидер к ней раз в 40 больше, чем у простой Меги. Но! Если "эмулировать" ХМегой возможности старой Меги, то это не только просто, но и может быть сделало ФОРМАЛЬНО!!! Т.е. заменой одного кода на другой, подобно подстрочному переводу со словарем. Никакого особого ума для процедуры такой подстановки не требуется. Я даже программу хотела такую написать, но этому мешает отсутствие информации о том, как каком из портов используется USART, а если таймер, то который из множества. Ну, и данные, записываемые в управляющие порты, потребовались бы в числовом виде, а не в виде формулы или слива из переменных. Другими словами формализм подстановки здесь почти всегда срабатывает. Теперь дам конкретные советы. Если бы мне кто-то такое раньше дал, то я бы освоила ХМегу за один день :). 1. Портов у ХМеги стало много больше, потому у них кроме имен появились отчества :). Но к этому очень легко привыкнуть, т.к. строятся они на понятной мнемонике. Заменяем (вместо номера порта пишу букву X): PORTX -> PORTX.OUT PINX -> PORTX.IN DDRX -> PORTX.DIR вместо точки можно писать подчеркивание, но лично мне больше нравится точка по аналогии с элементами структур на языке C. У служебных регистров (таймеров, USART, SPI, ADC и др.) аналогично. Их имена легко найти в хидере. Например: USARTE0.BAUDCTRLA USARTE0.BAUDCTRLB USARTE0.CTRLA USARTE0.CTRLB USARTE0.CTRLC USARTE0.STATUS - в данном случае речь идет о USART на порту E. Концевые буквы A,B,C пусть не раздражают - это просто деление служебного регистра на байты, т.е. все флаги в одном байте не помещаются. Сами же битовые флаги в хидере тоже поименованы, а потому код программы получается нагляднее, когда пользуются этими именами, а не цифирью. Например, установка 57600 бод на Fosc = 32 МГц: int bsel = 2221; // 32 MHz/16/57600/(2^-6) - 1 USARTE0.BAUDCTRLA = (unsigned char)bsel; USARTE0.BAUDCTRLB = (-6 << 4) | (bsel >> 8); USARTE0.CTRLA = USART_RXCINTLVL_LO_gc | USART_TXCINTLVL_LO_gc; USARTE0.CTRLB = USART_RXEN_bm | USART_TXEN_bm; USARTE0.CTRLC = USART_CHSIZE_8BIT_gc | USART_SBMODE_bm; Кажется сложным, но на самом деле просто. bsel - делитель частоты, под него отведено 12 бит - 8 бита в регистре BAUDCTRLA и 4 в BAUDCTRLВ. Помимо этого есть мантисса степени двойки, позволяющая увеличить bsel до максимальной точности (но не более 4095). В моем примере bsel пришлось округлить, но из-за того, что число велико, ошибка крайне мала. Но кто не хочет заморачиваться с мантиссой, пишите попросту: USARTE0.BAUDCTRLA = делитель; USARTE0.BAUDCTRLB = 0; и будет у вас, как в старой Меге. USARTE0.CTRLA = USART_RXCINTLVL_LO_gc | USART_TXCINTLVL_LO_gc; - здесь я задаю низкий приоритет прерываниям RXC и TXC. У Меги все прерывания были равны, а у ХМеги бывают низкого приоритета (LO), среднего (MID) и высокого (HI). Сложности здесь нет никакой, просто старшее прерывание может перерывать процедуру обработки более низкого. У меня главное таймеры, а передача по UASRT ерунда, потому и назначила им низкий приоритет. Не хотите заморачиваться с приоритетами - назначайте всем прерываниям один и тот же приоритет (не важно какой из трех), и будут они тогда ждать друг дружку, как в обычной Меге. Главное не забыть разрешить всем этим прерываниям выполняться - вот так нужно сделать лишь однажды: PMIC.CTRL = PMIC_HILVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_LOLVLEN_bm; чтобы все три приоритета разрешить к исполнению. USARTE0.CTRLB = USART_RXEN_bm | USART_TXEN_bm; - разрешение прерываний RXC и TXC. USARTE0.CTRLC = USART_CHSIZE_8BIT_gc | USART_SBMODE_bm; - 8 бит данных + 1 стоп бит. От стоп-бита можно отказаться, убрав его флаг. 2. У ХМеги частота осциллятора и ее источник изменяются программно, а не фузами, как у обычных Мег. И в этом состоит первая сложность, с которой приходится столкнуться. А поскольку это место одно из сложных, то на этом месте ХМегу часто бросают. Так уж неудачно для ХМеги сложилось, что самая большая трудность встречается в самом начале программы. Для кварца 8 МГц это выглядит так: CLK.PSCTRL = 0x00; // отказываюсь от делителя OSC.XOSCCTRL = 0x4B; // выбираю диапазон установленного кварца (2 MHz - 9 MHz) OSC.XOSCFAIL = OSC_XOSCFDIF_bm | OSC_XOSCFDEN_bm; // включаю детекцию ошибок от нестабильности частоты CCP = CCP_IOREG_gc; // блокирую на 4 такта всю работу (при важных переключениях так всегда поступают) OSC.CTRL = OSC_XOSCEN_bm; // велю запустить генератор на кварце while( !(OSC.STATUS & OSC_XOSCRDY_bm)); // ждем, пока кварц не разгонится CCP = CCP_IOREG_gc; // блокирую на 4 такта CLK.CTRL = CLK_SCLKSEL_XOSC_gc; // велю перейти на внешний источник частоты while( !(OSC.STATUS & OSC_XOSCRDY_bm)); // снова жду, пока не устаканится - сочинить такое никому не под силу, очевидно, что это я где-то списала, как и все остальные. :) Помимо этого ХМега способна разогнать свою частоту с помощью встроенного PLL в целое число раз (но не более, чем 31). Поэтому после перехода на кварцованнцю частоту 8 МГц, я еще и PLL запускаю со множителем 4, чтоб достигнуть 32 Мгц. Эту часть кода я опускаю, что бы не пугать начинающих. :) 3. Программирование таймеров. Пример полусекундного таймера: TCC0.PER = 15625; // 2 Гц TCC0.CTRLA = TC_CLKSEL_DIV1024_gc; TCC0.CTRLB = 0; TCC0.INTCTRLA = TC_OVFINTLVL_HI_gc; где: TCC0.PER - период. До этого числа счетчик возрастает с нуля, вызывает прерывание и снова падает до нуля. Т.е. здесь минимальный режим таймера работает подобно CТС-режиму на старых Мегах, потому и задание СТС-режима тут отсутствует. TCC0.CTRLA = TC_CLKSEL_DIV1024_gc; - делитель на 1024, как и у Меги самый большой из возможных. TCC0.INTCTRLA = TC_OVFINTLVL_HI_gc; - вызывать прерывание высокого приоритета (приоритет может быть любой, но для меня это критично). А теперь пример посложнее - реализация идеи, которую мне Леонид Иваныч подсказал. Речь идет о двух прерывания на одном и том же таймере: по переполнению - 1 Гц, по сравнению уровнем на полувысоте - 2 Гц для мигания светодиодом (им вдвое чаще приходится дергать). TCC0.CCA = 15625/2; // Полувысота для режима сравнения (через нее зигзаг за секунду проходит дважды) TCC0.PER = 15625; // Высота зигзага 1 Гц ровно TCC0.CTRLA = TC_CLKSEL_DIV1024_gc; // делитель тактовой частоты на 1024 TCC0.CTRLB = TC0_CCAEN_bm | TC_WGMODE_DS_T_gc; // Разрешаю Compare-Mode, устанавливаю режим зигзага вместо пилы TCC0.INTCTRLA = TC_OVFINTLVL_HI_gc; // разрешаю прерывание высокого приоритета для переполнения - 1 Гц TCC0.INTCTRLB = TC_CCAINTLVL_LO_gc; // разрешаю прерывание низкого приоритета для сравнения - 2 Гц Вот, собственно и почти все трудности. Не испытывала пока SPI, ADC и DAC. Но SPI здесь задается подобно USART, а ЦАПа в простых Мегах не было. Однако что не возьми, то задается либо подобно UASRT, либо подобно таймеру. Т.е. в принципе не слишком сложно. Опять же поспрошать можно, как то или другое установить под свои значения, которые за время работы над проектом обычно не меняются. ХМеге троекратное ура! Вот где можно разгуляться душе, успевшей заскорузнуть на программировании обычных Мег. :)