3071|6

87

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

先楫官方工程师干货:基于HPM6750 CAN2.0 及 CAN- FD 操作指南 [复制链接]

 

简介

 

本文主要介绍了HPM6750的控制器局域网CAN(以下简称CAN控制器)的概述以及基于HPM-SDK CAN控制器的开发指导(包括实现CAN2.0、CAN-FD)。

 

 

 CAN控制器

 

1. 概述

 

CAN 是 Controller Area Network 的缩写(以下称为 CAN),是 ISO 国际标准化的串行通信协议。HPM6750 MCU搭载了4路CAN控制器,CAN0/CAN1/CAN2/CAN3,它们具有如下特性:

 

● 支持 CAN 2.0B 协议,支持多达 8 字节的数据载荷, 数据速率可达 1Mbit/s;

● 支持 CAN FD 协议,支持多达 64 字节的数据载荷, 数据速率可达 2.5Mbit/s;

● 支持 1 ∼ 1/256 的波特率预分频,灵活配置波特率;

● 16 个接收缓冲器;

– FIFO 方式;

– 错误或者不被接收的数据不会覆盖存储的消息;

● 1 个高优先主发送缓冲器 PTB;

● 8 个副发送缓冲器 STB;

– FIFO 方式;

– 优先级仲裁方式;

● 16 组独立的筛选器;

– 支持 11 位标准 ID 和 29 位扩展 ID;

– 可编程 ID CODE 位以及 MASK 位;

● PTB/STB 均支持支持单次发送模式;

● 支持静默模式;

● 支持回环模式;

● 支持待机模式;

● 支持捕捉传输的错误种类以及定位仲裁失败位置;

● 可编程的错误警告值;

● 支持 ISO11898-4 规定时间触发 CAN 以及接收时间戳可配置停止位:1位,1.5位或者2位。

 

2. 系统框图

 

 

3. 管脚

 

管脚名称 方向 功能说明
RXD 输入

CAN接受数据信号

TXD 输出

CAN 发送数据信号

STBY 输出

CAN 外部收发器待机控制信号

 

 

CAN控制器功能开发指引

 

1. API功能描述

 

CAN开发主要使用以下接口:

 

2. API数据结构

CAN开发主要使用以下接口:

//获取CAN默认配置
hpm_stat_t can_get_default_config(can_config_t *config);
//CAN 初始化接口
hpm_stat_t can_init(CAN_Type *base, can_config_t *config, uint32_t src_clk_freq);
//接收过滤器配置
hpm_stat_t can_set_filter(CAN_Type *base, const can_filter_config_t *config);
//CAN 数据发送接口(阻塞模式)
hpm_stat_t can_send_message_blocking(CAN_Type *base, const can_transmit_buf_t *message);
//CAN高优先级数据发送接口(PTB 阻塞模式)
hpm_stat_t can_send_high_priority_message_blocking(CAN_Type *base, const can_transmit_buf_t *message);
//CAN 数据接收接口(阻塞模式)
hpm_stat_t can_receive_message_blocking(CAN_Type *base, can_receive_buf_t *message);
//CAN 数据接收接口(非租塞模式)
hpm_stat_t can_read_received_message(CAN_Type *base, can_receive_buf_t *message);
//设置发送补偿及使能(CAN-FD高速率使用,TDC)
void can_set_transmitter_delay_compensation(CAN_Type *base, uint8_t sample_point, bool enable);

 

2.1 CAN配置

typedef struct {
    union {
        struct {
           //当禁用use_lowlevel_timing_setting时,以下参数有效。
            uint32_t baudrate;  //CAN 2.0波特率设定
            uint32_t baudrate_fd; // CAN-FD波特率设定,当enable_canfd使能才有效           
            uint16_t can20_samplepoint_min; //CAN 2.0最小采样点(0~1000)           
            uint16_t can20_samplepoint_max; //CAN 2.0最大采样点(0~1000)
            uint16_t canfd_samplepoint_min; //CAN-FD 最小采样点(0~1000)
            uint16_t canfd_samplepoint_max; //CAN-FD 最大采样点(0~1000)
        };
        struct {
//当启用use_lowlevel_timing_setting时,以下参数有效。
            can_bit_timing_param_t can_timing;  //CAN2.0 位时间参数
            can_bit_timing_param_t canfd_timing; //CAN-FD 位时间参数
        };
    };
can_loopback_mode_t loopback_mode;    //CAN回环模式,默认是正常模式
bool use_lowlevel_timing_setting;     //是否启用位时间参数设定
     bool enable_canfd;   //是否启用CAN-FD
     bool enable_self_ack;   //是否启用自ACK帧
bool disable_re_transmission_for_ptb;  //是否禁用高优先级PTB发送重传, false:单发模式 true:重传模式
bool disable_re_transmission_for_stb;  //是否禁用STP发送重传, false:单发模式, true:重传模式
uint16_t filter_list_num;   //接受过滤器list总数
can_filter_config_t *filter_list;  //接受过滤器list指针
} can_config_t;




