NXP CM0 Kinetis 微控制器 Clock 测试简介

 一、 IEC60730 Invariable Clock Test Architecture简介

       时钟测试程序测试处理器的时钟频率是否处于卡滞状态。时钟测试可在单片机复位后执行一次,也可在运行时。

       时钟测试原理是基于两个独立时钟源的比较。如果测试例程检测到时钟源之间频率比的变化,则返回失败错误码。测试例程在应用程序中使用一个计时器和一个周期事件。周期性事件也可以是来自不同定时器的中断,就像已经涉及的中断一样。时钟测试的框图如下图所示。

 

二、实际应用示例(测试平台IAR ,主控 KE15 )

  1. KE15 选择两个不同的时钟源进行 Clock Test ,这里选择 Fast IRC 经过 LPFLL 倍频后的 72MHz 的时钟源和 Slow IRC 8MHz 时钟源,通过 Systick 和 LPTMR 两个定时器的计数值进行测试。
  2. 配置系统时钟为 FIRC 72MHz & LPTMR 时钟源为 SIRC 8MHz
  3. 初始化测试的条件参数

         (1)宏定义以下参数

#define LPTMR_USED                LPTMR0

#define SYSTICK_RELOAD_VALUE 10000

#define ISR_FREQUENCY 7200 /* Hz */

#define CLOCK_TEST_TOLERANCE 20 /* % */

#define REF_TIMER_CLOCK_FREQUENCY 8e06

 

         (2)初始化测试比较 Clock 的初始值,其中参数 safety_common_t & clock_test_t 定义在 IEC60730_safety.h 中,初始化将要比较的 Clock 的定时器的计数值的参考值范围。

 

/*!
* @brief Initialization of Safety clock test.
*
* Complete Initialization of the clock test.
* Function calculates limit values.
* Cals clock test init function from the IEC60730B library.
* @param psSafetyCommon - The pointer of the Common Safety structure
* @param psSafetyClockTest - The pointer of the Safety Clock test structure
* @param peClockFreq - The pointer of the clock name enumeration
* @return None
*/

void SafetyClockTestInit(safety_common_t *psSafetyCommon, clock_test_t *psSafetyClockTest)

{
psSafetyCommon->ui32McgirclkFreq = REF_TIMER_CLOCK_FREQUENCY;
psSafetyClockTest->ui32ClockTestExpected = psSafetyCommon->ui32McgirclkFreq / (uint32_t)ISR_FREQUENCY;
psSafetyClockTest->ui32ClockTestTolerance = (psSafetyClockTest->ui32ClockTestExpected * (uint32_t)CLOCK_TEST_TOLERANCE) /(uint32_t)100 ;
psSafetyClockTest->ui32ClockTestLimitHigh = psSafetyClockTest->ui32ClockTestExpected + psSafetyClockTest->ui32ClockTestTolerance;
psSafetyClockTest->ui32ClockTestLimitLow = psSafetyClockTest->ui32ClockTestExpected - psSafetyClockTest->ui32ClockTestTolerance;
psSafetyClockTest->ui16ClockTestStart = 0; /* clock test result will be processed after the first interrupt occurs */
IEC60730B_CLK_SYNC_Init((unsigned long *)&psSafetyClockTest->ui32ClockTestContext);

}

         (3)初始化 LPTMR 定时计数器

/*!

* @brief Initialization of LPTMR
* This function initializes the LPTMR. LPTMR is used for clock test.
* @param void
* @return None
*/

void LPTMR_initialisation(void)

{
/* SIRCDIV */ /* SIRCCFG */
/* slow IRC must be disabled */

SCG->SIRCCSR &= ~SCG_SIRCCSR_SIRCEN_MASK; /* disable slow IRC */
SCG->SIRCCFG |= SCG_SIRCCFG_RANGE_MASK; /* Slow IRC high range clock (8 MHz) */
SCG->SIRCDIV &= ~SCG_SIRCDIV_SIRCDIV2_MASK;
SCG->SIRCDIV |= SCG_SIRCDIV_SIRCDIV2(1);
SCG->SIRCCSR |= SCG_SIRCCSR_SIRCEN_MASK; /* enable slow IRC */

/* enable clock for LPTMR */
PCC->CLKCFG[PCC_LPTMR0_INDEX] &= ~PCC_CLKCFG_CGC_MASK; /* Clock disabled */
PCC->CLKCFG[PCC_LPTMR0_INDEX] |= PCC_CLKCFG_PCS(2); /* slow IRC Clock. */
PCC->CLKCFG[PCC_LPTMR0_INDEX] |= PCC_CLKCFG_CGC_MASK; /* Clock enabled */

LPTMR0->CSR = 0; /* time counter mode */
LPTMR0->CSR = LPTMR_CSR_TCF_MASK | LPTMR_CSR_TFC_MASK; /* CNR reset on overflow */
LPTMR0->PSR |= LPTMR_PSR_PBYP_MASK; /* prescaler bypassed, selected clock directly clocks the CNR */
LPTMR0->PSR &= (~LPTMR_PSR_PCS_MASK); /* clear prescaler clock 0 selected MCGIRCLK */

LPTMR0->PSR |= LPTMR_PSR_PCS(0);
LPTMR0->CMR = 0; /* clear the compare register */
LPTMR0->CSR |= LPTMR_CSR_TEN_MASK; /* enable timer */


}

 

         (4)初始化 Systick 定时计数器,其中,重载计数器的数值为  SYSTICK_RELOAD_VALUE ,然后就是 Systick 的中断函数,中断函数内部就是获取 LPTMR 的计数值,获取 LPTMR 的计数值后会重新Reset LPTMR,其中 IEC60730B_CLK_SYNC_LPTMR_Isr() 库函数头文件包含于 IEC60730_B_clock.h 如下代码所示。

