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.

J721EXCPXEVM: SPI3/SPI6 TX: Only first interrupt/SPI message captured in message transmit during callback mode

Part Number: J721EXCPXEVM

Tool/software:

1. DUT: Device in use is the Jacinto J721e EVM carrier board with the GESI board extension.

2. Processor core: I'm developing on the mcu2_1 R5F core.

3. OS: I'm running RTOS for the OS.

4. SDK version: I am currently using only the SDK/PDK (ti-processor-sdk-rtos-j721e-evm-10_01_00_04) for my libraries and calls. Nothing custom as of yet.

5. Hardware setup: I've been testing with both SPI6 and SPI3 for our purposes, using a SPI simulator (Waveshare) to transmit messages. Let's start with the setup for SPI6: On the GESI Motor Control Header, SPI6_CLK is pin 18, SPI6_D0 is pin 14, SPI6_D1 is pin 36, and SPI6_CS1 is pin 30; the simulator is connected on the CLK, D0, D1, to their counterparts and CS0 to the SPI6_CS1. Occasionally, I will hook up digital oscilloscope to the lines to verify the message is being transmitted.

6: Software: I am attaching an example source code with which I can produce the problem. This has a .c file with the SPI setup and instructions; a CMakeLists.txt file is included to show you the build configuration.

#include <stdio.h>
#include <string.h>
#include <ti/osal/osal.h>
#include <ti/drv/sciclient/sciclient.h>

/* TI-RTOS Header files */
#include <ti/drv/spi/soc/SPI_soc.h>
#include <ti/drv/spi/src/SPI_osal.h>
#include <ti/drv/spi/SPI.h>

#include <ti/board/src/j721e_evm/include/board_utils.h>
#include <ti/csl/soc/j721e/src/cslr_soc_baseaddress.h>
#include <ti/csl/soc/j721e/src/cslr_wkup_ctrl_mmr.h>


/** \brief Application stack size */
#define APP_TSK_STACK_MAIN              (0x4000U)
/** \brief Task stack */
static uint8_t  gAppTskStackMain[APP_TSK_STACK_MAIN] __attribute__((aligned(32)));

/* Maximum # of channels per SPI instance */
#define MCSPI_MAX_NUM_CHN       4

/* SPI transfer message definitions */
#define SPI_MSG_LENGTH    8
#define SPI_WORD_SIZE_IN_BITS 8

#define SIZE_TOO_LARGE          (0x1FFFU)

#define MCSPI3_CONFIG_IDX       (3U)
#define MCSPI6_CONFIG_IDX       (6U)

#ifdef __cplusplus
extern "C" {
#endif //__cplusplus

extern void UART_printf(const char *pcString, ...);

#ifdef __cplusplus
}
#endif //__cplusplus

/* Callback mode variables */
SemaphoreP_Params cbSemParams;
SemaphoreP_Handle cbSem[MCSPI_MAX_NUM_CHN] = {NULL, NULL, NULL, NULL};

unsigned char slaveRxBuffer[128] __attribute__ ((aligned (128)));
unsigned char slaveTxBuffer[128] __attribute__ ((aligned (128)));

void MCSPI_initSciclient()
{
    int32_t ret = CSL_PASS;
    Sciclient_ConfigPrms_t        config;

    /* Now reinitialize it as default parameter */
    ret = Sciclient_configPrmsInit(&config);
    if (CSL_PASS != ret)
    {
        UART_printf("Sciclient_configPrmsInit Failed\n");
    }
    else if (CSL_PASS == ret)
    {
        ret = Sciclient_init(&config);
        if (CSL_PASS != ret)
        {
            UART_printf("Sciclient_init Failed\n");
        }
    }
}

