/* tutorial TinyAVR 1-Series */ /* Clock 1 - interní zdroje clocku*/ /* Ve fuses zvolen 20MHz oscilátor (lze volit ještě 16MHz) */ #include #define MY_OSC_CALIBRATION 0x99 void clock_2MHz(uint8_t kalibrace); void clock_20MHz(void); void clock_ULP32(void); void clock_tune_up(void); void clock_tune_down(void); volatile int8_t osc_error[4]; int main(void){ // vyčte odchylky frekvence - jen pro zajímavost osc_error[0] = SIGROW.OSC20ERR5V; // Odchylka od 20MHz při 5V napájení osc_error[1] = SIGROW.OSC20ERR3V; // Odchylka od 20MHz při 3V napájení osc_error[2] = SIGROW.OSC16ERR5V; // Odchylka od 16MHz při 5V napájení osc_error[3] = SIGROW.OSC16ERR3V; // Odchylka od 16MHz při 3V napájení clock_2MHz(MY_OSC_CALIBRATION); //clock_ULP32(); //clock_20MHz(); while (1) { //clock_tune_up(); //clock_tune_down(); } } // Nastaví clock 20MHz (z interního 20MHz bez děličky) a vypustí clock na CLKOUT (PB5) void clock_20MHz(void){ // v případě potřeby zde dočasně vypněte přerušení CCP = CCP_IOREG_gc; // odemyká zápis do chráněného registru CLKCTRL.MCLKCTRLA = CLKCTRL_CLKOUT_bm | CLKCTRL_CLKSEL_OSC20M_gc; // vypouští clock na PB5 (CLKOUT), vybírá 20MHz oscilátor CCP = CCP_IOREG_gc; // odemyká zápis do chráněného registru CLKCTRL.MCLKCTRLB = 0; // vypne prescaler (děličku) } // Nastaví clock na ~32kHz vnitřní oscilátor a vypustí clock na CLKOUT (PB5) void clock_ULP32(void){ CCP = CCP_IOREG_gc; // odemyká zápis do chráněného registru CLKCTRL.MCLKCTRLB = 0; // vypne prescaler (děličku) CCP = CCP_IOREG_gc; // odemyká zápis do chráněného registru CLKCTRL.MCLKCTRLA = CLKCTRL_CLKOUT_bm | CLKCTRL_CLKSEL_OSCULP32K_gc; // vypouští clock na PB5 (CLKOUT), vybírá 20MHz oscilátor } // Nastaví clock 2MHz (z interního 20MHz s děličkou 10x) s individuální kalibrací a vypustí clock na CLKOUT (PB5) // vstupním argumentem je kalibrační hodnota void clock_2MHz(uint8_t kalibrace){ // v případě potřeby zde dočasně vypněte přerušení CCP = CCP_IOREG_gc; // odemyká zápis do chráněného registru CLKCTRL.OSC20MCALIBA = kalibrace; // zapíše novou hodnotu kalibračního registru (zjištěnou empiricky) CCP = CCP_IOREG_gc; // odemyká zápis do chráněného registru CLKCTRL.MCLKCTRLA = CLKCTRL_CLKOUT_bm | CLKCTRL_CLKSEL_OSC20M_gc; // vypouští clock na PB5 (CLKOUT), vybírá 20MHz oscilátor CCP = CCP_IOREG_gc; // odemyká zápis do chráněného registru CLKCTRL.MCLKCTRLB = CLKCTRL_PDIV_10X_gc | CLKCTRL_PEN_bm; // F_CPU = 20MHz / 10 = 2MHz, PEN = Prescaler Enable } // funkce pro ladění frekvence interního oscilátoru void clock_tune_up(void){ uint8_t tmp = CLKCTRL.OSC20MCALIBA & 0x3F; // přečte aktuální kalibrační hodnotu if(tmp < 0x3F){ // maximální kalibrační hodnota je 0x3F (63) tmp++; // přidáme krok CPU_CCP = CCP_IOREG_gc; // odemyká zápis do chráněného registru CLKCTRL.OSC20MCALIBA = tmp; // zapíše novou hodnotu kalibračního registru } } void clock_tune_down(void){ uint8_t tmp = CLKCTRL.OSC20MCALIBA & 0x3F; if(tmp > 0){ // minimální kalibrační hodnota je 0 tmp--; // ubereme krok CPU_CCP = CCP_IOREG_gc; // odemyká zápis do chráněného registru CLKCTRL.OSC20MCALIBA = tmp; // zapíše novou hodnotu kalibračního registru } }