주석 추가
This commit is contained in:
@@ -18,30 +18,32 @@
|
||||
#define ECHO_MISO_NODE DT_NODELABEL(echo_miso)
|
||||
#define ECHO_CS_NODE DT_NODELABEL(echo_cs)
|
||||
|
||||
/* ADC SPI 핀 */
|
||||
static const struct gpio_dt_spec echo_sclk = GPIO_DT_SPEC_GET(ECHO_SCLK_NODE, gpios);
|
||||
static const struct gpio_dt_spec echo_miso = GPIO_DT_SPEC_GET(ECHO_MISO_NODE, gpios);
|
||||
static const struct gpio_dt_spec echo_cs = GPIO_DT_SPEC_GET(ECHO_CS_NODE, gpios);
|
||||
|
||||
/*
|
||||
* NRFX_SPIM_INSTANCE() takes the peripheral register symbol (for example
|
||||
* NRF_SPIM3), not a numeric instance index. Passing 3 makes p_reg invalid
|
||||
* and causes a fault inside nrfx_spim_init().
|
||||
*/
|
||||
/* SPIM3 레지스터 인스턴스 */
|
||||
static nrfx_spim_t echo_spim = NRFX_SPIM_INSTANCE(NRF_SPIM3);
|
||||
static bool echo_adc_initialized;
|
||||
|
||||
/* ADC 원본 수신 버퍼 */
|
||||
static uint8_t raw_capture[ECHO_ADC_MAX_SAMPLES * 2];
|
||||
|
||||
/* GPIO 포트 레지스터 선택 */
|
||||
static NRF_GPIO_Type *gpio_reg_for_spec(const struct gpio_dt_spec *spec)
|
||||
{
|
||||
return (spec->port == DEVICE_DT_GET(DT_NODELABEL(gpio1))) ? NRF_P1 : NRF_P0;
|
||||
}
|
||||
|
||||
/* 포트 포함 절대 핀 번호 */
|
||||
static uint32_t gpio_abs_pin(const struct gpio_dt_spec *spec)
|
||||
{
|
||||
uint32_t port = (spec->port == DEVICE_DT_GET(DT_NODELABEL(gpio1))) ? 1U : 0U;
|
||||
return NRF_GPIO_PIN_MAP(port, spec->pin);
|
||||
}
|
||||
|
||||
/* SPIM RX 전송 */
|
||||
static int echo_adc_transfer_rx(uint8_t *buf, size_t len)
|
||||
{
|
||||
nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_XFER_RX(buf, len);
|
||||
@@ -56,6 +58,7 @@ static int echo_adc_transfer_rx(uint8_t *buf, size_t len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 12비트 샘플 추출 */
|
||||
static void echo_adc_unpack_samples(uint16_t *samples, uint16_t num_samples)
|
||||
{
|
||||
for (uint16_t i = 0; i < num_samples; i++)
|
||||
@@ -66,6 +69,7 @@ static void echo_adc_unpack_samples(uint16_t *samples, uint16_t num_samples)
|
||||
}
|
||||
}
|
||||
|
||||
/* 무응답 샘플 확인 */
|
||||
static bool echo_adc_samples_all_zero(const uint16_t *samples, uint16_t num_samples)
|
||||
{
|
||||
for (uint16_t i = 0; i < num_samples; i++)
|
||||
@@ -79,6 +83,7 @@ static bool echo_adc_samples_all_zero(const uint16_t *samples, uint16_t num_samp
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 안정 우선 캡처 */
|
||||
static int echo_adc_capture_slow(uint16_t *samples, uint16_t num_samples)
|
||||
{
|
||||
for (uint16_t i = 0; i < num_samples; i++)
|
||||
@@ -94,28 +99,33 @@ static int echo_adc_capture_slow(uint16_t *samples, uint16_t num_samples)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 속도 우선 캡처 */
|
||||
static int echo_adc_capture_fast(uint16_t *samples, uint16_t num_samples)
|
||||
{
|
||||
NRF_SPIM_Type *spim = echo_spim.p_reg;
|
||||
NRF_GPIO_Type *cs_port = gpio_reg_for_spec(&echo_cs);
|
||||
uint32_t cs_mask = BIT(echo_cs.pin);
|
||||
|
||||
/* SPIM 직접 제어 */
|
||||
nrf_spim_enable(spim);
|
||||
spim->RXD.MAXCNT = 2U;
|
||||
|
||||
for (uint16_t i = 0; i < num_samples; i++)
|
||||
{
|
||||
/* CS 하강 후 2바이트 수신 */
|
||||
cs_port->OUTCLR = cs_mask;
|
||||
spim->RXD.PTR = (uint32_t)&raw_capture[i * 2U];
|
||||
spim->EVENTS_END = 0;
|
||||
spim->TASKS_START = 1;
|
||||
|
||||
/* 전송 완료 대기 */
|
||||
uint32_t timeout = 10000U;
|
||||
while (!spim->EVENTS_END && (timeout > 0U))
|
||||
{
|
||||
timeout--;
|
||||
}
|
||||
|
||||
/* CS 복귀 */
|
||||
cs_port->OUTSET = cs_mask;
|
||||
|
||||
if (timeout == 0U)
|
||||
@@ -131,12 +141,14 @@ static int echo_adc_capture_fast(uint16_t *samples, uint16_t num_samples)
|
||||
|
||||
int echo_adc_init(void)
|
||||
{
|
||||
/* 중복 초기화 방지 */
|
||||
if (echo_adc_initialized || nrfx_spim_init_check(&echo_spim))
|
||||
{
|
||||
echo_adc_initialized = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* GPIO 준비 확인 */
|
||||
const struct gpio_dt_spec *pins[] = { &echo_sclk, &echo_miso, &echo_cs };
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(pins); i++)
|
||||
@@ -148,6 +160,7 @@ int echo_adc_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* ADC SPI 설정 */
|
||||
nrfx_spim_config_t config = NRFX_SPIM_DEFAULT_CONFIG(
|
||||
gpio_abs_pin(&echo_sclk),
|
||||
NRF_SPIM_PIN_NOT_CONNECTED,
|
||||
@@ -162,7 +175,7 @@ int echo_adc_init(void)
|
||||
config.ss_active_high = false;
|
||||
|
||||
nrfx_err_t err = nrfx_spim_init(&echo_spim, &config, NULL, NULL);
|
||||
if (err != NRFX_SUCCESS)
|
||||
if (err != 0)
|
||||
{
|
||||
DBG_PRINTF("[ECHO] init fail err=%d\r\n", err);
|
||||
return -EIO;
|
||||
@@ -175,6 +188,7 @@ int echo_adc_init(void)
|
||||
|
||||
int echo_adc_wake(void)
|
||||
{
|
||||
/* 더미 읽기 웨이크업 */
|
||||
int err = echo_adc_init();
|
||||
if (err)
|
||||
{
|
||||
@@ -187,6 +201,7 @@ int echo_adc_wake(void)
|
||||
|
||||
int echo_adc_capture(uint16_t *samples, uint16_t num_samples)
|
||||
{
|
||||
/* 입력값 검사 */
|
||||
if (samples == NULL)
|
||||
{
|
||||
return -EINVAL;
|
||||
@@ -203,12 +218,14 @@ int echo_adc_capture(uint16_t *samples, uint16_t num_samples)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* 빠른 캡처 우선 */
|
||||
err = echo_adc_capture_fast(samples, num_samples);
|
||||
if ((err == 0) && !echo_adc_samples_all_zero(samples, num_samples))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 실패 시 안정 캡처 */
|
||||
DBG_PRINTF("[ECHO] fast capture fallback err=%d\r\n", err);
|
||||
return echo_adc_capture_slow(samples, num_samples);
|
||||
}
|
||||
|
||||
@@ -23,16 +23,20 @@
|
||||
#define MUX_SEL0_NODE DT_NODELABEL(mux_sel0)
|
||||
#define MUX_SEL1_NODE DT_NODELABEL(mux_sel1)
|
||||
|
||||
/* 피에조 전원/구동 GPIO */
|
||||
static const struct gpio_dt_spec piezo_pwr = GPIO_DT_SPEC_GET(PIEZO_PWR_NODE, gpios);
|
||||
static const struct gpio_dt_spec piezo_pe = GPIO_DT_SPEC_GET(PIEZO_PE_NODE, gpios);
|
||||
static const struct gpio_dt_spec piezo_p_out = GPIO_DT_SPEC_GET(PIEZO_P_OUT_NODE, gpios);
|
||||
static const struct gpio_dt_spec piezo_n_out = GPIO_DT_SPEC_GET(PIEZO_N_OUT_NODE, gpios);
|
||||
static const struct gpio_dt_spec piezo_dmp = GPIO_DT_SPEC_GET(PIEZO_DMP_NODE, gpios);
|
||||
|
||||
/* 채널 선택 MUX GPIO */
|
||||
static const struct gpio_dt_spec mux_en_a = GPIO_DT_SPEC_GET(MUX_EN_A_NODE, gpios);
|
||||
static const struct gpio_dt_spec mux_en_b = GPIO_DT_SPEC_GET(MUX_EN_B_NODE, gpios);
|
||||
static const struct gpio_dt_spec mux_sel0 = GPIO_DT_SPEC_GET(MUX_SEL0_NODE, gpios);
|
||||
static const struct gpio_dt_spec mux_sel1 = GPIO_DT_SPEC_GET(MUX_SEL1_NODE, gpios);
|
||||
|
||||
/* MUX 제어 상태 */
|
||||
struct mux_state {
|
||||
uint8_t en_a;
|
||||
uint8_t en_b;
|
||||
@@ -40,6 +44,7 @@ struct mux_state {
|
||||
uint8_t sel1;
|
||||
};
|
||||
|
||||
/* 채널별 MUX EN/SEL 조합 */
|
||||
static const struct mux_state mux_map[PIEZO_NUM_CHANNELS] = {
|
||||
{1, 0, 0, 0},
|
||||
{1, 0, 1, 0},
|
||||
@@ -50,26 +55,33 @@ static const struct mux_state mux_map[PIEZO_NUM_CHANNELS] = {
|
||||
};
|
||||
|
||||
static bool piezo_initialized;
|
||||
|
||||
/* 빠른 GPIO 제어용 절대 핀 */
|
||||
static uint32_t piezo_pe_abs;
|
||||
static uint32_t piezo_p_out_abs;
|
||||
static uint32_t piezo_n_out_abs;
|
||||
static uint32_t piezo_dmp_abs;
|
||||
|
||||
/* 포트 OUT 직접 갱신용 비트 마스크 */
|
||||
static uint32_t piezo_pe_mask;
|
||||
static uint32_t piezo_p_out_mask;
|
||||
static uint32_t piezo_n_out_mask;
|
||||
static uint32_t piezo_dmp_mask;
|
||||
|
||||
/* 포트 포함 절대 핀 번호 */
|
||||
static uint32_t gpio_abs_pin(const struct gpio_dt_spec *spec)
|
||||
{
|
||||
uint32_t port = (spec->port == DEVICE_DT_GET(DT_NODELABEL(gpio1))) ? 1U : 0U;
|
||||
return NRF_GPIO_PIN_MAP(port, spec->pin);
|
||||
}
|
||||
|
||||
/* 버스트 타이밍용 1사이클 지연 */
|
||||
static inline void burst_nop(void)
|
||||
{
|
||||
__asm__ volatile("nop");
|
||||
}
|
||||
|
||||
/* 짧은 반주기 보정 지연 */
|
||||
static inline void nop_delay_9(void)
|
||||
{
|
||||
burst_nop(); burst_nop(); burst_nop();
|
||||
@@ -77,6 +89,7 @@ static inline void nop_delay_9(void)
|
||||
burst_nop(); burst_nop(); burst_nop();
|
||||
}
|
||||
|
||||
/* 긴 반주기 보정 지연 */
|
||||
static inline void nop_delay_14(void)
|
||||
{
|
||||
burst_nop(); burst_nop(); burst_nop(); burst_nop();
|
||||
@@ -85,6 +98,7 @@ static inline void nop_delay_14(void)
|
||||
burst_nop(); burst_nop();
|
||||
}
|
||||
|
||||
/* 댐핑 펄스 폭 지연 */
|
||||
static inline void nop_delay_32(void)
|
||||
{
|
||||
for (int i = 0; i < 32; i++)
|
||||
@@ -93,6 +107,7 @@ static inline void nop_delay_32(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* 출력/MUX 안전 대기 상태 */
|
||||
static void piezo_drive_idle(void)
|
||||
{
|
||||
nrf_gpio_pin_clear(piezo_pe_abs);
|
||||
@@ -108,11 +123,13 @@ static void piezo_drive_idle(void)
|
||||
|
||||
int piezo_init(void)
|
||||
{
|
||||
/* 중복 초기화 방지 */
|
||||
if (piezo_initialized)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 모든 제어 핀 목록 */
|
||||
const struct gpio_dt_spec *pins[] =
|
||||
{
|
||||
&piezo_pwr, &piezo_pe, &piezo_p_out, &piezo_n_out,
|
||||
@@ -121,12 +138,14 @@ int piezo_init(void)
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(pins); i++)
|
||||
{
|
||||
/* GPIO 포트 준비 확인 */
|
||||
if (!device_is_ready(pins[i]->port))
|
||||
{
|
||||
DBG_PRINTF("[PIEZO] GPIO device not ready (%d)\r\n", (int)i);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* 초기 출력 Low */
|
||||
int err = gpio_pin_configure_dt(pins[i], GPIO_OUTPUT_INACTIVE);
|
||||
if (err)
|
||||
{
|
||||
@@ -135,6 +154,7 @@ int piezo_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* 직접 제어용 핀/마스크 캐시 */
|
||||
piezo_pe_abs = gpio_abs_pin(&piezo_pe);
|
||||
piezo_p_out_abs = gpio_abs_pin(&piezo_p_out);
|
||||
piezo_n_out_abs = gpio_abs_pin(&piezo_n_out);
|
||||
@@ -152,27 +172,32 @@ int piezo_init(void)
|
||||
|
||||
void piezo_power_on(void)
|
||||
{
|
||||
/* 필요 시 자동 초기화 */
|
||||
if (!piezo_initialized && piezo_init() != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* 피에조 전원 인가 */
|
||||
gpio_pin_set_dt(&piezo_pwr, 1);
|
||||
}
|
||||
|
||||
void piezo_power_off(void)
|
||||
{
|
||||
/* 필요 시 자동 초기화 */
|
||||
if (!piezo_initialized && piezo_init() != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* 출력 정지 후 전원 차단 */
|
||||
piezo_drive_idle();
|
||||
gpio_pin_set_dt(&piezo_pwr, 0);
|
||||
}
|
||||
|
||||
int piezo_select_channel(uint8_t channel)
|
||||
{
|
||||
/* 필요 시 자동 초기화 */
|
||||
if (!piezo_initialized)
|
||||
{
|
||||
int err = piezo_init();
|
||||
@@ -182,28 +207,35 @@ int piezo_select_channel(uint8_t channel)
|
||||
}
|
||||
}
|
||||
|
||||
/* 채널 범위 검사 */
|
||||
if (channel >= PIEZO_NUM_CHANNELS)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* MUX 채널 선택 */
|
||||
gpio_pin_set_dt(&mux_en_a, mux_map[channel].en_a);
|
||||
gpio_pin_set_dt(&mux_en_b, mux_map[channel].en_b);
|
||||
gpio_pin_set_dt(&mux_sel0, mux_map[channel].sel0);
|
||||
gpio_pin_set_dt(&mux_sel1, mux_map[channel].sel1);
|
||||
|
||||
/* MUX 안정화 대기 */
|
||||
k_busy_wait(PIEZO_MUX_SETTLE_US);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void piezo_burst_sw(uint8_t cycles)
|
||||
{
|
||||
/* 초기화/횟수 검사 */
|
||||
if (!piezo_initialized || cycles == 0U)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* 타이밍 흔들림 방지 */
|
||||
unsigned int key = irq_lock();
|
||||
|
||||
/* P1 비제어 핀 상태 보존 */
|
||||
uint32_t saved_p1_out = NRF_P1->OUT;
|
||||
uint32_t p1_ctrl_mask = piezo_p_out_mask | piezo_n_out_mask | piezo_dmp_mask;
|
||||
uint32_t p1_all_low = saved_p1_out & ~p1_ctrl_mask;
|
||||
@@ -211,21 +243,27 @@ void piezo_burst_sw(uint8_t cycles)
|
||||
uint32_t p1_p_low_n_high = p1_all_low | piezo_n_out_mask;
|
||||
uint32_t p1_dmp_high = p1_all_low | piezo_dmp_mask;
|
||||
|
||||
/* 구동 Enable 전 초기 Low 정렬 */
|
||||
NRF_P0->OUTCLR = piezo_pe_mask;
|
||||
NRF_P1->OUT = p1_all_low;
|
||||
NRF_P0->OUTSET = piezo_pe_mask;
|
||||
|
||||
for (uint8_t i = 0; i < cycles; i++)
|
||||
{
|
||||
/* P High / N Low */
|
||||
NRF_P1->OUT = p1_p_high_n_low;
|
||||
nop_delay_14();
|
||||
|
||||
/* P Low / N High */
|
||||
NRF_P1->OUT = p1_p_low_n_high;
|
||||
nop_delay_9();
|
||||
}
|
||||
|
||||
/* 잔류 전하 방전 */
|
||||
NRF_P1->OUT = p1_dmp_high;
|
||||
nop_delay_32();
|
||||
|
||||
/* 출력 Low 복귀 */
|
||||
NRF_P1->OUT = p1_all_low;
|
||||
NRF_P0->OUTCLR = piezo_pe_mask;
|
||||
irq_unlock(key);
|
||||
|
||||
Reference in New Issue
Block a user