|
先楫官方工程师干货:基于HPM6750 CAN2.0 及 CAN- FD 操作指南
[复制链接]
本文主要介绍了HPM6750的控制器局域网CAN(以下简称CAN控制器)的概述以及基于HPM-SDK CAN控制器的开发指导(包括实现CAN2.0、CAN-FD)。
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位。
3. 管脚
管脚名称 |
方向 |
功能说明 |
RXD |
输入 |
CAN接受数据信号
|
TXD |
输出 |
CAN 发送数据信号
|
STBY |
输出 |
CAN 外部收发器待机控制信号
|
1. API功能描述
CAN开发主要使用以下接口:
2. API数据结构
CAN开发主要使用以下接口:
-
- hpm_stat_t can_get_default_config(can_config_t *config);
-
- 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);
-
- hpm_stat_t can_send_message_blocking(CAN_Type *base, const can_transmit_buf_t *message);
-
- hpm_stat_t can_send_high_priority_message_blocking(CAN_Type *base, const can_transmit_buf_t *message);
-
- hpm_stat_t can_receive_message_blocking(CAN_Type *base, can_receive_buf_t *message);
-
- hpm_stat_t can_read_received_message(CAN_Type *base, can_receive_buf_t *message);
-
- void can_set_transmitter_delay_compensation(CAN_Type *base, uint8_t sample_point, bool enable);
-
2.1 CAN配置
- typedef struct {
- union {
- struct {
-
- uint32_t baudrate;
- uint32_t baudrate_fd;
- uint16_t can20_samplepoint_min;
- uint16_t can20_samplepoint_max;
- uint16_t canfd_samplepoint_min;
- uint16_t canfd_samplepoint_max;
- };
- struct {
-
- can_bit_timing_param_t can_timing;
- can_bit_timing_param_t canfd_timing;
- };
- };
- can_loopback_mode_t loopback_mode;
- bool use_lowlevel_timing_setting;
- bool enable_canfd;
- bool enable_self_ack;
- bool disable_re_transmission_for_ptb;
- bool disable_re_transmission_for_stb;
- uint16_t filter_list_num;
- can_filter_config_t *filter_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;
- can_filter_mode_t mode;
- bool enable;
- uint32_t code;
- uint32_t mask;
- } can_filter_config_t;
2.3 CAN发送
- /**
- * @brief CAN transmit buffer data structure
- */
- typedef union _can_tx_buf {
- uint32_t buffer[18];
- struct {
- struct {
- uint32_t id: 29;
- uint32_t : 1;
- uint32_t transmit_timestamp_enable: 1;
- };
- struct {
- uint32_t dlc: 4;
- uint32_t bitrate_switch: 1;
- uint32_t canfd_frame: 1;
- uint32_t remote_frame: 1;
- uint32_t extend_id: 1;
- 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];
- struct {
- struct {
- uint32_t id: 29;
- uint32_t : 1;
- uint32_t error_state_indicator: 1;
- };
- struct {
- uint32_t dlc: 4;
- uint32_t bitrate_switch: 1;
- uint32_t canfd_frame: 1;
- uint32_t remote_frame: 1;
- uint32_t extend_id: 1;
- uint32_t : 4;
- uint32_t loopback_message: 1;
- uint32_t error_type: 3;
- uint32_t cycle_time: 16;
- };
- 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;
- can_config.baudrate_fd = 2500000;
- 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;
- can_config.baudrate_fd = 2500000;
- can_config.enable_canfd = use_canfd;
-
- 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网络隔离以及网络中继的复杂需求,实现了工业网关的功能。
|
|