본문 바로가기
MCU/STM32

[STM32G474] PWM으로 전력변환 DC-DC 토폴로지별 PWM 생성 방법: HAL API 활용(1)

by linuxgo 2025. 8. 19.
반응형

1. STM32G474 PWM 및 DC-DC 컨버터 개요

STM32G474는 STMicroelectronics의 STM32G4 시리즈에 속하는 고성능 32비트 ARM Cortex-M4 마이크로컨트롤러로, 최대 170MHz로 동작하며 Advanced-Control 타이머(TIM1, TIM8)를 포함한 다양한 타이머 기능을 제공합니다. PWM(Pulse Width Modulation)은 DC-DC 컨버터(예: Buck, Boost, Buck-Boost)와 같은 전력변환 애플리케이션에서 스위칭 소자를 제어하는 데 필수적입니다. 이 문서에서는 STM32G474의 Advanced-Control 타이머를 HAL API로 사용하여 주요 DC-DC 컨버터 토폴로지(Buck, Boost, Buck-Boost)에 적합한 PWM 신호를 생성하는 방법을 상세히 다룹니다. 모든 예제 코드는 STM32CubeMX로 생성된 완전한 코드로 구성되며, STM32CubeIDE에서 실행 가능합니다. 각 코드에는 상세한 주석이 포함되어 있습니다.

PWM 모듈의 주요 특징

  • 타이머: Advanced-Control 타이머(TIM1, TIM8)는 PWM 출력, 보완 출력, 데드타임 삽입, 브레이크 입력을 지원.
  • 채널: 최대 4개의 PWM 채널(CH1CH4) 및 보완 출력(CH1NCH4N).
  • 모드: PWM Mode 1(에지 정렬), PWM Mode 2(중앙 정렬).
  • 분해능: 높은 PWM 분해능 제공(타이머 카운터 및 비교 레지스터).
  • 클럭: AHB/APB 클럭으로 동작, 저전력 모드 지원.
  • 고급 기능: 데드타임 삽입, 브레이크 입력, 반복 카운터.
  • DC-DC 컨버터 관련: 고주파 PWM(50 kHz~500 kHz), 보완 출력 및 데드타임은 H-브리지 또는 동기 정류에 적합.

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. Buck 컨버터

  •   특징: 입력 전압을 낮춰 출력. 단일 스위치(MOSFET) 사용.
  •   PWM 요구사항:
    •   단일 PWM 채널(예: TIM1_CH1).
    •   주파수: 50 kHz~500 kHz (효율 및 인덕터 크기에 따라 조정).
    •   PWM Mode 1(에지 정렬) 권장.
    •   듀티 사이클: 출력 전압(Vout) = 입력 전압(Vin) * 듀티 사이클(D).
    •   동기 정류 시 보완 출력 및 데드타임 필요.
  •   예제 설정: 100 kHz PWM, 초기 듀티 사이클 50%.

3.2. Boost 컨버터

  •   특징: 입력 전압을 높여 출력. 단일 스위치 사용.
  •   PWM 요구사항:
    •   단일 PWM 채널.
    •   주파수: 50 kHz~500 kHz.
    •   PWM Mode 1 권장.
    •   듀티 사이클: Vout = Vin / (1-D).
    •   동기 정류 시 보완 출력 및 데드타임 필요.
  •   예제 설정: 100 kHz PWM, 초기 듀티 사이클 50%.

3.3. Buck-Boost 컨버터

  •   특징: 입력 전압을 높이거나 낮춰 출력. H-브리지 또는 단일 스위치 사용.
  •   PWM 요구사항:
    •   H-브리지 사용 시 두 채널(예: TIM1_CH1, TIM1_CH2) 또는 보완 출력.
    •   주파수: 50 kHz~500 kHz.
    •   PWM Mode 2(중앙 정렬) 권장 (노이즈 감소).
    •   데드타임 필수 (H-브리지 단락 방지).
    •   듀티 사이클: Vout = Vin * D / (1-D).
  •   예제 설정: 100 kHz PWM, 초기 듀티 사이클 50%, 데드타임 100 ns.

4. PWM 설정 및 동작 원리

