// MS2 Speed control Application
// Target : M128
// Crystal: 16MHz

/*
 마이크로 스텝드라이버 구동 소스
 포트 연결
 Enable		: PORTB 7번핀
 Mode1		: PORTB 5번핀
 Mode0		: PORTB 4번핀
 R_DIR		: PORTB 3번핀
 R_CLK		: PORTB 2번핀
 L_DIR		: PORTB 1번핀
 L_CLK		: PORTB 0번핀
*/

#include <iom128v.h>
#include <macros.h>
#include <stdio.h>


#define MOTOR1_PORT		PORTC       // 스테핑 모터 연결 포트
#define MOTOR1_PORT_DDR	DDRC        // 스테핑 모터 연결 포트의 DDR REG

#define MOTOR2_PORT		PORTE       // 스테핑 모터 연결 포트
#define MOTOR2_PORT_DDR	DDRE        // 스테핑 모터 연결 포트의 DDR REG

#define SW_PORT			 		PINA
#define SW_DDR_PORT				DDRA

#define SPEEDSW_PORT			PIND
#define SPEEDSW_DDR_PORT		DDRD

#define MOTOR1_ENABLE	 (MOTOR1_PORT = MOTOR1_PORT|0x80)
#define MOTOR1_DISABLE	 (MOTOR1_PORT = MOTOR1_PORT&0x7f)
#define MOTOR1_STEP_M0	 (MOTOR1_PORT = (MOTOR1_PORT&0xcf)|0x00)
#define MOTOR1_STEP_M1	 (MOTOR1_PORT = (MOTOR1_PORT&0xcf)|0x10)
#define MOTOR1_STEP_M2	 (MOTOR1_PORT = (MOTOR1_PORT&0xcf)|0x20)
#define MOTOR1_STEP_M3	 (MOTOR1_PORT = (MOTOR1_PORT&0xcf)|0x30)
#define MOTOR1_LEFT_CLK	 (MOTOR1_PORT = MOTOR1_PORT^0x01)
#define MOTOR1_RIGHT_CLK (MOTOR1_PORT = MOTOR1_PORT^0x04)
#define MOTOR1_LEFT_CW	 (MOTOR1_PORT = MOTOR1_PORT&0xfd)
#define MOTOR1_LEFT_CCW	 (MOTOR1_PORT = MOTOR1_PORT|0x02)
#define MOTOR1_RIGHT_CW	 (MOTOR1_PORT = MOTOR1_PORT&0xf7)
#define MOTOR1_RIGHT_CCW (MOTOR1_PORT = MOTOR1_PORT|0x08)


#define MOTOR2_ENABLE	 (MOTOR2_PORT = MOTOR2_PORT|0x80)
#define MOTOR2_DISABLE	 (MOTOR2_PORT = MOTOR2_PORT&0x7f)
#define MOTOR2_STEP_M0	 (MOTOR2_PORT = (MOTOR2_PORT&0xcf)|0x00)
#define MOTOR2_STEP_M1	 (MOTOR2_PORT = (MOTOR2_PORT&0xcf)|0x10)
#define MOTOR2_STEP_M2	 (MOTOR2_PORT = (MOTOR2_PORT&0xcf)|0x20)
#define MOTOR2_STEP_M3	 (MOTOR2_PORT = (MOTOR2_PORT&0xcf)|0x30)
#define MOTOR2_LEFT_CLK	 (MOTOR2_PORT = MOTOR2_PORT^0x01)
#define MOTOR2_RIGHT_CLK (MOTOR2_PORT = MOTOR2_PORT^0x04)
#define MOTOR2_LEFT_CW	 (MOTOR2_PORT = MOTOR2_PORT&0xfd)
#define MOTOR2_LEFT_CCW	 (MOTOR2_PORT = MOTOR2_PORT|0x02)
#define MOTOR2_RIGHT_CW	 (MOTOR2_PORT = MOTOR2_PORT&0xf7)
#define MOTOR2_RIGHT_CCW (MOTOR2_PORT = MOTOR2_PORT|0x08)


