본문으로 바로가기

[ble_app_interactive ] GettickCount() 만들기

category Nordic_nRF52 2022. 4. 4. 14:54

: Nordic nRF52 SES 를 사용해 1msec 단위의 tickcount 만들기

 

0> 기본 준비사항

 0-1> H/W datasheet

nRF52832 데이타시트 Block Ddiagram 중 일부

  NVIC : Nested Vectored Interrupt Controlloer

 

 

 

  0-2> S/W

 

  Default Exception Handlers     

    NMI_Handler

    HardFault_Handler

    ~~~~~ 중략 ~~~~

    SysTick_Handler

 

 

 

1> systick 이용하기

   : system tick timer 를 1ms 단위로 인터럽트 동작하게 설정후 인터럽트 핸들러에서

     global 변수 값을 증가 시키면 됩니다.

 1-1> system tick  1ms 로 설정하기

// 1msec SysTick interrupt 설정하기 
SysTick_Config(SystemCoreClock / 1000UL);

 1-2> 인터럽트 핸들러 만들기

: SysTick_Handler 함수 만들기 (이름이 동일해야 합니다.)

  코드가 정상적으로 실행이 된다면 1ms 단위로 SysTick_Handler() 함수가 호출이 될거고

  내부에 사용되는 m_timeMs 값도 1씩 증가 하게 됩니다.

volatile uint32_t m_timeMs = 0;
void SysTick_Handler(void)  {
    m_timeMs++;
}

 <참고 사항>

 : ses_startup_nrf52.s 파일안의 Default Exception Handler 부분을 확인해 보면

   다음 소스코드처럼 SysTick_Handler 함수가 weak 타입으로 선언이 되어 있고 함수를 재정의하면

   weak 함수를 대신해서 사용하게 됩니다.

************************************************************************************
 * Default Exception Handlers                                                       *
 ************************************************************************************/

  .thumb_func
  .weak   NMI_Handler
NMI_Handler:
  b     .
  
  ~~~~ 중략 ~~~~

  .thumb_func
  .weak   SysTick_Handler
SysTick_Handler:
  b     .
  
    ~~~~ 중략 ~~~~

 

 

 1-3> SysTick IRQ 인터럽트 Enable 하기

     :  NVIC_EnableIRQ(SysTick_IRQn); 

 

 1-4> GetTickCount() 만들기

uint32_t GetTickCount()
{
  return m_timeMs; 
}

   

 

2> 세부사항 분석

 2-1> SystemCoreClock 은 어디에 정의 되어 있지?

// system_nrf52.c 소스 코드
#define __SYSTEM_CLOCK_64M      (64000000UL)

#if defined ( __CC_ARM )
    uint32_t SystemCoreClock __attribute__((used)) = __SYSTEM_CLOCK_64M;
#elif defined ( __ICCARM__ )
    __root uint32_t SystemCoreClock = __SYSTEM_CLOCK_64M;
#elif defined ( __GNUC__ )
    uint32_t SystemCoreClock __attribute__((used)) = __SYSTEM_CLOCK_64M;  <-- 저는 요부분 사용됨.
#endif

 

 2-2> SysTick_Config()  함수내 사용되는 SysTick 분석

// core_cm4.h

#define SCS_BASE            (0xE000E000UL)
#define SysTick_BASE        (SCS_BASE +  0x0010UL)    /*!< SysTick Base Address */
#define SysTick             ((SysTick_Type   *)     SysTick_BASE  )

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;


__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
  ~~~ 중략 ~~~~
  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 */
}

 

  Coretex-M4 Processor Technical Reference Manual 의 4.1절   System Control Registers 참조

 

 2-3> NVIC_EnableIRQ() 함수 분석

// core_cm4.h 파일
#define SCS_BASE            (0xE000E000UL)  
#define NVIC_BASE           (SCS_BASE +  0x0100UL)   
#define NVIC                ((NVIC_Type      *)     NVIC_BASE     )

#define NVIC_EnableIRQ              __NVIC_EnableIRQ
__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn)
{
  if ((int32_t)(IRQn) >= 0)
  {
    __COMPILER_BARRIER();
    NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL));
    __COMPILER_BARRIER();
  }
}

typedef struct
{
  __IOM uint32_t ISER[8U];               /*!< Offset: 0x000 (R/W)  Interrupt Set Enable Register */
        uint32_t RESERVED0[24U];
  __IOM uint32_t ICER[8U];               /*!< Offset: 0x080 (R/W)  Interrupt Clear Enable Register */
        uint32_t RESERVED1[24U];
  __IOM uint32_t ISPR[8U];               /*!< Offset: 0x100 (R/W)  Interrupt Set Pending Register */
        uint32_t RESERVED2[24U];
  __IOM uint32_t ICPR[8U];               /*!< Offset: 0x180 (R/W)  Interrupt Clear Pending Register */
        uint32_t RESERVED3[24U];
  __IOM uint32_t IABR[8U];               /*!< Offset: 0x200 (R/W)  Interrupt Active bit Register */
        uint32_t RESERVED4[56U];
  __IOM uint8_t  IP[240U];               /*!< Offset: 0x300 (R/W)  Interrupt Priority Register (8Bit wide) */
        uint32_t RESERVED5[644U];
  __OM  uint32_t STIR;                   /*!< Offset: 0xE00 ( /W)  Software Trigger Interrupt Register */
}  NVIC_Type;

 

  Coretex-M4 Processor Technical Reference Manual 의 6.2절  NVIC 레지스터 참조 

 

 2-4> 참고로 Coretex-M4 technical manaul 첨부합니다.

Cortex-M4 Proc Tech Ref Manual.pdf
0.79MB

 

 

그럼 오늘 하루도 수고하세요.

반응형