配置S32K116 CMU检测时钟模块

电子说

1.3w人已加入

描述

    CMU仅适用于S32K11x系列。S32K1xx系列中的其他器件没有CMU。S32K11x有两个CMU单元:CMU0和CMU1。它监控作为系统时钟主要来源的FIRC。CMU需要通过软件启用,因为默认情况下未启用。CMU0用于时钟丢失检测时产生复位,映射到RCM_SRS[4]。当FIRC低于编程阈值时,标识时钟丢失,将IER[FHAIE]和IER[FLLAIE]以及阈值编程设置为启用复位功能。当FIRC低于或高于编程阈值限制时,CMU1用于中断生成。在CMU1中设置IER[FHIE]和IER[FLLIE]以及阈值编程,以启用中断功能。下图显示了CMU与芯片的连接:

时钟

    在禁用FIRC或SIRC之前,需要禁用CMU。如果FIRC从开始就不存在,则无法启用CMU,因为启用CMU需要系统时钟。

•对于安全应用,CMU应在与WDOG看门狗在不同的时钟上运行。

•CMU在最坏情况下将FIRC时钟超出范围事件标记为+/-7.5%的准确度,条件是FIRC和SIRC符合器件数据手册规格范围,即在最坏的情况下分别为+/-1.1%和+/-3.3%。如果FIRC和SIRC违反规范,CMU精度将进一步下降到+/-7.5%以下。

•当REF_CNT编程值为1000时,CMU在标记FIRC时钟超出范围事件时所用的硬件安全反应时间为128 us,精确度为+/-7.5%。如果FIRC和SIRC违反规范,硬件安全反应时长将超过128 us。

•建议通过软件将时钟范围超出事件,设置为复位系统,而不是使用中断。

    在S32K116 系统添加时钟监控单元。初始化时钟FIRC(48MHz),参考配置代码如下。

    CMU0只能在时钟丢失时触发复位,为此,配置参考计数、启用CMU0中断并启用频率检查。CMU1只能在频率高于或低于编程限制时触发中断。为此,配置参考计数、HTCR和LTCR、中断和启用频率检查。重新启动后,系统必须验证复位是否由时钟丢失引起。功能Sanity_check执行此操作,如果它是由FIRC丢失引起的,则系统进入安全状态。如果导致CMU1中断,系统将验证中断原因,然后进入安全状态。

#include "S32K116.h"

#include "clocks.h"

#define GREEN_LED 15 /* 定义绿色 LED */

#define RED_LED    16  /* 定义红色 LED */

/* Sanity_check函数可能返回状态的枚举 */

typedef enum

{

FIRC_NOT_OK = 0,

FIRC_OK= 1

}Sanity_check_status_t;

/*该功能表示如果时钟监视器检测到FIRC有问题,系统应跳至安全状态。*/

void Safe_state(void)

{

for(;;)

{

/* 应用程序特定安全状态 */

}

}

// 通过读取RCM_SRS寄存器,验证上次系统复位是否由时钟丢失触发。

SOSC_AND_SPLL_OK:系统复位不是由LOC或LOL触发的

*SOSC_NOT_OK: LOC触发了系统复位

*SPLL_NOT_OK:  系统复位由LOL触发

Sanity_check_status_t Sanity_check(void)

{

///应用软件需要检测RCM的错误标志状态

/* 判断RCM_SRS寄存器的 CMU_LOC 位是否被置位 */

if(True == ((RCM->SRS & RCM_SRS_CMU_LOC_MASK) >> RCM_SRS_CMU_LOC_SHIFT))

{

/* 返回 SOSC_NOT_OK 状态*/

return FIRC_NOT_OK;

}

/* 默认返回 SOSC_AND_SPLL_OK 状态*/

return FIRC_OK;

}

/* SCG_CMU_LVD_LVWSCG_IRQHandler 表示 CMU中断。当频率不在编程范围内时,通过 CMU1触发,通过关闭绿色LED,点亮红色 LED指示。*/

void SCG_CMU_LVD_LVWSCG_IRQHandler(void)

{

/* 关闭绿色的 LED */

PTD->PCOR |= 1 << GREEN_LED;

/* 开启红色的 LED */

PTD->PSOR |= 1 << RED_LED;

///对于丢失的中断请求,应用程序可能需要在系统级别上包括检测或保护措施

/* 中断由CMU1引起,频率高于阈值 */

if(True == (CMU_FC_1->IER & CMU_FC_SR_FHH_MASK) >> CMU_FC_SR_FHH_SHIFT)

{

        /* 清除中断的标志 */

CMU_FC_1->SR |= CMU_FC_SR_FHH_MASK;

/* 进入安装状态 */

Safe_state();

}

/* 中断由CMU1引起,频率低于阈值 */

else if(True == (CMU_FC_1->IER & CMU_FC_SR_FLL_MASK) >> CMU_FC_SR_FLL_SHIFT)

{

/* 清除中断的标志 */

CMU_FC_1->SR |= CMU_FC_SR_FLL_MASK;

/* 进入安装状态 */

Safe_state();

}

}