/* Callback mode functions */
void SPI_callback(SPI_Handle handle, SPI_Transaction *transaction)
{
    UART_printf("SPI callback data size: %d\n", transaction->count);
    if (transaction->count > SIZE_TOO_LARGE)
    {
        SemaphoreP_post(cbSem[0]);
        return;
    }
    // Print out data received
    UART_printf("Received data: ");
    for (uint32_t i = 0; i < transaction->count; i++)
    {
        UART_printf("%02X ", ((uint8_t*)transaction->rxBuf)[i]);
    }
    UART_printf("\n");
    // uint8_t numToCopy = transaction->count * (SPI_WORD_SIZE_IN_BITS / 8);
    // CircularBuffer_write(&g_rxbuffer, reinterpret_cast<uint8_t*>(transaction->rxBuf), numToCopy);
    SemaphoreP_post(cbSem[0]);
}

void spi_test_slave(void *arg0, void *arg1)
{
    UART_printf("Starting SPI Slave test. \n");
    TaskP_sleepInMsecs(1000);
    uint32_t  terminateXfer = 1;

    SPI_init();

    // == Set up the SPI test for receive ==
    SPI_Handle        spi;
    SPI_Params        spiParams;

    uint32_t instance = MCSPI6_CONFIG_IDX; 
    uint32_t domain = SPI_MCSPI_DOMAIN_MAIN;

    MCSPI_socInit();

    SPI_HWAttrs spi_cfg;
    SPI_socGetInitCfg(domain, instance, &spi_cfg);
    spi_cfg.enableIntr = BTRUE;
    spi_cfg.edmaHandle = NULL;
    spi_cfg.dmaMode    = BFALSE;
    spi_cfg.pinMode    = SPI_PINMODE_4_PIN; // Can use 3-pin mode for slave

    /* Set the SPI init configurations */
    spi_cfg.chNum = 0;
    spi_cfg.chnCfg[0].dataLineCommMode = MCSPI_DATA_LINE_COMM_MODE_1;
    spi_cfg.chnCfg[0].tcs = MCSPI_CS_TCS_0PNT5_CLK;
    spi_cfg.chnCfg[0].trMode = MCSPI_RX_ONLY_MODE;
    spi_cfg.chnCfg[0].enableFIFO = 1; // Enable FIFO for slave

    /* Set interrupt path */
    if(CSL_PASS != MCSPI_configSocIntrPath(instance, &spi_cfg, BTRUE))
    {
        UART_printf("\n Set interrupt path failed! Interrupt number %d\n", spi_cfg.intNum);
    }
    else
    {
        UART_printf("\n The interrupt path has been set with interrupt number %d\n", spi_cfg.intNum);
    }

    /* Set the SPI init configurations */
    SPI_socSetInitCfg(domain, instance, &spi_cfg);

    /* Initialize SPI handle */
    SPI_Params_init(&spiParams);
    spiParams.mode = SPI_SLAVE;
    spiParams.transferMode = SPI_MODE_CALLBACK;
    spiParams.transferCallbackFxn = SPI_callback;
    spiParams.transferTimeout = SemaphoreP_WAIT_FOREVER;
    spiParams.frameFormat = SPI_POL1_PHA0;
    spiParams.dataSize = 8U; // 8 bits
    spiParams.bitRate = 153600; // 153.6kHz

    spi = SPI_open(domain, instance, &spiParams);

    if (NULL == spi)
    {
        UART_printf("Error initializing SPI\n");
        return;
    }

    McSPISetSlaveChipSel(spi_cfg.baseAddr, spi_cfg.chNum, 1); // USE CS1

    uint32_t xfer_len = 8; //SPI_MSG_LENGTH;

    Osal_delay(500);

    // Attempt a transfer
    uintptr_t addrSlaveTxBuf = (uintptr_t)slaveTxBuffer;
    uintptr_t addrSlaveRxBuf = (uintptr_t)slaveRxBuffer;
    bool transferOK = true;

    memset(slaveRxBuffer, 0, sizeof(slaveRxBuffer));
    memset(slaveTxBuffer, 0, sizeof(slaveTxBuffer));
    memcpy(slaveTxBuffer, "TEST1234", 8); // Example data for slave TX
    
    while (1)
    {
        SPI_Transaction   transaction;
        transaction.count = xfer_len;
        transaction.arg = (void *)&terminateXfer;
        transaction.txBuf = (void *)addrSlaveTxBuf;
        transaction.rxBuf = (void *)addrSlaveRxBuf;

        // UART_printf("Transferring...\n");
        transferOK = SPI_transfer((SPI_Handle)spi, &transaction);
        if (!transferOK)
        {
            UART_printf("Error in SPI transfer\n");
        }
        else
        {   
            if (SPI_osalPendLock(cbSem[0], SemaphoreP_WAIT_FOREVER) != SemaphoreP_OK)
            {
                UART_printf("Error in SPI transfer - osalPendLock\n");
            }
        }
    }
}

