Skip to content
isdnetworks
Go back

사양서를 안 보고 코드부터 짰다

(수정됨)

새 I2C 센서를 붙이는데 값이 계속 이상했다. 코드를 몇 번 고쳤는데 나아지지 않았고 사양서를 보니 코드 문제가 아니었다.

Table of contents

Open Table of contents

변환 시간이 필요했다

읽는 흐름은 이랬다.

i2c_write(ADDR, REG_CTRL, CMD_START);   /* 측정 시작 */
i2c_read(ADDR, REG_DATA, buf, 2);       /* 값 읽기 */

CMD_START 를 보내고 곧바로 i2c_read 를 건다. 사양서에는 이렇게 적혀 있었다.

Measurement time: typ. 65ms, max. 85ms (14-bit resolution)

측정에 65밀리초가 걸리고 그 전에 읽으면 이전 값이나 쓰레기가 나온다. 그 값은 데이터시트의 타이밍 표에 그대로 적혀 있었다.

i2c_write(ADDR, REG_CTRL, CMD_START);
delay_ms(90);                            /* 최대치보다 여유 */
i2c_read(ADDR, REG_DATA, buf, 2);

90밀리초를 기다리게 했고 최대치가 85니까 여유를 뒀다. 이 시간은 센서가 정한 것이라 코드로 줄일 수 없다.

준비 여부를 물어보는 방법도 있었다

기다리는 대신 상태를 확인할 수도 있었다.

i2c_write(ADDR, REG_CTRL, CMD_START);

int wait = 0;
uint8_t st;
do {
    delay_ms(5);
    i2c_read(ADDR, REG_STATUS, &st, 1);
    wait += 5;
} while (!(st & STATUS_READY) && wait < 200);

if (!(st & STATUS_READY)) return -1;    /* 상한 초과 */
i2c_read(ADDR, REG_DATA, buf, 2);

STATUS_READY 가 서면 바로 읽으니 평균 대기가 짧아진다. 대신 통신이 늘어나고 5밀리초마다 상태를 묻는다.

이 장치는 1초에 한 번 읽으면 되니 고정 대기로 했고 자주 읽어야 하는 자리라면 상태 확인이 낫다.

해상도 설정에 따라 시간이 달라졌다

사양서를 더 읽어 보니 해상도 설정이 있었다.

14-bit  65ms
12-bit  17ms
11-bit   9ms

우리는 0.1도 단위면 충분해서 해상도를 12비트로 낮췄고 대기가 17밀리초로 줄었다.

필요한 정밀도를 먼저 정하면 나머지가 정해진다. 무조건 최고 해상도를 쓸 이유가 없었고 그 설정도 I2C 로 레지스터에 써 넣는 값이다.

변환식과 전기 특성

값을 변환하는 식도 확인했다.

Temperature = -46.85 + 175.72 * (raw / 65536)

내가 쓰던 식은 raw / 256.0 이었는데 다른 센서의 식이었다.

float temp = -46.85f + 175.72f * ((float)raw / 65536.0f);

계수가 센서마다 다르니 비슷한 센서라고 같은 식을 쓰면 안 된다. 계수를 #define 으로 빼 두면 다음에 센서가 바뀌어도 그 줄만 고치면 된다.

값이 가끔 튀는 문제도 남아 있어서 사양서의 전기 특성을 봤다.

Supply voltage: 2.1 ~ 3.6V
I2C pull-up: 10kΩ typ.

회로를 확인하니 풀업 저항이 4.7k였고 범위 안이긴 한데 선이 길어서 신호가 흔들렸다.

I2C 는 SDA 와 SCL 두 신호선을 여럿이 나눠 쓰는 구조라 풀업이 없으면 신호가 높은 쪽으로 안 올라간다. 이것은 코드로 못 고쳐서 하드웨어 담당자에게 넘겼다.

증상이 코드에서 안 잡히면 그 아래를 봐야 한다.

검증 — 확인 순서와 식별 레지스터

새 장치를 붙일 때 볼 순서를 적었다.

1. 사양서에서 확인
   - 주소, 레지스터 맵
   - 측정 시간, 준비 확인 방법
   - 값 변환식
   - 동작 범위 (온도, 전압)
   - 통신 속도 상한

2. 통신 확인
   - 주소로 응답하는가 (스캔)
   - 식별 레지스터 값이 맞는가

3. 값 확인
   - 알려진 조건에서 값이 맞는가 (상온에서 25도 근처)
   - 범위 안인가
   - 반복 읽었을 때 흔들림이 얼마인가

2번의 식별 레지스터 확인이 유용했다. 대부분의 센서가 고정 값을 주는 레지스터를 갖고 있다.

uint8_t id;
i2c_read(ADDR, REG_ID, &id, 1);
if (id != EXPECTED_ID) {
    log_error("센서 식별 불일치: 0x%02X (기대 0x%02X)", id, EXPECTED_ID);
    return -1;
}

REG_ID 가 맞으면 통신은 되는 것이고 값이 이상하면 통신이 아니라 다른 문제다. 통신 자체가 안 되는데 값 처리를 보는 것은 순서가 뒤바뀐 것이다.

값들이 어디서 왔는지 알 수 있게 주석도 달았다.

#define MEAS_TIME_MS   90    /* 사양서 5.2절: 14bit max 85ms */
#define TEMP_MIN      (-40.0f)  /* 사양서 2.1절 동작 범위 */
#define EXPECTED_ID    0xBE     /* 사양서 6.4절 */

숫자만 있으면 왜 그 값인지 모르는데 사양서 절 번호를 적어 두니 확인이 빨라졌다.

정리


Share this post on:

Previous Post
두 DB를 한 트랜잭션으로 묶고 싶을 때
Next Post
프레임워크가 구조를 정해 줄 때