int main(void)

{

/* 验证之前的复位是否是由时钟丢失引起的 */

if(FIRC_NOT_OK == Sanity_check())

{

/* 进入安全状态 */

Safe_state();

}

/* 使能端口 D的时钟,开启绿色和红色的LED 指示 */

PCC-> PCCn[PCC_PORTD_INDEX] = PCC_PCCn_CGC_MASK;

/* 选择 GPIO */

PORTD->PCR[GREEN_LED] = PORT_PCR_MUX(1);

/* 设置端口 D 引脚 15 为输出 */

PTD->PDDR |= 1 << GREEN_LED;

/* 选择 GPIO */

PORTD->PCR[RED_LED]   = PORT_PCR_MUX(1);

/* 设置端口 D 引脚 16 为输出 */

PTD->PDDR |= 1 << RED_LED;

/* 开启绿色 LED输出 */

PTD->PSOR |= 1 << GREEN_LED;

/* 配置寄存器将FIRC映射到引脚 */

FIRC_init();

/*启用NVIC模块中的CMC_FC_0和CMC_FC_1中断 */

NVIC_enable_CMU_interrupt();

/* 配置 SIRC */

SIRC_init();

/* 设置 SIRC 为系统时钟 */

SCG->RCCR = SCG_RCCR_SCS(2);

///对于安全相关应用,必须使用时钟监视器。如果应用安全功能使用SCG监视器的模块,用户应验证时钟监视器未被禁用,且其故障由软件管理。需要以下监督功能:内部快速参考时钟丢失、系统FIRC频率高于(可编程)上限频率参考、系统FIRC频率低于(可编程的)下限频率参考、应用软件必须在激活安全相关功能之前验证S32K1xx的初始化是否正确。时钟监视器已启用。

/* 配置 CMU0 来检测内部的 FIRC是否丢失 */

CMU0_init();

/* 配置 CMU1来检测 FIRC的频率是否变化 */

CMU1_init();

/* 关闭 FIRC,因此 CMU_FC_0 会触发复位 */

SCG->FIRCCSR &= ~SCG_FIRCCSR_FIRCEN_MASK;

for(;;){}

return 0;

}

#include "clocks.h"

/*NVIC_enable_CMU_interrupt 在NVIC中使能CMU模块的中断*/

void NVIC_enable_CMU_interrupt(void)

{

/* 清除 IRQs, SCG NVIC 中断 ID = 21 */

S32_NVIC->ICPR[0] = 1 << (SCG_CMU_LVD_LVWSCG_IRQn % 32);

/* 使能 IRQ */

S32_NVIC->ISER[0] = 1 << (SCG_CMU_LVD_LVWSCG_IRQn % 32);

}

/*SIRC_init 如果可以写入SIRCCSR,则禁用SIRC,以便可以选择8MHz频率,然后将DIV 1和2设置为除以1。启用SIRC并等待SIRC有效。*/

void SIRC_init(void)

{

/* 验证是否可以写入控制状态寄存器 */

if(False == ((SCG->SIRCCSR & SCG_SIRCCSR_LK_MASK) >> SCG_SIRCCSR_LK_SHIFT))

{

/* 禁用SIRC,以便进行更改 */

SCG->SIRCCSR &= ~(SCG_SIRCCSR_SIRCLPEN_MASK |SCG_SIRCCSR_SIRCEN_MASK);

SCG->SIRCDIV |= SCG_SIRCDIV_SIRCDIV1(1) | SCG_SIRCDIV_SIRCDIV2(1);

/*选择高频范围 (8MHz) */

SCG->SIRCCFG |= SCG_SIRCCFG_RANGE_MASK;

/* 使能 SIRC */

SCG->SIRCCSR |= SCG_SIRCCSR_SIRCLPEN_MASK |SCG_SIRCCSR_SIRCEN_MASK;

/* 等待直到 SIRC 是有效的 */

while(False == ((SCG->SIRCCSR & SCG_SIRCCSR_SIRCVLD_MASK) >> SCG_SIRCCSR_SIRCVLD_SHIFT));

}

}

/*FIRC_init 配置寄存器需要将FIRC输出到引脚上*/

void FIRC_init(void)

{

/* 配置内部的 FIRC到端口 B的第5脚 */

/* 在SCG_CLKOUTCNFG寄存器的CLKOUTSEL 中选择 FIRC  */

SCG->CLKOUTCNFG |= SCG_CLKOUTCNFG_CLKOUTSEL(3);

/* 在SIM_CHIPCTL,CLKOUTSEL中 选择 FIRC*/

SIM->CHIPCTL |= SIM_CHIPCTL_CLKOUTSEL(0);

/* 配置 CLKOUT 分频 */

SIM->CHIPCTL |= SIM_CHIPCTL_CLKOUTDIV(0);

/* 使能 CLKOUT */

SIM->CHIPCTL |= SIM_CHIPCTL_CLKOUTEN_MASK;

/* 将 CLKOUT 配置到引脚 PTB5 */

/* 使能端口 B 时钟 */

PCC->PCCn[PCC_PORTB_INDEX] = PCC_PCCn_CGC_MASK;

/* 设置端口 B的引脚 5设为输出 */

PTB->PDDR |= 1 << PTB5;

/* 选择 CLKOUT */

PORTB->PCR[PTB5] = PORT_PCR_MUX(5);

}

