
SPI, 스위치 모두 구현을 하지 못한 채로 숙소에 도착해서 밤새도록 관련 디버깅만 계속 했다...
밤 12시쯤에 스위치 구현이 되었고 새벽 3시쯤인가에 dot matrix가 구현이 완료되었던 것 같다.
그만큼 spi 통신 구현하는 것이 쉽지는 않았다.
2) dot matrix
dot matrix를 구현하기 위해 spi통신을 활용해야 한다. 정확히는 dot matrix를 제어하기 위하여 spi를 사용하는 것이다.

dot matrix는 switch matrix와 비슷한 방식으로 한줄씩 출력을 진행하는 것이다. 이 속도가 충분히 빠르다면 잔상효과로 인해 led가 동시에 들어와 있는 것처럼 보이는 것이다.
이 dot matrix를 여러개 제어하기 위해서는 너무나 많은 pin이 필요한데, 이를 해결하기 위한 모듈이 MAX7219 드라이버이다.
이 드라이버는 DOT MATRIX를 SPI로 제어할 수 있도록 도와주고 매트릭스의 확장까지 지원한다.


SPI통신의 구조는 다음과 같다.
| MOSI | 출력 | 입력 | 마스터 → 슬레이브 데이터 전송 |
| MISO | 입력 | 출력 | 슬레이브 → 마스터 데이터 수신 |
| SCK | 출력 | 입력 | 클럭 신호 (마스터가 제어) |
| SS/CS | 출력 | 입력 | 슬레이브 선택 (Low 활성) |
SPI통신은 UART와 다르게 동기식 통신이라는 특징이 있다. 따라서 SCK라는 클럭 신호가 필요하다.
SS라는 통신 선택기능이 있는데, 지금은 1대1통신을 할 예정이므로 이것은 신경쓰지 않고 1을 입력해주면 된다.
MATRIX에 출력을 하는 상황은 MASTER에서 출력하고 SLAVE에서 IN을 하는 상황이므로 MOSI이며, MISO상황은 존재하지 않는다.
따라서 MAX7219 모듈을 살펴보면 VCC, GND, DIN(MOSI), CS, CLK만 존재한다.

SPI회로의 내부를 간략하게 살펴보자. 클락에 맞게 동기적으로 통신한다고 했는데, 간단하게 MASTER와 SLAVE가 각각 shift register를 가지고 있기 때문에 동기적으로 데이터를 주고받는다고 생각하면 된다.

그럼 통신과정을 살펴보자.
SPI의 마스터와 슬레이브 장치의 데이터 버퍼가 원형 큐를 이루고 있다고 생각하면 이해하기 쉽다.
마스터 장치의 1비트 데이터가 MOSI를 통해 슬레이브로 전달되며, 동시에 slave장치의 1비트 데이터가 MISO를 통해 마스터 장치로 전달된다. 따라서 8개의 클럭이 발생되면 마스터장치의 1바이트 데이터를 slave에 전달한 결과를 얻을 수 있는 것이다.
void SPI_Init(void) {
// SPI 통신용 핀 출력 설정
DDRB |= (1 << SPI_SS_LED | 1 << SPI_MOSI | 1 << SPI_SCK);
// 초기 SS HIGH(disable)
PORTB |= (1 << SPI_SS_LED);
// 마스터 설정, 클럭 속도 설정
SPCR |= (1 << SPE | 1 << MSTR | 1 << SPR1 | 1 << SPR0);
}
spi 통신 설정.


MAX7219는 2바이트를 받아와서 어떠한 명령을 수행한다.
따라서 한 명령을 수행하기 위해서는 SPI를 두번 호출해야한다는 것이다.
void SPI_byteTx(uint8_t byte) {
// 바이트 전송 후 완료 시까지 대기
SPDR = byte;
while (!(SPSR & (1 << SPIF)))
;
}
다음은 1바이트를 송신하는 SPI 명령이다.
void SPI_rowTx(uint8_t address, uint8_t data) {
SPI_select_LED(); // LED 매트릭스 선택
SPI_byteTx(address); // 주소 전송
SPI_byteTx(data); // 데이터 전송
SPI_deselect_LED(); // LED 매트릭스 선택 해제
}
SS를 0으로 내린다음에 2바이트를 송신하도 다시 SS를 1로 올리는 모습이다.

MAX7219 에 같은 주소에 값을 입력하면 덮어쓰기가 되는 방식이 아니라 다음모듈로 SHIFT가 된다. 이를 활용해서 매트릭스를 표현할 수 있다.
void SPI_cascadeTx(LEDdata *d, int n) {
// 각 row별로 전송
for (int r = 0; r < 8; r++) {
SPI_select_LED(); // LED 매트릭스 선택
// 해당 row의 데이터를 매트릭스 모듈마다 전송
for (int i = n - 1; i >= 0; i--) {
SPI_byteTx(r + 1);
SPI_byteTx(d[i].vector[r]);
}
SPI_deselect_LED(); // LED 매트릭스 선택 해제
}
_delay_us(200);
}
이런식으로 한 매트릭스에 해당되는 내용을 출력하는 함수를 만들고, 한글자씩 SHIFT하는 방식으로 설계하였다.
'프로젝트 > MCU 경진대회' 카테고리의 다른 글
| 2024 COSS 차세대반도체 MCU 응용 경진대회 본선 2일차 (0) | 2025.04.02 |
|---|---|
| 2024 COSS 차세대반도체 MCU 응용 경진대회 본선 1일차(1/2) (0) | 2025.04.02 |
| 2024 COSS 차세대반도체 MCU 응용 경진대회 예선 (2) | 2025.04.01 |