임베디드

15. HAL 드라이버 분석

sdafdq 2026. 2. 3. 20:10
	  if(!HAL_GPIO_ReadPin(GPIO_SW_GPIO_Port, GPIO_SW_Pin)){
		  HAL_GPIO_WritePin(GPIO_LED_GPIO_Port, GPIO_LED_Pin, 0);
	  }else {
		  HAL_GPIO_WritePin(GPIO_LED_GPIO_Port, GPIO_LED_Pin, 1);
	  }

이거를 HAL드라이버 없이 해볼거임.

 

HAL드라이버 없었다면,

데이터시트 보고 핀 16진수(2진수) 주소 보고 찾아가면서 그걸 제어 해야 됨. 나는 결국 그거를 라이브러리로 만들기는 할 듯.

 

임베디드가 코드는 몇 줄 안되는 데 그 코드를 이해하기가 오래걸림.

 

 

우선은, 

MX_GPIO_Init();

이거 분석 해보고, 핀 초기화 하는 거,

 

HAL_GPIO_WritePin(GPIO_LED_GPIO_Port, GPIO_LED_Pin, 0);

이 함수 분석 해볼거임.

 

 

 

그 전에,

  HAL_Init();

여기에 있는,

 

 

 

HAL_StatusTypeDef HAL_Init(void)
{
  /* Configure Flash prefetch */
#if (PREFETCH_ENABLE != 0)
#if defined(STM32F101x6) || defined(STM32F101xB) || defined(STM32F101xE) || defined(STM32F101xG) || \
    defined(STM32F102x6) || defined(STM32F102xB) || \
    defined(STM32F103x6) || defined(STM32F103xB) || defined(STM32F103xE) || defined(STM32F103xG) || \
    defined(STM32F105xC) || defined(STM32F107xC)

  /* Prefetch buffer is not available on value line devices */
  __HAL_FLASH_PREFETCH_BUFFER_ENABLE();
#endif
#endif /* PREFETCH_ENABLE */

  /* Set Interrupt Group Priority */
  HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

  /* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */
  HAL_InitTick(TICK_INT_PRIORITY);

  /* Init the low level hardware */
  HAL_MspInit();

  /* Return function status */
  return HAL_OK;
}

여기 중에서 

__HAL_FLASH_PREFETCH_BUFFER_ENABLE();

저 함수를 분석 해 볼거임.

define 함수 긴 함.

 

 

플래시 버퍼를 미리 가져올 수 있게 하는 그런..

 

 

소스분석 빨리 하는 법

1. 어떤 상황에서 돌아가는 지 이해

2. 소스가 돌아가는 환경 만들기

3. 디버깅 할 수 있는 환경 만들기

 

우선은 HAL_Init()부터 보면

 

HAL_StatusTypeDef HAL_Init(void)
{
  /* Configure Flash prefetch */
#if (PREFETCH_ENABLE != 0)
#if defined(STM32F101x6) || defined(STM32F101xB) || defined(STM32F101xE) || defined(STM32F101xG) || \
    defined(STM32F102x6) || defined(STM32F102xB) || \
    defined(STM32F103x6) || defined(STM32F103xB) || defined(STM32F103xE) || defined(STM32F103xG) || \
    defined(STM32F105xC) || defined(STM32F107xC)

  /* Prefetch buffer is not available on value line devices */
  __HAL_FLASH_PREFETCH_BUFFER_ENABLE();
#endif
#endif /* PREFETCH_ENABLE */

  /* Set Interrupt Group Priority */
  HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

  /* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */
  HAL_InitTick(TICK_INT_PRIORITY);

  /* Init the low level hardware */
  HAL_MspInit();

  /* Return function status */
  return HAL_OK;
}

만약 PREFETCH_ENABLE != 0, 즉 0이 아니라면 미리 가져오는 것을 허용 하는 것,

그리고 자기에 맞는 저 STM32 칩 리스트 내에 있는 거라면,

__HAL_FLASH_PREFETCH_BUFFER_ENABLE()를 실행.

뭔가 플래시 버퍼를 미리 가져오는 설정을 init 하는 느낌임.

 

 

#if defined(STM32F101x6)

이거는 STM32F101x6가 선언되어 있는지 검사하는거.

검사만 하는거임. 전처리기는 전역적인거니 저게 어딘가에서 선언이 됐었는지 검사.

defined() 이런 전처리기용 함수가 있음. 

더 정확히는 함수라기 보다는 연산, 지시문 이라고 함.

 

 

여튼, 

#define __HAL_FLASH_PREFETCH_BUFFER_ENABLE()    (FLASH->ACR |= FLASH_ACR_PRFTBE)

이게 실행되고, 앞에는 매크로 함수 선언이고 뒤에가 내용인데,

