1. STM32G474 GPIO 개요
STM32G474는 STMicroelectronics의 STM32G4 시리즈에 속하는 고성능 32비트 ARM Cortex-M4 마이크로컨트롤러로, 최대 170MHz로 동작하며 다양한 GPIO 포트를 제공합니다. GPIO(General Purpose Input/Output) 모듈은 디지털 입력/출력, 인터럽트, 아날로그 입력으로 사용될 수 있습니다. 이 문서에서는 STM32G474의 GPIO를 HAL API를 사용하여 설정하고 사용하는 방법을 상세히 다룹니다. 모든 예제 코드는 STM32CubeMX로 생성된 완전한 코드로 구성되며, STM32CubeIDE에서 실행 가능합니다. 각 코드에는 상세한 주석이 포함되어 있습니다.
GPIO 모듈의 주요 특징
- 포트와 핀: STM32G474는 여러 GPIO 포트(GPIOA, GPIOB, ..., GPIOH)를 제공하며, 각 포트는 최대 16개의 핀을 가짐.
- 모드: 입력, 출력, 아날로그 모드 지원.
- 출력 타입: 푸시-풀(Push-Pull), 오픈 드레인(Open-Drain).
- 풀업/풀다운: 내부 풀업/풀다운 저항 설정 가능.
- 속도: Low, Medium, High, Very High 속도 설정.
- 인터럽트: 외부 인터럽트(EXTI)로 이벤트 감지 가능.
- 클럭: AHB2 클럭을 통해 동작하며, 저전력 모드 지원.
HAL API는 하드웨어 레지스터 직접 조작 대신 추상화된 함수를 제공하여 GPIO 설정을 간소화합니다.
2. 주요 GPIO HAL API 함수
2.1. GPIO 초기화 및 설정 함수
- HAL_GPIO_Init(GPIO_TypeDef GPIOx, GPIO_InitTypeDef GPIO_Init)**
- 설명: GPIO 핀의 모드, 풀업/풀다운, 속도, 출력 타입 등을 설정.
- 매개변수: GPIOx (GPIO 포트), GPIO_Init (설정 구조체).
- 사용 예: GPIOA의 핀 5를 출력, 푸시-풀, 고속으로 설정.
- HAL_GPIO_DeInit(GPIO_TypeDef GPIOx, uint32_t GPIO_Pin)*
- 설명: GPIO 핀을 기본 상태로 초기화.
- HAL_GPIO_WritePin(GPIO_TypeDef GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)*
- 설명: GPIO 핀의 출력 상태 설정 (HIGH 또는 LOW).
- 매개변수: PinState (GPIO_PIN_SET 또는 GPIO_PIN_RESET).
- HAL_GPIO_ReadPin(GPIO_TypeDef GPIOx, uint16_t GPIO_Pin)*
- 설명: GPIO 핀의 입력 상태 읽기.
- 반환값: GPIO_PinState (GPIO_PIN_SET 또는 GPIO_PIN_RESET).
2.2. 인터럽트 관련 함수
- HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
- 설명: 외부 인터럽트 핸들러.
- HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
- 설명: 사용자 정의 인터럽트 콜백 함수 (약한 링크로 정의, 오버라이드 필요).
- HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority)
- 설명: 인터럽트 우선순위 설정.
- HAL_NVIC_EnableIRQ(IRQn_Type IRQn)
- 설명: 인터럽트 활성화.
3. GPIO 설정 및 동작 원리
STM32G474의 GPIO를 효과적으로 사용하려면 시스템 클럭, GPIO 설정, 디버깅 및 프로그램 다운로드 절차를 정확히 구성해야 합니다. 아래는 STM32CubeMX와 STM32CubeIDE를 사용한 설정 절차와 동작 원리를 상세히 설명합니다.
3.1. STM32CubeMX 설정 절차
STM32CubeMX를 사용하여 GPIO, 시스템 클럭, 디버깅 인터페이스를 설정하는 단계는 다음과 같습니다:
- 프로젝트 생성:
- STM32CubeMX를 열고 "New Project"를 선택.
- MCU 선택 창에서 "STM32G474"를 검색하고, 사용하는 패키지(예: LQFP64)를 선택.
- 프로젝트 이름을 지정하고 저장 경로 설정.
- 시스템 클럭 설정 (최대 170 MHz, HSE 사용):
- Pinout & Configuration 탭에서 "System Core" > "RCC"를 선택.
- "HSE"를 "Crystal/Ceramic Resonator"로 설정 (외부 8 MHz 크리스털 가정).
- Clock Configuration 탭으로 이동.
- HSE를 8 MHz로 입력.
- PLL Source Mux를 "HSE"로 설정.
- PLL 설정: PLLM = 1, PLLN = 85, PLLR = 2, PLLR Enable 활성화.
- System Clock Mux를 "PLLCLK"로 설정.
- 결과: SYSCLK = (8 MHz / 1) * 85 / 2 = 340 / 2 = 170 MHz.
- HCLK (AHB), PCLK1 (APB1)을 170 MHz로 설정 (Divider = 1).
- Flash Latency를 4 WS로 설정 (170 MHz 동작 시 권장).
- 클럭 트리에서 에러가 없음을 확인.
- GPIO 설정:
- Pinout & Configuration 탭에서 사용할 핀을 설정.
- 예제 1 (LED 토글): GPIOA Pin 5를 "GPIO_Output"으로 설정, User Label을 "LED"로 지정, 속도를 "Medium"으로 설정.
- 예제 2 (버튼 인터럽트): GPIOA Pin 5를 "GPIO_Output" (LED), GPIOC Pin 13을 "GPIO_EXTI13"으로 설정, Pull-up 활성화.
- 예제 3 (ADC): GPIOA Pin 0를 "GPIO_Analog"로 설정.
- 각 핀의 설정 (Mode, Pull, Speed 등)은 예제 코드와 일치해야 함.
- Pinout & Configuration 탭에서 사용할 핀을 설정.
- ADC 설정 (예제 3):
- "Analog" > "ADC1"을 활성화.
- Parameter Settings에서:
- Resolution: 12-bit.
- Continuous Conversion Mode: Enable.
- Clock Prescaler: Asynchronous clock mode, divider 1.
- Regular Channel에서 Channel 1 (PA0)을 선택, Sampling Time을 247.5 Cycles로 설정.
- 디버깅 인터페이스 설정:
- "System Core" > "SYS"에서 Debug를 "Serial Wire" (SWD)로 설정.
- SWD 핀 (PA13: SWDIO, PA14: SWCLK)이 자동으로 예약됨.
- 프로젝트 설정 및 코드 생성:
- Project Manager 탭에서:
- Project Name과 저장 경로 확인.
- Toolchain/IDE를 "STM32CubeIDE"로 설정.
- Code Generator 옵션에서 "Copy only the necessary library files" 선택.
- "Generate Code"를 클릭하여 프로젝트 파일 생성.
- Project Manager 탭에서:
3.2. GPIO 동작 원리
- 시스템 초기화:
- 시스템 클럭을 170 MHz로 설정하고, GPIO 클럭을 활성화 (__HAL_RCC_GPIOx_CLK_ENABLE()).
- HAL 라이브러리와 시스템 타이머(Systick) 초기화 (HAL_Init()).
- GPIO 설정:
- GPIO_InitTypeDef 구조체를 사용하여 모드(입력, 출력, 아날로그), 풀업/풀다운, 속도 등을 설정.
- HAL_GPIO_Init 함수로 설정 적용.
- 인터럽트 설정 (예제 2):
- EXTI 라인을 설정하고 NVIC 인터럽트를 활성화 (HAL_NVIC_SetPriority, HAL_NVIC_EnableIRQ).
- 사용자 콜백 함수 (HAL_GPIO_EXTI_Callback)를 오버라이드하여 인터럽트 처리.
- GPIO 동작:
- 출력: HAL_GPIO_WritePin 또는 HAL_GPIO_TogglePin으로 핀 상태 제어.
- 입력: HAL_GPIO_ReadPin으로 상태 읽기 또는 인터럽트 처리.
- 아날로그: ADC를 통해 아날로그 값 읽기 (HAL_ADC_PollForConversion).
3.3. 디버깅 설정 절차 (STM32CubeIDE)
- 디버그 인터페이스 연결:
- STM32G474 보드와 ST-LINK 디버거를 연결 (SWDIO: PA13, SWCLK: PA14, GND, 3.3V).
- STM32CubeIDE에서 프로젝트를 열고, "Run" > "Debug Configurations" 선택.
- 디버그 구성:
- "STM32 Cortex-M MCU Debugging"에서 새 구성 생성.
- Debugger 탭에서:
- Debug Probe: ST-LINK (OpenOCD).
- Interface: Serial Wire (SWD).
- "Enable" 체크.
- Startup 탭에서:
- "Load image"와 "Load symbols" 활성화.
- 생성된 .elf 파일 경로 확인.
- "Apply" 후 "Debug" 클릭.
- 디버깅 기능 사용:
- 브레이크포인트 설정: main.c에서 원하는 코드 라인에 더블 클릭.
- 변수 모니터링: "Expressions" 또는 "Variables" 창에서 gpioStatus, adcValue 등 확인.
- 디버깅 실행: "Resume" (F8), "Step Over" (F6), "Step Into" (F5)로 코드 실행 제어.
- LED 상태 또는 ADC 값을 실시간으로 확인.
3.4. 프로그램 다운로드 절차 (STM32CubeIDE)
- 프로그램 빌드:
- STM32CubeIDE에서 프로젝트를 열고 "Project" > "Build Project" 클릭.
- 빌드 오류가 없음을 확인 (Console 창 확인).
- 프로그램 다운로드:
- ST-LINK 디버거가 연결된 상태에서 "Run" > "Run Configurations" 선택.
- "STM32 Cortex-M MCU"에서 새 구성 생성.
- Main 탭에서 .elf 파일 선택 확인.
- "Run" 클릭하여 프로그램을 STM32G474에 다운로드.
- 다운로드 완료 후, 보드가 자동으로 리셋되고 프로그램 실행.
- 검증:
- 예제 1: LED가 1초 간격으로 점멸.
- 예제 2: 버튼 누름 시 LED 토글.
- 예제 3: ADC 값이 adcValue 변수에 저장됨 (디버깅으로 확인).
4. GPIO 예제 코드
아래는 STM32G474의 GPIO를 HAL API로 제어하는 완전한 STM32CubeMX 생성 예제 코드입니다. 각 코드는 STM32CubeIDE에서 바로 실행 가능하며, 외부 HSE 클럭(8 MHz)을 사용하여 시스템 클럭을 170 MHz로 설정합니다. STM32CubeMX에서 생성된 주석은 그대로 유지되며, 나머지 코드에는 상세한 한글 주석이 추가되었습니다.
4.1. 예제 1: 기본 GPIO 출력 (LED 토글)
GPIOA 핀 5를 사용하여 LED를 1초 간격으로 토글합니다.
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* STM32CubeMX-generated code for GPIOA Pin 5 (LED toggle).
* LED toggles every 1 second. 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 */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define LED_Pin GPIO_PIN_5 // GPIOA 핀 5를 LED로 사용
#define LED_GPIO_Port GPIOA // LED가 연결된 GPIO 포트
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
volatile uint32_t gpioStatus = 0; // GPIO 상태 변수: 0 (초기화 완료), 1 (동작 중), 0xFFFF (오류)
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void); // 시스템 클럭 설정 함수 선언
static void MX_GPIO_Init(void); // GPIO 초기화 함수 선언
/* 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 핀 5를 출력 모드로 초기화
/* USER CODE BEGIN 2 */
if (gpioStatus != 1) // GPIO 초기화 성공 여부 확인
{
gpioStatus = 0xFFFF; // 초기화 실패 시 오류 상태 설정
while (1); // 오류 발생 시 무한 루프
}
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); // LED 핀 상태를 토글 (ON/OFF 전환)
HAL_Delay(1000); // 1초 대기 (1000ms)
/* 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 Output Level */
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET); // LED 핀 초기 상태를 LOW로 설정
/*Configure GPIO pin : PA5 */
GPIO_InitStruct.Pin = LED_Pin; // 설정할 핀: GPIOA 핀 5
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 출력 모드, 푸시-풀
GPIO_InitStruct.Pull = GPIO_NOPULL; // 풀업/풀다운 저항 사용 안 함
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM; // 출력 속도: 중속
HAL_GPIO_Init(LED_GPIO_Port, &GPIO_InitStruct); // GPIO 설정 적용
gpioStatus = 1; // GPIO 초기화 성공 표시
}
/* 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 */
gpioStatus = 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 */
설명:
- 기능: GPIOA 핀 5로 LED를 1초 간격으로 토글.
- 설정: 푸시-풀 출력, 중속, 풀업/풀다운 없음.
- GPIO: GPIOA 핀 5 (LED).
- 출력: LED가 1초마다 ON/OFF 전환.
- 클럭: HSE 8 MHz, PLL로 170 MHz SYSCLK.
4.2. 예제 2: GPIO 입력 및 인터럽트 (버튼 입력)
GPIOC 핀 13(사용자 버튼)을 입력으로 설정하고, 버튼 누름 시 LED(GPIOA 핀 5)를 토글합니다.
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* STM32CubeMX-generated code for button interrupt on GPIOC Pin 13 to toggle LED on GPIOA Pin 5.
* 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 */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define LED_Pin GPIO_PIN_5 // GPIOA 핀 5를 LED로 사용
#define LED_GPIO_Port GPIOA // LED가 연결된 GPIO 포트
#define BUTTON_Pin GPIO_PIN_13 // GPIOC 핀 13을 버튼 입력으로 사용
#define BUTTON_GPIO_Port GPIOC // 버튼이 연결된 GPIO 포트
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
volatile uint32_t gpioStatus = 0; // GPIO 상태 변수: 0 (초기화 완료), 1 (동작 중), 0xFFFF (오류)
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void); // 시스템 클럭 설정 함수 선언
static void MX_GPIO_Init(void); // GPIO 초기화 함수 선언
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) // 외부 인터럽트 콜백 함수
{
if (GPIO_Pin == BUTTON_Pin) // 인터럽트가 버튼 핀(GPIOC 핀 13)에서 발생했는지 확인
{
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); // LED 상태 토글 (ON/OFF 전환)
gpioStatus = 1; // 동작 상태 업데이트
}
}
/* 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 핀 5(출력) 및 GPIOC 핀 13(인터럽트 입력) 초기화
/* USER CODE BEGIN 2 */
if (gpioStatus != 1) // GPIO 초기화 성공 여부 확인
{
gpioStatus = 0xFFFF; // 초기화 실패 시 오류 상태 설정
while (1); // 오류 발생 시 무한 루프
}
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if (gpioStatus == 0xFFFF) // 오류 상태 확인
{
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET); // 오류 시 LED 끄기
}
/* 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_GPIOC_CLK_ENABLE(); // GPIOC 포트 클럭 활성화
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET); // LED 핀 초기 상태를 LOW로 설정
/*Configure GPIO pin : PA5 */
GPIO_InitStruct.Pin = LED_Pin; // 설정할 핀: GPIOA 핀 5
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 출력 모드, 푸시-풀
GPIO_InitStruct.Pull = GPIO_NOPULL; // 풀업/풀다운 저항 사용 안 함
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM; // 출력 속도: 중속
HAL_GPIO_Init(LED_GPIO_Port, &GPIO_InitStruct); // GPIOA 핀 5 설정 적용
/*Configure GPIO pin : PC13 */
GPIO_InitStruct.Pin = BUTTON_Pin; // 설정할 핀: GPIOC 핀 13
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; // 인터럽트 모드, 하강 에지 트리거
GPIO_InitStruct.Pull = GPIO_PULLUP; // 내부 풀업 저항 활성화
HAL_GPIO_Init(BUTTON_GPIO_Port, &GPIO_InitStruct); // GPIOC 핀 13 설정 적용
/* EXTI interrupt init */
HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0); // EXTI15_10 인터럽트 우선순위 설정
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); // EXTI15_10 인터럽트 활성화
gpioStatus = 1; // GPIO 초기화 성공 표시
}
/* 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 */
gpioStatus = 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 */
설명:
- 기능: GPIOC 핀 13 버튼 누름 시 GPIOA 핀 5 LED 토글.
- 설정: 버튼은 하강 에지 인터럽트, 풀업 저항 사용.
- GPIO: GPIOA 핀 5 (LED), GPIOC 핀 13 (버튼).
- 출력: 버튼 누름마다 LED ON/OFF 전환.
- 클럭: HSE 8 MHz, PLL로 170 MHz SYSCLK.
4.3. 예제 3: 아날로그 입력 (ADC 트리거용 GPIO)
GPIOA 핀 0를 아날로그 입력으로 설정하여 ADC1을 통해 전압을 읽습니다.
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* STM32CubeMX-generated code for ADC1 with GPIOA Pin 0 as analog input.
* 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 */
ADC_HandleTypeDef hadc1; // ADC1 핸들러 구조체
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
volatile uint32_t gpioStatus = 0; // GPIO 상태 변수: 0 (초기화 완료), 1 (동작 중), 0xFFFF (오류)
volatile uint16_t adcValue = 0; // ADC 변환 값 저장 변수
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void); // 시스템 클럭 설정 함수 선언
static void MX_GPIO_Init(void); // GPIO 초기화 함수 선언
static void MX_ADC1_Init(void); // ADC1 초기화 함수 선언
/* 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 핀 0를 아날로그 모드로 초기화
MX_ADC1_Init(); // ADC1 초기화
/* USER CODE BEGIN 2 */
HAL_ADC_Start(&hadc1); // ADC 변환 시작
if (gpioStatus != 1) // GPIO 및 ADC 초기화 성공 여부 확인
{
gpioStatus = 0xFFFF; // 초기화 실패 시 오류 상태 설정
while (1); // 오류 발생 시 무한 루프
}
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if (HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK) // ADC 변환 완료 확인 (최대 10ms 대기)
{
adcValue = HAL_ADC_GetValue(&hadc1); // 변환된 ADC 값 읽기
}
HAL_Delay(100); // 100ms 대기 후 다음 변환
/* 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 ADC1 Initialization Function
* @param None
* @retval None
*/
static void MX_ADC1_Init(void)
{
ADC_ChannelConfTypeDef sConfig = {0}; // ADC 채널 설정 구조체 초기화
/** Common config
*/
hadc1.Instance = ADC1; // ADC1 선택
hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1; // ADC 클럭 분주기: 비동기 클럭, 분주 없음
hadc1.Init.Resolution = ADC_RESOLUTION_12B; // 12비트 해상도 설정
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; // 데이터 오른쪽 정렬
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE; // 스캔 모드 비활성화 (단일 채널)
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; // 단일 변환 완료 시 EOC 플래그 설정
hadc1.Init.ContinuousConvMode = ADC_CONTINUOUS_ENABLE; // 연속 변환 모드 활성화
if (HAL_ADC_Init(&hadc1) != HAL_OK) // ADC 초기화
{
Error_Handler(); // 초기화 실패 시 오류 처리
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_1; // ADC 채널 1 (GPIOA 핀 0) 선택
sConfig.Rank = ADC_REGULAR_RANK_1; // 첫 번째 채널로 설정
sConfig.SamplingTime = ADC_SAMPLETIME_247CYCLES_5; // 샘플링 시간: 247.5 사이클
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) // 채널 설정 적용
{
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 : PA0 */
GPIO_InitStruct.Pin = GPIO_PIN_0; // 설정할 핀: GPIOA 핀 0
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; // 아날로그 모드 설정
GPIO_InitStruct.Pull = GPIO_NOPULL; // 풀업/풀다운 저항 사용 안 함
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // GPIOA 핀 0 설정 적용
gpioStatus = 1; // GPIO 초기화 성공 표시
}
/* 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 */
gpioStatus = 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 */
설명:
- 기능: GPIOA 핀 0를 아날로그 입력으로 사용하여 ADC1로 전압 읽기.
- 설정: GPIOA 핀 0은 아날로그 모드, ADC1은 12비트, 연속 변환.
- GPIO: GPIOA 핀 0 (ADC 입력).
- 출력: ADC 변환 결과는 adcValue 변수에 저장.
- 클럭: HSE 8 MHz, PLL로 170 MHz SYSCLK.
5. 추가 고려 사항
- 클럭 설정: STM32CubeMX로 HSE 8 MHz를 사용하여 170 MHz SYSCLK 구성. 실제 보드의 HSE 주파수(예: 8 MHz 또는 25 MHz)에 따라 PLL 설정 조정 필요.
- GPIO 모드: 아날로그 모드는 ADC 사용 시 필수.
- 인터럽트: EXTI 라인은 핀 번호에 따라 공유되므로, NVIC 우선순위 설정 주의.
- 디버깅: SWD 인터페이스와 ST-LINK를 사용하여 실시간 변수 모니터링 및 브레이크포인트 설정.
- 저전력: GPIO 설정 시 풀업/풀다운 및 속도를 최적화하여 전력 소모 감소.
키워드: STM32G474, GPIO, HAL API, STM32G4, 마이크로컨트롤러, STM32CubeIDE, STM32CubeMX, LED 토글, 버튼 인터럽트, ADC, HSE 클럭, 디버깅
'MCU > STM32' 카테고리의 다른 글
[STM32G474] 타이머 트리거 사용법: HAL API로 타이머 트리거 설정 및 코드 예제 (0) | 2025.08.19 |
---|---|
[STM32G474] 타이머 사용법: HAL API로 타이머 설정 및 코드 예제 (0) | 2025.08.19 |
[STM32G474] I2C, SPI 사용법: HAL API로 설정 및 코드 예제 (0) | 2025.08.19 |
[STM32G474] UART 사용법: HAL API로 UART 설정 및 코드 예제 (0) | 2025.08.19 |
[STM32] 링커 스크립트: 상세 설명, 구조, 작성 방법 및 예제 (STM32 Linker Script: Detailed Explanation, Structure, Writing Methods, and Examples) (3) | 2025.08.18 |
[ STM32]STM32L432KC로 Modbus RTU Slave 코드 구현: DMA와 저전력 최적화 (0) | 2025.08.13 |
[STM32G474] 를 이용한 동일 어드레스를 갖는 64채널 I2C 디바이스 제어 (0) | 2025.08.12 |
[STM32H503RB] 로 I3C 프로토콜 구현: 초보자를 위한 상세 가이드 (0) | 2025.08.10 |