Transmit And Receive
该示例演示了 CAN 外设的收发数据功能。
CAN外接USB CAN FD分析仪,通过PC端收发标准数据帧,扩展数据帧,标准远程帧,扩展远程帧,FD标准数据帧,FD扩展数据帧等帧类型与CAN controller进行通信。
芯片端在CAN中断中接收PC下发的数据,并传输相同数据给PC端,PC端收到芯片回的数据。
环境需求
该示例支持以下开发套件:
Hardware Platforms |
Board Name |
---|---|
RTL87x2G HDK |
RTL87x2G EVB |
更多信息请参考快速入门。
硬件连线
EVB外接TJA1051 CAN Receiver模块,连接P3_2和CTX,P3_4和CRX,连接EVB 3.3V和模块VCC,EVB VCC3.3和连接模块NC,连接EVB GND和模块GND和S。
TJA1051 CAN Receiver模块另一端通过USB CAN FD分析仪连接到PC,连接模块CANH和分析仪CANH,连接模块CANL和分析仪CANL。
CAN收发器介绍
本示例中采用TJA1051模块作为CAN收发器,用户可自行选择所用的CAN收发器。 TJA1051是一款高速CAN收发器,为CAN控制器提供差动发送和接收功能,传输速率高达1Mbit/s。

CAN 收发器模块

CAN 收发器模块连接示意图
编译和下载
该示例的工程路径如下:
Project file: samples\peripheral\can\trx\proj\rtl87x2g\mdk
Project file: samples\peripheral\can\trx\proj\rtl87x2g\gcc
请按照以下步骤操作构建并运行该示例:
打开工程文件。
按照 快速入门 中 编译APP Image 给出的步骤构建目标文件。
编译成功后,在路径
mdk\bin
或gcc\bin
下会生成 app binapp_MP_xxx.bin
文件。按下复位按键,开始运行。
测试验证
IC复位后,CAN FD Tool上会收到各个类型的帧。
使用CAN FD Tool给IC发送数据帧。
在Debug Analyzer工具上,打印接收到的帧数据。
IC接收的帧数据log
IC将收到的数据帧发送回tool,在tool上可以看到发送和接收的数据帧。
代码介绍
该章节分为以下几个部分:
源码路径
工程路径:
sdk\samples\peripheral\can\trx\proj
源码路径:
sdk\samples\peripheral\can\trx\src
该工程的工程文件代码结构如下:
└── Project: trx
└── secure_only_app
└── Device includes startup code
├── startup_rtl.c
└── system_rtl.c
├── CMSIS includes CMSIS header files
├── CMSE Library Non-secure callable lib
├── Lib includes all binary symbol files that user application is built on
└── rtl87x2g_io.lib
├── Peripheral includes all peripheral drivers and module code used by the application
├── rtl_rcc.c
├── rtl_pinmux.c
├── rtl_nvic.c
└── rtl_can.c
└── APP includes the ble_peripheral user application implementation
├── main_ns.c
└── io_can.c
初始化
初始化流程包括了 can_board_init
和 can_driver_init
。
can_board_init
包含了对PAD和PINMUX的设置。
配置PAD:设置引脚、PINMUX模式、PowerOn、无内部上拉。
配置PINMUX:分配引脚分别为CAN_TX、CAN_RX功能。
can_driver_init
包含了对CAN外设的初始化。
使能PCC时钟。
关闭CAN的自动重传模式。
设置CAN总线同步位时间,将CAN总线速度设置为500kHz。
使能CAN FD,设置CAN FD可变速率段位同步时间,将CAN FD可变速率段速度设置为5MHz,设置采样补偿SSP为自动计算模式。
使能CAN,配置CAN中断。
等待CAN总线打开。
备注
注意:如果程序卡在等待CAN总线打开处,请检查CAN bus是否连接准确。
RCC_PeriphClockCmd(APBPeriph_CAN, APBPeriph_CAN_CLOCK, ENABLE);
init_struct.CAN_AutoReTxEn = DISABLE;
init_struct.CAN_BitTiming.b.can_brp = 3;
...
init_struct.CAN_FdEn = ENABLE;
/* Here config to 5mhz. */
init_struct.CAN_FdBitTiming.b.can_fd_brp = 0;
...
CAN_Init(&init_struct);
CAN_Cmd(ENABLE);
/* CAN interrupts enable */
CAN_INTConfig((CAN_BUS_OFF_INT | CAN_WAKE_UP_INT | CAN_ERROR_INT |
CAN_RX_INT | CAN_TX_INT), ENABLE);
...
/* polling CAN bus on status */
while (CAN_GetBusState() != CAN_BUS_STATE_ON)
...
功能实现
执行
can_basic_tx
,依次发送标准数据帧,扩展数据帧,标准远程帧,扩展远程帧,FD标准数据帧,FD扩展数据帧。使用设置的发送帧类型将邮箱配置为发送模式。
使能邮箱发送中断,等待RAM状态空闲。
CANError_TypeDef tx_error;
CANTxFrame_TypeDef tx_frame_type;
tx_frame_type.msg_buf_id = buf_id;
...
switch (frame_type)
...
CAN_MBTxINTConfig(tx_frame_type.msg_buf_id, ENABLE);
tx_error = CAN_SetMsgBufTxMode(&tx_frame_type, tx_data, data_len);
while (CAN_GetRamState() != CAN_RAM_STATE_IDLE)
...
备注
注意:如果使用同一个邮箱号连续发送多个帧,请务必保证前一帧发送完成后再发送下一帧。
发送完毕后执行
can_basic_rx
,等待PC端发送帧进入接收中断。如果使能了FIFO模式则使用邮箱12进行接收。
屏蔽接收帧rtr,ide,id过滤,即接收所有帧。
失能Rx DMA,失能自动回复。
使用设置的接收帧类型将邮箱配置为接收模式。
使能邮箱接收中断,等待RAM状态闲。
CANError_TypeDef rx_error;
CANRxFrame_TypeDef rx_frame_type;
#if CAN_RX_FIFO_EN
rx_frame_type.msg_buf_id = CAN_MESSAGE_FIFO_START_ID;
#else
rx_frame_type.msg_buf_id = 0;
#endif
rx_frame_type.extend_frame_id = 0;
...
rx_error = CAN_SetMsgBufRxMode(&rx_frame_type);
CAN_MBRxINTConfig(rx_frame_type.msg_buf_id, ENABLE);
while (CAN_GetRamState() != CAN_RAM_STATE_IDLE)
...
当发送完成或接收完成或出现错误时,进入中断处理函数
CAN_Handler
。依次从产生接收完成中断的邮箱中读取与打印接收到的帧数据。
执行
can_basic_tx
将接收到的帧类型与帧数据发送回去。执行
can_basic_rx
等待下一次中断。
...
CAN_ClearMBnRxDoneFlag(index);
CANError_TypeDef get_error;
CANMsgBufInfo_TypeDef mb_info;
get_error = CAN_GetMsgBufInfo(index, &mb_info);
...
CAN_GetRamData(mb_info.data_length, rx_data);
CANDataFrameSel_TypeDef frame_type = CAN_CheckFrameType(mb_info.rtr_bit, mb_info.ide_bit,
mb_info.edl_bit);
...
/* Send back frame here. */
can_basic_tx(0, frame_type, mb_info.standard_frame_id, \
mb_info.extend_frame_id, rx_data, mb_info.data_length);
/* Start rx next time. */
can_basic_rx();
...