(FLASH->ACR |= FLASH_ACR_PRFTBE)
포인터이름->멤버변수이름 = 값

-> 이거는 구조체 접근자 라고 한다.

FLASH라는 구조체의 ACR이라는 값을 가리킴.

 

|=는 비트연산자.

| 하나만으로는 그냥 or.

1+5 같은 느낌으로 걍 값만 가져오는 거.

|=는 or해서 값을 넣는거.

 

FLASH->ACR

FLASH구조체의 ACR값과,

FLASH_ACR_PRFTBE값을 OR연산해서 그걸 다시 FLASH 구조체의 ACR에 넣는거.

 

 

그럼 FLASH, ACR, FLASH_ACR_PRFTBE는 뭘까.

 

우선 FLASH는 저장장치이고, 그 안에 여러 종류의 레지스터가 있는데, 

실제로

typedef struct
{
    volatile uint32_t ACR;
    volatile uint32_t KEYR;
    volatile uint32_t OPTKEYR;
    volatile uint32_t SR;
    volatile uint32_t CR;
    ...
} FLASH_TypeDef;

이런 식으로 정의되어 있다고 함.

 

그걸 여기서 ACR이라는 역할을 하는 저장공간의 시작주소를 가지고 오는거임.

ACR은

ACR = Access Control Register
플래시 메모리에 어떻게 접근할지를 설정하는 레지스터

 

FLASH_ACR_PRFTBE

이거는, 

Prefetch Buffer Enable 버퍼 미리 읽기 가능,

CPU가 FLASH에서 명령어를 더 빨리 읽게 해주는 “미리 읽기(프리패치)” 기능을 켜는 스위치

 

FLASH_ACR_PRFTBE 는
ACR 레지스터의 Prefetch Enable 비트를 가리키는 비트 마스크 상수다.

즉, ACR용 버퍼 미리 읽기 비트 위치.

실제로 비트는 32비트로 되어 있고,

실제로 값이,

0x00000010

0000 0000 0000 0000 0000 0000 0001 0000

이렇게 되어 있다고 함.

 

그래서 ACR도 아마 32비트일건데, 각 비트는 여러 옵션, 모드를 결정하고 있을테고, 그 중 한 비트만 저걸 OR시켜서 값을 켜는거임.

 

값을 주석으로 보기 쉽게 표시해놨네.

 

 

 

FLASH는 저기서 안따라가져서 컨트롤 H로 찾음.

ACR포함해서 구조체 나옴. 

그리고 HAL드라이버 쪽이 아니라 드라이버 정보니 드라이버쪽으로 들어가는.

 

#define FLASH               ((FLASH_TypeDef *)FLASH_R_BASE)

FLASH_R_BASE값을 FLASH_TypeDef의 주소로 형변환.

 

FLASH_R_BASE는 플래시 레지스터 기본값, 즉 플래시 레지스터의 가장 기본이 되는 값일테니까 그걸 시작주소로 놓고 

그 주소를 

#define FLASH               ((FLASH_TypeDef *)FLASH_R_BASE)

아예 플래시 구조체 주소로 형변환해서 

저 주소 (AHBPERIPH_BASE + 0x00002000UL) 자체에 접근하면 

저 플래스 구조체의 형태로 읽겠다는거임.

아마 저게 하드웨어상의 물리적인 주소일텐데, 그거를 소프트웨어로 그대로 옮겨오고 싶어서 이렇게 한 조치 같음.

 

 

AHBPERIPH_BASE   는,

AHB는 AHB = Advanced High-performance Bus

고급 고성능 버스,

PERIPH는 Peripheral 주변기기의 약자로,

저 고급 고성능 버스에 연결된 주변기기들의 가장 첫번째로 연결된 것의 시작 주소일 것임.

 

 

 

 

 

여튼 이렇게 어렵게 찾아봤는데,

 

이거를 대충 아 이런 거구나 하고 구조를 알겠다 싶으면, 

그냥 값을 보는 게 맘 편함.

 

 

 

 

걍 저기다 브레이크 포인트 걸고

 

저 FLASH 복사해서 저기 Expressions에 추가 하면 됨.

 

표현식은 일종의 인터프리터같은 느낌.

저렇게 문자열을 넣어보면, 변수중에 있는지 조회해서, 있으면 그 변수의 주소와 타입을 가져와서, 

메모리로가서 그 주소 조회해오고 값을 가져옴.

 

정말 간단하게 이렇게 볼 수 있음.

'임베디드' 카테고리의 다른 글

17. 데이터시트 보고 코드 확인  (0) 2026.02.04
16. 구조체  (0) 2026.02.04
14. GPIO 제어  (0) 2026.02.03
13. 프로젝트 생성  (0) 2026.02.03
12. 환경구축  (0) 2026.02.03