Skip to content
isdnetworks
Go back

핀 하나를 나눠 쓴 대가

칩의 핀이 부족해서 하나를 두 용도로 쓰고 있었다. 레지스터 설정에 따라 같은 PIN_5 가 A로도 B로도 동작하는 구조였다.

회로에서는 자연스러운 선택이다. 핀을 하나 아끼면 더 작은 칩을 쓸 수 있고 그만큼 값과 기판 넓이가 줄어든다.

그 절약이 전부 소프트웨어 쪽으로 넘어왔다.

Table of contents

Open Table of contents

전환에 시간이 든다

A로 쓰다가 B로 쓰려면 모드를 바꾸고 다시 돌려놔야 한다.

set_pin_mode(PIN_5, MODE_B);
do_b_thing();
set_pin_mode(PIN_5, MODE_A);

do_b_thing 하나를 부르려고 set_pin_mode 를 두 번 부르는 모양이 된다. 그리고 전환 자체에 시간이 든다.

데이터시트에는 모드를 바꾼 뒤 신호가 안정될 때까지 몇 클럭을 기다리라고 적혀 있었다. 한 번이면 무시할 만한 값인데 A와 B를 자주 번갈아 쓰면 그 대기가 계속 쌓인다.

호출 한 번의 비용이 아니라 호출 빈도의 비용이었다. 바꿔 쓰는 횟수를 줄이는 것이 곧 성능 문제가 됐다.

동시에 못 쓴다

더 큰 문제는 두 기능을 같은 시각에 못 쓴다는 점이었다. A가 도는 동안 B가 필요해지면 A를 멈춰야 한다.

그런데 A가 통신이라 중간에 멈추면 받던 자료가 유실된다. 그래서 아무 때나 MODE_B 로 바꿀 수 없고 타이밍을 따로 맞춰야 했다.

소프트웨어가 하드웨어 제약을 계속 신경 쓰면서 돌게 된 것이다. B를 부르는 자리마다 지금 A가 한가한지를 먼저 따져야 했다.

원인 — 전환 구간에 끼어드는 인터럽트

A를 처리하는 중에 인터럽트가 들어오면 그 안에서도 같은 핀을 만질 수 있다.

메인: A 모드로 전환 → (인터럽트) → B로 바꿈 → 복귀 → 메인이 A라고 믿고 동작 → 실패

메인 쪽은 자기가 MODE_A 로 맞춰 뒀다고 믿는데 복귀 시점의 실제 레지스터는 MODE_B 다. 핀 모드가 코드의 가정과 어긋난 상태가 된다.

이것을 막으려고 전환 구간을 인터럽트로부터 닫았다.

disable_irq();
set_pin_mode(PIN_5, MODE_B);
do_b_thing();
set_pin_mode(PIN_5, MODE_A);
enable_irq();

disable_irqenable_irq 사이에서는 ISR 이 안 돌므로 모드가 중간에 안 바뀐다. 그런데 그 구간이 길면 그동안 다른 처리가 전부 밀린다.

하나를 막으니 다른 제약이 생기는 식이었다. do_b_thing 이 오래 걸릴수록 통신 쪽이 손해를 본다.

해결 — 현재 모드를 변수로 들고 있기

지금 어느 모드인지를 암묵적으로 가정하는 코드가 여기저기 있었다. 그 가정을 없애려고 현재 모드를 변수 하나로 명시했다.

static volatile pin_mode_t current_mode;

void ensure_mode(pin_mode_t m) {
    if (current_mode != m) {
        set_pin_mode(PIN_5, m);
        current_mode = m;
    }
}

ISR 에서도 읽고 쓰므로 volatile 을 붙여 컴파일러가 그 읽기를 걷어내지 못하게 했다. ensure_mode 는 이미 그 모드면 set_pin_mode 를 안 부르고 그냥 돌아온다.

그래서 불필요한 전환이 크게 줄었다. 상태를 안 들고 있으면 안전을 위해 매번 전환하게 되고 그 대기가 전부 낭비가 된다.

변수 하나를 관리하는 비용으로 전환 횟수를 샀다. 코드는 늘었지만 대기 시간은 줄었다.

회로에서 아낀 것이 넘어온다

여기까지가 전부 핀 하나를 아끼려다 생긴 일이다. 핀이 하나만 더 있었으면 전환도 대기도 인터럽트 차단도 없었다.

비용이 사라진 것이 아니라 회로에서 소프트웨어로 옮겨 간 것이다. 회로도에서는 안 보이고 코드에서만 보이니 아낀 쪽만 눈에 남는다.

그것이 틀린 결정이라는 말은 아니다. 칩 값과 기판 크기에 제약이 있었을 테고 그 판단은 그 판단대로 맞다.

다만 그 결정이 소프트웨어에 얼마를 물리는지를 설계 단계에서 같이 봤으면 좋았을 것이다. 한쪽 비용만 재면 총합이 늘어도 줄인 것처럼 보인다.

변경 내용 — 다음 판에 반영된 것

기판 개정 논의가 열렸을 때 핀 하나 때문에 소프트웨어가 얼마나 복잡해졌는지를 적어 올렸다.

숫자로 적으니 검토 대상이 됐다. 복잡하다는 말만으로는 회로 쪽이 움직일 근거가 되지 않는다.

같은 내용을 말로만 하면 취향 문제로 들린다. 시간과 개수로 적으면 기판 값과 같은 저울에 올릴 수 있다. 결과적으로 다음 판에서는 핀이 나뉘었다.

정리


Share this post on:

Previous Post
기술로는 되는데 계약으로 안 됐다
Next Post
폴더를 옮겼는데 옛 경로가 코드에 남아 있었다