本篇文章首先从理论讲起,从AUTOSAR规范以及MCAL手册两个不同角度(前者偏理论,后者偏实践)介绍了ICU模块的背景概念与理论,帮助读者在实际配置之前能有个理论的框架。然后详细的介绍了在TC397平台使用EB tresos对ICU驱动模块进行配置与调试的实战过程。文章首先介绍了常用的信号测量模式的配置,然后分别介绍了边沿计数、边沿检测以及时间戳记录的配置方式,全面的介绍了ICU模块的使用。
ICU模块作为比较常见的方波信号测量模块被广泛使用在不同的项目工程中。本文在最后根据前文介绍过的四种不同使用模式介绍了调试的代码以及调试结果,希望帮助读者更直观的理解ICU模块的使用。
目录
AUTOSAR规范解析
ICU驱动程序使用输入捕获单元(ICU)来解调PWM信号、脉冲计数、测量频率和占空比,并可以生成简单/唤醒中断。它只要提供以下服务:
- 控制唤醒中断
- 周期信号测量
- 边缘计数
- 信号边缘通知
- 记录边缘时间戳,可用于非周期信号的采集
ICU的信号测量模式(IcuMeasurementMode)一共支持以下几种类型:
- 边沿检测(ICU_MODE_SIGNAL_EDGE_DETECT):ICU通道检测到Icu_17_TimerIp_SetActivationCondition()配置的activation边沿(ICU_17_TIMERIP_RISING_EDGE、ICU_17_TIMERIP_FALLING_EDGE、ICU_17_TIMERIP_BOTH_EDGES)之后,产生中断。
- 信号测量(ICU_MODE_SIGNAL_MEASUREMENT):用于测量各种可配置边沿之间的不同时间。周期起始边缘的配置是通过配置完成的,并且在运行时无法更改。这种模式可以用于测量输入PWM信号的周期和占空比。
- 时间戳捕获(ICU_MODE_TIMESTAMP):用于捕获信号边沿对应的定时器值,这些边沿由Icu_17_TimerIp_SetActivationCondition()配置。
- 边沿计数(ICU_MODE_EDGE_COUNTER):用于对Icu_17_TimerIp_SetActivationCondition()配置的边沿进行计数。
缩略语
- Active Time:这取决于要捕获信号的起始边沿。
- 如果Start edge = falling edge,则Active Time = Low Time。
- 如果Start edge = rising edge,则Active Time = High Time。
- Start edge = both edges,则Active Time = High Time (如果上升沿出现在信号开始)。
- Start edge = both edges,则Active Time = Low Time(如果下降沿出现在信号开始)。
- DEM:Diagnostic Event Manager,基础软件中的诊断故障管理模块。
- DET:Default Error Tracer,基础软件中的错误跟踪模块。
- EcuM:ECU State Manager,基础软件中的ECU状态管理模块。
- Enumeration:C程序设计语言中的枚举或宏定义。
- ICU:Input Capture Unit,输入获取单元。
- ICU Channel:表示绑定到一个输入信号的逻辑ICU通道,其可以单独配置测量模式。
- ICU State:ICU通道的输入状态,可以为ICU_ACTIVE或ICU_IDLE。
- ICU_ACTIVE:activation边沿被检测到。
- ICU_IDLE:自从Icu_GetInputState()或者Icu_Init()被调用之后,activation边沿没有被检测到。
- Symbolic name for a channel:它是通道配置和相关属性的符号句柄,可以通过它访问配置结构体中此通道的配置。
- Wakeup event:唤醒事件在边沿检测模式中使用,这将导致相应驱动程序的唤醒。然而,是否有效边沿的决定不是由这个驱动程序完成的。这应由上层完成。
时序图
Icu_Init
ICU模块初始化,注解说明了一种常见的配置。
Icu_DeInit
ICU模块的去初始化。
Icu_SetMode
配置ICU模式为NORMAL模式,以及Notification与Wakeup的使能情况。NORMAL模式使能所有配位的通知对应中断,而SLEEP模式则是一种低功耗模式,仅仅使能具有wakeup能力的通知对应中断。
下图这是一个相对复杂的情况,ICU模块的使用者在配置完Actication的边沿之后,使能了Notification,所以在NORMAL模式下通知能够正常上报给使用着,但是配置为SLEEP模式之后,可以看到Channel虽然有Actication的边沿,但是并没有上报,只有在配置了wakeup能力的Channel有Actication的边沿之后,触发EcuM检测是否为有效事件并最终触发唤醒事件,用户再次配置ICU为NORMAL模式。
Icu_DisableWakeup
下面的示例是失能了Channel1的Wakeup能力,可以看到失能之后既不能wakeup-notification也没有rising edge notification。相应的Icu_EnableWakeup这里不再介绍。
Icu_SetActivationCondition
下面的例子可以看到,一开始当default start edge = ICU_BOTH_EDGES时,信号的上升和下降沿都能触发Notification,后来配置具体ICU_FALLING_EDGE或者ICU_RISING_EDGE,就会在对应的边沿触发Notification。
Icu_DisableNotification
失能通道的Notification,Icu_EnableNotification用来使能,就不赘述了。
Icu_GetInputState
除了ICU主动Notification,用户也可以主动查询结果,下图为使用Icu_GetInputState获取当前信号状态。
Icu Timestamping
下图将显示不同时间戳,ICU驱动的动作。
Icu Edge Counting
下图为ICU模块用作边沿计数的时序图。
Icu_GetTimeElapsed
将ICU的通道配置为SignalMeasurement,测量的电平状态为LowTime,使用Icu_GetTimeElapsed可以获得当前最新的低电平持续状态(上升沿或者读取操作会刷新当前值)。
如果Signal Measurement Property = PeriodTime,则可获取信号的周期事件,如下图。
Icu_GetDutyCycleValues
这是我们最常用的功能了,用于获得P波的ActiveTime以及PeriodTime,用户可以基于这两个节拍数计算获得占空比(ActiveTime/PeriodTime)。
MCAL用户手册
ICU 驱动程序负责提供 AUTOSAR指定的标准信号测量服务。ICU通道的底层捕获引擎可以是 GTM模块的TIM通道、CCU6模块的CC6 比较器、ERU通道或GPT12计时器。下图ICU的软/硬件接口图。
模块硬件依赖
ICU主要依赖的片内外设主要有GTM-TIM、CCU6、ERU和SCU。
ICU驱动器使用GTM-TIM对输入信号进行边沿检测、边沿计数、信号测量和时间戳。ICU驱动使用的关键GTM-TIM功能有:
- TIM通道在TPWM、TIEM和TIPM模式下超时检测(TDU)。多种工作模式可以实现对输入信号周期、占空比、边沿个数和边沿类型的检测。
- 多种的滤波模式,可以实现对输入信号的滤波处理。
- 信道时钟源配置,时钟信号来源于GTM的可配置时钟。
- 可以在检测到指定边沿或周期数后产生中断,测量后的数据保存在指定寄存器中供ICU驱动读取和使用。
GTM的TIM通道由ICU驱动程序独占使用TIM 通道不会与任何其他驱动程序共享MCU驱动程序提供 API,用于对 GTM的SFRs进行编程。ICU驱动程序使用这些API写入GTM的SFRs。MCU驱动程序还提供对TIM 通道的PORT引脚连接的设置和初始化。此外,对通道特定SFRS的更新由ICU驱动完成。由于这些通道专门保留给ICU驱动程序,因此不允许其他驱动程序或用户软件访问通道的SFRs。
TIM模块滤波模式可以配置为上升沿或下降沿。以下降沿滤波为例来说明。
- 即时边沿传播模式:检测到下降沿后立即输出,并在指定时间内保持低电平状态。
- 独立抗尖峰脉冲时间模式(上/下计数):检测到下降沿后计数器开始加数计数,检测到上升沿后计数器开始减数计数,直到计数器达到指定值,则判定该边沿有效并作为滤波后的输出。
- 独立抗尖峰脉冲时间模式(计数保持):检测到下降沿后计数器开始加数计数,检测到上升沿后计数器保持当前计数值不变,直到计数器达到指定值,则判定该边沿有效并作为滤波后的输出。
- 独立抗尖峰脉冲时间模式(计数复位:检测到下降沿后计数器开始加数计数,检测到上升沿后计数器复位为0,直到计数器达到指定值,则判定该边沿有效并作为滤波后的输出。
ICU驱动程序使用GTM-TIM中的下列硬件事件:
- 新值测量(NEWVAL):用于边沿检测、边沿计数、信号测量和时间戳记录。
- CNT计数器溢出(CNTOFL):用于识别计数器溢出。
- 超时检测(TODET):用于识别输入信号达到的超时阈值。
ICU驱动器可以使用T12定时器实例的CC6来实现信号测量、时间和信号边缘检测功能。ICU驱动程序使用的关键CCU6功能有:
- 时钟分频和预分频配置。
- 从PORT引脚选择CC6片的输入信号。
- 在捕获模式下的CC6比较器。
属于CCU6核心的T12的CC6x比较器被ICU通道使用。可以将CCU6核心保留为PWM或ICU。但是,为 ICU保留的核心的所有比较器都是专用于ICU的。ADC还可以使用CCU6触发事件,这些事件不会影响ICU的任何功能。MCU驱动程序提供用于编程CCU6的SFRs的API。ICU驱动程序使用这些API写入CCU6的SFRs。此外,由ICU驱动程序执行对特定通道SFRs的更新。由于这些通道专用于ICU驱动程序,因此不允许其他驱动程序或用户软件访问特定通道的SFRs。
ERU模块可用于信号边缘检测和通知的目的。ICU驱动使用的关键ERU功能有:
- ERU功能块的通道边沿检测特性由ICU驱动器配置和访问。
- ICU还为ERU通道配置PORT引脚选择。
ERU输入通道用于输入选择,ERU输出通道用于中断触发,由ICU驱动程序使用。由于两个ERU输出通道共享相同的中断线,因此两个通道应分配给相同的模块。ERU输入通道可由ICU、ADC或DSADC驱动程序使用。
ICU驱动程序使用GPT12外围设备的GPT定时器,实现边沿检测、边沿计数和增量接口模式。ICU驱动使用的关键GPT12功能有:
- 时钟预分频。
- 输入Port选择。
- Counter中的计时器和增量接口模式。
GPT12的GPT计时器实例由ICU驱动程序使用。GPT12计时器块可以与GPT驱动程序共享。MCU驱动程序提供API来编程GPT12的SFRs。ICU驱动程序使用这些API来写入GPT12的SFRs。此外,通道特定SFRs的更新由ICU驱动程序执行。由于这些通道专门保留给ICU驱动程序,因此不允许其他驱动程序或用户软件访问通道特定SFRs。
ICU驱动程序依赖于SCU的时钟、ENDINIT和复位功能。驱动程序需要fSPB和fGTM时钟信号才能正常工作。
下面是不同的检测模式对应需要的片内硬件支持以及具体的功能。
测量模式 | 片内硬件 | 功能特性 |
Edge detection | GTM(TIM), CCU6, GPT12 and ERU | Notifications, wake-up capable, timeout (only on TIM) |
Multi Edge detection | GTM(TIM) and GPT12 | Notifications |
Edge count | GTM(TIM) and GPT12 | Edge counting up to 32-bit, timeout (only on TIM) |
Signal measurement | GTM(TIM) and CCU6 | High time, low time, period and duty cycle |
Time stamp | GTM(TIM) and CCU6 | Linear and circular buffer, notifications |
Incremental interface mode | GPT12( Only T2, T3 and T4) | Detect direction and position from incremental encoder. Notification on encoder counter overflow/ underflow and on every count edge. |
驱动集成要点
与AUTOSAR基础软件的集成要点
EcuM:ECU管理模块是AUTOSAR基础软件的一部分,用于管理ECU。具体来说,在MCAL的上下文中,EcuM用于初始化和去初始化软件驱动程序。用户应在EcuM配置中配置唤醒信息,该信息将分配给每个具有唤醒功能的ICU通道。ICU中的MCAL包中提供的EcuM模块是stub代码(桩代码),需要在集成阶段用完整的EcuM模块替换。
Memory mapping:内存映射是AUTOSAR的一个概念,它允许将文本、变量、常量和配置数据重新定位到用户特定的内存区域。为了实现这一点,驱动程序的所有可重新定位元素都被封装在不同的内存段宏中。这些宏在lcu中定义在Icu_17_Timerlp_MemMap.h文件中,它在MCAL包中作为stub代码(桩代码)提供。集成者必须在内存部分宏中放置适当的编译器语法。语法确保元素被重新定位到正确的内存区域。示例实现列出了内存部分宏,如下所示。
/**** GLOBAL RAM DATA -- NON-CACHED LMU ****/
#if defined ICU_17_TIMERIP_START_SEC_VAR_CLEARED_ASIL_B_GLOBAL_32
/*****User pragmas here for Non-cached LMU*****/
#undef ICU_17_TIMERIP_START_SEC_VAR_CLEARED_ASIL_B_GLOBAL_32
#undef MEMMAP_ERROR
#elif defined ICU_17_TIMERIP_STOP_SEC_VAR_CLEARED_ASIL_B_GLOBAL_32
/*****User pragmas here for Non-cached LMU*****/
#undef ICU_17_TIMERIP_STOP_SEC_VAR_CLEARED_ASIL_B_GLOBAL_32
#undef MEMMAP_ERROR
/**** CORE[x] RAM DATA -- DSPR ****/ /*[x]=0..5*/
#elif defined ICU_17_TIMERIP_START_SEC_VAR_CLEARED_ASIL_B_CORE[x]_32
/*****User pragmas here for CORE[x] DSPR*****/
#undef ICU_17_TIMERIP_START_SEC_VAR_CLEARED_ASIL_B_CORE[x]_32
#undef MEMMAP_ERROR
#elif defined ICU_17_TIMERIP_STOP_SEC_VAR_CLEARED_ASIL_B_CORE[x]_32
/*****User pragmas here for CORE[x] DSPR*****/
#undef ICU_17_TIMERIP_STOP_SEC_VAR_CLEARED_ASIL_B_CORE[x]_32
#undef MEMMAP_ERROR
/**** CORE[x] RAM DATA INIT -- DSPR ****/ /*[x]=0..5*/
#elif defined ICU_17_TIMERIP_START_SEC_VAR_INIT_ASIL_B_CORE[x]_32
/*****User pragmas here for CORE[x] DSPR*****/
#undef ICU_17_TIMERIP_START_SEC_VAR_INIT_ASIL_B_CORE[x]_32
#undef MEMMAP_ERROR
#elif defined ICU_17_TIMERIP_STOP_SEC_VAR_INIT_ASIL_B_CORE[x]_32
/*****User pragmas here for CORE[x] DSPR*****/
#undef ICU_17_TIMERIP_STOP_SEC_VAR_INIT_ASIL_B_CORE[x]_32
#undef MEMMAP_ERROR
/**** GLOBAL CONST DATA -- PF[x] ****/
#elif defined ICU_17_TIMERIP_START_SEC_CONST_ASIL_B_GLOBAL_32
/*****User pragmas here for PF[x]*****/
#undef ICU_17_TIMERIP_START_SEC_CONST_ASIL_B_GLOBAL_32
#undef MEMMAP_ERROR
#elif defined ICU_17_TIMERIP_STOP_SEC_CONST_ASIL_B_GLOBAL_32
/*****User pragmas here for PF[x]*****/
#undef ICU_17_TIMERIP_STOP_SEC_CONST_ASIL_B_GLOBAL_32
#undef MEMMAP_ERROR
/**** GLOBAL CONFIG DATA -- PF[x] ****/
#elif defined ICU_17_TIMERIP_START_SEC_CONFIG_DATA_ASIL_B_GLOBAL_UNSPECIFIED
/*****User pragmas here for PF[x]*****/
#undef ICU_17_TIMERIP_START_SEC_CONFIG_DATA_ASIL_B_GLOBAL_UNSPECIFIED
#undef MEMMAP_ERROR
#elif defined ICU_17_TIMERIP_STOP_SEC_CONFIG_DATA_ASIL_B_GLOBAL_UNSPECIFIED
/*****User pragmas here for PF[x]*****/
#undef ICU_17_TIMERIP_STOP_SEC_CONFIG_DATA_ASIL_B_GLOBAL_UNSPECIFIED
#undef MEMMAP_ERROR
/**** CORE[x] CONFIG DATA -- PF[x] ****/ /*[x]=0..5*/
#elif defined ICU_17_TIMERIP_START_SEC_CONFIG_DATA_ASIL_B_CORE[x]_UNSPECIFIED
/*****User pragmas here for PF[x]*****/
#undef ICU_17_TIMERIP_START_SEC_CONFIG_DATA_ASIL_B_CORE[x]_UNSPECIFIED
#undef MEMMAP_ERROR
#elif defined ICU_17_TIMERIP_STOP_SEC_CONFIG_DATA_ASIL_B_CORE[x]_UNSPECIFIED
/*****User pragmas here for PF[x]*****/
#undef ICU_17_TIMERIP_STOP_SEC_CONFIG_DATA_ASIL_B_CORE[x]_UNSPECIFIED
#undef MEMMAP_ERROR
/**** CODE -- PF[x] ****/
#elif defined ICU_17_TIMERIP_START_SEC_CODE_ASIL_B_GLOBAL
/*****User pragmas here for PF[x]*****/
#undef ICU_17_TIMERIP_START_SEC_CODE_ASIL_B_GLOBAL
#undef MEMMAP_ERROR
#elif defined ICU_17_TIMERIP_STOP_SEC_CODE_ASIL_B_GLOBAL
/*****User pragmas here for PF[x]*****/
#undef ICU_17_TIMERIP_STOP_SEC_CODE_ASIL_B_GLOBAL
#undef MEMMAP_ERROR
#endif
#if defined MEMMAP_ERROR
#error "Icu_17_TimerIp_MemMap.h, wrong pragma command"
#endif
DET:DET模块是AUTOSAR基础软件的一部分,用于处理BSW模块报告的所有开发和运行时错误,ICU驱动程序通过Det_ReportError()将所有开发错误报告给DET模块。ICU驱动程序的用户必须处理通过Det_ReportError()报告给DET模块的所有错误。在MCAL软件包中,Det.h和Det.c文件作为一个stub代码(桩代码)提供,在集成阶段需要用完整的DET模块来替换。
SchM:SchM模块是RTE的一部分,用于管理BSW程序调度。lcu驱动程序使用SchM_Icu_17_TimerIp.h中定义的函数接口来保护SFRs和变量免受不同线程的并发访问。涉及的防重入的内容有:
- ResetEdgeCount
- SetActivationCondition
- GtmEnableEdgeCount
- GtmGetDutyCycle
SchM_Icu_17_TimerIp.h与SchM_Icu_17_TimerIp.c以桩代码的形式提供,集成者需要补全其中的中断suspend / resume操作。下面一种示例:
/**** Sample implementation of SchM_Icu_17_TimerIp.c ****/
#include "Os.h"
/* Disable the interrupts for entering critical section */
void SchM_Enter_Icu_17_TimerIp_ResetEdgeCount(void)
{
SuspendAllInterrupts();
}
/* Re-enable the interrupt for exiting the critical section */
void SchM_Exit_Icu_17_TimerIp_ResetEdgeCount(void)
{
ResumeAllInterrupts();
}
/* Disable the interrupts for entering critical section */
void SchM_Enter_Icu_17_TimerIp_SetActivationCondition(void)
{
SuspendAllInterrupts();
}
/* Re-enable the interrupt for exiting the critical section */
void SchM_Exit_Icu_17_TimerIp_SetActivationCondition(void)
{
ResumeAllInterrupts();
}
/* Disable the interrupts for entering critical section */
void SchM_Enter_Icu_17_TimerIp_GtmEnableEdgeCount(void)
{
SuspendAllInterrupts();
}
/* Re-enable the interrupt for exiting the critical section */
void SchM_Exit_Icu_17_TimerIp_GtmEnableEdgeCount(void)
{
ResumeAllInterrupts();
}
/* Disable the interrupts for entering critical section */
void SchM_Enter_Icu_17_TimerIp_GtmGetDutyCycle(void)
{
SuspendAllInterrupts();
}
/* Re-enable the interrupt for exiting the critical section */
void SchM_Exit_Icu_17_TimerIp_GtmGetDutyCycle(void)
{
ResumeAllInterrupts();
}
Notifications and callbacks:ICU驱动程序不执行任何通知。但是,ICU 驱动程序通过通知功能报告检测到的边沿和所需的时间戳捕获。这些通知功能可以通过Tresos为每个通道(在边沿检测和时间戳模式中)由用户配置。ICU不期待应用程序的任何回调。但ICU需要MCU的回调ISR。
Operating system (OS) :操作系统或应用程序必须确保在SR寄存器中配置正确的服务类型和中断优先级。还必须由操作系统或应用程来管理中断的启用和禁用。MCAL软件包提供的OS文件只是一个示例代码,集成商必须用实际的OS文件来更新所需的功能。
多核与资源管理
ICU驱动程序支持从所有CPU核心同时执行其API。在编译前,用户必须使用资源管理器模块将 ICU的每个通道分配给对应的CPU核心。以下是与ICU驱动程序中的多核相关的关键点:
- 可以使用资源管理器将每个ICU通道分配给任何核心。
- 对于依赖 ERU的ICU通道,使用OGU[x]和OGU[x+4]的通道(x=0-3),必须将这两个通道共享相同的中断线分配给相同的核心。例如,使用OGU0和OGU4的ICU通道应分配给相同的核心。
- 常数、变量和配置数据的正确内存空间定位应由用户完成。
用户应考虑以下内容,以确保驱动程序具有更好的性能:
Code section:ICU驱动程序的可执行代码被放置在单个MemMap区块下。它可以被重新定位到任何PFlash/DFlash区域。
Data section:标记为特定于某个核心的RAM可变存储器区段应重新定位到同一核心的DSPR/DLMU。标记为全局的区段应被重新定位到非缓存的LMU区域。
Configuration data and constants:标记为特定于核心的配置数据部分应重新定位到相同核心上的PFlash/DFlash。标记为全局的部分应重新定位到主核心上的PFlash/DFlash。
MCU support
ICU驱动程序依赖于MCU驱动程序进行时钟配置和timer-IP相关服务。只有在成功完成MCU初始化后,才能初始化ICU 驱动程序。在Eb tresos中配置MCU驱动程序时,必须考虑以下内容:
- GTM-TIM Icu channel:lCU驱动程序使用的GTM-TIM通道必须在MCU配置中保留,供lcu专用。保留的TIM通道可用于一个ICU通道。连接到TIM通道的端口引脚必须在MCU中进行配置。
- CCU6 Icu channel:ICU驱动程序使用的CCU6核心必须在MCU配置中保留,供ICU专用。因此,保留的CCU6核心的三个比较器(CC60、CC61和CC62)中的每一个都可以用于三个不同的ICU通道。
- GPT12 Icu channel:ICU驱动器使用的GPT12定时器必须保留在MCU配置中,供ICU专用。保留的定时器可以用于一个ICU通道。
- ERU Icu channel:ICU驱动器使用的ERS通道和相应的OGU通道必须保留在单片机配置中,供lcu专用。一个ERS通道可以与任何OGU通道配对。
Port support
PORT驱动程序配置整个微控制器的端口引脚。用户必须通过端口配置来配置ICU驱动程序使用的端口引脚,并在调用ICU驱动程序初始化之前初始化相应的端0口引脚。
Interrupt connections
ICU通道所使用的不同硬件的中断配置寄存器如下:
- GTM-TIM:SRC_GTMTIMwx (w= TIM module; x= TIM channel)
- CCU6:SRC_CCU6xSRy (x= CCU6 kernel; y=0-3)
- ERU:SRC_SCUERUx (x=0-3)
- GPT12:SRC_GPT120Tx (x=2-6, GPT12 timer)
所有发送到GTM-TIM的ISR必须被路由到Mcu_17_Gtm_TimChannelIsr,它进一步调用Icu_17_TimerIp_Timer_Isr,下面是它实现的一个示例。
ISR(GTMTIM0SR0_ISR)
{
/* Enable Global Interrupts */
ENABLE();
/* Parameter is TIM module number and TIM channel number */
Mcu_17_Gtm_TimChannelIsr(0, 2); /* For TIM 0 CH2*/
}
所有发送到CCU6的ISR必须被路由到Mcu_17_Ccu6_ChannelIsr,它进一步调用Icu_17_TimerIp_Timer_Isr,下面是它实现的一个示例。
ISR(CCU60SR0_ISR)
{
/* Enable Global Interrupts */
ENABLE();
/* Parameter are CCU6 kernel and comparator */
Mcu_17_Ccu6_ChannelIsr(CCU6_KERNEL_0,CCU6_CHANNEL_0);
}
如果CCU6的ISR被抢占,并且在抢占期间观察到输入边沿,则ICU模块测量的高电平时间、低电平时间和占空比值不正确。因此,如果用户预见到这种情况,建议在不可重入代码段执行CCU6xSRy_ISR。
所有发送到GPT12计时器的ISR必须路由到Mcu_17_Gpt12_ChannelIsr,它进一步调用Icu_17_TimerIp_Timer_Isr。示例ISR处理如下所示:
ISR(GPT12_T2_ISR)
{
/* Enable Global Interrupts */
ENABLE();
/* Parameter is GPT12 timer number 0 for T2, 1 for T3 and so on.*/
Mcu_17_Gpt12_ChannelIsr(0); /* For T2 timer */
}
所有发送到ERU计时器的ISR必须路由到Mcu_17_Eru_GatingIsr,它进一步调用Icu_17_TimerIp_Timer_Isr。示例ISR处理如下所示:
ISR(SCUERUSR0_ISR)
{
/* Enable Global Interrupts */
ENABLE();
/* Call Mcu Interrupt function, parameter is SRC index. */
Mcu_17_Eru_GatingIsr(0); /* For ERS 0*/
}
示例用法
Initialization:用户必须包括lcu_17_Timerlp.h文件,以访问初始化所需的ICU配置结构。
/* Include Icu.h to access configuration structures */
#include "Icu_17_TimerIp.h"
/* Module Initialization */
void Icu_Sample_Init(void)
{
/* MCU initializations */
Mcu_Init(&Mcu_Config);
(void)Mcu_InitClock( 0 );
while(Mcu_GetPllStatus() != MCU_PLL_LOCKED)
{
};
(void)Mcu_DistributePllClock();
/* Initialize ICU */
Icu_17_TimerIp_Init(&Icu_17_TimerIp_Config);
/* Initialize Check for ICU */
Error = Icu_17_TimerIp_InitCheck(&Icu_17_TimerIp_Config);
if (Error == E_OK)
{
/*ICU InitCheck should pass, then Call other APIs related to ICU */
}
}
Edge count mode:在配置了边沿计数功能的ICU通道上,边沿计数从调用Icu_17_TimerIp_EnableEdgeCount开始, Icu_17_TimerIp_GetEdgeNumbers返回调用Icu_17_TimerIp_Init或者Icu_17_TimerIp_ResetEdgeCount后计数的边沿数。通过调用Icu_17_TimerIp_DisableEdgeCount停止了边沿计数。Icu_17_Timerlp_ResetEdgeCount会重置已计数的边沿数,即使边沿计数活动已停止。
/* ICU module Initialization is necessary to start the edge counting feature */
Icu_17_TimerIp_Init(&Icu_17_TimerIp_Config);
Icu_17_TimerIp_EnableEdgeCount(<logical channel symbolic name>);
/* Provide edges on the port pin of the logical channel */
/* Read the number of edges detected. Returns the number of provided edges */
CountedEdges = Icu_17_TimerIp_GetEdgeNumbers(<logical channel symbolic name>);
/* Reset the counted edges */
Icu_17_TimerIp_ResetEdgeCount(<logical channel symbolic name>);
/* Read edge count after reset edge count. "0" will be returned */
CountedEdges = Icu_17_TimerIp_GetEdgeNumbers(<logical channel symbolic name>);
/* Provide edges on the port pin of the logical channel */
/* Read the number of edges detected. Returns the number of provided edges */
CountedEdges = Icu_17_TimerIp_GetEdgeNumbers(<logical channel symbolic name>);
/* Disable edge counting */
Icu_17_TimerIp_DisableEdgeCount(<logical channel symbolic name>);
/* Reset the counted edges */
Icu_17_TimerIp_ResetEdgeCount(<logical channel symbolic name>);
/* Read the number of edges detected. Returns "0" as edge counting is reset.*/
CountedEdges = Icu_17_TimerIp_GetEdgeNumbers(<logical channel symbolic name>);
/* Provide edges on the port pin of the logical channel */
/* Read the number of edges detected. Returns "0" as edge counting is disabled.*/
Time stamp mode:通过调用Icu_17_TimerIp_StartTimestamp开始捕获配置的有效边沿上的时间戳。在接收到特定数量(在活动开始时配置)的时间戳(仅在模块配置中配置通知功能时适用)后,应调用Icu_17_TimerIp_EnableNotification来接收通知。Icu_17_TimerIp_DisableNotification停止通知。Icu_17_TimerIp_StopTimestamp停止捕获有效边沿的时间戳,Icu_17_TimerIp_GetTimestampIndex返回接下来要填充时间戳的缓冲区位置。
/* ICU module Initialization is necessary to start the time stamping feature */
Icu_17_TimerIp_Init(&Icu_17_TimerIp_Config);
/* Buffer to fill timestamps. BUFFER_SIZE indicates the size of the buffer */
Icu_17_TimerIp_ValueType Buffer[BUFFER_SIZE];
/* Start the time stamping activity. NOTIFY_INTERVAL is the number of timestamps to be
received to issue notification*/
Icu_17_TimerIp_StartTimestamp(<logical channel symbolic name>, Buffer, BUFFER_SIZE,
NOTIFY_INTERVAL);
/* Enable notifications to receive notifications */
Icu_17_TimerIp_EnableNotification(<logical channel symbolic name>);
/* Provide edges on the port pin of the logical channel */
/* Read the buffer index next to be filled */
NextIndex = Icu_17_TimerIp_GetTimestampIndex(<logical channel symbolic name>);
/* Notification function would have been invoked if sufficient number of edges are provided */
/* Disable Notifications */
Icu_17_TimerIp_DisableNotification(<logical channel symbolic name>);
/* Provide edges on the port pin of the logical channel */
/* Read the buffer index next to be filled. The index read here will be different from the
previous read as the time stamping activity is still active */
NextIndex = Icu_17_TimerIp_GetTimestampIndex(<logical channel symbolic name>);
/* Notification function would not have been invoked even if sufficient number of edges are
provided */
/* Disable time stamping */
Icu_17_TimerIp_StopTimestamp(<logical channel symbolic name>);
/* Provide edges on the port pin of the logical channel */
/* Notification function would not have been invoked even if sufficient number of edges are
provided */
/* Read the buffer index next to be filled. The index read here will be same from the previous
read as the time stamping activity is disabled */
NextIndex = Icu_17_TimerIp_GetTimestampIndex(<logical channel symbolic name>);
Signal measurement mode:在调用Icu_17_TimerIp_StartSignalMeasurement后开始测量高时间、低时间、周期或工作周期(根据配置)。通过调用Icu_17_TimerIp_GetInputState来获得新的测量值是否可用。 lcu_17_Timerlp_GetTimeElapsed来读取测量的高时间、低时间或周期。Icu_17_Timerlp_GetDutyCycleValues读取测量的占空比。通过调用Icu_17_TimerIp_StopSignalMeasurement停止信号测量活动。通过调用Icu_17_TimerIp_StartSignalMeasurement重新启动信号测量。
/* ICU module Initialization is necessary to start the signal measurement feature */
Icu_17_TimerIp_Init(&Icu_17_TimerIp_Config);
/* Start signal measurement activity */
Icu_17_TimerIp_StartSignalMeasurement(<non duty cycle logical channel symbolic name>);
Icu_17_TimerIp_StartSignalMeasurement(<duty cycle logical channel symbolic name>);
/* Provide edges on the port pin of the logical channel */
/* Check channel status before reading the corresponding values.*/
if(ICU_ACTIVE == Icu_17_TimerIp_GetInputState(<non duty cycle logical channel symbolic name>))
{
/* Channel status is active read the measured time */
SignalMeasureValue = Icu_17_TimerIp_GetTimeElapsed(<non duty cycle logical channel symbolic
name>);
/* Read the measured time again, this will return 0 */
SignalMeasureValue = Icu_17_TimerIp_GetTimeElapsed(<non duty cycle logical channel symbolic
name>);
}
if(ICU_ACTIVE == Icu_17_TimerIp_GetInputState(<duty cycle logical channel symbolic name>))
{
Icu_17_TimerIp_DutyCycleType DutyCycle;
/* Channel status is active, read the duty cycle values */
Icu_17_TimerIp_GetDutyCycleValues(<duty cycle logical channel symbolic name>, &DutyCycle);
/* read the duty cycle values again. this will return 0 */
Icu_17_TimerIp_GetDutyCycleValues(<duty cycle logical channel symbolic name>, &DutyCycle);
}
/* Stop signal measurement activity */
Icu_17_TimerIp_StopSignalMeasurement(<non duty cycle logical channel symbolic name>);
Icu_17_TimerIp_StopSignalMeasurement(<duty cycle logical channel symbolic name>);
/* Provide edges on the port pin of the logical channel */
/* Check channel status, will return IDLE as signal measurement activity is stopped */
ChannelState = Icu_17_TimerIp_GetInputState(<non duty cycle logical channel symbolic name>));
ChannelState = Icu_17_TimerIp_GetInputState(<duty cycle logical channel symbolic name>));
/* Start signal measurement activity */
Icu_17_TimerIp_StartSignalMeasurement(<non duty cycle logical channel symbolic name>);
Icu_17_TimerIp_StartSignalMeasurement(<duty cycle logical channel symbolic name>);
/* Provide edges on the port pin of the logical channel */
/* Check channel status, will return ACTIVE as signal measurement activity is started */
ChannelState = Icu_17_TimerIp_GetInputState(<non duty cycle logical channel symbolic name>));
ChannelState = Icu_17_TimerIp_GetInputState(<duty cycle logical channel symbolic name>));
Edge detection mode:边缘检测配置的ICU信道上的边缘检测(上升、下降或任意边沿)在调用Icu_17_TimerIp_Init后启动。ICU通道状态通过对Icu_17_TimerIp_GetInputState的调用获取。调用Icu_17_TimerIp_EnableNotification来接收配置边沿上的通知(仅在模块配置中配置通知功能时才适用)。Icu_17_TimerIp_DisableNotification停止发布通知。通过调用Icu_17_TimerIp_DisableEdgeDetection停止边缘检测活动。并通过调用Icu_17_TimerIp_EnableEdgeDetection重新启用。调用Icu_17_Timerlp_EnableMultiEdgeDetection 检测多个边,并在检测多个边后发出通知。
/* ICU module Initialization is necessary to start the edge detection activity */
Icu_17_TimerIp_Init(&Icu_17_TimerIp_Config);
/* Provide edges on the port pin of the logical channel */
/* Check channel status, will return ACTIVE and no notifications are detected */
ChannelState = Icu_17_TimerIp_GetInputState(<logical channel symbolic name>);
/* Read channel state again, will return IDLE */
ChannelState = Icu_17_TimerIp_GetInputState(<logical channel symbolic name>);
/* Enable Notifications */
Icu_17_TimerIp_EnableNotification(<logical channel symbolic name>);
/* Provide edges on the port pin of the logical channel */
/* Channel respective notification function would have been issued.*/
/* Disable Notifications */
Icu_17_TimerIp_DisableNotification(<logical channel symbolic name>);
/* Provide edges on the port pin of the logical channel */
/* Channel respective notification function would not have been issued */
/* Check channel status, will return ACTIVE */
ChannelState = Icu_17_TimerIp_GetInputState(<logical channel symbolic name>);
/* Disable Edge detection */
Icu_17_TimerIp_DisableEdgeDetection(<logical channel symbolic name>);
/* Provide edges on the port pin of the logical channel */
/* Channel respective notification function would not have been issued */
/* Check channel status, will return IDLE and no notifications are detected */
ChannelState = Icu_17_TimerIp_GetInputState(<logical channel symbolic name>);
/* Enable multiple edge detection. EDGE_COUNT number of edge will be detected */
Icu_17_TimerIp_EnableMultiEdgeDetection(<logical channel symbolic name>, EDGE_COUNT);
/* Enable notifications */
Icu_17_TimerIp_EnableNotification(<logical channel symbolic name>);
/* Provide multiple edges on the port pin of the logical channel */
/* Notification would have been issued after detecting EDGE_COUNT edges.*/
General API:Icu_17_TimerIp_SetActivationCondition应在调用Icu_17_TimerIp_Init后调,且仅用于处于边沿检测、时间戳和边沿计数模式的通道。Icu_17_TimerIp_EnableWakeup启用唤醒和Icu_17_TimerIp_DisableWakeup禁用唤醒应在调用Icu_17_TimerIp_Init后调用,且仅在具有唤醒功能的通道上运行。Icu_17_TimerIp_SetMode应在调用Icu_17_TimerIp_Init后调用,将ICU驱动程序的状态更改为SLEEP或NORMAL。应在调用Icu_17_TimerIp_Init后调用Icu_17_TimerIp_DeInit重置ICU模块的初始化状态。调用Icu_17_TimerIp_DeInit后,应再次调用Icu_17_TimerIp_Init以启动ICU 驱动程序的任何功能。
/* ICU module Initialization is necessary to start the ICU channel activities */
Icu_17_TimerIp_Init(&Icu_17_TimerIp_Config);
/* Default edge for detection, edge counting and time stamping is taken from configuration */
/* Change the default active edge to RISING_EDGE */
Icu_17_TimerIp_SetActivationCondition(<logical channel symbolic name>,ICU_RISING_EDGE);
/* Edge detection, edge counting and time stamping will be done on rising edge */
/* Enable wakeup for a wakeup capable channel */
Icu_17_TimerIp_EnableWakeup(<wakeup capable logical channel symbolic name>);
/* Change mode to sleep */
Icu_17_TimerIp_SetMode(ICU_MODE_SLEEP);
/* provide signal on the wakeup capable channel */
/* EcuMCheckWakeup will be invoked from ISR to indicate a wakeup signal */
/* Change mode to normal */
Icu_17_TimerIp_SetMode(ICU_MODE_NORMAL);
/* Disable wakeup for a wakeup capable channel */
Icu_17_TimerIp_DisableWakeup(<wakeup capable logical channel symbolic name>);
/* Change mode to sleep */
Icu_17_TimerIp_SetMode(ICU_MODE_SLEEP);
/* provide signal on the wakeup capable channel */
/* EcuMCheckWakeup will not be invoked */
Incremental interface mode:初始化后,计数设置为0。在调用Icu_17_TimerIp_StartIncInterface后,开始检测增量接口配置的ICU通道上的边沿。计数值通过调用Icu_17_TimerIp_ReadEncCount来获取,调用Icu_17_TimerIp_ReadEncCountDir获取计数器方向(默认为测量到边沿递增)。应调用Icu_17_TimerIp_CalibratePos来校准初始计数器的值。通过调用Icu_17_TimerIp_StopIncInterface来停上增量接口活动。
/* ICU module Initialization is necessary to start the incremental interface activity */
Icu_17_TimerIp_Init(&Icu_17_TimerIp_Config);
/* Check encoder count and direction, will return 0 and UP direction(HW default) */
EncCount = Icu_17_TimerIp_ReadEncCount(<logical channel symbolic name>);
EncDir = Icu_17_TimerIp_ReadEncCountDir(<logical channel symbolic name>);
/* Enable incremental interface channel */
Icu_17_TimerIp_StartIncInterface(<logical channel symbolic name>);
/* Provide edges on the port pin(both counter and direction signal) of the logical channel */
/* No notifications are issued */
/* Check encoder count and direction, will return non zero and current counter direction(HW
default) as per the given input signals */
EncCount = Icu_17_TimerIp_ReadEncCount(<logical channel symbolic name>);
EncDir = Icu_17_TimerIp_ReadEncCountDir(<logical channel symbolic name>);
/* Update the encoder position */
Icu_17_TimerIp_CalibratePos(<logical channel symbolic name>, <new counter position to be set>);
/* Enable Notifications */
Icu_17_TimerIp_EnableNotification(<logical channel symbolic name>);
/* Provide edges on the port pin(both counter and direction signal) of the logical channel */
/* Notifications for each count edge is issued */
/* Notifications for counter overflow/underflow is issued if the encoder counter overflows or
underflows */
/* Check encoder count and direction, will return non zero and current counter direction(HW
default) as per the given input signals starting from the encoder position set */
EncCount = Icu_17_TimerIp_ReadEncCount(<logical channel symbolic name>);
EncDir = Icu_17_TimerIp_ReadEncCountDir(<logical channel symbolic name>);
/* Disable incremental interface channel */
Icu_17_TimerIp_StopIncInterface(<logical channel symbolic name>);
/* Provide edges on the port pin(both counter and direction signal) of the logical channel */
/* Check encoder count and direction, will return same as the previous call as the incremental
mode is disabled. */
EncCount = Icu_17_TimerIp_ReadEncCount(<logical channel symbolic name>);
EncDir = Icu_17_TimerIp_ReadEncCountDir(<logical channel symbolic name>);
Timeout functionality:在 CU通道的配置中可以使用TIM硬件和边沿检测或边沿计数模式启用超时功能。在ICU初始化后,超时功能被禁用。该功能可以通过调用Icu_17_TimerIp_SetTimeoutValue使用适当的超时值。如果在超时到期之前没有识别出配置的边缘,则发出配置的超时通知。可以通过将超时值配置为0在运行时禁用超时检测。
/* ICU module Initialization is necessary to start the edge detection/edge count activity */
Icu_17_TimerIp_Init(&Icu_17_TimerIp_Config);
/* Provide some configured timeout edges and stop the signal */
/* Timeout notification is not issued since the timeout value is not configured */
Icu_17_TimerIp_SetTimeoutValue(<logical channel symbolic name>,<timeout value>);
/* Provide some configured timeout edges and stop the signal and wait for the timeout to expire
*/
/* Timeout notification is not issued since the notifications are not enabled */
/* Enable Notifications */
Icu_17_TimerIp_EnableNotification(<logical channel symbolic name>);
/* Provide some configured timeout edges and stop the signal */
/* Timeout notification is issued after the timeout value expired */
环境与目标
本文使用的为英飞凌提供的开发板KIT_A2G_TC397XA_TFT。我们选择X103排针上的P02.5作为外部信号的输入引脚,如下图在开发板的X103引脚。
涉及的软件如下:
涉及的软件如下:
- EB-tresos:用于生成动态代码,具体工程搭建参考《【AUTOSAR MCAL】MCAL基础与EB tresos工程新建》。
- HighTech:用于编译生成elf文件,具体的工程搭建参考《【MCAL】HighTec集成TC3xx对应MCAL的Demo》。
- UDE 5.2:用于下载和调试程序。
涉及的参考文档如下表。
序号 | 参考资料 | 内容 |
1 | 《Infineon-AURIX_TC39x-UserManual-v02_00-EN》 | 英飞凌TC39x用户手册 |
2 | 《Infineon-AURIX_TC3xx_Part1-UserManual-v02_00-EN.pdf》 | 英飞凌TC3xx用户手册 |
3 | 《Infineon-AURIX_TC3xx_Part2-UserManual-v02_00-EN.pdf》 | 英飞凌TC3xx用户手册 |
4 | 《Infineon-TC39x-DataSheet-v01_00-EN》 | 英飞凌TC39x数据手册 |
5 | 《ApplicationKitManual-TC3X7-ADAS-V21.pdf》 | 开发板KIT_A2G_TC397XA_TFT说明 |
6 | 《MC-ISAR_TC3xx_UM_Icu_17_TimerIp.pdf》 | 英飞凌提供的TC3xx芯片ICU用户手册 |
我们本次实验使用GTM_TIM0_5实现包括信号测量、边沿检测、边沿计数以及时间戳的功能。
EB tresos配置
这里我们讨论以下ICU的时钟来源,我们先看一下芯片手册的截图,可以看出CMU使用的是Cluster的时钟,而fCluster0的时钟来源则是fGTM
再看下一个来自芯片手册的截图,我们在本例中ICU使用的是CMU_CLK。
综上所述,本例的ICU的时钟线如下图所示。
MCU配置
McuClocksettingConfig
GtmClusterConf
GtmGlobalConfiguration
McuGtmTimAllocationconf
选择GTM_TIM0_5通道为ICU使用。
ICU配置-信号测量模式
IcuOptionalApis
下列API的开启依赖于使用的功能,例如信号检测,信号测量,边沿计数等。直接字面意思应该就能明白,这里就不一一赘述了。
IcuChannel
这个容器主要需要我们关心的有以下三个参数:
- IcuDefaultStartEdge:配置默认激活边沿,如果没有通过lcu_SetActivationCondition()服务调用配置激活边沿,则该边缘将用于此通道。对于周期信号测量,配置的边沿是周期的开始。对于占空比测量配置的边沿是有效电平和周期的开始边沿,占空比测量不能配置BOTH EDGES。对于占空比的测量,在lcu_StartSignalMeasurement()调用后看到的第一个边沿被认为是测量的开始。
- IcuMeasurementMode:测量方式,参考MCAL手册中Icu_MeasurementModeType的定义。
- IcuAssignedHwUnit:ICU使用的硬件单元,这里我们使用的是GTM,还可以是ERU/CCU6/GPT12。
lcuSignalMeasurement
这里选择测量占空比的形式。
GtmTimerlnputConfiguration
首先是General里的GtmTimerUsed,这里我们选择之前预留的GTM_TIM0_5。
然后是TimChannelGeneral的配置,我们需要关注的参数有:
- TimChannellnputSelect:这决定了当前TIM通道的输入:分为当前的TIM通道还是前一个。
- TimChannelPortPinSelect :这决定了TIM通道的输入端口和引脚。按照之前的原理规划我们选择P02.5。
- TimChannelClockSelect:时钟选择,这里我们选择CMU_CLK0。
最后,我们还需要关心滤波配置,如下图。
Port配置
配置对应引脚为输入。
ResourceM
ICU配置不同点-边沿计数模式
然后打开对应的API。
ICU配置不同点-边沿检测模式
边沿检测必须完成对应中断的配置的情况,否则无法进回调函数。下面是对应的IRQ配置,注意选择对应通道。
然后我们打开边沿检测的API。
选择边沿检测功能。
新建IcuSignalEdgeDetection,并在lcuSignalNotification配置回调函数。
ICU配置不同点-时间戳记录模式
TBU配置,时间戳必须有个时间基准,所以在MCU中需要配置TBU,选择其中一个即可。
ICU配置,选取测量方式为时间戳方式。
选择处理时间戳存储Buffer的方式为环形存储。
ICU驱动使用与调试
信号测量模式调试
下面是调试初始化以及执行代码。
/* Initialize ICU */
void ICU_int()
{
Icu_17_TimerIp_Init(&Icu_17_TimerIp_Config);
Icu_17_TimerIp_StartSignalMeasurement(IcuConf_IcuChannel_IcuChannel_TIM0_5);
}
Icu_17_TimerIp_DutyCycleType Read_ICU_TIM0_5_PORT02_5;
float Icu_Measurement1_DutyCycle = 0;
float Icu_Measurement1_Period = 0;
void ICU_GetResult
{
Icu_17_TimerIp_GetDutyCycleValues(IcuConf_IcuChannel_IcuChannel_TIM0_5, &Read_ICU_TIM0_5_PORT02_5);
/* Get the Measurement DutyCycle */
Icu_Measurement1_DutyCycle = Read_ICU_TIM0_5_PORT02_5.ActiveTime * 1.0 / Read_ICU_TIM0_5_PORT02_5.PeriodTime;
/* Get the Measurement Period */
cu_Measurement1_Period = 100000000.0 / Read_ICU_TIM0_5_PORT02_5.PeriodTime;
}
我们使用逻辑分析仪产生一个2KHz,占空比为50%的信号,实际调试结果如下。可以看到测量结果跟配置一致。
边沿计数模式调试
下面是调试初始化以及执行代码。
/* Initialize ICU */
void ICU_int()
{
Icu_17_TimerIp_Init(&Icu_17_TimerIp_Config);
#if ICU_17_TIMERIP_EDGE_COUNT_API
Icu_17_TimerIp_EnableEdgeCount(IcuConf_IcuChannel_IcuChannel_TIM0_5);
#endif
}
uint32 ICUx_GetxEdgeNumbers = 0;
uint8 ICUx_DemoFlags = 0;
void ICU_GetResult
{
#if ICU_17_TIMERIP_EDGE_COUNT_API
if(ICUx_DemoFlags == 1)
{
ICUx_GetxEdgeNumbers = Icu_17_TimerIp_GetEdgeNumbers(IcuConf_IcuChannel_IcuChannel_TIM0_5);
ICUx_DemoFlags = 1;
}
if(ICUx_DemoFlags == 3)
{
Icu_17_TimerIp_ResetEdgeCount(IcuConf_IcuChannel_IcuChannel_TIM0_5);
ICUx_DemoFlags = 4;
}
if(ICUx_DemoFlags == 5)
{
Icu_17_TimerIp_DisableEdgeCount(IcuConf_IcuChannel_IcuChannel_TIM0_5);
ICUx_DemoFlags = 6;
}
if(ICUx_DemoFlags == 7)
{
Icu_17_TimerIp_EnableEdgeCount(IcuConf_IcuChannel_IcuChannel_TIM0_5);
ICUx_DemoFlags = 8;
}
#endif
}
最终计数的结果如下所示。
边沿检测模式调试
下面是调试初始化以及执行代码。在回调函数中一直自增一个变量,观察变量即可知道回调是否被调用。
/* Initialize ICU */
void ICU_int()
{
Icu_17_TimerIp_Init(&Icu_17_TimerIp_Config);
#if ICU_17_TIMERIP_EDGE_DETECT_API
SRC_GTMTIM05.B.SRE = 1;
Icu_17_TimerIp_EnableEdgeDetection(IcuConf_IcuChannel_IcuChannel_TIM0_5);
Icu_17_TimerIp_EnableNotification(IcuConf_IcuChannel_IcuChannel_TIM0_5);
#endif
}
#if ICU_17_TIMERIP_EDGE_DETECT_API
volatile uint32 ICUx_SignalEdgeDetectionNum = 0;
void IcuSignalEdgeDetection_No1 (void)
{
ICUx_SignalEdgeDetectionNum++;
}
#endif
调试结果如下。
时间戳记录模式调试
下面是调试初始化以及执行代码。
#if ICU_17_TIMERIP_TIMESTAMP_API
uint32 TimestampBufferRx[10] = {0x00,0x00};
#endif
/* Initialize ICU */
void ICU_int()
{
Icu_17_TimerIp_Init(&Icu_17_TimerIp_Config);
#if ICU_17_TIMERIP_TIMESTAMP_API
SRC_GTMTIM05.B.SRE = 1;
Icu_17_TimerIp_StartTimestamp(IcuConf_IcuChannel_IcuChannel_TIM0_5,TimestampBufferRx,10,10);
Icu_17_TimerIp_EnableNotification(IcuConf_IcuChannel_IcuChannel_TIM0_5);
#endif
}
#if ICU_17_TIMERIP_TIMESTAMP_API
volatile uint32 ICUx_TimestampNum = 0;
void TimestampNotification_Read (void)
{
ICUx_TimestampNum++;
}
#endif
下面是调试结果。
十六宿舍 原创作品,转载必须标注原文链接。
©2023 Yang Li. All rights reserved.
欢迎关注 『十六宿舍』,大家喜欢的话,给个👍,更多关于嵌入式相关技术的内容持续更新中。