本应用手册介绍了 CAN 转 UART 桥接器。本文档描述了 CAN 转 UART 桥接器的结构和行为。本文档详细介绍了软件实现、硬件连接和应用程序用法。用户可以通过修改预定义来配置桥接器。此外,还提供了相关代码。
Other TMs
基于不同的应用,器件之间有多种通信方法。如今,MCU 通常支持一种以上的通信方法。例如,MSPM0 可以针对特定器件支持 UART、SPI、CAN 等。当器件通过不同的通信接口传输数据时,会构建一个桥。
对于 CAN 和 UART,CAN-UART 桥接器用作两个接口之间的转换器。CAN-UART 桥接器使器件能够在一个接口上发送和接收信息,并在另一个接口上接收和发送信息。
本应用手册介绍了用于创建和使用 CAN-UART 桥接器的软件和硬件设计。通过提供 CAN 和 UART 通信接口,MSPM0G3507 微控制器 (MCU) 可用作解决方案。随附的演示使用具有 2Mbps CANFD 和 9600 波特率 UART 的 MSPM0G3507 来演示通道之间的数据收发。
CAN-UART 桥接器连接 CAN 和 UART 接口。本文中的示例可依靠 Launchpad 上的 XDS110 来使用 PC 观察 UART 数据。用户还可以通过 CAN-UART 桥接器从 PC 向 CAN 总线发送消息。对于 CAN 总线数据,用户可以使用 CAN 分析器或两个 LaunchPAD 形成环路,如随附演示的基本结构所示。
本文中的示例同时支持透明传输和协议传输。图 1-1 所示为用于透明传输的 PC 终端程序。图 1-2 所示为用于协议传输的 PC 终端程序。
对于协议传输,此示例指定了 UART 消息格式。用户还可以根据应用程序需要修改格式。接收来自 UART 的消息时,消息格式为 < 55 AA ID1 ID2 ID3 ID4 Length Data1 Data2 ...>。用户可以通过输入相同格式的数据,将数据从终端发送到 CAN 总线。55 AA 是标头。ID 区域为四字节。长度区域为一字节,表示数据长度。
对于透明传输,UART 使用可配置的超时来检测一条消息。来自 UART 的数据被填充到 CAN 的数据区域(反向相同)。CAN ID 是默认值。
在本文的设计中,CAN-UART 桥接器同时使用 CAN 接收和发送以及 UART 接收和发送。因此 CAN 模块和 UART 模块都必须进行配置。由于不同通信的消息格式不同,CAN-UART 桥接器还必须转换消息格式。
对于 CAN,CAN 模块支持传统 CAN 和 CAN FD(具有灵活数据速率的 CAN)协议。CAN 模块符合 ISO 11898-1:2015 标准。如需更多信息,请参阅相关文档。对于 UART,该接口可用于在 MSPM0 器件和另一个采用串行异步通信协议的器件之间传输数据。如需更多信息,请参阅相关文档。图 2-1 展示了 CAN-UART 桥接器的基本原理。通常,CAN 的通信速率远高于 UART 的通信速率。对于 CAN FD,波特率可高达 5Mbps,而 UART 以 9600bps 的波特率工作,如示例代码所示。因此,CAN 接收到的数据可能无法及时由 UART 发送。为了匹配波特率,该方案使用缓冲器在 CAN 和 UART 之间传输数据。此缓冲器不仅实现了数据缓存,还实现了数据格式转换。这相当于在两个通信接口之间添加屏障。用户可以为过载情况添加过载控制操作。
可以在 图 2-3 中看到具有协议传输功能的 CAN-UART 桥接器的结构。CAN-UART 桥接器可以分为四个独立的任务:从 UART 接收、从 CAN 接收、通过 CAN 传输、通过 UART 传输。两个 FIFO 实现双向消息传输和消息缓存。
图 2-4 展示了具有透明传输功能的 CAN-UART 桥接器的结构。添加了计时器中断,用于在一个数据包结束时检测超时。
UART 和 CAN 接收均设置为中断触发,以便能及时接收消息。进入中断时,首先通过 getXXXRxMsg() 提取消息。
对于 CAN,CAN 帧是固定格式。MSPM0 支持传统 CAN 或 CANFD。CANFD 的帧如 图 2-2 所示。本文中的示例可以在数据区域中为协议传输定义零、一和四个字节的附加 ID。
ID 区域 | 数据 | |
---|---|---|
协议传输 | 4/1/0 字节 | (数据长度)字节 |
对于 UART 协议传输,根据串行帧信息来识别消息。UART 消息格式在 UART 数据包格式中列出。
报头 | ID 区域 | 数据长度 | 数据 | |
---|---|---|---|---|
协议传输 | 0×55 0×AA | 4/1/0 字节 | 1 字节 | (数据长度)字节 |
透明传输 | — | — | — | (数据长度)字节 |
报头是一个固定的十六进制数字,组合为 0x55 0xAA,表示组的开头。ID 区域默认占用四个字节以匹配 CAN ID,可配置为一个字节,或者 ID 区域不存在。数据长度区域占用一个字节。数据长度区域之后是特定长度的数据。此格式作为示例提供。用户可以根据应用的要求修改格式。
对于 UART 透明传输,发生超时时会识别消息。所有字节都被视为纯数据。默认值是数据包信息的装载。(例如 ID)。
收到消息后,processXXXRxMsg() 转换消息的格式,并将消息作为新元素存储在 FIFO 中。FIFO 元素的格式如 图 2-5 所示。在 FIFO 元素的格式中,FIFO 元素中有四个类别:来源 ID、目标 ID、数据长度 和数据。用户还可以根据应用的要求更改消息项目。此外,该方案还会检查 FIFO 是否已满以进行过载控制。用户可以根据应用要求添加过载控制操作。
CAN 和 UART 传输均在主函数中执行。当检测到 FIFO 非空时,将提取 FIFO 元素。消息将被格式化并发送。对于 CAN,CAN 帧是固定格式。对于 UART,消息以 CAN 数据包格式中所述的格式发送。在本文的设计中,使用 UART TX 中断将数据填充到 UART TX 缓冲区中。
FIFO 结构如 图 2-5 所示。每个 FIFO 使用三个全局变量来指示 FIFO 状态。gUart2Can_FIFO, gUart2Can_FIFO.fifo_in 指示写入位置,gUart2Can_FIFO.fifo_out 指示读取位置,gUart2Can_FIFO.fifo_Count 指示 gUart2Can_FIFO 中的元素数量。
如果 gUart2Can_FIFO 为空,gUart2Can_FIFO.fifo_in 等于 gUart2Can_FIFO.fifo_out,并且 gUart2Can_FIFO.fifo_count 为零。
执行 processUartRxMsg() 时,来自 UART 的新消息将存储到 gUart2Can_FIFO 中。因此,gUart2Can_FIFO.fifo_in 会移动到下一个位置,并且 gUart2Can_FIFO.fifo_count 会递增 1。
将消息从 gUart2Can_FIFO 传输到 CAN 时,gUart2Can_FIFO.fifo_out 会移动到下一个位置,而 gUart2Can_FIFO.fifo_count 会减去 1。gCan2Uart_FIFO 与 gUart2Can_FIFO 类似。
任务 | 函数 | 说明 | 位置 |
---|---|---|---|
UART 接收 | getUartRxMsg() | 获取接收到的 UART 消息 | bridge_uart.c bridge_uart.h |
processUartRxMsg() | 转换接收到的 UART 消息格式,并将消息存储到 gUART_RX_Element 中 | ||
UART 发送 | processUartTxMsg() | 转换要通过 UART 发送的 gUART_TX_Element 格式 | |
sendUartTxMsg() | 通过 UART 发送消息 | ||
CAN 接收 | getCANRxMsg() | 获取接收到的 CAN 消息 | bridge_can.c bridge_can.h |
processCANRxMsg() | 转换接收到的 CAN 消息格式,并将消息存储到 gCAN_RX_Element 中 | ||
CAN 发送 | processCANTxMsg() | 转换要通过 CAN 发送的 gCAN_TX_Element 格式 | |
sendCANTxMsg() | 通过 CAN 发送消息 |
所有可配置参数都在 user_define.h 中定义,这些参数在可配置参数中列出。
对于 UART,此示例同时支持透明传输和协议传输。可以通过定义 UART_TRANSPARENT 或 UART_PROTOCOL 来切换这些函数。
在透明传输中,用户可以配置超时来检测一条 UART 消息接收是否完成。
在协议传输中,用户可以为不同格式配置 ID 长度。请注意,有一个固定的 2 字节报头 (0×55 0×AA) 和 1 字节数据长度。若要更详细地修改格式,用户可能需要直接修改代码。
#define UART_TRANSPARENT
#ifdef UART_TRANSPARENT
/* The format of Uart:
* Transparent transmission - Data1 Data2 ...*/
#define UART_TIMEOUT (0x4000) //timeout 250ms
#else
#define UART_PROTOCOL
/* The format of Uart:
* if UART_ID_LENGTH = 4, format is 55 AA ID1 ID2 ID3 ID4 Length Data1 Data2 ...
* if UART_ID_LENGTH = 1, format is 55 AA ID Length Data1 Data2 ...
* if UART_ID_LENGTH = 0, format is 55 AA Length Data1 Data2 ...*/
//#define UART_ID_LENGTH (0)
//#define UART_ID_LENGTH (1)
#define UART_ID_LENGTH (4)
#endif
对于 CAN,ID 和数据长度包含在 CAN 帧中。用户可以通过更改 CAN_ID_LENGTH 在数据区域中添加另一个 ID。(默认值为 0)。
/* The format of CAN:
* if CAN_ID_LENGTH = 4, format is ID1 ID2 ID3 ID4 Data1 Data2 ...
* if CAN_ID_LENGTH = 1, format is ID Data1 Data2 ...
* if CAN_ID_LENGTH = 0, format is Data1 Data2 ...*/
#define CAN_ID_LENGTH (0)
//#define CAN_ID_LENGTH (1)
//#define CAN_ID_LENGTH (4)
参数 | 可选值 | 说明 |
---|---|---|
#define UART_TRANSPARENT | 定义/未定义 | 启用 UART 透明传输。 |
#define UART_PROTOCOL | 定义/未定义 | 启用 UART 协议传输。 |
#define UART_TIMEOUT (0x4000) | 超时 = UART_TIMEOUT/32768s | 超时表示一条 UART 消息接收完成。仅在定义了 UART_TRANSPARENT 时可用。在本例中,默认值为 250ms。 |
#define UART_ID_LENGTH (4) | 0/1/4 | 可选 UART ID 长度,与协议中的 ID 区域相关。仅在定义了 UART_PROTOCOL 时可用。在本例中,默认值为四字节。 |
#define CAN_ID_LENGTH (0) | 0/1/4 | 可选 CAN ID 长度,与协议中的 ID 区域相关。在本例中,默认值为 0 字节。 |
#define TRANSMIT_DATA_LENGTH (12) | <=64 | 数据区域的大小。如果接收到的消息包含的数据多于此值,可能会发生数据丢失。 |
#define C2U_FIFO_SIZE (8) | CAN 到 Uart 的 FIFO 大小。请注意 SRAM 的用法。 | |
#define U2C_FIFO_SIZE (8) | Uart 到 CAN 的 FIFO 大小。请注意 SRAM 的用法。 | |
#define DEFAULT_UART_ORIGIN_ID (0x00) | UART 原始 ID 的默认值 | |
#define DEFAULT_UART_DESTINATION_ID (0x00) | UART 目标 ID 的默认值 | |
#define DEFAULT_CAN_ORIGIN_ID (0x00) | CAN 原始 ID 的默认值 | |
#define DEFAULT_CAN_DESTINATION_ID (0x00) | CAN 目标 ID 的默认值 |
Custom_Element 结构在 user_define.h 中定义。Custom_Element 也显示在 图 2-5 中。
来源标识符指示消息的来源。以下是示例(CAN_ID_LENGTH =0,UART_ID_LENGTH =4)。
目标标识符 指示消息的目标。以下是示例(CAN_ID_LENGTH =0,UART_ID_LENGTH =4)。
/*user-defined information storage structure */
typedef struct {
/*! Origin Identifier, indicating the origin of the message */
uint32_t origin_id;
/*! Destination Identifier, indicating the destination of the message */
uint32_t destination_id;
/*! Data Length Code */
uint8_t dlc;
/*! Data bytes */
uint8_t data[TRANSMIT_DATA_LENGTH];
} Custom_Element;
Custom_FIFO 结构在 user_define.h 中定义。这也显示在 图 2-5 中。
typedef struct {
uint16_t fifo_in;
uint16_t fifo_out;
uint16_t fifo_count;
Custom_Element *fifo_pointer;
} Custom_FIFO;
gCan2Uart_FIFO 和 gUart2Can_FIFO 在 main.c 中定义请注意 SRAM 的使用情况,该使用情况与 C2U_FIFO_SIZE、U2C_FIFO_SIZE 和 Custom_Element 的大小相关。
/* Variables for C2U_FIFO
* C2U_FIFO is used to temporarily store message from CAN to UART */
Custom_Element gC2U_FIFO[C2U_FIFO_SIZE];
Custom_FIFO gCan2Uart_FIFO = {0, 0, 0, gC2U_FIFO};
/* Variables for U2C_FIFO
* U2C_FIFO is used to temporarily store message from UART to CAN */
Custom_Element gU2C_FIFO[U2C_FIFO_SIZE];
Custom_FIFO gUart2Can_FIFO = {0, 0, 0, gU2C_FIFO};
对于 UART 接收,在 bridge_uart.c 中定义了三个全局变量。
uint8_t gUartReceiveGroup[UART_RX_SIZE];
Custom_Element gUART_RX_Element;
uint16_t gGetUartRxMsg_Count;
下面介绍 UART 接收的过程
对于 UART 传输,在 bridge_uart.c 中定义了两个全局变量。
uint8_t gUartTransmitGroup[UART_TX_SIZE];
Custom_Element gUART_TX_Element;
下面介绍 UART 传输的过程。
对于 UART 接收,在 bridge_uart.c 中定义了两个全局变量。
uint8_t gUartReceiveGroup[UART_RX_SIZE];
Custom_Element gUART_RX_Element;
下面介绍 UART 接收的过程。
对于 UART 传输,在 bridge_uart.c 中定义了两个全局变量。
uint8_t gUartTransmitGroup[UART_TX_SIZE];
Custom_Element gUART_TX_Element;
下面介绍 UART 传输的过程。
对于 CAN 接收,在 bridge_can.c 中定义了两个全局变量。
DL_MCAN_RxBufElement rxMsg;
Custom_Element gCAN_RX_Element;
下面介绍 CAN 接收 的过程。
对于 CAN 传输,在 bridge_can.c 中定义了两个全局变量。
DL_MCAN_TxBufElement txMsg0;
Custom_Element gCAN_TX_Element;
下面介绍 CAN 传输的过程。
表 3-2 中的函数被分类到不同的文件中。UART 接收和传输函数包含在 bridge_uart.c 和 bridge_uart.h 中。CAN 接收和传输函数包含在 bridge_can.c 和 bridge_can.h 中。FIFO 元素结构在 user_define.h 中定义。
用户可以通过文件轻松分离函数。例如,如果只需要 UART 函数,用户可以保留 bridge_uart.c 和 bridge_uart.h 以调用相应函数。
对于外设的基本配置,该项目集成了 SysConfig 配置文件。用户可以使用 SysConfig 轻松修改外设的基本配置。
需要此功能的应用程序必须包含 CAN 模块 API 和 UART 模块 API。所有 API 文件都包含在下载的 SDK 中。
表 3-3 列出了 CAN-UART 桥接器设计在闪存大小和 RAM 大小方面的占用空间。图 3-1 和 表 3-3 的制作是使用 Code Composer Studio(版本:12.7.1.00001)且优化级别为 2 的条件下确定的。
用户可以调整 FIFO 的大小。FIFO 越大,意味着缓存容量越大,但占用的 RAM 空间也越大。有关详细信息,请参阅 节 5 中的相关内容。此外,此代码中数据字段的大小默认设置为最大 64 字节。用户可以根据实际数据长度配置数据字段大小。使用 12 字节的数据字段能够显著减少 RAM 的使用,如 表 3-3 中所列
所需的最小代码大小(字节) | 闪存 | SRAM |
---|---|---|
CAN-UART 桥接器 (协议传输) U2C_FIFO_SIZE=8 C2U_FIFO_SIZE = 8 数据大小 = 12 字节) |
6328 | 910 |
CAN-UART 桥接器 (协议传输) U2C_FIFO_SIZE=8 C2U_FIFO_SIZE=8 数据大小 = 64 字节) |
6416 | 2054 |
CAN-UART 桥接器 (协议传输 U2C_FIFO_SIZE=30 C2U_FIFO_SIZE=30 数据大小 = 12 字节) |
6432 | 1966 |
通过 LaunchPad 上的 XDS110,用户可以使用 PC 在 UART 端发送和接收消息。作为演示,可以将两个 LaunchPad 用作两个 CAN-UART 桥接器以形成一个环路。当 PC 通过其中一个 LaunchPad 发送 UART 消息时,PC 将从另一个 LaunchPad™ 接收 UART 消息。图 4-1 展示了基本结构。请注意,构建 CAN 总线需要 CAN 收发器。
随附的演示使用两个 LaunchPad:一个 TCAN1046EVM 和一个 PC。TCAN1046EVM 是一款高速双通道 CAN 收发器评估模块。图 4-2 显示了演示的连接。对于 LaunchPad,PA12 用于 CAN 发送,PA13 用于 CAN 接收。PA12 和 PA13 应连接到 TCAN1046EVM 的 TX 引脚和 RX 引脚。PA20 用于 UART 发送,PA21 用于 UART 接收。请注意,LaunchPad 的 eZ-FET 上的反向通道 UART 接口可用于与 PC 的 UART 通信。
对于 TCAN1046EVM,VCC 必须连接到 5V,VIO 必须连接到 3.3V,因为 TCAN1046 支持电平移位。要构建 CAN 总线,CANH1 和 CANL1 必须连接到 CANH2 和 CANL2。此外,CAN 总线上的终端(CANH 和 CANL)必须配置 J2(或 J3)和 J6(或 J8)跳线。每个跳线都将 120Ω 终端添加到各自的总线。有关更多信息,请参阅相关文档。
本节介绍了 CAN-UART 桥接器设计在应用程序方面的特性,以及如何对设计进行配置以满足应用程序需求。
有各种可配置参数,如 节 3.2 中所示。用户可以通过修改 user_define.h 中定义的所有参数来配置 CAN 和 UART 数据包帧、FIFO 的大小或数据区域的最大大小。
用户可以在 user_define.h 中修改 Custom_Element 的定义。可根据应用程序和存储要求增加或减少条目。
/*user-defined information storage structure */
typedef struct {
/*! Origin Identifier, indicating the origin of the message */
uint32_t origin_id;
/*! Destination Identifier, indicating the destination of the message */
uint32_t destination_id;
/*! Data Length Code */
uint8_t dlc;
/*! Data bytes */
uint8_t data[TRANSMIT_DATA_LENGTH];
} Custom_Element;
两个通信接口的接收和传输单独运行。消息通过 FIFO 传输。用户可以更改结构(例如使消息遵循特定的格式,甚至是特定的通信协议)。此外,用户可以根据 图 2-3 将结构拆分为单向传输。
MSPM0 的 CAN 模块符合 CAN 协议 2.0 A、B 和 ISO 11898-1:2015 标准。用户可以配置 CAN 模块的各种功能。通过使用 SysConfig,用户可以更改 CAN 的基本配置。(例如,数据传输速率)。
代码提供了 CAN ID 的可选配置。示例代码默认为 11 位 ID(标准 ID)。可以通过修改 user_define.h 来更改配置。