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:无法通过 SPI 读取器件 ID 寄存器

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

https://e2e.ti.com/support/interface-group/interface/f/interface-forum/1290323/tcan4550-unable-to-read-device-id-register-through-spi

器件型号:TCAN4550

您好!

我正在尝试为我的微控制器设置 STM32修改其中包含的 TCAN4550演示代码。 为了测试实现情况、我尝试读取器件 ID 寄存器。 但是、每当我尝试读取时、我总是会得到值0 out。 我敢肯定这可能意味着我的 SPI 实施不正确、但我还想布置好一般设置、看看我是否漏掉了任何东西。 此外、为了便于参考、我使用 TCAN 升压模块并将其与 STM32 Nucleo 板连接。

SPI 参数(对于 MCU):

时钟频率:10.5MBit/s

CPOL = 0、CPHA = 1边沿

帧格式:Motorola MSB 优先、数据大小:8位、 全双工主机

在我的代码中、首先要做的是对 TCAN 上的 RST 引脚施加脉冲之前将 NCS 引脚设置为高电平(我使用升压模块上的 GPIO_RST 引脚)。 对其进行脉冲之后、我发现升压模块上的 VCCOUT 和 nINT LED 处于活动状态。 我确定这意味着 TCAN 处于待机状态? 我不确定 nINT LED 为什么亮起、无论如何我都无法读取器件中断寄存器。 RST 脉冲后、我意外地尝试读取器件 ID 寄存器。  

我通过直流桶形插孔使用12V 电压为升压模块供电。 我也只将 SPI 接口、GND 和 RST 引脚连接至 TCAN 板。 以下是我执行 SPI 功能的设置。

void SPI_WRITE_32(SPI_HandleTypeDef *hspi, uint16_t address, uint8_t num_words, uint32_t pData)
{
    SPI_WRITE_BURST_START(hspi, address, num_words, pData);
    SPI_WRITE_BURST_WRITE(hspi, address, num_words, pData);
    SPI_WRITE_BURST_END();
}

uint32_t
SPI_READ_32(SPI_HandleTypeDef *hspi, uint16_t address)
{
    uint32_t returnData;

    SPI_READ_BURST_START(hspi, address, 1);
    returnData = SPI_READ_BURST_READ(hspi, address);
    SPI_READ_BURST_END();

    return returnData;
}

/*
 * @brief Burst write start
 *
 * The SPI transaction contains 3 parts: the header (start), the payload, and the end of data (end)
 * This function is the start, where the register address and number of words are transmitted
 *
 * @param address A 16-bit address of the destination register
 * @param words The number of 4-byte words that will be transferred. 0 = 256 words
 */
void SPI_WRITE_BURST_START(SPI_HandleTypeDef *hspi, uint16_t address, uint8_t num_words, uint32_t pData)
{

    // Prepare the data for SPI transmission
	// Prepare the data for SPI transmission
	uint16_t opcodeAndHighAddress = (WRITE_OPCODE << 8) | ((address >> 8) & 0xFF);
	uint16_t lowAddressAndNumWords = ((address & 0xFF) << 8) | num_words;

	// Create a 32-bit value from the prepared data
	uint32_t combinedValue = ((uint32_t)opcodeAndHighAddress << 16) | lowAddressAndNumWords;

	// Extract individual 8-bit values
	uint8_t msb = (combinedValue >> 24) & 0xFF; // Most significant byte
	uint8_t byte2 = (combinedValue >> 16) & 0xFF;
	uint8_t byte1 = (combinedValue >> 8) & 0xFF;
	uint8_t lsb = combinedValue & 0xFF;         // Least significant byte

    // set CS gpio low
    HAL_GPIO_WritePin(GPIOC, nCS_Pin, GPIO_PIN_RESET);

    // Send the first 16-bit SPI packet (opcode and top 8 bits of address)
    HAL_StatusTypeDef status = HAL_SPI_Transmit(hspi, &msb, sizeof(byte3), HAL_MAX_DELAY);
    HAL_SPI_Transmit(hspi, &byte2, sizeof(byte2), HAL_MAX_DELAY);
    HAL_SPI_Transmit(hspi, &byte1, sizeof(byte1), HAL_MAX_DELAY);
    HAL_SPI_Transmit(hspi, &lsb, sizeof(byte0), HAL_MAX_DELAY);

}

