本文记录了基于最小工程配置CAN通讯的过程。实现了调用Mcal的API实现CAN的收发测试。 主要过程是在先在Eb中配置CAN相关模块,并在RTA-OS中使能对应中断,最后在项目中调用Mcal 的API实现CAN收发。
一、CAN控制器
CAN控制器FlexCAN模块,支持CANFD(CAN with Flexible Date rate)总线协议。FlexCAN模块全面实施CAN总线协议,包括CAN 2.0B协议和CANFD总线协议。下图所示为FlexCAN模块的结构框架,其中,CAN协议接口(CAN Protocol Interface)子模块管理CAN总线上的串行通信;RAM访问请求用于收发消息、验证收到的消息及处理执行错误;消息缓存管理器(Message Buffer Management)子模块管理收发消息的缓存、仲裁及消息ID匹配算法;总线接口单元(Bus Interface Unit)子模块控制FlexCAN模块与系统总线交互,并建立与时钟的连接。
普通CAN和CANFD的区别:
二、EB配置
在EB中可能依赖的模块:Port、Platform、Can_43_FLEXCAN
1.PORT模块的配置
本实例使用FlexCAN0,分配引脚PTB0作为FlexCAN0_Rx,分配引脚PTB1作为FlexCAN0_Tx。
Port-General:
- Config Variant:选择配置变体类型。在这里选择的是 VariantPreBuild ,表示使用构建前配置 变体。
- PortSetPinModeDoesNotTouchGpioLevel:启用此选项后,设置引脚模式时不会影响GPIO电 平。(这里我踩了坑,由于不够细心这里忘记选上了,导致后面查问题查了很久)
Port-PortContainer:
是用来组织和管理所有相关的Port配置项容器,在这里需要新增一个:
然后在容器里面增加两个和CAN有关的引脚:
附PCR寄存器的序号计算方法:
- 取当前引脚所在端口数乘以32(以 PTD16 为例,3x32=96);
端口数对照表:
0 — PORTA
1 — PORTB
2 — PORTC
3 — PORTD
4 — PORTE - 取当前引脚序号(以 PTD16 为例,引脚序号为16);
- 两者相加为PCR寄存器的序号(以 PTD16 为例,其PCR寄存器序号为 96+16=112 )。
2.Mcu模块
Mcu-McuClockSettingConfig-McuClockReferencePoint:
检查一下这两个参考时钟有没有配置
Mcu-McuModeSettingConf-McuPeripheral:
需要检查一下有没有使能相应外设的时钟。
2.Can_43_FLEXCAN模块配置
Can-General
- Development Error Detection:开发错误检测功能,以帮助调试和开发过程中的错误检测。
- Can Multicore Support:CAN驱动多核支持,使其能够在多核处理器上运行。
- Provide Version Info API:提供版本信息的API,程序能够获取驱动程序的版本信息。
- Can Driver Index (0 -> 255):这是CAN驱动程序的索引,用于区分不同的CAN驱动程序实例。
- Can Main Function Busoff Period (seconds) (0 -> 65.535):设置在总线关闭状态下调用主函数的周期时间。
- Can Main Function Wakeup Period (seconds) (0 -> 65.535):设置在唤醒状态下调用主函数的周期时间。
- Can Main Function Mode Period (seconds) (0 -> 65.535):设置在模式状态下调用主函数的周期时间。
- Can Multiplexed Transmission:启用复用传输以支持多路传输。
- Can Timeout Method:设置CAN驱动程序的超时处理方法,这里选择
OSIF_COUNTER_DUMMY
表示使用一个占位符计数器。 - Can Timeout Duration (0.000001 -> 65.535):设置CAN驱动程序的超时持续时间。
- CanLpdUReceiveCalloutFunction:设置接收数据包时调用的回调函数。
- Can Os Counter Ref:设置引用的操作系统计数器。
- CanSupportTTCANRef:启用时间触发CAN(TTCAN)功能支持。
- Can MB Count Extension Support:启用消息缓冲区计数扩展以支持更多的消息缓冲区。
- CanSetBaudrateApi:启用用于设置CAN总线波特率的API。
- CanApiEnableMbAbort:启用中止消息缓冲区传输的API。
- CanEnableDualClockMode:启用双时钟模式,以支持在不同时钟源之间切换。
- Can Global Time Support:启用全局时间支持功能。
- CanListenOnlyModeApi:启用只监听模式的API,用于调试和测试。
Can-CanMainFunctionRWPeriods:
Can_MainFunction_Read或Can_MainFunction_Write的周期。单位是秒。用于polling模式
Can-CanController-General
在“CanController”标签页新建配置表,这里Can接收和发送还有BusOFF类型都选择中断模式,在“Can CPU Reference Clock”中选择系统时钟参考点,用于稍后计算波特率;在完成波特率配置后,还需要在“Can Controller Default Baudrate”中输入波特率配置表路径,如下图所示
Can-CanController-CanControllerBaudrateConfig
配置波特率为500kbps,
- CanBaudrateTypeSuport:CAN波特率类型:NORMAL_CBT/ENHANCE_CBT
- Can Automatic Time Segments Calculation: 若为true,从CanControllerBaudRate参数开始推导CAN位定时值
- Can Bus Length :Can总线长度
- Can Propagation Delay Tranceiver :收发器延迟(ns为单位)
- Can Tx ArbitrationStart Delay :5位字段表示从CAN总线上的CRC字段的第一个比特开始,TX仲裁进程的起点可以延迟多少个CAN位。
- Can Controller Prescaller 指定控制器的预调用者
- Can Controller Prescaller Alternate :指定控制器的备用预调用者
- Can Controller BaudRate Config lD :控制器波特率配置
- CanControllerBaudrate:控制器速率,单位为Kbps
- Can Synchronization Segment : 同步段用于同步整个网络的所有节点
- Can Propagation Segment :用于补偿CAN网络中的物理延迟(禁用扩展CAN位定时时,CanControllerPropSeg有效值为1-8 Tq;当启用扩展CAN位定时时,CanControllerPropSeg有效值为1- 64tq)
波特率计算公式:
波特率
=
时钟频率
Can Controller Prescaller
×
(
Can Synchronization Segment
+
Can Propagation Segment
+
Can Phase Segment 1
+
Can Phase Segment 2
)
\text{波特率} = \frac{\text{时钟频率}}{\text{Can Controller Prescaller} \times (\text{Can Synchronization Segment} + \text{Can Propagation Segment} + \text{Can Phase Segment 1} + \text{Can Phase Segment 2})}
波特率=Can Controller Prescaller×(Can Synchronization Segment+Can Propagation Segment+Can Phase Segment 1+Can Phase Segment 2)时钟频率
eg: 500k
500k = 80M 8 × ( 1 + 8 + 7 + 4 ) \text{500k} = \frac{\text{80M}}{8 \times (\text{1} + \text{8} + \text{7} + \text{4})} 500k=8×(1+8+7+4)80M
Can-CanHardwareObject:
在此处注册所需要的HRH和HOH,需要注意,此处一定是所有的receive之后才能注册transmit
CAN接口模块设计的初衷就是不能直接访问硬件,与硬件保持独立,这也就意味着CAN接口层只能通过CAN模块的接口去获取硬件有关的内容,主要使用的CAN模块接口有Hth和Hrh。
- Can Object Type :选择接收
- Can MainFunction RW Period Reference :如果选择polling模式需要打开
- Can Controller Reference :选择对应的CanController
CanHardwareObject-CanHwFilte:
- 基准CanId
- 滤波掩码,当对应的位为1时,接收的报文的相应位与CanHwFilterCode对应位必须一致才能通过滤波。
Eg:若CanHwFilterCode为0x64,CanHwFilterMask为2047(0x7FF),则只能接收CanId为0x64的报文,若CanHwFilterMask为2032(0x7F0),则能接收0x60~0x6F区间内所有的报文
三、RTA-OS配置
用于响应CAN0控制器的不同消息缓冲区的中断请求
CAN0_ORED_0_31_MB_IRQHandler
CAN0_ORED_32_63_MB_IRQHandler
CAN0_ORED_IRQHandler
四、项目调试
1.在Parameters.mk里增加模块
在Eb里面增加了新模块之后,需要修改工程根目录下的Parameters.mk,增加对应的模块,否则会报头 文件找不到的错误。
#MCAL modules used
MCAL_MODULE_LIST := BaseNXP Det Mcu Rte Gpt Port Can_43_FLEXCAN
2.API调用
main.c
/*
* Copyright 2020 NXP
*
* NXP Confidential. This software is owned or controlled by NXP and may only be used strictly
* in accordance with the applicable license terms. By expressly accepting
* such terms or by downloading, installing, activating and/or otherwise using
* the software, you are agreeing that you have read, and that you agree to
* comply with and are bound by, such license terms. If you do not agree to
* be bound by the applicable license terms, then you may not retain,
* install, activate or otherwise use the software.
*
* This file contains sample code only. It is not part of the production code deliverables.
*/
#ifdef __cplusplus
extern "C" {
#endif
//linus change version
/*==================================================================================================
* INCLUDE FILES
==================================================================================================*/
#include "modules.h"
#include "Mcu.h"
#include "Gpt.h"
#include "Dio.h"
#include "Port.h"
#include "Icu.h"
#include "Os.h"
#include "Os_Target.h"
#include "ResetFunc.h"
#include "IoMcuAdc.h"
#include "IoMcuDio.h"
#include "IoMcuIcu.h"
#include "IoMcuPwm.h"
//#include "S32K3_LdCfg.h"
#include "Platform.h"
#include "Can_43_FLEXCAN.h"
/*==================================================================================================
* EXTERN DECLARATIONS
==================================================================================================*/
/*==================================================================================================
* GLOBAL VARIABLES
==================================================================================================*/
/*==================================================================================================
* GLOBAL FUNCTIONS
==================================================================================================*/
int main(void)
{
uint8 Status;
switch(Sys_GetCoreID())
{
case 0U:
{
Port_Init(NULL_PTR);
Mcu_Init(NULL_PTR);
Mcu_InitClock(McuClockSettingConfig_0);
while ( MCU_PLL_LOCKED != Mcu_GetPllStatus() ){}
Mcu_DistributePllClock();
Mcu_SetMode(McuModeSettingConf_0);
ResetFunc_RstSrc();
Gpt_Init(NULL_PTR);
Platform_Init(NULL_PTR);
Can_43_FLEXCAN_Init(NULL_PTR);
Can_43_FLEXCAN_SetControllerMode(CanController_DEBUG, CAN_CS_STARTED);
StartCore(0, &Status);
StartCore(1, &Status);
Os_InitializeVectorTable();
StartOS(OSDEFAULTAPPMODE);
break;
}
case 1U:
{
Gpt_Init(NULL_PTR);
Platform_Init(NULL_PTR);
Os_InitializeVectorTable();
StartOS(OSDEFAULTAPPMODE);
break;
}
default :
{
break;
}
}
}
#ifdef __cplusplus
}
#endif
/** @} */
发送数据示例:
uint8 send_buffer[8] = {1,2,3,4,5,6,7,8};
Can_PduType CanSend = {.id = 0x55u,.length = 8,.sdu = send_buffer};
Can_43_FLEXCAN_Write(CanDEG_Hth0, &CanSend);