#define MOTOR1DELAY		 		10000
#define MOTOR2DELAY		 		10000

#define MOTOROFF				0
#define MOTORON					1
#define MOTORMID				2				
#define MOTORGOLEFT				3	
#define MOTORGORIGHT			4	

#define SPEEDRATE				2
#define LIMIT					10000


#define LEFTEND					0
#define RIGHTEND				1
#define MID						2

#define PRESS					1
#define OPEN					0

#define ON						1
#define OFF						0

#define IDLE					0
#define ACTIVE					1

volatile int key7state = OPEN, key6state = OPEN, key0state = OPEN, key1state = OPEN;
volatile int speedswstate[8];

// motor1durate : motor speed control      
// motor1pos    : motor position (리미트 스위치를 사용하기 위한 판단)
volatile int motor1over=0, motor1durate=30, motor1pos=MOTORGOLEFT, motor1state=ON;
volatile long motor1delay = 0;
volatile int motor2over=0, motor2durate=15, motor2pos=MOTORGOLEFT, motor2state=ON;

volatile long motor2delay = 0;


void port_init(void);
void uart0_init(void);
void delay(int n);
void timer0_init(void);
void timer0_ovf_isr(void);
void timer1_init(void);
void timer1_ovf_isr(void);
int putchar(char c);
void init_devices(void);


void port_init(void)
{
	PORTA = 0x00;
	DDRA  = 0x03;
	PORTB = 0x00;
	DDRB  = 0x00;
	PORTC = 0x00;
	DDRC  = 0xFF;
	PORTD = 0x00;
	DDRD  = 0xFF;
	PORTE = 0x00;
	DDRE  = 0x00;
	PORTF = 0x00;
	DDRF  = 0x00;
	PORTG = 0x00;
	DDRG  = 0x03;
}


//UART0 initialize
// desired baud rate: 9600
// actual: baud rate:9615 (0.2%)
// char size: 8 bit
// parity: Disabled
void uart0_init(void)
{
 UCSR0B = 0x00; //disable while setting baud rate
 UCSR0A = 0x00;
 UCSR0C = 0x06;
 UBRR0L = 0x67; //set baud rate lo
 UBRR0H = 0x00; //set baud rate hi
 UCSR0B = 0x18;
}


void delay(int n)
{
	volatile int i,j;
	for(i=1;i<n;i++)
	{
    	for(j=1;j<600;j++);
	}
}

//TIMER0 initialize - prescale:32
// WGM: Normal
// desired value: 10KHz
// actual value: 10.000KHz (0.0%)
void timer0_init(void)
{
 TCCR0 = 0x00; //stop
 ASSR  = 0x00; //set async mode
 TCNT0 = 0xCE; //set count
 OCR0  = 0x32;
 TCCR0 = 0x03; //start timer
}

#pragma interrupt_handler timer0_ovf_isr:iv_TIM0_OVF
void timer0_ovf_isr(void)
{
 TCNT0 = 0xCE; //reload counter value
 
 	if(motor1delay > MOTOR1DELAY){
 	motor1over++;
 	if(motor1over > motor1durate){
 		motor1over = 0;
		if(motor1state == ON){
 			MOTOR1_LEFT_CLK;
 			MOTOR1_RIGHT_CLK;
		}
 	}
 }else{
 	motor1delay++; 
 } 
}

//TIMER1 initialize - prescale:8
// WGM: 0) Normal, TOP=0xFFFF
// desired value: 10KHz
// actual value: 10.000KHz (0.0%)
void timer1_init(void)
{
 TCCR1B = 0x00; //stop
 TCNT1H = 0xFF; //setup
 TCNT1L = 0x38;
 OCR1AH = 0x00;
 OCR1AL = 0xC8;
 OCR1BH = 0x00;
 OCR1BL = 0xC8;
 OCR1CH = 0x00;
 OCR1CL = 0xC8;
 ICR1H  = 0x00;
 ICR1L  = 0xC8;
 TCCR1A = 0x00;
 TCCR1B = 0x02; //start Timer
}

