SPI 플래시에 0x9F 명령을 보냈는데 EF 40 16 대신 FF FF FF나 한 바이트 밀린 값이 나오나요? 명령과 응답을 한 번의 칩 선택 구간에서 네 바이트 교환으로 다루면 확인할 지점이 분명해집니다. 이 글은 MCU 펌웨어와 임베디드 Linux 개발자를 위한 Winbond W25Q32JV의 JEDEC ID 읽기 예제입니다.
예제는 호스트 PC의 가짜 SPI 버스로 전송 순서와 오류 처리를 검증합니다. 실제 플래시 칩, 배선, 전압, SPI 파형을 측정한 결과는 아닙니다. 다른 모델에서는 해당 부품의 데이터시트와 예상 ID를 다시 확인하세요.
1. 네 바이트를 보내야 세 바이트를 받는다
Winbond W25Q32JV 데이터시트의 Read JEDEC ID (9Fh) 명령은 명령 바이트 뒤에 제조사·메모리 종류·용량 코드 세 바이트를 출력합니다. W25Q32JV-IQ/JQ의 표에는 EF 40 16, IM/JM의 표에는 EF 70 16이 제시됩니다. 이는 제품 식별 코드이며, 일반적인 데이터 읽기 주소나 더미 사이클과 혼동하면 안 됩니다. 실제 부품의 뒷자리와 데이터시트 리비전을 다시 대조하세요. Winbond 공식 W25Q32JV 데이터시트, 현재 문서 목록
SPI는 송신과 수신이 동시에 진행됩니다. 송신 버퍼를 9F 00 00 00으로 두면, 첫 수신 바이트 rx[0]은 명령을 보내는 동안 들어온 값이라 버립니다. 그다음 rx[1], rx[2], rx[3]이 ID입니다. 여기서 00 세 개는 응답을 읽기 위해 클럭을 만드는 송신 값입니다. 이 명령에 별도 주소 바이트를 붙이지 않습니다.
칩 선택(CS)을 0x9F 전송 후에 해제하면 플래시가 다음 세 바이트를 같은 명령으로 보지 않을 수 있습니다. Linux spidev의 일반 read()와 write() 사이에는 CS가 해제됩니다. 한 메시지 안의 full-duplex 전송은 SPI_IOC_MESSAGE(N)으로 수행할 수 있습니다. MCU HAL에서도 CS를 내리고 네 바이트를 교환한 뒤 올리는 동등한 전송 함수를 사용하세요. Linux 커널 SPI userspace 문서
| 교환 번호 | MOSI (MCU → 플래시) | MISO (플래시 → MCU) | 처리 |
|---|---|---|---|
| 0 | 9F |
미정 | 버림 |
| 1 | 00 |
EF |
제조사 |
| 2 | 00 |
40 |
종류 |
| 3 | 00 |
16 |
용량 코드 |
2. 복사해서 빌드하는 C 예제
다음 파일을 jedec_id.c로 저장하세요. gcc -std=c11 -Wall -Wextra -Werror jedec_id.c -o jedec_id로 빌드하고, Windows PowerShell에서 .\jedec_id.exe, Linux에서 ./jedec_id를 실행합니다. 검사용 assert가 켜지도록 -DNDEBUG를 붙이지 않습니다.
spi_exchange는 CS를 유지한 채 길이만큼 동시에 송수신하는 보드별 함수의 계약입니다. 실제 보드에서는 CS 설정과 HAL 오류 반환을 이 함수에 연결하세요. 코드는 교환 실패 또는 명백한 미연결 패턴에서 호출자의 기존 ID를 덮어쓰지 않습니다. FF FF FF 검사는 진단 힌트이지 완전한 연결 검증이 아닙니다.
예상 출력:
3. 보드에 연결할 때 확인할 것
- 데이터시트의 전원 전압과 보드 IO 전압을 비교하고 GND, CS, CLK, MOSI, MISO를 확인합니다. W25Q32JV의 제품 페이지에는 2.7~3.6 V 제품군이 명시되어 있습니다. Winbond 제품 정보
- 해당 부품 데이터시트에 맞는 SPI 모드와 속도를 설정합니다. 초기 디버깅에서는 낮은 속도부터 시작하고, 한 CS 구간에 명령과 응답 세 바이트가 모두 들어가는지 로직 애널라이저로 봅니다.
- 반환 ID 세 바이트를 기록하고 대상 부품 표와 비교합니다.
rx[0]을 ID로 해석하면 한 바이트 밀립니다.FF FF FF는 MISO 풀업, CS 미선택, 잘못된 배선·모드·전원 상태 등을 순서대로 확인할 신호이며 원인을 하나로 단정하지 않습니다. - Linux의
spidev라면 같은 메시지의 한 full-duplex 구간을 사용합니다. 명령write()후 별도read()호출로 나누지 않습니다. 커널 드라이버가 장치를 점유한다면/dev/spidev*사용 여부도 먼저 확인합니다.
예제의 가짜 버스는 정확한 9F 00 00 00과 한 번의 4바이트 호출, EF 40 16 파싱, 통신 실패·미연결 패턴·잘못된 인수를 검사했습니다. 실제 하드웨어가 없다면 여기까지가 검증 범위입니다. 예제 코드는 JDevCompany가 작성한 CC0-1.0 코드이며, 공식 문서 확인과 호스트 실행 검증은 2026-09-25에 수행했습니다.
댓글
첫 댓글을 남겨 보세요.