TCAN4550-Q1: 数据无法发送,显示SPIERR错误,CANERR错误,GLOBALERR错误,CANSLNT错误等。

Part Number: TCAN4550-Q1
Other Parts Discussed in Thread: TCAN4550,

我用nrf52832的SPI来读写tcan4550.经过几天折腾,最终还是卡在了数据发送不出去的境地。

软件用的是ti的官方驱动库,初始化过程我都用log打印出来,查看都通过了。在main函数里发数据试试的,然后查询发送标志位,发现一直没反应。然后我就利用下面的函数一直读。

void tcan4550_init()
{
/*初始化spi引脚*/
bool error=true;
/*初始化寄存器*/
TCAN4x5x_Device_ClearSPIERR(); // Clear any SPI ERR flags that might be set as a result of our pin mux changing during MCU startup
nrf_delay_us(1000);
/* Step one attempt to clear all interrupts */
TCAN4x5x_Device_Interrupt_Enable dev_ie = {0}; // Initialize to 0 to all bits are set to 0.
TCAN4x5x_Device_ConfigureInterruptEnable(&dev_ie); // Disable all non-MCAN related interrupts for simplicity

TCAN4x5x_Device_Interrupts dev_ir = {0}; // Setup a new MCAN IR object for easy interrupt checking
TCAN4x5x_Device_ReadInterrupts(&dev_ir); // Request that the struct be updated with current DEVICE (not MCAN) interrupt values
// NRF_LOG_INFO("TCAN4x5x_Device_ReadInterrupts:%x",dev_ir.word);
if (dev_ir.PWRON) // If the Power On interrupt flag is set
TCAN4x5x_Device_ClearInterrupts(&dev_ir); // Clear it because if it's not cleared within ~4 minutes, it goes to sleep

/* Configure the CAN bus speeds */
TCAN4x5x_MCAN_Nominal_Timing_Simple TCANNomTiming = {0}; // 500k arbitration with a 40 MHz crystal ((40E6 / 2) / (32 + 8) = 500E3)
TCANNomTiming.NominalBitRatePrescaler = 2;
TCANNomTiming.NominalTqBeforeSamplePoint = 32;
TCANNomTiming.NominalTqAfterSamplePoint = 8;

TCAN4x5x_MCAN_Data_Timing_Simple TCANDataTiming = {0}; // 2 Mbps CAN FD with a 40 MHz crystal (40E6 / (15 + 5) = 2E6)
TCANDataTiming.DataBitRatePrescaler = 2;
TCANDataTiming.DataTqBeforeSamplePoint = 32;
TCANDataTiming.DataTqAfterSamplePoint = 8;

/* Configure the MCAN core settings */
TCAN4x5x_MCAN_CCCR_Config cccrConfig = {0}; // Remember to initialize to 0, or you'll get random garbage!
cccrConfig.FDOE = 1; // CAN FD mode disenable
cccrConfig.BRSE = 1; // CAN FD Bit rate switch disenable

/* Configure the default CAN packet filtering settings */
TCAN4x5x_MCAN_Global_Filter_Configuration gfc = {0};
gfc.RRFE = 1; // Reject remote frames (TCAN4x5x doesn't support this)
gfc.RRFS = 1; // Reject remote frames (TCAN4x5x doesn't support this)
gfc.ANFE = TCAN4x5x_GFC_ACCEPT_INTO_RXFIFO0; // Default behavior if incoming message doesn't match a filter is to accept into RXFIO0 for extended ID messages (29 bit IDs)
gfc.ANFS = TCAN4x5x_GFC_ACCEPT_INTO_RXFIFO0; // Default behavior if incoming message doesn't match a filter is to accept into RXFIO0 for standard ID messages (11 bit IDs)

/* ************************************************************************
* In the next configuration block, we will set the MCAN core up to have:
* - 1 SID filter element
* - 1 XID Filter element
* - 5 RX FIFO 0 elements
* - RX FIFO 0 supports data payloads up to 64 bytes
* - RX FIFO 1 and RX Buffer will not have any elements, but we still set their data payload sizes, even though it's not required
* - No TX Event FIFOs
* - 2 Transmit buffers supporting up to 64 bytes of data payload
*/
TCAN4x5x_MRAM_Config MRAMConfiguration = {0};
MRAMConfiguration.SIDNumElements = 1; // Standard ID number of elements, you MUST have a filter written to MRAM for each element defined
MRAMConfiguration.XIDNumElements = 1; // Extended ID number of elements, you MUST have a filter written to MRAM for each element defined
MRAMConfiguration.Rx0NumElements = 5; // RX0 Number of elements
MRAMConfiguration.Rx0ElementSize = MRAM_64_Byte_Data; // RX0 data payload size
MRAMConfiguration.Rx1NumElements = 0; // RX1 number of elements
MRAMConfiguration.Rx1ElementSize = MRAM_64_Byte_Data; // RX1 data payload size
MRAMConfiguration.RxBufNumElements = 0; // RX buffer number of elements
MRAMConfiguration.RxBufElementSize = MRAM_64_Byte_Data; // RX buffer data payload size
MRAMConfiguration.TxEventFIFONumElements = 0; // TX Event FIFO number of elements
MRAMConfiguration.TxBufferNumElements = 2; // TX buffer number of elements
MRAMConfiguration.TxBufferElementSize = MRAM_64_Byte_Data; // TX buffer data payload size


/* Configure the MCAN core with the settings above, the changes in this block are write protected registers, *
* so it makes the most sense to do them all at once, so we only unlock and lock once */

error = TCAN4x5x_MCAN_EnableProtectedRegisters(); // Start by making protected registers accessible
NRF_LOG_INFO("TCAN4x5x_MCAN_EnableProtectedRegisters:%d",error);
error =TCAN4x5x_MCAN_ConfigureCCCRRegister(&cccrConfig); // Enable FD mode and Bit rate switching
NRF_LOG_INFO("TCAN4x5x_MCAN_ConfigureCCCRRegister:%d",error);
error =TCAN4x5x_MCAN_ConfigureGlobalFilter(&gfc); // Configure the global filter configuration (Default CAN message behavior)
NRF_LOG_INFO("TCAN4x5x_MCAN_ConfigureGlobalFilter:%d",error);
error =TCAN4x5x_MCAN_ConfigureNominalTiming_Simple(&TCANNomTiming);// Setup nominal/arbitration bit timing
NRF_LOG_INFO("TCAN4x5x_MCAN_ConfigureNominalTiming_Simple:%d",error);
error =TCAN4x5x_MCAN_ConfigureDataTiming_Simple(&TCANDataTiming); // Setup CAN FD timing
NRF_LOG_INFO("TCAN4x5x_MCAN_ConfigureDataTiming_Simple:%d",error);
TCAN4x5x_MRAM_Clear(); // Clear all of MRAM (Writes 0's to all of it)
error =TCAN4x5x_MRAM_Configure(&MRAMConfiguration); // Set up the applicable registers related to MRAM configuration
NRF_LOG_INFO("TCAN4x5x_MRAM_Configure:%d",error);

error = TCAN4x5x_TimeStampDisable();
NRF_LOG_INFO("TCAN4x5x_TimeStampDisable:%d",error);

//error = TCAN4x5x_LoopbackModeEnable();
//NRF_LOG_INFO("TCAN4x5x_LoopbackModeEnable:%d",error);

error =TCAN4x5x_MCAN_DisableProtectedRegisters(); // Disable protected write and take device out of INIT mode
NRF_LOG_INFO("TCAN4x5x_MCAN_DisableProtectedRegisters:%d",error);

/* Set the interrupts we want to enable for MCAN */
TCAN4x5x_MCAN_Interrupt_Enable mcan_ie = {0}; // Remember to initialize to 0, or you'll get random garbage!
mcan_ie.RF0NE = 1; // RX FIFO 0 new message interrupt enable
mcan_ie.TCE = 1;
TCAN4x5x_MCAN_ConfigureInterruptEnable(&mcan_ie); // Enable the appropriate registers


/* Setup filters, this filter will mark any message with ID 0x055 as a priority message */
TCAN4x5x_MCAN_SID_Filter SID_ID = {0};
SID_ID.SFT = TCAN4x5x_SID_SFT_CLASSIC; // SFT: Standard filter type. Configured as a classic filter
SID_ID.SFEC = TCAN4x5x_SID_SFEC_PRIORITYSTORERX0; // Standard filter element configuration, store it in RX fifo 0 as a priority message
SID_ID.SFID1 = 0x055; // SFID1 (Classic mode Filter)
SID_ID.SFID2 = 0x7FF; // SFID2 (Classic mode Mask)
error =TCAN4x5x_MCAN_WriteSIDFilter(0, &SID_ID); // Write to the MRAM
NRF_LOG_INFO("TCAN4x5x_MCAN_WriteSIDFilter:%d",error);

/* Store ID 0x12345678 as a priority message */
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 (Classic mode filter)
XID_ID.EFID2 = 0x1FFFFFFF; // EFID2 (Classic mode mask)
error =TCAN4x5x_MCAN_WriteXIDFilter(0, &XID_ID); // Write to the MRAM
NRF_LOG_INFO("TCAN4x5x_MCAN_WriteXIDFilter:%d",error);
/* Configure the TCAN4550 Non-CAN-related functions */
TCAN4x5x_DEV_CONFIG devConfig = {0}; // Remember to initialize to 0, or you'll get random garbage!
devConfig.SWE_DIS = 0; // Keep Sleep Wake Error Enabled (it's a disable bit, not an enable)
devConfig.DEVICE_RESET = 0; // Not requesting a software reset
devConfig.WD_EN = 0; // Watchdog disabled
devConfig.nWKRQ_CONFIG = 0; // Mirror INH function (default)
devConfig.INH_DIS = 0; // INH enabled (default)
devConfig.GPIO1_GPO_CONFIG = TCAN4x5x_DEV_CONFIG_GPO1_MCAN_INT1; // MCAN nINT 1 (default)
devConfig.FAIL_SAFE_EN = 0; // Failsafe disabled (default)
devConfig.GPIO1_CONFIG = TCAN4x5x_DEV_CONFIG_GPIO1_CONFIG_GPO; // GPIO set as GPO (Default)
devConfig.WD_ACTION = TCAN4x5x_DEV_CONFIG_WDT_ACTION_nINT; // Watchdog set an interrupt (default)
devConfig.WD_BIT_RESET = 0; // Don't reset the watchdog
devConfig.nWKRQ_VOLTAGE = 0; // Set nWKRQ to internal voltage rail (default)
devConfig.GPO2_CONFIG = TCAN4x5x_DEV_CONFIG_GPO2_NO_ACTION; // GPO2 has no behavior (default)
devConfig.CLK_REF = 1; // Input crystal is a 40 MHz crystal (default)
devConfig.WAKE_CONFIG = TCAN4x5x_DEV_CONFIG_WAKE_BOTH_EDGES;// Wake pin can be triggered by either edge (default)
error =TCAN4x5x_Device_Configure(&devConfig); // Configure the device with the above configuration
NRF_LOG_INFO("TCAN4x5x_Device_Configure:%d",error);


error =TCAN4x5x_Device_SetMode(TCAN4x5x_DEVICE_MODE_STANDBY); // Set to normal mode, since configuration is done. This line turns on the transceiver
NRF_LOG_INFO("TCAN4x5x_Device_SetMode:%d",error);

error =TCAN4x5x_Device_SetMode(TCAN4x5x_DEVICE_MODE_NORMAL); // Set to normal mode, since configuration is done. This line turns on the transceiver
NRF_LOG_INFO("TCAN4x5x_Device_SetMode:%d",error);

TCAN4x5x_MCAN_ClearInterruptsAll(); // Resets all MCAN interrupts (does NOT include any SPIERR interrupts)
}

