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.

IWR1443: IWR as spi slave transmitting more than 64 bytes

Part Number: IWR1443
Other Parts Discussed in Thread: MMWAVE-SDK

Hi,

I am trying to use an IWR1443 as a spi slave connected to an MSP430 which is serving as the master. I have gotten it working with the IWR1443 sending 64 byte packets at a time but I would like to be able to read out a longer list of objects all at once. Currently reading all the detected objects requires reading out 20 separate 64 byte packets.

The mmwave sdk documentation for v 2.01.00.04 for the spi module has a mention of a MIBSPI_RAM_MAX_ELEM which is 64 but it also gives some vague information about transmitting amounts larger than the RAM buffer size as a compile time option.

1. How can I tell if this was enabled as a compile time option in the mmwave SDK and if it is not is there a way I can enable it?

2. Is there a timing diagram that describes how long the SPI master must deactivate the CS/CLK signal to allow transfers?

3. Why can the driver not load the ram buffer as the transaction progresses? Since I am only running my spi bus at 2MHz I would think the IWR processor would be able to keep the SPI module continuously fed with data to transmit?

SPI Code to send 64 bytes

#include <ti/drivers/dma/dma.h>
#include <ti/drivers/gpio/gpio.h>
#include <ti/drivers/pinmux/pinmux.h>
#include <ti/drivers/spi/SPI.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/gates/GateMutex.h>
#include <xdc/runtime/System.h>

// clang-format off
#include <ti/control/mmwavelink/mmwavelink.h>
#include <ti/control/mmwavelink/include/rl_datatypes.h>
#include <ti/control/mmwavelink/include/rl_sensor.h>
// clang-format on

#include "mmw.h"
#include "mmw_spi.h"

uint32_t numberOfDetectedObjects;
MmwDemo_detectedObj objectsToSend[MMW_MAX_OBJ_OUT];
Semaphore_Handle spiOutputDataBufferReady;
uint32_t qformat;
rlRfTempData_t tempData = {0};

typedef struct dssCalibrationData {
    float rangeBias;
    int16_t comps[24];
} dssCalibrationData_t;

dssCalibrationData_t calibrationData;

// Packet format definitions
// 4 byte header
// 5 - 12 byte objects
// 100 objects total -> 20 packets
#define SPI_DATA_PACKET_SIZE 64
#define SPI_PACKETS_PER_FRAME 20
#define SPI_OBJ_PER_PACKET 5
#define PACKET_OBJ_SIZE 60

uint8_t txPlaceholder[1344] = {0x5A};
uint8_t rxPlaceholder[1344] = {0x5A};

void setCalibrationData(MmwDemo_DataPathObj* obj)
{
    calibrationData.rangeBias = obj->cliCommonCfg->compRxChanCfg.rangeBias;
    int32_t i;
    for (i = 0; i < 12; i++)
    {
        calibrationData.comps[(i * 2)] = obj->cliCommonCfg->compRxChanCfg.rxChPhaseComp[i].real;
        calibrationData.comps[(i * 2) + 1] = obj->cliCommonCfg->compRxChanCfg.rxChPhaseComp[i].imag;
    }
    // Semaphore_post(spiOutputDataBufferReady);
}

/**
 *  @b Description
 *  @n
 *      This method copies the detected objects to the buffer used by the SPI
 * task and then notifies the SPI task that the data is ready to be sent
 *
 *  @retval
 *      Not applicable
 */
void setSpiObjectsToSend(MmwDemo_DataPathObj* objects)
{
    static int temperatureCounter = 0;
    temperatureCounter++;
    if (temperatureCounter == 10)
    {
        int32_t retVal;
        retVal = rlRfGetTemperatureReport(RL_DEVICE_MAP_INTERNAL_BSS,
                                          (rlRfTempData_t*)&tempData);

        if (retVal != 0)
        {
            // An error occurred
            System_printf("Error reading temperature\n");
        }
        temperatureCounter = 0;
    }
    memcpy(&objectsToSend, objects->objOut,
           sizeof(MmwDemo_detectedObj) * MMW_MAX_OBJ_OUT);
    numberOfDetectedObjects = objects->numObjOut;
    qformat = objects->xyzOutputQFormat;

    Semaphore_post(spiOutputDataBufferReady);
}



/**
 *  @b Description
 *  @n
 *      This task manages communications over the SPI bus. The IWR1443 behaves
 * as a slave to transmit data to a host processor. The IWR pulls the
 * SPI_HOST_INTR pin low when there is a data packet ready for transmission task
 * and then notifies the SPI task that the data is ready to be sent
 *
 *  @retval
 *      Not applicable
 */
