: Nordic nRF52 SES 를 사용해 1msec 단위의 tickcount 만들기
0> 기본 준비사항
0-1> H/W datasheet
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 첨부합니다.
그럼 오늘 하루도 수고하세요.
'Nordic_nRF52' 카테고리의 다른 글
[secure_bootloader ] 프로젝트 분석 (0) | 2022.04.11 |
---|---|
[ble_app_cts_c ] 프로젝트 분석 (0) | 2022.04.07 |
[ble_app_beacon ] 프로젝트 분석 (0) | 2022.04.05 |
[nRF52 ] NRF_LOG 출력 UART 에서 RTT 로 변경하기 (0) | 2022.03.25 |
[nRF52 ] ble_app_interactive 프로젝트를 이용한 ble_app_bms 장치 통신하기 (0) | 2022.03.24 |