#pragma interrupt_handler timer1_ovf_isr:iv_TIM1_OVF
void timer1_ovf_isr(void)
{
 //TIMER1 has overflowed
 TCNT1H = 0xFF; //reload counter high value
 TCNT1L = 0x38; //reload counter low value
 
 	if(motor2delay > MOTOR2DELAY){
 		motor2over++;
 		if(motor2over > motor2durate){
 			motor2over = 0;
 			if(motor2state == ON){
				MOTOR2_LEFT_CLK;
 				MOTOR2_RIGHT_CLK;
			}
 		}
 }else{
  	  motor2delay++;
 }  
}

int putchar(char c)
{
    while (((UCSR0A>>UDRE0)&0x01) == 0) ;  // UDRE, data register empty
        
    UDR0 = c;
    return c;
}



//call this routine to initialize all peripherals
void init_devices(void)
{
	//stop errant interrupts until set up
	CLI(); //disable all interrupts
	XDIV  = 0x00; //xtal divider
	XMCRA = 0x00; //external memory
	port_init();
	uart0_init();
	timer0_init();
	timer1_init();
	
	MCUCR = 0x00;
	EICRA = 0x00; //extended ext ints
	EICRB = 0x00; //extended ext ints
	EIMSK = 0x00;
	TIMSK = 0x05; //timer interrupt sources
	ETIMSK = 0x00; //extended timer interrupt sources
	SEI(); //re-enable interrupts
	//all peripherals are now initialized
}

void init_system(void){
	MOTOR1_PORT_DDR = 0xff;
	MOTOR2_PORT_DDR = 0xff;
	
	motor1state = ON;
	MOTOR1_ENABLE;
	MOTOR1_STEP_M0;
	MOTOR1_LEFT_CCW;
	MOTOR1_RIGHT_CCW;
	
	motor2state = ON;
	MOTOR2_ENABLE;
	MOTOR2_STEP_M2;
	MOTOR2_LEFT_CCW;
	MOTOR2_RIGHT_CCW;
	
	SW_DDR_PORT = 0x00;
	SPEEDSW_DDR_PORT = 0x00;	
}	