/*
 *  ======== main ========
 */
 int main(void)
 {
    UART_printf("[UART] spi_test main()\n");

    /*  This should be called before any other OS calls (like Task creation, OS_start, etc..) */
    OS_init();

    /* Call board init functions */
    Board_initCfg boardCfg;
    Board_STATUS  boardStatus;

    /* Initialize the task params */
    TaskP_Params taskParams;
    TaskP_Params_init(&taskParams);

    /* Set the task priority higher than the default priority (1) */
    taskParams.priority     = 2;
    taskParams.stack        = gAppTskStackMain;
    taskParams.stacksize    = sizeof (gAppTskStackMain);

    TaskP_Params taskDataProcess;
    TaskP_Params_init(&taskDataProcess);
    
    TaskP_create(&spi_test_slave, &taskParams);

    // If we run on MCU1_0, we need to setup the SciServer
    // For now, we will set up for MCU2_0, which uses a sciclient
    MCSPI_initSciclient();

    Board_PinmuxConfig_t boardPinmuxCfg;
    Board_pinmuxGetCfg(&boardPinmuxCfg);
    boardPinmuxCfg.autoCfg = BOARD_PINMUX_AUTO;
    boardPinmuxCfg.gesiExp = BOARD_PINMUX_GESI_ICSSG;
    Board_pinmuxSetCfg(&boardPinmuxCfg);

    boardCfg = BOARD_INIT_PINMUX_CONFIG |
               BOARD_INIT_MODULE_CLOCK  |
               BOARD_INIT_UART_STDIO |
               BOARD_INIT_MODULE_CLOCK_MAIN;
    boardStatus = Board_init(boardCfg);

    //-- Enable this for MCSPI3 usage
    // UART_printf("Unlocking MCU_MCSPI1 from MCSPI3\n");
    // /* Unlock lock key registers for MCU Partition 1 */
    // /* write Partition Lock Key 0 Register */
    // CSL_REG32_WR(CSL_MCU_CTRL_MMR0_CFG0_BASE + CSL_MCU_CTRL_MMR_CFG0_LOCK1_KICK0, 0x68EF3490);
    // /* write Partition Lock Key 1 Register */
    // CSL_REG32_WR(CSL_MCU_CTRL_MMR0_CFG0_BASE + CSL_MCU_CTRL_MMR_CFG0_LOCK1_KICK1, 0xD172BC5A);
    // /* Check for unlock */
    // uint32_t regVal = CSL_REG32_RD(CSL_MCU_CTRL_MMR0_CFG0_BASE + CSL_MCU_CTRL_MMR_CFG0_LOCK1_KICK0);
    // while ((regVal & 0x1) != 0x1U)
    // {
    //     regVal = CSL_REG32_RD(CSL_MCU_CTRL_MMR0_CFG0_BASE + CSL_MCU_CTRL_MMR_CFG0_LOCK1_KICK0);
    // }

    // /* Enable MCU_MCSPI1 and MCSPI3 independently pin out */
    // /* MCU_CTRL_MMR0.CTRLMMR_MCU_SPI1_CTRL.SPI1_LINKDIS */
    // CSL_REG32_WR(CSL_MCU_CTRL_MMR0_CFG0_BASE +
    //     CSL_MCU_CTRL_MMR_CFG0_MCU_SPI1_CTRL,
    //         CSL_MCU_CTRL_MMR_CFG0_MCU_SPI1_CTRL_SPI1_LINKDIS_MASK);

    // UART_printf("Unlocking CLK to MCSPI3.\n");
    // /* Unlock lock key registers for MAIN Partition 2 */
    // /* write Partition Lock Key 0 Register */
    // CSL_REG32_WR(CSL_CTRL_MMR0_CFG0_BASE + CSL_MAIN_CTRL_MMR_CFG0_LOCK2_KICK0, 0x68EF3490);
    // /* write Partition Lock Key 1 Register */
    // CSL_REG32_WR(CSL_CTRL_MMR0_CFG0_BASE + CSL_MAIN_CTRL_MMR_CFG0_LOCK2_KICK1, 0xD172BC5A);
    // /* Check for unlock */
    // regVal = CSL_REG32_RD(CSL_CTRL_MMR0_CFG0_BASE + CSL_MAIN_CTRL_MMR_CFG0_LOCK2_KICK0);
    // while ((regVal & 0x1) != 0x1U)
    // {
    //     regVal = CSL_REG32_RD(CSL_CTRL_MMR0_CFG0_BASE + CSL_MAIN_CTRL_MMR_CFG0_LOCK2_KICK0);
    // }

    // /* Set CTRLMMR_SPI3_CLKSEL */
    // // 0x0010819C
    // CSL_REG32_WR(CSL_CTRL_MMR0_CFG0_BASE + CSL_MAIN_CTRL_MMR_CFG0_SPI3_CLKSEL, 0x10000);
    // CSL_REG32_WR(CSL_CTRL_MMR0_CFG0_BASE + CSL_MAIN_CTRL_MMR_CFG0_SPI6_CLKSEL, 0x10000);

    UART_printf("Done.\n");

    // Creates a callback semaphore
    SemaphoreP_Params_init(&cbSemParams);
    cbSemParams.mode = SemaphoreP_Mode_BINARY;
    cbSem[0] = SemaphoreP_create(0, &cbSemParams);

    /* Start the scheduler to start the tasks executing. */
    OS_start();
 }
