NXP公司K20+PF8100实现硬件窗口看门狗

news2024/10/7 6:44:07

Kinetis® K20 72 MHz MCU系列为中等性能的Kinetis产品组合提供了可扩展的入门级产品,具有差异化的集成,配备高精度模拟集成和灵活的低功耗功能。其相关资源可在NXP的官网获得。

PF81/PF82为PMIC系列专为高性能处理应用而设计,如娱乐中控、车载信息服务、仪表板、汽车网络、ADAS、视图和传感器融合,内部集成了硬件看门狗等功能。本例主要使用NXP平台提供的I2C控制器驱动PF80实现硬件看门狗功能。

概念说明

下面是本篇文章涉及的一些概念说明,帮助读者更好的理解:

  • BUCK/LDO:BUCK与LDO都是直流变直流(DC-DC),BUCK转换器是一个通过降低电压来增加电流的转换器,LDO是一个直流线性电压控制器,它运作在输入输出压差非常小时。BUCK的输出纹波及稳压性不如LDO好,因此像DSP、ARM、FPGA等内核电源(1.2V、1.5V、2.5V等)宜用LDO,而高输入电压(>5V)、高输出电流(>2A),高输入/输出压差时,宜用BUCK。
  • PMIC:PMIC(Power Management IC)又称电源管理IC,是一种特定用途的集成电路,其功能是为主系统提供二级电源管理等工作。本例使用的PF8100芯片内部集成多路的BUCK/LDO,并提供了电压/电流监控以及硬件看门狗等功能,本例主要讲硬件看门狗。
  • 硬件看门狗:看门狗,全称WatchDog Timer,硬件看门狗是利用一个定时器电路,其定时输出连接到电路的复位端,程序在一定时间范围内对定时器清零(俗称“喂狗”),因此程序正常工作时,定时器总不能溢出,也就不能产生复位信号。其本身并不是用来解决系统出现的问题,而是对一些程序潜在错误和恶劣环境干扰等因素导致系统死机而在无人干预情况下自动恢复系统正常工作状态。
  • 窗口看门狗:窗口看门狗之所以称为窗口,就是因为其喂狗时间是一个有上下限的范围内(窗口),可以通过设定相关寄存器,设定其上限时间(但是下限是固定的0x3F)。也就是说:喂狗的时间不能过早,也不能过晚,必须在上下限时间范围内喂狗。
  • 系统电源设计:Soc一般涉及多档电源的需求,其通常被分为多个电源域,不同的电源域可以独立的上下电。如下面这个系统电源设计的例子,12V供电,先在以及转成3.3供MCU,然后5V供到两个PMIC芯片,最后PMIC芯片再给下一级MTK的各个电源域供电:

实现原理

嵌入式程序运行在以前飞思卡尔的KL24Z开发平台,与PF81通过IIC进行通信配置寄存器控制各BUCK/LDO输出电压以及错误管理与本例着重讲述的看门狗,下面是他的原理示意图:

嵌入式程序 

NXP官网提供了PF8x的各个功能的配置接口,包括:

  • 上下电顺序
  • BUCK/LDO配置
  • 电压/温度监控
  • 看门狗配置
  • 中断相关

下面代码片主要展现的是看门口配置相关的接口,主要包括:

  1. 看门狗模块窗口等参数配置
  2. 喂狗接口
  3. 获取当前看门狗运行状态

内部补充了中文注释帮助您理解:

