__HAL_RCC_GPIOx_LK_ENABLE 그리고 HAL_GPIO_WritePin

김지성·2022년 7월 6일
1

Embedded

목록 보기
3/19

1.1 __HAL_RCC_GPIOx_LK_ENABLE

__HAL_RCC_GPIOC_LK_ENABLE();			//LED가 PORTC의 13번핀으로 설정되있음.
#define __HAL_RCC_GPIOC_CLK_ENABLE()   do { \
                                        __IO uint32_t tmpreg; \
                                              SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPCEN);\
                                        /* Delay after an RCC peripheral clock enabling */\
                                        tmpreg = READ_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPCEN);\
                                        UNUSED(tmpreg); \
                                      } while(0U)

MX_GPIO_Init()을 따라간다음 HAL_RCC_GPIOC_LK_ENABLE()을 따라가보면 위와 같은 소스가 나온다.

GPIOC의 CLK을 ENABLE시켜주기 위해 필요한 소스는 아래와 같다.
( RCC->APB2ENR = *(40021000).APB2ENR )

#define SET_BIT(REG, BIT)     ((REG) |= (BIT))

SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPCEN);\

결과적으로 SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPCEN);을 숫자로 표현하면 아래와 같다.

RCC->APB2ENR = REG = (pointer)(0x40021018)
RCC_APB2ENR_IOPCEN = BIT = 16


결과적으로 다음과 같이 표현할 수 있다.
(pointer)(0x40021018) |= 16


1을 왼쪽으로 4번 쉬프트하면 IOPCEN이 1로 SET되는걸 알 수 있다. 그림에서 보다시피 1로 SET된다면 I/O port C Clock이 enabled되는걸 확인할 수 있다.

1.2 HAL_GPIO_WritePin

HAL_GPIO_WritePin(GPIO_LED_GPIO_Port, GPIO_LED_Pin, GPIO_PIN_SET)
void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
{ 
  /* Check the parameters */
  assert_param(IS_GPIO_PIN(GPIO_Pin)); 				//assert_param는 작동안함
  assert_param(IS_GPIO_PIN_ACTION(PinState));		//assert_param는 작동안함

  if (PinState != GPIO_PIN_RESET)
  {
    GPIOx->BSRR = GPIO_Pin;
  }
  else
  {
    GPIOx->BSRR = (uint32_t)GPIO_Pin << 16u;
  }
}

MX_GPIO_Init()을 따라간다음 HAL_GPIO_WritePin()를 따라가보면 위와 같은 소스가 나온다. 실질적으로 HAL_GPIO_WritePin을 작동시키는 소스는 아래와 같다.

  if (PinState != GPIO_PIN_RESET)
  {
    GPIOx->BSRR = GPIO_Pin;
  }
  else
  {
    GPIOx->BSRR = (uint32_t)GPIO_Pin << 16u;
  }

1) PinState != GPIO_PIN_RESET에서 GPIO_PIN_RESET은 0으로 define되어 있다. "!="연산에 의하여 PinState가 1일 경우 결과가 참으로 나오기 때문에 if문이 실행되고, PinState가 0일 경우 결과가 거짓으로 나오므로 else문이 실행될 것이다.

if (PinState != GPIO_PIN_RESET)
else

2)

GPIO_Pin = GPIO_LED_PIN = 8192(= 1<<13)
*GPIOx = GPIO_LED_GPIO_Port = 0x40011000

GPIOx_BSRR와 관련된 레퍼런스를 보면 다음과 같다.

if문을 보면 " GPIOx->BSRR = GPIO_Pin; "으로 되어있다. GPIOx_BSRR 레지스터에서 GPIO_Pin만큼 쉬프트 하라는 뜻이 된다. GPIO_Pin은 1 << 13이므로 왼쪽으로 13번 움직이면 "BS13"이 1로 SET된다.

결국은 GPIOC_BSRR레지스터에서 BS13을 SET해줌으로써 PC13(LED)을 ON시켜줄 수 있도록 제어해주는 소스이다.

3)
else문을 보면 "GPIOx->BSRR = (uint32_t)GPIO_Pin << 16u;"로 되어있다. if문과 조금 다른것은 이미 왼쪽으로 13번 쉬프트한 레지스터(LED가 ON된 상태)에서 16번 더 왼쪽으로 움직이게 만들었다는 것이다. "BRy"핀의 설명을 읽어보면 1로 SET될 경우 ODRx를 RESET(CLEAR)시킨다는걸 알 수 있다. BR13이 1로 SET된다면 LED를 꺼질 것이다.

4) 즉 BSy핀을 SET시킨다면 LED를 ON시킬 수 있고 BRy를 SET시킨다면 LED를 OFF시킬 수 있다.

1.3 HAL을 사용하지 않고 LED 제어해보기

HAL_GPIO_WritePin에서는 LED를 제어시킬 수 있고, __HAL_RCC_GPIOx_LK_ENABLE에서는 LED가 작동할 수 있도록 클럭(CLK)를 제어시킬 수 있는걸 알게 됐다.

HAL를 사용하지 않고 코드를 작성해보면 아래같이 표현할 수 있다.

//클록을 제어하기 위해서
volatile unsigned int * reg = 0x40021018;
*reg |= 16;
___________________________________________________________________

//LED를 제어하기 위해서
volatile unsigned int * reg2 = 0x40011000
while (1)
{
	  *reg2 = 0x2000;
	  HAL_Delay(100);
	  *reg2 = (0x2000 << 16);
	  HAL_Delay(100);

}
profile
JUST DO IT

0개의 댓글