cmake_minimum_required(VERSION 3.24)

# Set the project name and version
project(spirx VERSION 1.0)

# Use debug or release libs
if(CMAKE_BUILD_TYPE STREQUAL "Release")
    set(BUILD_PROFILE "release")
else()
    set(BUILD_PROFILE "debug")
endif()

if(NOT DEFINED BOARD)
    set(BOARD "j721e_evm")
endif()

# Set the target processor
if(NOT DEFINED TARGET_PROCESSOR)
    set(TARGET_PROCESSOR "r5f")  # Modify this according to your target processor (R5F or A72, etc.)
elseif(NOT "${TARGET_PROCESSOR}" STREQUAL "r5f")
    message(FATAL_ERROR "TARGET_PROCESSOR=${TARGET_PROCESSOR} is not supported for this project.")
endif()

# Set the target core
# mcu1_0 mcu1_1 are no longer supported
set(SUPPORTED_CORES mcu2_0 mcu2_1)
if(NOT DEFINED TARGET_CORE)
    set(TARGET_CORE "mcu2_1")
elseif(NOT "${TARGET_CORE}" IN_LIST SUPPORTED_CORES)
    message(FATAL_ERROR "TARGET_CORE=${TARGET_CORE} not in supported core list.")
endif()

# Append to additional build options
if("${TARGET_CORE}" STREQUAL "mcu2_0")
    set(ADDITIONAL_BUILD_OPTS "${ADDITIONAL_BUILD_OPTS} -DBUILD_MCU2_0 -DBUILD_MCU")
elseif("${TARGET_CORE}" STREQUAL "mcu2_1")
    set(ADDITIONAL_BUILD_OPTS "${ADDITIONAL_BUILD_OPTS} -DBUILD_MCU2_1 -DBUILD_MCU")
endif()