//基于提供的地址,通过IIC执行读取寄存器
pf8x_status_t PF8X_ReadRegister(pf8x_drv_data_t* drvData, uint8_t address,
        uint8_t* rxData)
{
    pf8x_status_t status;
    uint8_t i2cAddress;
    uint8_t txFrame[PF8X_READ_FRAME_LENGTH] = {0};
    uint8_t rxFrameCrc[PF8X_FRAME_SIZE] = {0};
    uint8_t rxFrame[PF8X_FRAME_SIZE - 3U] = {0};

    FS_ASSERT(drvData != NULL);
    FS_ASSERT(rxData != NULL);

    i2cAddress = PF8X_GetI2CAddress(drvData);//获取IIC地址
    txFrame[0] = address;

    /* Send I2C command with register address only. */
    status = MCU_I2C_SendData(txFrame, PF8X_READ_FRAME_LENGTH, i2cAddress);//发送数据
    if (status != pf8xStatusOk)
    {
        return status;
    }

    if(drvData->crcEnabled)//如果当前芯片I2C通信开启CRC验证
    {
        /* Read 2 bytes - 1 data byte, 1 CRC byte. */
        status = MCU_I2C_ReceiveData(PF8X_RX_SIZE, i2cAddress, rxFrameCrc);//读取寄存器数据
        if (status != pf8xStatusOk)
        {
            return status;
        }

        /* I2C response frame contains just data and CRC.
         * The Device address and Register address is added
         * for proper CRC check. */
        rxFrameCrc[2] = address;
        rxFrameCrc[3] = (uint8_t)((i2cAddress << 1U) | 0x01U); /* R/W bit is 1 for I2C read */

        /* Check CRC. */
        status = PF8X_CheckCRC(rxFrameCrc, PF8X_FRAME_SIZE);
        if (status != pf8xStatusOk)
        {
            return status;
        }

        *rxData = rxFrameCrc[1];
    }
    else//没有开启crc
    {
        /* Read 1 byte - data byte only, no CRC. */
        status = MCU_I2C_ReceiveData(PF8X_RX_SIZE - 1U, i2cAddress, rxFrame);//读取crc数据
        if (status != pf8xStatusOk)
        {
            return status;
        }

        *rxData = rxFrame[0];
    }

    return pf8xStatusOk;
}
//写寄存器
pf8x_status_t PF8X_WriteRegister(pf8x_drv_data_t* drvData, uint8_t address,
        uint8_t writeData)
{
    uint8_t i2cAddress;
    uint8_t txFrameCrc[PF8X_FRAME_SIZE] = {0};
    uint8_t txFrame[PF8X_FRAME_SIZE - 1U] = {0};

    FS_ASSERT(drvData != NULL);

    i2cAddress = PF8X_GetI2CAddress(drvData);//获取寄存器地址

    if(drvData->crcEnabled)//如果crc功能打开
    {
        txFrameCrc[3] = (uint8_t)(i2cAddress << 1U); /* R/W bit is 0 for write */

        /* Sets address of the register (first two bits are ignored). */
        txFrameCrc[2] = address;

        /* Sets data. */
        txFrameCrc[1] = writeData;

        /* Add CRC. */
        txFrameCrc[0] = PF8X_CalcCRC(txFrameCrc, PF8X_FRAME_SIZE);//计算crc

        /* Write 3 bytes - register address byte, data byte, CRC byte. */
        return MCU_I2C_SendData(txFrameCrc, PF8X_COMM_FRAME_SIZE, i2cAddress);//发送数据
    }
    else
    {
        txFrame[2] = (uint8_t)(i2cAddress << 1U); /* R/W bit is 0 for write */

        /* Sets address of the register (first two bits are ignored). */
        txFrame[1] = address;

        /* Sets data. */
        txFrame[0] = writeData;

        /* Write 2 bytes - register address byte, data byte, no CRC. */
        return MCU_I2C_SendData(txFrame, PF8X_COMM_FRAME_SIZE - 1U, i2cAddress);//发送配置数据
    }
}

//配置看门狗模块,包括超时周期等函数
pf8x_status_t PF8X_SetWatchdogConfig(pf8x_drv_data_t* drvData, bool wdEnable,
        bool wdStbyEnable, uint8_t wdDuration, uint8_t wdMaxExpire, uint8_t wdMaxCnt)
{
    pf8x_status_t status;
    uint8_t rxData = 0;

    FS_ASSERT(drvData != NULL);

    /* Read CTRL1 register. */
    status = PF8X_ReadRegister(drvData, PF8X_CTRL1_ADDR, &rxData);
    if (status != pf8xStatusOk)
    {
        return status;
    }

    /* Clear bits before changing them. */
    rxData &= ~(PF8X_F_WD_EN_MASK | PF8X_F_WD_STBY_EN_MASK);
    /* Modify register content. */
    rxData |= ((uint8_t)wdEnable << PF8X_F_WD_EN_SHIFT) |
            ((uint8_t)wdStbyEnable << PF8X_F_WD_STBY_EN_SHIFT);

    /* Write settings to CTRL1 register. */
    if(drvData->secureEnabled)
    {
        status = PF8X_WriteRegisterSecured(drvData, PF8X_CTRL1_ADDR, rxData);
    }
    else
    {
        status = PF8X_WriteRegister(drvData, PF8X_CTRL1_ADDR, rxData);
    }
    if (status != pf8xStatusOk)
    {
        return status;
    }

    /* Write settings to WD_CONFIG register. */
    status = PF8X_WriteRegister(drvData, PF8X_WD_CONFIG_ADDR, wdDuration);
    if (status != pf8xStatusOk)
    {
        return status;
    }

    /* Read WD_EXPIRE register. */
    status = PF8X_ReadRegister(drvData, PF8X_WD_EXPIRE_ADDR, &rxData);
    if (status != pf8xStatusOk)
    {
        return status;
    }

    /* Clear bits before changing them. */
    rxData &= ~(PF8X_F_WD_MAX_EXPIRE_MASK);
    /* Modify register content. */
    rxData |= wdMaxExpire;

    /* Write settings to WD_EXPIRE register. */
    status = PF8X_WriteRegister(drvData, PF8X_WD_EXPIRE_ADDR, rxData);
    if (status != pf8xStatusOk)
    {
        return status;
    }

    /* Read WD_COUNTER register. */
    status = PF8X_ReadRegister(drvData, PF8X_WD_COUNTER_ADDR, &rxData);
    if (status != pf8xStatusOk)
    {
        return status;
    }

    /* Clear bits before changing them. */
    rxData &= ~(PF8X_F_WD_MAX_CNT_MASK);
    /* Modify register content. */
    rxData |= wdMaxCnt;

    /* Write settings to WD_COUNTER register. */
    return PF8X_WriteRegister(drvData, PF8X_WD_COUNTER_ADDR, rxData);
}

