Формирование синусоиды с преобразованием в ШИМ сигнал и дополнительные возможности таймеров в Xmega

Формирование синусоиды с преобразованием в ШИМ сигнал и дополнительные возможности таймеров в Xmega

   Микропроцессоры Xmega имеют несколько таймер-счетчиков с расширенными возможностями, которые могут быть использованы, например, для управления двигателями или для контроля за питанием. Данная статья посвящена данным возможностям и в частотности формированию синусоиды и формировании из нее ШИМ сигнала с вставкой интервалов мертвого времени для управления ключами инвертора, который может использоваться, например, для управления электродвигателями.

   Улучшение дополнительных сигналов

   Улучшение дополнительных сигналов – «Advanced Waveform eXtension» (AWeX) является расширением возможностей таймера-счетчика, которые обычно используют в применениях для управления двигателями и контролем за питанием. Когда используется улучшение AWeX, выходной сигнал ШИМ с таймер-счетчика проходит через модуль AWeX контролирующий ножки порта.

   На следующем рисунке показан модуль AWeX имеющий три подфункции: вставка мертвого времени – «Dead-time Insertion» (DTI), образцовый генератор и защита от повреждения.

Формирование синусоиды с преобразованием в ШИМ сигнал в Xmega

   

   Вставка мертвого времени

   Во многих применениях, таких, как управление электродвигателями, используется генерация ШИМ сигнала по полумостовой схеме, аналогичной показанной на следующем рисунке:

Формирование синусоиды с преобразованием в ШИМ сигнал в Xmega

   Если высокая сторона переключается по ШИМ сигналу PWMH, а нижняя по инверсному ШИМ сигналу PWML, то выходное напряжение VOUT будет пропорционально скважности ШИМ сигнала PWMH.

   Показанная полумостовая схема обычно реализуется на ключах MOSFET или IGBT. Так как эти устройства не могут включиться или отключиться мгновенно, в силу того, что существует небольшое время нарастания/спадания выходного сигнала. Если сигнал, подаваемый на низкую сторону, является инверсией сигнала подаваемого на высокую сторону, то всегда существует короткий интервал времени, когда обе стороны включены, что приведет к короткому замыканию между питанием и землей в течение этого периода. Такие замыкания называют сквозными и являются не допустимыми.

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

   Интервалы протяженности мертвого времени для высокой и низкой стороны могут быть установлены индивидуально в регистрах DTHS и DTLS соответственно. Для простоты регистры DTHS и DTLS могут быть установлены в одинаковое значение записью регистра DTBOTH. Значение мертвого времени задается в тактах основных системных часов. Допустимые значения мертвого времени находятся в диапазоне от 0 до 255 тактов основных системных часов.

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

   Только парные ножки, настроенные на выход, могут быть использованы для вставки мертвого времени модулем AWeX. Карта расположения ножек для вставки мертвого времени показана в следующей таблице:

Ножка

Сигнал

Pin 0

CCAH

Pin 1

CCAL

Pin 2

CCBH

Pin 3

CCBL

Pin 4

CCCH

Pin 5

CCCL

Pin 6

CCDH

Pin 7

CCDL

 

   Образцовый генератор

   Образцовый генератор использует регистры DTI и двойной буферный механизм для синхронизации битового образца на порту, к которому он подключен. Компаратор канала А таймера-счетчика 0 соединенный с тем же портом ввода-вывода может быть распределен или перекрывать все ножки порта. Это позволяет сложным образцам ШИМ быть сгенерированными на потру ввода-вывода.

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

Функционирование образцового генератора показано на следующем рисунке:

