Systick 세팅 순서

Systick 설정 순서는 아래와 같다. Systick 이란 Cortex-M 시리즈 마이크로컨트롤러의 코어에 기본적으로 동일하게 내장된 24비트 타이머다.

참고 홈페이지: https://developer.arm.com/documentation/dui0552/a/cortex-m3-peripherals/system-timer–systick

Systick 프로그래밍 메뉴얼: https://www.st.com/resource/en/programming_manual/pm0056-stm32f10xxx20xxx21xxxl1xxxx-cortexm3-programming-manual-stmicroelectronics.pdf


Systick 설정 Flow는 아래와 같아.
1.HAL_Init() => 2.HAL_InitTick() => 3.HAL_SYSTICK_Config() => 4.SysTick_Config()


SystemCoreClock 은 전역 변수로 16000000 로 설정 되어 있어 SystemClock_Config 호술 시 설정에 맞게 SystemCoreClock이 업데이트 된다.

5. SystemClock_Config(void) => 6. HAL_RCC_ClockConfig() => SystemCoreClock을 다시 업데이트 후 => HAL_InitTick()

Clock configuration register 인 RCC_CFGR 레지터에 clock이 어떻게 설정되었는지 확인 후 SystemCoreClock 값을 업데이트를 한다.
보드 설정에는 아래와 같이 PLL(Phase-Locked Loop) 사용으로 설정 되어 있음
clock_setting


Systick 이 어떻게 설정되는지 함수를 분석해 보았다.


HAL_InitTick 함수 내용

__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
...

  /* Configure the SysTick to have interrupt in 1ms time basis*/
  if (HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq)) > 0U)
  {
    return HAL_ERROR;
  }

...
  /* Return function status */
  return HAL_OK;
}

HAL_SYSTICK_Config 함수에 systick count 값을 계산하여 넘겨준다.
Systick count 방식은 count down 방식이므로 (count - 1) 값으로 systic count가 설정 되어야하며 0 보다 커야한다.
systic count 값이 0이 되었을 때 아래와 같은 인터럽트 함수가 호출 된다.
count 값을 구하는 공식은 아래와 같다.
systick_cal

Systick 인터럽트 함수

void SysTick_Handler(void)
{
  /* USER CODE BEGIN SysTick_IRQn 0 */

  /* USER CODE END SysTick_IRQn 0 */
  HAL_IncTick();
  /* USER CODE BEGIN SysTick_IRQn 1 */

  /* USER CODE END SysTick_IRQn 1 */
}
__weak void HAL_IncTick(void)
{
  uwTick += uwTickFreq;
}


HAL_InitTick => HAL_SYSTICK_Config 함수가 호출 된다.

uint32_t HAL_SYSTICK_Config(uint32_t TicksNumb)
{
   return SysTick_Config(TicksNumb);
}
SysTick_Config가 #include "core_cm3.h”에 정의 되어 있는데 어떻게 core_cm3.h를 include를 하는지 확인해 보았다.

1. #include "stm32f1xx_hal.h"
HAL_SYSTICK_Config()는 위 해더 파일에 정의 되어 있다.

2. #include "stm32f1xx_hal_conf.h"
stm32f1xx_hal.h은 stm32f1xx_hal_conf.h을 include 한다.

3. #define HAL_CORTEX_MODULE_ENABLED
stm32f1xx_hal_conf.h 에서 HAL_CORTEX_MODULE_ENABLED 이 define 되어 있다.


4. #ifdef HAL_CORTEX_MODULE_ENABLED
   #include "stm32f1xx_hal_cortex.h"
   #endif /* HAL_CORTEX_MODULE_ENABLED */
stm32f1xx_hal_conf.h는 stm32f1xx_hal_cortex.h를 위와 같이 include 한다.

5. #include "stm32f1xx_hal_cortex.h"
stm32f1xx_hal_conf.h에서 stm32f1xx_hal_cortex.h를 include 한다.

6. #include "stm32f1xx_hal_def.h"
stm32f1xx_hal_cortex.h에서 stm32f1xx_hal_def.h를 include 한다.

7. #include "stm32f1xx.h"
stm32f1xx_hal_def.h는 stm32f1xx.h를 include 한다.

8. #elif defined(STM32F103xB)
   stm32f1xx.h에 위와 같이 정의 되어 있고 STM32F103xB는 아래와 같이 컴파일 시 predefine 되어 있다.
   
   arm-none-eabi-gcc "$<" -mcpu=cortex-m3 -std=gnu11 -g3 -DSTM32F103xB -c -I"/Users/mong/STM32CubeIDE/project/stm32f103/src" -I"/Users/mong/STM32CubeIDE/project/stm32f103/src/ap" -I"/Users/mong/STM32CubeIDE/project/stm32f103/src/bsp" -I"/Users/mong/STM32CubeIDE/project/stm32f103/src/common" -I"/Users/mong/STM32CubeIDE/project/stm32f103/src/hw" -I"/Users/mong/STM32CubeIDE/project/stm32f103/src/lib" -I"/Users/mong/STM32CubeIDE/project/stm32f103/src/lib/cub_f103/Drivers/CMSIS/Device/ST/STM32F1xx/Include" -I"/Users/mong/STM32CubeIDE/project/stm32f103/src/lib/cub_f103/Drivers/CMSIS/Include" -I"/Users/mong/STM32CubeIDE/project/stm32f103/src/lib/cub_f103/Drivers/STM32F1xx_HAL_Driver/Inc" -O0 -ffunction-sections -fdata-sections -Wall -fstack-usage -MMD -MP -MF"$(@:%.o=%.d)" -MT"$@" --specs=nano.specs -mfloat-abi=soft -mthumb -o "$@"