# Specify the C compiler and flags
set(CMAKE_C_COMPILER "$ENV{TI_TOOLCHAIN_PATH}/bin/tiarmclang")
set(CMAKE_CXX_COMPILER "$ENV{TI_TOOLCHAIN_PATH}/bin/tiarmclang")
set(CMAKE_LINKER "$ENV{TI_TOOLCHAIN_PATH}/bin/tiarmclang")
set(LIBC_AR "$ENV{TI_TOOLCHAIN_PATH}/lib/libc.a") 

# Specify the C flags (e.g., optimization, architecture)
set(CMAKE_C_FLAGS "-g -DMAKEFILE_BUILD -fno-strict-aliasing -EL -mfloat-abi=hard -mfpu=vfpv3-d16 -mcpu=cortex-r5 -mthumb -march=thumbv7r -DFREERTOS -DSOC_J721E -Dj721e_evm=j721e_evm ${ADDITIONAL_BUILD_OPTS}")
set(CMAKE_CXX_FLAGS "-DMAKEFILE_BUILD -fno-strict-aliasing -EL -mfloat-abi=hard -mfpu=vfpv3-d16 -mcpu=cortex-r5 -mthumb -march=thumbv7r -DFREERTOS -DSOC_J721E -Dj721e_evm=j721e_evm ${ADDITIONAL_BUILD_OPTS}")

# Set PDK_SOURCE_DIR
if(NOT DEFINED PDK_SOURCE_DIR)
    set(PDK_SOURCE_DIR "$ENV{TI_SDK_PATH}/pdk_jacinto_10_01_00_25")
endif()

set(SPI_LIB "${CMAKE_SOURCE_DIR}/lib/${BUILD_PROFILE}/wx.spi.aer5f")

# Add the include directories for Processor SDK and PDK
include_directories(
    ${PDK_SOURCE_DIR}/packages
    ${CMAKE_CURRENT_SOURCE_DIR}
    ${CMAKE_SOURCE_DIR}/board/src/
    ${CMAKE_SOURCE_DIR}/board/src/j721e_evm/include
    ${CMAKE_CURRENT_SOURCE_DIR}/src/
    ${PDK_SOURCE_DIR}/packages/ti/csl/
    ${PDK_SOURCE_DIR}/packages/ti/csl/arch/r5/
    ${PDK_SOURCE_DIR}/packages/ti/csl/arch/r5/src/startup/
    ${PDK_SOURCE_DIR}/packages/ti/kernel/freertos/config/j721e/r5f/
)

if("${TARGET_CORE}" STREQUAL "mcu2_0" OR "${TARGET_CORE}" STREQUAL "mcu2_1")
    set(ADDITIONAL_LIBS
        "${PDK_SOURCE_DIR}/packages/ti/build/j721e/linker_r5_freertos.lds"
    )
else()
    message(FATAL_ERROR "Core not yet supported.")
endif()

# Add the source files
set(SOURCES
    ${CMAKE_CURRENT_SOURCE_DIR}/main.c
)

# Add the source to the executable
add_executable(${PROJECT_NAME} ${SOURCES})