void tcan4550_data_tx(void)
{
TCAN4x5x_Device_Interrupts dev_ir = {0}; // Define a new Device IR object for device (non-CAN) interrupt checking
TCAN4x5x_MCAN_Interrupts mcan_ir = {0};

/* Define the CAN message we want to send*/
TCAN4x5x_MCAN_TX_Header header = {0}; // Remember to initialize to 0, or you'll get random garbage!
uint8_t data[8] = {0x55, 0x66, 0x77, 0x88,0x99, 0xaa, 0xbb, 0xcc}; // Define the data payload
header.DLC = MCAN_DLC_8B; // Set the DLC to be equal to or less than the data payload (it is ok to pass a 64 byte data array into the WriteTXFIFO function if your DLC is 8 bytes, only the first 8 bytes will be read)
header.ID = 0x144; // Set the ID
header.FDF = 0; // CAN FD frame enabled
header.BRS = 0; // Bit rate switch enabled
header.EFC = 0;
header.MM = 0;
header.RTR = 0;
header.XTD = 0; // We are not using an extended ID in this example
header.ESI = 0; // Error state indicator

TCAN4x5x_MCAN_WriteTXBuffer(0, &header, data); // This function actually writes the header and data payload to the TCAN's MRAM in the specified TX queue number. It returns the bit necessary to write to TXBAR,
// but does not necessarily require you to use it. In this example, we won't, so that we can send the data queued up at a later point.


/* Let's make a different CAN message */
data[0] = 0x11;
data[1] = 0x22;
data[2] = 0x33;
data[3] = 0x44; // Define the data payload

header.DLC = MCAN_DLC_8B; // Set the DLC to be equal to or less than the data payload (it is ok to pass a 64 byte data array into the WriteTXFIFO function if your DLC is 8 bytes, only the first 8 bytes will be read)
header.ID = 0x123; // Set the ID
header.FDF = 0; // CAN FD frame enabled
header.BRS = 0; // Bit rate switch enabled
header.EFC = 0;
header.MM = 0;
header.RTR = 0;
header.XTD = 0; // We are not using an extended ID in this example
header.ESI = 0; // Error state indicator

TCAN4x5x_MCAN_WriteTXBuffer(1, &header, data); // This line writes the data and header to TX FIFO 1

TCAN4x5x_MCAN_TransmitBufferContents(1); // Request that TX Buffer 1 be transmitted
nrf_delay_ms(100);
NRF_LOG_INFO("AddRequestTransmission1:%X",TCAN4x5x_MCAN_Tx_AddRequestTransmissionOccurred(1));
TCAN4x5x_Device_ReadInterrupts(&dev_ir);
TCAN4x5x_MCAN_ReadInterrupts(&mcan_ir);

//while(!mcan_ir.TC);
NRF_LOG_INFO("Device_ReadInterrupts:%X",dev_ir.word);
NRF_LOG_INFO("MCAN_ReadInterrupts:%X",mcan_ir.word);
NRF_LOG_INFO("MCAN_ReadInterruptsflag:%X",AHB_READ_32(0x0824));
// TCAN4x5x_MCAN_ClearInterruptsAll();
}

