STM32F103C8T6 개발보드에서 발생하는 간헐적인 USB CDC 문제를 디버깅 중입니다. 정지 모드에서 깨어난 후 컴퓨터가 가상 시리얼 포트를 잃는 경우가 있습니다(하드웨어 리셋이 아닌 이상 재등록되지 않음). 클록/USB 초기화 시퀀스가 적절한지, 검증된 해결책이 있는지 확인해 주시면 감사하겠습니다.
이것은 F1 시리즈 디바이스와 정지(STOP) 모드 후 USB 재열거(re-enumeration)에서 발생하는 고전적이면서 극도로 성가신 문제입니다! 확실히 정상이며 표준적인 문제 해결 단계를 모두 시도해 보셨을 것입니다. 간헐적인 성격(10–30% 재현율)은 복잡한 클록 재구성 중에 발생하는 미묘한 타이밍/메타안정성 문제를 시사합니다.
다음은 제가 분석한 내용과 특히 USB 주변기기의 클록 도메인 및 필요한 48MHz 클록 안정성에 초점을 맞춰 추천할 사항입니다.
클록 시퀀스 정상성 검사 및 48MHz 도메인
RCC 시퀀스는 HSE/PLL 재활성화에 대해 표준적이고 올바른 것으로 보입니다. 문제는 PLL 자체보다는 전원 차단에서 풀 스피드 작동으로 전환하는 동안 USB 주변기기(48MHz 클록을 PLL / 1.5에서 유도받음)가 이를 처리하는 방식에 있습니다.
USB 클록 소스 제약: USB FS 클록은 반드시 PLL에서 유도되어야 하며, 정확히 PLLCLK / 1.5를 사용해 48MHz를 맞춰야 합니다. PLL의 일시적인 불안정성도 디바이스가 호스트 PC에 전송하는 첫 몇 개의 SOF(Start-of-Frame) 패킷을 손상시켜 호스트가 디바이스를 무시하게 만들 수 있습니다(좀비 CDC 상태).
리셋 타이밍:__HAL_RCC_USB_FORCE_RESET() 및 __HAL_RCC_USB_RELEASE_RESET() 시퀀스는 좋지만, 깨어난 후 PLL 잠금 시간에 비해 충분히 길지 않거나타이밍이 맞지 않을 수 있습니다. F103의 데이터시트에는 HSE 시작 시간과 별도의 PLL 잠금 시간이 나와 있습니다. 기본적으로 다음을 수행하고 있습니다:
깨우기 → HSE/PLL 시작
… (PLL 잠금) …
USB 클록 활성화 + 리셋 펄스
… (즉시 USBD_Init) …
PLL이 USB 리셋 해제 시점에 막 안정화된 상태라면 초기 클록이 여전히 한계 상태일 수 있습니다. 2ms 지연은 PLL/USB 클록 체인 전체가 완전히 안정되도록 보장하기에 충분하지 않을 수 있습니다.
권장 해결책: 분리/재연결(Detach/Attach) 절차
D+를 강제로 저전압으로 끌어내리는 것이 복구를 개선한다는 관찰이 핵심입니다. 물리적 분리/재연결을 강제하는 것은 호스트 PC에 USB 디바이스가 사라졌다가 다시 나타났음을 신뢰성 있게 알리는 유일한 방법입니다.
동작 원리: USB 열거는 호스트에 의해 처리됩니다. 디바이스의 클록이 깨어남 주기 동안 불안정하면 호스트는 응답 없는 디바이스 또는 오염된 데이터를 인식하고 포트를 ‘정지’ 또는 ‘오류’ 상태로 유지하며 물리적 리셋(사용자의 NRST 제공)을 기다립니다. 소프트 분리/재연결은 호스트의 USB 컨트롤러가 포트 열거 상태 머신을 재시작하게 합니다.
내부 D+ 풀업을 사용하는 경우 비활성화. 블루 필(Blue Pill)/D+에 외부 1.5kΩ을 사용하는 경우 GPIO를 사용해 D+를 강제로 저전압으로 끌어내려야 합니다.
D+ 핀을 GPIO 출력 저전압으로 구성.
HAL_Delay(10); (10ms는 일반적으로 신뢰할 수 있는 최소 분리 시간).
USB 재초기화(재연결):
D+ 핀을 다시 USB 기능으로 구성(또는 내부 풀업 재활성화).
전체 USB 재초기화 시퀀스 수행:
USBD_DeInit(&hUsbDeviceFS);
__HAL_RCC_USB_FORCE_RESET();
HAL_Delay(2); // 여전히 좋은 방법
__HAL_RCC_USB_RELEASE_RESET();
__HAL_RCC_USB_CLK_ENABLE();
USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS);
// ... (나머지 초기화 코드)
USBD_Start(&hUsbDeviceFS);
호스트는 이제 D+ 풀업 저항을 인식하고 재열거를 시작해야 합니다.
최선의 방법인가요? F1 시리즈의 경우, 정지 모드에서 깨어난 후 USB 재열거를 신뢰성 있게 하기 위해 소프트 분리를 강제하는 것은 잘 알려진 실용적 해결책입니다.
보드 레벨 주의 사항
전원 레일이 깨끗해 보이지만(20mVpp 이하의 리플은 우수함), 다음 사항을 고려하세요:
크리스탈 부하 커패시터(22pF): 8MHz HC-49 크리스탈의 경우 22pF은 상대적으로 높은 값이며, HSE 시작 시간을 약간 증가시키거나 깨어난 직후 주파수 안정성에 영향을 줄 수 있습니다. 대부분의 8MHz 크리스탈은 10pF~15pF 부하 커패시터를 권장합니다. 크리스탈 데이터시트의 권장 CL(부하 용량)을 확인하는 것이 좋습니다.
D+ 저항 허용오차: 1.5kΩ 풀업 저항은 올바릅니다. ±5% 범위 내에서 크게 벗어나지 않는지 확인하세요. 이 저항은 호스트에 풀 스피드 디바이스임을 신호로 전달합니다.
ESD 다이오드/누설 전류: D+/D-에 외부 ESD 보호 다이오드가 있다면 3.3V 신호에 간섭을 줄 수 있는 상당한 용량 또는 누설 전류를 추가하지 않는지 확인하세요.
D+ GPIO 분리/재연결을 확실히 시도해 보세요. 이 방법은 호스트가 디바이스의 깨어남 상태와 동기화되지 않은 문제를 해결합니다.
안녕하세요. 이는 F103 + Blue Pill에서 전형적인 함정으로, 주로 호스트 측에서 장치 연결 해제를 인식하지 못한 것과 Blue Pill의 하드웨어 설계 결함 때문입니다.
질문에 대한 해결책을 바로 드리겠습니다:
1. 근본 원인: D+ 풀업 저항과 소프트 연결
Blue Pill 보드의 D+ 풀업 저항(R10)은 일반적으로 MCU GPIO 제어 없이 바로 3.3V에 직접 납땜되어 있습니다.
현상: MCU가 정지 모드 또는 리셋 상태일 때도 D+는 저항에 의해 계속 고전압으로 유지됩니다. 호스트(PC)는 장치가 계속 연결되어 있다고 판단해 재열거(re-enumeration)를 시도하지 않습니다.
사용자 조치: "10ms 동안 저전압으로 설정"하셨다고 했는데, 이 시간이 너무 짧습니다. PC 측 USB 프로토콜 스택(특히 Windows)은 장치 연결 해제(SE0 상태)로 인식하기 위해 D+가 최소 100ms 이상 저전압 상태를 유지해야 하며, 500ms~1초가 권장됩니다.
2. 해결책: 강제 재열거 시퀀스 SystemCoreClockUpdate() 이후, USB 초기화 이전에 다음 “폭력적인” 리셋 코드를 추가하세요:
// 1. PA12(D+)를 GPIO 출력 저전압으로 강제 설정하여 연결 해제 시뮬레이션
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_RESET); // D+ 저전압
// 2. 호스트가 연결 해제를 인식할 충분한 대기 시간 확보
HAL_Delay(600); // 권장 500ms - 1000ms, 10ms는 절대 부족함
// 3. 핀 해제 후 USB 외부 장치 제어로 복귀 (이때 풀업 저항이 다시 D+를 끌어올려 호스트 열거 유발)
// 참고: 이후 USBD_Init에서 핀을 복합 기능으로 재설정하므로, 더 이상 강제 저전압을 유지하지 않아도 됩니다.
3. 클록 설정 보충 설명
F103의 USB 클록은 반드시 48MHz여야 합니다.
확인 사항: RCC 설정에서 RCC_USBCLKSOURCE_PLL_DIV1_5가 올바르게 구성되었는지 확인하세요.
72MHz(SysClk) / 1.5 = 48MHz. 이 단계가 잘못되면 USB는 타이밍 오류로 통신 불가 상태가 되며, 열거에 성공하더라도 “알 수 없는 장치” 오류가 발생합니다.
4. 질문에 대한 간결한 답변
타이밍 순서: HSE → PLL → Flash Latency → SysClk → D+ 600ms 강제 저전압 → USB Init
최선의 방법: 풀업 저항을 트랜지스터로 제어하지 않는 보드의 경우, PA12 소프트웨어 제어로 저전압을 만드는 것이 유일한 “소프트 연결 해제” 표준 방법입니다.
정정 사항: F103 정지 모드에서의 웨이크업은 일반적으로 USB가 완전히 작동 중단되는 실리콘 에러가 아닙니다. 문제는 주로 호스트 상태 머신이 리셋되지 않은 데 있습니다.
다음 단계 권장사항:
10ms 대기 시간을 600ms로 변경하시면 문제가 해결될 것입니다.
당신의 문제에 대해 유사한 사례를 경험한 적이 있습니다. 정지 모드에서 깨어난 후 USB CDC가 비정상 작동하는 것은 일반적으로 시계 복구 시퀀스와 USB 외부장치 상태가 완전히 재설정되지 않아 발생합니다. 다음은 핵심 사항과 권장 사항입니다:
1. 시계 복구 순서 및 에러타
F103은 정지 모드에서 깨어난 후 기본적으로 HSI(8MHz)를 시스템 클록으로 사용합니다. HSE와 PLL을 다시 활성화하는 단계는 올바르지만 중요한 시퀀스가 있습니다: PLL이 안정화된 후에야 USB 클록을 활성화해야 합니다. USB FS는 정확한 48MHz 클록(PLL에서 제공)이 필요합니다. USB 클록이 PLL이 불안정할 때 활성화되면 USB PHY가 비정상 작동하여 호스트가 인식하지 못할 수 있습니다.
HAL_RCC_OscConfig 이후 다음 코드를 추가하여 PLLRDY 플래그가 잠금 상태가 될 때까지 대기하는 것을 권장합니다:
2. USB 외부장치 완전 재설정
실행한 USBD_DeInit과 강제 재설정 시퀀스는 필수적이지만 순서를 최적화할 수 있습니다. ST의 에러타(일부 F1 모델에 해당)에 따르면 정지 모드에서 깨어난 후 USB 외부장치는 더 긴 재설정 펄스가 필요할 수 있습니다. USB 클록 비활성화, 재설정, 재활성화 사이의 지연 시간을 최소 10ms로 늘리는 것이 좋습니다.
보다 신뢰성 있는 방법은 깨어난 후 USB 클록을 먼저 비활성화한 상태로 유지하다가 시스템 클록이 완전히 안정화된 후(PLL 잠금 및 SYSCLK 전환 완료) 다음 하드웨어 재설정 시퀀스를 실행하는 것입니다:
__HAL_RCC_USB_CLK_DISABLE();
__HAL_RCC_USB_FORCE_RESET();
HAL_Delay(10);
__HAL_RCC_USB_RELEASE_RESET();
__HAL_RCC_USB_CLK_ENABLE();
// 이후 USBD_Init 등 초기화 실행
3. “소프트 디스커넥트” DP 강제 낮은 상태 유지
DP를 강제로 10ms 동안 낮은 상태로 유지해 연결 해제를 시뮬레이션하는 것은 효과적인 방법이며 F1 시리즈에서 널리 사용되는 모범 사례 중 하나입니다. 이는 호스트가 물리적 연결 해제를 감지하고 재인식을 유발합니다. 성공률을 높이기 위해 DP를 낮추기 전에 USB 외부장치 클록이 중지되었는지 확인하고, 낮은 상태를 10-20ms 동안 유지하는 것이 좋습니다. 이는 프로토콜 스택 수준의 방법이 아니지만 하드웨어적으로 가장 직접적인 해결책입니다.
4. 클록 소스 전환 권장사항
USB 작동 중에는 HSI로 절대 전환하지 마십시오. 올바른 방법은 깨어난 후 원래의 72MHz PLL 클록을 신속하게 안정화시키는 것입니다. PLL을 안정화시키고 잠금 상태를 확인한 후 USB를 처리해야 합니다. PLL이 안정화되기 전에는 USB 외부장치에 클록이 공급되지 않도록 하십시오.
5. 보드 레벨 원인 가능성
설명한 내용을 보면 하드웨어 문제 가능성은 낮지만 확인할 수 있습니다:
크리스탈 부하 커패시터: 8MHz HC-49에 대해 22pF는 일반적인 값이지만 깨어난 후 HSE 시작 속도가 느려지면 PLL 잠금 시간이 길어질 수 있습니다. 커패시터를 18-20pF로 줄이고 크리스탈 양단의 파형이 깨끗한지 확인하십시오.
USB 신호선: 22Ω 직렬 저항은 표준입니다. D+의 상향 저항(1.5kΩ)이 MCU의 3.3V에서 직접 공급되고, 깨어나는 순간 전원이 안정적으로 유지되는지 확인하십시오.
전원: 깨어나는 순간 전류 증가로 인해 LDO 전압이 떨어질 수 있습니다. 측정한 리플이 작더라도 VDD와 GND 사이에 10µF 탄탈륨 커패시터를 추가해 순시 응답을 개선할 수 있습니다.
요약 및 권장 단계
정지 모드에서 깨어난 후 클록 복구: HSE 활성화 → HSE 준비 완료 대기 → PLL 활성화 → PLL 잠금 대기 → SYSCLK을 PLL로 전환 → SystemCoreClock 업데이트
USB 완전 재설정: 먼저 USB 클록 비활성화 후 강제 재설정을 10ms 이상 유지하고 재설정 해제 후 클록 다시 활성화
USB 스택 재초기화: USBD_DeInit과 USBD_Init 시퀀스 호출
선택적 “소프트 디스커넥트”: 위 단계 후에도 문제가 반복된다면 USB 재초기화 전에 DP(PA12)를 푸시-풀 출력으로 구성하고 최소 15ms 동안 낮은 상태로 유지한 후 초기화 및 상향 저항 적용
이 순서로 작업하면 정지 모드에서 깨어난 후 USB CDC 복구 신뢰성을 크게 높일 수 있습니다.