-DSTM32F103xB가 predefine 되어 있음

https://gcc.gnu.org/onlinedocs/gcc-4.3.2/gcc/Preprocessor-Options.html

9. #include "stm32f103xb.h"
아래 정의 되어 있음
#define __Vendor_SysTickConfig     0U       /*!< Set to 1 if different SysTick Config is used */

stm32f103xb.h에서 core_cm3.h를 include 한다.

10. #include "core_cm3.h"
아래와 같이 SysTick_Config가 __STATIC_INLINE 으로 정의 되어 있다.

#if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U)

__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
  if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
  {
    return (1UL);                                                   /* Reload value impossible */
  }

  SysTick->LOAD  = (uint32_t)(ticks - 1UL);                         /* set reload register */
  NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
  SysTick->VAL   = 0UL;                                             /* Load the SysTick Counter Value */
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                   SysTick_CTRL_TICKINT_Msk   |
                   SysTick_CTRL_ENABLE_Msk;                         /* Enable SysTick IRQ and SysTick Timer */
  return (0UL);                                                     /* Function successful */
}

#endif

#define SysTick_CTRL_CLKSOURCE_Pos          2U                                  /*!< SysTick CTRL: CLKSOURCE Position */
#define SysTick_CTRL_CLKSOURCE_Msk         (1UL << SysTick_CTRL_CLKSOURCE_Pos)  /*!< SysTick CTRL: CLKSOURCE Mask */

#define SysTick_CTRL_TICKINT_Pos            1U                                  /*!< SysTick CTRL: TICKINT Position */
#define SysTick_CTRL_TICKINT_Msk           (1UL << SysTick_CTRL_TICKINT_Pos) 

#define SysTick_CTRL_ENABLE_Pos             0U                                  /*!< SysTick CTRL: ENABLE Position */
#define SysTick_CTRL_ENABLE_Msk            (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */

/* Memory mapping of Core Hardware */
#define SCS_BASE            (0xE000E000UL)                            /*!< System Control Space Base Address */
#define SysTick_BASE        (SCS_BASE +  0x0010UL)                    /*!< SysTick Base Address */
#define SysTick             ((SysTick_Type   *)     SysTick_BASE  )   /*!< SysTick configuration struct */

/* following defines should be used for structure members */
#define     __IM     volatile const      /*! Defines 'read only' structure member permissions */
#define     __OM     volatile            /*! Defines 'write only' structure member permissions */
#define     __IOM    volatile            /*! Defines 'read / write' structure member permissions */

/**
  \brief  Structure type to access the System Timer (SysTick).
 */
typedef struct
{
  __IOM uint32_t CTRL;                   /*!< Offset: 0x000 (R/W)  SysTick Control and Status Register */
  __IOM uint32_t LOAD;                   /*!< Offset: 0x004 (R/W)  SysTick Reload Value Register */
  __IOM uint32_t VAL;                    /*!< Offset: 0x008 (R/W)  SysTick Current Value Register */
  __IM  uint32_t CALIB;                  /*!< Offset: 0x00C (R/ )  SysTick Calibration Register */
} SysTick_Type;


systic_reload_value_register
systic_current_value_register
systick_control_and_status_register
systick_register_map

__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) 함수 분석 왜 __STATIC_INLINE 으로 정의 했는지 확인 필요
1. SysTick->LOAD 레지스터는 VAL 값이 0이되고 counter가 enable 되었을 때 VAL 값에 LOAD 값을 채우는 역할을 한다.
2. NVIC_SetPriority (SysTick_IRQn, (1UL « __NVIC_PRIO_BITS) - 1UL);
SysTick_IRQn의 Priority를 설정한다.
참고 링크: https://www.st.com/resource/en/programming_manual/pm0056-stm32f10xxx20xxx21xxxl1xxxx-cortexm3-programming-manual-stmicroelectronics.pdf


systick_set_priority


3. SysTick->CTRL 레지스터는 Systick 기능을 enable하는 레지스터이다.


systick_enable_register
참고 링크: https://www.st.com/resource/en/programming_manual/pm0056-stm32f10xxx20xxx21xxxl1xxxx-cortexm3-programming-manual-stmicroelectronics.pdf

RCC->CFGR 하기 함수에서 세팅이 된다.
HAL_StatusTypeDef HAL_RCC_OscConfig(RCC_OscInitTypeDef  *RCC_OscInitStruct)
{
  .....
  /* Configure the main PLL clock source and multiplication factors. */
  __HAL_RCC_PLL_CONFIG(RCC_OscInitStruct->PLL.PLLSource,
                        RCC_OscInitStruct->PLL.PLLMUL);
}

RCC란 무엇인가? Reset Clock Controller

HSE 뜻? High Speed External