IMX RT FlexCan调试手册

本文描述的FlexCan主要指的是NXP公司的I.MX RT系列提供的FlexCan低速总线,主要内容是个人根据在调试FlexCan接口时碰到的一些问题而总结出的调试心得,希望对后续使用到此类接口的朋友有所帮助。

1、 FlexCan内部结构

图表 1	FlexCan内部框图
其中比较重要的结构就是提供Message Buffers去临时存储发送或者接收到的CAN Frame数据,这也是后续会使用到的很重要的一个功能。CAN收发数据时,MBs会存储有仲裁域、数据域的数据(含ID),控制器将从这一块的空间去取得收发的数据,进而完成收发功能。
此处不做详细介绍,感兴趣的朋友直接参照手册即可,下面直接进入正题,关于FlexCan的初始化和不同的功能实现。
**

2、 FlexCan的初始化

**
第一步,配置CAN的总线时钟,配置如下:

/*Clock setting for FLEXCAN*/
clock_root_config_t rootCfg = {0};
rootCfg.mux = kCLOCK_CAN1_ClockRoot_MuxSysPll2Pfd3; //FLEXCAN_CLOCK_SOURCE_SELECT
rootCfg.div = 5; //CAN ROOT CLK:60M
CLOCK_SetRootClock(kCLOCK_Root_Can1, &rootCfg);

此处我配置的总线时钟为60M,主要是为了后续配置CANFD总线波特率方便分频,如数据域的几个常用波特率:1Mbps,2 Mbps,3 Mbps,4 Mbps,5Mbps等,具体波特率可以参照产品的实际需求去配置。
第二步,在配置完时钟之后,配置波特率的实际分频参数,注意这里为了更贴合CAN总线对Bit数据采样的需求(实际测试过程中也发现如果使用默认配置,板子当前的硬件链路高波特率下无法完成正常传输:3Mbps以上,收发器支持5Mbps),下图是1BIT的CAN数据的组成:
图表 2 CANFD 比特时间组成

代码如下:

if (FLEXCAN_FDCalculateImprovedTimingValues(flexcanConfig.baudRate, flexcanConfig.baudRateFD, CAN_CLK_FREQ,
                                            &timing_config))
{
    /* Update the improved timing configuration*/
    memcpy(&(flexcanConfig.timingConfig), &timing_config, sizeof(flexcan_timing_config_t));
}
else
{
    PRINTF("No found Improved Timing Configuration. Just used default configuration\r\n\r\n");
}

第三步,设置完波特率之后,就是初始化CAN控制器,使用的函数如下:

/*!
 * brief Initializes a FlexCAN instance.
 *
 * This function initializes the FlexCAN module with user-defined settings.
 * This example shows how to set up the flexcan_config_t parameters and how
 * to call the FLEXCAN_FDInit function by passing in these parameters.
 *  code
 *   flexcan_config_t flexcanConfig;
 *   flexcanConfig.clkSrc               = kFLEXCAN_ClkSrc0;
 *   flexcanConfig.baudRate             = 1000000U;
 *   flexcanConfig.baudRateFD           = 2000000U;
 *   flexcanConfig.maxMbNum             = 16;
 *   flexcanConfig.enableLoopBack       = false;
 *   flexcanConfig.enableSelfWakeup     = false;
 *   flexcanConfig.enableIndividMask    = false;
 *   flexcanConfig.disableSelfReception = false;
 *   flexcanConfig.enableListenOnlyMode = false;
 *   flexcanConfig.enableDoze           = false;
 *   flexcanConfig.timingConfig         = timingConfig;
 *   FLEXCAN_FDInit(CAN0, &flexcanConfig, 60000000UL, kFLEXCAN_8BperMB, false);
 *   endcode
 *
 * param base FlexCAN peripheral base address.
 * param pConfig Pointer to the user-defined configuration structure.
 * param sourceClock_Hz FlexCAN Protocol Engine clock source frequency in Hz.
 * param dataSize FlexCAN FD frame payload size.
 * param brs If bitrate switch is enabled in FD mode.
 */
void FLEXCAN_FDInit(
    CAN_Type *base, const flexcan_config_t *pConfig, uint32_t sourceClock_Hz, flexcan_mb_size_t dataSize, bool brs)

