아트메가/이론

ATMEGA128 SPI통신 알아보기 2편

원원 2023. 2. 19. 02:13

안녕하세요. 1편에 이어서 ATMEGA SPI통신 READ를 구현해보겠습니다.
1편에서는 SPI세팅과 SPI WRITE를 했었습니다 (1편:https://wowon.tistory.com/277)

 

SPI에서 마스터가 슬레이브에게 READ를 하려면 클럭을 흔들어야하는데 클럭은 마스터만 흔들 수 있습니다. 그래서 SPI통신은 WRITE를할때 READ를 같이 합니다. 그래서 READ를 하려면 의미없는 값을 WRITE하면 됩니다.
일반적으로 슬레이브(센서)를 READ를 할때 아래의 방식으로 합니다
1) 마스터가 슬레이브에게 특정값 WRITE함
2) 슬레이브는 특정값에 맞는 데이터를 준비해놓음
3) 마스터가 슬레이브에게 의미없는값을 WRITE함
4) 슬레이브는 특정값을 줌

READ해야하는 레지스터는 SPDR입니다. SPDR레지스터를 읽으면 수신버퍼를 읽을 수 있습니다

 

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <string.h>

/* SPI */
unsigned char SPI_WRITE(unsigned char data)
 {
     SPDR = data;
     while(!(SPSR&(1<<SPIF)));
     return SPDR;
 }
unsigned char SPI_READ(unsigned char data)
{
	unsigned char val;
	SPI_WRITE(data);
	val = SPI_WRITE(0x00);
	return val;
}
 void SPI0_init()
 {
     /* 
     PB0 : SS
     PB1 : SCK
     PB2 : MOSI
     PB3 : MISO
     */
     DDRB |= 0x07; // SS, SCK, MOSI OUTPUT
     DDRB &= ~0x08; // MISO INPUT
     SPCR = (1<<SPE)|(1<<MSTR);
 }
/* SPI */ 

int main(void)
{
	SPI0_init();
	unsigned char c=0;

	while(1)
	{
		PORTB &= ~0x01;
		c = SPI_READ(0x01);
		PORTB |= 0x01;
		_delay_ms(1000);
	}
}

1편에있는 코드를 변경하였습니다. WRITE하고나서 수신버퍼에 있는 값(SPDR)을 RETURN해줍니다. 그리고 SPI_READ함수에서는 1~4번과정이 적용되어있습니다.
SPI모듈을 연결안하고 코드를 실행시키면 당연히 c=0입니다.

그럼 이제 실제로 SPI통신을 지원하는 센서를 사용해서 SPI READ를 해보겠습니다.
사용 할 모듈은 MPU-9250입니다.
MPU-9250타이밍다이어그램입니다. 그리고 클럭 프리퀀스는 최대 1MHz입니다.

 

MPU-9250 SPI통신 규칙입니다. 먼저 Address format으로 READ나 WRITE를 하고나서 DATA를 WRITE/READ합니다.
이때 READ를 하려면 Address format의 7bit는 1이여야합니다.

읽을값은 107(0x6B), 117(0x75)이고 READ이므로 OR 0x80 해줘야합니다. READ를 하면 0x01, 0x71이 나와야 합니다.

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <string.h>

/* SPI */
unsigned char SPI_WRITE(unsigned char data)
 {
     SPDR = data;
     while(!(SPSR&(1<<SPIF)));
	 return SPDR;
 }
unsigned char SPI_READ(unsigned char data)
{
	unsigned char val;
	SPI_WRITE(data);
	val = SPI_WRITE(0x00);
	return val;
}
 void SPI0_init()
 {
     /* 
     PB0 : SS
     PB1 : SCK
     PB2 : MOSI
     PB3 : MISO
     */
     DDRB |= 0x07; // SS, SCK, MOSI OUTPUT
     DDRB &= ~0x08; // MISO INPUT
     SPCR = (1<<SPE)|(1<<MSTR)|(1<<CPOL)|(1<<CPHA)|(1<<SPR0);
 }
/* SPI */ 



int main(void)
{
	SPI0_init();
	unsigned char c=0;
	unsigned char c1=0;
	
	while(1)
	{
		PORTB &= ~0x01;
		c = SPI_READ(0x80|0x6B);
		PORTB |= 0x01;

		PORTB &= ~0x01;
		c1 = SPI_READ(0x80|0x75);
		PORTB |= 0x01;
		_delay_ms(1000);
	}
}

실제 변수에 들어가있는값이 0x01, 0x71이고 파형도 0x01, 0x71이 찍혔습니다.