/*****************************************************
Project : ATmega2560 MCU간의 SPI통신 테스트
Version : LK-AVR2560D V01
Date    : 2011-07-28
Author  : Kyung Nam Lee
Company : LKEMBEDDED 
Compiler: CodevisionAVR+AVRStudio
Comment: Master MCU(LK-AVR2560D확장형 개발보드)에서 SW1, SW2를 입력하면 Slave MCU(LK-AVR2560D확장형 개발보드)
        에서 부저와 LED가 ON/OFF 되며 마스터, 슬레이브 보드에서 서로 교환한 데이터를 RS232포트에 출력 하는 프로그램이다. 
        이때의 LK-AVR2560D확장형 개발보드간의 내장 된  10핀 박스헤더 커넥터(PORTB)는 10P플랫케이블 이용하여 반드시 서로 연결 되어 있어야 한다. 
*****************************************************/

#include <mega2560.h>
#include <delay.h>
#include <stdio.h>

//#define Master 
#define Slave   //LK-AVR2560D확장형 개발보드 Master or Slave동작 모드를 설정!


#ifdef Master
unsigned char SPI_send(unsigned char data)//
{ 
    unsigned char data3=0;    
    SPDR = data;            /* Start transmission */
    while(!(SPSR&0x80));    /* Wait for transmission complete */ 
    return SPDR; 
    /*return SPDR; 전송(write)함수와 읽기 함수를 구분 짓기 위해서 주석처리를 한다.
    필자는 굳이 함수를 따로 만들 필요성을 못 느낀다.  
    중요한 것은 SPI통신시에 Master에서 SPDR레지스터에 기록할때만 SPI Clock이 출력된다는 점이다.
    즉, 슬레이브에서는 SPDR레지스터에 값을 기록해서 대기하고 있으며, Master에서 SPDR레지스터에 값을 
    기록(출력하면) Feedback 되어서 Master에 입력된다는 점입니다.
    */  
}    
char SPI_read()//dummy값으로도 읽어 올수 있지만 위 SPI_send함수처럼 바로 읽어 들어 와도 무관한다. 
{ 
    unsigned char data3=0;    
    SPDR = 0x00; //Dummy Data
    while(!(SPSR&0x80));          
    return SPDR;  
}     
void Master_init()
{
    PORTB=0x00;
    DDRB=0x07; /* Set MOSI and SCK output, all others input */
    SPCR=0x50; /* Enable SPI, Master, set clock rate fck/16 */
    SPSR=0x00;
}
#endif 

#ifdef Slave 
/*슬레이브측에서 마스터로 데이터를 보낼 시에는 데이터를 SPDR레지스터에 저장만 하면됩니다.
이때의 마스터가 슬레이브로 데이터를 보낼 때 슬레이브의 데이터는 자동적으로 마스터로 전송됩니다.
결국 마스터에서 발생되는 SPI클럭 없이는 슬레이브에서 단독으로 마스터로 데이터를 보낼수는 없으며,
AVR칩의 SPI통신은 마스터와 슬레이브가 서로 교차연결된 원형(LOOP)구조로 데이터를 교환하고 있다.*/
char SPI_receive() //slave
{   
    
    unsigned char data2=0;  
    while(!(SPSR&0x80)); /* Wait for reception complete */
    data2= SPDR;         /* Return Data Register */  
    if(data2==0xfe)
    SPDR = 1;         /* Start transmission */
    else SPDR = 2; 
    printf("SLAVE LK-AVR2560D:receive data from MASTER:%d \r\n",data2); 
    return data2;
    
}
void Slave_init()
{
   
    PORTB=0x00;
    DDRB=0x08;  /* Set MISO output, all others input */   
    SPCR=0x40;  /* Enable SPI */
    SPSR=0x00;
}
#endif
 
void main(void)
{
    UCSR0A=0x00;
    UCSR0B=0x08;
    UCSR0C=0x06;
    UBRR0H=0x00;
    UBRR0L=0x67;  
      
    DDRG=0X13;  //LED, BUZZ OUTPUT SET
    PORTG=0X13; //LED, BUZZ INITIALIZE

    #ifdef Master     //master? 
    Master_init(); 
    #endif
    #ifdef Slave      //master? 
    Slave_init();
    #endif         
while (1)
    {           
         #ifdef Master     //master? 
            static unsigned char data1=0;
            if((PING&0X04)==0)  
            {    
                delay_ms(20); //8mS 지연시간이 확보가 되야만 송신값과 수신값이 겹쳐서 printf()출력 되지 않는다.          
                data1=SPI_send(0XFF); //Slave '0xff' Transmitter!   
                printf("MASTER  LK-AVR2560D: receive data from SLAVE:%d \r\n",data1); 
            }  
            else if((PING&0X08)==0)  
            {      
                delay_ms(20); 
                data1=SPI_send(0XFE); //Slave '0xfe' Transmitter! 
                printf("MASTER LK-AVR2560D: receive data from SLAVE:%d \r\n",data1);      
    
            } 
        #endif 
        #ifdef Slave      //master? 
            static unsigned char data=0;
            data=SPI_receive(); //Receive Function 
            if(data==0xff)
            {
            PORTG=0X00;   //Buzz, LED ON   
            }
            if(data==0xfe)
            {
            PORTG=0X13;  //Buzz, LED OFF
            }                    
        #endif 
    }
      
}