/*
 * @brief Burst write
 *
 * The SPI transaction contains 3 parts: the header (start), the payload, and the end of data (end)
 * This function writes a single word at a time
 *
 * @param data A 32-bit word of data to write to the destination register
 */
void SPI_WRITE_BURST_WRITE(SPI_HandleTypeDef *hspi, uint8_t num_words, uint16_t address, uint32_t pData)
{
	uint8_t byte3 = (pData >> 24) & 0xFF; // Most significant byte
	uint8_t byte2 = (pData >> 16) & 0xFF;
	uint8_t byte1 = (pData >> 8) & 0xFF;
	uint8_t byte0 = pData & 0xFF;          // Least significant byte

	// Send the first 16-bit SPI packet (opcode and top 8 bits of address)
	HAL_StatusTypeDef status = HAL_SPI_Transmit(hspi, &byte3, sizeof(byte3), HAL_MAX_DELAY);
	HAL_SPI_Transmit(hspi, &byte2, sizeof(byte2), HAL_MAX_DELAY);
	HAL_SPI_Transmit(hspi, &byte1, sizeof(byte1), HAL_MAX_DELAY);
	HAL_SPI_Transmit(hspi, &byte0, sizeof(byte0), HAL_MAX_DELAY);

}

/*
 * @brief Burst write end
 *
 * The SPI transaction contains 3 parts: the header (start), the payload, and the end of data (end)
 * This function ends the burst transaction by pulling nCS high
 */
void SPI_WRITE_BURST_END(void)
{  
// set CS gpio high again to indicate the end of the burst
    HAL_GPIO_WritePin(GPIOC, nCS_Pin, GPIO_PIN_SET);
}

/*
 * @brief Burst read start
 *
 * The SPI transaction contains 3 parts: the header (start), the payload, and the end of data (end)
 * This function is the start, where the register address and number of words are transmitted
 *
 * @param address A 16-bit start address to begin the burst read
 * @param words The number of 4-byte words that will be transferred. 0 = 256 words
 */
void SPI_READ_BURST_START(SPI_HandleTypeDef *hspi, uint16_t address, uint8_t words)
{

	// Prepare the data for SPI transmission
	uint16_t opcodeAndHighAddress = (WRITE_OPCODE << 8) | ((address >> 8) & 0xFF);
	uint16_t lowAddressAndNumWords = ((address & 0xFF) << 8) | num_words;

	// Create a 32-bit value from the prepared data
	uint32_t combinedValue = ((uint32_t)opcodeAndHighAddress << 16) | lowAddressAndNumWords;

	// Extract individual 8-bit values
	uint8_t msb = (combinedValue >> 24) & 0xFF; // Most significant byte
	uint8_t byte2 = (combinedValue >> 16) & 0xFF;
	uint8_t byte1 = (combinedValue >> 8) & 0xFF;
	uint8_t lsb = combinedValue & 0xFF;         // Least significant byte

    // Set the CS low to start the transaction
    HAL_GPIO_WritePin(GPIOC, nCS_Pin, GPIO_PIN_RESET);

           // Send the first 16-bit SPI packet (opcode and top 8 bits of address)
    HAL_StatusTypeDef status = HAL_SPI_Transmit(hspi, &msb, sizeof(byte3), HAL_MAX_DELAY);
    HAL_SPI_Transmit(hspi, &byte2, sizeof(byte2), HAL_MAX_DELAY);
    HAL_SPI_Transmit(hspi, &byte1, sizeof(byte1), HAL_MAX_DELAY);
    HAL_SPI_Transmit(hspi, &lsb, sizeof(byte0), HAL_MAX_DELAY);

    // Send the 16-bit address
    // Send the first 16-bit SPI packet (opcode and top 8 bits of address)
    // Handle an SPI transmit error by trying again
    if (status != HAL_OK)
    {
        SPI_READ_ERR_HANDLER(hspi, address);
    }
}