2.2 CAN过滤配置

/**
 * [url=home.php?mod=space&uid=159083]@brief[/url]  CAN acceptance filter modes
 */
typedef enum _can_filter_mode {
    can_filter_mode_both_frames,                //标准格式和扩展格式过滤选模式
can_filter_mode_standard_frames,            //标准格式过滤模式
can_filter_mode_extended_frames,            //扩展格式过滤模式
} can_filter_mode_t;


/**
 * @brief CAN acceptance configuration
 */
typedef struct {
uint16_t index;                             //过滤器index
can_filter_mode_t mode;                 //过滤器模式
     bool enable;                               //过滤器是否使能
     uint32_t code;                              //ID code
     uint32_t mask;                              //ID mask
} can_filter_config_t;

2.3 CAN发送

/**
 * @brief CAN transmit buffer data structure
 */
typedef union _can_tx_buf {
uint32_t buffer[18];    //发送 buffer,由于是联合体,和下面的共享一块内存区域,buffer大小:4*18=72
struct {
        struct {
            uint32_t id: 29;                      //CAN ID
            uint32_t : 1;
            uint32_t transmit_timestamp_enable: 1;  //时间戳使能
        };
        struct {
            uint32_t dlc: 4;                        //数据长度
            uint32_t bitrate_switch: 1;             //bitrate开关
            uint32_t canfd_frame: 1;                //can-fd标识位
            uint32_t remote_frame: 1;               //remote 标识位
            uint32_t extend_id: 1;                  //扩展ID
            uint32_t : 24;
        };
        uint8_t data[];                             //数据指针
    };
} can_transmit_buf_t;

2.4 CAN接收

/**
 * @brief CAN receive buffer data structure
 */
typedef union _can_rx_buf {
    uint32_t buffer[20];           //接收buffer,由于是联合体,和下面的数据共享一块内存区域
    struct {
        struct {
            uint32_t id: 29;        //can id
            uint32_t : 1;
            uint32_t error_state_indicator: 1;  //错误状态指示
        };
        struct {
            uint32_t dlc: 4;                   //数据长度
            uint32_t bitrate_switch: 1;        //bitrate开关
            uint32_t canfd_frame: 1;           //canfd 标识
            uint32_t remote_frame: 1;          //remote标识
            uint32_t extend_id: 1;             //扩展ID
            uint32_t : 4;
            uint32_t loopback_message: 1;      //回环数据标识
            uint32_t error_type: 3;            //错误类型
            uint32_t cycle_time: 16;           //cycle time
        };
        uint8_t data[];                        //数据指针
    };
} can_receive_buf_t;

3. 配置流程

 

CAN控制器的CAN2.0和CAN-FD配置流程如下图。

 

4. 样例

 

4.1 内部回环样例

 

需求:

1.CAN-FD协议

2.波特率2.5Mbps

3.内部回环模式

4.数据载荷64字节

5.遍历can-id从0~2047(11位标准ID)

6.每帧数据确保不同

7.阻塞发送、非阻塞接收(非中断模式)

8.对比接收和发送的数据包是否相等,并输出结果