void Spi_CommunicationsTask(UArg arg0, UArg arg1)
{
    Semaphore_Params semParams;
    Semaphore_Params_init(&semParams);
    semParams.mode = Semaphore_Mode_BINARY;
    spiOutputDataBufferReady = Semaphore_create(1, &semParams, NULL);

    // Setup PINMUX for SPIA
    // P6 - SPI_HOST_INTR_1
    // P5 - MISO
    // R8 - MOSI
    // R9 - SPI_CLK
    // R7 - SPI_CS
    Pinmux_Set_OverrideCtrl(SOC_XWR14XX_PINR8_PADAD,
                            PINMUX_OUTEN_RETAIN_HW_CTRL,
                            PINMUX_INPEN_RETAIN_HW_CTRL);
    Pinmux_Set_FuncSel(SOC_XWR14XX_PINR8_PADAD,
                       SOC_XWR14XX_PINR8_PADAD_SPIA_MOSI);

    Pinmux_Set_OverrideCtrl(SOC_XWR14XX_PINP5_PADAE,
                            PINMUX_OUTEN_RETAIN_HW_CTRL,
                            PINMUX_INPEN_RETAIN_HW_CTRL);
    Pinmux_Set_FuncSel(SOC_XWR14XX_PINP5_PADAE,
                       SOC_XWR14XX_PINP5_PADAE_SPIA_MISO);

    Pinmux_Set_OverrideCtrl(SOC_XWR14XX_PINR9_PADAF,
                            PINMUX_OUTEN_RETAIN_HW_CTRL,
                            PINMUX_INPEN_RETAIN_HW_CTRL);
    Pinmux_Set_FuncSel(SOC_XWR14XX_PINR9_PADAF,
                       SOC_XWR14XX_PINR9_PADAF_SPIA_CLK);

    Pinmux_Set_OverrideCtrl(SOC_XWR14XX_PINR7_PADAG,
                            PINMUX_OUTEN_RETAIN_HW_CTRL,
                            PINMUX_INPEN_RETAIN_HW_CTRL);
    Pinmux_Set_FuncSel(SOC_XWR14XX_PINR7_PADAG,
                       SOC_XWR14XX_PINR7_PADAG_SPIA_CS);

    Pinmux_Set_OverrideCtrl(SOC_XWR14XX_PINP6_PADAA,
                            PINMUX_OUTEN_RETAIN_HW_CTRL,
                            PINMUX_INPEN_RETAIN_HW_CTRL);
    Pinmux_Set_FuncSel(SOC_XWR14XX_PINP6_PADAA,
                       SOC_XWR14XX_PINP6_PADAA_GPIO_12);

    GPIO_setConfig(SOC_XWR14XX_GPIO_12, GPIO_CFG_OUTPUT);
    GPIO_write(SOC_XWR14XX_GPIO_12, 1U);

    // Setup the DMA module for the SPI driver to use
    DMA_Params dmaParams;
    DMA_Handle dmaHandle;
    int errCode;
    DMA_init();
    DMA_Params_init(&dmaParams);
    dmaHandle = DMA_open(0, &dmaParams, &errCode);

    // Setup the SPI driver
    SPI_Handle spiHandle;
    SPI_init();
    SPI_Params spiParams;
    SPI_Params_init(&spiParams);
    spiParams.mode = SPI_SLAVE;
    spiParams.frameFormat = SPI_POL0_PHA0;
    spiParams.pinMode = SPI_PINMODE_4PIN_CS;
    spiParams.shiftFormat = SPI_MSB_FIRST;
    spiParams.dmaEnable = 1;
    spiParams.dmaHandle = dmaHandle;
    spiParams.u.slaveParams.dmaCfg.txDmaChanNum = 1U;
    spiParams.u.slaveParams.dmaCfg.rxDmaChanNum = 0U;
    spiParams.u.slaveParams.chipSelect = 0U;
    spiParams.dataSize = 8;
    spiParams.transferTimeout = 50; // Time in system ticks
    spiParams.csHold = 1;
    spiParams.transferMode = SPI_MODE_BLOCKING;

    spiHandle = SPI_open(0, &spiParams);
    if (!spiHandle)
    {
        MmwDemo_debugAssert(0);
        return;
    }
    SPI_Transaction transaction;
    char transmitBuffer[SPI_DATA_PACKET_SIZE];
    char receiveBuffer[SPI_DATA_PACKET_SIZE];
    transaction.count = 1344;
    transaction.txBuf = txPlaceholder;
    transaction.rxBuf = rxPlaceholder;
    transaction.slaveIndex = 0;

    uint16_t frameCount = 0;
    while (1)
    {
        uint8_t packetCount = 0;

        if (Semaphore_pend(spiOutputDataBufferReady, BIOS_WAIT_FOREVER))
        {
            // #define RUN_CALIBRATE
            #ifdef RUN_CALIBRATE
            memset(transmitBuffer, 0, sizeof(transmitBuffer));
            memcpy(transmitBuffer, &calibrationData, sizeof(calibrationData));
            for(packetCount = 0; packetCount <= SPI_PACKETS_PER_FRAME; packetCount++)
            {
                memcpy(transmitBuffer + 3, &calibrationData, sizeof(calibrationData));
                transmitBuffer[2] = packetCount + 1;
                GPIO_write(SOC_XWR14XX_GPIO_12, 0U);
                SPI_transfer(spiHandle, &transaction);
                GPIO_write(SOC_XWR14XX_GPIO_12, 1U);
            }
            #else
            // Clear the buffer since the first memcpy does not write the entire
            // buffer
            memset(transmitBuffer, 0, sizeof(transmitBuffer));
            // Set the frame count
            GPIO_write(SOC_XWR14XX_GPIO_12, 0U);
            SPI_transfer(spiHandle, &transaction);
            GPIO_write(SOC_XWR14XX_GPIO_12, 1U);

            // for (packetCount = 0; packetCount < SPI_PACKETS_PER_FRAME;
            //      packetCount++)
            // {
            //     transmitBuffer[2] = packetCount + 1;
            //     transmitBuffer[3] = numberOfDetectedObjects & 0xFF;
            //     int memIndex = SPI_OBJ_PER_PACKET * packetCount;
            //     memcpy(transmitBuffer + 4, &objectsToSend[memIndex], PACKET_OBJ_SIZE);
            //     GPIO_write(SOC_XWR14XX_GPIO_12, 0U);
            //     SPI_transfer(spiHandle, &transaction);
            //     GPIO_write(SOC_XWR14XX_GPIO_12, 1U);
            // }
            #endif
        }
        frameCount++;
    }
}

