SPI 통신

2016. 4. 21. 18:04 from MCU/AVR

SPI 통신을 통해서 2byte 송수신 하기


ATmega128 두개로 SPI 통신을 테스트 해보았다. 하는 도중에 하위 1byte와 상위 1byte가 뒤집혀서 출력되는 현상이 있었는데 slave MISO 핀에 내부 풀업을 하지 않아서 발생하는 오류였다.


내부 풀업을 사용하지 않을시 아래와 같은 파형이 나온다. 저렇게 exp 적인 파형으로 인해서 잘못된 데이트가 입력되게 된다.







SPI 작동 방식





SPI 통신은 위 모양 처럼 환형큐의 모습을 가지고 있다. SPCR의 DORB(Data Order) 비트를 어떻게 설정 하느냐에 따라서 MSB 또는 LSB 부터 데이터 전송이 이루어진다.


2byte를 전송할 때에는 master와 slave 각 데이터를 상위 바이트와 하위 바이트로 나눈다. 그리고 상위 바이트는 상위 바이트끼리 환형큐 모양으로 전송하고, 하위 바이트도 환형큐 모양으로 전송한다.



< example >




SPCR의 CPHA bit이다. Setup과 Sample 뜻이 궁금했는데 아래 그림을 보면 알 수 있다.



CPHA가 0이면, master와 slave장치는 클럭신호 주기의 첫번째 엣지인 상승엣지에서 비트값을 읽고, 하강엣지에서 비트값을 변경할 수 있. CPHA가 1이면, 이 장치들은 클럭신호 주기의 두번째 엣지인 하강엣지에서 비트값을 읽는다. 그리고 비트값은 상승엣지에서 바뀔 수 있다. 비트값을 읽는동시에 값을 바꾸는 것이 아니다!



소스 코드


----------------------------------------- spi.h -------------------------------------------


#ifndef __SPI_H__

#define __SPI_H__


#define SS 0

#define SCK 1

#define MOSI 2

#define MISO 3


#define SPI_DDR DDRB

#define SPI_PORT PORTB

                                                            

void SPI_init_master();

void SPI_init_slave();


unsigned int SPI_IO_master(unsigned int);

unsigned int SPI_IO_slave(unsigned int);


#endif __SPI_H__



---------------------------------------- SPI_function.c ----------------------------------


#include <delay.h>

#include <mega128.h>

#include "spi.h"



void Putch (unsigned char data);

void SPI_init_master()

{

    //SPI_PORT |= (1 << SS); // pull up pins

    SPI_PORT |= (1 << MOSI) | (1 << MISO) | (1 << SCK) | (1 << SS);     // pulled up

    SPI_DDR |= (1 << MOSI) | (0 << MISO) | (1 << SCK) | (1 << SS);    // MOSI, SCK, SS output mode

    

    // SPI enable, set Master, fosc / 4    

    SPCR |= (0 << SPIE) | (1 << SPE) | (0 << DORD) | (1 << MSTR) | (0 << CPOL) | (1 << CPHA) | (0 << SPR0);

}


void SPI_init_slave()

{

    SPI_PORT |= (1 << MOSI) | (1 << MISO) | (1 << SCK) | (1 << SS);     // pulled up

    SPI_DDR = (1 << MISO);  // MISO output mode

    

    // SPI enable, set Slave    

    SPCR |= (0 << SPIE) | (1 << SPE) | (0 << DORD) | (0 << MSTR) | (0 << CPOL) | (1 << CPHA) | (0 << SPR0); 

}




unsigned int SPI_IO_master(unsigned int byte)

{

    unsigned int ad_value;

    unsigned char Mbyte, Lbyte; 

      

    SPI_PORT &= ~(1 << SS); //slave select low (통신할 수 있는 상태를 만듬)

      

    SPDR = (byte >> 8);                     

    while(!(SPSR & 0x80)); 

    Mbyte = SPDR;


    SPDR = byte;

    while(!(SPSR & 0x80)); 

    Lbyte = SPDR;

    

    ad_value = ((Mbyte << 8) | Lbyte);

    

    SPI_PORT |= (1 << SS);


    return ad_value;

}


unsigned int SPI_IO_slave(unsigned int byte)

{

    unsigned int ad_value;

    unsigned char Mbyte, Lbyte;

    

    SPDR = (byte >> 8);

    while(!(SPSR & 0x80));

    Mbyte = SPDR;


    SPDR = byte;

    while(!(SPSR & 0x80));

    Lbyte = SPDR;

                 

    ad_value = ((Mbyte << 8) | Lbyte);

    

    return ad_value;

}


------------------------------------------- master.c --------------------------------------------


#include <stdio.h>

#include <delay.h>

#include <mega128.h>xx  

#include "spi.h"



void UARTInit();          


void main()

{  

    unsigned int test = 2010;

    unsigned int rtn, cnt = 0;

 

    PORTA = 0x01;   

    DDRA = 0x0f;

    

    SPI_init_master();

    UARTInit();

    

    while(1){

        rtn = SPI_IO_master(test);

        delay_us(50);

                             

        //if (rtn != 4050) PORTA ^= 0x01;        

        //printf("%u \r\n", rtn);                

    }

}

     

void UARTInit()

{

    UCSR0A = 0x0;

    UCSR0B = 0b00001000;

    UCSR0C = 0b00000110;

    UBRR0H = 0;

    UBRR0L = 8;

}


----------------------------------------------- slave.c -----------------------------------------------


#include <stdio.h>

#include <delay.h>

#include <meag128.h>

#include "spi.h"


void UARTInit();


void main()

{

unsigned int test2 = 4050;

unsigned int rtn;


DDRA = 0xff;

PORTA = 0x01;


SPI_init_slave();

UARTInit();


while(1){

rtn = SPI_IO_slave (test2);


if (rtn != 2010) PORTA ^= 0x01;

}

}



void UARTInit()

{

    UCSR0A = 0x0;

    UCSR0B = 0b00001000;

    UCSR0C = 0b00000110;

    UBRR0H = 0;

    UBRR0L = 8;

}

'MCU > AVR' 카테고리의 다른 글

부트로더란?  (0) 2016.08.06
내부 풀업 저항 (I/O 포트)  (0) 2016.04.19
펌웨어와 임베디드  (0) 2015.05.29
인터럽트 한개로 다수의 RC 서보 제어  (0) 2013.12.17
[AVR] 데이터 손실  (0) 2013.12.12
Posted by 나무길 :