void board_can_loopback_test(void)
{
    bool result;
    uint32_t error_cnt = 0;
    uint32_t can_src_clk_freq;
    can_config_t can_config;
    board_init_can(BOARD_APP_CAN_BASE);
    can_src_clk_freq = board_init_can_clock(BOARD_APP_CAN_BASE);
    can_config.baudrate = 1000000; /* 1Mbps */
    can_config.baudrate_fd = 2500000; /*5Mbps*/
    can_config.loopback_mode = can_loopback_internal; //内部回环
    can_config.enable_canfd = true;
    hpm_stat_t status = can_init(BOARD_APP_CAN_BASE, &can_config, can_src_clk_freq);
    if (status != status_success) {
        printf("CAN initialization failed, error code: %d\n", status);
        return;
    }
    can_transmit_buf_t tx_buf;
    can_receive_buf_t rx_buf;
    memset(&tx_buf, 0, sizeof(tx_buf));
    memset(&rx_buf, 0, sizeof(rx_buf));
    tx_buf.dlc = can_payload_size_64;
    tx_buf.canfd_frame = 1;
    tx_buf.bitrate_switch = 1;
    for (uint32_t i = 0; i < 2048; i++) {
        tx_buf.id = i;
        for (uint32_t j = 0; j < 64u; j++) {
            tx_buf.data[j] = (uint8_t)i + j + 1;
        }
        can_send_message_blocking(BOARD_APP_CAN_BASE, &tx_buf);
        can_read_received_message(BOARD_APP_CAN_BASE, &rx_buf);
        result = can_buf_compare(&tx_buf, &rx_buf);
        if (!result) {
            error_cnt++;
            can_set_transmitter_delay_compensation(BOARD_APP_CAN_BASE, 64, true);
            hpm_stat_t status = can_init(BOARD_APP_CAN_BASE, &can_config, can_src_clk_freq);
            if (status != status_success) {
                printf("CAN initialization failed, error code: %d\n", status);
                return;
            }
            printf("ID=%08x, result:%s\n", rx_buf.id, result ? "passed": "failed");
        }
    }
    printf("    CAN loopback test for extend frame %s, error_cnt:%d\n", error_cnt == 0 ? "passed" : "failed", error_cnt);
}


 

4.2 两路闭环收发样例

 

需求:

1.CAN2.0协议

2.波特率1000000,1Mbps

3.CAN0发送,CAN1接收

4.数据载荷8字节

5.CAN0阻塞发送,CAN1阻塞接收

6.对比CAN0发送包和CAN1接收包是否相同,并输出结果

7.压测100次,输出最终结果
 

void can0_can1_rxrx_loop_test(void)
{
    pm_stat_t status;
    can_config_t can_config;
    bool use_canfd = false;
    can_get_default_config(&can_config);
    can_config.baudrate = 1000000; /* 1Mbps */
    can_config.baudrate_fd = 5000000; /* 2Mbps */
    can_config.enable_canfd = use_canfd;
    board_init_can(HPM_CAN0);
    board_init_can(HPM_CAN1);
    uint32_t can_src_clk_freq0 = board_init_can_clock(HPM_CAN0);
    uint32_t can_src_clk_freq1 = board_init_can_clock(HPM_CAN1);
    hpm_stat_t status0 = can_init(HPM_CAN0, &can_config, can_src_clk_freq0);
    if (status0 != status_success) {
        printf("CAN initialization failed, error code: %d\n", status0);
        return;
    }
    hpm_stat_t status1 = can_init(HPM_CAN1, &can_config, can_src_clk_freq1);
    if (status1 != status_success) {
        printf("CAN initialization failed, error code: %d\n", status1);
        return;
    }
    printf("CMD_STA_CMD_CTRL(0xA0)= %08x\n", HPM_CAN0->CMD_STA_CMD_CTRL);
    printf("F_PRESC               = %08x\n", HPM_CAN0->F_PRESC);
    printf("S_PRESC               = %08x\n", HPM_CAN0->S_PRESC);
    printf("TDC                   = %08x\n", HPM_CAN0->TDC);
    uint32_t error_cnt = 0;
    bool result = false;
    can_transmit_buf_t tx_buf;
    can_receive_buf_t rx_buf;
 memset(&tx_buf, 0, sizeof(tx_buf));
    memset(&rx_buf, 0, sizeof(rx_buf));
    tx_buf.id = 0x101;
    uint32_t id_max;
    if (!use_canfd) {
        tx_buf.dlc = can_payload_size_8;
        id_max = 8;
    } else {
        tx_buf.dlc = can_payload_size_8;
        id_max = 64;
        tx_buf.canfd_frame = 1;
        tx_buf.bitrate_switch = 1;
    }
    for(int index = 0; index < 100; index++)
    {
        for (uint32_t i = 0; i < id_max; i++) {
            tx_buf.data = (uint8_t)(index+i);
        }
        can_send_high_priority_message_blocking(HPM_CAN0, &tx_buf);
        can_receive_message_blocking(HPM_CAN1, &rx_buf);
        result = can_buf_compare(&tx_buf, &rx_buf);
        if (!result) {
            error_cnt++;
            printf("    CAN0->CAN1 for standard frame %s\n", result ? "passed" : "failed");
        }
        can_receive_message_blocking(HPM_CAN0, &rx_buf);
        result = can_buf_compare(&tx_buf, &rx_buf);
        if (!result) {
            error_cnt++;
            printf("    CAN1->CAN0 for standard frame %s\n", result ? "passed" : "failed");
        }
    }
    printf("    CAN can0 can1 rxrx loop test for result: %s, error_cnt:%d\n", error_cnt == 0 ? "passed" : "failed", error_cnt);
}

 