set(GROUPED_LIBS 
    "${PDK_SOURCE_DIR}/packages/ti/csl/lib/j721e/${TARGET_PROCESSOR}/${BUILD_PROFILE}/ti.csl.aer5f"
    "${PDK_SOURCE_DIR}/packages/ti/drv/uart/lib/j721e/${TARGET_PROCESSOR}/${BUILD_PROFILE}/ti.drv.uart.aer5f"
    "${PDK_SOURCE_DIR}/packages/ti/drv/i2c/lib/j721e/${TARGET_PROCESSOR}/${BUILD_PROFILE}/ti.drv.i2c.aer5f"
    "${PDK_SOURCE_DIR}/packages/ti/drv/udma/lib/j721e/${TARGET_CORE}/${BUILD_PROFILE}/udma.aer5f"
    "${PDK_SOURCE_DIR}/packages/ti/drv/gpio/lib/j721e/${TARGET_PROCESSOR}/${BUILD_PROFILE}/ti.drv.gpio.aer5f"
    "${PDK_SOURCE_DIR}/packages/ti/drv/pmic/lib/j721e_evm/${TARGET_PROCESSOR}/${BUILD_PROFILE}/pmic.aer5f"
    "${PDK_SOURCE_DIR}/packages/ti/drv/pm/lib/j721e/${TARGET_PROCESSOR}/${BUILD_PROFILE}/pm_lib.aer5f"
    "${PDK_SOURCE_DIR}/packages/ti/board/lib/j721e_evm/${TARGET_PROCESSOR}/${BUILD_PROFILE}/ti.board.aer5f"
    # "${CMAKE_SOURCE_DIR}/../../lib/${BUILD_PROFILE}/j721e_board.aer5f"
    "${PDK_SOURCE_DIR}/packages/ti/drv/sciclient/lib/j721e/${TARGET_CORE}/${BUILD_PROFILE}/sciclient.aer5f"
    "${PDK_SOURCE_DIR}/packages/ti/osal/lib/freertos/j721e/${TARGET_PROCESSOR}/${BUILD_PROFILE}/ti.osal.aer5f"
    "${PDK_SOURCE_DIR}/packages/ti/kernel/lib/j721e/${TARGET_CORE}/${BUILD_PROFILE}/ti.kernel.freertos.aer5f"
    "${PDK_SOURCE_DIR}/packages/ti/csl/lib/j721e/${TARGET_PROCESSOR}/${BUILD_PROFILE}/ti.csl.init.aer5f"
    "${PDK_SOURCE_DIR}/packages/ti/drv/spi/lib/j721e/r5f/${BUILD_PROFILE}/ti.drv.spi.aer5f"
    # "${CMAKE_SOURCE_DIR}/../../lib/${BUILD_PROFILE}/wx.spi.aer5f"
    "${LIBC_AR}"
)

# Link the necessary libraries (adjust paths to your SDK)
target_link_libraries(${PROJECT_NAME}
    "${ADDITIONAL_LIBS}"
    $<LINK_GROUP:RESCAN, ${GROUPED_LIBS}>
)

# Define the required linker flags (for linking in startup files, etc.)
target_link_options(${PROJECT_NAME} PRIVATE 
    -Werror 
    -Wl,-q 
    -Wl,-u,_c_int00 
    -Wl,--display_error_number 
    -Wl,--use_memcpy=fast 
    -Wl,--use_memset=fast 
    -Wl,--diag_suppress=10063-D 
    -Wl,--diag_suppress=10068-D 
    -Wl,--diag_suppress=10083-D 
    -Wl,-c 
    -mcpu=cortex-r5 
    -march=armv7-r 
    -Wl,--diag_suppress=10230-D  
    -Wl,-x 
    -Wl,--zero_init=on
)

# Set the output directory
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)

# Set the post-build commands (e.g., copy binaries to specific folder)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy ${EXECUTABLE_OUTPUT_PATH}/${PROJECT_NAME} ${CMAKE_SOURCE_DIR}/bin/${BUILD_PROFILE}/${PROJECT_NAME}_${TARGET_PROCESSOR}_${TARGET_CORE}.xer5f
)

Some things of note in these: 

  • SPI6 is being used
  • Interrupts are enabled; callback mode.
  • I've tried both 3-pin mode and 4-pin mode; but currently I have 4-pin mode working again
    • In order to get it working with CS1, McSPISetSlaveChipSel() is used to set the SPIENSLV register to the appropriate value.
  • Channel 0 is being used, since TRM states that this is the only channel supported for RX
  • dataLineCommMode is 1.
  • dataSize is 8 bits, initial transfer length is 8 bytes.
    • There's stuff also being done with a TxBuffer, which only comes into play if we're using TXRX mode
  • Added some code to enable GESI board pinmuxing
  • Optionally have some calls to disconnect MCSPI3 from MCU_SPI1 if we're using that SPI; don't need to get into that for this, as I think I have that figured out.
  • All build options are pulled from the .mk files in the PDK.
  • FIFO is being used.

