简介
本文主要介绍了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开发主要使用以下接口:
//获取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. api数据结构
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过滤配置
/** * @brief 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; //过滤器indexcan_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=72struct { 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 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 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 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[i].id = i+1; if (!use_canfd) { tx_buf[i].dlc = can_payload_size_8; data_max = 8; } else { tx_buf[i].canfd_frame = 1; tx_buf[i].bitrate_switch = 1; tx_buf[i].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[i] = (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 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网络隔离以及网络中继的复杂需求,实现了工业网关的功能。
利用非完全补偿技术实现超高增益带宽,并降低输入电压噪声
基于飞凌OK113i-S开发板适配10寸LCD显示
运营商加速数字化转型 如何构建和融入新的数字生态圈
KRC内部安全如何控制
中小型芯片代理商生存危机迫在眉睫,路在何方?
干货分享|基于HPM6750 CAN2.0 及 CAN- FD 操作指南
新品速递丨精度为 ±0.5% 的电压监控器
变色灯的电路图
智慧路灯供电及安全设计要求有哪些?
洲明智慧综合杆及智能交通专项工程荣获最佳工程奖
为何买冰箱都认海尔?320项专利守护,一根羽毛就能看到差距
直线电机模组与丝杆模组的优缺点对比
华为P10明日发布 三成用户购买意愿强烈
光衍射相对光强分布的测量
瑞萨与台积电将合作开发28nm纳米嵌入式闪存制程技术
2018年全球半导体支出将超千亿美元 三星占两成
双通道模拟采样电路图
华为参股的威马汽车,旗下首台新能源汽车EX5已经正式下线
禹山溶解氧测定仪传感器安装注意事项
实时人工智能模型旨在帮助保护大堡礁