This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] TCAN4550:传输延迟小于100毫秒时数据丢失,即使发生传输,也始终设置 SPI ERR。

Guru**** 2535750 points
Other Parts Discussed in Thread: TCAN4550

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/interface-group/interface/f/interface-forum/1074582/tcan4550-data-loss-when-transmitting-with-a-delay-less-than-100ms-and-spi-err-is-always-set-even-when-the-transmission-is-happening

部件号:TCAN4550
“线程: 测试”中讨论的其它部件

你好

我是 Sanskar Verma, 我在使用  TCAN4550为 CAN-FD 开发产品时遇到了问题。

我能够以1000毫秒的延迟传输和接收数据,但如果将延迟降至100毫秒或以下,则所有数据包都无法到达接收器。 传输延迟小于100毫秒时,数据会严重丢失。

如果 CAN_Transmit 延迟1000毫秒或更长时间,我可以接收所有数据。但我的应用程序不需要延迟传输。 我想不断地传输和接收来自多个节点的数据。

我正在附加 SPI 通信的所有4个波形以及寄存器0x000c,0x820,0x0824,0x0830的值供您参考。 如果您想从我身边获得更多信息,请查看并告诉我。

CLK    NCS

CLK CLK

   味噌

MOSI 莫西

寄存器的值

0x000C = 30000a / 20000a / 8 / 804000e (这些值保持随机波动)

0x820 = 88 / 8a (这些值大部分显示)

0x824 = 10105

0x830 = 809628 ff

