Sentry Turret System -2

최진철·2026년 2월 8일

Sentry Turret?

목록 보기
2/2
post-thumbnail

STM32-Nucleo F-401re 보드에서 조이스틱(아날로그 2축)으로 서보 2개를 제어하는 기능을 구현하면서 만난 문제들과 해결 과정을 상세히 정리했습니다.

초보자분들이나 비슷한 프로젝트 하시는 분들께 조금이라도 도움이 되길 바랍니다.

프로젝트 개요 <-- 여기를 클릭하시면 기초적인 구현 내용을 확인할 수 있으니 확인 바랍니다.

Issue: ADC 값 나오긴 하지만 고정됨 (변하지 않음)

X:2039 → 1500us | Y:2070 → 1500us  (계속 동일 값 반복)

원인

DMA 설정에서 hadc1.Init.DMAContinuousRequests = DISABLE;
→ DMA가 한 번만 전송하고 멈춤

해결

hadc1.Init.DMAContinuousRequests = ENABLE;

-> CubeMX에서 다시 설정 후 재생성.

또한 Rank 2 채널에도 SamplingTime 명시:

sConfig.Channel = ADC_CHANNEL_9;
sConfig.Rank = 2;
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;  // 명시적으로 설정

DMA + 다중 채널일 때 ContinuousRequests는 거의 항상 ENABLE!

Issue2: HAL_ADC_Start_DMA() 호출 후 시스템 완전 멈춤

[4/4] ADC DMA 시작 중...
(여기서 무한 멈춤, 에러 핸들러도 안 나옴)

원인

DMA 인터럽트 핸들러에서 미묘한 문제 (버퍼 오버런, 우선순위 충돌, 또는 콜백에서 블로킹 동작) 발생 가능성 높음. 디버깅 어려움.

해결 (임시) ㅠㅠ

DMA → 폴링 방식으로 전환

HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 50);
adc_values[0] = HAL_ADC_GetValue(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 50);
adc_values[1] = HAL_ADC_GetValue(&hadc1);

DMA 인터럽트 문제를 해결하지 못해 일단 Polling으로 먼저 동작 확인 후 DMA로 업그레이드 추천합니다.

하지만 폴링 방식으로 바꿨는데도 값이 여전히 고정되는 문제를 겪었습니다.

Continuous Mode + Scan Mode에서 HAL_ADC_Start()를 한 번만 호출 → 같은 변환 결과만 반복 읽어오는 것을 확인했는데요 이를 해결하기 위해
매 루프마다 Stop → Start로 새로운 변환 사이클 강제 시작했습니다.

HAL_ADC_Stop(&hadc1);
HAL_Delay(1);           // 안정화용 짧은 딜레이
HAL_ADC_Start(&hadc1);

HAL_ADC_PollForConversion(&hadc1, 50);
adc_values[0] = HAL_ADC_GetValue(&hadc1);

HAL_ADC_PollForConversion(&hadc1, 50);
adc_values[1] = HAL_ADC_GetValue(&hadc1);

Continuous라도 매번 새로 시작하지 않으면 최신 값이 안 들어옴. Scan 모드에서는 채널 순서대로 Poll 두 번 필수!

issue 3: 인터럽트 콜백 안에서 printf() 쓰면 시스템 멈춤

버튼 누르면 한 번 메시지 나오고 완전 freeze

원인

인터럽트 컨텍스트에서 블로킹 함수(printf → UART 전송 대기) 사용 → 다른 인터럽트(예: SysTick) 못 들어와 데드락이 발생했습니ㅏㄷ.

해결

플래그 방식으로 변경

volatile uint8_t mode_changed = 0;
volatile uint8_t control_mode = 0;  // 0: manual, 1: auto

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
    if (GPIO_Pin == B1_Pin) {
        control_mode = !control_mode;
        mode_changed = 1;

최종적으로 폴링 방식 + 플래그 인터럽트로 안정화 성공

앞으로 DMA 인터럽트 방식 재도전 (HAL_ADC_ConvCpltCallback() 활용)하겠습니다.

이 글 읽으시는 분들, 비슷한 문제 겪으시면 댓글로 공유해주세요~
다음엔 DMA + 서보 smooth 제어까지 완성해서 올리겠습니다!
화이팅! 🚀

profile
세상의 어려운 문제를 해결하자

0개의 댓글