안녕하세요. 오늘은 ATMEGA128로 SPI통신에대해 알아보겠습니다. 이 글에서는 SPI통신 WRITE만 알아보고 실제로 8*8 dot matrix(MAX7219사용)을 제어해보겠습니다
기본적인 SPI개념은 아래 글 참조바랍니다
*사용 핀
ATMEGA128에서 SS,SCK,MOSI,MISO 핀은 아래의 핀을 사용합니다
*SPI관련 레지스터
SPCR 레지스터입니다. 이 레지스터에서는 SPI통신을 하기위한 다양한 설정을 합니다.
※ SPCR 레지스터
7bit SPIE : SPI 인터럽트 Enable. Enable일때 인터럽트가 뜨려면 SPIF bit 와 SREG 비트가 set되어야함
6bit SPE : SPE Enable
5bit DORD : [1]은 LSB, [0]은 MSB
4bit MSTR : [1]은 Master mode, [0]은 Slave mode
3bit CPOL : Clock parity
2bit CPHA : Clock phase
1bit SPR1 : Clock Rate Speed1
0bit SPR0 : Clock Rate Speed1
SPI통신에는 interrupt함수가 1개입니다.(SPI_STC_vect) Master mode일때 인터럽트를 사용하면, 인터럽트는 데이터가 송신완료되고나서 발생하고 Slave mode일때 인터럽트를 사용하면 데이터를 수신되고나서 인터럽트가 발생합니다. 아래에서 Master mode일때 인터럽트방식과 polling방식 모두 테스트해보겠습니다.
※ SPSR 레지스터
7bit SPIF : SPI Interrupt Flag. 데이터 전송이 완료되면 set 됩니다.
6bit WCOL : Write COLlsion flag. 데이터 전송중에 SPDR가 기록되면 set됩니다.
0bit SPI2X : Double SPI Speed Bit.
※ SPDR 레지스터
Read/WRite할때 사용하는 레지스터입니다.
이제 실제로 코드를 작성해서 SPI통신을 해보겠습니다.
Master모드, polling방식, CPOL 0, CPHA 0, Clock Speed 4Mhz, MSB
SPSR레지스터 설정
7bit SPIE : 0
6bit SPE : 1
5bit DORD : 0
4bit MSTR : 1
3bit CPOL : 0
2bit CPHA : 0
1bit SPR1 : 0
0bit SPR0 : 0
사실상 Master모드와 SPI를 사용한다는 설정말고는 기본값입니다
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <string.h>
void SPI_WRITE(unsigned char data)
{
SPDR = data;
while(!(SPSR&(1<<SPIF)));
}
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();
while(1)
{
PORTB &= ~0x01;
SPI_WRITE(0xAA);
PORTB |= 0x01;
}
}
코드에서 while(!(SPSR&(1<<SPIF)));부분이 있습니다. while(!(SPSR&(0x08));과 같은거고 SPSR의 7번째 bit가 0이면 대기하고있고 1이면 통과입니다. SPSR의 7번째 비트는 SPIF입니다. SPIF는 데이터전송이 완료하고나서 1이되므로 SRDR = data에서 데이터를 보내고 기다리고있다가 SPIF가 1이되면 다음코드로 진행입니다.
그럼 위의 코드에서 SRDR = data를 하고 SPIF비트가 set될때까지 기다리지 않는다면 나오는 파형을 보겠습니다.
void SPI_WRITE(unsigned char data)
{
SPDR = data;
//while(!(SPSR&(1<<SPIF)));
}
SS라인이 LOW일때 클럭이 8번 흔들려야하는데, SPIF를 기다리지않고 계속 SRDR에 데이터를 보내니까 데이터를 인식하지 못합니다.
그럼 위의 코드에서 SRDR = data 뒤에 delay를 1ms 줘보겠습니다
void SPI_WRITE(unsigned char data)
{
SPDR = data;
//while(!(SPSR&(1<<SPIF)));
_delay_ms(1);
}
데이터를 잘 인식합니다
위의 방식은 polling 방식이였고 이제 interrupt 방식을 해보겠습니다.
Master모드, interrupt방식, CPOL 0, CPHA 0, Clock Speed 4Mhz, MSB
SPSR레지스터 설정
7bit SPIE : 1
6bit SPE : 1
5bit DORD : 0
4bit MSTR : 1
3bit CPOL : 0
2bit CPHA : 0
1bit SPR1 : 0
0bit SPR0 : 0
그리고 interrupt를 사용하므로 전역인터럽트르 set 해줘야합니다 (sei();)
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <string.h>
unsigned char spi_interrupt = 0;
/* SPI */
ISR(SPI_STC_vect)
{
spi_interrupt = 1;
}
void SPI_WRITE(unsigned char data)
{
SPDR = data;
while(!spi_interrupt);
spi_interrupt = 0;
}
void SPI0_init()
{
/*
PB0 : SS
PB1 : SCK
PB2 : MOSI
PB3 : MISO
*/
DDRB |= 0x07; // SS, SCK, MOSI OUTPUT
DDRB &= ~0x08; // MISO INPUT
SPCR = (1<<SPIE)|(1<<SPE)|(1<<MSTR);
}
/* SPI */
int main(void)
{
sei();
SPI0_init();
while(1)
{
PORTB &= ~0x01;
SPI_WRITE(0xAA);
PORTB |= 0x01;
}
}
SPI통신을 사용해서 실제 모듈과 통신을 해보겠습니다. 사용할 모듈은 8*8 dot matrix(MAX7219) 입니다. 이 모듈은 SPI READ할 필요는 없고 SPI WRITE만 해서 dot matrix를 키면 됩니다. polling 방식을 사용할겁니다.
8*8 dot matrix(MAX7219)랑 통신할때 필요한 기본적인 설정방법은 https://wowon.tistory.com/276 사이트와 데이터시트 참조 바랍니다.SPI 통신에 관한 글이므로 MAX7219에 대해 자세히는 설명하지않겠습니다.
기본적으로 MAX7219랑 통신하려면 먼저 MAX7219 세팅을 해주고나서,dot matrix를 켜주면 됩니다.
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <string.h>
/* SPI */
void SPI_WRITE(unsigned char data)
{
SPDR = data;
while(!(SPSR&(1<<SPIF)));
}
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 */
void MAX7219(unsigned char address, unsigned char data)
{
PORTB &= ~0x01;
SPI_WRITE(address);
SPI_WRITE(data);
PORTB |= 0x01;
}
int main(void)
{
SPI0_init();
DDRA= 0xff;
int line = 0;
int i;
unsigned char display_dotmatrix[2][8] = {
{0xc3, 0xc3, 0xc3, 0xff, 0xff, 0xc3, 0xc3, 0xc3},
{0xff, 0xff, 0x18, 0x18, 0x18, 0x18, 0xff, 0xff},
};
MAX7219(0x09,0x00);
MAX7219(0x0A,0x01);
MAX7219(0x0b,0x07);
MAX7219(0x0c,0x01);
MAX7219(0x0f,0x00);
while(1)
{
PORTB &= ~0x01;
for (i = 0; i < 8; i++) {
MAX7219(i+1, display_dotmatrix[line][i]);
}
PORTB |= 0x01;
_delay_ms(1000);
line = !line;
}
}
다음에는 SPI READ를 해보겠습니다
'아트메가 > 이론' 카테고리의 다른 글
ATMEGA128 주솟값으로 제어하기 (0) | 2023.02.25 |
---|---|
ATMEGA128 SPI통신 알아보기 2편 (1) | 2023.02.19 |
ATMEGA128 UART 수신인터럽트 발생하는 시점 (0) | 2023.01.08 |
ATMEGA128 TWI(I2C)통신 알아보기 3편 (0) | 2022.09.13 |
ATMEGA128 TWI(I2C)통신 알아보기 2편 (2) | 2022.09.11 |