4.3 四路收发样例

 

需求:

1.CAN-FD协议

2.波特率2.5Mbps

3.数据载荷64字节

4.启用中断接收

5.CAN0/CAN1/CAN2/CAN3顺序发送数据

6.确保CAN0/CAN1/CAN2/CAN3 can-id不同

7.确保每次发送的数据包内容不同

8.分别对比每次一路CAN发送数据包和其它三路CAN接收的数据包是否相同,并输出结果

9.压测100次,并输出结果


static can_info_t s_can_info[] = {
        { .can_base = HPM_CAN0 },
        { .can_base = HPM_CAN1 },
#if defined(HPM_CAN2)
        { .can_base = HPM_CAN2 },
#endif
#if defined (HPM_CAN3)
        { .can_base = HPM_CAN3 },
#endif
};
volatile static bool has_new_rcv_msg_array[4];
volatile static can_receive_buf_t s_can_rx_buf_array[4];
SDK_DECLARE_EXT_ISR_M(IRQn_CAN0, board_can_isr0);
SDK_DECLARE_EXT_ISR_M(IRQn_CAN1, board_can_isr1);
SDK_DECLARE_EXT_ISR_M(IRQn_CAN2, board_can_isr2);
SDK_DECLARE_EXT_ISR_M(IRQn_CAN3, board_can_isr3);
void board_can_isr0(void)
{
    uint8_t flags = can_get_tx_rx_flags(HPM_CAN0);
    if ((flags & CAN_EVENT_RECEIVE) != 0) {
        can_read_received_message(HPM_CAN0, (can_receive_buf_t *)&s_can_rx_buf_array[0]);
        has_new_rcv_msg_array[0] = true;
    }
    can_clear_tx_rx_flags(HPM_CAN0, flags);
}
void board_can_isr1(void)
{
    uint8_t flags = can_get_tx_rx_flags(HPM_CAN1);
    if ((flags & CAN_EVENT_RECEIVE) != 0) {
        can_read_received_message(HPM_CAN1, (can_receive_buf_t *)&s_can_rx_buf_array[1]);
        has_new_rcv_msg_array[1] = true;
    }
    can_clear_tx_rx_flags(HPM_CAN1, flags);
}
void board_can_isr2(void)
{
    uint8_t flags = can_get_tx_rx_flags(HPM_CAN2);
    if ((flags & CAN_EVENT_RECEIVE) != 0) {
        can_read_received_message(HPM_CAN2, (can_receive_buf_t *)&s_can_rx_buf_array[2]);
        has_new_rcv_msg_array[2] = true;
    }
    can_clear_tx_rx_flags(HPM_CAN2, flags);
}
void board_can_isr3(void)
{
    uint8_t flags = can_get_tx_rx_flags(HPM_CAN3);
    if ((flags & CAN_EVENT_RECEIVE) != 0) {
        can_read_received_message(HPM_CAN3, (can_receive_buf_t *)&s_can_rx_buf_array[3]);
        has_new_rcv_msg_array[3] = true;
    }
    can_clear_tx_rx_flags(HPM_CAN3, flags);
}
void board_can0_1_2_3_txrx_loop_test(void)
{
    hpm_stat_t status;
    can_config_t can_config;
    bool use_canfd = true;
    can_get_default_config(&can_config);
    can_config.baudrate = 1000000; /* 1Mbps */
    can_config.baudrate_fd = 2500000; /* 5Mbps */
    can_config.enable_canfd = use_canfd;
    /* Initialize CAN */
    for (uint32_t i=0; i < ARRAY_SIZE(s_can_info); i++) {
        can_info_t  *info = &s_can_info;
        board_init_can(info->can_base);
        info->clock_freq = board_init_can_clock(info->can_base);
        status = can_init(info->can_base, &can_config,  info->clock_freq);
        if (status != status_success) {
            printf("CAN %d initialization failed, error code: %d\n", i, status);
            return;
        }
        printf("CMD_STA_CMD_CTRL(0xA0)= %08x\n", info->can_base->CMD_STA_CMD_CTRL);
        printf("F_PRESC               = %08x\n", info->can_base->F_PRESC);
        printf("S_PRESC               = %08x\n", info->can_base->S_PRESC);
        printf("TDC                   = %08x\n", info->can_base->TDC);
        can_enable_tx_rx_irq(info->can_base, CAN_EVENT_RECEIVE);
    }
    intc_m_enable_irq_with_priority(IRQn_CAN0, 1);
    intc_m_enable_irq_with_priority(IRQn_CAN1, 1);
    intc_m_enable_irq_with_priority(IRQn_CAN2, 1);
    intc_m_enable_irq_with_priority(IRQn_CAN3, 1);


    uint32_t error_cnt = 0;
    bool result = false;
    can_transmit_buf_t tx_buf[4];
    uint32_t data_max;
    memset(tx_buf, 0, sizeof(tx_buf));
    for(int i = 0; i < 4; i ++)
    {
        tx_buf.id = i+1;
        if (!use_canfd) {
            tx_buf.dlc = can_payload_size_8;
            data_max = 8;
        } else {
            tx_buf.canfd_frame = 1;
            tx_buf.bitrate_switch = 1;
            tx_buf.dlc = can_payload_size_64;
            data_max = 64;
        }
    }
    for(int index = 0; index < 100; index++)
    {
        for(uint32_t can_i = 0; can_i < 4; can_i++)
        {
            for (uint32_t i = 0; i < data_max; i++) {
                tx_buf[can_i].data = (uint8_t)(index+can_i+i);
            }
        }
        for(uint32_t can_i = 0; can_i < 4; can_i++)
        {
            can_send_high_priority_message_blocking(s_can_info[can_i].can_base, &tx_buf[can_i]);
            for(int j= 1; j < 4; j++)
            {
                printf("recv canid:%d\n", (can_i+j)%4);
                while(!has_new_rcv_msg_array[(can_i+j)%4])
                {
                }
                has_new_rcv_msg_array[(can_i+j)%4] = false;
                result = can_buf_compare(&tx_buf[can_i], &s_can_rx_buf_array[(can_i+j)%4]);
                if (!result) {
                    error_cnt++;
                }
                printf("  CAN%d->CAN%d for standard frame %s\n", can_i, (can_i+j)%4, result ? "passed" : "failed");
            }
        }
    }
    printf("    CAN can0 can1 rxrx loop test for result: %s, error_cnt:%d\n", error_cnt == 0 ? "passed" : "failed", error_cnt);
} 

