0. main 함수
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(); 기존 코드
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
//MX_GPIO_Init(); 기존 코드
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
volatile unsigned int * reg = 0x40021018;
*reg |= 16;
/* Infinite loop */
/* USER CODE BEGIN WHILE */
volatile unsigned int * reg2 = 0x40011004;
*reg2 = (*reg2 & ~(15UL << 20U)) | (3U << 20U);
volatile unsigned int * reg3 = 0x40011010;
while (1)
{
*reg3 = 0x2000;
HAL_Delay(100);
*reg3 = (0x2000 << 16);
HAL_Delay(100);
/*HAL_GPIO_WritePin(GPIO_LED_GPIO_Port, GPIO_LED_Pin, 1);
HAL_Delay(100);
HAL_GPIO_WritePin(GPIO_LED_GPIO_Port, GPIO_LED_Pin, 0);
HAL_Delay(100);
*/
/*
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_Delay(100);
*/
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
1. HAL 드라이버 분석 방법
: HAL_GPIO_WritePin(); 함수를 이용하지 않고 나의 코드로 어떻게 구현?
: 데이터 시트를 보고 해당하는 번지수 찾아서 하나하나씩 제어해야함 (소스 코드는 정작 5~6줄 but 그 과정이 매우 어려움)
: 우리는 파일 드라이브에 쓰여진 코드를 분석하며 어떤 코드인지 분석하고 그 코드 토대로 데이터시트 보면서 필요한것만 뽑아서 코드 작성
1-0. 코드 분석할 때 빨리 하는 방법
- 소스가 어떤 환경에서 돌아가는지 이해
- 소스가 돌아갈 수 있는 환경 만들기
- 디버깅 할 수 있는 단계 만들기 (디버깅을 하면서 코드 분석해야함)
ex) __HAL_FLASH_PREFETCH_BUFFER_ENABLE(); 함수 분석해보기 (HAL_Init함수)
#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
- 칩에 따라 속성을 바꾸기 위한 #define문 코드 (우리꺼는 STM32F103xB)
- 이 칩들 중에 하나 속하면 아래 __HAL_FLASH_PREFETCH_BUFFER_ENABLE(); 수행
- ctrl + 왼쪽 마우스로 함수 클릭하면 아래 사진과 같이 동작 수행

- FLASH 분석하기 위해 FLASH도 ctrl + 왼쪽 마우스 클릭

- FLASH는 ((FLASH_TypeDef *) FLASH_R_BASE)로 정의되어 있음을 알 수 있음

- 디버깅하면서 Expression창에서 FLASH를 검색하면 위 사진과 같이 0x40022000 번지를 접근하는 것을 알 수 있음
- 이때, 맨 처음 코드는 (FLASH->ACR |= FLASH_ACR_PRFTBE)이었기에 FLASH->ACR을 검색하면 동일하게 0x40022000이고 FLASH_ACR_PRFTBE와 or연산하기에 얘도 검색해보면 아래 사진과 같이 16임을 알 수 있다

결론.
#define __HAL_FLASH_PREFETCH_BUFFER_ENABLE() (FLASH->ACR |= FLASH_ACR_PRFTBE)은,
*(0x40022000) |= 16;과 같다.
1-1. FLASH_TypeDef에 더 깊이 분석해보기
: FLASH는 ((FLASH_TypeDef *) FLASH_R_BASE)로 정의되어있음
: FLASH->ACR = 40022000번지에 접근
: FLASH->KEYR = 40022004번지에 접근
...

