目录
Wdt模块概念解析
库函数后缀pal解析
将对应库函数添加到对应工程中
S32DS配置WGT、Timer外设参数
FTM_MC外设函数
FTM_DRV_Init函数定义
FTM_DRV_ClearStatusFlags外设函数
FTM_DRV_InitCounter外设函数
FTM_DRV_InitCounter外设函数
FTM_DRV_CounterStart外设函数
INT_SYS_InstallHandler外设函数
INT_SYS_InstallHandler定义
INT_SYS_EnableIRQ外设函数
WDOG_DRV_Init外设函数
WDOG_DRV_Init外设函数
WDOG_DRV_Trigger函数解析
POWER_SYS_GetResetSrcStatusCmd函数
编写ftmCallback中断响应函数
Wdt模块概念解析
这里需要注意的是看门狗模块在S32K144中称为WDT(Watchdog Timer)模块,但是在消费电子总则称为iwdg或wwdg模块,首先名字上有区别其实WGT芯片片上外设,使用的是片上外设自己的时钟源,同时可以被配置为iwdg模块跟wwdg模块的功能,根据S32DS中就能进行配置选择。
然后看门狗当程序出现错误的时候,如程序卡死、跑飞、硬件故障的时候看门狗模块就会触发,然后触发系统内部复位,然后进行运行。
库函数后缀pal解析
在S32DS的工程中有些驱动后面会跟一个pal,这里跟pal的意思是外设抽象层,如果没有跟pal则是外设驱动层,抽象层是在驱动层上面进一部封装,如果你的程序需要再S32DS的不同芯片上进行移植的话,可以通过选择pal层进行编写程序,这样改动的少,但是程序如果不需要移植,可以随便选。
但是如果不需要一直,驱动层对于驱动抽象层的好处是程序运行快,不需要进行二次封装等优势。
将对应库函数添加到对应工程中
这里首先添加看门狗、电源管理的工程库函数。
然后再添加看门狗对应的定时器到工程中。
S32DS配置WGT、Timer外设参数
然后需要配置看门狗、定时器的时钟分频系数,等参数具体截图如下所示,首先选择看门狗时钟源,然后开启中断、然后设置Timeout Value的数值,这个数值是看门狗的超时时间,即定时器超过这个时间,系统发出中断然后开启中断。
这里需要注意的是Window Value 还有Timeout Value 这两个数值,这两个数值前者是最低喂狗时间,然后Timeout Value是最晚喂食时间,然后如果Window Value的数值不设置就是独立看门狗,如果Window Value的设置就是窗户看门狗。
然后这里配置定时器,定时器的分频系数,还有定时器超时开启中断配置。
需要注意的是这里通过定时器产生的中断函数来在中断函数中进行喂狗,如果定时器产生的中断函数没有及时喂狗,那么系统看门狗就会调用中断函数,通常用于保存数据等,同时系统开始复位。
FTM_MC外设函数
这里首先需要初始化喂狗使用的定时器,具体初始化函数解析,跟代码如下所示。
FTM_DRV_Init函数定义
该函数用于将定时器外设生成结构体配置代码,初始化进芯片中,函数原型如下所示。
status_t FTM_DRV_Init(uint32_t instance, const ftm_user_config_t * info, ftm_state_t * state)然后再函数参数中,第一个参数 instance 是选择初始化那个芯片外设,然后第二个参数是将定时器配置界面配置参数生成的结构体定义,进行取地址,ftm_user_config_t 也就是用户配置定时器配置结构体,将用户的配置初始化到instance选择的芯片外设中,然后state结构体中定义了大量的定时器外设状态成员属性。
在运行的过程中,state的成员属性会实时进行更新,同时如果需要查询定时器频率或者中断等状态,可以通过state的这个结构体边量来进行查询。
FTM_DRV_ClearStatusFlags外设函数
该函数用来清楚系统中断标志位,防止没有清楚系统中断标志位,系统中断一直被触发,具体函数原型如下所示。
void FTM_DRV_ClearStatusFlags(uint32_t instance, uint32_t flagMask)首先这里需要注意的是instance同样是对应的芯片外设,然后flagMask这个参数是对应的想要函数清楚的系统硬件中断标志位,这个函数只能用来清楚标志位,硬件的中断触发标志位是由芯片硬件来完成触发的。
这个函数常用的清楚标志位如下所示。
FTM_TIMER_OVERFLOW_FLAG—— 定时器溢出标志(TOF)FTM_CHANNEL0_EVENT_FLAG—— 通道 0 事件标志(CH0F)FTM_CHANNEL1_EVENT_FLAG、FTM_CHANNEL2_EVENT_FLAG等FTM_FAULT_DETECT_FLAG—— 故障检测标志
FTM_DRV_InitCounter外设函数
这个函数用来开启定时器计数模式,这个函数只用来配置定时器的定时模式,舍弃了定时器的pwm ICU等功能。
FTM_DRV_InitCounter外设函数
这个函数中两个参数其中instance是对应的系统硬件编号,然后ftm_timer_param_t这个结构体是对应的系统配置中生成的硬件结构体参数。
status_t FTM_DRV_InitCounter(uint32_t instance, const ftm_timer_param_t * timer) #define INST_FLEXTIMER_MC1 0U /* Timer mode configuration for flexTimer_mc1 */ ftm_timer_param_t flexTimer_mc1_TimerConfig = { FTM_MODE_UP_TIMER, /* Counter mode */ 0U, /* Initial counter value */ 37500U, /* Final counter value */ };然后将这些系统初始化配置,初始化对应的定时器定时模式中进去。
FTM_DRV_CounterStart外设函数
开启定时器计数模式函数,在完成配置定时器计数模式的函数初始化之后,需要调用这个函数来开启计数模式,具体函数原型如下所示。
status_t FTM_DRV_CounterStart(uint32_t instance)这里需要注意的是,该函数顺序必须在函数定时器模式配置之后,在调用这个函数。
INT_SYS_InstallHandler外设函数
首先这个函数中INT是中断的缩写,然后SYS是系统的意思,Intasll是安装的意思,然后Handler是第一个意思也就是处理程序的意思,除此之外handler还有一个意思在程序中也经常使用也就是句柄的意思,这意思通常指的是,程序资源或者对象标识符,通常一个函数返回值也能够称为句柄进行使用。
INT_SYS_InstallHandler定义
首先这个函数是S32DS中的中断注册函数,这个函数能够修改中断向量表,将自己定义的函数newHandler绑定到系统的硬件资源上去,具体函数原型如下所示。
void INT_SYS_InstallHandler(IRQn_Type irqNumber, const isr_t newHandler, isr_t* const oldHandler)其中irqNunber是对应的硬件外设中断,然后newhandler是新的处理函数,oldhandler是旧的程序如果没有这里通过(isr_t * )0,也就是空指针来进行处理。
同时在初始化完成之后,系统就会调用自己定义的中断处理函数来相应对应的中断事件发生了。
INT_SYS_EnableIRQ外设函数
在完成中断外设的初始化配置之后,还有进行Enable来进行使能,使能的目的是开启NVIC中断嵌套向量控制器的中断编号,如果不开启当外设硬件中断响应之后NVIC因为没有开启中断通道依然会被屏蔽掉。
void INT_SYS_EnableIRQ(IRQn_Type irqNumber)WDOG_DRV_Init外设函数
这个函数用来初始化看门狗,将外设配置的函数参数初始化进对应的芯片外设中去。
WDOG_DRV_Init外设函数
具体函数原型如下所示
status_t WDOG_DRV_Init(uint32_t instance, const wdog_user_config_t * userConfigPtr)首先这里instance是对应的芯片外设参数的意思,然后 wdog_user_config_t 结构体是封装了生成的代码配置的结构体,然后该函数通过将用户配置生成的外设基本参数代码,初始化进对应的外设当中去。
然后再配置完成时候同时需要配置对应的看门狗中断函数,同时开启对应的看门狗中断函数,具体代码如下所示。
INT_SYS_InstallHandler(WDOG_EWM_IRQn,&watch_isr,(isr_t*)0); INT_SYS_EnableIRQ(WDOG_EWM_IRQn);WDOG_DRV_Trigger函数解析
该函数用来执行喂狗操作,具体函数原型如下所示。
void WDOG_DRV_Trigger(uint32_t instance) { DEV_ASSERT(instance < WDOG_INSTANCE_COUNT); WDOG_Type * base = s_wdogBase[instance]; WDOG_Trigger(base); }在函数参数中instance是对应的芯片外设,然后在调用函数过后对这个芯片对应的看门狗来进行喂狗操作。
POWER_SYS_GetResetSrcStatusCmd函数
芯片复位查询函数,RCM这个模块是芯片上专门用来控制复位的一个模块,然后RCM是(Reset Control Moudle),是专门内置在S32K144芯片上的一个片上外设模块,是专门用来查询复位的,具体函数原型如下所示。
bool POWER_SYS_GetResetSrcStatusCmd(const RCM_Type * const baseAddr , const rcm_source_names_t srcName)然后函数的第一个参数填入RCM即可,然后第二个参数是选择查询对应的复位原因。是因为低电压复位,还是上电复位,等多种原因。
RCM_LOW_VOLT:低电压复位RCM_POWER_ON:上电复位RCM_EXTERNAL_PIN:外部引脚复位RCM_SYS_SOFTWARE:软件复位RCM_CORE_LOCKUP:内核死锁复位RCM_DEBUG_REQUEST:调试器复位
if(POWER_SYS_GetResetSrcStatusCmd(RCM,RCM_WATCH_DOG) == true) { PINS_DRV_TogglePins(PTD,(1<<15)); delay_ms(1000); }编写ftmCallback中断响应函数
定时器在中断系统安装相应程序的函数配置中,将ftmCallback这个函数名字关联到了对应的定时器中断响应函数里面,然后当定时器开启硬件中断之后会进行调用这个函数,同样的这里需要编写中断响应函数,在调用中断的时候完成作用,具体代码如下。
void ftmCallback(void) { cnt++;//每到100ms定时器就会调用这个函数 if(cnt == feed ) { WDOG_DRV_Trigger(INST_WATCHDOG1); PINS_DRV_TogglePins(PTD,(1<<0)); cnt=0; } FTM_DRV_ClearStatusFlags(INST_FLEXTIMER_MC1,FTM_TIME_OVER_FLOW_FLAG); }因为这里中断配置的目的是为了喂狗,所以在中断响应函数中,需要进行的目的是判断当前时间来在规定时间内完成喂狗,防止看门狗进行复位,同时在中断响应函数调用完成之后进行清除中断标志位,来防止中断进行二次触发。
/* ################################################################### ** Filename : main.c ** Processor : S32K1xx ** Abstract : CAN例程 发送接收CAN报文 ** Main module. ** This module contains user's application code. ** Settings : ** Contents : ** No public methods ** ** ###################################################################*/ /*! ** @file main.c ** @version 01.00 ** @brief ** Main module. ** This module contains user's application code. */ /*! ** @addtogroup main_module main module documentation ** @{ */ /* MODULE main */ /* Including necessary module. Cpu.h contains other modules needed for compiling.*/ #include "Cpu.h" #include "delay.h" //#include "key.h" volatile int exit_code = 0; /* //配置邮箱 #define CAN_TX_MAIL (0U) //发送邮箱 #define CAN_RX_MAIL (1U) //接收邮箱 #define CAN_FILTER 0x00 //CAN滤波器屏蔽设置 can_message_t recv_msg; //存储接收到的CAN报文 int flag=0; //can接收成功标志 uint8_t buff[8]; //存储接收到的can报文data数组 int id; //存储接收到的can报文id //can回调函数 void can_callback(uint32_t instance,can_event_t event,uint32_t buffIdx,void* state) { //调用can receive函数接收can报文 CAN_Receive(&can_pal1_instance, CAN_RX_MAIL, &recv_msg); //根据回调函数传入的can event事件做判断是发送还是接收 switch(event){ case CAN_EVENT_RX_COMPLETE: //接收完成事件 flag=1; //如果接收事件flag为1 break; case CAN_EVENT_TX_COMPLETE: //发送完成事件 break; default: break; } } //can初始化函数 void can_init() { //官方的can初始化函数调用 CAN_Init(&can_pal1_instance, &can_pal1_Config0); //can接收buff配置结构体 can_buff_config_t rx_config={ .enableFD=false, //启用FD模式配置 .enableBRS=false, //可变速率配置 .fdPadding=0U, //fd的padding选项配置 .idType=CAN_MSG_ID_STD, //帧类型 标准帧 扩展帧 .isRemote=false //是否为远程帧 }; //can发送buff配置结构 can_buff_config_t tx_config={ .enableFD=false, .enableBRS=false, .fdPadding=0U, .idType=CAN_MSG_ID_STD, .isRemote=false }; //配置接收buff CAN_ConfigRxBuff(&can_pal1_instance,CAN_RX_MAIL,&rx_config,CAN_FILTER); CAN_ConfigTxBuff(&can_pal1_instance,CAN_TX_MAIL,&tx_config);//配置发送buff CAN_SetRxFilter(&can_pal1_instance,CAN_MSG_ID_STD,CAN_RX_MAIL,CAN_FILTER);//配置接收滤波器 CAN_InstallEventCallback(&can_pal1_instance,&can_callback,NULL);//设置can回调函数 CAN_Receive(&can_pal1_instance,CAN_RX_MAIL,&recv_msg);//can接收函数 } */ int feed = 4U; int cnt = 0U; void ftmCallback(void) { cnt++;//每到100ms定时器就会调用这个函数 if(cnt == feed ) { WDOG_DRV_Trigger(INST_WATCHDOG1); PINS_DRV_TogglePins(PTD,(1<<0)); cnt=0; } FTM_DRV_ClearStatusFlags(INST_FLEXTIMER_MC1,FTM_TIME_OVER_FLOW_FLAG); } void watch_isr(void) { } /*! \brief The main function for the project. \details The startup initialization sequence is the following: * - startup asm routine * - main() */ int main(void) { /* Write your local variable definition here */ //记得初始化变量 ftm_state_t wdt_state; /*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/ #ifdef PEX_RTOS_INIT PEX_RTOS_INIT(); /* Initialization of the selected RTOS. Macro is defined by the RTOS component. */ #endif /*** End of Processor Expert internal initialization. ***/ /* Write your code here */ /* For example: for(;;) { } */ //时钟初始化 CLOCK_SYS_Init(g_clockManConfigsArr, CLOCK_MANAGER_CONFIG_CNT,g_clockManCallbacksArr, CLOCK_MANAGER_CALLBACK_CNT); CLOCK_SYS_UpdateConfiguration(0U, CLOCK_MANAGER_POLICY_AGREEMENT);//更新时钟 delay_init(); PINS_DRV_Init(NUM_OF_CONFIGURED_PINS, g_pin_mux_InitConfigArr); //初始化IO /* can_init(); //调用can初始化函数 can_message_t tx_msg={ .id=0x11, //设置id .length=8, //设置报文长度 .cs=0U, //命令码 .data[0]=0x01, //八个字节数据 .data[1]=0x11, .data[2]=0x21, .data[3]=0x31, .data[4]=0x41, .data[5]=0x51, .data[6]=0x61, .data[7]=0x71, };*/ FTM_DRV_Init(INST_FLEXTIMER_MC1, &flexTimer_mc1_InitConfig,&wdt_state); INT_SYS_InstallHandler(FTM0_Ovf_Reload_IRQn,&ftmCallback,(isr_t*)0); INT_SYS_EnableIRQ(FTM0_Ovf_Reload_IRQn); FTM_DRV_InitCounter(INST_FLEXTIMER_MC1, &flexTimer_mc1_TimerConfig); FTM_DRV_CounterStart(INST_FLEXTIMER_MC1); WDOG_DRV_Init(INST_WATCHDOG1, &watchdog1_Config0); INT_SYS_InstallHandler(WDOG_EWM_IRQn,&watch_isr,(isr_t*)0); INT_SYS_EnableIRQ(WDOG_EWM_IRQn); if(POWER_SYS_GetResetSrcStatusCmd(RCM,RCM_WATCH_DOG) == true) { PINS_DRV_TogglePins(PTD,(1<<15)); delay_ms(1000); } int flag = 0; while(1) { //发送消息 /* CAN_Send(&can_pal1_instance,CAN_TX_MAIL,&tx_msg); if(flag){ //如果接受成功 for(int i = 0 ;i<8;++i){ buff[i]=recv_msg.data[i]; //提取data } id=recv_msg.id;//提取id PINS_DRV_TogglePins(PTD, 1); //闪烁led PTD1 flag=0;//清零flag } delay_ms(200);*/ if(((PINS_DRV_ReadPins(PTC)>>12)&0x01)==0x01) { //读取某个GPIO端口 通过位移操作定位某一个pin delay_ms(20);//delay 按键去抖 if(((PINS_DRV_ReadPins(PTC)>>12)&0x01)==0x01) { //再次读取查看是否真正按下 if(flag==1) { //如果flag有效 feed=6;//清零flag } } } if(((PINS_DRV_ReadPins(PTC)>>12)&0x01)==0) { flag=1; } } /*** Don't write any code pass this line, or it will be deleted during code generation. ***/ /*** RTOS startup code. Macro PEX_RTOS_START is defined by the RTOS component. DON'T MODIFY THIS CODE!!! ***/ #ifdef PEX_RTOS_START PEX_RTOS_START(); /* Startup of the selected RTOS. Macro is defined by the RTOS component. */ #endif /*** End of RTOS startup code. ***/ /*** Processor Expert end of main routine. DON'T MODIFY THIS CODE!!! ***/ for(;;) { if(exit_code != 0) { break; } } return exit_code; /*** Processor Expert end of main routine. DON'T WRITE CODE BELOW!!! ***/ } /*** End of main routine. DO NOT MODIFY THIS TEXT!!! ***/ /* END main */ /*! ** @} */ /* ** ################################################################### ** ** This file was created by Processor Expert 10.1 [05.21] ** for the NXP S32K series of microcontrollers. ** ** ################################################################### */