划重点

 

使用HPM6750的CAN控制器,可以轻松实现4路CAN2.0/CAN-FD同时收发数据,易于实现CAN网络隔离以及网络中继的复杂需求,实现了工业网关的功能。

 

最新回复

nmg
论坛有开发板,如果想试用,可以来借 不过要年后了,现在快递啥的都停了   详情 回复 发表于 2023-1-19 19:28
点赞 关注
 
 

回复
举报

7042

帖子

11

TA的资源

版主

沙发
 
讲解非常详细到位,车载CAN的应用会越来越多,CAN用的地方也会非常广泛。
 
 
 

回复

115

帖子

0

TA的资源

一粒金砂(高级)

板凳
 

能有4个CAN2.0接口,在工业控制领域是有很大的好处的。

 

 
 
 

回复

3

帖子

0

TA的资源

一粒金砂(中级)

4
 

同时实现4路CANFD高速收发确实是比较先进了,现在STM32H系列最多两路CANFD还不能同时使用。微盟的2518SPI扩展用的太难受!能申请开发板就好了


点评

nmg
论坛有开发板,如果想试用,可以来借 不过要年后了,现在快递啥的都停了  详情 回复 发表于 2023-1-19 19:28
 
 
 

回复

3

帖子

0

TA的资源

一粒金砂(中级)

5
 

技术支持怎么样?期待


点评

nmg
我这边感觉技术支持应该可以,论坛这边提交过去网友的问题,他们都会响应  详情 回复 发表于 2023-1-19 19:21
 
 
 

回复

5263

帖子

236

TA的资源

管理员

6
 
rlg81 发表于 2023-1-17 21:06 技术支持怎么样?期待

我这边感觉技术支持应该可以,论坛这边提交过去网友的问题,他们都会响应

加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身
 
 
 

回复

5263

帖子

236

TA的资源

管理员

7
 
rlg81 发表于 2023-1-17 21:04 同时实现4路CANFD高速收发确实是比较先进了,现在STM32H系列最多两路CANFD还不能同时使用。微盟的2518SPI扩 ...

论坛有开发板,如果想试用,可以来借

不过要年后了,现在快递啥的都停了

加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表