4.0 KiB
ADC 캡처 데이터가 전부 0으로 나온 상황 정리
작성일: 2026-06-11
배경
ADC echo 파형이 그래프 앞쪽으로 압축되어 보이는 문제가 있었다.
원인 후보로 src/drivers/echo_adc/echo_adc.c에서 2바이트 샘플마다 nrfx_spim_xfer()를 한 번씩 호출하는 구조가 지목되었다. 이 구조는 샘플마다 드라이버 호출/대기/CS 처리 오버헤드가 붙기 때문에 실제 샘플 간격이 예상보다 커질 수 있다.
그래서 샘플 간격을 줄이기 위해, 기존 레퍼런스 펌웨어처럼 SPIM 레지스터를 직접 만지는 hot loop 방식으로 바꾸는 실험을 했다.
현재 정상 동작 기준
현재 정상 동작하는 기준 코드는 샘플 1개마다 아래 경로를 사용한다.
nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_XFER_RX(buf, len);
nrfx_spim_xfer(&echo_spim, &xfer, 0);
그리고 echo_adc_init()에서는 CS 핀을 SPIM의 hardware SS 핀으로 넘긴다.
nrfx_spim_config_t config = NRFX_SPIM_DEFAULT_CONFIG(
gpio_abs_pin(&echo_sclk),
NRF_SPIM_PIN_NOT_CONNECTED,
gpio_abs_pin(&echo_miso),
gpio_abs_pin(&echo_cs));
실패한 실험 뒤에는 이 정상 동작 기준으로 원복했다.
실패 실험 1: SPIM SS를 끊고 CS를 GPIO로 수동 제어
echo_adc_init()에서 SPIM이 CS 핀을 소유하지 않도록 바꿨다.
NRF_SPIM_PIN_NOT_CONNECTED
즉 원래 있던 아래 설정을 제거했다.
gpio_abs_pin(&echo_cs)
그 뒤 CS를 GPIO 출력으로 직접 설정하고, nrfx_spim_xfer()와 direct capture loop 양쪽에서 수동으로 CS를 내리고 올렸다.
cs_port->OUTCLR = cs_mask;
nrfx_spim_xfer(&echo_spim, &xfer, 0);
cs_port->OUTSET = cs_mask;
캡처 루프도 아래처럼 SPIM 레지스터 직접 접근 방식으로 바꿨다.
spim->RXD.MAXCNT = 2U;
for (...) {
cs_port->OUTCLR = cs_mask;
spim->RXD.PTR = (uint32_t)&raw_capture[i * 2U];
spim->EVENTS_END = 0;
spim->TASKS_START = 1;
while (!spim->EVENTS_END) {
}
cs_port->OUTSET = cs_mask;
}
결과/위험:
- ADC 데이터가 전부 0으로 나올 수 있다.
- 가능한 원인은 CS/SPIM 소유권 불일치, RX-only direct start가
nrfx_spim_xfer()와 다르게 동작하는 문제, 또는 nrfx가 내부적으로 준비하던 SPIM 상태가 빠진 문제다. - 이 단순한 "SS 끊기 + direct loop" 패치는 그대로 쓰면 안 된다.
실패 실험 2: Hardware SS를 유지한 채 같은 CS를 수동 토글
echo_cs는 계속 SPIM hardware SS 핀으로 설정해둔 상태에서, echo_adc_capture() 내부만 direct register loop로 바꿨다.
예시:
NRF_SPIM_Type *spim = echo_spim.p_reg;
uint32_t cs_mask = BIT(echo_cs.pin);
spim->RXD.MAXCNT = 2U;
for (...) {
NRF_P0->OUTCLR = cs_mask;
spim->RXD.PTR = (uint32_t)&raw_capture[i * 2U];
spim->EVENTS_END = 0;
spim->TASKS_START = 1;
while (!spim->EVENTS_END) {
}
NRF_P0->OUTSET = cs_mask;
}
결과/위험:
- 이 경우도 ADC 데이터가 전부 0으로 나올 수 있다.
- 이유는 hardware SS가 켜진 상태에서 펌웨어가 같은 CS 핀을 직접
NRF_P0->OUTCLR/OUTSET으로 건드리기 때문이다. - 즉 SPIM hardware SS 제어와 수동 GPIO CS 제어가 같은 핀에서 겹쳐 ADC 프레임 타이밍이 깨질 수 있다.
- hardware SS를 켠 상태에서 같은 CS 핀을 수동으로 토글하면 안 된다.
핵심 정리
레퍼런스 펌웨어의 direct SPIM loop를 이 Zephyr/nrfx 포팅 코드에 내부 루프만 바꿔서 그대로 넣으면 안 된다.
더 빠른 캡처 경로가 필요하면, 아래를 포함한 별도 low-level SPIM 경로로 제대로 구성해야 한다.
- CS 소유권을 명확히 정하기: hardware SS 또는 manual GPIO 중 하나만 사용
- SPIM PSEL 상태 확인
- SCLK 생성을 보장하기 위한 RXD/TXD 설정 확인
RXD.MAXCNT = 2EVENTS_END클리어 및 polling- CS 타이밍 검증
그 전까지는 정상 동작이 확인된 nrfx_spim_xfer() 경로를 유지한다.