7/8: Expected behavior/What is happening instead: I send a string of bytes from the simulator via SPI that is longer than 8 bytes. For example: 

b'\x00\x00\x00\x00~\x10\xc1\x90\xa00\x98\x90\x0c\xd0\xa0\x00\x80\xb9\xe7~\x00\x00\x00\x00\x00\x00~\x10\xc1\x90\xa0\xb0\x98\x08th\xc0\x00\x80wR~\x00\x00\x00\x00\x00\x00\x00~\x10\xc1\x90\xa0p\x98\xd0\x18\x84\x80\x00\x80\x91w~\x00\x00\x00\x00\x00\x00\x00\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

I would expect to get the entire byte string, but I do not. Currently with the attached code, I only get the first 8 bytes:

Starting SPI Slave test. 

 The interrupt path has been set with interrupt number 384
SPI callback data size: 8
Received data: 00 00 00 00 7e 10 c1 90

I see that the callback does get called. However, for subsequent transmits, the callback doesn't get called, meaning there is no interrupt? I would expect that the entire first message gets through in 8-byte clumps, and subsequently any messages sent after that would also be sent.

9. Other boards: I have tested similar code on a TVA4VM EVM board, which seemed to work just fine--I was using SPI5 at the time and that board has a CS0 on it's main header.

10. Every boot: Yes, this happens every boot.

11. Diagnosis/Debug:

  • 3-PIN vs. 4-PIN: With CS0 not available on the board, it seemed like the best way to go with what we were trying to do was to try 3-pin; initially, this helped us with getting some of the message through, but upon discovery of the SPIENSLV register, we were able to get CS1 to be the used chip select for 4-pin mode. Either way, we're observing the same thing: early-terminated messages and not receiving any after the first.
  • FIFO enabled vs. disabled: Interestingly, if we disable FIFO usage, we get every interrupt, but none of the data gets through (all 0's). With FIFO enabled, only first 8 bytes as seen in the snippet above.
  • Blocking (polling) vs. Callback: I've altered the attached code slightly to use blocking mode (don't use interrupt, etc.) and in that polling mode, it seems like I'm getting the entire message--which is a workaround, but I don't see it as a solution.
  • Changing the transaction count: If I change this to 16, I get the first 16 bytes, 128 yields 128 bytes; however, the size of the incoming message is not going to be that predictable.
  • Bitrate: Changing this to a faster bitrate does nothing.
  • TX only vs. TX_RX mode: Not much of a difference here. I'm seeing the first message received, and on the simulator side, I get the first message and the contents of the second message; but on the J721e side, only the first message is received and the callback is never called again (no interrupt), so nothing else is sent.
  • DMA vs no DMA: No observable differences. Not planning on using the DMA anyway.

12: Logs/etc.

No logs really, but I do have a register dump for the MCSPI6: 