Формирование синусоиды с преобразованием в ШИМ сигнал в Xmega

   Регистр DTBUFLS используется в качестве буферного регистра для регистра разрешения перекрытия выхода – «Output Override Enable» (OOE) модуля AWeX, в то время как DTBUFHS используется в качестве буферного регистра для регистра выхода OUT связанного с модулем порта ввода-вывода. Захват значений полученных из буферного регистра и передача их предназначенным выходам происходит по событию UPDATE сформированного в модуле таймер-счетчика.

 

   Защита от повреждения

   Функция защиты от повреждения позволяет осуществлять быстрые и независимые действия при обнаружении повреждения. Защита от повреждения является контролируемым событием, таким образом, любое событие Системы событий может быть использовано для запуска действия по обнаружению повреждения.

   Когда функция защиты от повреждения включена, поступающие событие от любого выбранного канала событий может вызвать ее механизм работы. Каждый канал событий может быть независимо настроен как вход защиты от повреждения. Все настроенные на защиту от повреждения каналы событий объединяются в один по схеме ИЛИ и запускают механизм защиты при поступлении любого из событий.

   Защита может выполнять два действия:

  • отмена разрешения перекрытия, которая очищает регистр разрешения перекрытия выходов (OUTOVEN) и, тем самым, отключает перекрытие на всех выходах таймера-счетчика.
  • отмена направления, которая сбрасывает регистр направления (DIR) соответствующего порта, что переводит все ножки порта третье состояние.

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

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

  • в режиме блокировки, выход генератора импульсов будет находиться в аварийном состоянии до тех пор, пока не исчезнет условие срабатывания защиты и программно не будет сброшен флаг обнаружения повреждения. После выполнения двух этих условий, выход генератора импульсов восстановит свою нормальную работу, но только после выполнения очередного события UPDATE таймер-счетчика.
  • в пошаговом режиме, выход генератора импульсов будет находиться в аварийном состоянии до тех пор, пока не исчезнет условие срабатывания защиты. После выполнения этого условия, выход генератора импульсов восстановит свою нормальную работу, но только после выполнения очередного события UPDATE таймер-счетчика.

 

   Высокое разрешение

    Модуль разрешения HiRes (High Resolution - "Высокое разрешение") увеличивает разрешение ШИМ на 2 разряда. Это достигается комбинацией генератора ШИМ сигнала и стандартным модулем таймер-счетчика с высокой разрешающей способностью позволяющим увеличить частоту в 4 раза. Данный принцип показан на следующем рисунке:

Формирование синусоиды с преобразованием в ШИМ сигнал в Xmega

   Ширина импульса разделена на две части: грубое время tCOARSE и уточненное время tFINE, сумма которых равна времени импульса tP. Таймер-счетчик генерирует грубую часть импульса, в то время как функция HiRes растягивает его на промежуток до 3 тактов.

   Это достигается делением процесса формирования ШИМ сигнала на две части. Таймер-счетчик используется для генерации ШИМ сигнала из 14 старших битов для канала сравнения таймер счетчика. Этот грубый сигнал подается на модуль HiRes, который отвечает за добавление улучшенной части импульса состоящего из двух младших битов.

   Работа расширения HiRes контролируется двумя битами HREN0 и HREN1 в регистре HIRESx.CTRL разрешающие работу HiRes таймер-счетчиков 0 и 1 соответственно.

   Для корректной работы модуля HiRes необходимо настроить входные часы на частоту в 4 раза большую, чем основные системные часы. На следующем рисунке представлена упрощенная схема формирования часов:

Формирование синусоиды с преобразованием в ШИМ сигнал в Xmega

   Как представлено на рисунке делители B и С делят основную частоту системных часов на 4. Модуль HiRes тактируется от выхода делителя А, т.е. с частотой в 4 раза большей частоты ЦПУ.

   При включенном модуле HiRes и корректной настройке системных часов таймер-счетчик готов к работе с высокой разрешающей способностью. В режиме HiRes таймер-счетчик ведет себя примерно так, как будто частота системных часов увеличена в 4 раза. Однако, это не совсем так, поскольку имеются важные отличия:

  • Таймер-счетчик не имеет четырехкратную частоту системных часов, но счетчик достигает значения 4 в каждом системном цикле. Другими словами второй младший бит всегда 0.
  • Значение периода/вершины таймер-счетчика не может быть установлено в значение «самое высокое разрешение». Второй младший бит должен быть равен 0.
  • Выходные положительные и отрицательные импульсы не могут быть короче грубой части импульса. Значение для сравнения равное 0 выдает постоянный низкий сигнал. Значение для сравнения равное PER выдает постоянный высокий сигнал.

   Ну и как обычно, напоследок рабочий пример программы по формированию синусоиды и преобразованию ее в ШИМ сигнал с вставкой метрового времени для управления ключами инвертора.

 

   Пример.

   Задача: Написать программу формирования синусоидального сигнала с частотой 50 Гц и выдачей ее в форме ШИМ на выходную ножку с вставкой интервалов мертвого времени.

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

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

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

 

   Для начала рассмотрим вариант с непосредственным вычислением значений синусоиды в реальном времени и преобразование ее в ШИМ сигнал с вставкой интервалов мертвого времени.

   Будем использовать внешний кварцевый генератор с частотой 16 МГц и основной системной частоты 48 МГц и нормальный режим таймера. Более подробную информацию о тактировании от внешнего источника можно найти в уроке «Задание частоты тактирования Xmega A от внешнего генератора». Для удобства и наглядности будем выдавать сформированную синусоиду на ЦАП. В качестве выходного канала ЦАП возьмем канал 0 DACB. Более подробную информацию о использовании ЦАП можно найти в уроке «Использование ЦАП в микропроцессорах Xmega А». Т.к. вычисление занимает много времени, установим частоту вычисления значений синусоиды (происходит по прерыванию таймера) 5 кГц. При формировании ШИМ будем использовать одностороннюю пилу. Более подробную информацию про формирование ШИМ и задание частоты таймера можно найти в уроке «Использование таймера на Xmega A». Амплитуду синусоиды зададим равной 2047 для максимальной развертки синусоиды ЦАП и наименьшей погрешности при формировании ШИМ. Частоту синусоиды установим равной 50 Гц, а частоту ШИМ 11,7 кГц, что должно быть достаточно для точной передачи сигнала и работы низковольтных силовых ключей (но лучше уточнить в документации на силовые ключи максимально допустимую частоту переключений и изменить ее, если требуется, в меньшую сторону). В качестве выходов ШИМ сигналов будем использовать канал CCB модуля AWeX это соответсвует ножкам 2 и 3 порта Е для управления ключами низкой и высокой стороны инвертора соответственно. Т.е. на ножке 3 порта Е будет ШИМ сигнал с вставленными интервалами мертвого времени, а на ножке 2 инвертированная ШИМ с вставленными интервалами мертвого времени. Интервал мертвого времени надо выбирать исходя из параметров используемых силовых ключей, в примере возьмем его равным 1 мкс как для высокой, так и для низкой стороны.

   Код работающей программы для процессора Xmega128A1 имеет следующий вид:

#define ENABLE_BIT_DEFINITIONS // разрешение использования групповых битовых имен
 
/* Объявление используемых библиотек */
#include <ioxm128a1.h>
#include <ina90.h>
#include <math.h>
 
#define Ampl 2047   // Амплитуда синусоиды
#define Freq 50       // Частота синусоиды
float Step=(float)Freq/5000*2*3.1415926536; // Шаг угла для вычисления синусоиды при частоте вычисления 5 кГц
float MaxAngle=(float)2*3.1415926536;         // Максимальный угол соответствующий 360 градусам
float Angle;            // текущий угол синусоиды
float sinV;              // Вычисленное значение синусоиды
 
void InitDAC(void)         // Настройка ЦАП
{
   DACB.CTRLB = 0;                                // одноканальная работа канала 0
   DACB.CTRLA = 0x05;                           // Разрешение работы DACB и канала 0 
   DACB.TIMCTRL = 0x50;                       // минимум 48 CLK между преобразованиями
}
 
int main(void)
{
   __disable_interrupt();   // Запрещение прерываний
 
/* Установка тактирования от 3-х кранной частоты внешнего генератора 3*16=48 */
   OSC.XOSCCTRL = 0xCB;                 // выбор внешнего генератора с временем запуска 16 тыс. CLK и частотой 12-16 МГц
   OSC.CTRL = 0x08;                           // разрешение работы внешнего генератора
   while((OSC.STATUS & 0x08) == 0 ) ; // ожидание появления в регистре статуса бита включения синхронизации от внешнего генератора
      OSC.PLLCTRL = 0xC3;                   // настройка блока PLL на синхронизацию от внешнего источника и 3-х кратоное умножение
   OSC.CTRL = OSC.CTRL | 0x10;         // разрешение работы блока PLL
   while((OSC.STATUS & 0x10) == 0 ) ; // ожидание появления в регистре статуса бита включения блока PLL
      CCP = 0xD8;                                 // включение защиты от изменения регистров ввода-вывода на время изменения синхронизации
   CLK.CTRL = 0x04;                           // настройка системной синхронизации от блока PLL
   OSC.CTRL = OSC.CTRL & 0xFE;       // отключение системной синхронизации от внутреннего RC-генератора частотой 2 МГц
 
   PORTE.DIRSET = 0x0C;             // Настройка ножек 2 и 3 порта Е как выходы - соответствующие инверсии OC0B и OC0B модуля AWeX
 
   TCC0.CTRLA=0x05;      // N=64
   TCC0.PER=150-1;         // частота таймера 5кГц при системной частоте 48МГц
   TCC0.INTCTRLA=1;      // разрешение прерываний по таймеру с приоритетом low
 
   TCE0.CTRLA=0x01;      // N=1;
   TCE0.CTRLB=0x03;      // Режим односторонней ШИМ
   TCE0.PER=4096-1;       // частота ШИМ 11,7 кГц при системной частоте 48МГц
   AWEXE.CTRL=AWEX_DTICCBEN_bm;   // Разрешение работы вставки интервалов мертвого времени по каналу B
   AWEXE.OUTOVEN=0x0C; // Перекрытие выходов 2 и 3 порта Е модулем AWeX
   AWEXE.DTBOTH=48;    // интервал метрового времени на оба выходных сигнала по 1 мкс при системной частоте 48МГц
 
   PMIC.CTRL = 1;           // приоритет прерываний уровня low
   InitDAC();                   // Запуск процедуры инициализации ЦАП
 
   __enable_interrupt();   // Разрешение прерываний
 
   while(1) {}                  // пустой бесконечный цикл
}
 