- 0번지부터 시작한다고 가정한다면,
- 0 ACR
- 4 KEYR
- 8 OPTKEYR
- 12 SR
- 16 CR
- 20 AR
- 24 RESERVED
- 28 OBR
- 32 WRPR
=> FLASH라는 공간이 큰 덩어리로 있고 그 안에 각각의 레지스터 이름을 설정하여 구조체화한 것
(1) __IO는 무엇을 의미?
: #define __IO volatile로 정의되어있음
: 'volatile'은 휘발성을 뜻하여, 최적화 방지 위해 씀
cf. 컴파일러는 최적화라는 것을 한다.
ex)
int a = 3;
a = 7;
a = 8;
a = 12;
printf("%d\n", a); 라는 코드를 보면,
↓
int a = 12;
printf("%d\n", a); 로 최적화
BUT, GPIO 제어과정에서 스위치를 껐다키는 과정을 반복하기위해
*a = 0x03;
*a |= 1;
*a |= 0;
*a |= 1;
*a |= 0;
↓
*a = 0x03;
*a |= 0;로 최적화한다면 내가 원했던 코드가 되지않음
+ 이외에도, 자주 사용하는 변수의 값이 있다면 메모리가 아닌 cpu 레지스터 내에 저장하는 경우 존재
결론.
__IO는 volatile로 정의되어있고 이 의미는 "최적화 하지마 + 자주 사용하는 값이라고 cpu 레지스터에 넣지마"
= " 최적화하지말고 무조건 메모리에 올려서 사용해"
(FLASH->ACR |= FLASH_ACR_PRFTBE) 은,
volatile unsigned int * reg = 0x40022000;
* reg |= 16;과 같다
(2) 16의 의미에 대해 알아보자.

=> 결론적으로, (0x1UL << FLASH_ACR_PRFTBE_Pos)인데 이때 FLASH_ACR_PRFTBE_Pos는 4U로 정의되어있다.
=> 1 << 4;
=> 16
2. 데이터시트를 통해 코드 확인

- FLASH_ACR을 다루려면 0x4002 2000번지로 접근
- 이때, 아까 정의되어있던 구조체 구조(순서) 동일
- 좀 더 살펴보면, 아래 사진과 같이 정의되어있음
- 프리패치 & 하프 사이클 액세스를 활성/비활성화하는 레지스터
- 떠올려보니 함수명이 __HAL_FLASH_PREFETCH_BUFFER_ENABLE()


- 우리는 FLASH_ACR |= 16;을 했는데 이 말은 즉슨, 4bit를 왼쪽으로 옮긴것
- 이때, Bit 4 PRFTBE: Prefetch buffer enable로 정의되어있고 1은 Prefetch is enabled임
결론.
__HAL_FLASH_PREFETCH_BUFFER_ENABLE();
↓
#define __HAL_FLASH_PREFETCH_BUFFER_ENABLE() (FLASH->ACR |= FLASH_ACR_PRFTBE)
↓
*(0x40022000) |= 16;
↓
플래시 메모리의 프리패치 기능을 활성화한 것
2-1. 프리패치란?
: SSD 보급 전 HDD를 읽는 속도를 높이기 위해 HDD의 데이터를 미리 메모리(RAM)에 가져오는 기술
윈도우 부팅시 사용하는 시스템 파일과 자주 사용하는 응용 프로그램들의 정보 등을 먼저 읽어들여서 부팅이나 프로그램을 빠르게 실행되도록 도와주는 기능
: CPU가 명령어를 실행하기 전에 Flash 메모리에서 데이터를 미리 읽어와 속도를 향상시키는 기능
cf. OS는 주기억장치(RAM)에 저장하고 전원 끄면 데이터 사라지기에, 보조기억장치(HDD/SDD)에 저장
=> 부팅시 보조기억장치에 있는 메모리가 RAM으로 복사되어 그 복사된 OS를 CPU가 실행시키는 것임
'임베디드' 카테고리의 다른 글
[오제이 튜브의 임베디드 강의] 8강. GPIO제어 고아먹기 (0) | 2025.01.07 |
---|---|
[오제이 튜브의 임베디드 강의] 7강. GPIO제어 부셔먹기 (0) | 2025.01.06 |
[오제이 튜브의 임베디드 강의] 5강. 환경 구축해보기 (1) | 2025.01.02 |
[오제이 튜브 임베디드 강의] 4강. 전기 기본 상식 (1) | 2025.01.01 |
[오제이 튜브의 임베디드 강의] 3강. 실무자는 어떻게 칩을 고르나요? (0) | 2025.01.01 |