SPI Code attempt to send 1344 bytes

#include <ti/drivers/dma/dma.h>
#include <ti/drivers/gpio/gpio.h>
#include <ti/drivers/pinmux/pinmux.h>
#include <ti/drivers/spi/SPI.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/gates/GateMutex.h>
#include <xdc/runtime/System.h>

// clang-format off
#include <ti/control/mmwavelink/mmwavelink.h>
#include <ti/control/mmwavelink/include/rl_datatypes.h>
#include <ti/control/mmwavelink/include/rl_sensor.h>
// clang-format on

#include "mmw.h"
#include "mmw_spi.h"

uint32_t numberOfDetectedObjects;
MmwDemo_detectedObj objectsToSend[MMW_MAX_OBJ_OUT];
Semaphore_Handle spiOutputDataBufferReady;
uint32_t qformat;
rlRfTempData_t tempData = {0};

typedef struct dssCalibrationData {
    float rangeBias;
    int16_t comps[24];
} dssCalibrationData_t;

dssCalibrationData_t calibrationData;

// Packet format definitions
// 4 byte header
// 5 - 12 byte objects
// 100 objects total -> 20 packets
#define SPI_DATA_PACKET_SIZE 64
#define SPI_PACKETS_PER_FRAME 20
#define SPI_OBJ_PER_PACKET 5
#define PACKET_OBJ_SIZE 60

uint8_t txPlaceholder[1344] = {0x5A};
uint8_t rxPlaceholder[1344] = {0x5A};

void setCalibrationData(MmwDemo_DataPathObj* obj)
{
    calibrationData.rangeBias = obj->cliCommonCfg->compRxChanCfg.rangeBias;
    int32_t i;
    for (i = 0; i < 12; i++)
    {
        calibrationData.comps[(i * 2)] = obj->cliCommonCfg->compRxChanCfg.rxChPhaseComp[i].real;
        calibrationData.comps[(i * 2) + 1] = obj->cliCommonCfg->compRxChanCfg.rxChPhaseComp[i].imag;
    }
    // Semaphore_post(spiOutputDataBufferReady);
}

/**
 *  @b Description
 *  @n
 *      This method copies the detected objects to the buffer used by the SPI
 * task and then notifies the SPI task that the data is ready to be sent
 *
 *  @retval
 *      Not applicable
 */