/*
 * @brief Burst read start
 *
 * The SPI transaction contains 3 parts: the header (start), the payload, and the end of data (end)
 * This function where each word of data is read from the TCAN4x5x
 *
 * @return A 32-bit single data word that is read at a time
 */
uint32_t
SPI_READ_BURST_READ(SPI_HandleTypeDef *hspi, uint16_t address)
{
	uint8_t readData0;
	uint8_t readData1;
	uint8_t readData2;
	uint8_t readData3;
	uint32_t returnData;

	HAL_SPI_Receive (hspi, &readData0, sizeof(readData0), HAL_MAX_DELAY);
	HAL_SPI_Receive (hspi, &readData1, sizeof(readData1), HAL_MAX_DELAY);
	HAL_SPI_Receive (hspi, &readData2, sizeof(readData2), HAL_MAX_DELAY);
	HAL_SPI_Receive (hspi, &readData3, sizeof(readData3), HAL_MAX_DELAY);

	returnData = (((uint32_t)readData0) << 24) | (((uint32_t)readData1 << 16)) | (((uint32_t)readData2) << 8) | readData3;

	return returnData;

}

/*
 * @brief Burst write end
 *
 * The SPI transaction contains 3 parts: the header (start), the payload, and the end of data (end)
 * This function ends the burst transaction by pulling nCS high
 */
void SPI_READ_BURST_END(void)
{
    // set CS gpio high
    HAL_GPIO_WritePin(GPIOC, nCS_Pin, GPIO_PIN_SET);
}

我因此调用 SPI_READ_32:

uint32_t readvalue;
TCAN4x5x_Device_ClearSPIERR(&hspi2);
readvalue = SPI_READ_32(&hspi2, REG_SPI_DEVICE_ID1);

有人对什么可能会出错有直觉吗?  

提前感谢

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

    您好,Nivant,

    我看到 SPI 模式的一个大问题可能就是这个问题。  TCAN4550仅支持模式0 (CPOL = 0、CPHA = 0)。  您可以调整模式并尝试再次读取寄存器吗?

    此致、

    乔纳森

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

    是的、我相信 CPHA=0意味着数据采样在第一个边沿上? 这就是我将其设置为执行的操作。

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

    尊敬的 Nivant:

    好的,我指的是描述 CPHA = 1在你原来的帖子,这看起来不正确。

    CPOL = 0、CPHA = 1边缘

    该数据在上升沿被采样、在下降沿移出。  

    另一个要验证的项目是 NCS (SPI 芯片选择)线路在整个 SPI 事务期间是否保持低电平。  TCAN4550至少需要2个32位字用于 SPI 读取或写入事务。  NCS 信号无法在这两个字之间转换回高电平、并且在整个64位 SPI 事务期间必须保持低电平。  如果它在第一个32位字的末尾转换为高电平、则 TCAN4550将中止 SPI 读取事务、并且不会返回第二个字中的数据。

    可以使用示波器或逻辑分析仪监控 SPI 信号吗?

    此致、

    乔纳森

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

    尊敬的 Jonathan:

    感谢您的建议。 我能够使用逻辑分析仪分析 SPI 通信。 我看到 nCS 线路确实正确、SPI 通信如下所示:

    h41 | h00、h00 | h00、h04 | h00、h01 | h00、h41 | h00、 h00 | h00、h04 | h00、h01 | h00

    其中每个数据包被逗号分隔、MOSI 和 MISO 以 MOSI | MISO 分隔。 基本上、这意味着 MCU 会发送 SPI 标头数据包、频率应该是正确的 h41000401。 我注意到我的 MCU 正在发送 SPI 接头两次。 这会是问题吗?

    谢谢你。  

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

    我刚意识到我调换了操作码。 发送正确的操作码将有所帮助!

    现在可以读取器件 ID 寄存器。 希望别人能从中学习!

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

    尊敬的 Nivant:

    我是否正确理解您现在已使其正常工作?  如果不是这样、那么读取器件 ID 寄存器0x0000的结果应该会作为参考。  我已将示波器和逻辑分析仪连接到4个 SPI 信号。

    此致、

    乔纳森

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

    是的、它工作正常、感谢您的帮助!

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

    不用客气。  如果您有任何其他问题、请告诉我们。

    此致、

    乔纳森