0x0800 = c84004a0

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    桑斯卡尔

    我已经通知了我们的一位专家,他们将在周末后做出回应。 我们非常感谢您在这里的耐心等待。

    此致,

    埃里克·哈克特  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    你好,桑斯卡尔,

    我很乐意提供帮助,您能给我一些其他信息吗?

    您是使用 TI 的评估板,还是已经开发出自己的评估板?  如果您开发了自己的主板,您是否介意分享有关 TCAN4550电路的原理图?

    您使用的是哪种微处理器,您使用的是 TCAN4550附带的演示代码,或者您是否开发了自己的固件和驱动程序?

    SPI 数据速率是多少?  它与 CLK 波形的距离大约为3 Mbps。  这是正确的吗?

    NCS 波形的图片与 CLK 波形的图片相同。  您能否提供 NCS 的图解,或验证它在 SPI 事务之间是否为高?

    您能否提供缩小的图像来捕获在 NCS 下限和下限之间传输的完整 SPI 数据?  我们需要验证位数是否正确。  TCAN4550检查 SPI 事务中的位数是否正确,如果不正确,它将生成 SPI 错误。  这些位正在状态寄存器中设置,因此我们需要弄清楚原因。  在 NCS 落边和上升边之间传输多少位?

    对于寄存器0x820值0x88,这是 SPI 错误,然后是全局错误,也是为任何错误(包括 SPI 错误)设置的。  对于值0x8A,此 参数设置了 M_CAN 中断,这很可能表示您已收到消息。

    对于寄存器0x824值0x10105,您设置了 RF0W 和 RF0L,表示已达到 RX FIFO 水印,并且您丢失了消息。  这通常是因为您的 RX FIFO 没有足够的元素来存储收到的消息,从而让处理器有时间从内存中读取这些消息,并释放 RX FIFO 元素以获取新消息。  如果 RX FIFO 已满,新消息将根据您的配置被拒绝或覆盖。  如果在这两种情况下都有消息丢失,则会设置 RF0L 位。

    您还能提供 CAN 控制器配置寄存器的值吗? 这些是地址为0x1000或更高的寄存器。  我想了解一下您如何配置 CAN 控制器,例如您的 RX 和 TX FIFO 以及或缓冲器中有多少元素等

    根据您迄今为止提供的信息,我怀疑这里有一两个不同的问题。  第一个问题是 SPI 驱动程序生成错误时出现一些问题。  如果在写入 SPI 数据时出错,TCAN4550将放弃该事务,这可能导致延迟和损坏配置寄存器和 CAN 消息数据。

    第二个问题是,您的 CAN 控制器和 MRAM 空间可能没有为您的应用程序正确设置,您可能需要调整 RX FIFO 大小以防止消息丢失。

    如果您尚未阅读我们的《软件用户指南》,我建议您查看该指南,因为它讨论了如何配置设备。  您可以在此处找到它(链接)。

    此致,

    乔纳森

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    乔纳森您好,

    我附加了缩小图像,以捕获 在 NCS 下限和下限之间传输的完整 SPI 数据,然后再次上限。

    SPI 数据速率为3mbps,我正在 NCS 落边和上升边之间传输32位。

      以1000毫秒的延迟传输数据时的寄存器值

    0x0820=4a0

    0x000C=8

    0x0824=10000

      以10-100ms 或更低的延迟传输数据时的寄存器值

    0x0820=0

    0x000C=8

    0x0824=10000

    您能更强调 CAN 静音标志,在这种情况下它被设为高。

    我已附加了 TCAN4550.c 文件中的代码,以便您可以检查 MRAM 的配置。

    /*
    *TCAN4550.c
    *说明:此文件包含 TCAN4550函数,并依赖于 TCAN4x5x_SPI 抽象函数
    * TCAN4550与 TCAN4x5x 的附加功能集:
    *-看门狗计时器功能
    *
    *版本:1.2.0
    *日期:2019年5月1日
    *
    *更改日志
    * 1.2.1 (2019年9月19日)
    *-向 TCAN4x5x_MCAN_ReadXIDFilter 函数中添加了一个缺少的 AHB_Burst 读取结束(),这会导致下一次读取或写入失败
    *
    * 1.2.0 (2019年5月1日)
    *-增加了 MCAN_ConfigureGlobalFilter 功能以更改默认数据包行为
    *-添加了一个定义,允许高速缓存 MCAN 配置寄存器以减少 SPI 读取的数量
    *-向 MCAN_ReadNextFIFO 方法添加了 FIFO 填充级别检查器,如果没有新元素可供读取,则退出
    *-为 SID 和 XID 过滤器添加了读取功能
    *-增加了 SPIERR 清除功能
    *
    * 1.1.1 (2018年6月12日)
    *- ConfigureNominalTiming_Simple ()函数的次要拼写更正
    *
    * 1.1 (2018年6月6日)
    *-更新代码以提高可读性和一致性
    *-为了保持一致性,对某些函数名称进行了更新
    *-增加了中断的功能和抽象
    *-为最终硅更新了位字段
    *
    *
    *版权所有(c) 2019德州仪器(TI)公司。 保留所有权利。
    *软件许可协议
    *
    *以源代码和二进制格式重新分发和使用,有无
    *允许修改,但前提是符合以下条件
    *符合:
    *
    *重新发布源代码必须保留上述版权
    *注意,此条件列表和以下免责声明。
    *
    *二进制形式的再发行必须复制上述版权
    *注意,本条件列表和中的以下免责声明
    *随提供的文档和/或其他材料
    *分布。
    *
    *德州仪器(TI)公司的名称和的名称均不相同
    *其贡献者可用于认可或推广衍生产品
    *未经事先书面许可。
    *
    *本软件由版权所有者和贡献者提供
    *“原样”和任何明示或暗示的担保,包括但不包括
    *限于对适销性和适用性的暗示保证
    *一项特定目的不可否认。 在任何情况下,版权均不受限制
    *所有者或贡献者应对任何直接,间接,偶然,
    *特殊,模范或后果性损害(包括但不包括)
    *仅限于采购替代货物或服务;不使用,
    *数据或利润;或业务中断)
    责任理论,无论是合同责任,严格责任还是侵权行为
    *(包括疏忽或其他原因)因使用而产生
    *,即使被告知可能会造成此类损坏。
    *

    #include "TCAN4550.h"(#include "TCAN4550.h")

    volatile INT8_t TCAN_INT_Cnt = 0;//用于跟踪 MCAN 中断引脚的中断的变量
    UINT8_t UNIQUE ID_G = 0x01;
    UINT8_t global_ID_G = 0xFF;


    #ifdef TCAN4x5x_MCAN_Cache_configuration
    //如果启用了缓存,请定义必要的变量
    UINT32_t TCAN4x5x_MCAN_Cache[9];
    #endif

    /**
    *@简短启用受保护的 MCAN 寄存器
    *
    *尝试启用 CCCR.CCE 和 CCCR.init 以允许写入 MCAN 配置所需的受保护寄存器
    *
    *@如果成功启用则返回@c true,否则返回@c false
    *
    布尔
    TCAN4x5x_MCAN_EnableProtectedRegisters (void)

    UINT8_t i;
    UINT32_t readValue,firstRead;

    firstRead = AHB_READ_32 (REG_MCAN_CCCR);
    如果((firstRead &(REG_BITS_MCAN_CCCR_CCE | REG_BITS_MCAN_CCCR_init))=(REG_BITS_MCAN_CCCR_CCE | REG_BITS_MCAN_CCCR_INIT)))
    返回 true;

    //取消设置 CSA 和 CSR 位,因为如果我们处于待机模式,这些位将被设置。 将1写入这些位将强制发生时钟停止事件,并阻止返回到正常模式
    firstRead ~(REG_BITS_MCAN_CCCR_CSA | REG_BITS_MCAN_CCCR_CSR | REG_BITS_MCAN_CCCR_CCE | REG_BITS_MCAN_CCCR_INIT);
    //最多尝试5次设置 CCCR 寄存器(如果没有),然后进行配置失败,因为我们需要设置这些位来配置设备。
    (i = 5;i > 0;i -)

    AHB_WRITE _32 (REG_MCAN_CCCR,firstRead | REG_BITS_MCAN_CCCR_CCE | REG_BITS_MCAN_CCCR_init);
    readValue = AHB_READ_32 (REG_MCAN_CCCR);

    如果((readValue &(REG_BITS_MCAN_CCCR_CCE | REG_BITS_MCAN_CCCR_init))=(REG_BITS_MCAN_CCCR_CCE | REG_BITS_MCAN_CCCR_INIT)))
    返回 true;
    否则,如果(i = 1)//尝试次数用完,请放弃
    返回 false;
    }
    返回 true;
    }


    /**
    *@简要禁用受保护的 MCAN 寄存器
    *
    *尝试禁用 CCCR.CCE 和 CCCR.init 以禁止写入受保护的寄存器
    *
    *@如果成功启用则返回@c true,否则返回@c false
    *
    布尔
    TCAN4x5x_MCAN_DisableProtectedRegisters (空)

    UINT8_t i;
    UINT32_t readValue;

    readValue = AHB_READ_32 (REG_MCAN_CCCR);
    如果(((readValue & REG_BITS_MCAN_CCCR_CCE)=0)
    返回 true;

    //最多尝试5次取消设置 CCCR 寄存器,如果没有,则失败配置,因为我们需要设置这些位来配置设备。
    (i = 5;i > 0;i -)

    AHB_WRTE_32 (REG_MCAN_CCCR,(READValue &~(REG_BITS_MCAN_CCCR_CSA | REG_BITS_MCAN_CCCR_CSR | REG_BITS_MCCR_CCE | REG_BITS_MCAN_CCCR_INIT))));//取消设置这些位
    readValue = AHB_READ_32 (REG_MCAN_CCCR);

    如果(((readValue & REG_BITS_MCAN_CCCR_CCE)=0)
    返回 true;
    如果(i = 1)
    返回 false;
    }
    返回 true;
    }


    /**
    *@简介配置 MCAN CCCR 寄存器
    *
    *配置 CCCR 寄存器的位以匹配 CCCR 配置结构
    *
    *@警告此函数将写入受保护的 MCAN 寄存器
    *@注释要求使用@c TCAN4x5x_MCAN_EnableProtectedRegister()和@c TCAN4x5x_MCAN_DisableProtectedRegister()解锁受保护的寄存器,以便在配置后锁定寄存器
    *
    *@param * cccrConfig 是指向包含配置位的@c TCAN4x5x_MCAN_CCCR_Config 结构的指针
    *
    *@如果成功启用则返回@c true,否则返回@c false
    *
    布尔
    TCAN4x5x_MCAN_ConfigureCCCRRegister (TCAN4x5x_MCAN_CCCR_Config * cccrConfig)

    UINT32_t 值,readValue;


    value = cccrConfig->word;
    Value &=~(REG_BITS_MCAN_CCCR_RESPOND_Mask | REG_BITS_MCAN_CCCR_CSA | REG_BITS_MCCR_CCE | REG_BITS_MCAN_CCCR_INIT);//按位并获取有效位(忽略保留位以及 CCE 和 CCE)

    //如果我们在此处进行了设置,我们可以更新该值,以便我们的受保护写入保持启用状态
    value |=(REG_BITS_MCAN_CCCR_init | REG_BITS_MCAN_CCCR_CCE);


    AHB_WRITE _32 (REG_MCAN_CCCR,值);
    #ifdef TCAN4x5x_MCAN_VERIFY_CONFIGURATION 写入
    readValue = AHB_READ_32 (REG_MCAN_CCCR);

    //需要执行这些按位数,以便对时钟停止请求执行此操作,并且在比较读回值时不会触发错误失败
    ~((readValue & M ü(REG_BITS_MCAN_CCCR_RESPOND_Mask | REG_BITS_MCAN_CCCR_CSA | REG_BITS_MCCR_CSR | REG_BITS_MCAN_CCCR_CCE | REG_BITS_MCAN_CCCR_INIT))))
    !=(数值和~(REG_BITS_MCAN_CCCR_RESPOND_Mask | REG_BITS_MCAN_CCCR_CSA | REG_BITS_MCAN_CCCR_CSR | REG_BITS_MCCR_CCE | REG_BITS_MCAN_CCCR_INIT))))

    //如果我们的书面值和回读值不相同,则返回失败。
    返回 false;
    }

    //检查 CSR 位是否与预期不符,因为这可以由硬件设置。
    如果(((readValue & REG_BITS_MCAN_CCCR_CSR)!= cccrConfig->CSR)

    //然后 CSR 位存在差异,这可能不是故障。
    如果(TCAN4x5x_Device_ReadMode()=TCAN4x5x_device_mode_standby)

    // CSR 位是由于处于待机模式而设置的。 不是故障。
    返回 true;
    }否则{
    //由于其他原因,它不匹配,我们确实失败了。
    返回 false;
    }
    }
    #endif
    返回 true;
    }


    /**
    *@简介阅读 MCAN CCCR 配置寄存器
    *
    *读取 MCAN CCCR 配置寄存器并更新通过的@c TCAN4x5x_MCAN_CCCR_Config 结构
    *
    *@param * cccrConfig 是指向包含将更新的 CCCR 位字段的@c TCAN4x5x_MCAN_CCCR_Config 结构的指针
    *
    无效
    TCAN4x5x_MCAN_ReadCCCRRegister (TCAN4x5x_MCAN_CCCR_Config * cccrConfig)

    cccrConfig->word = AHB_READ_32 (REG_MCAN_CCCR);
    }


    /**
    *@简介使用简单结构读取 MCAN 数据时间设置
    *
    *读取 MCAN 数据计时寄存器并更新@c *dataTiming 结构
    *
    *@警告此函数将写入受保护的 MCAN 寄存器
    *@注释要求使用@c TCAN4x5x_MCAN_EnableProtectedRegister()和@c TCAN4x5x_MCAN_DisableProtectedRegister()解锁受保护的寄存器,以便在配置后锁定寄存器
    *
    *@param *数据计时是@c TCAN4x5x_MCAN_Data_Timing_Simple 结构的指针,该结构包含简化的数据计时信息
    *
    无效
    TCAN4x5x_MCAN_ReadDataTimingFD_Simple (TCAN4x5x_MCAN_Data_Timing_Simple *数据计时)

    UINT32_t 正则数据;

    //读取数据计时寄存器
    RegData = AHB_READ_32 (REG_MCAN_DBTP);

    //只有同时设置了 CCE 和 init,这些寄存器才可写入。 设置标称位计时和预计算器信息
    dataTiming->DataBitRatePrescaler =((regData >> 16)& 0x1F)+ 1;
    dataTiming->DataTqBeforeSamplePoint =(((regData >>8)& 0x1F)+2;
    dataTiming->DataTqAfterSamplePoint =(((regData >=4)& 0xF)+1;
    }


    /**
    *@简介使用原始的 MCAN 结构读取 MCAN 数据时间设置
    *
    *读取 MCAN 数据计时寄存器并更新@c *dataTiming 结构
    *
    *@param *数据计时是@c TCAN4x5x_MCAN_Data_Timing_Simple 结构的指针,该结构包含原始数据计时信息
    *
    无效
    TCAN4x5x_MCAN_ReadDataTimingFD_Raw (TCAN4x5x_MCAN_Data_Timing_Raw *数据计时)

    UINT32_t 正则数据;

    //读取数据计时寄存器
    RegData = AHB_READ_32 (REG_MCAN_DBTP);

    //只有同时设置了 CCE 和 init,这些寄存器才可写入。 设置标称位计时和预计算器信息
    dataTiming->DataBitRatePrescaler =((regData >> 16)和0x1F);
    dataTiming->DataTimeSeg1andProp =((regData >> 8)& 0x1F);
    dataTiming->DataTimeSeg2 =((regData >> 4)和0xF);
    dataTiming->DataSyncJumpWidth =(regData 和0xF);

    IF (regData & REG_BITS_MCAN_DBTP_TD_EN)

    //如果设置了 TDC,则读取 TDC 寄存器
    RegData = AHB_READ_32 (REG_MCAN_TDCR);
    数据计时->TDCOffset =((regData >> 8)和0x7F);
    数据计时->TDCFilter =(正数据和0x7F);
    }否则{
    数据计时->TDCOffset = 0;
    dataTiming->TDCFilter =0;
    }
    }


    /**
    *@简介使用简单的数据计时结构写入 MCAN 数据时间设置
    *
    *使用@c *数据计时指针的输入将数据计时信息写入 MCAN
    *
    *@警告此函数将写入受保护的 MCAN 寄存器
    *@注释要求使用@c TCAN4x5x_MCAN_EnableProtectedRegister()和@c TCAN4x5x_MCAN_DisableProtectedRegister()解锁受保护的寄存器,以便在配置后锁定寄存器
    *
    *@param *数据计时是@c TCAN4x5x_MCAN_Data_Timing_Simple 结构的指针,该结构包含简化的数据计时信息
    *@如果成功启用则返回@c true,否则返回@c false
    *
    布尔
    TCAN4x5x_MCAN_ConfigureDataTiming_Simple (TCAN4x5x_MCAN_Data_Timing_Simple *数据计时)

    UINT32_t writeValue,TDCOWriteValue;
    UINT32_t tempValue;

    //只有同时设置了 CCE 和 init,这些寄存器才可写入。 设置标称位计时和预计算器信息
    //检查以确保预校准器在1-32范围内
    tempValue =数据计时->DataBitRatePrescaler;
    如果(tempValue > 32)
    tempValue =32;
    否则,如果(tempValue == 0)
    tempValue = 1;

    writeValue =((UINT32_t)(tempValue -1))<16;// Subtract 1,因为 MCAN 期望值小于实际值1

    //在采样点处于有效范围2-33之前检查 Tq
    tempValue = dataTiming->DataTqBeforeSamplePoint;
    如果(tempValue > 33)
    tempValue =33;
    否则(tempValue <2)
    tempValue =2;

    writeValue |=((UINT32_t)(tempValue -2))<8;// Subtract 2 (同步位),因为 MCAN 期望值比实际值低1
    TDCOWriteValue =(UINT32_t)(tempValue - 1)<8;// Subtract 1,用于使次采样点与主要样本匹配。 我们推出了同步功能。 请参阅下面的注释了解原因
    //在采样点处于1-16的有效范围内后检查 Tq
    tempValue = dataTiming->DataTqAfterSamplePoint;
    如果(tempValue > 16)
    tempValue =16;
    否则,如果(tempValue == 0)
    tempValue = 1;

    writeValue |=((UINT32_t)(tempValue -1))<4;// Subtract 1,因为 MCAN 期望值小于实际值1

    //在大多数情况下,从 tq 复制采样点后的 SJW
    writeValue |=((UINT32_t)(tempValue -1));// Subtract 1,因为 MCAN 期望值小于实际值1

    //注意:在大多数情况下,您希望启用“收发器延迟补偿偏移”,并将其设置为比 MCAN 中 DTSEG1寄存器多1个。
    //这样做可确保次要样本点与主样本点相同
    writeValue |= REG_BITS_MCAN_DBTP_TD_EN;
    AHB_WRITE _32 (REG_MCAN_DBTP,writeValue);//将值写入 DBTP 寄存器

    #ifdef TCAN4x5x_MCAN_VERIFY_CONFIGURATION 写入
    //检查写入是否成功。
    tempValue = AHB_READ_32 (REG_MCAN_DBTP);
    IF (tempValue != writeValue)
    返回 false;
    #endif

    AHB_WRITE _32 (REG_MCAN_TDCR,TDCOWriteValue);
    #ifdef TCAN4x5x_MCAN_VERIFY_CONFIGURATION 写入
    //检查写入是否成功。
    tempValue = AHB_READ_32 (REG_MCAN_TDCR);
    IF (tempValue != TDCOWriteValue)
    返回 false;
    #endif

    //配置时间戳计数器以使用外部时间戳值。 使用 CAN FD 的时间戳需要执行此操作
    AHB_WRITE _32 (REG_MCAN_TSCC,REG_BITS_MCAN_TSCC_COUNT_EXTERNAL);
    返回 true;
    }


    /**
    *@简介使用原始 MCAN 数据计时结构写入 MCAN 数据时间设置
    *
    *使用@c *数据计时指针的输入将数据计时信息写入 MCAN
    *
    *@警告此函数将写入受保护的 MCAN 寄存器
    *@注释要求使用@c TCAN4x5x_MCAN_EnableProtectedRegister()和@c TCAN4x5x_MCAN_DisableProtectedRegister()解锁受保护的寄存器,以便在配置后锁定寄存器
    *
    *@param *数据计时是@c TCAN4x5x_MCAN_Data_Timing_Raw 结构的指针,其中包含原始数据计时信息
    *
    *@如果成功启用则返回@c true,否则返回@c false
    *
    布尔
    TCAN4x5x_MCAN_ConfigureDataTiming_Raw (TCAN4x5x_MCAN_Data_Timing_Raw *数据计时)

    UINT32_t writeValue;
    #ifdef TCAN4x5x_MCAN_VERIFY_CONFIGURATION 写入
    UINT32_t tempValue;
    #endif

    //只有同时设置了 CCE 和 init,这些寄存器才可写入。 设置标称位计时和预计算器信息
    writeValue =((UINT32_t)(dataTiming->DataBitRatePrescaler & 0x1F)<16;
    writeValue |=((UINT32_t)(dataTiming->DataTimeSeg1和 Prop & 0x1F)<8;
    writeValue |=((UINT32_t)(dataTiming->DataTimeSeg2 & 0x0F))<4;
    writeValue |=((UINT32_t)(dataTiming->DataSyncJumpWidth & 0x0F));
    如果((数据计时->TDCOffset > 0)||(数据计时->TDCFilter > 0))

    //如果设置了其中任一项,则启用发送器延迟补偿
    writeValue |= REG_BITS_MCAN_DBTP_TD_EN;
    AHB_WRITE _32 (REG_MCAN_DBTP,writeValue);
    #ifdef TCAN4x5x_MCAN_VERIFY_CONFIGURATION 写入
    //检查写入是否成功。
    tempValue = AHB_READ_32 (REG_MCAN_DBTP);
    IF (tempValue != writeValue)
    返回 false;
    #endif

    writeValue =(UINT32_t)(数据计时->TDCOffset & 0x7F)<8;
    writeValue |=(UINT32_t)(数据计时->TDCFilter & 0x7F);
    AHB_WRITE _32 (REG_MCAN_TDCR,writeValue);
    #ifdef TCAN4x5x_MCAN_VERIFY_CONFIGURATION 写入
    //检查写入是否成功。
    tempValue = AHB_READ_32 (REG_MCAN_TDCR);
    IF (tempValue != writeValue)
    返回 false;
    #endif
    }否则{
    AHB_WRITE _32 (REG_MCAN_DBTP,writeValue);
    #ifdef TCAN4x5x_MCAN_VERIFY_CONFIGURATION 写入
    //检查写入是否成功。
    tempValue = AHB_READ_32 (REG_MCAN_DBTP);
    IF (tempValue != writeValue)
    返回 false;
    #endif
    }

    //配置时间戳计数器以使用外部时间戳值。 使用 CAN FD 的时间戳需要执行此操作
    AHB_WRITE _32 (REG_MCAN_TSCC,REG_BITS_MCAN_TSCC_COUNT_EXTERNAL);

    返回 true;
    }


    /**
    *@简介使用简单的计时结构读取 MCAN 标称/仲裁时间设置
    *
    *读取 MCAN 标称计时寄存器并更新@c *nomTiming 结构
    *
    *@param * nomTiming 是@c TCAN4x5x_MCAN_NOMINAL_Timing_Simple 结构的指针,该结构包含简化的标称计时信息
    *
    无效
    TCAN4x5x_MCAN_ReadNominalTiming_Simple (TCAN4x5x_MCAN_NOMINAL_Timing_Simple * NomTiming)

    UINT32_t readValue;

    readValue = AHB_READ_32 (REG_MCAN_NBTP);

    //只有同时设置了 CCE 和 init,这些寄存器才可写入。 设置标称位计时和预计算器信息
    NomTiming->NominalBitRatePrescaler =(((readValue >=16)& 0x1FF)+1;
    NomTiming->NominalTqBeforeSamplePoint =(((readValue >>8)& 0xFF)+2;
    NomTiming->NominalTqAfterSamplePoint =(readValue & 0x7F)+1;
    }


    /**
    *@简介使用原始 MCAN 计时结构读取 MCAN 标称/仲裁时间设置
    *
    *读取 MCAN 标称计时寄存器并更新@c *nomTiming 结构
    *
    *@param * nomTiming 是@c TCAN4x5x_MCAN_NOMINAL_Timing_Raw 结构的指针,其中包含原始 MCAN 标称计时信息
    *
    无效
    TCAN4x5x_MCAN_ReadNominalTiming_Raw (TCAN4x5x_MCAN_NOMINAL_Timing_Raw *坏时间)

    UINT32_t readValue;

    readValue = AHB_READ_32 (REG_MCAN_NBTP);

    //只有同时设置了 CCE 和 init,这些寄存器才可写入。 设置标称位计时和预计算器信息
    NomTiming->NominalSyncJumpWidth =((readValue >>25)& 0x7F);
    NomTiming->NominalBitRatePrescaler =((readValue >> 16)和0x1FF);
    NomTiming->NominalTimeSeg1andProp =(((readValue >>8)& 0xFF);
    nomTiming->NominalTimeSeg2 =(readValue 和0x7F);
    }


    /**
    *@简介使用简单的额定正时结构编写 MCAN 额定正时设置
    *
    *使用@c *nomTiming 指针的输入将数据计时信息写入 MCAN
    *
    *@警告此函数将写入受保护的 MCAN 寄存器
    *@注释要求使用@c TCAN4x5x_MCAN_EnableProtectedRegister()和@c TCAN4x5x_MCAN_DisableProtectedRegister()解锁受保护的寄存器,以便在配置后锁定寄存器
    *
    *@param * nomTiming 是@c TCAN4x5x_MCAN_NOMINAL_Timing_Simple 结构的指针,该结构包含简化的标称计时信息
    *@如果成功启用则返回@c true,否则返回@c false
    *
    布尔
    TCAN4x5x_MCAN_ConfigureNominalTiming_Simple (TCAN4x5x_MCAN_NOMINAL_Timing_Simple * NomTiming)

    UINT32_t writeValue,tempValue;


    //只有同时设置了 CCE 和 init,这些寄存器才可写入。 设置标称位计时和预计算器信息
    //检查预校准器是否在1-512的有效范围内
    tempValue = nomTiming->NomalBitRatePrescaler;
    如果(tempValue > 512)
    tempValue =512;
    否则,如果(tempValue == 0)
    tempValue = 1;
    writeValue =((UINT32_t)(tempValue -1))<16;// Subtract 1,因为 MCAN 期望值小于实际值1


    //检查预校准器是否在2-257的有效范围内
    tempValue = nomTiming->NomalTqBeforeSamplePoint;
    如果(tempValue > 257)
    tempValue =257;
    否则(tempValue <2)
    tempValue =2;
    writeValue |=((UINT32_t)(tempValue -2))<8;// Subtract 2,1用于同步,1因为 MCAN 期望值比实际值小1

    //检查预校准器是否在2-257的有效范围内
    tempValue = nomTiming->NomalTqAfterSamplePoint;
    如果(tempValue > 128)
    tempValue =128;
    否则(tempValue <2)
    tempValue =2;
    writeValue |=((UINT32_t)(tempValue -1));// Subtract 1,因为 MCAN 期望值小于实际值1
    writeValue |=((UINT32_t)(tempValue -1))<25;// NSWW 用于匹配钻头时间值后的 MCAN

    //将值写入 NBTP 寄存器
    AHB_WRITE _32 (REG_MCAN_NBTP,writeValue);
    #ifdef TCAN4x5x_MCAN_VERIFY_CONFIGURATION 写入
    //检查写入是否成功
    tempValue = AHB_READ_32 (REG_MCAN_NBTP);
    IF (tempValue != writeValue)
    返回 false;
    #endif

    返回 true;
    }


    /**
    *@简介使用原始的 MCAN 额定正时结构编写 MCAN 额定正时设置
    *
    *使用@c *nomTiming 指针的输入将数据计时信息写入 MCAN
    *
    *@警告此函数将写入受保护的 MCAN 寄存器
    *@注释要求使用@c TCAN4x5x_MCAN_EnableProtectedRegister()和@c TCAN4x5x_MCAN_DisableProtectedRegister()解锁受保护的寄存器,以便在配置后锁定寄存器
    *
    *@param * nomTiming 是@c TCAN4x5x_MCAN_NOMINAL_Timing_Raw 结构的指针,其中包含原始 MCAN 标称计时信息
    *@如果成功启用则返回@c true,否则返回@c false
    *
    布尔
    TCAN4x5x_MCAN_ConfigureNominalTiming_Raw (TCAN4x5x_MCAN_NOMINAL_Timing_Raw *坏时间)

    UINT32_t writeValue;
    #ifdef TCAN4x5x_MCAN_VERIFY_CONFIGURATION 写入
    UINT32_t tempValue;
    #endif
    //只有同时设置了 CCE 和 init,这些寄存器才可写入。 设置标称位计时和预计算器信息
    writeValue =((UINT32_t)(nomTiming->NomalSyncJumpWidth & 0x7F))<25;
    writeValue |=((UINT32_t)(nomTiming->NomalBitRatePrescaler & 0x1FF))<16;
    writeValue |=((UINT32_t)(nomTiming->NominalTimeSeg1andProp))<8;
    writeValue |=((UINT32_t)(nomTiming-> NomalTimeSeg2和0x7F));
    AHB_WRITE _32 (REG_MCAN_NBTP,writeValue);
    #ifdef TCAN4x5x_MCAN_VERIFY_CONFIGURATION 写入
    //检查写入是否成功
    tempValue = AHB_READ_32 (REG_MCAN_NBTP);
    IF (tempValue != writeValue)
    返回 false;
    #endif
    返回 true;
    }

    /**
    *@简介使用传递的全局过滤器配置结构配置 MCAN 全局过滤器配置寄存器。
    *
    *配置 MCAN 控制器在接收消息时的默认行为。 这可能包括默认情况下接受或拒绝 CAN 消息。
    *
    *@警告此函数将写入受保护的 MCAN 寄存器
    *@注释要求使用@c TCAN4x5x_MCAN_EnableProtectedRegister()和@c TCAN4x5x_MCAN_DisableProtectedRegister()解锁受保护的寄存器,以便在配置后锁定寄存器
    *
    *@param * GFC 是包含寄存器值的@c TCAN4x5x_MCAN_Global_Filter_Configuration 结构的指针
    *@如果成功启用则返回@c true,否则返回@c false
    *
    布尔
    TCAN4x5x_MCAN_ConfigureGlobalFilter (TCAN4x5x_MCAN_Global_Filter_Configuration *GFC)

    UINT32_t writeValue,readValue;


    writeValue =(GFC->Word & REG_BITS_MCAN_GFC_MASk);
    AHB_WRITE _32 (REG_MCAN_GFC,writeValue);

    #ifdef TCAN4x5x_MCAN_VERIFY_CONFIGURATION 写入
    readValue = AHB_READ_32 (REG_MCAN_GFC);

    //需要执行这些按位数,以便对时钟停止请求执行此操作,并且在比较读回值时不会触发错误失败
    IF (readValue != writeValue)

    //如果我们的书面值和回读值不相同,则返回失败。
    返回 false;
    }
    #endif
    返回 true;
    }


    /**
    *@简介配置 MRAM 寄存器
    *
    *使用@c *MRAMConfig 指针设置 MRAM 内存空间的各个部分。
    * MRAM 中可以配置多个不同的元素,包括其元素数量和元素大小。
    *此函数将自动为每个适当的 MRAM 部分生成起始地址,并尝试立即将其放回原位。
    *此函数将检查是否存在分配过多的内存条件,如果发现这种情况,则返回@c false。
    *
    *@警告此函数将写入受保护的 MCAN 寄存器
    *@注释要求使用@c TCAN4x5x_MCAN_EnableProtectedRegister()和@c TCAN4x5x_MCAN_DisableProtectedRegister()解锁受保护的寄存器,以便在配置后锁定寄存器
    *
    *@param * MRAMConfig 是@c TCAN4x5x_MRAM_Config 结构的指针,该结构包含所需的 MRAM 配置
    *@如果成功返回@c true,否则返回@c false
    *
    布尔
    TCAN4x5x_MRAM_Configure (TCAN4x5x_MRAM_Config * MRAMConfig)

    UINT16_t startAddress = 0x0000;//在我们将每个部分的起始地址和结束地址写入相应的寄存器时,用于保存这些地址
    UINT32_t registerValue = 0;//用于创建32位字以写入每个寄存器
    UINT32_t readValue =0;
    UINT8_t MRAMValue;


    //首先可以设置11位筛选器部分。
    MRAMValue = MRAMConfig->SIDNumElement;
    如果(MRAMValue > 128)
    MRAMValue = 128;

    registerValue = 0;
    如果(MRAMValue > 0)

    registerValue =((UINT32_t)(MRAMValue)<<16)|((UINT32_t) startAddress);
    }
    startAddress >=(4 *(uint16_t) MRAMValue);
    AHB_WRITE _32 (REG_MCAN_SIDFC,registerValue);
    #ifdef TCAN4x5x_MCAN_Cache_configuration
    TCAN4x5x_MCAN_Cache[TCAN4x5x_MCAN_Cache_SIDFC]= registerValue;
    #endif
    #ifdef TCAN4x5x_MCAN_VERIFY_CONFIGURATION 写入
    //验证注册内容
    readValue = AHB_READ_32 (REG_MCAN_SIDFC);
    IF (readValue != registerValue)
    返回 false;
    #endif


    // 29位扩展滤波器部分
    MRAMValue = MRAMConfig->XIDNumElement;
    如果(MRAMValue > 64)
    MRAMValue = 64;

    registerValue = 0;
    如果(MRAMValue > 0)

    registerValue =((UINT32_t)(MRAMValue)<<16)|((UINT32_t) startAddress);
    }
    startAddress >=(8 *(uint16_t) MRAMValue);
    AHB_WRITE _32 (REG_MCAN_XIDFC,registerValue);
    #ifdef TCAN4x5x_MCAN_Cache_configuration
    TCAN4x5x_MCAN_Cache[TCAN4x5x_MCAN_Cache_XIDFC]= registerValue;
    #endif
    #ifdef TCAN4x5x_MCAN_VERIFY_CONFIGURATION 写入
    //验证注册内容
    readValue = AHB_READ_32 (REG_MCAN_XIDFC);
    IF (readValue != registerValue)
    返回 false;
    #endif


    // RX FIFO 0
    MRAMValue = MRAMConfig->Rx0NumElement;
    如果(MRAMValue > 64)
    MRAMValue = 64;

    registerValue = 0;
    如果(MRAMValue > 0)

    registerValue =((UINT32_t)(MRAMValue)<<<16)|(UINT32_t) startAddress);//写入起始地址和元素数
    registerValue |= REG_BITS_MCAN_RXF0C_F0OM_OVERWRITE;// FIFO 已满时也启用覆盖模式
    }
    startAddress >=((((UINT32_t) TCAN4x5x_MCAN_TXRXESC_DataByteValue ((uint8_t) MRAMConfig->Rx0ElementSize)+ 8)*(uint16_t) MRAMValue);
    AHB_WRITE _32 (REG_MCAN_RXF0C,registerValue);
    #ifdef TCAN4x5x_MCAN_Cache_configuration
    TCAN4x5x_MCAN_Cache[TCAN4x5x_MCAN_Cache_RXF0C]= registerValue;
    #endif
    #ifdef TCAN4x5x_MCAN_VERIFY_CONFIGURATION 写入
    //验证注册内容
    readValue = AHB_READ_32 (REG_MCAN_RXF0C);
    IF (readValue != registerValue)
    返回 false;
    #endif

    // RX FIFO 1.
    MRAMValue = MRAMConfig->Rx1NumElement;
    如果(MRAMValue > 64)
    MRAMValue = 64;

    registerValue = 0;
    如果(MRAMValue > 0)

    registerValue =((UINT32_t)(MRAMValue)<<16)|((UINT32_t) startAddress);
    }
    startAddress >=((((UINT32_t) TCAN4x5x_MCAN_TXRXESC_DataByteValue ((uint8_t) MRAMConfig->Rx1ElementSize)+ 8)*(uint16_t) MRAMValue);
    AHB_WRITE _32 (REG_MCAN_RXF1C,registerValue);
    #ifdef TCAN4x5x_MCAN_Cache_configuration
    TCAN4x5x_MCAN_Cache[TCAN4x5x_MCAN_Cache_RXF1C]= registerValue;
    #endif
    #ifdef TCAN4x5x_MCAN_VERIFY_CONFIGURATION 写入
    //验证注册内容
    readValue = AHB_READ_32 (REG_MCAN_RXF1C);
    IF (readValue != registerValue)
    返回 false;
    #endif

    // RX 缓冲器
    //由于 RXBuffers 有点奇怪,您实际上不知道 MCAN 有多少元素。 相反,您可以通过过滤器间接告诉它。
    //例如,您必须设置一个过滤器,以告诉它要使用哪个值
    MRAMValue = MRAMConfig->RxBufNumElement;
    如果(MRAMValue > 64)
    MRAMValue = 64;

    registerValue = 0;
    如果(MRAMValue > 0)

    registerValue =((UINT32_t) startAddress);
    }
    startAddress >=((((UINT32_t) TCAN4x5x_MCAN_TXRXESC_DataByteValue ((uint8_t) MRAMConfig->RxBufElementSize)+8)*(uint16_t) MRAMValue);
    AHB_WRITE _32 (REG_MCAN_RXBC,registerValue);
    #ifdef TCAN4x5x_MCAN_Cache_configuration
    TCAN4x5x_MCAN_Cache[TCAN4x5x_MCAN_Cache_RXBC]= registerValue;
    #endif
    #ifdef TCAN4x5x_MCAN_VERIFY_CONFIGURATION 写入
    //验证注册内容
    readValue = AHB_READ_32 (REG_MCAN_RXBC);

    IF (readValue != registerValue)
    返回 false;
    #endif

    // TX 事件 FIFO
    MRAMValue = MRAMConfig->TxEventFIFO 子图;
    如果(MRAMValue > 32)
    MRAMValue =32;

    registerValue = 0;
    如果(MRAMValue > 0)

    registerValue =((UINT32_t)(MRAMValue)<<16)|((UINT32_t) startAddress);
    }
    startAddress >=(8 *(uint16_t) MRAMValue);
    AHB_WRITE _32 (REG_MCAN_TXEFC,registerValue);
    #ifdef TCAN4x5x_MCAN_Cache_configuration
    TCAN4x5x_MCAN_Cache[TCAN4x5x_MCAN_Cache_TXEFC]= registerValue;
    #endif
    #ifdef TCAN4x5x_MCAN_VERIFY_CONFIGURATION 写入
    //验证注册内容
    readValue = AHB_READ_32 (REG_MCAN_TXEFC);
    IF (readValue != registerValue)
    返回 false;
    #endif

    // TX 缓冲区
    MRAMValue = MRAMConfig->TxBufferNumElement;
    如果(MRAMValue > 32)
    MRAMValue =32;


    registerValue = 0;
    如果(MRAMValue > 0)

    registerValue =((UINT32_t)(MRAMValue)<<24)|((UINT32_t) startAddress);
    registerValue |= REG_BITS_MCAN_TXBC_TFQM;//将 TFQM 设置为1 (队列模式),并将所有寄存器设置为通用非专用缓冲区。
    }
    startAddress >=((((UINT32_t) TCAN4x5x_MCAN_TXRXESC_DataByteValue ((uint8_t) MRAMConfig->TxBufferElementSize)+8)*(uint16_t) MRAMValue);
    AHB_WRITE _32 (REG_MCAN_TXBC,registerValue);
    #ifdef TCAN4x5x_MCAN_Cache_configuration
    TCAN4x5x_MCAN_Cache[TCAN4x5x_MCAN_Cache_TXBC]= registerValue;
    #endif
    #ifdef TCAN4x5x_MCAN_VERIFY_CONFIGURATION 写入
    //验证注册内容
    readValue = AHB_READ_32 (REG_MCAN_TXBC);
    IF (readValue != registerValue)
    返回 false;
    #endif


    //检查并确保我们没有超出内存限制。 如果是,则返回失败
    如果((startAddress -1)>(MRAM_SIZE + REG_MRAM))
    返回 false;

    //设置 RX 元素大小寄存器
    registerValue =(UINT32_t)(MRAMConfig->RxBufElementSize)<8)|(((UINT32_t)(MRAMConfig->Rx1ElementSize)<<4)|(UINT32_t)(MRAMConfig->Rx0ElementSize));
    AHB_WRITE _32 (REG_MCAN_RXESC,registerValue);
    #ifdef TCAN4x5x_MCAN_Cache_configuration
    TCAN4x5x_MCAN_Cache[TCAN4x5x_MCAN_Cache_RXESC]= registerValue;
    #endif
    #ifdef TCAN4x5x_MCAN_VERIFY_CONFIGURATION 写入
    //验证注册内容
    readValue = AHB_READ_32 (REG_MCAN_RXESC);
    IF (readValue != registerValue)
    返回 false;
    #endif


    //设置 TX 元素大小寄存器
    registerValue =(UINT32_t)(MRAMConfig->TxBufferElementSize);
    AHB_WRITE _32 (REG_MCAN_TXESC,registerValue);
    #ifdef TCAN4x5x_MCAN_Cache_configuration
    TCAN4x5x_MCAN_Cache[TCAN4x5x_MCAN_Cache_TXESC]= registerValue;
    #endif
    #ifdef TCAN4x5x_MCAN_VERIFY_CONFIGURATION 写入
    //验证注册内容
    readValue = AHB_READ_32 (REG_MCAN_TXESC);
    IF (readValue != registerValue)
    返回 false;
    #endif

    返回 true;
    }


    /**
    *@简要清除(零填充) MRAM 的内容
    *
    *向 MRAM 中的每个地址写入0。 用于在初始配置期间将 MRAM 初始化为已知值,以避免意外 ECC 错误发生
    *
    无效
    TCAN4x5x_MRAM_CLEAR (作废)

    UINT16_t curAddr;
    const uint16_t endAddr = REG_MRAM + MRAM_SIZE;

    //需要将0写入整个 MRAM
    CurAddr = REG_MRAM;

    同时(curAddr < endAddr)

    AHB_WRITE _32 (curAddr,0);
    curAddr +=4;
    }

    }


    /**
    *@简介阅读下一部 MCAN FIFO 元素
    *
    *此函数将读取指定的下一个 MCAN FIFO 元素,并返回相应的标题信息和数据有效负载。
    *电子邮件的起始地址是通过查看 MCAN 的寄存器自动计算的,该寄存器显示要读取的下一个元素的位置。
    *
    *@param FIFO @是与 RXFIFO 0或 RXFIFO 1相对应的 c TCAN4x5x_MCAN_FIFO 枚举
    *@param *标头是指向包含 CAN 特定标头信息的@c TCAN4x5x_MCAN_RX_Header 结构的指针
    *@param dataPayload[]是一个字节数组,将使用读取数据进行更新
    *
    *@警告@c dataPayload[]必须至少与最大的数据有效负载一样大,否则可能会写入到超出界限的内存
    *
    *@返回从 TCAN4x5x 读取并存储到@c 数据有效负载的字节数[]
    *
    UINT8_t.
    TCAN4x5x_MCAN_ReadNextFIFO (TCAN4x5x_MCAN_FIFO _Enum FIFO FIFO,TCAN4x5x_MCAN_RX_Header *报头,uint8_t 数据有效负载[])

    UINT32_t 读数据;
    UINT16_t startAddress;
    UINT8_t I=0,getIndex,元件尺寸;

    //获取获取获取缓冲区的位置和大小,具体取决于源类型
    开关(FIFOd精细)

    默认值:// RXFIFO 为默认值

    ReadData = AHB_READ_32 (REG_MCAN_RXF0S);
    如果((ReadData 和0x0000007F)=0)
    返回0;
    getIndex =(uint8_t)(((ReadData 和0x3F00)>> 8);
    //获取 RX 0开始位置和大小...
    #ifdef TCAN4x5x_MCAN_Cache_configuration
    ReadData = TCAN4x5x_MCAN_Cache[TCAN4x5x_MCAN_Cache_RXF0C];
    #else
    ReadData = AHB_READ_32 (REG_MCAN_RXF0C);
    #endif
    startAddress =(uint16_t)(ReadData 和0x0000FFFF)+ REG_MRAM;
    #ifdef TCAN4x5x_MCAN_Cache_configuration
    ReadData = TCAN4x5x_MCAN_Cache[TCAN4x5x_MCAN_Cache_RXESC];
    #else
    ReadData = AHB_READ_32 (REG_MCAN_RXESC);
    #endif
    ReadData &= 0x07;
    ElementSize = TCAN4x5x_MCAN_TXRXESC_DataByteValue(ReadData);//此 MCAN 配置支持的最大理论数据有效负载
    //计算最新索引的实际起始地址
    startAddress >=((((UINT32_t) elementSize + 8)* getIndex);
    休息;
    }

    盒装 RXFIFO:

    ReadData = AHB_READ_32 (REG_MCAN_RXF1S);
    如果((ReadData 和0x0000007F)=0)
    返回0;
    getIndex =(uint8_t)(((ReadData 和0x3F00)>> 8);
    //获取 RX 1开始位置和大小...
    #ifdef TCAN4x5x_MCAN_Cache_configuration
    ReadData = TCAN4x5x_MCAN_Cache[TCAN4x5x_MCAN_Cache_RXF1C];
    #else
    ReadData = AHB_READ_32 (REG_MCAN_RXF1C);
    #endif
    startAddress =(uint16_t)(ReadData 和0x0000FFFF)+ REG_MRAM;
    #ifdef TCAN4x5x_MCAN_Cache_configuration
    ReadData = TCAN4x5x_MCAN_Cache[TCAN4x5x_MCAN_Cache_RXESC];
    #else
    ReadData = AHB_READ_32 (REG_MCAN_RXESC);
    #endif
    ReadData =(ReadData 和0x70)>> 4;
    ElementSize = TCAN4x5x_MCAN_TXRXESC_DataByteValue(ReadData);//此 MCAN 配置支持的最大理论数据有效负载
    //计算最新索引的实际起始地址
    startAddress >=((((UINT32_t) elementSize + 8)* getIndex);
    休息;
    }
    }


    //读取数据,从突发读取开始
    AHB_READ_爆破_START (起始地址,2);
    ReadData = AHB_READ_爆破_READ();//第一个报头
    Header->ESI =(ReadData & 0x8000000)>> 31;
    HEAD-> XTD =(ReadData 和0x40000000)>> 30;
    Header->RTR =(ReadData & 0x20000000)>> 29;

    IF (信头->XTD)
    Header->ID =(ReadData 和0xFFFFFFF);
    否则
    Header->ID =(ReadData & 0x1FFC0000)>> 18;

    ReadData = AHB_READ_爆破_READ();//第二个报头
    AHB_READ_爆破 结束();//终止连拍读取
    HEAD-> RXTS =(ReadData 和0x0000FFFF);
    Header->DLC =(ReadData & 0x000F0000)>> 16;
    Header->BRS =(ReadData & 0x00100000)>>20;
    Header->FDF =(ReadData & 0x00200000)>> 21;
    Header->FIDX =(ReadData & 0x7F000000)>> 24;
    Header->ANMF =(ReadData & 0x8000000)>> 31;

    //获取实际数据
    //如果标头的数据有效载荷大小小于我们可以存储的最大值,则更新新元素大小以只读我们需要的内容(防止意外溢出读取)
    IF (TCAN4x5x_MCAN_DLCToBytes(THEADER->DLC)<元件大小)
    ElementSize = TCAN4x5x_MCAN_DLCToBytes(头->DLC);//返回数据字节的数量

    //在 MRAM 的数据有效负载区域,为所需的数据字节数开始连读
    //下面的方程式确保我们将始终读取正确的单词数,因为除法将截断任何余数,我们需要一个 ceil()类似的函数
    如果(元素大小> 0)为{
    AHB_READ_爆破_START (起始地址+8,(元素大小+3)>>2);
    I = 0;//用于计算我们已读取的字节数。
    同时(i <元素大小){
    如果((i % 4)= 0){
    ReadData = AHB_READ_爆破_READ();
    }

    dataPayload[i]=(uint8_t)(((ReadData >>((I % 4)* 8))和0xFF);
    I++;
    IF (I >元件尺寸)
    I =元件尺寸;
    }
    AHB_READ_爆破 结束();//终止连拍读取
    }
    //确认已读 FIFO
    开关(FIFOd精细)

    默认值:// RXFIFO
    AHB_WRITE _32 (REG_MCAN_RXF0A,getIndex);
    休息;

    盒装 RXFIFO:
    AHB_WRITE _32 (REG_MCAN_RXF1A,getIndex);
    休息;
    }


    返回 i;//返回检索的字节数
    }


    /**
    *@简要阅读指定的 RX 缓冲区元素
    *
    *此函数将读取指定的 MCAN 缓冲区元素并返回相应的标题信息和数据有效负载。
    *自动计算元素的起始地址。
    *
    *@param bufIndex 是要读取的 RX 缓冲区索引(从0开始)
    *@param *标头是指向包含 CAN 特定标头信息的@c TCAN4x5x_MCAN_RX_Header 结构的指针
    *@param dataPayload[]是一个字节数组,将使用读取数据进行更新
    *
    *@警告@c dataPayload[]必须至少与最大的数据有效负载一样大,否则可能会写入到超出界限的内存
    *
    *@返回从 TCAN4x5x 读取并存储到@c 数据有效负载的字节数[]
    *
    UINT8_t.
    TCAN4x5x_MCAN_ReadRXBuffer (uint8_t bufIndex,TCAN4x5x_MCAN_RX_Header *标头,uint8_t 数据有效负载[])

    UINT32_t 读数据;
    UINT16_t startAddress;
    UINT8_t I=0,getIndex,元件尺寸;

    //获取 get 缓冲区的位置和大小
    getIndex = bufIndex;
    如果(getIndex > 64)
    getIndex =64;

    //获取 RX 缓冲区开始位置和大小...
    #ifdef TCAN4x5x_MCAN_Cache_configuration
    ReadData = TCAN4x5x_MCAN_Cache[TCAN4x5x_MCAN_Cache_RXBC];
    #else
    ReadData = AHB_READ_32 (REG_MCAN_RXBC);
    #endif
    startAddress =(uint16_t)(ReadData 和0x0000FFFF)+ REG_MRAM;
    #ifdef TCAN4x5x_MCAN_Cache_configuration
    ReadData = TCAN4x5x_MCAN_Cache[TCAN4x5x_MCAN_Cache_RXESC];
    #else
    ReadData = AHB_READ_32 (REG_MCAN_RXESC);
    #endif
    ReadData =(ReadData 和0x0700)>> 8;
    ElementSize = TCAN4x5x_MCAN_TXRXESC_DataByteValue(ReadData);//此 MCAN 配置支持的最大理论数据有效负载
    //计算最新索引的实际起始地址
    startAddress >=((((UINT32_t) elementSize + 8)* getIndex);

    //读取数据,从突发读取开始
    AHB_READ_爆破_START (起始地址,2);
    ReadData = AHB_READ_爆破_READ();//第一个报头
    Header->ESI =(ReadData & 0x8000000)>> 31;
    HEAD-> XTD =(ReadData 和0x40000000)>> 30;
    Header->RTR =(ReadData & 0x20000000)>> 29;

    IF (信头->XTD)
    Header->ID =(ReadData 和0xFFFFFFF);
    否则
    Header->ID =(ReadData & 0x1FFC0000)>> 18;

    ReadData = AHB_READ_爆破_READ();//第二个报头
    AHB_READ_爆破 结束();//终止连拍读取
    HEAD-> RXTS =(ReadData 和0x0000FFFF);
    Header->DLC =(ReadData & 0x000F0000)>> 16;
    Header->BRS =(ReadData & 0x00100000)>>20;
    Header->FDF =(ReadData & 0x00200000)>> 21;
    Header->FIDX =(ReadData & 0x7F000000)>> 24;
    Header->ANMF =(ReadData & 0x8000000)>> 31;

    //获取实际数据
    //如果标题的数据有效载荷大小小于我们可以存储的最大值,则更新新元素大小以只读我们需要的内容(防止意外溢出读取)
    IF (TCAN4x5x_MCAN_DLCToBytes(THEADER->DLC)<元件大小)
    ElementSize = TCAN4x5x_MCAN_DLCToBytes(头->DLC);//返回数据字节的数量

    //在 MRAM 的数据有效负载区域,为所需的数据字节数开始连读
    //下面的方程式确保我们将始终读取正确的单词数,因为除法将截断任何余数,我们需要一个 ceil()类似的函数
    如果(元素大小> 0)为{
    AHB_READ_爆破_START (起始地址+8,(元素大小+3)>>2);
    I = 0;//用于计算我们已读取的字节数。
    同时(i <元素大小){
    如果((i % 4)= 0){
    ReadData = AHB_READ_爆破_READ();
    }

    dataPayload[i]=(uint8_t)(((ReadData >>((I % 4)* 8))和0xFF);
    I++;
    IF (I >元件尺寸)
    I =元件尺寸;
    }
    AHB_READ_爆破 结束();//终止连拍读取
    }
    //确认已读 FIFO
    IF (getIndex <32)

    AHB_WRTE_32 (REG_MCAN_NDAT1,1 << getIndex);
    }否则{
    AHB_WRTE_32 (REG_MCAN_NDAT2,1 <<(getIndex-32));
    }


    返回 i;//返回检索的字节数
    }


    /**
    *@向指定的 TX 缓冲区写入 CAN 短消息
    *
    *此函数将向指定的 TX 缓冲区写入 CAN 消息,稍后可使用@c TCAN4x5x_MCAN_TransmitBufferContents()函数传输该消息
    *
    *@param bufIndex 是要写入的 TX 缓冲区索引(从0开始)
    *@param *标头是指向包含 CAN 特定标头信息的@c TCAN4x5x_MCAN_TX_Header 结构的指针
    *@param dataPayload[]是一个包含数据有效负载的字节数组
    *
    *@警告@c dataPayload[]必须至少与@c *标题结构内指定的 DLC 大小相同
    *
    *@返回从 TCAN4x5x 读取并存储到@c 数据有效负载的字节数[]
    *
    UINT32_t.
    TCAN4x5x_MCAN_WriteTXBuffer (uint8_t bufIndex,TCAN4x5x_MCAN_TX_Header *报头,uint8_t 数据有效负载[])

    //步骤1:获取的起始地址
    UINT32_t SPIData;
    UINT16_t startAddress;
    UINT8_t I,元件尺寸,温度;


    //获取 TX Start 的位置和大小...
    #ifdef TCAN4x5x_MCAN_Cache_configuration
    SPIData = TCAN4x5x_MCAN_Cache[TCAN4x5x_MCAN_Cache_TXBC];
    #else
    SPIData = AHB_READ_32 (REG_MCAN_TXBC);
    #endif
    startAddress =(uint16_t)(SPIData 和0x0000FFFF)+ 0x8000;
    //传输 FIFO 和队列编号
    临时=(uint8_t)((SPIData >>24)和0x3F);
    元件尺寸=温度>32? 32:温度;
    //专用传输缓冲区
    临时=(uint8_t)((SPIData >=16)和0x3F);
    元件尺寸+=温度>32? 32:温度;

    如果(bufIndex >(元素大小-1))为{
    返回0;
    }

    //获取每个 TX 元素的实际元素大小
    #ifdef TCAN4x5x_MCAN_Cache_configuration
    SPIData = TCAN4x5x_MCAN_Cache[TCAN4x5x_MCAN_Cache_TXESC];
    #else
    SPIData = AHB_READ_32 (REG_MCAN_TXESC);
    #endif
    元件尺寸= TCAN4x5x_MCAN_TXRXESC_DataByteValue (SPIData & 0x07)+ 8;

    //计算最新索引的实际起始地址
    startAddress ==((UINT32_t) elementSize * bufIndex);

    //现在,我们需要实际检查我们正在写入的数据量(因为如果我们发送的是8字节 CAN 数据包,我们不需要填充64字节 FIFO)
    元素大小=(TCAN4x5x_MCAN_DLCToBytes(Header->DLC & 0x0F)+8)>2;//将其转换为单词,以便除以4进行更轻松的读取,并且只查看数据有效负载
    如果(TCAN4x5x_MCAN_DLCToBytes (header->DLC & 0x0F)% 4){//如果我们没有完整的数据字值... 我们需要向上舍入到最接近的单词(默认情况下它会截断)。 只需添加另一个词即可完成。
    元件尺寸+= 1;
    }
    //读取数据,从突发读取开始
    AHB_write_burn_start (startAddress,elementSize);
    SPIData = 0;

    SPIData |=((UINT32_t)标头->ESI & 0x01)<< 31;
    SPIData |=((UINT32_t)标题->XTD & 0x01)<<30;
    SPIData |=((UINT32_t)标题->RTR & 0x01)<<29;

    IF (信头->XTD)
    SPIData |=((UINT32_t)标题->ID & 0xFFFFFFF);
    否则
    SPIData |=((UINT32_t)标头->ID & 0x07FF)<<18;

    AHB_write_burn_write (SPIData);

    SPIData = 0;
    SPIData |=((UINT32_t)标题->DLC 和0x0F)<<16;
    SPIData |=((UINT32_t)标题->BRS & 0x01)<<20;
    SPIData |=((UINT32_t)标题->FDF & 0x01)<<21;
    SPIData |=((UINT32_t)标题->EFC & 0x01)<<23;
    SPIData |=((UINT32_t)标题->MM & 0xFF)<<24;
    AHB_write_burn_write (SPIData);

    //获取实际数据
    ElementSize = TCAN4x5x_MCAN_DLCToBytes(标头->DLC & 0x0F);//返回数据字节的数量
    I = 0;//用于计算我们已读取的字节数。
    同时(i <元素大小){
    SPIData = 0;
    //如果 elementSize - i < 4,则这意味着我们使用的是最后一个单词,单词长度小于4字节
    如果((元件尺寸- I)< 4){
    同时(i <元素大小)

    SPIData ||((UINT32_t) dataPayload[i]<<(I % 4)* 8);
    I++;
    }

    AHB_write_burn_write (SPIData);
    }否则{
    SPIData |=((UINT32_t) dataPayload[I++]);
    SPIData ||((UINT32_t) dataPayload[I++])<< 8;
    SPIData |=((UINT32_t) dataPayload[I++)<16;
    SPIData ||((UINT32_t) dataPayload[I++])<< 24;

    AHB_write_burn_write (SPIData);
    }

    IF (I >元件尺寸)
    I =元件尺寸;
    }
    AHB_write_burn_end();//终止连拍读取

    return (UINT32_t)1<< bufIndex;//返回检索到的字节数
    }


    /**
    *@指定 TX 缓冲区的发射 TX 缓冲区内容简介
    *
    *将指定的缓冲区索引位值写入 TXBAR 寄存器以请求发送消息
    *
    *@param bufIndex 是要写入的 TX 缓冲区索引(从0开始)
    *
    *@警告功能不检查缓冲区内容是否有效
    *
    *@如果请求排队,返回@c true;如果缓冲区值无效(超出范围),返回@c false
    *
    布尔
    TCAN4x5x_MCAN_TransmitBufferContents (uint8_t bufIndex)

    UINT32_t writeValue;
    UINT8_t 要求 Buf = bufIndex;

    如果(被要求购买的产品> 31)
    返回 false;

    writeValue =1 <<重新认证的 Buf;

    AHB_WRITE _32 (REG_MCAN_TXBAR,writeValue);
    返回 true;
    }


    /**
    *@将 MCAN 标准 ID 筛选器简单写入 MRAM
    *
    *此功能将向指定的滤芯写入标准 ID MCAN 滤波器
    *
    *@param filterIndex 是 MRAM 中要写入的 SID 筛选器索引(从0开始)
    *@param *过滤器是指向包含 MCAN 过滤器信息的@c TCAN4x5x_MCAN_SID_Filter 结构的指针
    *
    *@如果写入成功,则返回@c true;如果不成功,则返回@c false
    *
    布尔
    TCAN4x5x_MCAN_WriteSID 过滤器(uint8_t 过滤器索引,TCAN4x5x_MCAN_SID_Filter *过滤器)

    UINT32_t 读数据;
    UINT16_t startAddress;
    UINT8_t getIndex;
    #ifdef TCAN4x5x_MCAN_Cache_configuration
    ReadData = TCAN4x5x_MCAN_Cache[TCAN4x5x_MCAN_Cache_SIDFC];
    #else
    ReadData = AHB_READ_32 (REG_MCAN_SIDFC);
    #endif
    getIndex =(ReadData 和0x00FF0000)>> 16;
    如果(filterIndex > getIndex)//检查五分制数字是否有效且在范围内。 如果没有,则失败
    返回 false;
    否则
    getIndex =文件索引;

    startAddress =(uint16_t)(ReadData 和0x0000FFFF)+ REG_MRAM;
    //计算最新索引的实际起始地址
    startAddress +=(getIndex <<<2);//乘以4并添加到起始地址

    AHB_WRITE _32 (startAddress,filter->word);//将值写入寄存器
    #ifdef TCAN4x5x_device_verify_configuration_writes
    //验证写入是否成功
    ReadData = AHB_READ_32 (startAddress);
    IF (ReadData!=过滤器->单词)
    返回 false;
    #endif
    返回 true;
    }


    /**
    *@简要阅读 MRAM 中的 MCAN 标准 ID 筛选器
    *
    *此功能将从指定的滤芯读取标准 ID MCAN 滤波器
    *
    *@param filterIndex 是 MRAM 中要读取的 SID 筛选器索引(从0开始)
    *@param *过滤器是指向将使用读取 MCAN 过滤器更新的@c TCAN4x5x_MCAN_SID_Filter 结构的指针
    *
    *@如果读取成功则返回@c true,如果不成功则返回@c false
    *
    布尔
    TCAN4x5x_MCAN_ReadSID 过滤器(uint8_t 过滤器索引,TCAN4x5x_MCAN_SID_Filter *过滤器)

    UINT32_t 读数据;
    UINT16_t startAddress;
    UINT8_t getIndex;
    #ifdef TCAN4x5x_MCAN_Cache_configuration
    ReadData = TCAN4x5x_MCAN_Cache[TCAN4x5x_MCAN_Cache_SIDFC];
    #else
    ReadData = AHB_READ_32 (REG_MCAN_SIDFC);
    #endif
    getIndex =(ReadData 和0x00FF0000)>> 16;
    如果(filterIndex > getIndex)//检查五分制数字是否有效且在范围内。 如果没有,则失败
    返回 false;
    否则
    getIndex =文件索引;

    startAddress =(uint16_t)(ReadData 和0x0000FFFF)+ REG_MRAM;
    //计算最新索引的实际起始地址
    startAddress +=(getIndex <<<2);//乘以4并添加到起始地址

    filter->word = AHB_READ_32(startAddress);//从 MRAM 中读取值
    返回 true;
    }


    /**
    *@将 MCAN 扩展 ID 筛选器简单写入 MRAM
    *
    *此功能将向指定的滤芯写入扩展 ID MCAN 滤波器
    *
    *@参数索引是 MRAM 中要写入的 XID 筛选器索引(从0开始)
    *@param *过滤器是指向包含 MCAN 过滤器信息的@c TCAN4x5x_MCAN_XID_Filter 结构的指针
    *
    *@如果写入成功,则返回@c true;如果不成功,则返回@c false
    *
    布尔
    TCAN4x5x_MCAN_WriteXIDFilter (uint8_t 文件索引,TCAN4x5x_MCAN_XID_Filter *过滤器)

    UINT32_t ReadData,writeData;
    UINT16_t startAddress;
    UINT8_t getIndex;
    #ifdef TCAN4x5x_MCAN_Cache_configuration
    ReadData = TCAN4x5x_MCAN_Cache[TCAN4x5x_MCAN_Cache_XIDFC];
    #else
    ReadData = AHB_READ_32 (REG_MCAN_XIDFC);
    #endif
    getIndex =(ReadData 和0x00FF0000)>> 16;
    如果(filterIndex > getIndex)//检查五分制数字是否有效且在范围内。 如果没有,则失败
    返回 false;
    否则
    getIndex =文件索引;

    startAddress =(uint16_t)(ReadData 和0x0000FFFF)+ REG_MRAM;
    //计算最新索引的实际起始地址
    startAddress +=(getIndex <<<3);//乘以4并添加到起始地址

    //将这两个词写在内存中
    writeData =(UINT32_t)(过滤器->EFEC)<<29;
    writeData |=(UINT32_t)(过滤器->EFID1);
    AHB_write_32 (startAddress,writeData);//将值写入寄存器
    #ifdef TCAN4x5x_device_verify_configuration_writes
    ReadData = AHB_READ_32 (startAddress);
    IF (ReadData!= writeData)
    返回 false;
    #endif

    startAddress +=4;
    writeData =(UINT32_t)(过滤器->EFT)<<30;
    writeData |=(UINT32_t)(过滤器->EFID2);
    AHB_write_32 (startAddress,writeData);//将值写入寄存器
    #ifdef TCAN4x5x_device_verify_configuration_writes
    ReadData = AHB_READ_32 (startAddress);
    IF (ReadData!= writeData)
    返回 false;
    #endif

    返回 true;
    }


    /**
    *@简要阅读 MRAM 中的 MCAN 扩展 ID 筛选器
    *
    *此功能将从指定的滤芯读取扩展 ID MCAN 滤波器
    *
    *@参数索引是 MRAM 中要读取的 XID 筛选器索引(从0开始)
    *@param *过滤器是一个指向@c TCAN4x5x_MCAN_XID_Filter 结构的指针,该结构将使用来自 MRAM 的信息进行更新
    *
    *@如果读取成功则返回@c true,如果不成功则返回@c false
    *
    布尔
    TCAN4x5x_MCAN_ReadXIDFilter (uint8_t 文件索引,TCAN4x5x_MCAN_XID_Filter *过滤器)

    UINT32_t 读数据;
    UINT16_t startAddress;
    UINT8_t getIndex;
    #ifdef TCAN4x5x_MCAN_Cache_configuration
    ReadData = TCAN4x5x_MCAN_Cache[TCAN4x5x_MCAN_Cache_XIDFC];
    #else
    ReadData = AHB_READ_32 (REG_MCAN_XIDFC);
    #endif
    getIndex =(ReadData 和0x00FF0000)>> 16;
    如果(filterIndex > getIndex)//检查五分制数字是否有效且在范围内。 如果没有,则失败
    返回 false;
    否则
    getIndex =文件索引;

    startAddress =(uint16_t)(ReadData 和0x0000FFFF)+ REG_MRAM;
    //计算最新索引的实际起始地址
    startAddress +=(getIndex <<<3);//乘以4并添加到起始地址

    AHB_READ_爆破_START (起始地址,2);//发送 SPI 标头,用于连续读取2个单词的 SPI
    ReadData = AHB_READ_爆破_READ();//从 MRAM 读取第一个单词

    FILTER->EFEC =(TCAN4x5x_XID_EFEC_VALUES)(((ReadData >> 29)& 0x07);
    FILTER->EFID1 = ReadData & 0x1FFFFFFF;

    ReadData = AHB_READ_爆破_READ();//从 MRAM 读取第二个单词
    AHB_READ_爆破 结束();//终止 SPI 事务
    FILTER->EFT =(TCAN4x5x_XID_EFT_VALUES)(((ReadData >> 30)和0x03);
    FILTER->EFID2 = ReadData & 0x1FFFFFFF;

    返回 true;
    }


    /**
    *@简要阅读 MCAN 中断
    *
    *读取 MCAN 中断并更新传递给函数的@c TCAN4x5x_MCAN_interrupts 结构
    *
    *@param *ir 是指向包含将要更新的中断位字段的@c TCAN4x5x_MCAN_Interrupts 结构的指针
    *
    无效
    TCAN4x5x_MCAN_ReadInterrupts (TCAN4x5x_MCAN_Interrupts *ir)

    IR->Word = AHB_READ_32 (REG_MCAN_IR);
    }


    /**
    *@简要清除 MCAN 中断
    *
    *将尝试清除@c TCAN4x5x_MCAN_Interrupts 结构中标记为'1'的任何中断
    *
    *@param *ir 是指向包含将要更新的中断位字段的@c TCAN4x5x_MCAN_Interrupts 结构的指针
    *
    无效
    TCAN4x5x_MCAN_ClearInterrupts (TCAN4x5x_MCAN_Interrupts *ir)

    AHB_WRITE _32 (REG_MCAN_IR,ir->单词);
    }


    /**
    *@简要清除所有 MCAN 中断
    *
    *清除所有 MCAN 中断
    *
    无效
    TCAN4x5x_MCAN_ClearInterruptsAll (void)(TCAN4x5x_MCAN_ClearInterruptsAll [无效

    AHB_WRITE _32 (REG_MCAN_IR,0xFFFFFFFF);
    }


    /**
    *@简要阅读 MCAN 中断启用寄存器
    *
    *读取 MCAN 中断启用寄存器并更新通过的@c TCAN4x5x_MCAN_Interrupt _Enable 结构
    *
    *@param * ie 是指向包含将要更新的中断位字段的@c TCAN4x5x_MCAN_Interrupt _Enable 结构的指针
    *
    无效
    TCAN4x5x_MCAN_ReadInterruptEnable (TCAN4x5x_MCAN_Interrupt 启用*)

    IE->Word = AHB_READ_32 (REG_MCAN_IE);
    }


    /**
    *@简介配置 MCAN 中断启用寄存器
    *
    *根据传递的@c TCAN4x5x_MCAN_Interrupt _Enable 结构配置 MCAN 中断启用寄存器
    *还启用 MCAN 中断至 INT1引脚。
    *
    *@param *ie 是指向包含所需的已启用中断位的@c TCAN4x5x_MCAN_Interrupt _Enable 结构的指针
    *
    无效
    TCAN4x5x_MCAN_ConfigureInterruptEnable (TCAN4x5x_MCAN_Interrupt 启用*)

    AHB_WRITE _32 (REG_MCAN_IE,i->单词);
    AHB_WRITE _32 (REG_MCAN_Ile,REG_BITS_MCAN_Ile_EINT0);//这是启用 MCAN Int mux 到输出 nINT 引脚所必需的
    }


    /**
    *@简述将 CAN 消息 DLC 十六进制值转换为对应的字节数
    *
    *@param inputDLC 是 CAN 消息结构的发件人/发件人的 DLC 值
    *@返回数据的字节数(0-64字节)
    *
    UINT8_t.
    TCAN4x5x_MCAN_DLCToBytes(uint8_t InputDLC)

    静态 const uint8_t lookup[7]={12,16,20,24,32, 48,64};

    IF (输入 DLC < 9)
    回车输入 DLC;

    IF (输入 DLC < 16)
    return lookup[(unsigned int)(inputdlc-9)];

    返回0;

    }


    /**
    *@简述将 MCAN ESC (元素大小)值转换为其对应的字节数
    *
    *@param inputESCValue 是元素大小配置寄存器的值
    *@返回数据的字节数(8-64字节)
    *
    UINT8_t.
    TCAN4x5x_MCAN_TXRXESC_DataByteValue (uint8_t InputESValue)

    静态 const uint8_t lookup[8]={8,12,16,20,24, 32,48,64};
    return lookup[(unsigned int)(inputESValue & 0x07);
    }

    /* *
    *设备启动(非 MCAN)功能*
    ************* *

    /**
    *@简介阅读 TCAN4x5x 设备版本寄存器
    *
    *@返回设备版本寄存器的寄存器值
    *
    UINT16_t.
    TCAN4x5x_Device_ReadDevice 版本(void)

    UINT32_t readValue;

    readValue = AHB_READ_32 (REG_SPI_REVISION);

    返回(uint16_t)( readValue & 0xffff);
    }


    /**
    *@简介配置设备模式和引脚寄存器
    *
    *根据传递的@c TCAN4x5x_dev_config 结构配置设备模式和引脚寄存器,但会屏蔽写入中的保留位
    *
    *@param *设备配置是指向包含所需设备模式和引脚寄存器值的@c TCAN4x5x_dev_config 结构的指针
    *
    *@如果配置成功完成,则返回@c true;如果未成功完成,则返回@c false
    *
    布尔
    TCAN4x5x_Device_Configure (TCAN4x5x_dev_config *设备配置)

    //首先,我们必须阅读注册表
    UINT32_t 读设备= AHB_READ_32 (REG_DEP_MODES_AND_PINS);

    //然后掩码将由结构设置的位
    readDevice &=~(REG_BITS_DEVICE_MODE_SWE_MASK | REG_BITS_DEVICE_MODE_DEVICE_RESET | REG_BITS_DEVICE_MODE_WDT_MASK |
    REG_BITS_DEVICE_MODE_NWKRQ_CONFIG_MASK | REG_BITS_DEVICE_MODE_INH_MASK | REG_BITS_DEVICE_MODE_GPO1_FUNC_MASK |
    reg_bits_device_mode_fail_safe_mask | REG_bits_device_mode_GPO1_mode_mask | REG_bits_device_mode_WDT_action_mask |
    reg_bits_device_mode_WDT_reset_bit | REG_bits_device_mode_NWKRQ_vol_mask | REG_bits_device_mode_TESTMODE_ENMASK |
    reg_bits_device_mode_GPO2_mask | REG_bits_device_mode_WD_CLK_mask | REG_bits_device_mode_wak_PIN_mask);

    //复制到内存中的临时位置,因此我们不修改传入的结构
    TCAN4x5x_dev_config tempcfg;
    tempcfg.word = devcfg->word;

    //清除保留的标志。
    tempcfg.RESERVED0 = 0;
    tempcfg.RESERVED1 = 0;
    tempcfg.RESERVED2 = 0;
    tempcfg.RESERVED3 = 0;
    tempcfg.RESERVED4 = 0;
    tempcfg.RESERVED5 = 0;


    //根据传入结构设置位
    readDevice |=(REG_bits_device_mode_Forced_set_bits | tempcfg.word);

    AHB_WRITE _32 (REG_DEP_MODES_AND_PINS,readDevice);

    #ifdef TCAN4x5x_device_verify_configuration_writes
    //检查写入是否成功。
    UINT32_t readValue = AHB_READ_32 (REG_DEP_MODES_AND_PINS);//读取值
    IF (readValue != readDevice)
    返回 false;
    #endif
    返回 true;
    }


    /**
    *@简介可读取设备模式和引脚寄存器
    *
    *读取设备模式和引脚寄存器,并更新传递的@c TCAN4x5x_dev_config 结构
    *
    *@param *设备配置是指向要使用当前模式和引脚寄存器值更新的@c TCAN4x5x_dev_config 结构的指针
    *
    无效
    TCAN4x5x_Device_ReadConfig (TCAN4x5x_dev_config *设备配置)

    devcfg->word = AHB_READ_32 (REG_DEP_MODES_AND_PINS);
    }


    /**
    *@简要阅读设备中断
    *
    *读取设备中断并更新传递给函数的@c TCAN4x5x_Device_Interrupts 结构
    *
    *@param *ir 是指向包含将要更新的中断位字段的@c TCAN4x5x_Device_Interrupts 结构的指针
    *
    无效
    TCAN4x5x_Device_ReadInterrupts (TCAN4x5x_Device_Interrupts *ir)

    IR->Word = AHB_READ_32 (REG_DEP_IR);

    }


    /**
    *@简要清除设备中断
    *
    *将尝试清除@c TCAN4x5x_Device_Interrupts 结构中标记为'1'的任何中断
    *
    *@param *ir 是指向包含将要更新的中断位字段的@c TCAN4x5x_Device_Interrupts 结构的指针
    *
    无效
    TCAN4x5x_Device_ClearInterrupts (TCAN4x5x_Device_Interrupts *ir)

    AHB_WRITE _32 (REG_DEV_IR,IR->Word);
    //printmsg("IR %x",ir->单词);
    }


    /**
    *@简要清除所有设备中断
    *
    *清除所有设备中断
    *
    无效
    TCAN4x5x_Device_ClearInterruptsAll (void)(TCAN4x5x_Device_ClearInterruptsAll [无效

    AHB_WRITE _32 (REG_DEP_IR,0xFFFFFFFF);
    }


    /**
    *@简述会清除可能设置的 SPIERR 标志
    *
    无效
    TCAN4x5x_Device_ClearSPIERR (无效)

    AHB_WRITE _32 (REG_SPI_STATUS,0xFFFFFFFF);//只需编写所有1份,尝试清除已设置的 SPIERR
    }


    /**
    *@简要阅读设备中断启用寄存器
    *
    *读取设备中断启用寄存器并更新通过的@c TCAN4x5x_Device_Interrupt _Enable 结构
    *
    *@param *ie 是指向包含将要更新的中断位字段的@c TCAN4x5x_Device_Interrupt 的结构的指针
    *
    无效
    TCAN4x5x_Device_ReadInterruptEnable (TCAN4x5x_Device_Interrupt 启用*)

    IE->Word = AHB_READ_32 (REG_DEP_IE);
    }


    /**
    *@简述配置设备中断启用寄存器
    *
    *根据传递的@c TCAN4x5x_Device_Interrupt _Enable 结构配置设备中断启用寄存器
    *
    *@param *ie 是指向包含所需的已启用中断位的@c TCAN4x5x_Device_Interrupt 的结构的指针
    *
    *@如果配置成功完成,则返回@c true;如果未成功完成,则返回@c false
    *
    布尔
    TCAN4x5x_Device_ConfigureInterruptEnable (TCAN4x5x_Device_Interrupt 启用*)

    AHB_WRITE _32 (REG_DEP_IE,i->单词);
    #ifdef TCAN4x5x_device_verify_configuration_writes
    //检查写入是否成功。
    UINT32_t readValue = AHB_READ_32 (REG_DEP_IE);//读取值
    readValue &= REG_BITS_DEVICE_IE_MASK;//应用掩码忽略保留
    IF (readValue !=(ie-> word & REG_bits_device_IE_mask))
    返回 false;
    #endif
    返回 true;
    }


    /**
    *@简介设置 TCAN4x5x 设备模式
    *
    *根据输入@c modeDefine enum 设置 TCAN4x5x 设备模式
    *
    *@param modeDefine 是@c TCAN4x5x_Device_Mode_Enum enum
    *
    *@如果配置成功完成,则返回@c true;如果未成功完成,则返回@c false
    *
    布尔
    TCAN4x5x_Device_SetMode (TCAN4x5x_Device_Mode_Enum 模式指定)

    UINT32_t writeValue =(AHB_READ_32 (REG_DEP_MOS_AND_Pins)&~REG_BITS_DEVICEMODE_Mask);

    开关(模式降档){
    案例 TCAN4x5x_device_mode_normal:
    writeValue |= REG_BITS_DEVICE_MODE_NORMAL;
    休息;

    案例 TCAN4x5x_device_mode_sleep:
    writeValue |= REG_bits_device_mode_DEVICEMODE_SLEEP;
    休息;

    案例 TCAN4x5x_device_mode_standby:
    writeValue |= REG_bits_device_mode_DEVICEMODE_STANDBY;
    休息;

    默认值:
    返回 false;
    }

    AHB_WRITE _32 (REG_DEP_MODES_AND_PINS,writeValue);

    #ifdef TCAN4x5x_device_verify_configuration_writes
    //检查写入是否成功。
    writeValue &= REG_bits_device_mode_DEVICEMODE_MASK;//掩码我们关心验证的部分
    如果((AHB_READ_32 (REG_DEP_MOes_and_Pins)和 REG_BITS_DEVICEMODE_MASK)!= writeValue)
    返回 false;
    #endif
    返回 true;
    }


    /**
    *@简介可读取 TCAN4x5x 设备模式
    *
    *读取 TCAN4x5x 设备模式并返回@c modeDefine 枚举
    *
    *@返回当前状态的@c TCAN4x5x_Device_Mode_Enum 枚举
    *
    TCAN4x5x_Device_Mode_Enum
    TCAN4x5x_Device_ReadMode (void)

    UINT32_t readValue =(AHB_READ_32 (REG_DEP_MOS_AND_PINS)和 REG_BITS_DEVICEMODE_MASK);

    开关(readValue){
    大小写 REG_BITS_DEVICE_MODE_NORMAL:
    返回 TCAN4x5x_DEVICE_MODE_NORMAL;

    案例 REG_BITS_DEVICE_MODE_SLEEP:
    返回 TCAN4x5x_DEVICE_MODE_SLEEP;

    案例 REG_BITS_DEVICE_MODE_STANDBY:
    返回 TCAN4x5x_DEVICE_MODE_STANDBY;

    默认值:
    返回 TCAN4x5x_DEVICE_MODE_STANDBY;
    }
    }


    /**
    *@简介设置 TCAN4x5x 设备测试模式
    *
    *根据输入@c modeDefine enum 设置 TCAN4x5x 设备测试模式
    *
    *@param modeDefine 是@c TCAN4x5x_Device_Test_Mode_Enum enum
    *
    *@如果配置成功完成,则返回@c true;如果未成功完成,则返回@c false
    *
    布尔
    TCAN4x5x_Device_EnableTestMode (TCAN4x5x_Device_Test_Mode_Enum 模式诊断)

    UINT32_t readWriteValue = AHB_READ_32 (REG_DEP_MOes_and_Pins);
    readWriteValue &=~REG_bits_device_mode_TESTMODE_mask;//清除我们正在设置的位

    //根据传入的值设置适当的位
    开关(模式降档)

    案例 TCAN4x5x_device_test_mode_normal:
    TCAN4x5x_Device_DisableTestMode();
    休息;

    盒装 TCAN4x5x_device_test_mode_controller:
    readWriteValue |= REG_BITS_DEVICE_MODE_CONTROLLER | REG_BITS_DEVICE_MODE_EN;
    休息;

    案例 TCAN4x5x_device_test_mode_PHY:
    readWriteValue |= REG_BITS_DEVICE_MODE_PHY | REG_BITS_DEVICE_MODE_EN;
    休息;

    默认值:返回 false;//如果传递了无效值,则返回 Fail
    }
    AHB_WRITE _32 (REG_DEP_MODES_AND_PINS,readWriteValue);//写入更新的值

    #ifdef TCAN4x5x_device_verify_configuration_writes
    //检查写入是否成功。
    IF (AHB_READ_32 (REG_DEP_MODE_AND_PINS)!= readWriteValue)
    返回 false;
    #endif
    返回 true;
    }


    /**
    *@简述禁用 TCAN4x5x 设备测试模式
    *
    *@如果禁用测试模式成功,则返回@c true;如果失败,则返回@c false
    *
    布尔
    TCAN4x5x_Device_DisableTestMode (void)

    UINT32_t readWriteValue = AHB_READ_32 (REG_DEP_MOes_and_Pins);
    readWriteValue &=~(REG_bits_device_mode_TESTMODE_mask | REG_bits_device_mode_TESTMODE_ENMASK);//清除位
    AHB_WRITE _32 (REG_DEP_MODES_AND_PINS,readWriteValue);//写入更新的值

    #ifdef TCAN4x5x_device_verify_configuration_writes
    //检查写入是否成功。
    IF (AHB_READ_32 (REG_DEP_MODE_AND_PINS)!= readWriteValue)
    返回 false;
    #endif
    返回 true;
    }


    /**
    *@简介可读取 TCAN4x5x 设备测试模式
    *
    *@返回当前设备测试模式的@c TCAN4x5x_Device_Test_Mode_Enum
    *
    TCAN4x5x_Device_Test_Mode_Enum
    TCAN4x5x_Device_ReadTestMode (void)

    UINT32_t readValue = AHB_READ_32 (REG_DEP_MODES_AND_PINS);

    //如果测试模式已启用...
    IF (readValue 和 REG_bits_device_mode_TESTMODE_ENMASK)

    IF (readValue 和 REG_BITS_DEVICE_MODE_CONTROLLER)

    返回 TCAN4x5x_device_test_mode_controller;
    }否则{
    返回 TCAN4x5x_device_test_mode_PHY;
    }
    }
    返回 TCAN4x5x_device_test_mode_normal;
    }


    /**
    *@简介配置监视程序
    *
    *@param WDTtimeout 是监视狗窗口不同时间的@c TCAN4x5x_WDT_Timer_Enum 枚举
    *
    *@如果配置成功,则返回@c true,否则返回@c false
    *
    布尔
    TCAN4x5x_WDT_Configure (TCAN4x5x_WDT_Timer_Enum WDTtimeout)

    UINT32_t readWriteValue = AHB_READ_32 (REG_DEP_MOes_and_Pins);
    readWriteValue &=~REG_BITS_DEVICE_MODE_WD_TIMER 掩码;//清除我们正在设置的位

    //根据传入的值设置适当的位
    交换机(WDTtimeout)

    盒装 TCAN4x5x_WDT_60ms:
    readWriteValue |= REG_BITS_DEVICE_MODE_WD_TIMEER_60ms;
    休息;

    案例 TCAN4x5x_WDT_600ms:
    readWriteValue |= REG_BITS_DEVICE_MODE_WD_TIMER 600ms;
    休息;

    案例 TCAN4x5x_WDT_3S:
    readWriteValue |= REG_BITS_DEVICE_MODE_WD_TIMEER_3S;
    休息;

    案例 TCAN4x5x_WDT_6S:
    readWriteValue |= REG_BITS_DEVICE_MODE_WD_TIMEER_6S;
    休息;

    默认值:返回 false;//如果传递了无效值,则返回 Fail
    }
    AHB_WRITE _32 (REG_DEP_MODES_AND_PINS,readWriteValue);//写入更新的值

    #ifdef TCAN4x5x_device_verify_configuration_writes
    //检查写入是否成功。
    IF (AHB_READ_32 (REG_DEP_MODE_AND_PINS)!= readWriteValue)
    返回 false;
    #endif
    返回 true;
    }


    /**
    *@简介阅读看门狗配置
    *
    *@返回当前配置时间窗口的@c TCAN4x5x_WDT_Timer_Enum 枚举
    *
    TCAN4x5x_WDT_Timer_Enum
    TCAN4x5x_WDT_READ (作废)

    UINT32_t readValue = AHB_READ_32 (REG_DEP_MODES_AND_PINS);
    readValue &= REG_BITS_DEVICE_MODE_WD_TIMER 掩码;

    开关(readValue)

    病例 REG_BITS_DEVICE_MODE_WD_TIMEER_60ms:
    返回 TCAN4x5x_WDT_60ms;

    病例 REG_BITS_DEVICE_MODE_WD_TIMEER_600ms:
    返回 TCAN4x5x_WDT_600ms;

    案例 REG_BITS_DEVICE_MODE_WD_TIMEER_3S:
    返回 TCAN4x5x_WDT_3S;

    案例 REG_BITS_DEVICE_MODE_WD_TIMEER_6S:
    返回 TCAN4x5x_WDT_6S;

    默认值:返回 TCAN4x5x_WDT_60ms;//如果传递了无效值,则我们将返回 POR 默认值
    }
    }


    /**
    *@简介启用看门狗计时器
    *
    *@如果成功启用则返回@c true,否则返回@c false
    *
    布尔
    TCAN4x5x_WDT_Enable (空)

    UINT32_t readWriteValue = AHB_READ_32 (REG_DEP_MOes_and_PINS)| REG_BITS_DEVICE_MODE_WDT_EN;
    AHB_WRITE _32 (REG_DEP_MODES_AND_PINS,readWriteValue);//启用监视狗计时器

    #ifdef TCAN4x5x_device_verify_configuration_writes
    //检查写入是否成功。
    IF (AHB_READ_32 (REG_DEP_MODE_AND_PINS)!= readWriteValue)
    返回 false;
    #endif

    返回 true;
    }


    /**
    *@简述禁用看门狗计时器
    *
    *@如果成功禁用则返回@c true,否则返回@c false
    *
    布尔
    TCAN4x5x_WDT_Disable (作废)

    UINT32_t writeValue = AHB_READ_32 (REG_DEP_MOes_and_Pins);
    writeValue &=~REG_BITS_DEVICE_MODE_WDT_EN;//清除 EN 位
    AHB_WRITE _32 (REG_DEP_MODES_AND_PINS,writeValue);//禁用监视狗计时器

    #ifdef TCAN4x5x_device_verify_configuration_writes
    //检查写入是否成功。
    IF (AHB_READ_32 (REG_DEP_MODE_AND_PINS)!= writeValue)
    返回 false;
    #endif
    返回 true;
    }


    /**
    *@简要重置看门狗计时器
    *
    无效
    TCAN4x5x_WDT_Reset (作废)

    UINT32_t writeValue = AHB_READ_32 (REG_DEP_MOes_and_Pins);
    writeValue |= REG_BITS_DEVICE_MODE_WDT_RESET_BIT;
    AHB_WRITE _32 (REG_DEP_MODES_AND_PINS,writeValue);//重置监视狗计时器
    }
    /*
    void CAN_Transmit _Helper (uint16_t ID,uint8_t *数据,uint8_t 大小){
    静态

    }*/

    void CAN_Transmit (uint16_t ID,uint8_t *数据,uint8_t 大小)

    静态 int 队列=0;

    addLog_CAN_data(((char*)数据,大小,ID,CAN_TX_LOG_buffer);
    TCAN4x5x_MCAN_TX_HEADER HEADER ={0};//记得初始化到0,否则会出现随机垃圾!
    HEADER.DLC =大小;//将 DLC 设置为等于或小于数据负载(如果您的 DLC 为8字节,则可以将64字节数据阵列传递到 WriteTXFIFO 函数中,但只能读取前8字节)
    header.ID = ID;//设置 ID
    HEADER.FDF = 1;// CAN FD 帧已启用
    HEADER.BRS = 1;//位速率开关已启用
    HEADER.EFC = 0;
    收割台.mm = 0;
    HEADER.RTR = 0;
    HEADER.XTD = 0;//本例中未使用扩展 ID
    HEADER.ESI = 0;//错误状态指示符


    TCAN4x5x_MCAN_WriteTXBuffer(队列,头,数据);//此函数实际上将头和数据有效负载写入 TCAN 的指定 TX 队列编号的 MRAM 中。 它返回写入 TXBAR 所需的位,
    //但不一定要求您使用它。 在本示例中,我们不会这样做,这样我们就可以在以后发送排队等候的数据。
    TCAN4x5x_MCAN_TransmitBufferContents (队列);//现在,我们可以发送我们之前排队但未发送的 TX FIFO 元素0数据。
    队列++;
    IF (队列=8)
    队列=0;

    }

    接收到无效 TCAN_DATA (无效)

    如果(TCAN_INT_Cnt > 0)


    TCAN_INT_Cnt--;
    TCAN4x5x_Device_Interrupts dev_ir ={0};//为设备(非 CAN)中断检查定义新的设备 IR 对象
    TCAN4x5x_MCAN_interrupts mCAN_ir ={0};//设置新的 MCAN IR 对象以方便中断检查
    TCAN4x5x_Device_ReadInterrupts (/dev/ir);//读取设备中断寄存器
    TCAN4x5x_MCAN_ReadInterrupts (&mCAN_ir);//读取中断寄存器

    如果(dev_ir.SPIERR)//设置了 SPIERR 标志
    TCAN4x5x_Device_ClearSPIERR();//清除 SPIERR 标志

    如果(mCAN_ir.RF0N)// RX FIFO 0中有新消息

    TCAN4x5x_MCAN_RX_Header MsgHeader ={0};//初始化为0,否则将产生垃圾
    UINT8_t numBytes =0;//自 ReadNextFIFO 函数以来使用,将返回读取的数据字节数
    UINT8_t dataPayload[64]={0};//用于存储收到的数据

    TCAN4x5x_MCAN_ClearInterrupts (&mCAN_ir);//清除设置的任何中断位。
    while (((AHB_READ_32 (0x10A4)&0xFF)>0){
    NumBytes = TCAN4x5x_MCAN_ReadNextFIFO (RXFIFO,&MsgHeader,dataPayload);//这将读取 RX FIFO 0中的下一个元素
    // printmsg("data %x\n", dataPayload[0]);
    // for (int i=1;i<=numBytes-1;i++){
    // printmsg("%x\n", dataPayload[I]);
    //}
    // printmsg("No of Char %x\n", numBytes);
    // numBytes 中将有其传输的字节数。 或者,您可以对 MsgHeader.dlc 中的 DLC 值进行解码
    //数据现在位于 dataPayload[]中,消息特定信息位于 MsgHeader 结构中。
    如果(MsgHeader.ID == unique ID_G)//示例,说明如何根据接收到的地址执行操作

    //做些什么
    CAN_dataRX_handler (dataPayload,numBytes,0);
    }
    否则,如果(MsgHeader.ID == global_ID_G){
    //printmsg (“全局命令”);
    CAN_dataRX_handler (dataPayload,numBytes,1);
    }
    }
    }

    }
    }


    无效 Init_can (uint16_t unique 标识,uint16_t global_ID)

    TCAN4x5x_Device_ClearSPIERR();//清除由于 MCU 启动期间 PIN mux 发生变化而可能设置的任何 SPI ERR 标志

    /*步骤一尝试清除所有中断*/
    TCAN4x5x_Device_Interrupt _Enable dev_ie ={0};//初始化为0至所有位均设置为0。
    TCAN4x5x_Device_ConfigureInterruptEnable(&DED_IE);//为了简单起见,禁用所有与 MCAN 无关的中断

    TCAN4x5x_Device_Interrupts dev_ir ={0};//设置新的 MCAN IR 对象以方便中断检查
    TCAN4x5x_Device_ReadInterrupts (/dev/ir);//请求使用当前设备(非 MCAN)中断值更新结构

    //printmsg("PWRON %x",dev_ir.PWRON);

    如果(dev_ir.PWRON)//设置了“启动中断”标志
    TCAN4x5x_Device_ClearInterrupts (/dev/ir);//清除它是因为如果它在~4分钟内未被清除,它将进入睡眠状态

    /*配置 CAN 总线速度*/
    TCAN4x5x_MCAN_NOMINAL_Timing_Simple TCANNomTiming ={0};// 40 MHz 晶体的500k 仲裁(((40E6 / 2)/(32 + 8)= 500E3)
    TCANNomTiming.NominalBitRatePrescaler =2;
    TCANNomTime.NominalTqBeforeSamplePoint =32;
    TCANNomTime.NominalTqAfterSamplePoint =8;

    TCAN4x5x_MCAN_Data_Timing_Simple TCANDataTiming ={0};//具有40 MHz 晶体的500kbps CAN FD (40E6 /(15 + 5)= 2E6)
    TCANDataTiming.DataBitRatePrescaler =2;
    TCANDataTime.DataTqBeforeSamplePoint =32;
    TCANDataTiming.DataTqAfterSamplePoint =8;

    /*配置 MCAN 核心设置*/
    TCAN4x5x_MCAN_CCCR_Config cccrConfig ={0};//记得初始化到0,否则会出现随机垃圾!
    cccrConfig.FDOE = 1;// CAN FD 模式启用
    cccrConfig.BRSE = 1;// CAN FD 位速率开关启用

    /*配置默认 CAN 数据包过滤设置*/
    TCAN4x5x_MCAN_Global_Filter_Configuration GFC ={0};
    GFC.RRFE = 1;//拒绝远程帧(TCAN4x5x 不支持此功能)
    GFC.RRFS = 1;//拒绝远程帧(TCAN4x5x 不支持此功能)
    GFC.ANFE = TCAN4x5x_GFC_reject;//如果传入消息与过滤器不匹配,默认行为是接受 RXFIO0接收扩展 ID 消息(29位 ID)
    GFC.ANFS = TCAN4x5x_GFC_reject;//如果传入消息与过滤器不匹配,默认行为是接受标准 ID 消息的 RXFIO0 (11位 ID)

    /*
    *在下一个配置块中,我们将 MCAN 核心设置为:
    *- 1 SID 滤芯
    *- 1个 XID 过滤器滤芯
    *- 5 RX FIFO 0元件
    *- RX FIFO 0支持高达64字节的数据有效负载
    *- RX FIFO 1和 RX 缓冲器不会有任何元素,但我们仍会设置它们的数据有效负载大小,即使这不是必需的
    *-无发射事件 FIFO
    *-2个传输缓冲区,支持多达64字节的数据负载
    *
    TCAN4x5x_MRAM_Config MRAMConfiguration ={0};
    MRAMConfiguration.SIDNumElements = 1;//标准 ID 元素数,您必须为定义的每个元素都有一个写入 MRAM 的过滤器
    MRAMConfiguration.XIDNumElements = 1;//扩展 ID 元素数,您必须为定义的每个元素编写一个过滤器到 MRAM
    MRAMConfiguration.Rx0NumElement = 16;// RX0元素数
    MRAMConfiguration.Rx0元素大小= MRAM_32_Byte 数据;// RX0数据有效负载大小
    MRAMConfiguration.Rx1NumElements = 0;// RX1元素数
    MRAMConfiguration.Rx1元素大小= MRAM_32_Byte_Data;// RX1数据有效负载大小
    MRAMConfiguration.RxBufNumElements = 0;// RX 缓冲区元素数
    MRAMConfiguration.RxBufElementSize = MRAM_32_Byte_Data;// RX 缓冲区数据有效负载大小
    MRAMConfiguration.TxEventFIFO 元素= 0;// TX 事件 FIFO 元素数
    MRAMConfiguration.TxBufferNumElements = 8;// TX 缓冲区元素数
    MRAMConfiguration.TxBufferElementSize = MRAM_32_Byte_Data;// TX 缓冲区数据有效负载大小


    /*使用上述设置配置 MCAN 核心,此块中的更改为写保护寄存器,*
    因此,一次完成所有操作是最有意义的,所以我们只解锁一次,然后锁定一次*/

    TCAN4x5x_MCAN_EnableProtectedRegisters ();//首先让受保护的寄存器可访问
    TCAN4x5x_MCAN_ConfigureCCCRRegister (&cccrConfig);//启用 FD 模式和比特率切换
    TCAN4x5x_MCAN_ConfigureGlobalFilter(&GFC);//配置全局过滤器配置(默认 CAN 消息行为)
    TCAN4x5x_MCAN_ConfigureNominalTiming_Simple (&TCANNomTiming);//设置标称/仲裁位计时
    TCAN4x5x_MCAN_ConfigureDataTiming_Simple (&TCANDataTiming);//设置 CAN FD 计时
    TCAN4x5x_MRAM_CLEAR ();//清除所有 MRAM (向所有 MRAM 写入0)
    TCAN4x5x_MRAM_Configure (&MRAMConfiguration);//设置与 MRAM 配置相关的适用寄存器
    TCAN4x5x_MCAN_DisableProtectedRegisters();//禁用保护写入并使设备退出初始化模式


    /*设置要为 MCAN */启用的中断
    TCAN4x5x_MCAN_Interrupt _Enable mCAN_ie ={0};//记得初始化到0,否则会出现随机垃圾!
    mCAN_i.RF0NE = 1;// RX FIFO 0新消息中断启用

    TCAN4x5x_MCAN_ConfigureInterruptEnable(&mCAN_IE);//启用相应的寄存器


    /*设置过滤器,此过滤器将把 ID 为0x055的任何邮件标记为优先级邮件*/
    TCAN4x5x_MCAN_SID_Filter SID_ID ={0};
    SID_ID.SFT = TCAN4x5x_SID_SFT_DUALID;// SFT:标准滤波器类型。 配置为经典过滤器
    SID_ID.SFEC = TCAN4x5x_SID_SFEC_PRIORITYSTORERX0;//标准滤波器元件配置,将其作为优先信息存储在 RX fifo 0中
    SID_ID.SFID1 =唯一 ID;// SFID1 (经典模式筛选器)
    SID_ID.SFID2 = global_ID;// SFID2 (经典模式掩码)
    TCAN4x5x_MCAN_WriteSIDFilter (0,&SID_ID);//写入 MRAM


    /*将 ID 0x12345678存储为优先级消息*/
    // TCAN4x5x_MCAN_XID_Filter XID_ID ={0};
    // XID_ID.EFT = TCAN4x5x_XID_EFT_CLASSIC;// EFT
    // XID_ID.EFEC = TCAN4x5x_XID_EFEC_PRIORITYSTORERX0;// EFEC
    // XID_ID.EFID1 = 0x12345678;// EFID1 (经典模式过滤器)
    // XID_ID.EFID2 = 0x1FFFFFFF;// EFID2 (经典模式掩码)
    // TCAN4x5x_MCAN_WriteXIDFilter (0,&XID_ID);//写入 MRAM

    /*配置 TCAN4550与 CAN 无关的功能*/
    TCAN4x5x_dev_config devConfig ={0};//请记住初始化为0,否则将出现随机垃圾!
    devConfig.SWE_DIS = 0;//保持休眠唤醒错误已启用(这是一个禁用位,而不是启用位)
    devConfig.device_reset = 0;//未请求软件重置
    devConfig.WD_EN = 0;//看门狗已禁用
    devConfig.nWKRQ_config = 0;// Mirror INH 函数(默认)
    devConfig.INH_DIS = 0;// INH 已启用(默认)
    devConfig.GPIO1_GPO_config = TCAN4x5x_dev_config_GPO1_MCAN_INT1;// MCAN nINT 1 (默认)
    devConfig.fail_safe_EN = 0;//已禁用故障安全(默认)
    devConfig.GPIO1_config = TCAN4x5x_dev_config_GPIO1_CONFIG_GPO;// GPIO 设置为 GPO (默认)
    devConfig.WD_action = TCAN4x5x_dev_config_WDT_action_nINT;//看门狗设置中断(默认)
    devConfig.WD_bit_reset = 0;//不要重置看门狗
    devConfig.nWKRQ_voltage = 0;//将 nWKRQ 设置为内部电压轨(默认)
    devConfig.GPO2_config = TCAN4x5x_dev_config_GPO2_MCAN_INT0;// GPO2无行为(默认)
    devConfig.CLK_REF = 1;//输入晶体为40 MHz 晶体(默认)
    devConfig.wak_config = TCAN4x5x_dev_config_wak_both _edges;//唤醒引脚可由任一边缘触发(默认)
    TCAN4x5x_Device_Configure (&devConfig);//使用上述配置配置配置设备

    TCAN4x5x_Device_SetMode (TCAN4x5x_device_mode_normal);//配置完成后设置为正常模式。 这条线路将打开收发器

    TCAN4x5x_MCAN_ClearInterruptsAll();//重置所有 MCAN 中断(不包括任何 SPIERR 中断)
    //printmsg (“测试 read2 %x\n",AHB_read_32 (0x0820));
    //printmsg (“在结尾%x\n",AHB_READ_32 (0x0800));

    }

    UINT8_t readTCAN_Unique 地址(无效)

    返回 UNIQUE ID_G;
    }

    UINT8_t readTCAN_global_Address (无效)

    返回 global_ID_G;
    }

    如果您想从我身边获得更多信息,请分享您的电子邮件 ID 并告诉我。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    你好,桑斯卡尔,

    感谢您提供所有 SPI 信号的缩小图像。  这非常有帮助,我可以看到我们需要首先解决的问题,这些问题可能会解决,也可能不会解决所有其他问题。  我发现,NCS 信号每隔32位就会过渡到较高的位置。  对于单个寄存器读或写,您需要 NCS 信号保持低64位,然后再转换高。  前32位用于告诉 TCAN4550您是要读写寄存器,寄存器的地址和寄存器的数量。  

    可以读/写多个连续的寄存器。 地址字段将是注册块的起始地址(最小地址),然后,长度字段将是您要访问的注册块中的注册数。  这在优化配置代码方面非常有用,方法是减少传输的 SPI 位总数,方法是消除对每个连续寄存器的 R/W,地址和长度字段的写入需求,从而为块中的每个寄存器节省32位。  这减少了通过 SPI 配置设备或向 MRAM 读/写数据以加快 CAN 消息处理所需的总时间。

    您需要将 NCS 引脚保持在低位至少64位,然后为“长度”字段中指定的每个附加寄存器增加32个数据位。  设备将计算时钟周期数,以确定是否收到了正确的时钟周期数,如果它不是32的倍数,则会设置 SPI 错误标志。  如果“长度”字段大于1,则它还将验证是否已传输正确数量的单词(32位),或者它也将设置错误。

    但现在,让我们重点关注单个寄存器的读/写,该寄存器的 R/W 代码+地址+长度字段需要32个 SCLK 周期,而单个32位寄存器的数据需要32个 SCLK 周期来读或写。  对于整个64位事务来说,NCS 保持低值非常重要,否则将设置 SPI 错误并丢弃写入数据。

    SPI 驱动程序通常以8,16或32位块传输数据,并在每个数据块后自动切换 NCS 引脚“低”和“高”。  只要 NCS 引脚在整个事务中保持较低的值,就可以使用较小数据块将数据传输到 TCAN4550。  您可能需要修改 SPI 驱动程序,以允许多个32位数据块的 NCS 引脚保持较低。  这可以通过创建单独的驱动程序函数来控制在 SPI 读/写数据函数前后调用的 NCS 来实现, 或者向驱动程序添加一个附加的长度参数,以指示需要在 NCS 转换之间传输多少32位数据块。

    CANSLNT (CAN 静音)位是设备故障安全功能的一部分,可以出于多种原因进行设置,包括总线不活动,CLKIN 或晶体振荡器时钟停止, 或者处理器停止运行 SPI 线路等 。TCAN4550数据表的8.4.5部分对此进行了更详细的说明,并有一些状态图显示了此信号与设备模式更改的关系。

    此致,

    乔纳森

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我正在附加 SPI 信号的放大图像。 请重新检查,我认为 NCS 每64位就会转换高。我通过软件控制 NCS,但在64位后才转换高,因为我要发送32位数据,32位用于光学代码和地址。 我随函附上该部分代码供您参考。

    void AHB_WRITE_32(uint16_t address, uint32_t data)
    {
    		AHB_WRITE_BURST_START(address, 1);
    	    AHB_WRITE_BURST_WRITE(data);
    	    AHB_WRITE_BURST_END();
    
    }
    
    
    void AHB_WRITE_BURST_START(uint16_t address, uint8_t words)
    {
    	uint8_t txDataTemp[4];
    		txDataTemp[0]=AHB_WRITE_OPCODE;
    		txDataTemp[1]=((address & 0xFF00)>>8);
    		txDataTemp[2]=(address & 0x00FF);
    		txDataTemp[3]=words;
    
    	HAL_GPIO_WritePin(TCAN_CS_GPIO_Port, TCAN_CS_Pin, GPIO_PIN_RESET);  //chip select low
    	WAIT_FOR_IDLE;
    	HAL_SPI_Transmit(&hspi2, txDataTemp, 4, 100);
    	WAIT_FOR_IDLE;
    }
    
    
    void AHB_WRITE_BURST_WRITE(uint32_t data)
    {
    	 	uint8_t txDataTemp[4];
    		txDataTemp[0]=((data & 0xFF000000)>>24);
    		txDataTemp[1]=((data & 0x00FF0000)>>16);
    		txDataTemp[2]=((data & 0x0000FF00)>>8);
    		txDataTemp[3]=(data & 0x000000FF);
    		WAIT_FOR_IDLE;
    		HAL_SPI_Transmit(&hspi2, txDataTemp, 4, 100);
    			WAIT_FOR_IDLE;
    
    }
    
    
    void AHB_WRITE_BURST_END(void)
    {
    	WAIT_FOR_IDLE;
    	HAL_GPIO_WritePin(TCAN_CS_GPIO_Port, TCAN_CS_Pin, GPIO_PIN_SET);  //chip select High
    }

    当我每秒传输32位数据时(延迟1000毫秒后,我将持续传输)。 然后读取中断寄存器0x820=4a0。 这表示 CAN 错误,全局错误和 CAN 静音。 您能否解释设置这些标志的原因? (在这种情况下,我可以接收所有正在传输的数据包)

    同时,当我在100毫秒或更低的延迟下连续传输32位数据时。 然后读取中断寄存器0x820 =0,在这种情况下,我也可以接收所有数据包。

    您能解释这种行为吗?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    桑斯卡尔

    感谢您为单个配准读取放大图像。  这是我想要看到并验证 NCS 信号是否正确的内容。  以前图像上的十六进制解码值使我觉得您在 NCS 边缘之间没有完整的64位。  此示波器图像显示正确。

    TCAN4550中有三种故障安全机制,详见数据表8.4.5部分。  所述的第三种机制是监控 CAN 总线的活动或非活动状态。  如果启用了 SWE 计时器,则如果在 CAN 总线上未检测到活动大约1秒钟,设备将设置 CAN 静音标志。

    由于您的传输延迟为1,因此很可能导致此计时器过期,这将设置此标志。  

    此监护计时器基于默认启用的 SWE 计时器,也用于在退出睡眠模式时检测假唤醒事件。  可以通过将寄存器0x0800[1]中的 SWE_DIS 位设置为“1”来禁用此功能。

    是否可以尝试将 SWE_DIS 设置为1以禁用此计时器, 和/或尝试将延迟时间1000毫秒缩短为500毫秒等更短的值,以确保在计时器到期前 CAN 总线上有活动,以查看 CAN 静音是否消失?  

    这两个选项中的任何一个都应阻止设置 CAN 静音标志。

    此致,

    乔纳森

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    乔纳森,你好,我尝试禁用 SWE_DIS 位,但它不起作用。 请您思考一下这背后的另一个可能原因吗?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    你好,桑斯卡尔,

    为了确保我完全理解这种情况,我想澄清几点。

    当您说禁用 SWE_DIS 位不起作用时,您是否意味着在每秒传输一次时状态寄存器中设置的相同错误位(0x0820 = 0x4A0,CAN 错误,全局错误和 CAN 静音)仍会出现。  这是正确的吗,无论 SWE_DIS 位是如何设置的,您都看不到行为的差异?

    此外,您还可以接收所有正在传输的数据包,这些数据包在消息之间有1秒和100毫秒的延迟。 正确吗?

    是当前的问题,我们正在尝试回答为什么 CAN 错误出现在状态寄存器中,并且延迟了1秒,或者还有其他问题,而不是这个问题,或者除了这个问题之外,这个问题还没有解决。

    我将验证设置您在传输延迟为1时看到的 CAN 错误的条件,以便我们可以确定如何在您的应用中处理或防止这些错误。  我将在下周初的后续帖子中提供此信息。

    此致,

    乔纳森

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    你好,桑斯卡尔,

    另请检查以确保 FAIL_SAFE _EN 位设置为“0”(寄存器0x0800[13]),以查看这是否阻止设置 CAN 静默错误位。

    此致,

    乔纳森