#pragma vector=TCC0_OVF_vect   // обработка прерываний по переполнению таймера С0
__interrupt void irqTCC0_OVF_vect(void)
{
   Angle=Angle+Step;                // Увеличение угла на размер шага
   if (Angle>=MaxAngle)             // Если угол превышает максимальный, то обнуление угла
      Angle=Angle-MaxAngle;
   sinV=sinf(Angle)*Ampl+2048; // Вычисление синусоиды и сдвиг ее на среднее значение равное 2048
 
    if (DACB.STATUS & 1)           // проверка пустоты регистра канала 0
       DACB.CH0DATA = (int)(sinV);  // если пуст - запись в ЦАП текущего значения синусоиды - вывод ее на ЦАП
 
    TCE0.CCB=(int)(sinV);          // Запись в модуль СС текущего значения синусоиды - вывод ее в форме ШИМ
}
 

   Рассмотрим вариант с формированием синусоиды из массива значений и преобразование ее в ШИМ сигнал с вставкой интервалов мертвого времени.

   Будем использовать внешний кварцевый генератор с частотой 16 МГц и основной системной частоты 48 МГц и нормальный режим таймера. Более подробную информацию о тактировании от внешнего источника можно найти в уроке «Задание частоты тактирования Xmega A от внешнего генератора». Для удобства и наглядности будем выдавать сформированную синусоиду на ЦАП. В качестве выходного канала ЦАП возьмем канал 0 DACB. Более подробную информацию о использовании ЦАП можно найти в уроке «Использование ЦАП в микропроцессорах XMega А». Установим частоту для изменения значений синусоиды (происходит по прерыванию таймера) 10 кГц т.е. имеем 200 значений на период при частоте синусоиды 50 Гц. При формировании ШИМ будем использовать одностороннюю пилу. Более подробную информацию про формирование ШИМ и задание частоты таймера можно найти в уроке «Использование таймера на Xmega A». Массив значений синусоиды рассчитаем на 200 точек на период при амплитуде 2047 и среднем значением 2048 для максимальной развертки синусоиды ЦАП и наименьшей погрешности при формировании ШИМ. Частоту синусоиды установим равной 50 Гц, а частоту ШИМ 11,7 кГц, что должно быть достаточно для точной передачи сигнала и работы низковольтных силовых ключей (но лучше уточнить в документации на силовые ключи максимально допустимую частоту переключений и изменить ее, если требуется, в меньшую сторону). В качестве выходов ШИМ сигналов будем использовать канал CCB модуля AWeX это соответсвует ножкам 2 и 3 порта Е для управления ключами низкой и высокой стороны инвертора соответственно. Т.е. на ножке 3 порта Е будет ШИМ сигнал с вставленными интервалами мертвого времени для высокой стороны, а на ножке 2 инвертированный ШИМ с вставленными интервалами мертвого времени для низкой стороны. Интервал мертвого времени надо выбирать исходя из параметров используемых силовых ключей, в примере возьмем его равным 1 мкс как для высокой, так и для низкой стороны.

   Код работающей программы для процессора Xmega128A1 имеет следующий вид:

#define ENABLE_BIT_DEFINITIONS // разрешение использования групповых битовых имен
 
/* Объявление используемых библиотек */
#include <ioxm128a1.h>
#include <ina90.h>
 
