/********************************************************************************
*
*   Compiler: AVR-GCC
*   
*   This little program needs a little cleaning. It outputs two PWM channels for
*   standard motors (PB3 AND PD7), and 2 remote-control style pwm channels
*   for the ATMega16. Each motor should be continuously moving, so plug them
*   in and test them. Use this program as a basis to build bigger programs..
*   
*   
*   The chip (ATMega8, 16 or 32):
*
*                   +------\_/-----+
*   (XCK)   PB0     |  1        40 |    PA0     XCK=USART extern clock in / out
*           PB1     |  2        39 |    PA1
*           PB2     |  3        38 |    PA2
* <-motor1  PB3     |  4        37 |    PA3
*           PB4     |  5        36 |    PA4
*   (MOSI)  PB5     |  6        35 |    PA5 
*   (MISO)  PB6     |  7        34 |    PA6 
*   (SCK)   PB7     |  8        33 |    PA7
*          RESET    |  9        32 |    AREF
*           VCC     | 10        31 |    GND
*           GND     | 11        30 |    AVCC
*           XTAL2   | 12        29 |    PC7
*           XTAL1   | 13        28 |    PC6
* USART     PD0     | 14        27 |    PC5
* USART     PD1     | 15        26 |    PC4             
*           PD2     | 16        25 |    PC3
*           PD3     | 17        24 |    PC2
* <-servoB  PD4     | 18        23 |    PC1
* <-servoA  PD5     | 19        22 |    PC0
*           PD6     | 20        21 |    PD7  motor2->
*                   +--------------+
*
*
*
********************************************************************************/

#include <avr/io.h>
#include <delay.h>

// some constants to keep track of what directions things are moving:
#define UP              1
#define DOWN            -1
// to help make code more transparent:
#define TRUE			1
#define FALSE			0


/********************************************************************************
*		INIT_CHIP
********************************************************************************/
void init_chip(void)
{
	// init stuff for the 8 bit timers:
	TCCR0 = 0x72;	// set phase correct PWM for timer 0
	OCR0 =  128;	// set starting duty cycle for timer 0 - pin PB3

	TCCR2 = 0x72;	// set phase correct PWM for timer 2
	OCR2 =  128;	// set starting duty cycle for timer 2 - pin PD7

	// init stuff for the 16 bit timer
    TCCR1A  = 0xA2;		// 0xFX versus 0xAX to invert waveform
    TCCR1B  = 0x19;		// 0x19 for 20ms prescaler
    ICR1    = 20000;	// TOP value of counter set at 20ms (base freq = 50Hz)
    OCR1A   = 1500;		// Starting duty cycle (1500=center) motor A - pin PD5
    OCR1B   = 1500;		// Starting duty cycle (1500=center) motor B - pin PD4    

	// set output pins
	DDRD  = 0xB0;     // set output bits (OCR 1A 1B & motor 2 compare)
	DDRB  = 0x08;     // set output motor 1
}



/********************************************************************************
*		MAIN
********************************************************************************/
void main (void)
{    
  uint16_t	pw_A		= 1500;	// duty cycle for servo A
  uint16_t	pw_B		= 1500; // duty cycle for servo B
  uint8_t	pw_1		= 127;	// duty cycle for motor 1
  uint8_t	pw_2		= 127;	// duty cycle for motor 2

  int8_t directionA	= UP;
  int8_t directionB	= DOWN;
  int8_t direction1	= UP;
  int8_t direction2	= DOWN;

  uint8_t speedA		= 2;    
  uint8_t speedB		= 3;
  uint8_t speed1		= 1;
  uint8_t speed2		= 1;

  init_chip();    // initializes registers and pin stuff

  _delay_loop_2(5000); // wait 5ms for stuff to turn on
    
  while (TRUE){

	//check if pulse width changes need to switch directions:
	if(pw_A >= 2000) directionA	= DOWN;
	if(pw_A <= 1000) directionA	= UP;

	if(pw_B >= 2000) directionB	= DOWN;
	if(pw_B <= 1000) directionB	= UP;

	if(pw_1 >= 245) direction1	= DOWN;
	if(pw_1 <= 10) direction1	= UP;

	if(pw_2 >= 245) direction2	= DOWN;
	if(pw_2 <= 10) direction2	= UP;
	
	pw_A += (directionA * speedA);
	pw_B += (directionB * speedB);
	pw_1 += (direction1 * speed1);
	pw_2 += (direction2 * speed2);
    
    OCR1A	= pw_A;   // replace output compare registers
    OCR1B	= pw_B;   // with the new pulse widths 
    OCR0	= pw_1;
    OCR2	= pw_2;

    _delay_loop_2(5000); // delay some number of microseconds

    }
}



// ************************* 16 Bit timer reference *******************************
//
// TCCR1A bits:
//    |                |                                 |            = 0xA2 
// COM1A1 - COM1A0 - COM1B1 - COM1B0 - FOC1A - FOC1B - WGM11 - WGM10
//
// TCCR1B bits:
//                              |        |                        |   = 0x19
// ICNC1  - ICES1  -   -    - WGM13  - WGM12  - CS12  - CS11  - CS10
//
// WGM - turn bits 11 12 & 13 on for fast PWM where ICR1 defines TOP
// COM - in fast PWM mode, A1 & B1 on. A0 & B0 off and on toggles wave invert
// FOC1A, FOC1B - set these bits for channel A and channel B, respectively
// CS - prescaling 0-5: none - 1 - 8 - 64 - 256; 
//
// OCR1AH & OCR1AL (to specify high and low bytes - may be needed)

// ************************* 8 Bit timer reference *******************************
//
// TCCR0 bits:
//          1       1       1                      1      1      = 0x73
// FOC0 - WGM00 - COM01 - COM00 - WGM01 - CS02 - CS01 - CS00
//
//
//
// WGM - turn bits 11 12 & 13 on for fast PWM where ICR1 defines TOP
// COM - in fast PWM mode, A1 & B1 on. A0 & B0 off and on toggles wave invert
// FOC - always 0 for pwm
// CS - prescaling 0-5: none - 1 - 8 - 64 - 256; 

