무선 칩셋의 특정 레지스터를 SPI 로 읽으면 항상 0이 나왔다. 다른 레지스터는 정상인데 그것만 그렇다.
배선을 의심했고 SPI 규격을 의심했고 타이밍을 의심했는데 다른 레지스터가 잘 읽히니 그쪽일 가능성은 낮았다.
Table of contents
Open Table of contents
데이터시트를 다시 읽었다
처음에 읽었을 때는 Register Map 표만 봤는데 주소와 비트 정의가 있는 표다.
이번에는 그 장 전체를 읽었다. 표 아래에 각주가 있었다.
이 레지스터는 칩이 특정 모드일 때만 유효하다.
다른 모드에서 읽으면 0을 반환한다.
MODE_IDLE 로 전환을 안 하고 읽고 있었고 전환한 뒤 읽으니 값이 나왔다.
원인 — 표와 각주가 말하는 것
Register Map 만 보고 넘어갔기 때문에 못 봤다. 표는 무엇이 있는가를 각주는 언제 유효한가를 알려 준다.
Register Map 은 정적인 그림이라 조건이 안 보인다. 칩 상태에 따라 같은 주소가 다른 것을 뜻하거나 아예 안 읽히기도 한다.
읽는 쪽에서 보면 이 둘은 같은 무게가 아니다. 주소를 몰라서 못 읽는 일보다 조건을 몰라서 0을 읽는 일이 훨씬 찾기 어렵다.
주소가 틀리면 아무 값이나 나와서 금방 안다. 조건을 안 맞추면 그럴듯한 0이 나와서 배선부터 의심하게 된다.
코드에도 답이 있었다
더 허탈한 것이 있었다. 벤더가 준 예제 코드를 열어 봤다.
static int read_status(void)
{
set_mode(MODE_IDLE); /* 이 레지스터는 IDLE에서만 읽힌다 */
return reg_read(REG_STATUS);
}
같은 파일 안 다른 함수에 set_mode 가 먼저 있고 주석까지 달려 있었다. 내가 짠 함수는 그 패턴을 안 따랐다.
예제에서 필요한 부분만 복사해 오면서 앞뒤 문맥을 뺀 것이고 reg_read 한 줄만 가져왔다.
그래서 순서를 바꿨다
새 하드웨어를 붙일 때의 순서를 다시 잡았다.
1. 동작 모드와 상태 전이도를 먼저 읽는다
2. 그다음 레지스터 맵
3. 각 레지스터의 유효 조건을 함께 적어 둔다
그리고 Datasheet 보다 예제를 먼저 여는 쪽으로 바꿨다. 같은 기능을 다루는 부분이 있으면 이미 동작하는 코드가 가장 빠른 답이다.
그 코드는 통째로 읽는다. 필요한 줄만 뽑으면 앞뒤에 있던 전제가 함께 안 온다.
이번 경우가 그랬는데 set_mode 가 reg_read 보다 앞에 있었고 그것을 안 가져오니 같은 문제가 났다.
복사할 때 주석도 같이 가져온다. 주석이 안 오면 왜 그렇게 하는지가 사라지고 다음 사람이 그 줄을 지운다.
참고 자료 — 벤더 문서의 계층
이 일을 겪고 벤더 자료를 보는 순서를 정했다.
| 자료 | 담는 것 | 언제 보나 |
|---|---|---|
| 데이터시트 | 전기적 특성, 레지스터, 유효 조건 | 처음, 그리고 값이 이상할 때 |
| 애플리케이션 노트 | 실제 사용 패턴, 권장 설정 | 설계할 때 |
| 예제 코드 | 동작하는 순서 | 붙일 때 |
| 에라타 | 문서와 실제가 다른 부분 | 문서대로 했는데 안 될 때 |
마지막이 특히 중요했는데 Errata 는 Datasheet 가 틀린 곳의 목록이다.
문서대로 했는데 안 되면 여기부터 본다. 이 칩셋에도 Errata 가 있었고 다른 레지스터 하나가 문서와 다르게 동작한다고 적혀 있었다.
나중에 그것도 겪었을 텐데 미리 봐서 피했다. 틀린 곳을 적어 둔 문서가 따로 있다는 것을 아는 것만으로 조사 한 번을 덜었다.
정리
- 레지스터 표만 보고 넘어가면 유효 조건을 놓친다
- 표는 무엇이 있는지를 각주는 언제 유효한지를 말한다
- 주소가 틀리면 금방 아는데 조건을 안 맞추면 그럴듯한 0이 나온다
State Diagram을 먼저 읽고Register Map과 유효 조건을 함께 적는다- 예제 코드에서 같은 기능을 다루는 부분을 먼저 찾는다
- 동작하는 코드가 가장 빠른 답인 경우가 있다
- 예제에서 필요한 줄만 뽑으면
set_mode같은 전제가 빠진다 - 복사할 때 주석을 같이 가져와야 이유가 안 사라진다
Errata는 문서가 틀린 곳 목록이라 문서대로 했는데 안 되면 거기부터 본다