logo输出的结果是这样的

硬件电路图是这样的

SPI的四根线跟主控链接,VSUP 5V,VIO3.3V。

TCAN4550canl 和canH接到can逻辑分析仪。

疑问1:现在没啥思路继续排查问题,请问下个方向我如何做呢?

疑问2:我自己做过另一个集成主控和tcan4550的小板子,发现同样的程序spi只能把ID给读出来,可是写其他寄存器就失败,读出来都是0。这也是一头雾水?

请帮忙指点一下方向。

  • 您好!

    对于您的问题1:

    首先、您可以确认 VSUP 电压电平仅为5V 吗?

    SPI的四根线跟主控链接,VSUP 5V,VIO3.3V。


    TCAN4550-Q1的最小工作 VSUP 电源电压为5.5V、因为内部5V LDO 需要至少5.5V 的电压才能产生5V 稳压电压、为 CAN 收发器和数字内核使用的其他内部 LDO 供电。 如果 VSUP 电压低于5.5V、该器件可能无法正常运行并进入受保护的欠压保护模式、甚至会发生上电复位(POR)。

    此外、该内部5V LDO 需要在 VCCOUT 引脚上使用10 μ F 电容、以滤波和稳定 LDO。 我在您的原理图中仅看到一个1uF 和一个100nF 滤波电容器。 这至少应为10uF

    请确保使用大于5.5V 的 VSUP 电压。

    对于您的问题2:

    这可能表明存在电压或时钟相关问题。 器件 ID 寄存器是在逻辑中创建的、不要求晶体工作、因为它们不需要数字内核返回值。 其余寄存器需要一个功能稳定的时钟来读取或写入数据。 VIO 电源为时钟电路供电、因此我要验证 VSUP 电源是否都大于5.5V、VIO 是否为3.3V。 正常运行时、RST 引脚必须保持低电平、因此请确认该引脚也是低电平、并且器件没有被保持在复位状态。

    从原理图中观察到的其他情况:

    -中断引脚(nINT)是一个开漏引脚,如果使用它,需要一个上拉电阻器连接到 VIO。 原理图显示了一个下拉电阻器、因此我不知道您是否在使用此引脚。 如果您想使用它、则电阻不正确。

    - GPO2引脚也是一个开漏引脚,如果使用它,将需要一个上拉电阻器而不是下拉电阻器。

    - TCAN4550-Q1通过 OSC1和 OSC2管脚支持晶振和单端时钟。 该器件通过查找小于150mV (max)的电压来监控 OSC2引脚是否处于"接地"引脚。 如果检测到电压低于150mV、器件将切换到单端时钟模式。 因此、使用晶体时、务必将 OSC2引脚保持在150mV 以上、这可能需要对时钟电路元件进行一些优化、以确保振荡波形的最低电平不会交叉低于150mV 电平、并导致意外切换到单端时钟模式。 如果发生这种情况、它将阻止数字内核和 CAN 控制器具有功能时钟、然后产生与 SPI 和 CAN 总线的通信错误。

    我不知道您是否有与时钟相关的问题、但根据您的观察、这是一种可能性。 建议在 OSC1引脚和晶体之间连接一个串联阻尼电阻、以便在晶体过大时帮助减少流过晶体的电流。 如果这不是选项、那么增加晶体负载电容器上的电容也将有助于降低振幅。 如需更多信息、请参阅 TCAN455x 时钟优化和设计指南应用报告(链接)。

    如果电压电平和时钟看起来正常、则请监控各种状态、错误计数器和中断寄存器以获取更多信息。

    0x000C、0x0820、0x0824、0x1040、0x1044、 0x1050