STM32G474의 PWM을 DC-DC 컨버터에 사용하려면 시스템 클럭, 타이머 설정, GPIO 설정, 디버깅 및 프로그램 다운로드 절차를 정확히 구성해야 합니다. 아래는 STM32CubeMX와 STM32CubeIDE를 사용한 설정 절차입니다.

4.1. STM32CubeMX 설정 절차

  1. 프로젝트 생성:
    •   STM32CubeMX에서 "New Project" 선택, "STM32G474" 검색, 패키지(예: LQFP64) 선택.
    •   프로젝트 이름 및 저장 경로 설정.
  2. 시스템 클럭 설정 (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.
  3. PWM 설정:
    •   "Timers" > "TIM1" 선택.
    •   Buck/Boost: Channel 1 (PA8)을 "PWM Generation CH1"로 설정, User Label: "PWM_OUT".
    •   Buck-Boost: Channel 1 (PA8, TIM1_CH1), Channel 2 (PA9, TIM1_CH2) 또는 보완 출력 (PA7, TIM1_CH1N).
    •   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 1 (Buck/Boost) 또는 PWM Mode 2 (Buck-Boost).
      •   Dead Time: 100 ns (Buck-Boost).
    •   GPIO: PA8, PA9, PA7 자동 설정, 속도 "High".
  4. 디버깅 인터페이스 설정:
    •   "System Core" > "SYS"에서 Debug를 "Serial Wire" (SWD)로 설정.
    •   SWD 핀: PA13 (SWDIO), PA14 (SWCLK).
  5. 프로젝트 설정 및 코드 생성:
    •   Project Manager:
      •   Toolchain/IDE: STM32CubeIDE.
      •   Code Generator: "Copy only the necessary library files".
    •   "Generate Code" 클릭.

4.2. PWM 동작 원리

  1. 시스템 초기화:
    •   시스템 클럭 170 MHz, GPIO 및 타이머 클럭 활성화.
    •   HAL_Init()으로 HAL 라이브러리 및 Systick 초기화.
  2. PWM 설정:
    •   TIM1 설정 (TIM_OC_InitTypeDef 구조체).
    •   Prescaler와 ARR로 주파수 설정 (예: 100 kHz).
    •   Compare Register(CCR)로 듀티 사이클 설정.
    •   보완 출력 및 데드타임 설정 (Buck-Boost).
  3. 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 파형 확인 (PA8, PA7, PA9).

5. PWM 예제 코드

아래는 STM32G474의 TIM1을 HAL API로 사용하여 DC-DC 컨버터 토폴로지별 PWM 신호를 생성하는 예제 코드입니다. 코드는 STM32CubeIDE에서 실행 가능하며, HSE 8 MHz로 170 MHz SYSCLK를 설정합니다.

5.1. 예제 1: Buck 컨버터 PWM (Mode 1)

TIM1 채널 1(PA8)에서 100 kHz PWM 신호를 PWM Mode 1로 출력, 듀티 사이클을 동적으로 변경.

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * STM32CubeMX-generated code for TIM1 Channel 1 (PA8) PWM output in Mode 1 for Buck converter.
  * PWM frequency: 100 kHz, initial duty cycle: 50%. Duty cycle changes dynamically.
  * 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_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를 PWM 출력으로 초기화
  MX_TIM1_Init(); // TIM1를 PWM Mode 1로 초기화
  /* USER CODE BEGIN 2 */
  HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); // TIM1 채널 1 PWM 출력 시작
  if (pwmStatus != 1) // PWM 초기화 성공 여부 확인
  {
    pwmStatus = 0xFFFF; // 초기화 실패 시 오류 상태 설정
    while (1); // 오류 발생 시 무한 루프
  }
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    // 듀티 사이클을 0%에서 100%로 점진적으로 변경 (Buck 컨버터 출력 전압 조절)
    for (pwmPulse = 0; pwmPulse <= 100; pwmPulse += 1)
    {
      __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, pwmPulse); // PWM 듀티 사이클 설정
      HAL_Delay(50); // 50ms 대기
    }
    for (pwmPulse = 100; pwmPulse >= 0; pwmPulse -= 1)
    {
      __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, pwmPulse); // PWM 듀티 사이클 설정
      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 포트 클럭 활성화

  /*Configure GPIO pin : PA8 */
  GPIO_InitStruct.Pin = PWM_Pin; // 설정할 핀: GPIOA 핀 8
  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을 TIM1_CH1로 설정
  HAL_GPIO_Init(PWM_GPIO_Port, &GPIO_InitStruct); // GPIOA 핀 8 설정 적용

  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_UP; // 업 카운터 모드 (PWM Mode 1)
  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_PWM1; // PWM 모드 1 (에지 정렬)
  sConfigOC.Pulse = 50; // 초기 펄스 값: 50% 듀티 사이클 (50/100)
  sConfigOC.OCPolarity = TIM_OCPOLARITY_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 = 0; // 데드타임 비활성화
  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)에서 100 kHz PWM 신호를 PWM Mode 1로 출력, 듀티 사이클을 0%에서 100%로 변경하여 Buck 컨버터 스위치 제어.
  • 설정: PWM 주파수 100 kHz (PSC=16, ARR=99), 초기 듀티 사이클 50% (Pulse=50), PWM Mode 1.
  • GPIO: GPIOA 핀 8 (TIM1_CH1).
  • 출력: PWM 파형은 PA8에서 출력, 듀티 사이클이 5초마다 0%에서 100%로 변화.
  • 클럭: HSE 8 MHz, PLL로 170 MHz SYSCLK.