/*!

* @brief Initialization of Systick timer
* This function configures the Systick as a source of interrupt
* @param reload_value - defines the period of counter refresh
* @return None
*/

void SystickInitialisation(uint32_t reload_value)

{
SysTick->VAL = 0;
SysTick->LOAD = reload_value;
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk;

}


/*!
* @brief Systick interrupt function
* @param void
* @return None
*/

void SYSTICK_Isr(void)

{
/* clock test function */
SafetyClockTestIsr(&g_sSafetyClockTest);
/* Safety tests which cannot be interrupted */
SafetyIsrFunction(&g_sSafetyCommon, &g_sSafetyRamTest, &g_sSafetyRamStackTest);
/* Refreshing the watchdog. For short period of interrupts, choose higher refresh ratio parameter */
SafetyWatchdogRuntimeRefresh(&g_sSafetyWdTest);

}


/*!
* @brief Clock test function, called from interrupt.
* This function calls clock test function from the IEC60730B library and enable the test evaluation.
* It must be called in the Systick interrupt to catch the value of LPTMR counter.
* @param psSafetyClockTest - The pointer of the Safety Clock test structure
* @return None
*/

void SafetyClockTestIsr(clock_test_t *psSafetyClockTest)

{
IEC60730B_CLK_SYNC_LPTMR_Isr((unsigned long*)LPTMR_USED, (unsigned long *)&psSafetyClockTest->ui32ClockTestContext);
psSafetyClockTest->ui16ClockTestStart |= 1; /* to prevent checking of result before execution */

}

 

         (5)在 Runtime 中测试 Clock ,比较定时计数器的计数值和期望值,返回结果,然后进行错误机制处理函数。

/*!

* @brief Clock test check function.
* This function can be called from any place of application.
* It calls the IEC60730B_CLK_Check function from the IEC60730 library
* In case of incorrect clock test result, it updates the ui32SafetyErrors variable accordingly.
* A node of program flow check is placed here.
* @param psSafetyCommon - The pointer of the Common Safety structure
* @param psSafetyClockTest - The pointer of the Safety Clock test structure
* @param psSafetyProgramFlowTest - The pointer of the Program flow test structure
* @return None
*/

void SafetyClockTestCheck(safety_common_t *psSafetyCommon, clock_test_t *psSafetyClockTest)

{
if (psSafetyClockTest->ui16ClockTestStart) /* condition is valid after the first Systick interrupt */
{
psSafetyCommon->IEC60730B_clock_test_result = IEC60730B_CLK_Check(psSafetyClockTest->ui32ClockTestContext, psSafetyClockTest->ui32ClockTestLimitLow, psSafetyClockTest->ui32ClockTestLimitHigh);
if(psSafetyCommon->IEC60730B_clock_test_result == IEC60730B_ST_CLK_FAIL)
{
psSafetyCommon->ui32SafetyErrors |= CLOCK_TEST_ERROR;
SafetyErrorHandling(psSafetyCommon);

}

}

}


三、例程函数调用特别说明

  1. 时钟测试的测试函数放在IEC60730_B_clock.c中,并作为C函数编写。带有函数原型的头文件是IEC60730_B_clock.h。公共库头文件是  IEC60730_B.h。调用以下函数测试时钟频率:
  • IEC60730B_CLK_SYNC _Init ()
  • IEC60730B_CLK_SYNC_LPTMR_Isr ()
  • IEC60730B_CLK_SYNC_RTC_Isr ()
  • IEC60730B_CLK_Check ()

 

  1. 用户必须配置 LPTMR/RTC ,选择合适的周期事件并计算限值。32 位的全局变量,用来存储计时器计数器寄存器的内容,然后必须声明。所选定时器的时钟源不能与周期事件的时钟源相同。 IEC60730B_CLK_SYNC_Init() 函数被调用一次,通常在 while() 循环之前。然后在周期性事件中调用 IEC60730B_CLK_SYNC_LPTMR_Isr() 函数。用于计算 - IEC60730B_CLK_Check() 的函数可以在任何选择的时间调用。当 test 处于初始化阶段时, check 函数返回 “progress” 值。如果从 LPTMR/RTC 捕获的值在预设的限制内,检查函数将返回一个传递值。如果不是,则返回一个定义的失败值。


四、参考资料

IEC60730_B_Clock_Test_for_CM0_rev3_0.pdf

接下来会逐步讲一下其他的安全测试,敬请期待,互相学习。

★博文内容均由个人提供,与平台无关,如有违法或侵权,请与网站管理员联系。

★文明上网,请理性发言。内容一周内被举报5次,发文人进小黑屋喔~

评论