521177 13
R MCSPI6_CFG_MCSPI_HL_REV 0x0000000B 0x40301A0B
R MCSPI6_CFG_MCSPI_HL_HWINFO 0x0000000B 0x00000009
R MCSPI6_CFG_MCSPI_HL_SYSCONFIG 0x0000000B 0x00000004
R MCSPI6_CFG_MCSPI_REVISION 0x0000000B 0x0000002B
R MCSPI6_CFG_MCSPI_SYSCONFIG 0x0000000B 0x00000308
R MCSPI6_CFG_MCSPI_SYSSTATUS 0x0000000B 0x00000001
R MCSPI6_CFG_MCSPI_IRQSTATUS 0x0000000B 0x00010008
R MCSPI6_CFG_MCSPI_IRQENABLE 0x0000000B 0x00000004
R MCSPI6_CFG_MCSPI_WAKEUPENABLE 0x0000000B 0x00000000
R MCSPI6_CFG_MCSPI_SYST 0x0000000B 0x00000000
R MCSPI6_CFG_MCSPI_MODULCTRL 0x0000000B 0x00000004
R MCSPI6_CFG_MCSPI_CHCONF_0 0x0000000B 0x302113D0
R MCSPI6_CFG_MCSPI_CHSTAT_0 0x0000000B 0x00000043
R MCSPI6_CFG_MCSPI_CHCTRL_0 0x0000000B 0x00001401
R MCSPI6_CFG_MCSPI_TX_0 0x0000000B 0x00000000
R MCSPI6_CFG_MCSPI_RX_0 0x0000000B 0x000000A0
R MCSPI6_CFG_MCSPI_CHCONF_1 0x0000000B 0x00060000
R MCSPI6_CFG_MCSPI_CHSTAT_1 0x0000000B 0x00000000
R MCSPI6_CFG_MCSPI_CHCTRL_1 0x0000000B 0x00000000
R MCSPI6_CFG_MCSPI_TX_1 0x0000000B 0x00000000
R MCSPI6_CFG_MCSPI_RX_1 0x0000000B 0x00000000
R MCSPI6_CFG_MCSPI_CHCONF_2 0x0000000B 0x00060000
R MCSPI6_CFG_MCSPI_CHSTAT_2 0x0000000B 0x00000000
R MCSPI6_CFG_MCSPI_CHCTRL_2 0x0000000B 0x00000000
R MCSPI6_CFG_MCSPI_TX_2 0x0000000B 0x00000000
R MCSPI6_CFG_MCSPI_RX_2 0x0000000B 0x00000000
R MCSPI6_CFG_MCSPI_CHCONF_3 0x0000000B 0x00060000
R MCSPI6_CFG_MCSPI_CHSTAT_3 0x0000000B 0x00000000
R MCSPI6_CFG_MCSPI_CHCTRL_3 0x0000000B 0x00000000
R MCSPI6_CFG_MCSPI_TX_3 0x0000000B 0x00000000
R MCSPI6_CFG_MCSPI_RX_3 0x0000000B 0x00000000
R MCSPI6_CFG_MCSPI_XFERLEVEL 0x0000000B 0x00080700
R MCSPI6_CFG_MCSPI_DAFTX 0x0000000B 0x00000000
R MCSPI6_CFG_MCSPI_DAFRX 0x0000000B 0x00000000

In summary: I expect repeated interrupts for long messages and reoccurring interrupts for subsequent messages, but I'm not seeing that happen. Is this a limitation of the EVM+GESI board we are using? Am I making a bad assumption in my code on how the SPI works?

  • Hello Tyler,

    SPI6 is connected as slave to your simulator(master).

      • In order to get it working with CS1, McSPISetSlaveChipSel() is used to set the SPIENSLV register to the appropriate value.
    • Channel 0 is being used, since TRM states that this is the only channel supported for RX

    Good.

    In slave mode, Only channel 0 can be configured as a slave but through the [22-21] SPIENSLV bit field any of the SPIEN[i] signals can be used to select the MCSPI module. In slave mode and when the [1] PIN34 is set to 0x0 , the MCSPI uses the edge of SPIEN[i] to detect word length. For this reason, SPIEN[i] must become inactive between each word.

    Changing the transaction count: If I change this to 16, I get the first 16 bytes, 128 yields 128 bytes; however, the size of the incoming message is not going to be that predictable.

    In call back mode transaction count should be known to prior to receive.  This is needed in SPI .Whereas in blocking mode this will keep on polling the messages

    Even on SPI5 it should be the same scenario.

    Regards

    Tarun Mukesh

  • In call back mode transaction count should be known to prior to receive.

    Sure, that makes sense. Still, if I break up the incoming message into 8 bytes each, so it's multiple transfers, it only completes the first transfer.

  • Hello,

    I will be on leave till Monday. Please expect delay in response.

    Regards 

    Tarun Mukesh 

  • Hello,

    For Multi word transfers then SPIEN should toggle between each SPI word. The falling and raising edges usually detects the start and end of word.

    Is the external Master de-asserting the SPIEN between each multiword transfer ?

    Can you share the logic analyzer snippets ?

    Regards

    Tarun Mukesh