maa samples 140->100 변경, mec/maa 수신 시 Piezo 자동 Active/Sleep
- MAA_NUM_SAMPLES 140에서 100으로 변경 (DR_ADC_ECHO_SAMPLES_MAX 제한) - 단일(mec) 및 모든 채널(maa) 에코 캡처 명령 수신 시 Piezo 자동 Active, 응답 송신 후 Sleep - Cmd_mpa 중복 호출 정리 (dr_piezo_system_init 내부에 power_on 포함) - 채널별 디버그 로그 추가 - 코드 리뷰 주석 정리 및 기타 파일 업데이트 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,35 +3,88 @@
|
||||
* @brief Piezo Transducer Driver (2MHz Signal Generator)
|
||||
* @author Charles KWON
|
||||
* @date 2025-12-09
|
||||
*
|
||||
*
|
||||
* @details Uses Timer2 + GPIOTE + PPI for CPU-free 2MHz waveform generation
|
||||
*
|
||||
*
|
||||
* Timing Diagram (???):
|
||||
*
|
||||
*
|
||||
* |<----------- PE HIGH ----------->|
|
||||
* PE ___/?????????????????????????????????\___
|
||||
* P_OUT ___/?\_/?\_/?\_/?\_/?\________________\___
|
||||
* N_OUT ___\_/?\_/?\_/?\_/?\_/________________\___
|
||||
* DMP _________________________/?????\_________
|
||||
* |<-- 3~5 cycles -->| |<DMP>|
|
||||
*
|
||||
*
|
||||
* P_OUT? N_OUT? ?? ?? ?? (???)
|
||||
*
|
||||
*
|
||||
* 2MHz = 500ns period = 250ns half-period
|
||||
* Timer @ 16MHz: 1 tick = 62.5ns
|
||||
* Half-period = 250ns = 4 ticks
|
||||
* Full-period = 500ns = 8 ticks
|
||||
******************************************************************************/
|
||||
|
||||
#include "dr_piezo.h"
|
||||
#include "nrf_gpio.h"
|
||||
#include "nrf_timer.h"
|
||||
#include "nrf_gpiote.h"
|
||||
#include "nrf_ppi.h"
|
||||
#include "nrf_delay.h"
|
||||
#include "power_control.h"
|
||||
#include "app_util_platform.h"
|
||||
/*******************************************************************************
|
||||
* [한국어 설명] 피에조 초음파 트랜스듀서 드라이버
|
||||
*
|
||||
* === 개요 ===
|
||||
* 방광 측정용 2MHz 초음파 송신 신호를 생성하는 드라이버.
|
||||
* nRF52840의 하드웨어 주변장치(Timer2 + GPIOTE + PPI)를 활용하여
|
||||
* CPU 개입 없이 정밀한 2MHz 파형을 자동으로 생성한다.
|
||||
*
|
||||
* === 초음파 TX 시퀀스 ===
|
||||
* 1단계: PE(Pulse Enable) = HIGH -> MOSFET 드라이버 활성화
|
||||
* 2단계: P_OUT/N_OUT 교번 펄스 생성 (2MHz, 3~7 사이클)
|
||||
* - P_OUT과 N_OUT은 역상(반대 위상)으로 동작
|
||||
* - 피에조 소자 양단에 +/-20V 교번 전압 인가
|
||||
* 3단계: DMP(Dump) = HIGH -> 펄스 완료 후 피에조에 남은 잔류 에너지 방전
|
||||
* 4단계: DMP = LOW -> 방전 완료
|
||||
* 5단계: PE = LOW -> MOSFET 드라이버 비활성화, 유휴 상태 복귀
|
||||
*
|
||||
* === 하드웨어 아키텍처 ===
|
||||
* [Timer2] --- CC[0](반주기=4틱) ---> [PPI CH8,9] ---> [GPIOTE CH4,5] -> P_OUT/N_OUT 토글
|
||||
* |-- CC[1](전체주기=8틱) --> [PPI CH10,11] --> [GPIOTE CH4,5] -> P_OUT/N_OUT 토글
|
||||
* |-- CC[2](전체주기=8틱) --> 타이머 자동 클리어 + 인터럽트(잔여 사이클 카운트)
|
||||
*
|
||||
* - Timer2: 16MHz 클럭, 16비트 모드
|
||||
* - CC[0] = 4틱(250ns) -> 반주기 시점에서 P_OUT/N_OUT 토글
|
||||
* - CC[1] = 8틱(500ns) -> 전체주기 시점에서 P_OUT/N_OUT 토글
|
||||
* - CC[2] = 8틱(500ns) -> 인터럽트 발생 + 타이머 자동 클리어(SHORT)
|
||||
*
|
||||
* - GPIOTE CH4: P_OUT 핀 토글 모드
|
||||
* - GPIOTE CH5: N_OUT 핀 토글 모드
|
||||
*
|
||||
* - PPI CH8: CC[0] 이벤트 -> P_OUT 토글 태스크
|
||||
* - PPI CH9: CC[0] 이벤트 -> N_OUT 토글 태스크
|
||||
* - PPI CH10: CC[1] 이벤트 -> P_OUT 토글 태스크
|
||||
* - PPI CH11: CC[1] 이벤트 -> N_OUT 토글 태스크
|
||||
*
|
||||
* === 전원 ===
|
||||
* DR_PIEZO_PWR_EN(P1.9) -> DC/DC 컨버터 활성화 -> +/-20V 고전압 생성
|
||||
*
|
||||
* === 소프트웨어 버스트 모드 (dr_piezo_burst_sw 계열) ===
|
||||
* Timer/PPI 대신 CPU에서 직접 GPIO를 제어하는 방식.
|
||||
* 인터럽트를 비활성화(__disable_irq)하고 NOP 명령어로 정밀 타이밍 생성.
|
||||
* 포트 레지스터(NRF_P1->OUT)에 직접 접근하여 여러 핀을 동시에 제어.
|
||||
* 주파수별(1.7/1.8/1.9/2.0/2.1/2.2 MHz) NOP 개수가 다름.
|
||||
*
|
||||
* NOP 타이밍 계산법:
|
||||
* CPU 클럭 64MHz -> 1 NOP = 15.625ns
|
||||
* 목표 반주기(ns) = 1,000,000 / (목표주파수MHz * 2)
|
||||
* 필요 NOP 수 = (목표 반주기 - 레지스터 쓰기 시간(~30ns)) / 15.625
|
||||
* 루프 오버헤드(~47ns = 3 NOP)는 두 번째 반주기에서 차감
|
||||
******************************************************************************/
|
||||
|
||||
/* 헤더 포함 */
|
||||
#include "dr_piezo.h"
|
||||
#include "nrf_gpio.h" /* GPIO 제어 (핀 설정, 출력) */
|
||||
#include "nrf_timer.h" /* 타이머 주변장치 제어 */
|
||||
#include "nrf_gpiote.h" /* GPIOTE (GPIO Tasks and Events) 제어 */
|
||||
#include "nrf_ppi.h" /* PPI (Programmable Peripheral Interconnect) 제어 */
|
||||
#include "nrf_delay.h" /* 지연(딜레이) 함수 */
|
||||
#include "power_control.h" /* 전원 관리 */
|
||||
#include "app_util_platform.h" /* 인터럽트 우선순위 등 플랫폼 유틸리티 */
|
||||
|
||||
/* 조건부 디버그 출력: FEATURE_PRINTF 정의 시 SEGGER RTT로 출력 */
|
||||
#ifdef FEATURE_PRINTF
|
||||
#include "debug_print.h"
|
||||
#else
|
||||
@@ -39,62 +92,76 @@
|
||||
#endif
|
||||
|
||||
/*==============================================================================
|
||||
* HARDWARE RESOURCE ALLOCATION
|
||||
* 하드웨어 리소스 할당
|
||||
* - Timer2: 2MHz 파형 생성의 시간 기준 (16MHz 클럭)
|
||||
* - GPIOTE CH4/5: P_OUT/N_OUT 핀의 하드웨어 토글
|
||||
* - PPI CH8~11: 타이머 비교 이벤트 -> GPIOTE 토글 태스크 자동 연결
|
||||
*============================================================================*/
|
||||
#define PIEZO_TIMER NRF_TIMER2
|
||||
#define PIEZO_TIMER_IRQn TIMER2_IRQn
|
||||
#define PIEZO_TIMER_IRQ_PRIORITY 6
|
||||
#define PIEZO_TIMER NRF_TIMER2 /* 사용할 타이머 인스턴스 */
|
||||
#define PIEZO_TIMER_IRQn TIMER2_IRQn /* 타이머2 인터럽트 번호 */
|
||||
#define PIEZO_TIMER_IRQ_PRIORITY 6 /* 인터럽트 우선순위 (6 = 중간) */
|
||||
|
||||
/* GPIOTE channels */
|
||||
#define GPIOTE_CH_P_OUT 4
|
||||
#define GPIOTE_CH_N_OUT 5
|
||||
/* GPIOTE 채널 할당 - 핀 토글 제어용 */
|
||||
#define GPIOTE_CH_P_OUT 4 /* P_OUT(양극 출력) 토글용 GPIOTE 채널 */
|
||||
#define GPIOTE_CH_N_OUT 5 /* N_OUT(음극 출력) 토글용 GPIOTE 채널 */
|
||||
|
||||
/* PPI channels */
|
||||
#define PPI_CH_P_OUT_TOGGLE_0 8
|
||||
#define PPI_CH_N_OUT_TOGGLE_0 9
|
||||
#define PPI_CH_P_OUT_TOGGLE_1 10
|
||||
#define PPI_CH_N_OUT_TOGGLE_1 11
|
||||
/* PPI 채널 할당 - 타이머 이벤트 -> GPIOTE 태스크 연결 */
|
||||
#define PPI_CH_P_OUT_TOGGLE_0 8 /* CC[0](반주기) -> P_OUT 토글 */
|
||||
#define PPI_CH_N_OUT_TOGGLE_0 9 /* CC[0](반주기) -> N_OUT 토글 */
|
||||
#define PPI_CH_P_OUT_TOGGLE_1 10 /* CC[1](전체주기) -> P_OUT 토글 */
|
||||
#define PPI_CH_N_OUT_TOGGLE_1 11 /* CC[1](전체주기) -> N_OUT 토글 */
|
||||
|
||||
/*==============================================================================
|
||||
* TIMING CONSTANTS
|
||||
* 타이밍 상수
|
||||
* Timer2 클럭: 16MHz -> 1틱 = 62.5ns
|
||||
* 2MHz 신호: 주기 500ns(8틱), 반주기 250ns(4틱)
|
||||
*============================================================================*/
|
||||
#define TIMER_FREQ_MHZ 16
|
||||
#define TICK_NS (1000 / TIMER_FREQ_MHZ) /* 62.5ns */
|
||||
#define TIMER_FREQ_MHZ 16 /* 타이머 클럭 주파수 (MHz) */
|
||||
#define TICK_NS (1000 / TIMER_FREQ_MHZ) /* 1틱 = 62.5ns */
|
||||
|
||||
/* 2MHz: period = 500ns, half = 250ns */
|
||||
#define PERIOD_TICKS_2MHZ 8 /* 500ns / 62.5ns = 8 */
|
||||
#define HALF_PERIOD_TICKS 4 /* 250ns / 62.5ns = 4 */
|
||||
/* 2MHz 기준 타이밍: 주기 = 500ns, 반주기 = 250ns */
|
||||
#define PERIOD_TICKS_2MHZ 8 /* 전체 주기: 500ns / 62.5ns = 8틱 */
|
||||
#define HALF_PERIOD_TICKS 4 /* 반주기: 250ns / 62.5ns = 4틱 */
|
||||
|
||||
/*==============================================================================
|
||||
* PIEZO OPERATING FREQUENCY CONFIGURATION
|
||||
* 피에조 동작 주파수 설정
|
||||
*============================================================================*/
|
||||
/*
|
||||
* Target piezo frequency: 1.8 MHz
|
||||
* 목표 피에조 주파수: 2.1 MHz (하드웨어 버스트 모드용)
|
||||
*
|
||||
* Timing (hardcoded in dr_piezo_burst_sw for stability):
|
||||
* 1.8 MHz: 556ns period, 278ns half-period
|
||||
* At 64MHz CPU (1 NOP = 15.625ns):
|
||||
* First half: 15 NOPs (~234ns)
|
||||
* Second half: 12 NOPs (~188ns) + loop overhead
|
||||
* 소프트웨어 버스트 모드의 타이밍은 각 주파수별 함수에 NOP 개수로 하드코딩됨.
|
||||
* 안정적인 파형 생성을 위해 컴파일 타임에 고정.
|
||||
*
|
||||
* To change frequency, modify the NOP counts in dr_piezo_burst_sw():
|
||||
* 2.0 MHz: First=14, Second=11
|
||||
* 2.1 MHz: First=13, Second=10
|
||||
* 1.5 MHz: First=18, Second=15
|
||||
* NOP 기반 타이밍 계산 (CPU 64MHz, 1 NOP = 15.625ns):
|
||||
* 1.7 MHz: 반주기 294ns -> 첫 반주기 18 NOP, 둘째 반주기 10 NOP + 루프 오버헤드
|
||||
* 1.8 MHz: 반주기 278ns -> 첫 반주기 17 NOP, 둘째 반주기 11 NOP + 루프 오버헤드
|
||||
* 1.9 MHz: 반주기 263ns -> 첫 반주기 15 NOP, 둘째 반주기 9 NOP + 루프 오버헤드
|
||||
* 2.0 MHz: 반주기 250ns -> 첫 반주기 15 NOP, 둘째 반주기 10 NOP + 루프 오버헤드
|
||||
* 2.1 MHz: 반주기 238ns -> 첫 반주기 14 NOP, 둘째 반주기 9 NOP + 루프 오버헤드
|
||||
* 2.2 MHz: 반주기 227ns -> 첫 반주기 13 NOP, 둘째 반주기 8 NOP + 루프 오버헤드
|
||||
*
|
||||
* 주파수를 변경하려면 dr_piezo_burst_sw_XXmhz() 함수의 NOP 수를 수정할 것.
|
||||
*/
|
||||
#define PIEZO_FREQ_MHZ 2.1f
|
||||
#define PIEZO_FREQ_MHZ 2.1f /* 기본 동작 주파수 (MHz) */
|
||||
|
||||
/*==============================================================================
|
||||
* STATIC VARIABLES
|
||||
* 정적 변수
|
||||
*============================================================================*/
|
||||
static volatile bool m_tx_active = false;
|
||||
static volatile uint8_t m_remaining_cycles = 0;
|
||||
static uint32_t m_period_ticks = PERIOD_TICKS_2MHZ;
|
||||
static bool m_power_enabled = false;
|
||||
static bool m_initialized = false;
|
||||
static volatile bool m_tx_active = false; /* TX 송신 중 플래그 (인터럽트에서 변경) */
|
||||
static volatile uint8_t m_remaining_cycles = 0; /* 남은 펄스 사이클 수 (인터럽트에서 감소) */
|
||||
static uint32_t m_period_ticks = PERIOD_TICKS_2MHZ; /* 현재 주기 (타이머 틱 단위) */
|
||||
static bool m_power_enabled = false; /* DC/DC 컨버터 전원 상태 */
|
||||
static bool m_initialized = false; /* 드라이버 초기화 완료 여부 */
|
||||
|
||||
/*==============================================================================
|
||||
* INTERRUPT HANDLER
|
||||
* 타이머2 인터럽트 핸들러
|
||||
* 매 주기(CC[2])마다 호출되어 잔여 사이클을 감소시킨다.
|
||||
* 잔여 사이클이 0이 되면:
|
||||
* 1) 타이머 정지 및 클리어
|
||||
* 2) GPIOTE 비활성화 (P_OUT/N_OUT 토글 중단)
|
||||
* 3) GPIO를 출력 모드로 재설정 후 LOW로 초기화
|
||||
* 4) DMP 펄스 발생 (피에조 잔류 에너지 방전)
|
||||
* 5) PE = LOW (MOSFET 드라이버 비활성화)
|
||||
*============================================================================*/
|
||||
void TIMER2_IRQHandler(void)
|
||||
{
|
||||
@@ -140,9 +207,12 @@ void TIMER2_IRQHandler(void)
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* POWER CONTROL FUNCTIONS
|
||||
* 전원 제어 함수
|
||||
* DC/DC 컨버터(±20V)를 ON/OFF하여 피에조 구동 전압을 제어한다.
|
||||
* 전원 안정화에 약 10ms 필요.
|
||||
*============================================================================*/
|
||||
|
||||
/* 피에조 전원 ON: DC/DC 컨버터 활성화 → ±20V 생성 */
|
||||
void dr_piezo_power_on(void)
|
||||
{
|
||||
nrf_delay_ms(20);
|
||||
@@ -158,6 +228,7 @@ void dr_piezo_power_on(void)
|
||||
DBG_PRINTF("[DR_PIEZO] Power ON: +/-20V ready\r\n");
|
||||
}
|
||||
|
||||
/* 피에조 전원 OFF: TX 비활성화 후 DC/DC 컨버터 차단 */
|
||||
void dr_piezo_power_off(void)
|
||||
{
|
||||
dr_piezo_disable();
|
||||
@@ -169,10 +240,17 @@ void dr_piezo_power_off(void)
|
||||
DBG_PRINTF("[DR_PIEZO] Power OFF\r\n");
|
||||
}
|
||||
|
||||
/* 피에조 전원 상태 확인 */
|
||||
bool dr_piezo_is_power_on(void)
|
||||
{
|
||||
return m_power_enabled;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* PRIVATE FUNCTIONS
|
||||
* 내부(private) 초기화 함수
|
||||
*============================================================================*/
|
||||
|
||||
/* GPIO 초기화: 모든 신호 핀을 출력 모드로 설정하고 LOW(유휴)로 초기화 */
|
||||
static void dr_piezo_gpio_init(void)
|
||||
{
|
||||
nrf_gpio_cfg_output(DR_PIEZO_PIN_PE);
|
||||
@@ -192,6 +270,7 @@ static void dr_piezo_gpio_init(void)
|
||||
DBG_PRINTF("[DR_PIEZO] GPIO init done\r\n");
|
||||
}
|
||||
|
||||
/* GPIOTE 초기화: P_OUT/N_OUT을 토글 모드로 설정 (PPI 연결 대상) */
|
||||
static void dr_piezo_gpiote_init(void)
|
||||
{
|
||||
/* P_OUT: Toggle mode, initial LOW */
|
||||
@@ -215,6 +294,12 @@ static void dr_piezo_gpiote_init(void)
|
||||
DBG_PRINTF("[DR_PIEZO] GPIOTE init done\r\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* 타이머 초기화: 16MHz 클럭, 16비트 모드
|
||||
* CC[0]=반주기(4틱): 반주기 시점 토글 이벤트
|
||||
* CC[1]=전체주기(8틱): 전체주기 시점 토글 이벤트
|
||||
* CC[2]=전체주기(8틱): 인터럽트 발생 + 타이머 자동 클리어(SHORT)
|
||||
*/
|
||||
static void dr_piezo_timer_init(void)
|
||||
{
|
||||
nrf_timer_task_trigger(PIEZO_TIMER, NRF_TIMER_TASK_STOP);
|
||||
@@ -258,6 +343,12 @@ static void dr_piezo_timer_init(void)
|
||||
DBG_PRINTF("[DR_PIEZO] Timer init done (period=%d ticks)\r\n", m_period_ticks);
|
||||
}
|
||||
|
||||
/*
|
||||
* PPI 초기화: 타이머 비교 이벤트 → GPIOTE 토글 태스크 연결 (4채널)
|
||||
* CC[0] 이벤트(반주기) → P_OUT 토글 + N_OUT 토글
|
||||
* CC[1] 이벤트(전체주기) → P_OUT 토글 + N_OUT 토글
|
||||
* 이로써 P_OUT과 N_OUT은 항상 역상으로 동작함.
|
||||
*/
|
||||
static void dr_piezo_ppi_init(void)
|
||||
{
|
||||
/*
|
||||
@@ -302,9 +393,10 @@ static void dr_piezo_ppi_init(void)
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* TX DRIVER FUNCTIONS
|
||||
* TX 드라이버 공개 함수
|
||||
*============================================================================*/
|
||||
|
||||
/* TX 드라이버 초기화: GPIO → GPIOTE → Timer → PPI 순서로 설정 */
|
||||
void dr_piezo_init(void)
|
||||
{
|
||||
DBG_PRINTF("[DR_PIEZO] Initializing TX driver...\r\n");
|
||||
@@ -321,6 +413,7 @@ void dr_piezo_init(void)
|
||||
DBG_PRINTF("[DR_PIEZO] TX driver ready (2MHz)\r\n");
|
||||
}
|
||||
|
||||
/* TX 드라이버 해제: 타이머 정지, PPI/GPIOTE 비활성화, 모든 핀 LOW */
|
||||
void dr_piezo_uninit(void)
|
||||
{
|
||||
nrf_timer_task_trigger(PIEZO_TIMER, NRF_TIMER_TASK_STOP);
|
||||
@@ -346,6 +439,13 @@ void dr_piezo_uninit(void)
|
||||
DBG_PRINTF("[DR_PIEZO] TX driver uninitialized\r\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* 하드웨어 기반 버스트 송신 (Timer + PPI + GPIOTE 사용)
|
||||
* 1) GPIOTE를 재설정: P_OUT=HIGH 시작, N_OUT=LOW 시작 (역상)
|
||||
* 2) PE = HIGH → MOSFET 드라이버 활성화
|
||||
* 3) 타이머 시작 → PPI가 자동으로 P_OUT/N_OUT 토글
|
||||
* 4) 인터럽트 핸들러에서 잔여 사이클 관리 및 종료 처리
|
||||
*/
|
||||
void dr_piezo_burst(uint8_t cycles)
|
||||
{
|
||||
if (m_tx_active)
|
||||
@@ -409,11 +509,13 @@ void dr_piezo_burst(uint8_t cycles)
|
||||
nrf_timer_task_trigger(PIEZO_TIMER, NRF_TIMER_TASK_START);
|
||||
}
|
||||
|
||||
/* 기본 사이클 수(5)로 버스트 송신 */
|
||||
void dr_piezo_pulse(void)
|
||||
{
|
||||
dr_piezo_burst(DR_PIEZO_DEFAULT_CYCLES);
|
||||
}
|
||||
|
||||
/* TX 출력 활성화: 수동으로 초기 상태 설정 (PE=HIGH, P_OUT=HIGH, N_OUT=LOW) */
|
||||
void dr_piezo_enable(void)
|
||||
{
|
||||
nrf_gpio_pin_set(DR_PIEZO_PIN_P_OUT);
|
||||
@@ -423,6 +525,7 @@ void dr_piezo_enable(void)
|
||||
DBG_PRINTF("[DR_PIEZO] TX enabled\r\n");
|
||||
}
|
||||
|
||||
/* TX 출력 비활성화: 모든 신호 핀 LOW로 복귀 (유휴 상태) */
|
||||
void dr_piezo_disable(void)
|
||||
{
|
||||
nrf_gpio_pin_clear(DR_PIEZO_PIN_DMP);
|
||||
@@ -432,11 +535,13 @@ void dr_piezo_disable(void)
|
||||
DBG_PRINTF("[DR_PIEZO] TX disabled\r\n");
|
||||
}
|
||||
|
||||
/* TX 송신 중 여부 확인 (인터럽트 핸들러에서 false로 전환) */
|
||||
bool dr_piezo_is_busy(void)
|
||||
{
|
||||
return m_tx_active;
|
||||
}
|
||||
|
||||
/* 동작 주파수 변경 (100kHz~4MHz): 타이머 CC 레지스터 재설정 */
|
||||
void dr_piezo_set_frequency(uint32_t freq_hz)
|
||||
{
|
||||
if (freq_hz < 100000 || freq_hz > 4000000)
|
||||
@@ -456,9 +561,14 @@ void dr_piezo_set_frequency(uint32_t freq_hz)
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* MUX CONTROL FUNCTION
|
||||
* MUX 제어 함수
|
||||
* 8채널 아날로그 MUX로 피에조 에코 신호 경로를 선택한다.
|
||||
* MUXA: CH0~CH3 담당, MUXB: CH4~CH7 담당
|
||||
* SEL0, SEL1: MUX 내부 채널 주소 선택
|
||||
* High Drive(H0H1) 모드: MUX IC의 빠른 스위칭을 위해 강한 출력 구동력 사용
|
||||
*============================================================================*/
|
||||
|
||||
/* MUX 제어 핀 초기화: 4개 핀 모두 High Drive 출력으로 설정, 기본값 LOW */
|
||||
void dr_piezo_mux_init(void)
|
||||
{
|
||||
/* Configure MUX control pins as outputs */
|
||||
@@ -522,9 +632,18 @@ void dr_piezo_mux_init(void)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 피에조 채널 선택 (0~7)
|
||||
* 채널 매핑 (EN_MUXA, EN_MUXB, SEL0, SEL1):
|
||||
* CH0 = MUXA 입력0 (1,0,0,0) CH4 = MUXB 입력0 (0,1,1,1)
|
||||
* CH1 = MUXA 입력2 (1,0,1,0) CH5 = MUXB 입력1 (0,1,0,1)
|
||||
* CH2 = MUXA 입력1 (1,0,0,1) CH6 = MUXB 입력2 (0,1,1,0)
|
||||
* CH3 = MUXA 입력3 (1,0,1,1) CH7 = MUXB 입력3 (0,1,0,0)
|
||||
* 채널 전환 후 MUX 안정화 대기 시간(1.3ms) 필요.
|
||||
*/
|
||||
void dr_piezo_select_channel(uint8_t channel)
|
||||
{
|
||||
channel = channel & 0x07; /* Mask to 0-7 */
|
||||
channel = channel & 0x07; /* 0~7 범위로 마스킹 */
|
||||
|
||||
switch (channel) {
|
||||
// EN_A EN_B SEL0 SEL1
|
||||
@@ -566,6 +685,7 @@ void dr_piezo_select_channel(uint8_t channel)
|
||||
nrf_delay_us(DR_PIEZO_MUX_SETTLING_US);
|
||||
}
|
||||
|
||||
/* 핀 테스트: 각 신호 핀을 순서대로 HIGH/LOW 토글 (오실로스코프 확인용) */
|
||||
void dr_piezo_test_pins(void)
|
||||
{
|
||||
DBG_PRINTF("[DR_PIEZO] Pin test...\r\n");
|
||||
@@ -606,9 +726,10 @@ void dr_piezo_test_pins(void)
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* SYSTEM FUNCTIONS
|
||||
* 시스템 함수 (전원 + TX 드라이버 통합 제어)
|
||||
*============================================================================*/
|
||||
|
||||
/* 시스템 전체 초기화: 전원 ON → TX 드라이버 초기화 */
|
||||
void dr_piezo_system_init(void)
|
||||
{
|
||||
DBG_PRINTF("[DR_PIEZO] System init...\r\n");
|
||||
@@ -617,6 +738,7 @@ void dr_piezo_system_init(void)
|
||||
DBG_PRINTF("[DR_PIEZO] System ready\r\n");
|
||||
}
|
||||
|
||||
/* 시스템 전체 종료: TX 드라이버 해제 → 전원 OFF */
|
||||
void dr_piezo_system_uninit(void)
|
||||
{
|
||||
dr_piezo_uninit();
|
||||
@@ -624,6 +746,7 @@ void dr_piezo_system_uninit(void)
|
||||
DBG_PRINTF("[DR_PIEZO] System shutdown\r\n");
|
||||
}
|
||||
|
||||
/* 전원 확인 후 버스트 송신 (블로킹: 송신 완료까지 대기) */
|
||||
void dr_piezo_transmit(uint8_t cycles)
|
||||
{
|
||||
if (!m_power_enabled)
|
||||
@@ -638,60 +761,74 @@ void dr_piezo_transmit(uint8_t cycles)
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* SOFTWARE-BASED BURST
|
||||
* 소프트웨어 기반 버스트 모드
|
||||
* 2025-12-11 Charles KWON
|
||||
*==============================================================================
|
||||
*
|
||||
* Timing Diagram:
|
||||
*
|
||||
* |<-margin->|<----- pulses ----->|<-- DMP -->|<-margin->|
|
||||
*
|
||||
*
|
||||
* Timer/PPI/GPIOTE 하드웨어 대신 CPU에서 직접 GPIO 레지스터를 조작하여
|
||||
* 초음파 펄스를 생성하는 방식. 인터럽트를 비활성화하여 정확한 타이밍 보장.
|
||||
*
|
||||
* === 타이밍 다이어그램 ===
|
||||
*
|
||||
* |<-마진->|<----- 펄스들 ----->|<-- DMP -->|<-마진->|
|
||||
*
|
||||
* PE ___/--------------------------------------------------\___
|
||||
* P_OUT ___________/-\_/-\_/-\_/-\_/-\____________________\_______
|
||||
* N_OUT ___________\_/-\_/-\_/-\_/-\_/____________________\_______
|
||||
* DMP __________________________________/----------\____________
|
||||
*
|
||||
* Signal Description:
|
||||
* - PE (Pulse Enable): Wraps entire sequence with margin before and after
|
||||
* - P_OUT: Positive output, starts LOW, toggles at 2MHz, opposite phase to N_OUT
|
||||
* - N_OUT: Negative output, starts LOW, toggles at 2MHz, opposite phase to P_OUT
|
||||
* - DMP (Dump): Activates after pulses complete, simultaneous with N_OUT falling edge
|
||||
*
|
||||
* Timing Specifications:
|
||||
* - Frequency: 2MHz (500ns period, 250ns half-period)
|
||||
* - CPU Clock: 64MHz (1 NOP = 15.625ns)
|
||||
* - Duty Cycle: 50:50
|
||||
* - DMP Pulse Width: ~500ns
|
||||
* - PE Margin: ~3 NOPs before pulses and after DMP
|
||||
*
|
||||
* Pin Mapping (Port P1):
|
||||
* - P1.02: N_OUT (Negative output)
|
||||
* - P1.03: P_OUT (Positive output)
|
||||
* - P1.05: PE (Pulse Enable)
|
||||
* - P1.09: DMP (Dump control)
|
||||
*
|
||||
* Note: Direct register access (NRF_P1->OUT) is used for simultaneous
|
||||
* multi-pin control to ensure precise timing and phase alignment.
|
||||
*
|
||||
* === 신호 설명 ===
|
||||
* - PE (Pulse Enable): 전체 시퀀스를 감싸는 활성화 신호 (전후 마진 포함)
|
||||
* - P_OUT: 양극 출력, N_OUT과 역상으로 2MHz 토글
|
||||
* - N_OUT: 음극 출력, P_OUT과 역상으로 2MHz 토글
|
||||
* - DMP (Dump): 펄스 완료 후 피에조 잔류 에너지 방전
|
||||
*
|
||||
* === 동작 원리 ===
|
||||
* 1) __disable_irq()로 인터럽트 차단 → 타이밍 흔들림 방지
|
||||
* 2) PE ON (P0.25 OUTSET 레지스터 사용 → 다른 P0 핀 영향 없음)
|
||||
* 3) NOP 마진 후 for 루프로 P_OUT/N_OUT 교번 출력
|
||||
* 4) DMP 펄스 (32 NOP ≒ 500ns)
|
||||
* 5) PE OFF 후 __enable_irq()로 인터럽트 복원
|
||||
*
|
||||
* === 포트 레지스터 직접 접근 ===
|
||||
* NRF_P1->OUT 레지스터에 미리 계산된 비트 마스크를 직접 기록.
|
||||
* 이 방식으로 P_OUT, N_OUT, DMP를 동시에 제어하면서도
|
||||
* 채널 선택 핀(MUX SEL)은 보존한다 (P1_CTRL_MASK로 제어 핀만 변경).
|
||||
* PE는 P0 포트에 있으므로 OUTSET/OUTCLR 레지스터로 별도 제어.
|
||||
*============================================================================*/
|
||||
/* 핀 번호에서 포트 내 비트 위치 추출 (하위 5비트 = 0~31) */
|
||||
#define PIN_NUM(pin) ((pin) & 0x1F)
|
||||
|
||||
|
||||
/* Bit masks for P1 port pins - derived from dr_piezo.h definitions
|
||||
*
|
||||
* WARNING: Never hardcode pin numbers!
|
||||
* Hardcoding may save a developer's time momentarily,
|
||||
* but it will also shorten their lifespan
|
||||
/* P1 포트 핀의 비트 마스크 - dr_piezo.h의 핀 정의에서 자동 생성
|
||||
*
|
||||
* 경고: 핀 번호를 절대 하드코딩하지 말 것!
|
||||
* 하드코딩은 개발자의 시간을 일시적으로 절약해줄 수 있지만,
|
||||
* 동시에 개발자의 수명을 단축시킬 것이다.
|
||||
* - Charles KWON
|
||||
*
|
||||
* 각 마스크는 해당 핀의 포트 레지스터 내 비트 위치를 나타낸다.
|
||||
* NRF_P1->OUT에 직접 쓸 때 사용되며, 여러 핀을 동시에 제어 가능.
|
||||
*/
|
||||
|
||||
#define P_OUT_MASK (1UL << PIN_NUM(DR_PIEZO_PIN_P_OUT)) /* P1.03 -> P1.07 */
|
||||
#define N_OUT_MASK (1UL << PIN_NUM(DR_PIEZO_PIN_N_OUT)) /* P1.02 -> P1.06 */
|
||||
#define PE_MASK (1UL << PIN_NUM(DR_PIEZO_PIN_PE)) /* P1.05 -> P0.25 */
|
||||
#define DMP_MASK (1UL << PIN_NUM(DR_PIEZO_PIN_DMP)) /* P1.09 -> P1.00 */
|
||||
#define P_OUT_MASK (1UL << PIN_NUM(DR_PIEZO_PIN_P_OUT)) /* P1.07 양극 출력 */
|
||||
#define N_OUT_MASK (1UL << PIN_NUM(DR_PIEZO_PIN_N_OUT)) /* P1.06 음극 출력 */
|
||||
#define PE_MASK (1UL << PIN_NUM(DR_PIEZO_PIN_PE)) /* P0.25 펄스 활성화 */
|
||||
#define DMP_MASK (1UL << PIN_NUM(DR_PIEZO_PIN_DMP)) /* P1.00 방전 제어 */
|
||||
|
||||
/* Combined mask for all piezo control signals (excluding channel select) */
|
||||
/* P1 포트에서 피에조 제어에 사용하는 핀들의 결합 마스크 (채널 선택 핀 제외) */
|
||||
#define P1_CTRL_MASK (P_OUT_MASK | N_OUT_MASK | DMP_MASK)
|
||||
|
||||
/*
|
||||
* 소프트웨어 버스트 - 기본 주파수 2.1MHz
|
||||
*
|
||||
* NOP 타이밍 계산:
|
||||
* 2.1MHz → 주기 476ns, 반주기 238ns
|
||||
* CPU 64MHz → 1 NOP = 15.625ns
|
||||
* 첫 반주기: 14 NOP(≒219ns) + 레지스터 쓰기(≒30ns) = ≒249ns
|
||||
* 둘째 반주기: 9 NOP(≒141ns) + 루프 오버헤드(≒47ns) + 레지스터 쓰기(≒30ns) = ≒218ns
|
||||
* 합계: ≒436~476ns (≒2.1MHz)
|
||||
*/
|
||||
void dr_piezo_burst_sw(uint8_t cycles)
|
||||
{
|
||||
/* Clamp cycles to valid range (1-20) */
|
||||
@@ -838,6 +975,13 @@ void dr_piezo_burst_sw(uint8_t cycles)
|
||||
* First half: 15 NOPs (~234ns)
|
||||
* Second half: 12 NOPs (~188ns) + loop overhead
|
||||
*/
|
||||
/*
|
||||
* 소프트웨어 버스트 - 1.8MHz
|
||||
* NOP 타이밍: 반주기 278ns
|
||||
* 첫 반주기: 17 NOP(≒266ns) + 레지스터 쓰기(≒30ns) = ≒296ns
|
||||
* 둘째 반주기: 11 NOP(≒172ns) + 루프 오버헤드(≒47ns) + 레지스터 쓰기(≒30ns) = ≒249ns
|
||||
* 합계: ≒499~556ns (≒1.8MHz)
|
||||
*/
|
||||
void dr_piezo_burst_sw_18mhz(uint8_t cycles)
|
||||
{
|
||||
/* Clamp cycles to valid range (1-20) */
|
||||
@@ -960,6 +1104,13 @@ void dr_piezo_burst_sw_18mhz(uint8_t cycles)
|
||||
* Second half: 11 NOPs (~172ns) + loop overhead (~47ns) = ~219ns
|
||||
* Total: ~468-500ns per cycle
|
||||
*/
|
||||
/*
|
||||
* 소프트웨어 버스트 - 2.0MHz
|
||||
* NOP 타이밍: 반주기 250ns
|
||||
* 첫 반주기: 15 NOP(≒234ns) + 레지스터 쓰기(≒30ns) = ≒264ns
|
||||
* 둘째 반주기: 10 NOP(≒156ns) + 루프 오버헤드(≒47ns) + 레지스터 쓰기(≒30ns) = ≒233ns
|
||||
* 합계: ≒468~500ns (≒2.0MHz)
|
||||
*/
|
||||
void dr_piezo_burst_sw_20mhz(uint8_t cycles)
|
||||
{
|
||||
/* Clamp cycles to valid range (1-20) */
|
||||
@@ -1083,6 +1234,13 @@ void dr_piezo_burst_sw_20mhz(uint8_t cycles)
|
||||
* Second half: 11 NOPs (~172ns) + loop overhead (~47ns) = ~219ns
|
||||
* Total: ~468-500ns per cycle
|
||||
*/
|
||||
/*
|
||||
* 소프트웨어 버스트 - 1.9MHz
|
||||
* NOP 타이밍: 반주기 263ns
|
||||
* 첫 반주기: 15 NOP(≒234ns) + 레지스터 쓰기(≒30ns) = ≒264ns
|
||||
* 둘째 반주기: 9 NOP(≒141ns) + 루프 오버헤드(≒47ns) + 레지스터 쓰기(≒30ns) = ≒218ns
|
||||
* 합계: ≒468~500ns (≒1.9MHz)
|
||||
*/
|
||||
void dr_piezo_burst_sw_19mhz(uint8_t cycles)
|
||||
{
|
||||
/* Clamp cycles to valid range (1-20) */
|
||||
@@ -1208,6 +1366,13 @@ void dr_piezo_burst_sw_19mhz(uint8_t cycles)
|
||||
* Second half: 11 NOPs (~172ns) + loop overhead (~47ns) = ~219ns
|
||||
* Total: ~452ns per cycle (~2.21 MHz)
|
||||
*/
|
||||
/*
|
||||
* 소프트웨어 버스트 - 2.2MHz
|
||||
* NOP 타이밍: 반주기 227ns
|
||||
* 첫 반주기: 13 NOP(≒203ns) + 레지스터 쓰기(≒30ns) = ≒233ns
|
||||
* 둘째 반주기: 8 NOP(≒125ns) + 루프 오버헤드(≒47ns) + 레지스터 쓰기(≒30ns) = ≒202ns
|
||||
* 합계: ≒435~454ns (≒2.2MHz)
|
||||
*/
|
||||
void dr_piezo_burst_sw_22mhz(uint8_t cycles)
|
||||
{
|
||||
/* Clamp cycles to valid range (1-20) */
|
||||
@@ -1327,6 +1492,13 @@ void dr_piezo_burst_sw_22mhz(uint8_t cycles)
|
||||
* Second half: 14 NOPs (~219ns) + loop overhead (~47ns) = ~266ns
|
||||
* Total: ~532-588ns per cycle
|
||||
*/
|
||||
/*
|
||||
* 소프트웨어 버스트 - 1.7MHz
|
||||
* NOP 타이밍: 반주기 294ns
|
||||
* 첫 반주기: 18 NOP(≒281ns) + 레지스터 쓰기(≒30ns) = ≒311ns
|
||||
* 둘째 반주기: 10 NOP(≒156ns) + 루프 오버헤드(≒47ns) + 레지스터 쓰기(≒30ns) = ≒233ns
|
||||
* 합계: ≒532~588ns (≒1.7MHz)
|
||||
*/
|
||||
void dr_piezo_burst_sw_17mhz(uint8_t cycles)
|
||||
{
|
||||
/* Clamp cycles to valid range (1-20) */
|
||||
|
||||
Reference in New Issue
Block a user