/* 获取当前看门狗状态*/
pf8x_status_t PF8X_GetWatchdogStatus(pf8x_drv_data_t* drvData, uint8_t* wdExpireCnt, uint8_t* wdEventCnt)
{
    pf8x_status_t status;
    uint8_t rxData = 0;

    FS_ASSERT(drvData != NULL);
    FS_ASSERT(wdExpireCnt != NULL);
    FS_ASSERT(wdEventCnt != NULL);

    /* Read WD_EXPIRE register. */
    status = PF8X_ReadRegister(drvData, PF8X_WD_EXPIRE_ADDR, &rxData);
    if (status != pf8xStatusOk)
    {
        return status;
    }

    *wdExpireCnt = (rxData & PF8X_F_WD_EXPIRE_CNT_MASK) >> PF8X_F_WD_EXPIRE_CNT_SHIFT;

    /* Read WD_COUNTER register. */
    status = PF8X_ReadRegister(drvData, PF8X_WD_COUNTER_ADDR, &rxData);
    if (status != pf8xStatusOk)
    {
        return status;
    }

    *wdEventCnt = (rxData & PF8X_F_WD_EVENT_CNT_MASK) >> PF8X_F_WD_EVENT_CNT_SHIFT;

    return status;
}

//清除看门狗,喂狗
pf8x_status_t PF8X_ClearWatchdog(pf8x_drv_data_t* drvData)
{
    pf8x_status_t status;

    FS_ASSERT(drvData != NULL);

    /* Write to WD_CLEAR register. */
    if(drvData->secureEnabled)
    {
        status = PF8X_WriteRegisterSecured(drvData, PF8X_WD_CLEAR_ADDR, PF8X_F_WD_CLEAR_1);
    }
    else
    {
        status = PF8X_WriteRegister(drvData, PF8X_WD_CLEAR_ADDR, PF8X_F_WD_CLEAR_1);
    }

    return status;
}

下面代码是一个窗口看门狗的实现,配置使能窗口看门狗模式,窗口设置大小120ms,下图是官方手册说明窗口模式和单端模式的不同喂狗时机,可以看出单端在整个窗口时间范围内喂狗就行,而窗口模式必循在60ms~120ms喂狗:

 下面是它的实现代码,已经在必要的位置增加了中文注释帮助您理解:

int main(void)
{
     //定时器配置结构体
     pit_config_t pitConfig = { false };
     pf8x_drv_data_t drvData = { .i2cAddressOtp = 0x00U, .secureEnabled = false, .crcEnabled = false };//初始化I2C设备结构体
     i2c_master_config_t masterConfig;//I2Cmaster 配置
     uint32_t sourceClock;


    //注册一个750ms唤醒定时器,定时器将wdFlag 置为真
    PIT_Init(PIT, &pitConfig);
    PIT_StopTimer(PIT, kPIT_Chnl_0);
    /* Set 750 ms timer period for channel 0 (3/4 of watchdog window). */
    PIT_SetTimerPeriod(PIT, kPIT_Chnl_0, MSEC_TO_COUNT(750, PIT_CLK));
    /* Enable timer interrupts for channel 0. */
    PIT_EnableInterrupts(PIT, kPIT_Chnl_0, kPIT_TimerInterruptEnable);
    /* Enable at the NVIC. */
    EnableIRQ(PIT_IRQ);


    /* Change default baudrate. */
    masterConfig.baudRate_Bps = I2C_BAUDRATE;
    //初始化I2C控制器
    sourceClock = I2C_MASTER_CLK;
    I2C_MasterInit(I2C_MASTER_BASEADDR, &masterConfig, sourceClock);
    

     /* 看门狗配置 - 看门狗使能, 使能窗口模式, 1024 ms 窗口. */
    status = PF8X_SetWatchdogConfig(&drvData, true, false, PF8X_F_WD_DURATION_1024_MS, PF8X_F_WD_MAX_EXPIRE_7, PF8X_F_WD_MAX_CNT_15);
    if (status != pf8xStatusOk)
    {
      //I2C通信错误
      while (1) 
      {
        if(wdFlag == true)//注册定时器将喂狗标志位置为真
        {
            status = PF8X_ClearWatchdog(&drvData);
            if (status != pf8xStatusOk)
            {
              /* I2C error. */
              while (1) {}
            }

            /* Read watchdog status. */
            status = PF8X_GetWatchdogStatus(&drvData, &wdExpCnt, &wdEvCnt);
            if (status != pf8xStatusOk)
            {
              /* I2C error. */
              while (1) {}
            }
        }    
      }
    }

}

