基于S32DS配置S32K344的FlexCAN模块
基于S32DS配置S32K344的FlexCAN模块
- 前言
- 配置
- 参考手册
- 位时间(Bit Time) 和 时间量子
前言
本文基于S32DS来配置FlexCAN模块,主控芯片是S32K344,实现正常收发CAN报文的功能,需要使用中断模式,Legacy Rx FIFO,波特率是500Kbit/s。由于我现在手上没有USB转CAN的设备,所以下面会配置两路CAN,在硬件上将二者的CAN_H和CAN_L连接在一起,一路负责发送,另一路负责接收。
另外需要强调一下,我使用的是RTD3.0.0。
配置
查看原理图
根据原理图配置。
FFO深度是6意味着最多存储6帧报文,当收到报文的时候,就触发中断,之后CPU去读FIFO,FIFO里剩余的报文会往前排一个位置,保证按照顺序会被读取。
掩码的话,哪个位等于1,就意味着这个位有一只“眼睛”,会关注这一位的值是否与我们的设定值相同。只有相同才会被匹配。写0的位置就不在乎啦。
新建两个控制器。
从下往上配置。
下面可以配置CANID=0x10
下面配置CANIF控制器1。
那么PTC9就不用查了,直接72+1 = 73,写进去。
DIO里配置假设的CAN0_STB。
新建include文件夹,存放头文件,并将其路径包含进来。
增加CDD
下面是CDD.c
#include "CDD.h"void CDD_CanIf_TxConfirmation(PduIdType CanIfTxPduId, Std_ReturnType result)
{}void CDD_CanIf_RxIndication(PduIdType RxPduId, const PduInfoType * PduInfoPtr)
{}void CDD_CanTransmit(PduIdType CanIfTxPduId, const uint8 * pdata)
{if((pdata != NULL_PTR) && (sizeof(pdata) <= 8)){PduInfoType PduInfo = {.SduDataPtr = (uint8*)pdata,.SduLength = sizeof(pdata)};CanIf_Transmit(CanIfTxPduId, &PduInfo);}
}
下面是CDD.h
#ifndef CDD_H_
#define CDD_H_#include "CanIf.h"void CDD_CanIf_TxConfirmation(PduIdType CanIfTxPduId, Std_ReturnType result);void CDD_CanIf_RxIndication(PduIdType RxPduId, const PduInfoType * PduInfoPtr);void CDD_CanTransmit(PduIdType CanIfTxPduId, const uint8 * pdata);#endif /* CDD_H_ */
编译报错
这些函数本来是要哎CanIf.c里面写的,但当前这个RTD里面没有,于是写了空函数,避免编译失败。放在CDD.c
void CanIf_ControllerBusOff(uint8 ControllerId)
{}
void CanIf_ControllerModeIndication( uint8 ControllerId, Can_ControllerStateType ControllerMode )
{}
在main.c里面添加代码
/**
* @file main.c
*
* @addtogroup main_module main module documentation
* @{
*//* Including necessary configuration files. */volatile int exit_code = 0;
/* User includes */#include "Mcu.h"
#include "CanIf.h"
#include "Can_43_FLEXCAN.h"
#include "Dio.h"
#include "Port.h"
#include "Platform.h"
#include "CDD.h"uint8 CAN0_msg[8] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08};
uint8 CAN1_msg[8] = {0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18};/*!\brief The main function for the project.\details The startup initialization sequence is the following:* - startup asm routine* - main()
*/
int main(void)
{/* Write your code here *//* Write your code here */OsIf_Init( NULL_PTR );Mcu_Init( NULL_PTR );Mcu_InitClock(McuConf_McuClockSettingConfig_McuClockSettingConfig_0);while (MCU_PLL_LOCKED != Mcu_GetPllStatus()){//do nothing}Mcu_DistributePllClock();Mcu_SetMode(McuConf_McuModeSettingConf_McuModeSettingConf_0);Platform_Init(NULL_PTR);Port_Init(NULL_PTR);Dio_WriteChannel(DioConf_DioChannel_DioChannel_CAN0_STB, STD_LOW);Can_43_FLEXCAN_Init(NULL_PTR);Can_43_FLEXCAN_SetControllerMode(CanController_0, CAN_CS_STARTED);Can_43_FLEXCAN_SetControllerMode(CanController_1, CAN_CS_STARTED);CanIf_Init(NULL_PTR);#if 0PduInfoType PduInfoCAN0 = {.SduDataPtr = CAN0_msg,.SduLength = sizeof(CAN0_msg)};CanIf_Transmit(CanIfTxPduCfg_0, &PduInfoCAN0);PduInfoType PduInfoCAN1 = {.SduDataPtr = CAN1_msg,.SduLength = sizeof(CAN1_msg)};CanIf_Transmit(CanIfTxPduCfg_1, &PduInfoCAN1); #elseCDD_CanTransmit(CanIfTxPduCfg_0, CAN0_msg);CDD_CanTransmit(CanIfTxPduCfg_1, CAN1_msg);#endiffor(;;){if(exit_code != 0){break;}}return exit_code;
}
参考手册
位时间(Bit Time) 和 时间量子
位时间(Bit Time) 和 时间量子(Time Quantum, Tq) 是紧密相关但不同层级的概念。
简单来说,它们的关系是:
1个位时间 (1 Bit) = 多个时间量子 (N * Tq)
详细解释
- 位时间 (Bit Time)
• 定义:传输1位(1 bit) 数据所需要的时间。
• 决定因素:它由CAN总线的波特率(Baud Rate) 直接决定。
◦ 公式: 位时间 (Bit Time) = 1 / 波特率 (Baud Rate)
• 举例:如果波特率是 500 kbps (即 500,000 bit/s),那么:
◦ 位时间 = 1 / 500,000 Hz = 2 µs◦ 这意味着每一位数据在总线上的持续时间为2微秒。
- 时间量子 (Time Quantum, Tq)
• 定义:CAN控制器配置时钟的最小基本时间单位。它是CAN控制器内部对位时间进行细分的基础。
• 决定因素:它来源于CAN控制器的输入时钟(通常来源于系统时钟)通过一个可编程的波特率预分频器(Baud Rate Prescaler) 得到。
◦ 公式: Tq = (波特率预分频器值) / (CAN输入时钟频率)
• 性质:Tq是软件可配置的,通过配置预分频器寄存器来实现。调整Tq的数量和长度是配置CAN总线时序的核心。
核心关系:一位数据是如何被分解的
一个位时间被固定地划分为4个不重叠的段(Segments),而每个段又由若干个Tq组成。
1 Bit Time = Sync_Seg + Prop_Seg + Phase_Seg1 + Phase_Seg2
段 (Segment) 功能描述 包含Tq数
同步段 (Sync-Seg) 用于同步总线上的各个节点。期望的边沿跳变(从隐性到显性或反之)就发生在这个时间段内。 固定为 1 Tq
传播时间段 (Prop-Seg) 用于补偿网络中的物理信号延迟(总线上的传播时间、收发器延迟等)。 可编程 (1~8 Tq)
相位缓冲段1 (Phase-Seg1) 用于重同步,可以根据边沿的相位误差进行延长或缩短。 可编程 (1~8 Tq)
相位缓冲段2 (Phase-Seg2) 用于重同步,可以根据边沿的相位误差进行缩短。 可编程 (1~8 Tq)
因此,一个位时间所包含的总Tq数是这4个段的Tq数之和:
1 Bit Time = (1 + Prop_Seg + Phase_Seg1 + Phase_Seg2) Tq
我们把这个总Tq数称为 Nominal Bit Time (NBT) 或 Baud Rate Prescaler Factor (BRP Factor)。
- 举例说明
假设我们要配置一个 500 kbps 的CAN总线,MCU的CAN模块输入时钟为 40 MHz。
-
计算位时间:
◦ Bit Time = 1 / 500,000 = 2 µs (2000 ns) -
确定总Tq数 (NBT):
◦ 我们决定将1个位时间划分为10个Tq。即 NBT = 10。◦ 那么,每个Tq的持续时间就是: Tq = Bit Time / NBT = 2 µs / 10 = 200 ns
-
计算预分频器值:
◦ 我们知道 Tq = Prescaler / F_can◦ 所以 Prescaler = Tq * F_can = 200ns * 40 MHz = (2e-7 s) * (4e7 Hz) = 8
◦ 我们需要将波特率预分频器设置为 8。
-
分配各段Tq数:
◦ Sync-Seg: 固定 1 Tq◦ Prop-Seg: 设为 3 Tq(补偿延迟)
◦ Phase-Seg1: 设为 3 Tq
◦ Phase-Seg2: 设为 3 Tq
◦ 检查总和: 1 + 3 + 3 + 3 = 10 Tq,符合我们的设计。
-
采样点位置:
◦ 采样点发生在Phase-Seg1结束之时。◦ 它的位置是:(Sync-Seg + Prop-Seg + Phase-Seg1) / NBT
◦ 在这个例子中,采样点在 (1+3+3)/10 = 70% 的位时间处。这是一个非常典型的设置。