데이지체인 구조 이해했으니 이제 실제로 통신해보자.
STM32F103의 SPI1 사용. CubeMX에서 설정.
SPI 설정
AD7280A SPI 스펙:
- 클럭: 최대 1MHz
- CPOL=0, CPHA=1 (Mode 1)
- MSB First
- 32비트 프레임
CubeMX 설정:
Mode: Full-Duplex Master
Prescaler: 64 (72MHz/64 = 1.125MHz → 좀 빠름)
CPOL: Low
CPHA: 2 Edge
First Bit: MSB
Data Size: 8 bit
데이터 사이즈가 8비트인데 AD7280A는 32비트 프레임이다. 4번 연속으로 보내면 된다.
핀 연결
STM32 AD7280A
PA5 (SCK) --> SCLK
PA6 (MISO) <-- DOUT (마지막 디바이스)
PA7 (MOSI) --> DIN
PA4 (GPIO) --> CS
CS는 하드웨어 NSS 안 쓰고 GPIO로 제어했다. 타이밍 제어하기 편해서.
첫 통신 시도
간단하게 레지스터 읽기 시도.
uint8_t tx[4] = {0x00, 0x00, 0x00, 0x00};
uint8_t rx[4] = {0};
HAL_GPIO_WritePin(CS_GPIO, CS_PIN, GPIO_PIN_RESET);
HAL_SPI_TransmitReceive(&hspi1, tx, rx, 4, 100);
HAL_GPIO_WritePin(CS_GPIO, CS_PIN, GPIO_PIN_SET);
printf("RX: %02X %02X %02X %02X\n", rx[0], rx[1], rx[2], rx[3]);
결과: RX: 00 00 00 00
아무것도 안 온다.
삽질 1: CPOL/CPHA
로직 분석기로 찍어봤다.

클럭은 나가는데 MISO가 항상 Low. AD7280A가 응답을 안 한다.
CPOL/CPHA 조합을 다 바꿔봤다.
Mode 0 (CPOL=0, CPHA=0): 안 됨
Mode 1 (CPOL=0, CPHA=1): 안 됨
Mode 2 (CPOL=1, CPHA=0): 안 됨
Mode 3 (CPOL=1, CPHA=1): 안 됨
다 안 된다. CPOL/CPHA 문제가 아니었다.
삽질 2: 전원
멀티미터로 전원 확인.
VDD: 4.8V (5V 레귤레이터에서) DVDD: 0V
DVDD가 안 들어가고 있었다. 회로도 다시 보니까 DVDD는 별도로 연결해야 했다. VDD에서 자동으로 나오는 게 아니었다.
점퍼 연결하고 다시 시도.
결과: RX: FF FF FF FF
뭔가 온다!
삽질 3: 프레임 구조
FF가 오긴 하는데 이게 정상인지 모르겠다.
데이터시트 다시 읽어보니까, 읽기 명령을 제대로 보내야 응답이 온다. 그냥 0x00 보내면 안 된다.
AD7280A 프레임 구조:
[31:27] Device Address (5bit)
[26:21] Register Address (6bit)
[20:13] Data (8bit)
[12] Write/Read bit
[11:3] Reserved + CRC
[2:0] Reserved
32비트 중에 CRC까지 계산해서 보내야 한다. CRC가 틀리면 무시한다.
이게 다음 글 주제다. CRC 계산에서 3일 날렸다.
일단 여기까지
SPI 하드웨어 설정은 됐다. AD7280A가 응답은 한다.
근데 제대로 된 명령을 보내려면 프레임 구조랑 CRC를 알아야 한다.
// 지금까지 코드
void AD7280A_Init(void) {
// SPI 이미 CubeMX에서 초기화됨
// CS High (Idle)
HAL_GPIO_WritePin(CS_GPIO, CS_PIN, GPIO_PIN_SET);
}
uint32_t AD7280A_Transfer(uint32_t tx) {
uint8_t tx_buf[4], rx_buf[4];
// 32bit를 8bit 4개로 분할 (Big Endian)
tx_buf[0] = (tx >> 24) & 0xFF;
tx_buf[1] = (tx >> 16) & 0xFF;
tx_buf[2] = (tx >> 8) & 0xFF;
tx_buf[3] = tx & 0xFF;
HAL_GPIO_WritePin(CS_GPIO, CS_PIN, GPIO_PIN_RESET);
HAL_SPI_TransmitReceive(&hspi1, tx_buf, rx_buf, 4, 100);
HAL_GPIO_WritePin(CS_GPIO, CS_PIN, GPIO_PIN_SET);
return (rx_buf[0] << 24) | (rx_buf[1] << 16) |
(rx_buf[2] << 8) | rx_buf[3];
}
다음은 레지스터 맵이랑 프레임 구조. 32비트 안에 뭐가 들어가는지.