这里有两个和MBs相关的参数,需要格外注意,分别是flexcanConfig.enableIndividMask和flexcanConfig.maxMbNum,enableIndividMask决定使用global mask还是使用individual mask,后面会有详细介绍,此处不细讲,maxMbNum决定最大的Message Buffer数量,由处理器决定,我们使用的处理器最大支持64个。
之后创建用户自定义的中断回调函数,并将用户中断回调注册到中断处理函数中,此处也是直接调用底层提供的API,如下:

    /* Create FlexCAN handle structure and set call back function. */
    FLEXCAN_TransferCreateHandle(CAN, &flexcanHandle, flexcan_callback, (flexcan_frame_t *)&rxframe);
    NVIC_SetPriority(CAN1_IRQn, 3);

用户中断回调函数的函数原型:

/*! @brief FlexCAN transfer callback function.
 *
 *  The FlexCAN transfer callback returns a value from the underlying layer.
 *  If the status equals to kStatus_FLEXCAN_ErrorStatus, the result parameter is the Content of
 *  FlexCAN status register which can be used to get the working status(or error status) of FlexCAN module.
 *  If the status equals to other FlexCAN Message Buffer transfer status, the result is the index of
 *  Message Buffer that generate transfer event.
 *  If the status equals to other FlexCAN Message Buffer transfer status, the result is meaningless and should be
 *  Ignored.
 */
typedef void (*flexcan_transfer_callback_t)(
    CAN_Type *base, flexcan_handle_t *handle, status_t status, uint32_t result, void *userData);

第四步,配置Message Buffers和对应的掩码,掩码有两种形式,其一是全局掩码,对全局的MBs有效,另一个是私有掩码,只对对应的MB有效,决定哪一个掩码有效就由上面描述的flexcanConfig.enableIndividMask = false/true决定。
全局掩码有三个,分别是RXMGMASK、RX14MASK、RX15MASK(RX14MASK只对MB 14有效,RX15MASK同理),全局掩码具体的设置函数如下:

    /* Set Rx Masking mechanism. */
    FLEXCAN_SetRxMbGlobalMask(CAN, FLEXCAN_RX_MB_STD_MASK(MASK, 0, 0));
	私有掩码则有64个,RXIMR0 - RXIMR63,对应MB0 – MB63,是一一对应的关系,所以私有掩码和对应的MB可以放到一起配置,这样看起来更方便,如下:
    /* Setup Rx Message Buffer. */
    mbConfig.format = kFLEXCAN_FrameFormatStandard;
    mbConfig.type = kFLEXCAN_FrameTypeData;
    rxframe.format = (uint8_t)kFLEXCAN_FrameFormatStandard;
    rxframe.type = (uint8_t)kFLEXCAN_FrameTypeData;
    rxframe.length = (uint8_t)DLC;
    
    for (uint8_t i = 0; i < MB_COUNT; i++)
    {
        if(idtable[i].id != 0x0U)
        {
            FLEXCAN_SetRxIndividualMask(CAN, i, FLEXCAN_RX_MB_STD_MASK(idtable[i].mask,0,0));
            mbConfig.id = FLEXCAN_ID_STD(idtable[i].id);
#if (defined(USE_CANFD) && USE_CANFD)
            FLEXCAN_SetFDRxMbConfig(CAN, i , &mbConfig, true);
#else
            FLEXCAN_SetRxMbConfig(CAN, i, &mbConfig, true);
#endif
            rxframe.id = FLEXCAN_ID_STD(idtable[i].id);
            rxXfer.mbIdx = (uint8_t)i;
#if (defined(USE_CANFD) && USE_CANFD)
            rxXfer.framefd = &rxframe;
            (void)FLEXCAN_TransferFDReceiveNonBlocking(CAN, &flexcanHandle, &rxXfer);
#else
            rxXfer.frame = &rxframe;
            (void)FLEXCAN_TransferReceiveNonBlocking(EXAMPLE_CAN, &flexcanHandle, &rxXfer);
#endif

        }
    }

这里的核心思想就是对于每一个MB都要配置对应的IndividualMask,同时启用该MB的接收函数,我们正常使用会让CAN接收函数常驻,在接收到数据时再通知应用,所以也要在中断回调中再次启用对应result(即MB index)的CAN接收函数,如下:

/*!
 * @brief FlexCAN Call Back function
 */
static void flexcan_callback(CAN_Type *base, flexcan_handle_t *handle, status_t status, uint32_t result, void *userdata)
{
    static BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    static BaseType_t outcome;
    switch (status)
    {
        case kStatus_FLEXCAN_RxIdle:
            outcome = xEventGroupSetBitsFromISR(flexcan_evengroup, BIT_1, &xHigherPriorityTaskWoken);
            if (outcome != pdFAIL)
                portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
            rxXfer.mbIdx = result;
#if (defined(USE_CANFD) && USE_CANFD)
            (void)FLEXCAN_TransferFDReceiveNonBlocking(base, &flexcanHandle, &rxXfer);
#else
            (void)FLEXCAN_TransferReceiveNonBlocking(base, &flexcanHandle, &rxXfer);
#endif

        break;

    case kStatus_FLEXCAN_TxIdle:
        if (TX_MESSAGE_BUFFER_NUM == result)
        {
            outcome = xEventGroupSetBitsFromISR(flexcan_evengroup, BIT_0, &xHigherPriorityTaskWoken);
            if (outcome != pdFAIL)
                portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
        }
        break;

    case kStatus_FLEXCAN_WakeUp:
        break;

    default:
        break;
    }
}

设置的MB ID和对应MASK的关系,如果设置MB[1]的ID是0x100,设置对应的RXIMR[1]的MASK为0x7FF,这说明MB[1]只会接收ID为0x100的CAN口数据,同理如果MASK设置为0x7FC,即最后两bit都为0,不会check,那此时MB[1]会接收ID范围为0x100-0x103的数据。
上述流程都是针对CANFD的,但如果使用CAN Classical,此时CAN将能支持CAN RXFIFO。
CAN/CANFD区别

当RXFIFO enable 后, RXFIFO 会占用前面几个MB, 首先MB[0:5]用来作为FIFO 缓存, 但是MB[6]之后的MB 可以用来定义 filter, 具体占用几个MB, 是通过CTRL2[RFFN] 来定义的, 那最少的定义(RFFN=0)MB6, 7 会被用做filter 的设置。
MB 6-7的空间能容纳8个 filter(4Byte存储一个filter), 这样RXIMR[0…7] 也有8个mask 与之对应, 这样 Rx FIFO global mask 就没有用途。
那么如果 RFFN = 1, MB6-9 用作filter, format C 格式的话, 那么会有16个filter, 但是 0-9 只有10个RXIMR 与之对应, 这样还有6个filter (10…15)没有mask 与其对应, 那么这样的换RX FIFO global mask 就跟这6个filter 合作,过滤收到的ID。

CANFIFO的filtertable配置idFilterTable对应的数组即可,然后再配置对应的MASK,如下:

/*! @brief FlexCAN Rx FIFO configuration structure. */
typedef struct _flexcan_rx_fifo_config
{
    uint32_t *idFilterTable;                    /*!< Pointer to the FlexCAN Rx FIFO identifier filter table. */
    uint8_t idFilterNum;                        /*!< The quantity of filter elements. */
    flexcan_rx_fifo_filter_type_t idFilterType; /*!< The FlexCAN Rx FIFO Filter type. */
    flexcan_rx_fifo_priority_t priority;        /*!< The FlexCAN Rx FIFO receive priority. */
} flexcan_rx_fifo_config_t;

/*!
 * @brief Configures the FlexCAN Rx FIFO.
 *
 * This function configures the Rx FIFO with given Rx FIFO configuration.
 *
 * @param base FlexCAN peripheral base address.
 * @param pRxFifoConfig Pointer to the FlexCAN Rx FIFO configuration structure.
 * @param enable Enable/disable Rx FIFO.
 *               - true: Enable Rx FIFO.
 *               - false: Disable Rx FIFO.
 */
void FLEXCAN_SetRxFifoConfig(CAN_Type *base, const flexcan_rx_fifo_config_t *pRxFifoConfig, bool enable);

至此,CAN的初始化基本完成,同时CAN接收函数保持常驻后台,如有不足欢迎补充。

3、调试问题