/* main function-----------------------------------*/
void main(void)
{
 	int motordir1=0, motordir2=0;
	int motor1where=MID, motor2where=MID;
	init_devices();
	init_system();

	//insert your functional code here...
	printf(" \n\n\rStepping Motor test program...\n\r");
	

	/* 딜레이로 마이크로 스텝 드라이버 구동 */ 
	while(1){
		// 모터의 방향 및 온 오프 콘트롤
		switch(SW_PORT){
		    // MOTOR 1 control
			case 0x01 : 
				 	  	if(key0state == OPEN){	
				 	  		if(!(motor1where == LEFTEND)){
				 	    		motor1pos = MOTORGOLEFT;
				 	  			motordir1 = 0;
				 	  			motor1state = ON;
								MOTOR1_LEFT_CCW;
    							MOTOR1_RIGHT_CCW;
								motor1delay=0;
							}
							key0state = PRESS;
						}else{
							if(!(motor1where == LEFTEND)){
				 	    		motor1pos = MOTORGOLEFT;
				 	  			motordir1 = 0;
				 	  			motor1state = ON;
								MOTOR1_LEFT_CCW;
    							MOTOR1_RIGHT_CCW;
							//	motor1delay=0;
							}
						}
						break;
			case 0x02 :	
				 	  	if(key1state == OPEN){	
				 	  		if(!(motor1where == RIGHTEND)){
				 	  			motor1pos = MOTORGORIGHT;
								motordir1 = 1;
				 	  			motor1state = ON;
								MOTOR1_LEFT_CW;
								MOTOR1_RIGHT_CW;
								motor1delay=0;
							}
							key1state = PRESS;
						}else{
							if(!(motor1where == RIGHTEND)){
				 	  			motor1pos = MOTORGORIGHT;
								motordir1 = 1;
				 	  			motor1state = ON;
								MOTOR1_LEFT_CW;
								MOTOR1_RIGHT_CW;
								//motor1delay=0;
							}
						}
						break;
			case 0x04 :	
			            motor1state = OFF;
				 	  	break;
			case 0x08 : 
			            motor1state = ON;
				 	  	break;
		    // MOTOR 2 control
			case 0x80 :	
				 	  	if(key7state == OPEN){
				 	  		if(!(motor2where == LEFTEND)){
				 	    		motor2pos = MOTORGOLEFT;
				 	    		motordir2 = 0;
				 	  			motor2state = ON;
								MOTOR2_LEFT_CCW;
    							MOTOR2_RIGHT_CCW;
								motor2delay=0;
							}
							key7state = PRESS;
						}else{
				 	  		if(!(motor2where == LEFTEND)){
				 	    		motor2pos = MOTORGOLEFT;
				 	    		motordir2 = 0;
				 	  			motor2state = ON;
								MOTOR2_LEFT_CCW;
    							MOTOR2_RIGHT_CCW;
								//motor2delay=0;
							}						
						}
						break;
			case 0x40 : 
						if(key6state == OPEN){
				 	  		if(!(motor2where == RIGHTEND)){
				 	  			motor2pos = MOTORGORIGHT;
			            		motordir2 = 1;
				 	  			motor2state = ON;
								MOTOR2_LEFT_CW;
								MOTOR2_RIGHT_CW;
								motor2delay=0;
							}
							key6state = PRESS;
						}else{
							if(!(motor2where == RIGHTEND)){
				 	  			motor2pos = MOTORGORIGHT;
			            		motordir2 = 1;
				 	  			motor2state = ON;
								MOTOR2_LEFT_CW;
								MOTOR2_RIGHT_CW;
								//motor2delay=0;
							}
						}
						break;
			case 0x20 : 
				 	  	motor2state = OFF;
				 	  	break;		
			case 0x10 :	
				 	  	motor2state = ON;
				 	  	break;
			case 0x00 : key7state = key6state = key1state = key0state =OPEN;			
			default   : //printf("No Button!"); 
					    break;
		}
		
		// 이후 모터의 속도 컨트롤
		switch(SPEEDSW_PORT&0xC3){
			case 0x01 : speedswstate[0] = PRESS;				 	  	
						break;
			case 0x02 : speedswstate[1] = PRESS;				 	  	
						break;		
			case 0x40 : speedswstate[6] = PRESS;				 	  	
						break;
			case 0x80 : speedswstate[7] = PRESS;				 	  	
						break;										
			case 0x00 : if(speedswstate[0] == PRESS){
				 	  		speedswstate[0] = OPEN;
							motor1durate = motor1durate + SPEEDRATE;
							if(motor1durate > LIMIT){
								motor1durate = LIMIT;
							}
						}
						if(speedswstate[1] == PRESS){
				 	  		speedswstate[1] = OPEN;
							motor1durate = motor1durate - SPEEDRATE;
							if(motor1durate <= 1){
								motor1durate = 1;
							}
						}
						
						if(speedswstate[6] == PRESS){
				 	  		speedswstate[6] = OPEN;
							motor2durate = motor2durate - SPEEDRATE;
							if(motor2durate > LIMIT){
								motor2durate = LIMIT;
							}
						}
						if(speedswstate[7] == PRESS){
				 	  		speedswstate[7] = OPEN;
							motor2durate = motor2durate + SPEEDRATE;
							if(motor2durate <= 1){
								motor2durate = 1;
							}
						}						
						break;
			default : break;		
		}
	    //printf("\r\n SPEEDSW_PORT&0x03 : %d ",SPEEDSW_PORT&0xC3);		
	}	
}