/* CMU0_init:该函数配置 CMU0来检测是否有 FIRC时钟丢失。 为此,需要对参考计数进行编程,需要启用中断和频率检查。当FIRC丢失时,将触发复位。*/

void CMU0_init(void)

{

/* 使能 CMU0 时钟门控*/

PCC->PCCn[PCC_CMU0_INDEX] = PCC_PCCn_CGC_MASK;

/*

            总线频率 =  8 MHz

    参考时钟频率 =  8 MHz

    监控时钟频率 = 48 MHz

* 公式1:

F1 = 3 * 参考时钟频率 / 总线频率

F1 = 3 * (8 MHz / 8MHz) = 3

* 公式 2:

F2 = 6 + 3 * (参考时钟频率 / 监控时钟频率)

F2 = 6 + 3 * (8 MHz / 48 MHz) = 6.5

* F1和F2结果之间的最大值Max(F1, F2),Max(3, 6.5) = 6.5

* 最大结果的上限 Ceiling(6.5) = 7

* RCCR[REF_CNT] = 7

*/

CMU_FC_0->RCCR = 7;

/* 使能 CMU0 中断*/

CMU_FC_0->IER |= CMU_FC_IER_FHHAEE_MASK | CMU_FC_IER_FLLAEE_MASK;

/* 使能频率检测 */

CMU_FC_0->GCR = CMU_FC_GCR_FCE_MASK;

/* 等待频率检查开始运行 */

while(False == (CMU_FC_0->SR & CMU_FC_SR_RS_MASK) >> CMU_FC_SR_RS_SHIFT);

}

/*CMU1_init:其功能配置CMU1以检测FIRC的频率是否不在编程限制之间。为此,需要对参考计数、HTRC和LTRC进行编程,需要启用中断和频率检查。如果频率不在限值之间,将触发SCG_CMU_LVD_LVWSCG_IRQ。*/

void CMU1_init(void)

{

/* 使能 CMU1时钟门控 */

PCC->PCCn[PCC_CMU1_INDEX] = PCC_PCCn_CGC_MASK;

/*

            总线频率 =  8 MHz

    参考时钟频率 =  8 MHz

    监控时钟频率 = 48 MHz

 * 公式1:

F1 = 3 * 参考时钟频率 / 总线频率

F1 = 3 * (8 MHz / 8MHz) = 3

 * 公式 2:

F2 = 6 + 3 * (参考时钟频率 / 监控时钟频率)

F2 = 6 + 3 * (8 MHz / 48 MHz) = 6.5

 * F1和F2结果之间的最大值Max(F1, F2),Max(3, 6.5) = 6.5

* 最大结果的上限 Ceiling(6.5) = 7

* RCCR[REF_CNT] = 7

*/

CMU_FC_1->RCCR = 7;

/*

* HTCR 和 LTCR 计算

* 参考时钟频率 =  8 MHz

* 监控时钟频率 = 48 MHz

* RCCR[REF_CNT] =  7

* Ideal_monitored_clock_count = (监控时钟频率 / 参考时钟频率 ) * REF_CNT

* Ideal_monitored_clock_count = (48 MHz / 8 MHz) * 7 = 42

         *参考时钟频率和监控时钟频率变化+/- 5%

* CMU_FC_inaccuracy = 3

* HTCR[HFREF] = (Ideal_monitored_clock_count * (100% + 5%)) + CMU_FC_inaccuracy

* HTCR[HFREF] = (42 * (105%)) + 3 = 47.1 --> 47

* LTCR[LFREF] = (Ideal_monitored_clock_count * (100% - 5%)) - CMU_FC_inaccuracy

* LTCR[LFREF] = ( 42 * (95%)) - 3 = 36.9 --> 37

*/

CMU_FC_1->HTCR = 47;

CMU_FC_1->LTCR = 37;

/* 使能 CMU1 中断 */

 CMU_FC_1->IER = CMU_FC_IER_FHHIE_MASK | CMU_FC_IER_FLLIE_MASK;

/* 使能频率检测 */

CMU_FC_1->GCR = CMU_FC_GCR_FCE_MASK;

/* 等待频率检查开始运行 */

while(False == (CMU_FC_1->SR & CMU_FC_SR_RS_MASK) >> CMU_FC_SR_RS_SHIFT);

}

时钟

时钟

时钟

时钟

时钟

  审核编辑:汤梓红
 
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分