재할당이 필요한 이유
STM32의 다중 사용 클럭과 재할당 기능
void Beep_Pwm_Init(u16 arr, u16 psc)
{
// 구조체 정의
GPIO_InitTypeDef GPIO_InitStructure = {0};
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = {0};
TIM_OCInitTypeDef TIM_OCInitStructure = {0};
// GPIO와 TIM 클럭 열기
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // GPIOB 클럭 활성화
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // TIM2 클럭 열기
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // 재할당 클럭 열기
GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE); // 일부 재할당 설정
GPIO_PinRemapConfig(GPIO_Remap_SWJ_NoJTRST, ENABLE); // PB10 재할당
// PB10 초기화
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 시간 단위 기본 설정
TIM_TimeBaseStructure.TIM_Period = arr - 1; // 재로드 값 설정
TIM_TimeBaseStructure.TIM_Prescaler = psc - 1; // 프리스케일러 설정
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 상승 모드 카운터
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
// 출력 비교 채널 초기화
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
TIM_OC3Init(TIM2, &TIM_OCInitStructure); // 채널 3 활성화
// 출력 모드
TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable); // 사전로드 레지스터 활성화
TIM_Cmd(TIM2, ENABLE);
// TIM_SetCompare3(TIM2, ccr); // 비교 레지스터의 값, 주파수
}
재할당이 필요한 이유
STM32 마이크로 컨트롤러에서재할당(Remap)의 주요 목적은인장 리소스 충돌을 해결하고하드웨어 설계 유연성 향상입니다.
1. 인장 충돌 해결
- 기본 외부 장치 인장이 디버깅 인터페이스或其他 외부 장치와 충돌할 때, 재할당을 통해 다른 인장으로 전환할 수 있습니다.
- 예: 기본적인 TIM2_CH3가 PA2에 있지만 PA2가 UART2에 의해 사용 중인 경우 → 재할당하여 PB10으로 변경합니다.
2. PCB 레이아웃 최적화
- 하드웨어 설계 시 신호를 더 적절한 인장으로 라우팅하기 위해 필요할 수 있습니다.
3. 디버깅 인터페이스 인장 해제
- STM32의 SWJ 디버깅 인터페이스 (PA13/14/15)는 기본적으로 3개의 인장으로 사용되며, 재할당을 통해 일부 인장을 일반 GPIO로 사용할 수 있습니다.
코드 문제 분석 (STM32F1 vs STM32F4)
1. 코드 내의 재할당 작업 (STM32F1 스타일)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // AFIO 클럭 활성화 (F1에만 적용) GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE); // TIM2 전체 재할당 (F1 기능) GPIO_PinRemapConfig(GPIO_Remap_SWJ_NoJTRST, ENABLE); // JTAG 비활성화 및 PB4 해제 (F1 기능)
문제:
- F4에는 AFIO 모듈이 없으므로, GPIO 복용 기능(AF) 구성으로 대체해야 합니다.
2. STM32F4의 올바른 구현 방법
- 단계:
- GPIO의 복용 기능(AF 번호) 직접 구성.
- `GPIO_PinAFConfig()`를 통해 외부 장치에 해당하는 AF 번호 선택 (예: TIM2=AF1).
- 재할당 함수 필요하지 않음!
정정된 코드 (F4에서는 TIM2_CH3를 PB10으로 매핑):
// 1. 클럭 열기 (F4의 GPIOB는 AHB1, TIM2는 APB1) RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // 2. PB10를 TIM2_CH3 (AF1)으로 설정 GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_TIM2); // 핵심 수정! // 3. GPIO를 복용 푸시풀 출력으로 초기화 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure);
STM32F1과 F4의 재할당 비교
| 특징 | STM32F1 | STM32F4 |
|---|---|---|
| 재할당 메커니즘 | AFIO 모듈 + `GPIO_PinRemapConfig()` | GPIOx_AFR寄存서로 직접 구성 |
| 클럭 열기 | `RCC_APB2Periph_AFIO` | AFIO 없이, 외부 장치 및 GPIO 클럭 열기 |
| 디버깅 인터페이스 해제 | `GPIO_Remap_SWJ_NoJTRST` | `SYSCFG->CFGR`寄存서로 구성 |
코드를 수정해야 하는 이유
1. STM32F4에는 AFIO 모듈이 없습니다
- F4의 인장 복용은 SYSCFG와 GPIOx_AFR寄存서를 관리하며, F1의 재할당 레지스터를 사용하지 않습니다.
2. TIM2의 PB10 복용 기능은 AF1입니다
- 매뉴얼 확인 필요: PB10의 TIM2_CH3는 AF1에 해당함 (즉, `GPIO_AF_SWJ`가 아님)
3. 디버깅 인터페이스 구성 방식이 다릅니다
- F4에서는 SYSCFG寄存서를 사용하여 JTAG 인장 해제:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); SYSCFG->CFGR |= SYSCFG_CFGR_SWJ_CFG_001; // JTAG 비활성화, SWD 유지
결론
재할당의 본질: 외부 장치 인장 전환을 통해 충돌 해결 또는 설계 개선.
STM32F1 vs F4:
- F1은 재할당 함수 (`GPIO_PinRemapConfig`)를 사용합니다.
- F4는 GPIO 복용 기능 (`GPIO_PinAFConfig`)으로 직접 구성합니다.
코드 문제: F1 API를 F4의 GPIO AF 구성으로 변경해야 합니다. 자세한 내용은 STM32F407 참조 매뉴얼의 'Alternate function mapping' 섹션을 참고하세요.
추가로 완전한 F4 코드 예제가 필요하다면 특정 외부 장치와 인장 요구사항을 알려주세요!