1. STM32G474 PWM 및 DC-DC 컨버터 개요
STM32G474는 STMicroelectronics의 STM32G4 시리즈에 속하는 고성능 32비트 ARM Cortex-M4 마이크로컨트롤러로, 최대 170MHz로 동작하며 Advanced-Control 타이머(TIM1, TIM8)를 포함한 다양한 타이머 기능을 제공합니다. PWM(Pulse Width Modulation)은 DC-DC 컨버터(예: LLC Half-Bridge, LLC Full-Bridge, Phase-Shifted Full-Bridge)와 같은 전력변환 애플리케이션에서 스위칭 소자를 제어하는 데 필수적입니다. 이 문서에서는 STM32G474의 Advanced-Control 타이머를 HAL API로 사용하여 주요 DC-DC 컨버터 토폴로지(LLC Half-Bridge, LLC Full-Bridge, Phase-Shifted Full-Bridge)에 적합한 PWM 신호를 생성하는 방법을 상세히 다룹니다. 모든 예제 코드는 STM32CubeMX로 생성된 완전한 코드로 구성되며, STM32CubeIDE에서 실행 가능합니다. 각 코드에는 상세한 주석이 포함되어 있습니다.
PWM 모듈의 주요 특징
- 타이머: Advanced-Control 타이머(TIM1, TIM8)는 PWM 출력, 보완 출력, 데드타임 삽입, 브레이크 입력을 지원.
- 채널: 최대 4개의 PWM 채널(CH1
CH4) 및 보완 출력(CH1NCH4N). - 모드: PWM Mode 1(에지 정렬), PWM Mode 2(중앙 정렬).
- 분해능: 높은 PWM 분해능 제공(타이머 카운터 및 비교 레지스터).
- 클럭: AHB/APB 클럭으로 동작, 저전력 모드 지원.
- 고급 기능: 데드타임 삽입, 브레이크 입력, 반복 카운터.
- DC-DC 컨버터 관련: 고주파 PWM(50 kHz~500 kHz), 보완 출력 및 데드타임은 LLC 및 PSFB에 적합.
HAL API는 복잡한 레지스터 설정을 추상화하여 PWM 설정을 간소화합니다.
2. 주요 PWM HAL API 함수
2.1. 타이머 및 PWM 초기화 함수
- *HAL_TIM_PWM_Init(TIM_HandleTypeDef htim)
- 설명: 타이머를 PWM 모드로 초기화.
- 매개변수: htim (타이머 핸들러 구조체).
- **HAL_TIM_PWM_ConfigChannel(TIM_HandleTypeDef htim, TIM_OC_InitTypeDef sConfig, uint32_t Channel)
- 설명: 특정 타이머 채널의 PWM 설정(듀티 사이클, 출력 극성 등).
- *HAL_TIM_PWM_Start(TIM_HandleTypeDef htim, uint32_t Channel)
- 설명: PWM 출력 시작.
- *HAL_TIMEx_PWMN_Start(TIM_HandleTypeDef htim, uint32_t Channel)
- 설명: 보완 PWM 출력 시작.
- **HAL_TIMEx_ConfigBreakDeadTime(TIM_HandleTypeDef htim, TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig)
- 설명: 데드타임 및 브레이크 입력 설정.
2.2. PWM 제어 함수
- *HAL_TIM_PWM_Pulse_Set(TIM_HandleTypeDef htim, uint32_t Channel, uint32_t Pulse)
- 설명: PWM 듀티 사이클 설정.
- *HAL_TIM_PWM_Pulse_Get(TIM_HandleTypeDef htim, uint32_t Channel)
- 설명: 현재 PWM 듀티 사이클 값 반환.
2.3. 인터럽트 관련 함수
- *HAL_TIM_PWM_IRQHandler(TIM_HandleTypeDef htim)
- 설명: 타이머 PWM 인터럽트 핸들러.
- *HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef htim)
- 설명: PWM 펄스 완료 시 호출되는 사용자 정의 콜백 함수.
3. DC-DC 컨버터 토폴로지별 PWM 요구사항
DC-DC 컨버터는 입력 전압을 원하는 출력 전압으로 변환하며, PWM 신호는 스위칭 소자(MOSFET, IGBT 등)를 제어하여 전력 흐름을 조절합니다. 각 토폴로지별 PWM 요구사항은 다음과 같습니다:
3.1. LLC Half-Bridge 컨버터
- 특징: 공진형 컨버터로 고효율, 고주파 동작(100 kHz~500 kHz). 두 개의 스위치로 Half-Bridge 구성.
- PWM 요구사항:
- 두 채널 PWM 신호(예: TIM1_CH1, TIM1_CH1N)로 상보적 출력, 50% 고정 듀티 사이클.
- 주파수: 100 kHz~500 kHz (공진 주파수에 따라 조정).
- PWM Mode 2(중앙 정렬) 권장 (대칭적 스위칭).
- 데드타임 필수 (스위치 단락 방지).
- 예제 설정: 100 kHz PWM, 50% 듀티 사이클, 100 ns 데드타임.
3.2. LLC Full-Bridge 컨버터
- 특징: 네 개의 스위치로 Full-Bridge 구성, 더 높은 전력 처리 가능.
- PWM 요구사항:
- 네 개의 PWM 신호(예: TIM1_CH1, CH1N, CH2, CH2N)로 두 쌍의 상보적 출력.
- 주파수: 100 kHz~500 kHz.
- PWM Mode 2 권장.
- 데드타임 필수.
- 예제 설정: 100 kHz PWM, 50% 듀티 사이클, 100 ns 데드타임.
3.3. Phase-Shifted Full-Bridge (PSFB) 컨버터
- 특징: 위상 천이(Phase-Shift)로 ZVS(Zero Voltage Switching)를 구현, 고효율.
- PWM 요구사항:
- 네 개의 PWM 신호(예: TIM1_CH1, CH1N, CH2, CH2N).
- 위상 천이 제어: 두 채널 간 위상 차 조절.
- 주파수: 50 kHz~200 kHz.
- PWM Mode 2 권장.
- 데드타임 필수.
- 예제 설정: 100 kHz PWM, 50% 듀티 사이클, 100 ns 데드타임, 위상 천이 조절.
4. PWM 설정 및 동작 원리
STM32G474의 PWM을 DC-DC 컨버터에 사용하려면 시스템 클럭, 타이머 설정, GPIO 설정, 디버깅 및 프로그램 다운로드 절차를 정확히 구성해야 합니다. 아래는 STM32CubeMX와 STM32CubeIDE를 사용한 설정 절차입니다.
4.1. STM32CubeMX 설정 절차
- 프로젝트 생성:
- STM32CubeMX에서 "New Project" 선택, "STM32G474" 검색, 패키지(예: LQFP64) 선택.
- 프로젝트 이름 및 저장 경로 설정.
- 시스템 클럭 설정 (170 MHz, HSE 사용):
- "System Core" > "RCC"에서 HSE를 "Crystal/Ceramic Resonator"로 설정 (8 MHz 크리스털 가정).
- Clock Configuration:
- HSE: 8 MHz.
- PLL 설정: PLLM = 1, PLLN = 85, PLLR = 2, PLLR Enable.
- System Clock Mux: PLLCLK.
- 결과: SYSCLK = (8 MHz / 1) * 85 / 2 = 170 MHz.
- HCLK, PCLK1, PCLK2: 170 MHz (Divider = 1).
- Flash Latency: 4 WS.
- PWM 설정:
- "Timers" > "TIM1" 선택.
- LLC Half-Bridge: Channel 1 (PA8, TIM1_CH1), Complementary Channel 1N (PA7, TIM1_CH1N).
- LLC Full-Bridge/PSFB: Channel 1 (PA8, TIM1_CH1), Channel 1N (PA7), Channel 2 (PA9, TIM1_CH2), Channel 2N (PB0, TIM1_CH2N).
- Parameter Settings:
- Prescaler (PSC): 16 (타이머 클럭 = 170 MHz / (16+1) = 10 MHz).
- Counter Period (ARR): 99 (PWM 주기 = (99+1) / 10 MHz = 10 µs, 주파수 = 100 kHz).
- Pulse: 50 (듀티 사이클 = 50%, 50/100).
- Mode: PWM Mode 2 (중앙 정렬).
- Dead Time: 100 ns.
- GPIO: PA8, PA7, PA9, PB0 자동 설정, 속도 "High".
- 디버깅 인터페이스 설정:
- "System Core" > "SYS"에서 Debug를 "Serial Wire" (SWD)로 설정.
- SWD 핀: PA13 (SWDIO), PA14 (SWCLK).
- 프로젝트 설정 및 코드 생성:
- Project Manager:
- Toolchain/IDE: STM32CubeIDE.
- Code Generator: "Copy only the necessary library files".
- "Generate Code" 클릭.
- Project Manager:
4.2. PWM 동작 원리
- 시스템 초기화:
- 시스템 클럭 170 MHz, GPIO 및 타이머 클럭 활성화.
- HAL_Init()으로 HAL 라이브러리 및 Systick 초기화.
- PWM 설정:
- TIM1 설정 (TIM_OC_InitTypeDef 구조체).
- Prescaler와 ARR로 주파수 설정 (예: 100 kHz).
- Compare Register(CCR)로 듀티 사이클 설정.
- 보완 출력 및 데드타임 설정 (LLC, PSFB).
- PSFB의 경우 위상 천이 구현.
- PWM 동작:
- HAL_TIM_PWM_Start 및 HAL_TIMEx_PWMN_Start로 PWM 출력 시작.
- HAL_TIM_PWM_Pulse_Set으로 듀티 사이클 동적 조절.
- 인터럽트로 위상 천이 및 동적 제어 가능.
4.3. 디버깅 및 프로그램 다운로드
- 디버깅:
- ST-LINK 연결 (SWDIO: PA13, SWCLK: PA14).
- STM32CubeIDE에서 "Debug Configurations" 설정 (ST-LINK, SWD).
- 브레이크포인트 및 변수 모니터링 (pwmPulse 등).
- 프로그램 다운로드:
- "Build Project"로 빌드.
- "Run Configurations"에서 .elf 파일 선택 후 다운로드.
- 오실로스코프로 PWM 파형 및 데드타임 확인.
5. PWM 예제 코드
아래는 STM32G474의 TIM1을 HAL API로 사용하여 DC-DC 컨버터 토폴로지별 PWM 신호를 생성하는 예제 코드입니다. 코드는 STM32CubeIDE에서 실행 가능하며, HSE 8 MHz로 170 MHz SYSCLK를 설정합니다.
5.1. 예제 1: LLC Half-Bridge 컨버터 PWM (Mode 2)
TIM1 채널 1(PA8) 및 보완 출력(PA7)에서 100 kHz PWM 신호를 PWM Mode 2로 출력, 50% 고정 듀티 사이클, 100 ns 데드타임.
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* STM32CubeMX-generated code for TIM1 Channel 1 (PA8) and Complementary Channel 1N (PA7) PWM output in Mode 2 for LLC Half-Bridge converter.
* PWM frequency: 100 kHz, fixed 50% duty cycle, dead time: 100 ns.
* System clock set to 170 MHz using HSE.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
TIM_HandleTypeDef htim1; // TIM1 핸들러 구조체
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define PWM_Pin GPIO_PIN_8 // PA8 핀을 PWM 출력으로 사용 (TIM1_CH1)
#define PWM_N_Pin GPIO_PIN_7 // PA7 핀을 보완 PWM 출력으로 사용 (TIM1_CH1N)
#define PWM_GPIO_Port GPIOA // PWM이 연결된 GPIO 포트
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
volatile uint32_t pwmStatus = 0; // PWM 상태 변수: 0 (초기화 완료), 1 (동작 중), 0xFFFF (오류)
volatile uint32_t pwmPulse = 50; // PWM 펄스 값 (듀티 사이클 50%, 50/100)
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void); // 시스템 클럭 설정 함수 선언
static void MX_GPIO_Init(void); // GPIO 초기화 함수 선언
static void MX_TIM1_Init(void); // TIM1 초기화 함수 선언
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init(); // HAL 라이브러리 및 시스템 타이머(Systick) 초기화
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config(); // 시스템 클럭을 170 MHz로 설정 (HSE 8 MHz 사용)
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init(); // GPIOA 핀 8 및 7를 PWM 출력으로 초기화
MX_TIM1_Init(); // TIM1를 PWM Mode 2로 초기화
/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); // TIM1 채널 1 PWM 출력 시작
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1); // TIM1 채널 1N 보완 출력 시작
if (pwmStatus != 1) // PWM 초기화 성공 여부 확인
{
pwmStatus = 0xFFFF; // 초기화 실패 시 오류 상태 설정
while (1); // 오류 발생 시 무한 루프
}
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
// LLC Half-Bridge는 50% 고정 듀티 사이클 사용, 주파수 조절은 공진 탱크 설계에 따라 별도 구현
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0}; // 오실레이터 설정 구조체 초기화
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; // 클럭 설정 구조체 초기화
/** Configure the main internal regulator output voltage
*/
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1); // 전압 레귤레이터를 Scale 1로 설정 (최대 성능)
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; // 외부 HSE 오실레이터 사용
RCC_OscInitStruct.HSEState = RCC_HSE_ON; // HSE 활성화
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; // PLL 활성화
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; // PLL 소스를 HSE로 설정
RCC_OscInitStruct.PLL.PLLM = 1; // PLL 분주기 M = 1
RCC_OscInitStruct.PLL.PLLN = 85; // PLL 곱셈기 N = 85
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; // PLL P 출력 분주기 = 2
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; // PLL Q 출력 분주기 = 2
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; // PLL R 출력 분주기 = 2 (SYSCLK = 8 MHz * 85 / 2 = 170 MHz)
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) // 오실레이터 설정 적용
{
Error_Handler(); // 설정 실패 시 오류 처리
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; // 설정할 클럭 종류 지정
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; // 시스템 클럭 소스를 PLL로 설정
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // AHB 클럭 분주기 = 1 (HCLK = 170 MHz)
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; // APB1 클럭 분주기 = 1 (PCLK1 = 170 MHz)
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; // APB2 클럭 분주기 = 1 (PCLK2 = 170 MHz)
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) // 클럭 설정 및 플래시 레이턴시 4 WS 적용
{
Error_Handler(); // 설정 실패 시 오류 처리
}
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0}; // GPIO 설정 구조체 초기화
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE(); // GPIOA 포트 클럭 활성화
/*Configure GPIO pins : PA8, PA7 */
GPIO_InitStruct.Pin = PWM_Pin | PWM_N_Pin; // 설정할 핀: GPIOA 핀 8 (CH1), 핀 7 (CH1N)
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 대체 기능, 푸시-풀
GPIO_InitStruct.Pull = GPIO_NOPULL; // 풀업/풀다운 저항 사용 안 함
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // 출력 속도: 고속
GPIO_InitStruct.Alternate = GPIO_AF1_TIM1; // PA8, PA7을 TIM1_CH1, TIM1_CH1N으로 설정
HAL_GPIO_Init(PWM_GPIO_Port, &GPIO_InitStruct); // GPIOA 핀 설정 적용
pwmStatus = 1; // PWM 초기화 성공 표시
}
/**
* @brief TIM1 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM1_Init(void)
{
TIM_OC_InitTypeDef sConfigOC = {0}; // 타이머 출력 비교 구조체 초기화
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0}; // 브레이크 및 데드타임 구조체 초기화
htim1.Instance = TIM1; // TIM1 선택
htim1.Init.Prescaler = 16; // 프리스케일러: 170 MHz / (16+1) = 10 MHz
htim1.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1; // 중앙 정렬 모드 1 (PWM Mode 2)
htim1.Init.Period = 99; // ARR: (99+1) / 10 MHz = 10 µs (100 kHz PWM)
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 클럭 분주 없음
htim1.Init.RepetitionCounter = 0; // 반복 카운터 비활성화
if (HAL_TIM_PWM_Init(&htim1) != HAL_OK) // TIM1 PWM 모드 초기화
{
Error_Handler(); // 초기화 실패 시 오류 처리
}
sConfigOC.OCMode = TIM_OCMODE_PWM2; // PWM 모드 2 (중앙 정렬)
sConfigOC.Pulse = 50; // 펄스 값: 50% 듀티 사이클 (50/100)
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; // 출력 극성: High
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; // 보완 출력 극성: High
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; // 빠른 모드 비활성화
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) // 채널 1 PWM 설정
{
Error_Handler(); // 설정 실패 시 오류 처리
}
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE; // 런 모드 오프 상태 비활성화
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE; // 유휴 상태 비활성화
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF; // 락 레벨 비활성화
sBreakDeadTimeConfig.DeadTime = 100; // 데드타임: 100 ns (10 MHz 클럭 기준)
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE; // 브레이크 입력 비활성화
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH; // 브레이크 극성
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; // 자동 출력 비활성화
if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK) // 브레이크 및 데드타임 설정
{
Error_Handler(); // 설정 실패 시 오류 처리
}
pwmStatus = 1; // PWM 초기화 성공 표시
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
pwmStatus = 0xFFFF; // 오류 상태 설정
while (1) // 무한 루프에서 대기
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
while (1) // 어설션 오류 시 무한 루프
{
}
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
설명:
- 기능: TIM1 채널 1(PA8) 및 보완 출력(PA7)에서 100 kHz PWM 신호를 PWM Mode 2로 출력, 50% 고정 듀티 사이클, 100 ns 데드타임으로 LLC Half-Bridge 스위치 제어.
- 설정: PWM 주파수 100 kHz (PSC=16, ARR=99), 듀티 사이클 50% (Pulse=50), PWM Mode 2, 데드타임 100 ns.
- GPIO: GPIOA 핀 8 (TIM1_CH1), GPIOA 핀 7 (TIM1_CH1N).
- 출력: PWM 파형은 PA8과 PA7에서 상보적으로 출력, 고정 50% 듀티 사이클.
- 클럭: HSE 8 MHz, PLL로 170 MHz SYSCLK.
5.2. 예제 2: LLC Full-Bridge 컨버터 PWM (Mode 2)
TIM1 채널 1(PA8), 채널 1N(PA7), 채널 2(PA9), 채널 2N(PB0)에서 100 kHz PWM 신호를 PWM Mode 2로 출력, 50% 고정 듀티 사이클, 100 ns 데드타임.
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* STM32CubeMX-generated code for TIM1 Channels 1, 1N, 2, 2N (PA8, PA7, PA9, PB0) PWM output in Mode 2 for LLC Full-Bridge converter.
* PWM frequency: 100 kHz, fixed 50% duty cycle, dead time: 100 ns.
* System clock set to 170 MHz using HSE.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
TIM_HandleTypeDef htim1; // TIM1 핸들러 구조체
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define PWM_CH1_Pin GPIO_PIN_8 // PA8 핀을 PWM 출력으로 사용 (TIM1_CH1)
#define PWM_CH1N_Pin GPIO_PIN_7 // PA7 핀을 보완 PWM 출력으로 사용 (TIM1_CH1N)
#define PWM_CH2_Pin GPIO_PIN_9 // PA9 핀을 PWM 출력으로 사용 (TIM1_CH2)
#define PWM_CH2N_Pin GPIO_PIN_0 // PB0 핀을 보완 PWM 출력으로 사용 (TIM1_CH2N)
#define PWM_GPIO_Port_A GPIOA // PWM CH1, CH1N, CH2가 연결된 GPIO 포트
#define PWM_GPIO_Port_B GPIOB // PWM CH2N이 연결된 GPIO 포트
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
volatile uint32_t pwmStatus = 0; // PWM 상태 변수: 0 (초기화 완료), 1 (동작 중), 0xFFFF (오류)
volatile uint32_t pwmPulse = 50; // PWM 펄스 값 (듀티 사이클 50%, 50/100)
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void); // 시스템 클럭 설정 함수 선언
static void MX_GPIO_Init(void); // GPIO 초기화 함수 선언
static void MX_TIM1_Init(void); // TIM1 초기화 함수 선언
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init(); // HAL 라이브러리 및 시스템 타이머(Systick) 초기화
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config(); // 시스템 클럭을 170 MHz로 설정 (HSE 8 MHz 사용)
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init(); // GPIOA 핀 8, 7, 9 및 GPIOB 핀 0를 PWM 출력으로 초기화
MX_TIM1_Init(); // TIM1를 PWM Mode 2로 초기화
/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); // TIM1 채널 1 PWM 출력 시작
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1); // TIM1 채널 1N 보완 출력 시작
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2); // TIM1 채널 2 PWM 출력 시작
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2); // TIM1 채널 2N 보완 출력 시작
if (pwmStatus != 1) // PWM 초기화 성공 여부 확인
{
pwmStatus = 0xFFFF; // 초기화 실패 시 오류 상태 설정
while (1); // 오류 발생 시 무한 루프
}
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
// LLC Full-Bridge는 50% 고정 듀티 사이클 사용, 주파수 조절은 공진 탱크 설계에 따라 별도 구현
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0}; // 오실레이터 설정 구조체 초기화
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; // 클럭 설정 구조체 초기화
/** Configure the main internal regulator output voltage
*/
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1); // 전압 레귤레이터를 Scale 1로 설정 (최대 성능)
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; // 외부 HSE 오실레이터 사용
RCC_OscInitStruct.HSEState = RCC_HSE_ON; // HSE 활성화
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; // PLL 활성화
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; // PLL 소스를 HSE로 설정
RCC_OscInitStruct.PLL.PLLM = 1; // PLL 분주기 M = 1
RCC_OscInitStruct.PLL.PLLN = 85; // PLL 곱셈기 N = 85
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; // PLL P 출력 분주기 = 2
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; // PLL Q 출력 분주기 = 2
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; // PLL R 출력 분주기 = 2 (SYSCLK = 8 MHz * 85 / 2 = 170 MHz)
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) // 오실레이터 설정 적용
{
Error_Handler(); // 설정 실패 시 오류 처리
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; // 설정할 클럭 종류 지정
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; // 시스템 클럭 소스를 PLL로 설정
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // AHB 클럭 분주기 = 1 (HCLK = 170 MHz)
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; // APB1 클럭 분주기 = 1 (PCLK1 = 170 MHz)
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; // APB2 클럭 분주기 = 1 (PCLK2 = 170 MHz)
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) // 클럭 설정 및 플래시 레이턴시 4 WS 적용
{
Error_Handler(); // 설정 실패 시 오류 처리
}
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0}; // GPIO 설정 구조체 초기화
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE(); // GPIOA 포트 클럭 활성화
__HAL_RCC_GPIOB_CLK_ENABLE(); // GPIOB 포트 클럭 활성화
/*Configure GPIO pins : PA8, PA7, PA9 */
GPIO_InitStruct.Pin = PWM_CH1_Pin | PWM_CH1N_Pin | PWM_CH2_Pin; // 설정할 핀: GPIOA 핀 8, 7, 9
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 대체 기능, 푸시-풀
GPIO_InitStruct.Pull = GPIO_NOPULL; // 풀업/풀다운 저항 사용 안 함
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // 출력 속도: 고속
GPIO_InitStruct.Alternate = GPIO_AF1_TIM1; // PA8, PA7, PA9를 TIM1_CH1, CH1N, CH2로 설정
HAL_GPIO_Init(PWM_GPIO_Port_A, &GPIO_InitStruct); // GPIOA 핀 설정 적용
/*Configure GPIO pin : PB0 */
GPIO_InitStruct.Pin = PWM_CH2N_Pin; // 설정할 핀: GPIOB 핀 0 (CH2N)
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 대체 기능, 푸시-풀
GPIO_InitStruct.Pull = GPIO_NOPULL; // 풀업/풀다운 저항 사용 안 함
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // 출력 속도: 고속
GPIO_InitStruct.Alternate = GPIO_AF1_TIM1; // PB0를 TIM1_CH2N으로 설정
HAL_GPIO_Init(PWM_GPIO_Port_B, &GPIO_InitStruct); // GPIOB 핀 설정 적용
pwmStatus = 1; // PWM 초기화 성공 표시
}
/**
* @brief TIM1 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM1_Init(void)
{
TIM_OC_InitTypeDef sConfigOC = {0}; // 타이머 출력 비교 구조체 초기화
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0}; // 브레이크 및 데드타임 구조체 초기화
htim1.Instance = TIM1; // TIM1 선택
htim1.Init.Prescaler = 16; // 프리스케일러: 170 MHz / (16+1) = 10 MHz
htim1.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1; // 중앙 정렬 모드 1 (PWM Mode 2)
htim1.Init.Period = 99; // ARR: (99+1) / 10 MHz = 10 µs (100 kHz PWM)
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 클럭 분주 없음
htim1.Init.RepetitionCounter = 0; // 반복 카운터 비활성화
if (HAL_TIM_PWM_Init(&htim1) != HAL_OK) // TIM1 PWM 모드 초기화
{
Error_Handler(); // 초기화 실패 시 오류 처리
}
sConfigOC.OCMode = TIM_OCMODE_PWM2; // PWM 모드 2 (중앙 정렬)
sConfigOC.Pulse = 50; // 펄스 값: 50% 듀티 사이클 (50/100)
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; // 출력 극성: High
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; // 보완 출력 극성: High
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; // 빠른 모드 비활성화
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) // 채널 1 PWM 설정
{
Error_Handler(); // 설정 실패 시 오류 처리
}
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK) // 채널 2 PWM 설정
{
Error_Handler(); // 설정 실패 시 오류 처리
}
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE; // 런 모드 오프 상태 비활성화
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE; // 유휴 상태 비활성화
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF; // 락 레벨 비활성화
sBreakDeadTimeConfig.DeadTime = 100; // 데드타임: 100 ns (10 MHz 클럭 기준)
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE; // 브레이크 입력 비활성화
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH; // 브레이크 극성
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; // 자동 출력 비활성화
if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK) // 브레이크 및 데드타임 설정
{
Error_Handler(); // 설정 실패 시 오류 처리
}
pwmStatus = 1; // PWM 초기화 성공 표시
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
pwmStatus = 0xFFFF; // 오류 상태 설정
while (1) // 무한 루프에서 대기
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
while (1) // 어설션 오류 시 무한 루프
{
}
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
설명:
- 기능: TIM1 채널 1(PA8), 채널 1N(PA7), 채널 2(PA9), 채널 2N(PB0)에서 100 kHz PWM 신호를 PWM Mode 2로 출력, 50% 고정 듀티 사이클, 100 ns 데드타임으로 LLC Full-Bridge 스위치 제어.
- 설정: PWM 주파수 100 kHz (PSC=16, ARR=99), 듀티 사이클 50% (Pulse=50), PWM Mode 2, 데드타임 100 ns.
- GPIO: GPIOA 핀 8, 7, 9 (TIM1_CH1, CH1N, CH2), GPIOB 핀 0 (TIM1_CH2N).
- 출력: PWM 파형은 PA8, PA7, PA9, PB0에서 상보적으로 출력, 고정 50% 듀티 사이클.
- 클럭: HSE 8 MHz, PLL로 170 MHz SYSCLK.
5.3. 예제 3: Phase-Shifted Full-Bridge (PSFB) 컨버터 PWM (Mode 2)
TIM1 채널 1(PA8), 채널 1N(PA7), 채널 2(PA9), 채널 2N(PB0)에서 100 kHz PWM 신호를 PWM Mode 2로 출력, 위상 천이 조절, 100 ns 데드타임.
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* STM32CubeMX-generated code for TIM1 Channels 1, 1N, 2, 2N (PA8, PA7, PA9, PB0) PWM output in Mode 2 for Phase-Shifted Full-Bridge converter.
* PWM frequency: 100 kHz, 50% duty cycle, dead time: 100 ns, phase shift adjustable.
* System clock set to 170 MHz using HSE.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
TIM_HandleTypeDef htim1; // TIM1 핸들러 구조체
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define PWM_CH1_Pin GPIO_PIN_8 // PA8 핀을 PWM 출력으로 사용 (TIM1_CH1)
#define PWM_CH1N_Pin GPIO_PIN_7 // PA7 핀을 보완 PWM 출력으로 사용 (TIM1_CH1N)
#define PWM_CH2_Pin GPIO_PIN_9 // PA9 핀을 PWM 출력으로 사용 (TIM1_CH2)
#define PWM_CH2N_Pin GPIO_PIN_0 // PB0 핀을 보완 PWM 출력으로 사용 (TIM1_CH2N)
#define PWM_GPIO_Port_A GPIOA // PWM CH1, CH1N, CH2가 연결된 GPIO 포트
#define PWM_GPIO_Port_B GPIOB // PWM CH2N이 연결된 GPIO 포트
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
volatile uint32_t pwmStatus = 0; // PWM 상태 변수: 0 (초기화 완료), 1 (동작 중), 0xFFFF (오류)
volatile uint32_t pwmPulse = 50; // PWM 펄스 값 (듀티 사이클 50%, 50/100)
volatile uint32_t phaseShift = 0; // 위상 천이 값 (0~99, 단위: 타이머 카운트)
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void); // 시스템 클럭 설정 함수 선언
static void MX_GPIO_Init(void); // GPIO 초기화 함수 선언
static void MX_TIM1_Init(void); // TIM1 초기화 함수 선언
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init(); // HAL 라이브러리 및 시스템 타이머(Systick) 초기화
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config(); // 시스템 클럭을 170 MHz로 설정 (HSE 8 MHz 사용)
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init(); // GPIOA 핀 8, 7, 9 및 GPIOB 핀 0를 PWM 출력으로 초기화
MX_TIM1_Init(); // TIM1를 PWM Mode 2로 초기화
/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); // TIM1 채널 1 PWM 출력 시작
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1); // TIM1 채널 1N 보완 출력 시작
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2); // TIM1 채널 2 PWM 출력 시작
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2); // TIM1 채널 2N 보완 출력 시작
if (pwmStatus != 1) // PWM 초기화 성공 여부 확인
{
pwmStatus = 0xFFFF; // 초기화 실패 시 오류 상태 설정
while (1); // 오류 발생 시 무한 루프
}
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
// 위상 천이를 0~99까지 점진적으로 변경 (PSFB 출력 전력 조절)
for (phaseShift = 0; phaseShift <= 99; phaseShift += 1)
{
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, pwmPulse + phaseShift); // 채널 2에 위상 천이 적용
HAL_Delay(50); // 50ms 대기
}
for (phaseShift = 99; phaseShift >= 0; phaseShift -= 1)
{
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, pwmPulse + phaseShift); // 채널 2에 위상 천이 적용
HAL_Delay(50); // 50ms 대기
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0}; // 오실레이터 설정 구조체 초기화
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; // 클럭 설정 구조체 초기화
/** Configure the main internal regulator output voltage
*/
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1); // 전압 레귤레이터를 Scale 1로 설정 (최대 성능)
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; // 외부 HSE 오실레이터 사용
RCC_OscInitStruct.HSEState = RCC_HSE_ON; // HSE 활성화
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; // PLL 활성화
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; // PLL 소스를 HSE로 설정
RCC_OscInitStruct.PLL.PLLM = 1; // PLL 분주기 M = 1
RCC_OscInitStruct.PLL.PLLN = 85; // PLL 곱셈기 N = 85
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; // PLL P 출력 분주기 = 2
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; // PLL Q 출력 분주기 = 2
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; // PLL R 출력 분주기 = 2 (SYSCLK = 8 MHz * 85 / 2 = 170 MHz)
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) // 오실레이터 설정 적용
{
Error_Handler(); // 설정 실패 시 오류 처리
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; // 설정할 클럭 종류 지정
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; // 시스템 클럭 소스를 PLL로 설정
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // AHB 클럭 분주기 = 1 (HCLK = 170 MHz)
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; // APB1 클럭 분주기 = 1 (PCLK1 = 170 MHz)
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; // APB2 클럭 분주기 = 1 (PCLK2 = 170 MHz)
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) // 클럭 설정 및 플래시 레이턴시 4 WS 적용
{
Error_Handler(); // 설정 실패 시 오류 처리
}
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0}; // GPIO 설정 구조체 초기화
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE(); // GPIOA 포트 클럭 활성화
__HAL_RCC_GPIOB_CLK_ENABLE(); // GPIOB 포트 클럭 활성화
/*Configure GPIO pins : PA8, PA7, PA9 */
GPIO_InitStruct.Pin = PWM_CH1_Pin | PWM_CH1N_Pin | PWM_CH2_Pin; // 설정할 핀: GPIOA 핀 8, 7, 9
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 대체 기능, 푸시-풀
GPIO_InitStruct.Pull = GPIO_NOPULL; // 풀업/풀다운 저항 사용 안 함
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // 출력 속도: 고속
GPIO_InitStruct.Alternate = GPIO_AF1_TIM1; // PA8, PA7, PA9를 TIM1_CH1, CH1N, CH2로 설정
HAL_GPIO_Init(PWM_GPIO_Port_A, &GPIO_InitStruct); // GPIOA 핀 설정 적용
/*Configure GPIO pin : PB0 */
GPIO_InitStruct.Pin = PWM_CH2N_Pin; // 설정할 핀: GPIOB 핀 0 (CH2N)
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 대체 기능, 푸시-풀
GPIO_InitStruct.Pull = GPIO_NOPULL; // 풀업/풀다운 저항 사용 안 함
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // 출력 속도: 고속
GPIO_InitStruct.Alternate = GPIO_AF1_TIM1; // PB0를 TIM1_CH2N으로 설정
HAL_GPIO_Init(PWM_GPIO_Port_B, &GPIO_InitStruct); // GPIOB 핀 설정 적용
pwmStatus = 1; // PWM 초기화 성공 표시
}
/**
* @brief TIM1 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM1_Init(void)
{
TIM_OC_InitTypeDef sConfigOC = {0}; // 타이머 출력 비교 구조체 초기화
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0}; // 브레이크 및 데드타임 구조체 초기화
htim1.Instance = TIM1; // TIM1 선택
htim1.Init.Prescaler = 16; // 프리스케일러: 170 MHz / (16+1) = 10 MHz
htim1.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1; // 중앙 정렬 모드 1 (PWM Mode 2)
htim1.Init.Period = 99; // ARR: (99+1) / 10 MHz = 10 µs (100 kHz PWM)
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 클럭 분주 없음
htim1.Init.RepetitionCounter = 0; // 반복 카운터 비활성화
if (HAL_TIM_PWM_Init(&htim1) != HAL_OK) // TIM1 PWM 모드 초기화
{
Error_Handler(); // 초기화 실패 시 오류 처리
}
sConfigOC.OCMode = TIM_OCMODE_PWM2; // PWM 모드 2 (중앙 정렬)
sConfigOC.Pulse = 50; // 펄스 값: 50% 듀티 사이클 (50/100)
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; // 출력 극성: High
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; // 보완 출력 극성: High
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; // 빠른 모드 비활성화
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) // 채널 1 PWM 설정
{
Error_Handler(); // 설정 실패 시 오류 처리
}
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK) // 채널 2 PWM 설정
{
Error_Handler(); // 설정 실패 시 오류 처리
}
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE; // 런 모드 오프 상태 비활성화
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE; // 유휴 상태 비활성화
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF; // 락 레벨 비활성화
sBreakDeadTimeConfig.DeadTime = 100; // 데드타임: 100 ns (10 MHz 클럭 기준)
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE; // 브레이크 입력 비활성화
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH; // 브레이크 극성
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; // 자동 출력 비활성화
if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK) // 브레이크 및 데드타임 설정
{
Error_Handler(); // 설정 실패 시 오류 처리
}
pwmStatus = 1; // PWM 초기화 성공 표시
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
pwmStatus = 0xFFFF; // 오류 상태 설정
while (1) // 무한 루프에서 대기
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
while (1) // 어설션 오류 시 무한 루프
{
}
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
설명:
- 기능: TIM1 채널 1(PA8), 채널 1N(PA7), 채널 2(PA9), 채널 2N(PB0)에서 100 kHz PWM 신호를 PWM Mode 2로 출력, 50% 듀티 사이클, 100 ns 데드타임, 위상 천이(0~99)로 PSFB 스위치 제어.
- 설정: PWM 주파수 100 kHz (PSC=16, ARR=99), 듀티 사이클 50% (Pulse=50), PWM Mode 2, 데드타임 100 ns, 위상 천이 동적 조절.
- GPIO: GPIOA 핀 8, 7, 9 (TIM1_CH1, CH1N, CH2), GPIOB 핀 0 (TIM1_CH2N).
- 출력: PWM 파형은 PA8, PA7, PA9, PB0에서 상보적으로 출력, 채널 2에 위상 천이 적용.
- 클럭: HSE 8 MHz, PLL로 170 MHz SYSCLK.
6. 추가 고려 사항
- 주파수 선택: LLC 컨버터는 공진 주파수에 맞춰 100 kHz
500 kHz, PSFB는 50 kHz200 kHz 사용. - 데드타임: 스위치 단락 방지를 위해 필수, 100 ns는 일반적인 값.
- 피드백 제어: 실제 애플리케이션에서는 ADC로 출력 전압/전류를 모니터링하여 주파수 또는 위상 천이 동적 조절.
- 디버깅: 오실로스코프로 PWM 파형, 데드타임, 위상 천이 확인.
- 저전력: GPIO 속도 및 타이머 설정 최적화로 전력 소모 감소.
키워드: STM32G474, PWM, HAL API, STM32G4, DC-DC 컨버터, LLC Half-Bridge, LLC Full-Bridge, Phase-Shifted Full-Bridge, Advanced-Control 타이머, PWM Mode 2, 보완 출력, 데드타임, 위상 천이, STM32CubeIDE, STM32CubeMX, HSE 클럭, 디버깅