PLL генератор в Xmega

    Мы уже знаем RC и кварцевые генераторы , описанные в предыдущих статьях курса микроконтроллера XMEGA. Эта часть, как и все остальные про тактирование, будет использовать ту же схему и те же исходные файлы. Демонстрационная плата использует прототип модуля X3-DIL64 от Leon Instruments .
    Схема PLL
    PLL, фазовая синхронизация, является противоположной предделителю и используется для увеличения частоты сигнала. Ранее использовавшиеся схемы PLL были в микроконтроллерах высшего класса и в FPGA, но в XMEGA это решение доступно во всех моделях, даже самых дешевых.
    У нас есть возможность умножить частоту выбранного генератора до 31 раз. Мы можем -выбрать из следующих генераторов:
    -встроенный RC 2 МГц
    -встроенный RC 32 МГц, но предварительно разделенный на 4 или 8 МГц
    -кварц 0,4-16 МГц
    -внешний тактовый сигнал
    Система PLL не может взаимодействовать с генераторами 32 кГц.
    Обратите внимание, что при неправильной настройке системы PLL вы можете разгонять микроконтроллер, что может привести к его нестабильной работе. Помните, что основной процессор может работать с тактовым сигналом на частоте 32 МГц. Частота на выходе PLL должна быть не ниже 10 МГц или выше 200 МГц. При необходимости вы можете использовать предделитель для уменьшения тактовой частоты.
    Мы напишем программу, которая позволяет изменять конфигурацию схемы ФАПЧ во время работы процессора. При нажатии на клавишу F4, подключенный к контакту на плате X3-DIL64 от Leon Instruments, мы будем увеличивать множитель PLL от 1 до 31, и в следующий раз, когда вы нажмете на множитель установлен равным 1, чтобы иметь возможность увеличить его снова. В качестве источника генератора сигналов используются 2 МГц, частота получена через ФАПЧ будет до 62 МГц, что намного превышает допустимый предел.
    Давайте будем следить за тем, что происходит в функции OscPLL. Первый шаг - запустить генератор, который будет источником сигнала для PLL и установить его как источник. На этом этапе должно быть четко указано, что конфигурация системы PLL не может быть изменена во время ее работы, и тем более, когда она является источником тактового сигнала.
void OscPLL(uint8_t pllfactor) 
{
 OSC.CTRL = OSC_RC2MEN_bm; 
 while(!(OSC.STATUS & OSC_RC2MRDY_bm));
 CPU_CCP = CCP_IOREG_gc; 
 CLK.CTRL = CLK_SCLKSEL_RC2M_gc; 
} 
    Затем мы можем перейти к конфигурации системы PLL. Однако, если он уже включен, мы должны сначала отключить его. В противном случае попытка изменить конфигурацию будет неэффективной. Ключом в этом фрагменте является регистр OSC.PLLCTRL. В нем нам нужен источник сигнала, множитель (переменная pllfactor является аргументом функции OscPLL), и, при желании, мы можем разделить частоту выходного сигнала на два.
OSC.CTRL &= ~OSC_PLLEN_bm; 
OSC.PLLCTRL = OSC_PLLSRC_RC2M_gc | pllfactor; 
OSC.CTRL = OSC_PLLEN_bm; 
    Как и в случае с другими генераторами, мы должны дождаться стабилизации тактового сигнала, проверив, установлен ли соответствующий бит в регистре состояния. Только тогда мы можем переключить источник сигнала, синхронизирующий микроконтроллер.
while(!(OSC.STATUS & OSC_PLLRDY_bm));
CPU_CCP = CCP_IOREG_gc;
CLK.CTRL = CLK_SCLKSEL_PLL_gc; 
    Система PLL может потерять фазовую синхронизацию, если тактовый сигнал слишком медленный, слишком быстрый или по какой-то причине неустойчивый. К счастью, микроконтроллеры XMEGA имеют возможность контролировать PLL-систему, как и в случае кварцевого генератора. Если обнаружены какие-либо неровности, встроенный генератор 2 МГц автоматически запустится и будет генерироваться прерывание OSC_OSCF_vect .
CPU_CCP = CCP_IOREG_gc;
OSC.XOSCFAIL = OSC_PLLFDEN_bm;
    Во время этих упражнений мы разгоняли процессорное ядро ​​почти в два раза. Согласно данным Atmel, система должна быть синхронизирована в диапазоне от 10 МГц (минимальная выходная частота PLL) до 32 МГц (максимальная частота ядра). Интересно, заметили ли читатели какие-либо нарушения в работе микроконтроллера вне этого диапазона. В моем случае все работало без сучка и задоринки. Однако в нормальных условиях допустимые диапазоны, указанные производителем системы, никогда не должны превышаться!