调试过程中实际碰到的问题有,CANFD的通信在自己的测试板上正常,但和标准CANFD模块通信测试无法通过,一直显示错误,后面确认是CANFD的CRC域未配置为ISO标准模式,配置成ISO标准模式即正常,寄存器CAN->CTRL2如下:

在这里插入图片描述

  • 7
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
### 回答1: IMX RT1050是一款功能强大的微控制器,但在调试时遇到问题可能是由以下原因引起的: 首先,调试的问题可能是硬件方面的。请确保IMX RT1050与调试工具之间的连接正确。检查调试工具的电源和连接电缆是否正常工作。还应该确保调试接口的引脚连接正确,例如JTAG或SWD。 其次,调试问题可能是由于软件设置不正确引起的。请检查您使用的调试工具和软件是否兼容IMX RT1050。确保调试配置文件正确设置,例如调试工具与目标设备的设备选项、时钟频率等。还应该检查是否有正确的调试固件和驱动程序。 另外,调试问题还可能是由于代码错误引起的。请仔细检查代码逻辑和语法错误,确保没有悬空指针、内存溢出等问题。可以使用调试工具中的断点和变量监视功能来帮助定位代码错误。 最后,如果以上方法都无法解决调试问题,建议参考IMX RT1050的官方文档和论坛,寻求更多的技术支持和解决方案。厂商可能会提供一些特殊的调试工具或技巧,帮助您解决调试问题。 综上所述,如果无法调试IMX RT1050,您可以从硬件、软件和代码三个方面进行排查和调试。及时仔细检查各个环节,并参考官方文档和论坛,以找出并解决问题。 ### 回答2: 对于imx rt1050无法调试的问题,有以下几个可能的原因和解决方法: 1. 连接问题:首先要确保你的开发板与计算机正确地连接。检查USB连接线是否插入正确,尝试更换USB线,或者使用不同的USB接口。还可以尝试重启计算机和开发板来解决潜在的连接问题。 2. 调试器设置问题:确保你的调试器设置正确。打开你所使用的集成开发环境(IDE),进入调试器设置,选择正确的调试器类型和目标设备类型。确认是否正确设置了调试器的端口和波特率等参数。 3. 软件问题:检查你的开发环境和SDK是否正确安装。确保你使用的是支持imx rt1050的开发环境版本,并且已经正确配置了相关的软件环境。尝试重新安装开发环境和SDK,或者尝试使用不同的开发环境来解决潜在的软件问题。 4. 硬件问题:如果以上方法都无效,有可能是硬件问题导致无法调试。检查你的开发板是否正常工作,例如检查供电是否正常、是否存在硬件损坏等。如果有必要,可以尝试更换开发板或者咨询厂家的技术支持。 总之,当遇到imx rt1050无法调试的问题时,可以从连接问题、调试器设置问题、软件问题和硬件问题等方面逐一排查,并采取相应的解决方法。如果以上方法都无效,建议寻求专业的技术支持来解决问题。 ### 回答3: IMX RT1050 是一款功能强大的嵌入式处理器,用于开发各种实时应用程序,但在进行调试时遇到问题可能是因为以下原因: 1. 硬件连接问题:请确保正确连接使用调试器(如J-Link)与目标板之间的调试接口,确保接口线正常工作,并且没有任何松动或接触不良。 2. 软件设置问题:调试前,请确保使用正确的 IDE(集成开发环境,如Keil MDK)并配置正确的调试选项。例如,选择正确的目标芯片型号(IMX RT1050),正确的调试接口(例如JTAG或SWD),以及正确的调试选项,如时钟频率和调试模式。 3. 编码问题:在程序编写过程中可能存在代码错误或配置问题。请确保您的代码没有任何逻辑错误,并且正确地初始化和配置了相关的硬件资源。 4. 供电问题:请确保目标板的供电电压和电流满足 IMX RT1050 的要求,以避免在调试过程中因为电源不足而出现问题。 5. 调试接口芯片问题:IMX RT1050 主芯片与调试器之间可能由于硬件兼容性问题而导致不能正常映射、调试相关操作。在这种情况下,您可能需要升级调试器固件,或者查找更多关于特定兼容性问题的信息。 如果以上解决方法无效,建议检查嵌入式处理器是否未被损坏,或者与原始设备制造商联系,以获取更详细的技术支持和建议。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值