Cap처 모드에서는 엄청 빠른 추파수나 클럭펄스 측정이 아니먄 굳이 DMA방식가지 추천하지 않는거 같습니다.
오하려 인터럽트 모드가 더 효율적이고 좋다는 이야기도 있네요...
그래도 우리는 GO...
// 완료 콜백
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
// DMA 방식
uint32_t diff;
uint32_t ic_Value0;
uint32_t ic_Value1;
if (htim->Instance != TIM2) return;
// 1. 값 복사 및 즉시 DMA 재시작 (신호 누락 방지)
ic_Value0 = Cap_Value[0];
ic_Value1 = Cap_Value[1];
HAL_TIM_IC_Start_DMA(htim, TIM_CHANNEL_1, Cap_Value, 2); // &htim2 대신 htim 사용
// 2. 주파수 계산을 위한 차이값 구하기
// unsigned 32비트 연산 특성상 롤오버(오버플로우)가 발생해도 자동으로 정확한 차이가 계산됩니다.
diff = ic_Value1 - ic_Value0;
// 3. 주파수 계산 (0 나누기 방지)
if (diff != 0)
{
// 입력 캡처 타이머의 클럭 주파수가 1MHz(1,000,000Hz)로 분주(Prescaler)되어 있다고 가정함
freq = 1000000UL / diff;
printf("Freq = %.2f Hz\r\n", freq);
}
//---------------------------------------------------------------
// 인터럽트 방식
/*
if(htim->Instance == TIM2)
{
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
//cap_new = TIM2 -> CCR1; //레지스터 직접 코딩
cap_new = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
*/
/* * [오버플로우 보정 최적화]
* uint32_t 데이터 타입 특성상 cap_new < cap_old 이더라도
* 뺌셈을 하면 자동으로 오버플로우가 계산되어 올바른 차이값이 나옵니다.
* 따라서 조건문(if-else)이 필요 없습니다.
*/
/*
period_cnt = cap_new - cap_old;
cap_old = cap_new;
// 0으로 나누기 방지 및 비정상적인 값(예: 노이즈로 인한 0) 필터링
if (period_cnt > 0)
{
// 타이머 클록이 1MHz(1us)이므로 카운트당 1us
freq = 1000000.0f / (float)period_cnt;
printf("Freq = %.2f Hz\r\n", freq);
}
else
{
freq = 0.0f;
}
}
}
*/
}
// TIM2 입력 클럭 = 90 MHz
// PSC = 89
// CNT 클럭 = 1 MHz
// CH1 Rising Edge Capture
// 1 Count = 1 us
//HAL_TIM_IC_Start(&htim2, TIM_CHANNEL_1); // 폴링방식
//HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1); // 인터럽트 방식
HAL_TIM_IC_Start_DMA(&htim2, TIM_CHANNEL_1, Cap_Value, 2); // DMA 방식