• STM32H743的FDCAN使用方法(2):STM32CubeMX初始化代码修改


    0 工具准备

    1.STM32CubeMX
    
    • 1

    1 前言

    本文介绍基于STM32CubeMX,修改基于STM32CubeMX生成的FDCAN初始化代码,成为我们能够正常使用的状态。

    2 初始化代码修改

    2.1 FDCAN初始化代码修改

    typedef enum
    {
        FDCAN_100K = 0,
        FDCAN_250K,
        FDCAN_500K,
        FDCAN_1M,
        FDCAN_2_5M,
        FDCAN_5M,
    } FDCAN_BAUD_CFG_Type;
    typedef enum
    {
        FDCAN_NORMAL = FDCAN_MODE_NORMAL,                            /* 正常模式 */
        FDCAN_RESTRICTED_OPERATIO = FDCAN_MODE_RESTRICTED_OPERATION, /* 受限模式 */
        FDCAN_BUS_MONITORING = FDCAN_MODE_BUS_MONITORING,            /* 监控模式 */
        FDCAN_INTERNAL_LOOPBACK = FDCAN_MODE_INTERNAL_LOOPBACK,      /* 内部环回模式 */
        FDCAN_EXTERNAL_LOOPBACK = FDCAN_MODE_EXTERNAL_LOOPBACK,      /* 外部环回模式 */
    } FDCAN_MODE_Type;
    const fdcan_cfg_t fdCANCfg[] =
        {
            /* 输入时钟100MHz,测试100K、250K、500K、1M、2M、5M收发CAN2.0正常 */
            {100000, 17, 2},  /* 采样点 :90% */
            {250000, 17, 2},  /* 采样点 :90% */
            {500000, 17, 2},  /* 采样点 :90% */
            {1000000, 17, 2}, /* 采样点 :90% */
            {2500000, 17, 2}, /* 采样点 :90% */
            {5000000, 17, 2}, /* 采样点 :90% */
    };
    /**
     * @brief 设置FDCAN标准ID过滤器
     *
     * @param id ID(0-0x7ff)
     * @param mask 掩码(0-0x7ff)
     */
    void set_fdcan_std_filter(u32 id, u32 mask)
    {
    
        hfdCan2StdFilter.IdType = FDCAN_STANDARD_ID; /* 设置标准 ID */
        /* 用于过滤索引,如果是标准 ID,范围 0 到 127。如果是扩展 ID,范围 0 到 64 */
        /* 过滤索引和前面配置的过滤器个数对应,如果个数为n,则索引为0 - n-1 */
        hfdCan2StdFilter.FilterIndex = 0;
        hfdCan2StdFilter.FilterType = FDCAN_FILTER_MASK;         /* 过滤器采样屏蔽位模式 */
        hfdCan2StdFilter.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; /* 如果过滤匹配,将数据保存到 Rx FIFO 0 */
        hfdCan2StdFilter.FilterID1 = id;                         /* 屏蔽位模式下,FilterID1 是消息 ID */
        hfdCan2StdFilter.FilterID2 = mask;                       /* 屏蔽位模式下,FilterID2 是消息屏蔽位 */
    }
    
    /**
     * @brief 设置FDCAN扩展ID过滤器
     *
     * @param id ID(0-0x1fffffff)
     * @param mask 掩码(0-0x1fffffff)
     */
    void set_fdcan_ext_filter(u32 id, u32 mask)
    {
    
        hfdCan2ExtFilter.IdType = FDCAN_EXTENDED_ID; /* 设置扩展 ID */
        /* 用于过滤索引,如果是标准 ID,范围 0 到 127。如果是扩展 ID,范围 0 到 64 */
        /* 过滤索引和前面配置的过滤器个数对应,如果个数为n,则索引为0 - n-1 */
        hfdCan2ExtFilter.FilterIndex = 0;
        hfdCan2ExtFilter.FilterType = FDCAN_FILTER_MASK;         /* 过滤器采样屏蔽位模式 */
        hfdCan2ExtFilter.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; /* 如果过滤匹配,将数据保存到 Rx FIFO 0 */
        hfdCan2ExtFilter.FilterID1 = id;                         /* 屏蔽位模式下,FilterID1 是消息 ID */
        hfdCan2ExtFilter.FilterID2 = mask;                       /* 屏蔽位模式下,FilterID2 是消息屏蔽位 */
    }
    /**
     * @brief FDCAN初始化
     *
     * @param mode 模式 环回、正常等
     * @param fdCANBaud FDCAN波特率
     * @return int 0:成功 -1:失败
     */
    int MX_FDCAN_Init(FDCAN_MODE_Type mode, FDCAN_BAUD_CFG_Type fdCANBaud)
    {
        HAL_StatusTypeDef ret;
        /* 选择FDCAN2 */
        hfdcan2.Instance = FDCAN2;
    
        /* 帧格式选择 */
        /* FDCAN_FRAME_CLASSIC:经典CAN格式(CAN2.0),最高支持1M
            仅支持收发CAN2.0报文
        */
        /* FDCAN_FRAME_FD_NO_BRS:不可变波特率FDCAN格式(仲裁段和数据段波特率一致),不兼容CAN2.0
            仲裁段和数据段的波特率一致
            支持收发FDCAN报文和CAN2.0报文
        */
        /* FDCAN_FRAME_FD_BRS:可变波特率FDCAN格式(仲裁段和数据段波特率可以一致),兼容CAN2.0
            在仲裁段使用较低波特率如500K,在数据段使用较高波特率如2M
            支持收发FDCAN报文和CAN2.0报文
        */
    
        /* 帧格式:不可变波特率 */
        hfdcan2.Init.FrameFormat = FDCAN_FRAME_FD_NO_BRS;
        /* 工作模式:自环、正常工作模式等 */
        /* 实测使用自环有bug,自己收不到自己发出的CAN报文 */
        hfdcan2.Init.Mode = mode;
    
        /* 关闭重传、发送暂停、协议错误处理 */
        hfdcan2.Init.AutoRetransmission = DISABLE;
        hfdcan2.Init.TransmitPause = DISABLE;
        hfdcan2.Init.ProtocolException = DISABLE;
    
        /* FDCAN分频系数 */
        /* CAN/FDCAN 1bit = 1Tq同步段 + 1-8Tq传播时间段 + 1-8相位缓冲段1 + 1-8相位缓冲段2 */
        /* CAN/FDCAN 实际使用中:1bit = 1Tq同步段 + TimeSeg1/BS1(传播时间段+相位缓冲段)+ TimeSeg2/BS2(相位缓冲段2) */
        /* 采样点推荐位置:85-90% 满足 (1Tq + BS1) / (1Tq + BS1 + BS2) , 建议87.5 */
    
        /* 经典CAN只需要关注仲裁阶段波特率设置,FDCAN需要设置仲裁段和数据段波特率且允许二者不一致(波特率可变)*/
        /*
            选择CAN2.0或FDCAN不可变波特率,仲裁段设置的波特率就是整个CAN报文波特率
            选择FDCAN可变波特率,仲裁段设置的波特率是仲裁段的CAN报文波特率
        */
        hfdcan2.Init.NominalPrescaler = FDCAN2_INPUT_CLOCK / (fdCANCfg[fdCANBaud].baud * (1 + fdCANCfg[fdCANBaud].bs1 + fdCANCfg[fdCANBaud].bs2));
        /* 用于动态调节Phase_Seg1和Phase_Seg2,所以不可以比Phase_Seg2和Phase_Seg2大,固定为1 */
        hfdcan2.Init.NominalSyncJumpWidth = 1;
        /* 设置位段1、位段2 */
        hfdcan2.Init.NominalTimeSeg1 = fdCANCfg[fdCANBaud].bs1;
        hfdcan2.Init.NominalTimeSeg2 = fdCANCfg[fdCANBaud].bs2;
    
        /* 只有选择FDCAN可变波特率帧格式这里的配置才作为数据段波特率 */
        hfdcan2.Init.DataPrescaler = FDCAN2_INPUT_CLOCK / (fdCANCfg[fdCANBaud].baud * (1 + fdCANCfg[fdCANBaud].bs1 + fdCANCfg[fdCANBaud].bs2));
        /* 用于动态调节Phase_Seg1和Phase_Seg2,所以不可以比Phase_Seg2和Phase_Seg2大,固定为1 */
        hfdcan2.Init.DataSyncJumpWidth = 1;
        /* 设置位段1、位段2 */
        hfdcan2.Init.DataTimeSeg1 = fdCANCfg[fdCANBaud].bs1;
        hfdcan2.Init.DataTimeSeg2 = fdCANCfg[fdCANBaud].bs2;
    
        /*
            FDCAN RAM偏移地址,只有一个FDCAN,偏移地址为0
            FDCAN1和FDCAN2共享2560个字(4Byte)
        */
        hfdcan2.Init.MessageRAMOffset = 0;
        /* 标准ID过滤器个数,范围0到128 */
        hfdcan2.Init.StdFiltersNbr = 1;
        /* 标准ID过滤器个数,范围0到64 */
        hfdcan2.Init.ExtFiltersNbr = 1;
        /* RXFIFO0元素个数,范围0到64 */
        hfdcan2.Init.RxFifo0ElmtsNbr = 64;
        /* RXFIFO0每个元素数据大小 */
        hfdcan2.Init.RxFifo0ElmtSize = FDCAN_DATA_BYTES_64;
        /* RXFIFO1元素个数,范围0到64 */
        hfdcan2.Init.RxFifo1ElmtsNbr = 0;
        /* RXFIFO1每个元素数据大小 */
        hfdcan2.Init.RxFifo1ElmtSize = FDCAN_DATA_BYTES_64;
        /* 设置Rx Buffer元素个数,范围0-64 */
        hfdcan2.Init.RxBuffersNbr = 0;
        /* 设置RxBuffer元素中每个数据大小,范围0-64 */
        hfdcan2.Init.RxBufferSize = FDCAN_DATA_BYTES_64;
        /* Tx Event FIFO元素个数,范围0到32 */
        hfdcan2.Init.TxEventsNbr = 0;
        /* 设置专用的 Tx Buffer 元素个数,范围 0 到 32*/
        hfdcan2.Init.TxBuffersNbr = 0;
        /* 设置用于Tx FIFO/Queue 的 Tx Buffers 个数。范围 0 到 32*/
        hfdcan2.Init.TxFifoQueueElmtsNbr = 32;
        /* 设置 FIFO 模式或者 QUEUE 队列模式 */
        hfdcan2.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;
        /* 设置 Tx Element 中的数据域大小 */
        hfdcan2.Init.TxElmtSize = FDCAN_DATA_BYTES_8;
        /* 初始化FDCAN2 */
        if (HAL_FDCAN_Init(&hfdcan2) != HAL_OK)
        {
            return -1;
        }
    
        /* 配置标准ID过滤器 */
        if (HAL_FDCAN_ConfigFilter(&hfdcan2, &hfdCan2StdFilter) != HAL_OK)
        {
            return -1;
        }
    
        /* 配置扩展ID过滤器 */
        if (HAL_FDCAN_ConfigFilter(&hfdcan2, &hfdCan2ExtFilter) != HAL_OK)
        {
            return -1;
        }
    
        /* 配置全局过滤器,配置后过滤器配置才会生效 */
        ret = HAL_FDCAN_ConfigGlobalFilter(&hfdcan2, FDCAN_REJECT, FDCAN_REJECT,
                                           ENABLE, ENABLE);
        if (ret != HAL_OK)
        {
            return -1;
        }
    
        /* 设置RxFIFO0的水印为1,接收到1个CAN报文就触发中断 */
        ret = HAL_FDCAN_ConfigFifoWatermark(&hfdcan2, FDCAN_CFG_RX_FIFO0, 1);
        if (ret != HAL_OK)
        {
            return -1;
        }
    
        /* 激活RXFIFO0的水印通知中断 */
        ret = HAL_FDCAN_ActivateNotification(&hfdcan2, FDCAN_IT_RX_FIFO0_WATERMARK, 0);
        if (ret != HAL_OK)
        {
            return -1;
        }
    
        /* 启动 FDCAN */
        HAL_FDCAN_Start(&hfdcan2);
    
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203

    为了便于使用,这里为FDCAN初始化函数增加了模式、波特率2个形参。所有的配置全部有详细注释,可以参考注释进行配置。

    2.2 增加FDCAN的RXFIFO0接收回调函数

    /**
     * @brief FDCAN的RXFIFO0接收回调
     *
     * @param hfdcan FDCAN句柄
     * @param RxFifo0ITs RXFIFO0状态
     */
    void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs)
    {
        FDCAN_RxHeaderTypeDef rxHeader;
        uint8_t rxData[64];
        if (hfdcan == &hfdcan2)
        {
            if ((RxFifo0ITs & FDCAN_IT_RX_FIFO0_WATERMARK) != RESET)
            {
                /* 轮询RX FIFO,直到无数据可读 */
                for (;;)
                {
                    if (HAL_FDCAN_GetRxFifoFillLevel(hfdcan, FDCAN_RX_FIFO0) > 0)
                    {
                        /* 从 RX FIFO0 读取数据 */
                        HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rxHeader, rxData);
                        add_fdcan_recv_msg(&rxHeader, rxData);
                    }
                    else
                    {
                        break;
                    }
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    2.3 增加FDCAN的发送函数

    /**
     * @brief 发送CAN/FDCAN报文
     *
     * @param buff 数据
     * @param len 长度
     * @return int 0-成功 -1-失败
     */
    int fdcan_send(u8 *buff, u8 len)
    {
        int timeout = 0;
        HAL_StatusTypeDef ret;
        /* 初始化FDCAN发送参数 */
        fdCANSendCfg.Identifier = 0x147;                      /* 设置消息的ID */
        fdCANSendCfg.IdType = FDCAN_STANDARD_ID;              /* 标准ID */
        fdCANSendCfg.TxFrameType = FDCAN_DATA_FRAME;          /* 数据帧 */
        fdCANSendCfg.ErrorStateIndicator = FDCAN_ESI_ACTIVE;  /* 设置错误状态指示 */
        fdCANSendCfg.BitRateSwitch = FDCAN_BRS_OFF;           /* 关闭可变波特率 */
        fdCANSendCfg.FDFormat = FDCAN_CLASSIC_CAN;            /* FDCAN格式 */
        fdCANSendCfg.TxEventFifoControl = FDCAN_NO_TX_EVENTS; /* 用于发送事件 FIFO 控制, 不存储 */
        fdCANSendCfg.MessageMarker = 0;                       /* 用于复制到 TX EVENT FIFO 的消息 Maker 来识别消息状态(检查消息是否发送成功等),范围0到0xFF */
        fdCANSendCfg.DataLength = (uint32_t)len << 16;        /* 发送数据长度 */
        /* 等待TX FIFO可用 */
        while (HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan2) == 0)
        {
            HAL_Delay(1);
            timeout++;
            if (timeout > 100)
            {
                return -1;
            }
        }
        /* 添加数据到 TX FIFO */
        ret = HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan2, &fdCANSendCfg, buff);
        if (ret != HAL_OK)
        {
            return -1;
        }
        add_fdcan_send_msg(&fdCANSendCfg, buff);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    以上代码和CAN调试器在100K、250K、500K、1M下测试100万次收发正常。在内部回环、外部回环下无法收到FDCAN自己发出的报文,怀疑是HAL库bug,本文使用的HAL库版本如下:

    STM32Cube FW_H7 V1.11.0

    此外,发现在高速接收CAN报文时,如果stm32H743主频被设置为480MHz则会丢掉几乎所有包,而主频设置为400MHz则能够正常接收。
    如果你也遇到了和我一样的问题,欢迎留言交流!
    问题确认:
    stm32H743主频设置为480MHz时FDCAN外设在回环模式工作不正常。需要修改2个地方:
    (1)将主频修改为400MHz。
    (2)LDO稳压器输出的电压选择VOS1(480MHz时是VOS0),语句如下:
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
    stm32H743即使是v版本,最好也不要将主频设置到480MHz,否则会有各种头疼和意想不到(在实际使用过程中,将主频提高到480MHz,温度上升将近10℃,一些外设也出现了令人头脑眩晕的问题)的问题,为了稳定和省事起见,还是老老实实将主频设置为400MHz。

  • 相关阅读:
    JAVA在线课程教学大纲系统计算机毕业设计Mybatis+系统+数据库+调试部署
    智己汽车数据驱动中心PMO高级经理张晶女士受邀为第十三届中国PMO大会演讲嘉宾
    智能家居的实用性设置有哪些?智汀小米的怎么样?
    学习java的第十七天。。。(封装性、包、访问权限控制、static修饰符)
    JDBC与Spring事务及事务传播性原理解析-下篇
    几何角度理解线性代数(1):向量、线性组合、矩阵乘法、行列式
    ConcurrentHashMap源码解析 3.put() 方法
    数据库中间件
    uniapp新版微信小程序用户隐私协议授权
    【图像去雾】基于颜色衰减先验的图像去雾附matlab代码
  • 原文地址:https://blog.csdn.net/kevin1499/article/details/139200039