十六宿舍 原创作品,转载必须标注原文链接。

©2023 Yang Li. All rights reserved.

欢迎关注 『十六宿舍』,大家喜欢的话,给个👍,更多关于嵌入式相关技术的内容持续更新中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/443337.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

阅读完synchronized和ReentrantLock的源码后,我竟发现其完全相似

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱敲代码的小黄&#xff0c;独角兽企业的Java开发工程师&#xff0c;CSDN博客专家&#xff0c;阿里云专家博主&#x1f4d5;系列专栏&#xff1a;Java设计模式、数据结构和算法、Kafka从入门到成神、Kafka从成神到升仙…

【数据结构】七大排序之快速排序详解(挖坑法快排,非递归快排,二路快排,三路快排)

目录 1.快速排序核心思路 2.挖坑法快速排序&#xff08;递归&#xff09; 2.1步骤 2.2代码&#xff08;详细注释&#xff09; 3.非递归快排&#xff08;用栈实现快速排序&#xff09; 3.1思路 3.2代码 4.二路快排 4.1思路 4.2代码 5.三路快排 5.1思路 5.2代码 1.快速…

大白话chatGPT及其原理之快速理解篇

大白话chatGPT及其原理之快速理解篇 从GPT名字理解chatGPTchatGPT三步曲 声明&#xff1a;本文为原创&#xff0c;未经同意请勿转载&#xff0c;感谢配合&#x1f604; chatGPT今年年初的时候是非常火爆的&#xff0c;现在也有很多相关的应用和插件。当然现在也有很多新的技术出…

老宋 带你五分钟搞懂vue

Vue 1.1 什么是框架 任何编程语言在最初的时候都是没有框架的&#xff0c;后来随着在实际开发过程中不断总结『经验』&#xff0c;积累『最佳实践』&#xff0c;慢慢的人们发现很多『特定场景』下的『特定问题』总是可以『套用固定解决方案』。于是有人把成熟的『固定解决方案…

袋鼠云春季生长大会圆满落幕,带来数实融合下的新产品、新方案、新实践

4月20日&#xff0c;以“数实融合&#xff0c;韧性生长”为主题的袋鼠云春季生长大会圆满落幕。 在春季生长大会中&#xff0c;袋鼠云带来了数实融合趋势下的最新行业沉淀、最佳实践经验和行业前瞻性的产品发布。从大数据基础软件“数栈”、到低代码数字孪生世界“易知微”&…

离散数学-考纲版-01-命题逻辑

文章目录 1. 命题逻辑的等值演算与推理演算参考1.1 命题1.2 常用联结词1.3 命题公式命题公式的分类-重言式-矛盾式-可满足式等价关系式-逻辑等价 logically equivalent 1.4 命题的等值演算与推理基本等价式逻辑蕴涵重言式 logically implication重言蕴涵推到归结法 1.5 命题公式…

log4j2日志简单使用

log4j2日志使用 1、log4j2介绍 Apache Log4j2是对Log4j的升级版&#xff0c; log4j2借鉴了logback的一些优秀的设计&#xff0c;并且修复了一些问题&#xff0c;因此带来了一些重大的提升&#xff0c;主要有&#xff1a; 1、异常处理&#xff1a;在logback中&#xff0c;Appe…

Makefile通用模板

工程目录 假如我们有以下目录结构&#xff1a; . ├── inc │ ├── add.h │ └── sub.h ├── main.c └── src├── add.c└── sub.c文件中的内容如下&#xff1a; //main.c #include <stdio.h> #include "add.h" #include "sub.h&q…

Mysql 学习(六)Mysql的数据目录

