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-Q1: SPI communication problem: How to use D3-TDA3xx-rvp to communicate with TCAN4550EVM?

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

Hi,

I have used vsdk3.7 and TI provided functions(in utils_mcspi.c) to do SPI communication test.
I have read TCAN4550 datasheet, TCAN45xx software user's  guide, and followed SPI Read or Write format to send a message to TCAN4550EVM.
However, D3-TDA3xx-rvp seems can't get the right response from TCAN4550EVM.
Please tell me what messages I should send/receive to prove SPI communication is successful.
My code shows below.
Could you help me check hardware configuration and fix related software problems?Thank you.

Regards,

Ethan

void spi_main()
{
UInt32 mcSpiInstNum=1U; // 0U, 1U, 2U, 3U
EDMA3_DRV_Handle edmaHandle;
void *gSpiHandle;
UInt8 i, j;
UInt8 dataRx[16], dataTx[16];
UInt32 dataLengthTx, dataLengthRx;
UInt32 val;


val = HW_RD_REG32(SOC_L4PER_CM_CORE_BASE + CM_L4PER_MCSPI2_CLKCTRL);


Task_sleep(1000U);


AppUtils_setBoardMux();


Utils_mcspiInit(mcSpiInstNum);
Task_sleep(500);

edmaHandle = Utils_dmaGetEdma3Hndl(0U);
Task_sleep(500);

gSpiHandle = Utils_mcspiOpen( (UInt8)mcSpiInstNum, (UInt8)mcSpiInstNum , 0, edmaHandle);
Task_sleep(1000);


memset(dataTx, test, sizeof(dataTx));
dataTx[0] = 0x41;
dataTx[1] = 0x00;
dataTx[2] = 0x04;
dataTx[3] = 0x01;
dataTx[4] = 0x00;
dataTx[5] = 0x00;
dataTx[6] = 0x00;
dataTx[7] = 0x00;

dataLengthTx = Utils_mcspiWrite(gSpiHandle, dataTx, 8U);

Vps_printf("dataTx[0] = %02X, dataTx[1] = %02X, dataTx[2] = %02X, dataTx[3] = %02X \n", dataTx[0], dataTx[1], dataTx[2], dataTx[3]);
Vps_printf("dataTx[4] = %02X, dataTx[5] = %02X, dataTx[6] = %02X, dataTx[7] = %02X \n", dataTx[4], dataTx[5], dataTx[6], dataTx[7]);


Task_sleep(500);



memset(dataRx, 0x00, sizeof(dataRx));


dataLengthRx = Utils_mcspiRead(gSpiHandle, dataRx, 8U);


Vps_printf("(A)dataRx[0] = %02X, dataRx[1] = %02X, dataRx[2] = %02X, dataRx[3] = %02X \n", dataRx[0], dataRx[1], dataRx[2], dataRx[3]);
Vps_printf("(A)dataRx[4] = %02X, dataRx[5] = %02X, dataRx[6] = %02X, dataRx[7] = %02X \n", dataRx[4], dataRx[5], dataRx[6], dataRx[7]);

Utils_mcspiClose(gSpiHandle);
Utils_mcspiDeinit(mcSpiInstNum);
}

  • Hello Ethan,

    I support the TCAN4550 device and will help you the best I can.  I am not currently familiar with the code that was provided to you from the D3-TDA3xx-rvp team so if I am unable to help you we may need to get them involved.

    The photo of your setup looks correct.  We basically need a VSUP voltage greater than 6V at the device pin.  You have supplied power to the VBAT header as expected which has a reverse polarity protection diode that will make the VSUP voltage a diode's drop lower than the VBAT supplied voltage.  Therefore you will need to make sure your supply is at least 7V.  Since the other power rail LEDs are on, I believe you have this correct.

    Then you will need your SPI wires connected to your processor board.  It appears you have wires connected to the correct SPI header pins.  I would also ask that you make sure you have connected the GND between the processor board and the TCAN4550 EVM.  Without a common GND connection, SPI communication will have no return path for the current and therefore fail.  I can't tell if the GND pin of the VBAT header on the supply is common to the Processor board, and even if it is, I might recommend using another GND pin on the same Digital IO Header on the TCAN4550 closer to the SPI pins to make a less inductive return current path between the two boards and improve the signal integrity of the SPI communication if it has become noisy.

    Later on once communication is established, connecting the interrupt pins such as nINT, GPIO1, and GPO2 could be connected as well, but this won't impact the current issue.

    I will note one additional device/hardware related issue that sometimes comes up during the early stages of firmware development.  The TCAN4550 has a failsafe feature that will cause the device to enter Sleep Mode after 4 minutes of inactivity.  When the device powers up, a 4 minute timer starts and the device needs to be configured into Normal Mode, or have the Power On Flag (PWRON) cleared.  This is described in the datasheet.  If you are unaware of this, it is common to have long pauses between your tests while you check code, read datasheets, etc. and when you come back to the device, it has entered Sleep Mode and will be unresponsive.  You can press the WAKE pushbutton, the Reset pushbutton, power cycle the device, or provide a Wake Up Pattern (WUP) on the CAN bus to wake it up so that it enters Standby mode again.  You can disable this feature by setting the SWE bit to 1 in the Configuration register, but this bit will have to be set following every initial power up.  In your photo, the LEDs are on so the device is not in Sleep Mode, but if you have not disabled this bit, the SPI communication will fail if the device is in Sleep Mode.  Once we get SPI communication working, you should be aware of this moving forward and add it to your configuration routine.

    From your TX Data byte array, it looks like you are trying to read register 0x0004.  Is this correct?  Since I am not familiar with the driver code, my only suggestion is to verify that the bytes are transmitted in the proper order and not reversed.

    You mention that you don't get a "right response" from the TCAN4550.  What response do you get?  Can you provide any form of scope or logic analyzer plots for the SPI bus during your communication? Without knowing what the TCAN4550 response is, and to verify the signals have proper timing and byte order, I can't provide any more detailed information at this time.

    Can you capture some scope plots of the signals and provide them to me so that I can do a more detailed analysis of your setup?

    Regards,

    Jonathan

  • Hi Jonathan,

    Thanks for your prompt reply.
    Yes, it is. I tried to read register 0x0004 and send "0x41 0x00 0x04 0x01 0x00 0x00 0x00 0x00" to TCAN4550EVM.
    But I am not sure whether the sending message is right.
    What message will TCAN4550EVM feedback to D3-TDA3xx-rvp when TCAN4550EVM receives 0x0004 reading register request? 0x30 0x35 0x35 0x34?


    write: 0x41 0x00 0x04 0x01 0x00 0x00 0x00 0x00 <== Is this correct?
    read:                                                                        <== unknown

    Regards,

    Ethan

  • Hi Ethan,

    When reading register 0x0004, the device will return 0x30, 0x35, 0x35, 0x34 as you suggest.  The read data is the last 4 bytes of Write function and therefore you need to be able to both write data on your MOSI pin and capture data on the MISO simultaneously.  When using the 0x41 "read" op code, the TX data bytes are of don't care value since you really just need to provide the clock cycles in order for the TCAN4550 to clock out the register data associated with the address you provided in the 2 bytes following the 0x41 op code.  The first byte returned on the MISO line simultaneously with the op code is the TCAN4550's Global Status Register that has the interrupt flags.  This is so the processor can monitor for SPI and other errors on every SPI transaction without specifically polling the status register.

    When using the 0x61 write op code, the last 4 data bytes are written to the register address provided immediately following the op code.  All bytes of the MISO except the first global status register are of don't care and can be ignored.

    Here are some plots from a basic SPI protocol tool and Logic Analyzer for your reference.This tool is wired over to the EVM just as you are trying to do with your processor board.

    This first image is the read/write log from the protocol tool.  I read both registers 0x0000 and 0x0004.

    This next image is the Logic Analyzer plot when reading register 0x0000. Just as a note, the Select line transitions were off screen with the required zoom settings needed to see the hex decoding values of the bytes.  So I just drew the falling and rising edges into the waveform shown in blue since they are required at the start and end of each SPI transaction.

    This next image is the Logic Analyzer plot of reading register 0x0004.  Once again I drew in the Select transitions.

    If you have any ability to monitor the SPI signals using a scope and logic analyzer, it would be good to know if there is any signs of activity on the TCAN4550 SDO (MISO) pin.  And is this a clear representation of what to expect from a TCAN4550 SPI Read?

    Regards,

    Jonathan

  • Hi Jonathan,

    My source code and test results show below.
    According to figure 2, while calling "Utils_mcspiWrite()", TCAN4550EVM seems to return messages simultaneously.
    So, the following "Utils_mcspiRead()" can't get return messages successfully. What is the right way to get return on D3-TDA3xx-rvp?
    Could you help analyse this problem and check software process, initialization and settings(in utils_mcspi.c)?

    software process:
    void spi_main()
    {
        UInt32 mcSpiInstNum=1U;    // 0U, 1U, 2U, 3U
        EDMA3_DRV_Handle edmaHandle;
        void *gSpiHandle;
        UInt8 i, j;
        UInt8 dataRx[16], dataTx[16];
        int dataTxEleNum=0;
        UInt32 dataLengthTx, dataLengthRx;
        UInt32 val;
        
        val = HW_RD_REG32(SOC_L4PER_CM_CORE_BASE + CM_L4PER_MCSPI2_CLKCTRL);
        Task_sleep(1000U);
        AppUtils_setBoardMux();
        
        Utils_mcspiInit(mcSpiInstNum);
        Task_sleep(500);
        
        edmaHandle = Utils_dmaGetEdma3Hndl(0U);
        Task_sleep(500);
        
        gSpiHandle = Utils_mcspiOpen( (UInt8)mcSpiInstNum, (UInt8)mcSpiInstNum , 0, edmaHandle);
        Task_sleep(1000);


        memset(dataTx, test, sizeof(dataTx));   
        dataTx[0] = 0x41;
        dataTx[1] = 0x00;
        dataTx[2] = 0x00;
        dataTx[3] = 0x01;
        dataTx[4] = 0x00;
        dataTx[5] = 0x00;
        dataTx[6] = 0x00;
        dataTx[7] = 0x00;   
        dataLengthTx = Utils_mcspiWrite(gSpiHandle, dataTx, 8U);//send to TCAN4550EVM   
        Vps_printf("(B)dataTx[0] = %02X, dataTx[1] = %02X, dataTx[2] = %02X, dataTx[3] = %02X \n", dataTx[0], dataTx[1], dataTx[2], dataTx[3]);
        Vps_printf("(B)dataTx[4] = %02X, dataTx[5] = %02X, dataTx[6] = %02X, dataTx[7] = %02X \n", dataTx[4], dataTx[5], dataTx[6], dataTx[7]);
            
            
        dataLengthRx = 0;
        memset(dataRx, 0x00, sizeof(dataRx));
        dataLengthRx = Utils_mcspiRead(gSpiHandle, dataRx, 8U);//try to receive return messages from TCAN4550EVM    
        Vps_printf("(A)dataRx[0] = %02X, dataRx[1] = %02X, dataRx[2] = %02X, dataRx[3] = %02X \n", dataRx[0], dataRx[1], dataRx[2], dataRx[3]);
        Vps_printf("(A)dataRx[4] = %02X, dataRx[5] = %02X, dataRx[6] = %02X, dataRx[7] = %02X \n", dataRx[4], dataRx[5], dataRx[6], dataRx[7]);

        if(dataLengthRx != 8U)
            Vps_printf("data Length error %d\n",dataLengthRx);
            
        
        Utils_mcspiClose(gSpiHandle);
        Vps_printf("=== spi  555\n");
        
        Utils_mcspiDeinit(mcSpiInstNum);
    }

    /*
    Copyright (c) [2012 - 2017] Texas Instruments Incorporated
    
    All rights reserved not granted herein.
    
    Limited License.
    
     Texas Instruments Incorporated grants a world-wide, royalty-free, non-exclusive
     license under copyrights and patents it now or hereafter owns or controls to
     make,  have made, use, import, offer to sell and sell ("Utilize") this software
     subject to the terms herein.  With respect to the foregoing patent license,
     such license is granted  solely to the extent that any such patent is necessary
     to Utilize the software alone.  The patent license shall not apply to any
     combinations which include this software, other than combinations with devices
     manufactured by or for TI ("TI Devices").  No hardware patent is licensed
     hereunder.
    
     Redistributions must preserve existing copyright notices and reproduce this
     license (including the above copyright notice and the disclaimer and
     (if applicable) source code license limitations below) in the documentation
     and/or other materials provided with the distribution
    
     Redistribution and use in binary form, without modification, are permitted
     provided that the following conditions are met:
    
     * No reverse engineering, decompilation, or disassembly of this software
       is permitted with respect to any software provided in binary form.
    
     * Any redistribution and use are licensed by TI for use only with TI Devices.
    
     * Nothing shall obligate TI to provide you with source code for the software
       licensed and provided to you in object code.
    
     If software source code is provided to you, modification and redistribution of
     the source code are permitted provided that the following conditions are met:
    
     * Any redistribution and use of the source code, including any resulting
       derivative works, are licensed by TI for use only with TI Devices.
    
     * Any redistribution and use of any object code compiled from the source code
       and any resulting derivative works, are licensed by TI for use only with TI
       Devices.
    
     Neither the name of Texas Instruments Incorporated nor the names of its
     suppliers may be used to endorse or promote products derived from this software
     without specific prior written permission.
    
     DISCLAIMER.
    
     THIS SOFTWARE IS PROVIDED BY TI AND TI'S LICENSORS "AS IS" AND ANY EXPRESS OR
     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     IN NO EVENT SHALL TI AND TI'S LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    */
    
    /**
     *******************************************************************************
     * \file utils_mcspi.c
     *
     * \brief  This file has the implementataion for UART
     *
     * \version 0.0 (Aug 2016) : [PG] First version
     * \version 0.1 (Oct 2017) : [PG] Updated for 4 McSPI
     *
     *******************************************************************************
    */
    
    /*******************************************************************************
     *  INCLUDE FILES
     *******************************************************************************
     */
    
    #include <xdc/std.h>
    #include <string.h>
    #include <stdlib.h>
    #include <string.h>
    #include <xdc/runtime/Error.h>
    #include <ti/sysbios/io/GIO.h>
    #include <ti/sysbios/io/DEV.h>
    #include <ti/drv/bsp_lld/mcspi/bsp_mcspi.h>
    #include <ti/drv/vps/include/devices/bsp_device.h>
    #include <ti/drv/vps/include/boards/bsp_board.h>
    #include <ti/csl/soc.h>
    #include <src/rtos/utils_common/include/utils_mcspi.h>
    #include <ti/drv/stw_lld/platform/irq_xbar.h>
    
    #define UTILS_MCSPI_NUM_MCSPI_INST (4U)
    #define UTILS_MCSPI_NUM_DEVICES    (8U)
    /** Num Bufs to be issued and reclaimed */
    #define UTILS_MCSPI_NUM_BUFS       (3U)
    
    /** \brief McSPI Configuration parameters */
    static Mcspi_Params mcspiCfgPrms[UTILS_MCSPI_NUM_MCSPI_INST];
    
    /** \brief String identifiers for the McSPI driver names */
    static xdc_String gMcspiDriverNames[UTILS_MCSPI_NUM_MCSPI_INST] =
    {
        "/mcspi0",
        "/mcspi1",
        "/mcspi2",
        "/mcspi3"
    };
    
    /**
     *  \brief McSPI communication handle object which contains the required
     *         information for communication with McSPI devices.
     */
    typedef struct
    {
        UInt32           deviceIdx;
        /**< Device Index of the corresponding device instance */
        GIO_Handle       mcspiHandle;
        /**< GIO Handle for McSPI */
        GIO_Params       mcspiIoPrms;
        /**< McSPI GIO parameters used while creating the driver */
        Mcspi_ChanParams mcspiChanParams;
        /**< McSPI Channel parameters */
    } Utils_mcspiDeviceCommObj;
    
    /**
     *  \brief Pointer to the radar McSPI communication object.
     */
    typedef Utils_mcspiDeviceCommObj *Utils_mcspiCommHandle;
    /* MISRA.VAR.MIN.VIS
     * MISRAC_2004_Rule_8.7
     * MISRAC_WAIVER: All global variables are defined at the top of the file
     * to increase readability and maintenance of code.
     */
    static Utils_mcspiDeviceCommObj gUtils_mcspiDeviceCommObj[UTILS_MCSPI_NUM_DEVICES];
    
    /*******************************************************************************
     *  Function Declarations
     *******************************************************************************
     */
    
    /* MISRA.FUNC.NOPROT.CALL Rule 8.2 fix */
    static inline void ti_sysbios_io_GIO_Params_init(ti_sysbios_io_GIO_Params *prms);
    
    /**
     *******************************************************************************
     *  \brief  User defined function which will initialize the McSPI. This function
     *          is called when the driver for McSPI is created.
     *
     * \return  None
     *
     *******************************************************************************
     */
    static void Utils_mcspiUserCommonInit(uint32_t mcSPINum);
    
    static void Utils_mcspi0UserInit(void);
    static void Utils_mcspi1UserInit(void);
    static void Utils_mcspi2UserInit(void);
    static void Utils_mcspi3UserInit(void);
    
    /**
     *******************************************************************************
     *
     * \brief Initializes the McSPI and adds the GIO_Device
     *
     * \return  None
     *
     *******************************************************************************
     */
    Void Utils_mcspiInit(UInt32 mcSpiInstNum)
    {
        if (mcSpiInstNum < UTILS_MCSPI_NUM_MCSPI_INST)
        {
            /* Set the mcspi params */
            switch(mcSpiInstNum)
            {
                case 0U: GIO_addDevice(gMcspiDriverNames[mcSpiInstNum],
                        (xdc_Ptr) & Mcspi_IOMFXNS,
                        &Utils_mcspi0UserInit,
                        (xdc_Int)mcSpiInstNum, (xdc_Ptr) & (mcspiCfgPrms[mcSpiInstNum]));
                        Bsp_boardSelectDevice(BSP_DRV_ID_MCSPI, BSP_DEVICE_MCSPI_INST_ID_0);
                        break;
                case 1U: GIO_addDevice(gMcspiDriverNames[mcSpiInstNum],
                        (xdc_Ptr) & Mcspi_IOMFXNS,
                        &Utils_mcspi1UserInit,
                        (xdc_Int)mcSpiInstNum, (xdc_Ptr) & (mcspiCfgPrms[mcSpiInstNum]));
                        Bsp_boardSelectDevice(BSP_DRV_ID_MCSPI, BSP_DEVICE_MCSPI_INST_ID_1);
                        break;
                case 2U: /* Set up non default Cross Bar */
                        IRQXBARConnect(SOC_IRQ_DMARQ_CROSSBAR_REGISTERS_BASE,
                #ifdef IPU_PRIMARY_CORE_IPU2
                                    CPU_IPU2, XBAR_INST_IPU1_IRQ_59, MCSPI3_IRQ);
                #else
                                    CPU_IPU1, XBAR_INST_IPU1_IRQ_59, MCSPI3_IRQ);
                #endif
                        GIO_addDevice(gMcspiDriverNames[mcSpiInstNum],
                        (xdc_Ptr) & Mcspi_IOMFXNS,
                        &Utils_mcspi2UserInit,
                        (xdc_Int)mcSpiInstNum, (xdc_Ptr) & (mcspiCfgPrms[mcSpiInstNum]));
                        Bsp_boardSelectDevice(BSP_DRV_ID_MCSPI, BSP_DEVICE_MCSPI_INST_ID_2);
                        break;
                case 3U:
                        /* Set up non default Cross Bar */
                        IRQXBARConnect(SOC_IRQ_DMARQ_CROSSBAR_REGISTERS_BASE,
                #ifdef IPU_PRIMARY_CORE_IPU2
                                    CPU_IPU2, XBAR_INST_IPU1_IRQ_60, MCSPI4_IRQ);
                #else
                                    CPU_IPU1, XBAR_INST_IPU1_IRQ_60, MCSPI4_IRQ);
                #endif
                        GIO_addDevice(gMcspiDriverNames[mcSpiInstNum],
                        (xdc_Ptr) & Mcspi_IOMFXNS,
                        &Utils_mcspi3UserInit,
                        (xdc_Int)mcSpiInstNum, (xdc_Ptr) & (mcspiCfgPrms[mcSpiInstNum]));
                        Bsp_boardSelectDevice(BSP_DRV_ID_MCSPI, BSP_DEVICE_MCSPI_INST_ID_3);
                        break;
                default:
                        /* Should not come here */
                        break;
            }
        }
    }
    /**
     *******************************************************************************
     *
     * \brief De-Initializes the McSPI and removes the GIO_Device
     *
     * \param mcSpiInstNum McSPI Instance Number
     * \return  None
     *
     *******************************************************************************
     */
    Void Utils_mcspiDeinit(UInt32 mcSpiInstNum)
    {
        GIO_removeDevice(gMcspiDriverNames[mcSpiInstNum]);
    }
    /**
     *******************************************************************************
     *
     * \brief Get the McSPI Device Name
     *
     * \param mcSpiInstNum McSPI Instance Number
     * \param devName      Device Name returned by the API.
     * \return  None
     *
     *******************************************************************************
     */
    void Utils_mcspiGetDevName (UInt32 mcSpiInstNum, xdc_String devName)
    {
        if (mcSpiInstNum < UTILS_MCSPI_NUM_MCSPI_INST)
        {
            strcpy(devName, gMcspiDriverNames[mcSpiInstNum]);
        }
    }
    /**
     *******************************************************************************
     *
     * \brief  Open the McSPI Device Handle
     *
     * \param deviceId          Index of the device being communicated with
     * \param mcSpiDevInstNum   McSPI Instance Number
     * \param mcSpiChannelNum   Channel number of the McSPI instance.
     * \param edmaHandle        EDMA handle to be used for the McSPI transfers.
     *
     * \return  Pointer to the handle of the mcspi communication handle.
     *
     *******************************************************************************
     */
    void * Utils_mcspiOpen(UInt8            deviceId,
                           UInt8            mcSpiDevInstNum,
                           UInt8            mcSpiChannelNum,
                           EDMA3_DRV_Handle edmaHandle)
    {
        Utils_mcspiCommHandle commHndl = &gUtils_mcspiDeviceCommObj[deviceId];
        static UInt32 fifoEnabled[UTILS_MCSPI_NUM_MCSPI_INST] = {0U, 0U, 0U, 0U};
        void * returnHandle    = NULL;
    
        if (mcSpiDevInstNum < UTILS_MCSPI_NUM_MCSPI_INST)
        {
            Error_Block eb;
            Error_init(&eb);
            /*
             * Initialize channel attributes.
             */
            GIO_Params_init(&commHndl->mcspiIoPrms);
    
            /* Update the McSPI channel parameters */
            commHndl->mcspiChanParams.hEdma = edmaHandle;
            commHndl->mcspiChanParams.chipSelTimeControl = MCSPI_CLK_CYCLE3;
            /* Fifo can be enabled for only one channel */
            if (fifoEnabled[mcSpiDevInstNum] == 0U)
            {
                commHndl->mcspiChanParams.fifoEnable         = (Bool) TRUE;
                fifoEnabled[mcSpiDevInstNum] = 1U;
            }
            else
            {
                commHndl->mcspiChanParams.fifoEnable         = (Bool) FALSE;
            }
            commHndl->mcspiChanParams.spiChipSelectHold  = (Bool) TRUE;
            commHndl->mcspiChanParams.chanNum = mcSpiChannelNum;
    
            /* If cross bar events are being used then make isCrossBarIntEn = TRUE
             * and
             * choose appropriate interrupt number to be mapped (assign it to
             * intNumToBeMapped)
             */
            /* Cross bar evt disabled */
            commHndl->mcspiChanParams.crossBarEvtParam.isCrossBarIntEn =
                (Bool) FALSE;
            /* Program an invalid value */
            commHndl->mcspiChanParams.crossBarEvtParam.intNumToBeMapped = 0xFF;
    
            commHndl->mcspiIoPrms.chanParams = (Ptr) & commHndl->mcspiChanParams;
            commHndl->mcspiIoPrms.model      = GIO_Model_ISSUERECLAIM;
            commHndl->mcspiIoPrms.numPackets = UTILS_MCSPI_NUM_BUFS + 1U;
    
            commHndl->deviceIdx = (UInt32) deviceId;
    
            commHndl->mcspiHandle = (GIO_Handle) GIO_create(
                (xdc_String) gMcspiDriverNames[mcSpiDevInstNum], (UInt32) GIO_INOUT,
                &commHndl->mcspiIoPrms, &eb);
            if (commHndl->mcspiHandle == NULL)
            {
                Vps_printf(" UTILS_MCSPI: McSPI GIO Create Failed!!\r\n");
            }
            returnHandle = (void*) commHndl;
        }
        else
        {
            returnHandle = NULL;
        }
        return returnHandle;
    }
    
    /**
     *******************************************************************************
     *
     * \brief  Close the McSPI Device Handle
     *
     * \param fd    Pointer to the McSPI commnication Handle.
     *
     * \return  SYSTEM_LINK_STATUS_SOK
     *
     *******************************************************************************
     */
    Int32 Utils_mcspiClose(void * fd)
    {
        Utils_mcspiCommHandle commHndl = (Utils_mcspiCommHandle) fd;
        GIO_delete((GIO_Handle *) &commHndl->mcspiHandle);
        return SYSTEM_LINK_STATUS_SOK;
    }
    
    /**
     *******************************************************************************
     *
     * \brief  Function to read from the McSPI device
     *
     * \param fd    Pointer to the McSPI commnication Handle.
     * \param pBuff Pointer to the buffer to which the data is written.
     * \param len   Number of bytes to read.
     *
     * \return  SYSTEM_LINK_STATUS_SOK if operation successful,
     *          SYSTEM_LINK_STATUS_EFAIL otherwise.
     *
     *******************************************************************************
     */
    Int32 Utils_mcspiRead(void * fd, UInt8 *pBuff, UInt16 len)
    {
        UInt32                    size             = 0U;
        Int                       status           = IOM_COMPLETED;
        Mcspi_DataParam           issueDataparam   = {0};
        Mcspi_DataParam           reclaimDataparam = {0};
        Ptr                       pReclaimDataParam;
        Int32                     retVal   = SYSTEM_LINK_STATUS_SOK;
        Utils_mcspiCommHandle commHndl = (Utils_mcspiCommHandle) fd;
        Mcspi_FifoTrigLvl         fifoLevel;
    
        issueDataparam.inBuffer = (UInt8 *) pBuff;
        issueDataparam.bufLen   = (UInt32) len;
        if ((UInt32)len > 0x1000U)
        {
            /* Something is wrong if this condition is met */
            Vps_printf(" UTILS_MCSPI: Too large read requested!! Length = %x\r\n",
                      (UInt32)len);
            retVal = SYSTEM_LINK_STATUS_EFAIL;
        }
        if (retVal == SYSTEM_LINK_STATUS_SOK)
        {
            if (len < (UInt16)32)
            {
                 fifoLevel.rxTriggerLvl = len;
                 fifoLevel.txTriggerLvl = len;
            }
            else
            {
                 fifoLevel.rxTriggerLvl = 32;
                 fifoLevel.txTriggerLvl = 32;
            }
            issueDataparam.outBuffer = NULL;
            size = (UInt32)len;
    
            status = GIO_control(commHndl->mcspiHandle, IOCTL_MCSPI_SET_TRIGGER_LVL,
                                 &fifoLevel);
    
    //        Vps_printf("(1)IOM_COMPLETED:%d, status:%d\n", IOM_COMPLETED, status);
    
            if (IOM_COMPLETED == status)
            {
                /* Issue the first & second empty buffers to the input stream */
                status = GIO_issue(commHndl->mcspiHandle, &issueDataparam, size,
                                   NULL);
            }
    
            if ((status != IOM_PENDING) && (status != IOM_COMPLETED))
            {
                Vps_printf(" UTILS_MCSPI: Failed to issue empty buffer to stream!!\r\n");
            }
            /* Reclaim is done after every issue and buffers are not primed. If
             * the buffers are primed next transfer is initialized as soon as
             * the first one is completed. We wont be able to ensure transfer
             * initializaton on Slave before master for second buffer
             */
            pReclaimDataParam = (Ptr) & reclaimDataparam;
            status =
                GIO_reclaim((GIO_Object *) commHndl->mcspiHandle,
                            (Ptr *) &pReclaimDataParam,
                            NULL,
                            NULL);
    
    
            
    //    #define  IOM_COMPLETED     0       /* I/O completed successfully */
    //    #define  IOM_PENDING       1       /* I/O queued and pending */
    
    //        Vps_printf("(2)IOM_COMPLETED:%d, status:%d\n", IOM_COMPLETED, status);
    
            if (IOM_COMPLETED != status)
            {
                Vps_printf(" UTILS_MCSPI: SPI Read Failed\r\n");
                retVal = SYSTEM_LINK_STATUS_EFAIL;
            }
            else
            {
                retVal = (Int32) len;
            //    Vps_printf("here\n");
            }
        }
        return retVal;
    }
    /**
     *******************************************************************************
     *
     * \brief  Function to write to the McSPI device
     *
     * \param fd    Pointer to the McSPI commnication Handle.
     * \param pBuff Pointer to the buffer to which the data is written.
     * \param len   Number of bytes to read.
     *
     * \return  SYSTEM_LINK_STATUS_SOK if operation successful,
     *          SYSTEM_LINK_STATUS_EFAIL otherwise.
     *
     *******************************************************************************
     */
    Int32 Utils_mcspiWrite(void * fd, UInt8 *pBuff, UInt16 len)
    {
        UInt32                    size             = 0;
        Int                       status           = IOM_COMPLETED;
        Mcspi_DataParam           issueDataparam   = {0};
        Mcspi_DataParam           reclaimDataparam = {0};
        Ptr                       pReclaimDataparam;
        Int32                     retVal   = SYSTEM_LINK_STATUS_SOK;
        Utils_mcspiCommHandle commHndl = (Utils_mcspiCommHandle) fd;
        Mcspi_FifoTrigLvl         fifoLevel;
    
        issueDataparam.outBuffer = (UInt8 *) pBuff;
        issueDataparam.bufLen    = (UInt32) len;
        issueDataparam.inBuffer  = NULL;
        size = (UInt32) len;
    
        if (len < (UInt16)32)
        {
             fifoLevel.rxTriggerLvl = len;
             fifoLevel.txTriggerLvl = len;
        }
        else
        {
             fifoLevel.rxTriggerLvl = 32;
             fifoLevel.txTriggerLvl = 32;
        }
    
        status = GIO_control(commHndl->mcspiHandle, IOCTL_MCSPI_SET_TRIGGER_LVL,
                             &fifoLevel);
        if (IOM_COMPLETED == status)
        {
            /* Issue the first & second empty buffers to the input stream */
            status = GIO_issue(commHndl->mcspiHandle, &issueDataparam, size,
                           NULL);
        }
    
        if ((status != IOM_PENDING) && (status != IOM_COMPLETED))
        {
            Vps_printf(" UTILS_MCSPI: Failed to issue empty buffer to stream!!\r\n");
        }
        /* Reclaim is done after every issue and buffers are not primed. If
         * the buffers are primed next transfer is initialized as soon as
         * the first one is completed. We wont be able to ensure transfer
         * initializaton on Slave before master for second buffer
         */
        pReclaimDataparam = (Ptr) & reclaimDataparam;
        status =
            GIO_reclaim(commHndl->mcspiHandle,
                        (Ptr *) &pReclaimDataparam,
                        NULL,
                        NULL);
    
        if (IOM_COMPLETED != status)
        {
            Vps_printf(" UTILS_MCSPI: SPI Write Failed\r\n");
            retVal = SYSTEM_LINK_STATUS_EFAIL;
        }
        else
        {
            retVal = (Int32) len;
        }
        return retVal;
    }
    
    static void Utils_mcspi0UserInit(void)
    {
        Utils_mcspiUserCommonInit(0U);
    }
    
    static void Utils_mcspi1UserInit(void)
    {
        Utils_mcspiUserCommonInit(1U);
    }
    
    static void Utils_mcspi2UserInit(void)
    {
        Utils_mcspiUserCommonInit(2U);
    }
    
    static void Utils_mcspi3UserInit(void)
    {
        Utils_mcspiUserCommonInit(3U);
    }
    
    static void Utils_mcspiUserCommonInit(uint32_t mcSPINum)
    {
        UInt32       i = 0U;
        static uint32_t done = 0U;
        if (done == 0U)
        {
            Mcspi_init();
            done = 1U;
        }
        memcpy((Void *)&mcspiCfgPrms[mcSPINum], (const Void *)&Mcspi_PARAMS, sizeof(Mcspi_Params));
        /* Set the McSPI parameters */
        mcspiCfgPrms[mcSPINum].instNum = mcSPINum;
        mcspiCfgPrms[mcSPINum].opMode          = MCSPI_OPMODE_INTERRUPT;
        mcspiCfgPrms[mcSPINum].hwiNumber       = 7;
        mcspiCfgPrms[mcSPINum].enableCache     = (UInt32) TRUE;
        mcspiCfgPrms[mcSPINum].edma3EventQueue = 0;
        mcspiCfgPrms[mcSPINum].enableErrIntr   = (UInt32) FALSE;
    #ifdef A15_TARGET_OS_LINUX
        mcspiCfgPrms[mcSPINum].prcmPwrmEnable = FALSE;
    #else
        mcspiCfgPrms[mcSPINum].prcmPwrmEnable = TRUE;
    #endif
        mcspiCfgPrms[mcSPINum].spiHWCfgData.masterOrSlave         = MCSPI_COMMMODE_MASTER;
        mcspiCfgPrms[mcSPINum].spiHWCfgData.singleOrMultiChEnable = MCSPI_SINGLE_CHANNEL;
        mcspiCfgPrms[mcSPINum].spiHWCfgData.pinOpModes    = MCSPI_PINOPMODE_4PIN;
        mcspiCfgPrms[mcSPINum].spiHWCfgData.fifoRxTrigLvl = 32;
        mcspiCfgPrms[mcSPINum].spiHWCfgData.fifoTxTrigLvl = 32;
    
        for (i = 0U; i < CSL_MCSPI_0_NumOfPhyChannels; i++)
        {
            mcspiCfgPrms[mcSPINum].spiHWCfgData.configChfmt[i].charLength = MCSPI_LEN_8BIT;
            mcspiCfgPrms[mcSPINum].spiHWCfgData.configChfmt[i].multiWordAccessEnable =
                (UInt32) FALSE;
            mcspiCfgPrms[mcSPINum].spiHWCfgData.configChfmt[i].spiChipSelectEnablePol =
                (UInt32) FALSE;
            mcspiCfgPrms[mcSPINum].spiHWCfgData.configChfmt[i].clockMode =
                MCSPI_MODE0;
            mcspiCfgPrms[mcSPINum].spiHWCfgData.configChfmt[i].clockRatioExtension = 0;
            mcspiCfgPrms[mcSPINum].spiHWCfgData.configChfmt[i].spiWordInitDelay    =
                MCSPI_NO_DELAY;
            mcspiCfgPrms[mcSPINum].spiHWCfgData.configChfmt[i].trasmitReceiveMode =
                MCSPI_BOTH_RXTX;
            mcspiCfgPrms[mcSPINum].spiHWCfgData.configChfmt[i].granularityEnable =
                (UInt32) TRUE;
    #if defined (TDA3XX_AR12_ALPS)
            /* 8 MHz Bus Frequency */
            mcspiCfgPrms[mcSPINum].spiHWCfgData.configChfmt[i].busFreq           = 1000000;//8000000;
    #else
            /* 24 MHz Bus Frequency */
            mcspiCfgPrms[mcSPINum].spiHWCfgData.configChfmt[i].busFreq           = 1000000;//24000000;
    #endif
            mcspiCfgPrms[mcSPINum].spiHWCfgData.configChfmt[i].spienHighPolarity =
                (UInt32) TRUE;//FALSE;
            mcspiCfgPrms[mcSPINum].spiHWCfgData.configChfmt[i].slaveModeChipSelect =
                MCSPI_SPIEN_0;
    #if defined (BOARD_TDA2XX_CASCADE_RADAR)
            if ((mcSPINum == 2) || (mcSPINum == 3))
            {
                mcspiCfgPrms[mcSPINum].spiHWCfgData.configChfmt[i].spiDat0Dir = MCSPI_IN;
                mcspiCfgPrms[mcSPINum].spiHWCfgData.configChfmt[i].spiDat1Dir = MCSPI_OUT;
            }
            else
            {
                mcspiCfgPrms[mcSPINum].spiHWCfgData.configChfmt[i].spiDat0Dir = MCSPI_OUT;
                mcspiCfgPrms[mcSPINum].spiHWCfgData.configChfmt[i].spiDat1Dir = MCSPI_IN;
            }
    #else
            mcspiCfgPrms[mcSPINum].spiHWCfgData.configChfmt[i].spiDat0Dir = MCSPI_OUT;
            mcspiCfgPrms[mcSPINum].spiHWCfgData.configChfmt[i].spiDat1Dir = MCSPI_IN;
    #endif
        }
    
        if (MCSPI_OPMODE_INTERRUPT == mcspiCfgPrms[mcSPINum].opMode)
        {
            Vps_printf(" UTILS_MCSPI: McSPI is configured in interrupt mode!!\r\n");
        }
    }
    

    Regards,

    Ethan

  • Hi Ethan,

    I now see what you are facing.  Thanks for the scope plots and code file. 

    From the scope plots, I see that you are in fact communicating with the TCAN4550.  The data on the yellow MISO line during your "Utils_mcspiWrite" function is the response from the TCAN4550.  There is no response from the TCAN4550 during your "Utils_mcspiRead" function because you are not writing the "0x41, 0x00, 0x00, 0x01" bytes to it on the MOSI line for the first 4 bytes.  I don't know what your "Select" line is doing between the the Write and Read functions, but I am assuming that is toggling back High after the Write, and then toggles back Low before the Read.  Unfortunately it is not possible to communicate with the TCAN4550 using this separate Write and Read functions.

    I've highlighted the bytes that are important as a Write, and the bytes that are important for a read during this process and to also show you that you are in fact getting data from the TCAN4550.

    You need a combined Write and Read function where you are both writing data on the MOSI line and capturing data simultaneously on the MISO line.  You can either create a new function for this, or try to modify the existing Write and Read functions.  I am not familiar with this particular processor, SDK, or source code files and if you need help writing these functions I may need to forward this thread into the Processor Forum where you can get some more code specific support.

    But here are some suggestions on how to modify the code to work from a general perspective.

    1.) Create a new Write_Read function that simultaneously outputs the TX buffer on the MOSI pin while capturing the data on the MISO pin.  This is my preferred method and how we do it in other processors.  It is important that the SPI Chip Select line transitions Low at the beginning of the packet and then High again at the end of the packet in order for the TCAN4550 to not discard the transaction and set the SPI Error flag.

    2.) Modify the Write function to capture the data on the MISO pin and return this buffer.  It is obvious the Write function is working properly and the TCAN4550 is responding.  We simply need to capture the data on the MISO line.  Then in your application code, to "write" to a register, you need to set byte0 to 0x61, and the last 4 bytes will hold the register data.  When writing to a register using op code 0x61, the rx buffer storing the MISO data is a don't care and can be ignored.  To "read" a register, you need to set byte0 to 0x41, and the last 4 bytes are don't care values or usually 0x00.

    3.) Modify the Read function to write data on the MOSI line just like is done during the Write function.  The end result would be the same as modifying the Write function, but perhaps this is a better option because when you can then leave the write function unchanged because it is working fine as it is. 

    4.) Modify how the SPI Chip Select pin is toggled with regard to the two functions and make a separate function that only toggles this line.  Then you can create a function or combination of the Write function, and Read function using 4 bytes for the write (bytes 0-3) and then 4 bytes for the read (bytes 4-7).  This should work as long as you the Select line remains low during between the read and write functions and only transitions high again at the end of the read function.

    Outside of providing you with the actual lines of modified code, does this make the situation clear about what the problem is and the approach that needs to be taken to correct it?

    Regards,

    Jonathan

  • Hi Jonathan,

    Thank you so much for detailed analysis and suggestions.
    I understand the problem I am facing now.
    I think I need more specific supports about modifing code(Processor SDK, Version 03.07.00) on D3-TDA3xx-rvp.
    Could you help me forward this thread into the Processor Forum, please?

    Regards,

    Ethan

  • Hi Ethan,

    You're welcome.  I am glad I could support you from the TCAN4550 perspective.  I wish I could support you more on the processor side, but I feel that is better suited for somebody on that team.  I will work to move this thread to the processor forum and or identify the correct individual to notify.

    If you have any additional questions about the TCAN4550 now, or in the future once you get your communication working, please feel free to reach out to us again on this forum.

    Regards,

    Jonathan

  • Hi,

    I will help you with the processor side for the SPI function the best I can.
    Let me know if you have any specific questions.

    Regards,
    Prasad

  • Hi Prasad,

    Sorry for late reply. I was on vacation last week.

    I have SPI communication problems between D3-TDA3xx-rvp and TCAN4550EVM.
    I have provided test result on Jan 21, 2020. e2e.ti.com/.../3233981

    I used TI provided "Utils_mcspiWrite()" and "Utils_mcspiRead" functions(in utils_mcspi.c), and the procedure shows below.
    According to scope plot, while calling "Utils_mcspiWrite()", the write function seems working.
    However, TCAN4550EVM seems to return messages simultaneously so that the following "Utils_mcspiRead()" can't get response successfully.

    I have no idea how to store response data on D3-TDA3xx-rvp and how to modify code(VisionSDK 03.07.00).
    Could you provide sample code or help me modify VisionSDK 03.07.00 step by step, please?

    software procedure:
    void spi_main()
    {
    UInt32 mcSpiInstNum=1U; // 0U, 1U, 2U, 3U
    EDMA3_DRV_Handle edmaHandle;
    void *gSpiHandle;
    UInt8 i, j;
    UInt8 dataRx[16], dataTx[16];
    int dataTxEleNum=0;
    UInt32 dataLengthTx, dataLengthRx;
    UInt32 val;

    val = HW_RD_REG32(SOC_L4PER_CM_CORE_BASE + CM_L4PER_MCSPI2_CLKCTRL);
    Task_sleep(1000U);
    AppUtils_setBoardMux();

    Utils_mcspiInit(mcSpiInstNum);
    Task_sleep(500);

    edmaHandle = Utils_dmaGetEdma3Hndl(0U);
    Task_sleep(500);

    gSpiHandle = Utils_mcspiOpen( (UInt8)mcSpiInstNum, (UInt8)mcSpiInstNum , 0, edmaHandle);
    Task_sleep(1000);


    memset(dataTx, test, sizeof(dataTx));
    dataTx[0] = 0x41;
    dataTx[1] = 0x00;
    dataTx[2] = 0x00;
    dataTx[3] = 0x01;
    dataTx[4] = 0x00;
    dataTx[5] = 0x00;
    dataTx[6] = 0x00;
    dataTx[7] = 0x00;
    dataLengthTx = Utils_mcspiWrite(gSpiHandle, dataTx, 8U);//send to TCAN4550EVM
    Vps_printf("(B)dataTx[0] = %02X, dataTx[1] = %02X, dataTx[2] = %02X, dataTx[3] = %02X \n", dataTx[0], dataTx[1], dataTx[2], dataTx[3]);
    Vps_printf("(B)dataTx[4] = %02X, dataTx[5] = %02X, dataTx[6] = %02X, dataTx[7] = %02X \n", dataTx[4], dataTx[5], dataTx[6], dataTx[7]);


    dataLengthRx = 0;
    memset(dataRx, 0x00, sizeof(dataRx));
    dataLengthRx = Utils_mcspiRead(gSpiHandle, dataRx, 8U);//try to receive return messages from TCAN4550EVM
    Vps_printf("(A)dataRx[0] = %02X, dataRx[1] = %02X, dataRx[2] = %02X, dataRx[3] = %02X \n", dataRx[0], dataRx[1], dataRx[2], dataRx[3]);
    Vps_printf("(A)dataRx[4] = %02X, dataRx[5] = %02X, dataRx[6] = %02X, dataRx[7] = %02X \n", dataRx[4], dataRx[5], dataRx[6], dataRx[7]);

    if(dataLengthRx != 8U)
    Vps_printf("data Length error %d\n",dataLengthRx);


    Utils_mcspiClose(gSpiHandle);
    Vps_printf("=== spi 555\n");

    Utils_mcspiDeinit(mcSpiInstNum);
    }

    Regards,

    Ethan

  • Hi,

    McSPI always works in the full duplex mode but the utils APIs are written for a specific use case.
    Where write will not read anything coming on the Rx line.
    Similarly Read will send Null (0) along with the SPI clock cycles and reads the data coming on Rx lines.
    If the SPI communication you need is similar to this you can use this Utils function.
    Otherwise you may need to modify the utils function.

    The Utils_mcspiWrite and Utils_mcspiRead APIs internally calls the UART drivers APIs.
    The underlying driver APIs are implemented to be full duplex and take Tx and Rx buffer both for a transaction.
    You can use this to get the desired McSPI communication.

    Regards,
    Prasad

  • Hi,

    I have solved this problem by setting an array for inBuffer in Utils_mcspiWrite.
    Thanks for your help and suggestions.

    Regards,
    Ethan