#define F_CPU 62000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "hd44780.h"
void Osc2MHz(void) {
    OSC.CTRL  =    OSC_RC2MEN_bm;
    while(!(OSC.STATUS & OSC_RC2MRDY_bm));
    CPU_CCP =    CCP_IOREG_gc; 
    CLK.CTRL =    CLK_SCLKSEL_RC2M_gc;
    LcdClear(); 
    Lcd("RC 2MHz");
}
void Osc32MHz(void) {
    OSC.CTRL = OSC_RC32MEN_bm;
    while(!(OSC.STATUS & OSC_RC32MRDY_bm));
    CPU_CCP = CCP_IOREG_gc;
    CLK.CTRL = CLK_SCLKSEL_RC32M_gc;
    LcdClear();
    Lcd("RC 32MHz")
}
void OscXtal(void) {      
    OSC.XOSCCTRL = OSC_FRQRANGE_12TO16_gc | OSC_XOSCSEL_XTAL_16KCLK_gc;
    OSC.CTRL = OSC_XOSCEN_bm;
    
    for(uint8_t i=0; i<255; i++) {                        
        if(OSC.STATUS & OSC_XOSCRDY_bm) {
            CPU_CCP = CCP_IOREG_gc;
            CLK.CTRL  = CLK_SCLKSEL_XOSC_gc;
            LcdClear(); 
            Lcd("XTAL"); 
            CPU_CCP        =    CCP_IOREG_gc;
            OSC.XOSCFAIL   =    OSC_XOSCFDEN_bm;
            return;
        }
        _delay_us(10);
    }     
    LcdClear();
    Lcd("Brak XTAL");
}
void OscPLL(uint8_t pllfactor) {
    
    OSC.CTRL  = OSC_RC2MEN_bm;
    while(!(OSC.STATUS & OSC_RC2MRDY_bm));
    CPU_CCP = CCP_IOREG_gc;
    CLK.CTRL  =  CLK_SCLKSEL_RC2M_gc;
    OSC.CTRL &= ~OSC_PLLEN_bm;
            
    OSC.PLLCTRL = OSC_PLLSRC_RC2M_gc | pllfactor; 
    OSC.CTRL  =  OSC_PLLEN_bm;
               
    while(!(OSC.STATUS & OSC_PLLRDY_bm));
    CPU_CCP = CCP_IOREG_gc;
    CLK.CTRL = CLK_SCLKSEL_PLL_gc;
    CPU_CCP           =    CCP_IOREG_gc;
    OSC.XOSCFAIL      =    OSC_PLLFDEN_bm;
    
    LcdClear();
    Lcd("PLL ");
    LcdDec(pllfactor*2);
    Lcd("MHz");
}
int main(void) {
    
    uint8_t pll = 4;
    PORTE.DIR         =    PIN0_bm;
                    
    PORTA.DIRCLR      =    PIN0_bm;
    PORTA.PIN0CTRL    =    PORT_OPC_PULLUP_gc;
    PORTE.DIRCLR      =    PIN5_bm;
    PORTE.PIN5CTRL    =    PORT_OPC_PULLUP_gc;
    PORTE.DIRCLR      =    PIN6_bm;
    PORTE.PIN6CTRL    =    PORT_OPC_PULLUP_gc;
    PORTF.DIRCLR      =    PIN4_bm;
    PORTF.PIN4CTRL    =    PORT_OPC_PULLUP_gc;
    LcdInit();
    LcdClear();
    Lcd("RC 2MHz");
    
    sei();
    
    while(1) {
        PORTE.OUTTGL  =    PIN0_bm;
        _delay_ms(50);
        
        if(!(PORTA.IN & PIN0_bm)) Osc2MHz();
        if(!(PORTE.IN & PIN5_bm)) Osc32MHz();
        if(!(PORTE.IN & PIN6_bm)) OscXtal();
        if(!(PORTF.IN & PIN4_bm)) {    
            pll++; 
            if(pll > 31) pll = 1; 
            OscPLL(pll); 
        }
    }
}
ISR(OSC_OSCF_vect) {
    OSC.XOSCFAIL     |=    OSC_XOSCFDIF_bm;
    LcdClear();
    Lcd("Awaria!");    
}
    Blogger Comment
    Facebook Comment

0 коммент.:

Отправить комментарий