数据库中数据的存放 Mysql中 InnoDB 和 MyISAM 这样的存储引擎都是把数据存储到磁盘上的&#xff0c;而我们把这种存放到磁盘上的东西叫做文件系统&#xff0c;当我们想读取对应数据的时候&#xff0c;就会把数据从文件系统上加载&#xff0c;并且处理返回给我们&#xff0c;当…

每日学术速递4.19

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CV 1.Visual Instruction Tuning 标题&#xff1a;可视化指令调优 作者&#xff1a;Haotian Liu, Chunyuan Li, Qingyang Wu, Yong Jae Lee 文章链接&#xff1a;https://arxiv.org/ab…

Midjourney:一步一步教你如何使用 AI 绘画 MJ

一步一步如何使用 Midjourney 教程&#xff1a;教学怎么用 MJ&#xff1f; 一、Midjourney&#xff08;MJ&#xff09;是什么&#xff1f; Midjourney是一款使用文字描述来生成高质量图像的AI绘画工具。这篇文章主要介绍了Midjourney及其用途&#xff0c;并针对Midjourney的使…

python 定时任务执行命令行

1.使用场景&#xff1a; 定时执行jmeter脚本&#xff0c;通过python定时器隔一段时间执行命令行命令。 2.库&#xff1a; os、datetime、threading &#xff08;1&#xff09;利用threading.Timer()定时器实现定时任务 Timer方法说明Timer(interval, function, argsNone, k…

如何利用python实现TURF分析?

1.TRUF分析简介 TURF分析(Total Unduplicated Reach and Frequency)是累计净到达率和频次分析的简称。最初被应用于媒介研究领域。典型应用场景是&#xff0c;在既定条件下&#xff0c;例如预算等资源限制或就当前实施的媒体组合投放计划&#xff0c;哪些渠道组合能让广告投放…

【三十天精通Vue 3】第十二天 Vue 3 过滤器详解

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 &#x1f31f;专栏地址: 三十天精通 Vue 3 文章目录 引言一、Vue 3 过滤器概述1.1 过滤器的简介1.2 过滤器的作用1.3 过…

WEB通用漏洞水平垂直越权详解业务逻辑访问控制脆弱验证

目录 一、知识点概述 <分类> <原理简述> 二、水平越权示例——检测数据比对弱 <越权演示> <如何防护> 三、垂直越权示例——权限操作无验证 <越权演示> <漏洞成因> 四、访问控制示例——代码未引用验证 <越权演示> 五、脆…

如何才能写出一个符合预期的正则?

如何才能写出一个符合预期的正则&#xff1f; 正则表达式入门示例讲解1、java里正则表达式replaceAll连续的字符正则测试题主问题讲解 2、开发者遇到金额的校验正则描述正则测试 3、java正则表达式匹配字符串正则描述正则测试 4、关于#正则表达式#的问题&#xff0c;如何解决&a…

0基础自学软件测试 用这个方法 99%的人都成功了

对于大多数0基础的小白而言&#xff0c;刚开始学软件测试&#xff0c;肯定会遇到各种各样的难题&#xff0c;有时候问题多了&#xff0c;扛不住了&#xff0c;导致最后无法坚持&#xff0c;或者学的很杂&#xff0c;学而不精。 那么有哪些比较有效的方法和技巧&#xff0c;可以…

系统分析师之数据库系统(七)

目录 一、数据库概念 1.1 数据库管理系统DBMS 1.2 数据库系统DBS 二、数据库设计 2.1 数据库设计过程 2.2 E-R模型 2.3 关系代数 2.4 规范化理论 2.4.1 价值与用途 2.4.2 函数依赖 2.4.3 键 2.4.4 范式 2.4.5 无损分解 三、并发控制 3.1 基本概念 3.2 问题示例…

SCA技术进阶系列(二):代码同源检测技术在供应链安全治理中的应用

一、直击痛点&#xff1a;为什么需要同源检测 随着“数字中国”建设的不断提速&#xff0c;企业在数字化转型的创新实践中不断加大对开源技术的应用&#xff0c;引入开源组件完成应用需求开发已经成为了大多数研发工程师开发软件代码的主要手段。随之而来的一个痛点问题是&…

开启数字化之旅:VR全景视频带你进入真实而神奇的世界

引言&#xff1a;随着科技的不断发展&#xff0c;虚拟现实技术正在成为越来越多人所追捧和体验的技术。而VR全景视频作为虚拟现实技术的一种重要应用&#xff0c;也得到了越来越多人的关注。那么&#xff0c;VR全景视频到底是什么&#xff1f;它的优势和特点是什么&#xff1f;…