簡(jiǎn)介
本文主要介紹了HPM6750的控制器局域網(wǎng)CAN(以下簡(jiǎn)稱CAN控制器)的概述以及基于HPM-SDK CAN控制器的開發(fā)指導(dǎo)(包括實(shí)現(xiàn)CAN2.0、CAN-FD)。
CAN控制器
1. 概述
CAN 是 Controller Area Network 的縮寫(以下稱為 CAN),是 ISO 國(guó)際標(biāo)準(zhǔn)化的串行通信協(xié)議。HPM6750 MCU搭載了4路CAN控制器,CAN0/CAN1/CAN2/CAN3,它們具有如下特性:
● 支持 CAN 2.0B 協(xié)議,支持多達(dá) 8 字節(jié)的數(shù)據(jù)載荷, 數(shù)據(jù)速率可達(dá) 1Mbit/s?
● 支持 CAN FD 協(xié)議,支持多達(dá) 64 字節(jié)的數(shù)據(jù)載荷, 數(shù)據(jù)速率可達(dá) 2.5Mbit/s?
● 支持 1 ~ 1/256 的波特率預(yù)分頻,靈活配置波特率?
● 16 個(gè)接收緩沖器?
– FIFO 方式?
– 錯(cuò)誤或者不被接收的數(shù)據(jù)不會(huì)覆蓋存儲(chǔ)的消息?
● 1 個(gè)高優(yōu)先主發(fā)送緩沖器 PTB?
● 8 個(gè)副發(fā)送緩沖器 STB?
– FIFO 方式?
– 優(yōu)先級(jí)仲裁方式?
● 16 組獨(dú)立的篩選器?
– 支持 11 位標(biāo)準(zhǔn) ID 和 29 位擴(kuò)展 ID?
– 可編程 ID CODE 位以及 MASK 位?
● PTB/STB 均支持支持單次發(fā)送模式?
● 支持靜默模式?
● 支持回環(huán)模式?
● 支持待機(jī)模式?
● 支持捕捉傳輸?shù)腻e(cuò)誤種類以及定位仲裁失敗位置?
● 可編程的錯(cuò)誤警告值?
● 支持 ISO11898-4 規(guī)定時(shí)間觸發(fā) CAN 以及接收時(shí)間戳可配置停止位:1位,1.5位或者2位。
2. 系統(tǒng)框圖
3. 管腳
管腳名稱 | 方向 | 功能說明 |
RXD | 輸入 | CAN接受數(shù)據(jù)信號(hào) |
TXD | 輸出 | CAN 發(fā)送數(shù)據(jù)信號(hào) |
STBY | 輸出 | CAN 外部收發(fā)器待機(jī)控制信號(hào) |
CAN控制器功能開發(fā)指引
1. API功能描述
CAN開發(fā)主要使用以下接口:
//獲取CAN默認(rèn)配置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數(shù)據(jù)發(fā)送接口(阻塞模式)hpm_stat_t can_send_message_blocking(CAN_Type *base, const can_transmit_buf_t *message);//CAN高優(yōu)先級(jí)數(shù)據(jù)發(fā)送接口(PTB阻塞模式)hpm_stat_t can_send_high_priority_message_blocking(CAN_Type *base, const can_transmit_buf_t *message);//CAN 數(shù)據(jù)接收接口(阻塞模式)hpm_stat_t can_receive_message_blocking(CAN_Type *base, can_receive_buf_t *message);//CAN數(shù)據(jù)接收接口(非租塞模式)hpm_stat_t can_read_received_message(CAN_Type *base, can_receive_buf_t *message);//設(shè)置發(fā)送補(bǔ)償及使能(CAN-FD高速率使用,TDC)void can_set_transmitter_delay_compensation(CAN_Type *base, uint8_t sample_point, bool enable);
2. API數(shù)據(jù)結(jié)構(gòu)
2.1 CAN配置
typedef struct { union { struct { //當(dāng)禁用use_lowlevel_timing_setting時(shí),以下參數(shù)有效。 uint32_t baudrate; //CAN 2.0波特率設(shè)定 uint32_t baudrate_fd; // CAN-FD波特率設(shè)定,當(dāng)enable_canfd使能才有效 uint16_t can20_samplepoint_min; //CAN 2.0最小采樣點(diǎn)(0~1000) uint16_t can20_samplepoint_max; //CAN 2.0最大采樣點(diǎn)(0~1000) uint16_t canfd_samplepoint_min; //CAN-FD 最小采樣點(diǎn)(0~1000) uint16_t canfd_samplepoint_max; //CAN-FD 最大采樣點(diǎn)(0~1000) }; struct {//當(dāng)啟用use_lowlevel_timing_setting時(shí),以下參數(shù)有效。 can_bit_timing_param_t can_timing; //CAN2.0 位時(shí)間參數(shù) can_bit_timing_param_t canfd_timing; //CAN-FD 位時(shí)間參數(shù) }; };can_loopback_mode_t loopback_mode; //CAN回環(huán)模式,默認(rèn)是正常模式bool use_lowlevel_timing_setting; //是否啟用位時(shí)間參數(shù)設(shè)定 bool enable_canfd; //是否啟用CAN-FD bool enable_self_ack; //是否啟用自ACK幀bool disable_re_transmission_for_ptb; //是否禁用高優(yōu)先級(jí)PTB發(fā)送重傳, false:?jiǎn)伟l(fā)模式 true:重傳模式bool disable_re_transmission_for_stb; //是否禁用STP發(fā)送重傳, false:單發(fā)模式, true:重傳模式uint16_t filter_list_num; //接受過濾器list總數(shù)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, //標(biāo)準(zhǔn)格式和擴(kuò)展格式過濾選模式can_filter_mode_standard_frames, //標(biāo)準(zhǔn)格式過濾模式can_filter_mode_extended_frames, //擴(kuò)展格式過濾模式} 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發(fā)送
/** * @brief CAN transmit buffer data structure */typedef union _can_tx_buf {uint32_t buffer[18]; //發(fā)送 buffer,由于是聯(lián)合體,和下面的共享一塊內(nèi)存區(qū)域,buffer大?。?*18=72struct { struct { uint32_t id: 29; //CAN ID uint32_t : 1; uint32_t transmit_timestamp_enable: 1; //時(shí)間戳使能 }; struct { uint32_t dlc: 4; //數(shù)據(jù)長(zhǎng)度 uint32_t bitrate_switch: 1; //bitrate開關(guān) uint32_t canfd_frame: 1; //can-fd標(biāo)識(shí)位 uint32_t remote_frame: 1; //remote 標(biāo)識(shí)位 uint32_t extend_id: 1; //擴(kuò)展ID uint32_t : 24; }; uint8_t data[]; //數(shù)據(jù)指針 };} can_transmit_buf_t;
2.4 CAN接收
/** * @brief CAN receive buffer data structure */typedef union _can_rx_buf { uint32_t buffer[20]; //接收buffer,由于是聯(lián)合體,和下面的數(shù)據(jù)共享一塊內(nèi)存區(qū)域 struct { struct { uint32_t id: 29; //can id uint32_t : 1; uint32_t error_state_indicator: 1; //錯(cuò)誤狀態(tài)指示 }; struct { uint32_t dlc: 4; //數(shù)據(jù)長(zhǎng)度 uint32_t bitrate_switch: 1; //bitrate開關(guān) uint32_t canfd_frame: 1; //canfd 標(biāo)識(shí) uint32_t remote_frame: 1; //remote標(biāo)識(shí) uint32_t extend_id: 1; //擴(kuò)展ID uint32_t : 4; uint32_t loopback_message: 1; //回環(huán)數(shù)據(jù)標(biāo)識(shí) uint32_t error_type: 3; //錯(cuò)誤類型 uint32_t cycle_time: 16; //cycle time }; uint8_t data[]; //數(shù)據(jù)指針 };} can_receive_buf_t;
3. 配置流程
CAN控制器的CAN2.0和CAN-FD配置流程如下圖。
4. 樣例
4.1 內(nèi)部回環(huán)樣例
需求:
1.CAN-FD協(xié)議
2.波特率2.5Mbps
3.內(nèi)部回環(huán)模式
4.數(shù)據(jù)載荷64字節(jié)
5.遍歷can-id從0~2047(11位標(biāo)準(zhǔn)ID)
6.每幀數(shù)據(jù)確保不同
7.阻塞發(fā)送、非阻塞接收(非中斷模式)
8.對(duì)比接收和發(fā)送的數(shù)據(jù)包是否相等,并輸出結(jié)果
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; //內(nèi)部回環(huán) 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 兩路閉環(huán)收發(fā)樣例
需求:
1.CAN2.0協(xié)議
2.波特率1000000,1Mbps
3.CAN0發(fā)送,CAN1接收
4.數(shù)據(jù)載荷8字節(jié)
5.CAN0阻塞發(fā)送,CAN1阻塞接收
6.對(duì)比CAN0發(fā)送包和CAN1接收包是否相同,并輸出結(jié)果
7.壓測(cè)100次,輸出最終結(jié)果
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[i] = (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 四路收發(fā)樣例
需求:
1.CAN-FD協(xié)議
2.波特率2.5Mbps
3.數(shù)據(jù)載荷64字節(jié)
4.啟用中斷接收
5.CAN0/CAN1/CAN2/CAN3順序發(fā)送數(shù)據(jù)
6.確保CAN0/CAN1/CAN2/CAN3 can-id不同
7.確保每次發(fā)送的數(shù)據(jù)包內(nèi)容不同
8.分別對(duì)比每次一路CAN發(fā)送數(shù)據(jù)包和其它三路CAN接收的數(shù)據(jù)包是否相同,并輸出結(jié)果
9.壓測(cè)100次,并輸出結(jié)果
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[i]; 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[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 < 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);}
劃重點(diǎn)
使用HPM6750的CAN控制器,可以輕松實(shí)現(xiàn)4路CAN2.0/CAN-FD同時(shí)收發(fā)數(shù)據(jù),易于實(shí)現(xiàn)CAN網(wǎng)絡(luò)隔離以及網(wǎng)絡(luò)中繼的復(fù)雜需求,實(shí)現(xiàn)了工業(yè)網(wǎng)關(guān)的功能。
-
CAN
+關(guān)注
關(guān)注
57文章
2754瀏覽量
463702
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論