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: Unable to read Device ID register through SPI

Part Number: TCAN4550

Hello!

I am trying to rework the included Demo code for the TCAN4550 for my microcontroller setup, the STM32. In order to test my implementation, I am attempting to read the Device ID register. However, whenever I try to read I always get a value of 0 out. I'm sure this could mean that my SPI implementation is incorrect, but I also want to post my general setup to see if I am missing anything. Also, for reference, I am using the TCAN BOOST module and interfacing it with a STM32 Nucleo board.

SPI Parameters (for the MCU):

Clock freq: 10.5MBit/s

CPOL = 0, CPHA = 1 Edge

Frame format: Motorola MSB First, Data size: 8 bits,. Full duplex master

In my code, the first thing that I do is set the nCS pin high before pulsing the RST pin on the TCAN (I am using the GPIO_RST pin on the BOOST module). After pulsing it, I find that the VCCOUT and nINT LEDs are active on the BOOST module. I'm sure this means that the TCAN is in the standby state? I'm not sure why the nINT LED is on, and I am unable to read the device interrupt register anyways. After pulsing RST, I try to read the Device ID register with no luck. 

I am powering the BOOST module through the DC barrel jack with 12V. I am also only connecting the SPI interface, GND, and RST pins to the TCAN board. Here is my setup for performing the SPI functions.

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);
}

And I am calling the SPI_READ_32 as such:

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

Does anyone have intuition on what may be going wrong? 

Thank you in advance

  • Hello Nivant,

    I see one big issue with with the SPI Mode that may be the issue.  The TCAN4550 only supports MODE 0 (CPOL = 0, CPHA = 0).  Can you adjust the mode and try reading the registers again?

    Regards,

    Jonathan

  • Yes I believe by CPHA=0 we mean that the data is sampled on the first edge? That is what I have it set to do.

  • Hi Nivant,

    Ok, I was referring to description that CPHA = 1 in your original post which looked incorrect.

    CPOL = 0, CPHA = 1 Edge

    The data is sampled on the Rising Edge and shifted out on the Falling Edge. 

    One additional item to verify is whether your nCS (SPI Chip Select) line is remaining low for the entire SPI transaction.  The TCAN4550 requires at least 2 32-bit words for a SPI Read or Write transaction.  The nCS signal can not transition back to High in between these two words and it must remain Low for the entire 64-bit SPI transaction.  If it transitions High at the end of the first 32-bit word, then the TCAN4550 will abort the SPI read transaction and it won't return the data in the second word.

    Can you monitor the SPI signals with a scope or logic analyzer?

    Regards,

    Jonathan

  • Hi Jonathan,

    Thank you for your suggestion. I was able to analyze the SPI communication using a logic analyzer. I saw that the nCS line is indeed correct, and the SPI communication is given as:

    h41 | h00, h00 | h00, h04 | h00, h01 | h00, h41 | h00, h00 | h00, h04 | h00, h01 | h00

    Where each packet is divided by a comma and MOSI and MISO are separated as MOSI | MISO. Basically this means that the MCU is sending a SPI header packet as h41000401 which should be correct. I am noticing that my MCU is sending the SPI Header twice though. Would this be an issue?

    Thank you. 

  • And I just realized that I had the opcodes switched around. Sending the right opcode would help!

    Reading the Device ID register works now. Hopefully someone else will learn from this!

  • Hi Nivant,

    Do I understand it correctly that you have it working now?  If not, here is what a read to the Device ID register 0x0000 should look like for reference.  I've got both a scope and logic analyzer connected to the 4 SPI signals.

    Regards,

    Jonathan

  • Yes, it is working correctly, thank you for your help!

  • You're welcome.  Let us know if you have any additional questions.

    Regards,

    Jonathan