5.2. 예제 2: Boost 컨버터 PWM (Mode 1)

TIM1 채널 1(PA8)에서 100 kHz PWM 신호를 PWM Mode 1로 출력, 듀티 사이클 동적 변경. (Buck과 유사하므로 코드 생략, 설정만 변경)

  • 설정 변경:
    • 동일한 100 kHz PWM (PSC=16, ARR=99).
    • 초기 듀티 사이클: 50% (Pulse=50).
    • PWM Mode 1, 단일 채널 (PA8, TIM1_CH1).
  • 설명: Boost 컨버터는 Vout = Vin / (1-D)로 동작, 듀티 사이클 증가 시 출력 전압 상승.

5.3. 예제 3: Buck-Boost 컨버터 PWM (Mode 2, 보완 출력)

TIM1 채널 1(PA8, TIM1_CH1) 및 보완 출력(PA7, TIM1_CH1N)에서 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 Channel 1 (PA8) and Complementary Channel 1N (PA7) PWM output in Mode 2 for Buck-Boost converter.
  * PWM frequency: 100 kHz, initial duty cycle: 50%, 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)
  {
    // 듀티 사이클을 0%에서 100%로 점진적으로 변경 (Buck-Boost 출력 전압 조절)
    for (pwmPulse = 0; pwmPulse <= 100; pwmPulse += 1)
    {
      __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, pwmPulse); // PWM 듀티 사이클 설정
      HAL_Delay(50); // 50ms 대기
    }
    for (pwmPulse = 100; pwmPulse >= 0; pwmPulse -= 1)
    {
      __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, pwmPulse); // PWM 듀티 사이클 설정
      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 포트 클럭 활성화

  /*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로 출력, 100 ns 데드타임 삽입. 듀티 사이클은 0%에서 100%로 변화.
  • 설정: 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에서 상보적으로 출력, 듀티 사이클이 5초마다 0%에서 100%로 변화.
  • 클럭: HSE 8 MHz, PLL로 170 MHz SYSCLK.

6. 추가 고려 사항

  • 주파수 선택: DC-DC 컨버터는 50 kHz~500 kHz 주파수 사용. 높은 주파수는 효율 감소, 낮은 주파수는 인덕터 크기 증가.
  • 데드타임: Buck-Boost 또는 동기 정류에서 단락 방지를 위해 필수.
  • 피드백 제어: 실제 애플리케이션에서는 ADC로 출력 전압/전류를 모니터링하여 듀티 사이클 동적 조절.
  • 디버깅: 오실로스코프로 PWM 파형 및 데드타임 확인.
  • 저전력: GPIO 속도 및 타이머 설정 최적화로 전력 소모 감소.

키워드: STM32G474, PWM, HAL API, STM32G4, DC-DC 컨버터, Buck, Boost, Buck-Boost, Advanced-Control 타이머, PWM Mode 1, PWM Mode 2, 보완 출력, 데드타임, STM32CubeIDE, STM32CubeMX, HSE 클럭, 디버깅

반응형