void setSpiObjectsToSend(MmwDemo_DataPathObj* objects)
{
    static int temperatureCounter = 0;
    temperatureCounter++;
    if (temperatureCounter == 10)
    {
        int32_t retVal;
        retVal = rlRfGetTemperatureReport(RL_DEVICE_MAP_INTERNAL_BSS,
                                          (rlRfTempData_t*)&tempData);

        if (retVal != 0)
        {
            // An error occurred
            System_printf("Error reading temperature\n");
        }
        temperatureCounter = 0;
    }
    memcpy(&objectsToSend, objects->objOut,
           sizeof(MmwDemo_detectedObj) * MMW_MAX_OBJ_OUT);
    numberOfDetectedObjects = objects->numObjOut;
    qformat = objects->xyzOutputQFormat;

    Semaphore_post(spiOutputDataBufferReady);
}



/**
 *  @b Description
 *  @n
 *      This task manages communications over the SPI bus. The IWR1443 behaves
 * as a slave to transmit data to a host processor. The IWR pulls the
 * SPI_HOST_INTR pin low when there is a data packet ready for transmission task
 * and then notifies the SPI task that the data is ready to be sent
 *
 *  @retval
 *      Not applicable
 */
void Spi_CommunicationsTask(UArg arg0, UArg arg1)
{
    Semaphore_Params semParams;
    Semaphore_Params_init(&semParams);
    semParams.mode = Semaphore_Mode_BINARY;
    spiOutputDataBufferReady = Semaphore_create(1, &semParams, NULL);

    // Setup PINMUX for SPIA
    // P6 - SPI_HOST_INTR_1
    // P5 - MISO
    // R8 - MOSI
    // R9 - SPI_CLK
    // R7 - SPI_CS
    Pinmux_Set_OverrideCtrl(SOC_XWR14XX_PINR8_PADAD,
                            PINMUX_OUTEN_RETAIN_HW_CTRL,
                            PINMUX_INPEN_RETAIN_HW_CTRL);
    Pinmux_Set_FuncSel(SOC_XWR14XX_PINR8_PADAD,
                       SOC_XWR14XX_PINR8_PADAD_SPIA_MOSI);

    Pinmux_Set_OverrideCtrl(SOC_XWR14XX_PINP5_PADAE,
                            PINMUX_OUTEN_RETAIN_HW_CTRL,
                            PINMUX_INPEN_RETAIN_HW_CTRL);
    Pinmux_Set_FuncSel(SOC_XWR14XX_PINP5_PADAE,
                       SOC_XWR14XX_PINP5_PADAE_SPIA_MISO);

    Pinmux_Set_OverrideCtrl(SOC_XWR14XX_PINR9_PADAF,
                            PINMUX_OUTEN_RETAIN_HW_CTRL,
                            PINMUX_INPEN_RETAIN_HW_CTRL);
    Pinmux_Set_FuncSel(SOC_XWR14XX_PINR9_PADAF,
                       SOC_XWR14XX_PINR9_PADAF_SPIA_CLK);

    Pinmux_Set_OverrideCtrl(SOC_XWR14XX_PINR7_PADAG,
                            PINMUX_OUTEN_RETAIN_HW_CTRL,
                            PINMUX_INPEN_RETAIN_HW_CTRL);
    Pinmux_Set_FuncSel(SOC_XWR14XX_PINR7_PADAG,
                       SOC_XWR14XX_PINR7_PADAG_SPIA_CS);

    Pinmux_Set_OverrideCtrl(SOC_XWR14XX_PINP6_PADAA,
                            PINMUX_OUTEN_RETAIN_HW_CTRL,
                            PINMUX_INPEN_RETAIN_HW_CTRL);
    Pinmux_Set_FuncSel(SOC_XWR14XX_PINP6_PADAA,
                       SOC_XWR14XX_PINP6_PADAA_GPIO_12);

    GPIO_setConfig(SOC_XWR14XX_GPIO_12, GPIO_CFG_OUTPUT);
    GPIO_write(SOC_XWR14XX_GPIO_12, 1U);

    // Setup the DMA module for the SPI driver to use
    DMA_Params dmaParams;
    DMA_Handle dmaHandle;
    int errCode;
    DMA_init();
    DMA_Params_init(&dmaParams);
    dmaHandle = DMA_open(0, &dmaParams, &errCode);

    // Setup the SPI driver
    SPI_Handle spiHandle;
    SPI_init();
    SPI_Params spiParams;
    SPI_Params_init(&spiParams);
    spiParams.mode = SPI_SLAVE;
    spiParams.frameFormat = SPI_POL0_PHA0;
    spiParams.pinMode = SPI_PINMODE_4PIN_CS;
    spiParams.shiftFormat = SPI_MSB_FIRST;
    spiParams.dmaEnable = 1;
    spiParams.dmaHandle = dmaHandle;
    spiParams.u.slaveParams.dmaCfg.txDmaChanNum = 1U;
    spiParams.u.slaveParams.dmaCfg.rxDmaChanNum = 0U;
    spiParams.u.slaveParams.chipSelect = 0U;
    spiParams.dataSize = 8;
    spiParams.transferTimeout = 50; // Time in system ticks
    spiParams.csHold = 1;
    spiParams.transferMode = SPI_MODE_BLOCKING;

    spiHandle = SPI_open(0, &spiParams);
    if (!spiHandle)
    {
        MmwDemo_debugAssert(0);
        return;
    }
    SPI_Transaction transaction;
    char transmitBuffer[SPI_DATA_PACKET_SIZE];
    char receiveBuffer[SPI_DATA_PACKET_SIZE];
    transaction.count = 1344;
    transaction.txBuf = txPlaceholder;
    transaction.rxBuf = rxPlaceholder;
    transaction.slaveIndex = 0;

    uint16_t frameCount = 0;
    while (1)
    {
        uint8_t packetCount = 0;

        if (Semaphore_pend(spiOutputDataBufferReady, BIOS_WAIT_FOREVER))
        {
            // #define RUN_CALIBRATE
            #ifdef RUN_CALIBRATE
            memset(transmitBuffer, 0, sizeof(transmitBuffer));
            memcpy(transmitBuffer, &calibrationData, sizeof(calibrationData));
            for(packetCount = 0; packetCount <= SPI_PACKETS_PER_FRAME; packetCount++)
            {
                memcpy(transmitBuffer + 3, &calibrationData, sizeof(calibrationData));
                transmitBuffer[2] = packetCount + 1;
                GPIO_write(SOC_XWR14XX_GPIO_12, 0U);
                SPI_transfer(spiHandle, &transaction);
                GPIO_write(SOC_XWR14XX_GPIO_12, 1U);
            }
            #else
            // Clear the buffer since the first memcpy does not write the entire
            // buffer
            memset(transmitBuffer, 0, sizeof(transmitBuffer));
            // Set the frame count
            GPIO_write(SOC_XWR14XX_GPIO_12, 0U);
            SPI_transfer(spiHandle, &transaction);
            GPIO_write(SOC_XWR14XX_GPIO_12, 1U);

            // for (packetCount = 0; packetCount < SPI_PACKETS_PER_FRAME;
            //      packetCount++)
            // {
            //     transmitBuffer[2] = packetCount + 1;
            //     transmitBuffer[3] = numberOfDetectedObjects & 0xFF;
            //     int memIndex = SPI_OBJ_PER_PACKET * packetCount;
            //     memcpy(transmitBuffer + 4, &objectsToSend[memIndex], PACKET_OBJ_SIZE);
            //     GPIO_write(SOC_XWR14XX_GPIO_12, 0U);
            //     SPI_transfer(spiHandle, &transaction);
            //     GPIO_write(SOC_XWR14XX_GPIO_12, 1U);
            // }
            #endif
        }
        frameCount++;
    }
}

  • Hi Kevin,

    We will need a few days to look in to this, we should have an answer for you by the end of the week.

    In the meantime I'd invite you to look at the SPI doxyen in the mmWave-SDK folder, C:\ti\mmwave_sdk_02_01_00_04\packages\ti\drivers\spi\docs\doxygen\html\index.html

    Cheers,

    Akash

  • Hi Akash,

    I have looked at the SPI doxygen, that was where the notes about the MIBSPI_RAM_MAX_ELEM and the compile option was located.

    I am looking forward to your update.

    Thanks,

    Kevin

  • Hi Kevin,

    Please find the itemized response below:

    1. The compile option to support multi icount in one transfer to achieve high throughput is SPI_MULT_ICOUNT_SUPPORT. It  is not enabled by default. You can enable it by uncommenting it in ~/ti/drivers/spi/src/mibspi_dma.c and re-compile. Please note that it has limitations and not supported for all SPI mode.

    2. This is for XWR1xx device as master, but you can use it as reference. Section  23.2.6.4 of TRM @http://www.ti.com/lit/pdf/swru522

    3. This was not a requirement during driver development. Will look into adding this to future release.

    Let me know if you need additional information.

    Thanks

    Yogesh

    1