#include <tiny2313.h>
#include <io.h>
#include <stdlib.h>
#include <stdio.h>
#include <delay.h>

//----------------------------------------------------------------------------------

#define F_CPU 8000000

//----------------------------------------------------------------------------------

double fG=100;

//-------------------------------------USI---------------------------------------------

//-------------------------------------timer0-------------------------------------------

void Timer0Init(void) {
    TCCR0A = (1<<COM0A0) | (1<<WGM01); //CTC, toggle on compare match, prescaler 1
    TCCR0B = (1<<CS00);
    //OCR0A = 0xFF;
}

void SetUpTim0A(double Foc)
{
double TimDiv;
unsigned char save = SREG; //save global interrupt flag 
TimDiv=(F_CPU/(2*1*Foc)-1)+0.5;
#asm("cli") //disable unterrupts
OCR0A=TimDiv;
SREG = save; //restore global interrupt flag
}

void UpdateTim0A(double freq)
{
	static double fG1_old = 0;

	if (fG1_old != freq)
	{
		SetUpTim0A(freq);
		fG1_old = freq;
	}
}
//-------------------------------------timer1---------------------------------------------

void Timer1Init(void) {
    TCCR1A = (1<<COM1A0);
    TCCR1B = (1<<WGM12) | (1<<CS11); //CTC, toggle on compare match, prescaler 1 
    //OCR1A = 0xFFFF;
    //TCNT1 = 0xFFFF; 
}
 
void SetUpTim1A(double Foc)
{
double TimDiv;
unsigned char save = SREG; //save global interrupt flag
TimDiv=(F_CPU/(2*1*Foc)-1)+0.5;
#asm("cli") //disable unterrupts
OCR1A=TimDiv;  
SREG = save; //restore global interrupt flag
}

void SetUpTim1OVF(double Foc)
{
double TimDiv;
unsigned char save = SREG; //save global interrupt flag
TimDiv=65536-((F_CPU/1)/Foc)+0.5; //TimDiv=(maximum timer value-((clock frequency/prescaler)/freqerency))
PORTB.0=1;
#asm("cli")  //disable unterrupts
TCNT1=TimDiv; 
PORTB.0=0;
SREG = save; //restore global interrupt flag
}

void UpdateTim1A(double freq)
{
	static double fG2_old = 0;

	if (fG2_old != freq)
	{
		SetUpTim1A(freq);
		fG2_old = freq;
	}
}

void UpdateTim1OVF(double freq)
{
	static double fG3_old = 0;

	if (fG3_old != freq)
	{
		SetUpTim1OVF(freq);
		fG3_old = freq;
	}
}

//---------------------------------------------------------------------------------------- 
 
void main(void)
{
static double fG1_old = 0;
static double fG2_old = 0;
static double fG3_old = 0;
unsigned char nG;
//double fG=100;

Timer0Init();
Timer1Init();
UpdateTim0A(fG);
UpdateTim1A(fG);
UpdateTim1OVF(fG);

TIMSK = (1<<TOIE1) | (1<<OCIE0A) | (1<<OCIE1A); //OVF,CTC INTERRUPTS ENABLED
//TIFR |= 0x01;

DDRB=0b11111111;

#asm("sei")
                
for(;;){
nG=0;

if (fG1_old != fG)
{
    SetUpTim0A(fG);
    fG1_old = fG;
}

if (fG2_old != fG)
{
    SetUpTim1A(fG);
    fG2_old = fG;
}

if (fG3_old != fG)
{
    SetUpTim1OVF(fG);
    fG3_old = fG;
}    

switch(nG){
    case 0: SetUpTim0A(fG); break; 
    case 1: SetUpTim1A(fG); break;
    case 2: SetUpTim1OVF(fG); break;
}
if (nG < 2)
    nG++;
else
    nG = 0;
    delay_ms(50);
}
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include <tiny2313.h>
#include <math.h>
#include <io.h>

#define F_CPU 8000000

#define N_1     		((1<<CS10))
#define N_8     		((1<<CS11))
#define N_64    		((1<<CS11)|(1<<CS10))
#define N_256   		((1<<CS12))
#define N_1024  		((1<<CS12)|(1<<CS10))

#define	VFG_TIMER_MAX		(65535.)
#define	VFG_DEFAULT_FREQENCY	(0UL)

#define	VFG_PIN		PORTB1
#define	VFG_DDR		DDRB
#define	VFG_PORT	PORTB

void VFG_init(void);
void VFG_set(unsigned int freq);
unsigned int VFG_get(void);

volatile unsigned long int vfg_freq = 0UL;

void VFG_init(void)
{
    VFG_DDR |= (1<<VFG_PIN); // set DDS pin as OUTPUT
 	TCCR1B |= (1<<WGM12); // set timer CTC mode
	TIMSK |= (1<<OCIE1A);
	VFG_set(VFG_DEFAULT_FREQENCY);
	#asm("sei")
}

void VFG_set(unsigned int freq)
{
        double TimDiv;
        unsigned char i, p_N, p_V, ret_N = 0; //i- , p_N -  , p_V -  , 
        unsigned int ret_OCRnx = 0;
	    unsigned long int ret_freq = 0UL;
	    double tmp, err = 100., OCRnx_calc = 0., freq_calc = 0.;

        for (i = 0; i < 5; ++i) {

		switch(i) {
		case 0: p_N = N_1; p_V = 0; break;
		case 1: p_N = N_8; p_V = 3; break;
		case 2: p_N = N_64; p_V = 6; break;
		case 3: p_N = N_256; p_V = 8; break;
		case 4: p_N = N_1024; p_V = 10; break;
		default: break;
		}

		tmp = (double)((unsigned long int)F_CPU >> (unsigned long int)(p_V + 1));
                OCRnx_calc = floor((tmp / (double)freq) - 1.);

                if (OCRnx_calc >= 0. && OCRnx_calc < VFG_TIMER_MAX) {
		        freq_calc = floor(tmp / (OCRnx_calc + 1.));
	                if ((double)freq > freq_calc) {
                                tmp = (1. - (freq_calc / (double)freq)) * 100.;
                        } else {
                                tmp = (1. - ((double)freq / freq_calc)) * 100.;
                        }
                        if (tmp < err) {
                        err = tmp;
                        ret_OCRnx = (unsigned int)OCRnx_calc;
                        ret_N = p_N;
				        ret_freq = (unsigned long int)freq_calc;
                        }
                }
        }

        TCCR1B = (TCCR1B & ~((1<<CS12)|(1<<CS11)|(1<<CS10))) | ret_N;
        OCR1A = ret_OCRnx;
	    vfg_freq = ret_freq;
}

unsigned int VFG_get(void)
{
	return vfg_freq; 
}

interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
	VFG_PORT ^= (1<<VFG_PIN);
}

void main(void)
{

	/* Initialize generator (defaults square wave at @1kHz on pin PB1) */
	VFG_init();

	/* Set frequency to 1234Hz */
	VFG_set(1234UL);

	/* loop */
	while (1);
}
;
;
;
;
;
;
;
;
;
;