本文主要是介绍【Autosar】MCAL - ICU(NXP - S32K14x),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
文章目录
- MCAL - ICU(NXP - S32K14x)
- 1. 概述
- 1.1 FlexTimer模块ICU介绍
- 1.1.1 输入捕获工作原理
- 1.1.2 过滤器
- 1.1.3 双边沿捕获工作原理
- 2. API
- 3. 配置介绍
- 3.1 IcuChannel
- 3.1.1 General
- 3.1.2 IcuSignalEdgeDetection
- 3.1.3 IcuSignalMeasurement
- 3.1.4 IcuTimestampMeasurement
- 3.2 IcuFtm
- 3.2.1 Ftm Modules
- 3.2.2 IcuFtmChannels
- 3.3 IcuHwInterruptConfigList
- 3.4 捕获模式介绍
- 3.4.1 时间戳
- 3.4.2 信号测量(ICU_DUTY_CYCLE)
- 3.5 遗留问题
MCAL - ICU(NXP - S32K14x)
MCAL - 汇总
- 配置工具:EB Tresos Studio
- 芯片类型:S32K146
1. 概述
ICU(Input Capture Unit)输入捕获的作用是监测输入信号的边沿跳变,以此来测量输入信号的频率、占空比、高/低电平持续时间。
1.1 FlexTimer模块ICU介绍
1.1.1 输入捕获工作原理
输入捕获模块监测输入信号(channel input),通过边沿监测模块将捕获到的信号与设定的监测边沿(上升沿/下降沿)比较,如果匹配则将当前的FTM Counter
值存到Cnv
中并且触发中断,此时用户可以读取并记录Cnv
值。
例如我设置的是上升沿捕获,FTM时钟频率为1MHz,第一次触发时程序记录Cnv
值为1000,第二次触发时记录Cnv
值为2000,此时可以计算信号周期period = (2000-1000) * 1000 / 1000000 = 1ms = 1KHz
。
捕获边沿可以设置为上边沿/下边沿/双边沿
,通过设置ELSB/ELSA
来设定。双边沿
是触发任意一个都会记录并触发中断,这种情况下可以计算输入信号的占空比。
1.1.2 过滤器
输入捕获模块配有滤波器(用户开启),输入信号的稳定时间需要满足规定采样时间,才会将信号传给边缘边沿,否则信号将被过滤。过滤器的采样时间如下图所示:
过滤器的采样时间参考下图:
1.1.3 双边沿捕获工作原理
Dual Edge Capture Mode - 双边沿捕获 。在这种模式下,只有一路输入,但是有2路通道进行捕获,多了一路通道用于记录数据,可以很方便的监测信号的占空比和周期。例如将通道0配置为上升沿捕获、通道1配置为下降沿捕获,当监测到上升沿时数据记录到C0V中,捕获到下降沿时数据记录到C1V中,我们可以使能通道1的 中断,当通道1中断触发后,可以通过C1V-C0V得到占空比,当再次触发后,利用当前值和历史值去计算周期(NXP处理方式))。
注意此模式只能用于偶数通道:0、2、4、6
S32K-RM中对配置有一个说明:
在双边沿监捕获模式下,通道需要配置为上升沿或下降沿捕获(在此处我并没有看到允许配置为1:1)。当两个通道配置不同,一个上升沿,一个下降沿时,可以监测占空比。当两个通道配置相同时,可以监测周期。
对于CnV和C(n+1)V的读取,S32K参考手册的Read coherency mechanism
中有介绍:注意数据读取的时候要先读取C(n)V再去读取C(n+1)V
2. API
函数 | 描述 |
---|---|
Icu_Init | ICU模块初始化 |
Icu_DeInit | ICU模块恢复至默认状态 |
Icu_SetActivationCondition | 设置触发边沿 |
Icu_EnableNotification | 使能中断回调 |
Icu_DisableNotification | 禁用中断回调 |
Icu_StartTimestamp | 开始时间戳模式 |
Icu_StopTimestamp | 停止时间戳模式 |
Icu_GetTimestampIndex | 获当前时间戳序号 |
Icu_StartSignalMeasurement | 开始信号测量 |
Icu_StopSignalMeasurement | 停止信号测量 |
Icu_GetDutyCycleValues | 获取占空比、周期值 |
3. 配置介绍
3.1 IcuChannel
3.1.1 General
IcuHwIP:
硬件模块选择
IcuFtmChannelRef:
硬件模块选择了FTM,此处就要打开并且选择对应的FTM通道(LPIT/PORT/LPTMR 同理)
IcuDefaultStartEdge:
默认开始捕获边沿(例如选择上边沿,那么只有监测到上边沿才会开始测量,配置的是ELSB/ELSA寄存器)
IcuMeasurementMode:
测量模式
IcuOverflowNotification:
溢出中断回调
3.1.2 IcuSignalEdgeDetection
当测量模式选择ICU_MODE_SIGNAL_EDGE_DETECT
的时候需要打开。
IcuSignalNotification:
中断回调
3.1.3 IcuSignalMeasurement
当测量模式选择ICU_MODE_SIGNAL_MEASUREMENT
的时候需要打开。
IcuSignalMeasurementProperty:
信号测量方式(占空比、周期、高电平时间、低电平时间)
3.1.4 IcuTimestampMeasurement
当测量模式选择ICU_MODE_TIMESTAMP
的时候需要打开。
IcuTimestampMeasurementProperty:
时间戳测量方式(回环、线性)
IcuTimestampNotification:
中断回调
3.2 IcuFtm
3.2.1 Ftm Modules
Ftm Hardware Module:
FTM模块选择
ICU FlexTimer Prescaler:
FTM时钟分频系数
IcuFlexTimer Clock source:
时钟源选择
3.2.2 IcuFtmChannels
Ftm Channel:
FTM通道选择
3.3 IcuHwInterruptConfigList
中断使能配置,根据对应的通道配置选择对应的中断。
3.4 捕获模式介绍
3.4.1 时间戳
时间戳测量方式:
- ICU_CIRCULAR_BUFFER:回环,数据存满后从0开始继续存储
- ICU_LINEAR_BUFFER:线性,数据存满后测量停止。
时间戳模式下可以设置NotifuInterval
参数。此参数的意义在于存储了指定个数的数据后再通知用户,例如我设置NotifuInterval为2,当触发了2次中断 存储了两个数据后,会触发一次回调通知,此时通过Icu_GetTimestampIndex
函数可以获取到当前存储位置为2(此处大家可能会有疑问,存储了两个数据后,当前的序号不应该是1吗,由于存储完数据后,Index会先增加1,再去调用回调函数,所以是2),所以每次触发后,获取的index-1才是当前的存储位置。因此这里会存在一个问题,例如上图当第三次触发回调的时候,此时缓存位置是5,但是获取的index由于超出最大缓存范围了,获取到的是0,所以这里需要做过零点处理。
void icu_test_init(void)
{Icu_Init(&Icu_Config);INT_SYS_EnableIRQ(FTM0_Ch0_Ch1_IRQn);Icu_EnableNotification(0);Icu_StartTimestamp(0, icu_buffer, sizeof(icu_buffer) / sizeof(icu_buffer[0]), 2);
}void Icu_channel0_notify(void)
{uint16_t index = 0;index = Icu_GetTimestampIndex(0);if(index == 0 ){index = sizeof(icu_buffer) / sizeof(icu_buffer[0]);return;}index -= 1;if(icu_buffer[index] > icu_buffer[index - 1]){printf("%d%\r\n", (icu_buffer[index] - icu_buffer[index - 1]) * 100 / 10000);}else{printf("%d%\r\n", (65535 - icu_buffer[index - 1] + icu_buffer[index]) * 100 / 10000);}
}
3.4.2 信号测量(ICU_DUTY_CYCLE)
该模式是通过FTM双边沿捕获模式实现。
NXP对于该测量方式的实现逻辑如下图所示,开始测量时,使能通道n,触发中断保存CnV的值①(注意假设此时捕获的是上升沿
),此时重新配置通道(通道n设置为下降沿捕获,通道n+1设置为上升沿捕获)并且关闭通道n中断,打开通道n+1的中断,当通道n+1中断触发后,同时获取Cnv的值②和C(n+1)V的值③,然后通过②-①得到占空比的值,通过③-①得到周期值,然后将③的值更新到历史值中。当通道n+1再次触发的时候是在⑤的位置,重复上述操作。
void icu_test_init(void)
{Icu_Init(&Icu_Config);INT_SYS_EnableIRQ(FTM0_Ch0_Ch1_IRQn);Icu_EnableNotification(0);Icu_StartSignalMeasurement(0);
}// 此函数在周期任务中调用
void Icu_get_duty_period(void)
{float duty = 0;Icu_DutyCycleType data = {0};Icu_GetDutyCycleValues(0, &data);printf("duty:%f%% period:%f(ms)\r\n", ((float)data.ActiveTime * 100 / data.PeriodTime),((float)data.PeriodTime * 1000 / 1000000));
}
3.5 遗留问题
从手册中可以看到,在双边沿模式下,两个通道配置的触发边沿应该是相反的,所以在EB中配置为IcuSignalMeasurement模式下,边沿触发应该选择上升沿或下降沿
,不应该选择双边沿(个人理解),但是当我选择为双边沿的时候,两个通道的触发方式都是(ELSA:ELSB = 1:1),它还是能够正常工作,且工作现象与(通道n:上升沿触发 / 通道n+1:下降沿触发)相同,所以这里我没有弄明白,在双边沿捕获模式下,双通道都配置为(ELSA:ELSB = 1:1)的情况下,内部是如何工作的?两者对于输入信号的捕获难道不会冲突吗?
。
我这里设置的占空比为30%,实际试验现象与上升沿触发一致
。
参考资料:
S32K-RM.pdf - NXP
AUTOSAR_MCAL_ICU_UM[1].pdf - NXP
这篇关于【Autosar】MCAL - ICU(NXP - S32K14x)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!