/* Массив значений синусоиды - 200 точек на период при амплитуде 2047 и среднем значении 2048 */
int sintable[200]={2048,2112,2177,2241,2305,2368,2432,2495,2557,2619,2681,
2742,2802,2861,2920,2977,3034,3090,3145,3199,3251,3303,3353,3402,3449,3495,
3540,3584,3625,3665,3704,3741,3776,3810,3842,3872,3900,3927,3951,3974,3995,
4014,4031,4046,4059,4070,4079,4086,4091,4094,4095,4094,4091,4086,4079,4070,
4059,4046,4031,4014,3995,3974,3951,3927,3900,3872,3842,3810,3776,3741,3704,
3665,3625,3583,3540,3495,3449,3402,3353,3303,3251,3199,3145,3090,3034,2977,
2920,2861,2802,2741,2681,2619,2557,2495,2432,2368,2305,2241,2177,2112,2048,
1984,1919,1855,1791,1728,1664,1601,1539,1477,1415,1355,1294,1235,1176,1119,
1062,1006,951,897,845,793,743,694,647,601,556,513,471,431,392,355,320,286,
254,224,196,169,145,122,101,82,65,50,37,26,17,10,5,2,1,2,5,10,17,26,37,50,65,
82,101,122,145,169,196,224,254,286,320,355,392,431,471,513,556,601,647,694,
743,793,845,897,951,1006,1062,1119,1176,1235,1294,1355,1415,1477,1539,1601,
1664,1728,1791,1855,1919,1984};
 
int N=0;           // номер текущего значения массива синусоиды
 
void InitDAC(void)         // Настройка ЦАП
{
   DACB.CTRLB = 0;                        // одноканальная работа канала 0
   DACB.CTRLA = 0x05;                   // Разрешение работы DACB и канала 0
   DACB.TIMCTRL = 0x50;                // минимум 48 CLK между преобразованиями
}
 
int main(void)
{
   __disable_interrupt();   // Запрещение прерываний
 
/* Установка тактирования от 3-х кранной частоты внешнего генератора 3*16=48 */
   OSC.XOSCCTRL = 0xCB;                 // выбор внешнего генератора с временем запуска 16 тыс. CLK и частотой 12-16 МГц
   OSC.CTRL = 0x08;                           // разрешение работы внешнего генератора
   while((OSC.STATUS & 0x08) == 0 ) ; // ожидание появления в регистре статуса бита включения синхронизации от внешнего генератора
      OSC.PLLCTRL = 0xC3;                   // настройка блока PLL на синхронизацию от внешнего источника и 3-х кратоное умножение
   OSC.CTRL = OSC.CTRL | 0x10;         // разрешение работы блока PLL
   while((OSC.STATUS & 0x10) == 0 ) ; // ожидание появления в регистре статуса бита включения блока PLL
      CCP = 0xD8;                                 // включение защиты от изменения регистров ввода-вывода на время изменения синхронизации
   CLK.CTRL = 0x04;                           // настройка системной синхронизации от блока PLL
   OSC.CTRL = OSC.CTRL & 0xFE;       // отключение системной синхронизации от внутреннего RC-генератора частотой 2 МГц
 
   PORTE.DIRSET = 0x0C;              // Настройка ножек 2 и 3 порта Е как выходы - соответствующие инверсии OC0B и OC0B модуля AWeX
 
   TCC0.CTRLA=0x05;       // N=64
   TCC0.PER=75-1;           // частота таймера 10кГц при системной частоте 48МГц
   TCC0.INTCTRLA=1;       // разрешение прерываний по таймеру с приоритетом low
 
   TCE0.CTRLA=0x01;        // N=1;
   TCE0.CTRLB=0x03;        // Режим односторонней ШИМ
   TCE0.PER=4096-1;         // частота ШИМ 11,7 кГц при системной частоте 48МГц
   AWEXE.CTRL=AWEX_DTICCBEN_bm;   // Разрешение работы вставки интервалов мертвого времени по каналу B
   AWEXE.OUTOVEN=0x0C; // Перекрытие выходов 2 и 3 порта Е модулем AWeX
   AWEXE.DTBOTH=48;       // интервал метрового времени на оба выходных сигнала по 1 мкс при системной частоте 48МГц
 
   PMIC.CTRL = 1;             // приоритет прерываний уровня low
   InitDAC();                     // Запуск процедуры инициализации ЦАП
 
   __enable_interrupt();     // Разрешение прерываний
 
   while(1) {}                   // пустой бесконечный цикл
}
 
#pragma vector=TCC0_OVF_vect   // обработка прерываний по переполнению таймера С0
__interrupt void irqTCC0_OVF_vect(void)
{
   if (DACB.STATUS & 1)                   // проверка пустоты регистра канала 0
   DACB.CH0DATA = sintable[N++];  // если пуст - запись в ЦАП текущего значения синусоиды - вывод ее на ЦАП
 
   if (N>=200) N=0;                         // Если массив окончен, то обнуление его
   TCE0.CCB=(int)(sintable[N]);        // Запись в модуль СС текущего значения синусоиды - вывод ее в форме ШИМ
}