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.

AM5716: SPI read func costs too long time

Part Number: AM5716

Hi, TI's experts:

We use a test task, running in dsp(c66) core of AM5716. We call spi read to read 16Bytes, ocmc-ram,non-dma mode, spi bus clock is 12MHz. The func costs 225us. It is too long, could you find out the reason?

cdcb14f323a53ace79481bdbf246084e.png

  • Hello  ,

    Before we can offer our help, could you please state what SW is being used and the version? I am assuming you are using TI RTOS here?

    -Josue

  • Hi,Josue,

    rtos sdk:processor_sdk_rtos_am57xx_6_03_00_106

  • Hi Josue,

    There are two tasks running in the RTOS:
    1. One task is responsible for initializing SPI1 and W5500, and it also sets up a 1ms timer.


    2. Another task waits for the timer interrupt to post a semaphore, and then reads a register from W5500 via SPI1.
    The spi module uses the DMA library: /root/ti/pdk_am57xx_1_0_17/packages/ti/drv/spi/lib/am571x/c66/release/ti.drv.spi.dma.ae6

    The addresses of the TX and RX buffers used by SPI are as follows:

    #define CSL_DSP_OCMC_RAM1_REGS (0x40300000U)
    uint8_t *txBuffer = (uint8_t *) (CSL_DSP_OCMC_RAM1_REGS +0x1000);
    uint8_t *rxBuffer = (uint8_t *) (CSL_DSP_OCMC_RAM1_REGS +0x6000);

  • Lin, 

    I will have to defer your question to our TI_RTOS engineer. Please share your configuration for the C66,. since this is most likely one of the factors.

    Best,

    Josue

  • The code is as follows:

    w5500_spi.c

    #include "w5500_spi.h"
    #include "socket.h"
    #include <ti/drv/spi/soc/SPI_soc.h>
    #ifdef SPI_DMA_ENABLE
    #include <ti/osal/CacheP.h>
    /* EDMA3 Header files */
    #include <ti/sdo/edma3/drv/edma3_drv.h>
    #include <ti/sdo/edma3/rm/edma3_rm.h>
    #include <ti/sdo/edma3/rm/sample/bios6_edma3_rm_sample.h>
    #include <ti/csl/src/ip/edma/V1/edma.h>
    static EDMA3_RM_Handle MCSPIApp_edmaInit(void);
    #endif
    static Semaphore_Handle spiSemaphore;
    SPI_Handle      spiHandle;  /* SPI handle */
    #define W5500_SPI_INDEX   1
    #define w5500_SPI_DEBUG    0
    
    //#define CSL_DSP_OCMC_RAM1_REGS (0x40300000U)
    //tx tx use 0CMC 40301000~4030b000,20K tx and 20K rx
    uint8_t *txBuffer = (uint8_t *) (CSL_DSP_OCMC_RAM1_REGS +0x1000);
    uint8_t *rxBuffer = (uint8_t *) (CSL_DSP_OCMC_RAM1_REGS +0x6000);
    #define ALIGN_128(len) (((len) + 127) & ~127)
    
    void delay_ms(uint32_t ms)
    {
        Task_sleep(ms);
    }
    //spi初始化
    void W5500_SPI_Init(void)
    {
        SPI_Params      spiParams; /* SPI params structure */
    #if w5500_SPI_DEBUG
        SPI_Transaction transaction;     /* SPI transaction structure */
    #endif
        Board_initCfg boardCfg;
        PRINTF("bufflen 0x5000,txbuff addr:%p ,rxbuff addr:%p.", txBuffer, rxBuffer);
        PRINTF("W5500_SPI_Init start !");
        /* Init SPI driver */
        boardCfg = BOARD_INIT_MODULE_CLOCK;
        Board_init(boardCfg);
        PRINTF("spi1 sclk reg:%x ,offset %x +VIRT0:%x !", CSL_MPU_CORE_PAD_IO_REGISTERS_REGS+CSL_CONTROL_CORE_PAD_IO_PAD_SPI1_SCLK, CSL_CONTROL_CORE_PAD_IO_PAD_SPI1_SCLK, VIRT0);
        HW_WR_REG32(CSL_MPU_CORE_PAD_IO_REGISTERS_REGS+CSL_CONTROL_CORE_PAD_IO_PAD_SPI1_SCLK,0x000c0000);
        HW_WR_REG32(CSL_MPU_CORE_PAD_IO_REGISTERS_REGS+CSL_CONTROL_CORE_PAD_IO_PAD_SPI1_D1,0x000c0000);
        HW_WR_REG32(CSL_MPU_CORE_PAD_IO_REGISTERS_REGS+CSL_CONTROL_CORE_PAD_IO_PAD_SPI1_D0,0x000c0000);
        HW_WR_REG32(CSL_MPU_CORE_PAD_IO_REGISTERS_REGS+CSL_CONTROL_CORE_PAD_IO_PAD_SPI1_CS0,0x0002000e);
        HW_WR_REG32(CSL_MPU_CORE_PAD_IO_REGISTERS_REGS+CSL_CONTROL_CORE_PAD_IO_PAD_GPMC_A9,0x0005010e);
        PRINTF("W5500_SPI_Init gpmc_a9:0x%x !", HW_RD_REG32(CSL_MPU_CORE_PAD_IO_REGISTERS_REGS+CSL_CONTROL_CORE_PAD_IO_PAD_GPMC_A9));
        CSL_xbarIrqConfigure(1, CSL_XBAR_INST_DSP1_IRQ_91, CSL_XBAR_MCSPI1_IRQ);
        HW_WR_REG32(0x4A002CBC,0x00240023);//set spi tx/rx irq band to dsp event
        SPI_HWAttrs spi_cfg;
        /* Set the SPI init configurations */
        SPI_socGetInitCfg(0, &spi_cfg);
        /*print spi hw config*/
        PRINTF("spi-cfg, baseAddr:0x%x.", spi_cfg.baseAddr);
        spi_cfg.enableIntr = false;
    #ifdef SPI_DMA_ENABLE
        /* Set the DMA related init config */
        spi_cfg.edmaHandle = MCSPIApp_edmaInit();
        spi_cfg.dmaMode    = TRUE;
    #endif
        /* Get the default SPI init configurations */
        SPI_socSetInitCfg(W5500_SPI_INDEX, &spi_cfg);
        // 创建SPI信号量
        Semaphore_Params semParams;
        Semaphore_Params_init(&semParams);
        semParams.mode = Semaphore_Mode_BINARY;
        spiSemaphore = Semaphore_create(1, &semParams, NULL);
    
        /* Open the Board flash NOR device with the test SPI port
           and use the default SPI configurations */
        SPI_Params_init(&spiParams);
        spiParams.transferMode = SPI_MODE_BLOCKING;
        spiParams.bitRate = 10000000; // max 30MHz
        spiParams.dataSize = 8;
        spiParams.transferTimeout = SemaphoreP_WAIT_FOREVER;
        spiParams.mode = SPI_MASTER;
        spiParams.frameFormat = SPI_POL0_PHA0;
        SPI_init();
        spiHandle = (SPI_Handle)SPI_open(W5500_SPI_INDEX, &spiParams);
        if(spiHandle == NULL)
        {
            PRINTF("\nError opening SPI driver\n");
        }
    #if w5500_SPI_DEBUG
        PRINTF("\n W5500_SPI_Init  status:%d.",transaction.status);
    #endif
    }
    
    void SPI_WriteByte(uint32_t addr, uint8_t data) {
        bool transferOK = false;
    #if w5500_SPI_DEBUG
        PRINTF("SPI_WriteByte addr:0x%4x data:0x%x !", addr, data);
    #endif
        txBuffer[0] = ((addr & 0xFF0000) >> 16);
        txBuffer[1] = ((addr & 0x00FF00) >> 8);
        txBuffer[2] = ((addr & 0x0000FF)|0x04); // Write操作
        txBuffer[3] = data;
        SPI_Transaction transaction;
        transaction.count = 4;
        transaction.txBuf = &txBuffer[0];
        transaction.rxBuf = &txBuffer[0];
        transferOK=SPI_transfer(spiHandle, &transaction);
        if (!transferOK) {
            /* SPI transaction failed */
            PRINTF("SPI_WriteByte SPI_transfer falied !");
        }
    }
    
    uint8_t SPI_ReadByte(uint32_t addr) {
        bool transferOK = false;
    #if w5500_SPI_DEBUG
        PRINTF("SPI_ReadByte addr:0x%4x start !", addr);
    #endif
        txBuffer[0] = ((addr & 0xFF0000) >> 16);
        txBuffer[1] = ((addr & 0xFF00) >> 8);
        txBuffer[2] = ((addr & 0x0000FF)); // Read
        txBuffer[3] = 0x00;
        SPI_Transaction transaction;
        transaction.count = 4;
        transaction.txBuf = &txBuffer[0];
        transaction.rxBuf = &rxBuffer[0];
        transferOK=SPI_transfer(spiHandle, &transaction);
        if (!transferOK) {
            /* SPI transaction failed */
            PRINTF("SPI_ReadByte SPI_transfer falied !");
        }
        return rxBuffer[3];
    }
    
    void W5500_WriteBuffer(uint32_t addr, uint8_t *buf, uint16_t len) {
        bool transferOK = false;
        SPI_Transaction transaction;
        transaction.count = 3 + len;
        memset(txBuffer, 0, transaction.count);
        txBuffer[0] = ((addr & 0xFF0000) >> 16);//(addr >> 8) & 0xFF;
        txBuffer[1] = ((addr & 0x00FF00) >> 8);//addr & 0xFF;
        txBuffer[2] = ((addr & 0x0000FF)|0x04);//0x04;//0x80; // Write操作
        memcpy(txBuffer + 3, buf, len);
        transaction.txBuf = &txBuffer[0];
        transaction.rxBuf = &rxBuffer[0];
        transferOK = SPI_transfer(spiHandle, &transaction);
        if (!transferOK) {
            /* SPI transaction failed */
            PRINTF("W5500_WriteBuffer SPI_transfer falied !");
        }
    }
    
    
    void W5500_ReadBuffer(uint32_t addr, uint8_t *buf, uint16_t len) {
        bool transferOK = false;
        SPI_Transaction transaction;
        int start, end;
    
        transaction.count = 3 + len;
        memset(rxBuffer, 0, transaction.count);
        memset(txBuffer, 0, transaction.count);
        txBuffer[0] = ((addr & 0xFF0000) >> 16);
        txBuffer[1] = ((addr & 0xFF00) >> 8);
        txBuffer[2] = ((addr & 0x0000FF)); // Read
    
    #if w5500_SPI_DEBUG
        PRINTF("txHeader:");
        PRINTF("%2x-%2x-%2x", txBuffer[0], txBuffer[1], txBuffer[2]);
    #endif
        transaction.txBuf = &txBuffer[0]; // 前3字节是发送的头
        transaction.rxBuf = &rxBuffer[0]; // 全部接收
        transaction.status = SPI_TRANSFER_STARTED;
    
    #if w5500_SPI_DEBUG
        PRINTF(" W5500_ReadBuffer SPI_transfer start !");
    #endif
        start =Timestamp_get32();
        transferOK = SPI_transfer(spiHandle, &transaction);
        end =Timestamp_get32();
        PRINTF("SPI_transfer,time = %d\n", (end-start)/600);
        if (!transferOK) {
            /* SPI transaction failed */
            PRINTF("W5500_ReadBuffer SPI_transfer falied !");
        }
        // 复制有效数据
        memcpy(buf, rxBuffer+3, len);
    }
    
    void SPI_CrisEnter(void)
    {
        Semaphore_pend(spiSemaphore, BIOS_WAIT_FOREVER);
    }
    
    void SPI_CrisExit(void)
    {
        Semaphore_post(spiSemaphore);
    }
    
    void SPI_CS_Select(void)
    {
        W5500_CS_0();
    }
    
    void SPI_CS_Deselect(void)
    {
        W5500_CS_1();
    }
    
    void W5500_Register(void)
    {
        PRINTF("W5500_Register start !");
        reg_wizchip_cris_cbfunc(SPI_CrisEnter,SPI_CrisExit);
    	reg_wizchip_cs_cbfunc(SPI_CS_Select,SPI_CS_Deselect);
    	reg_wizchip_spi_cbfunc(SPI_ReadByte,SPI_WriteByte);
        reg_wizchip_spi_bf_cbfunc(W5500_ReadBuffer,W5500_WriteBuffer);
    }
    
    void W5500_Reset(void)
    {
        //return;
        PRINTF("W5500_Reset start !");
        W5500_RST_0();
    	delay_ms(10);
    	W5500_RST_1();
    	delay_ms(100);
    }
    
    //配置socket0收发缓存为16KB
    /* Set socket0 send and receive cache to 16KB */
    uint8_t  tx_size[_WIZCHIP_SOCK_NUM_] = {16, 0, 0, 0, 0, 0, 0, 0};
    uint8_t  rx_size[_WIZCHIP_SOCK_NUM_] = {16, 0, 0, 0, 0, 0, 0, 0};
    void W5500_Phy_Init(void)
    {
        PRINTF("W5500_Phy_Init start !");
        wiz_PhyConf phyconf; 
    	phyconf.by = PHY_CONFBY_SW;
        phyconf.duplex = PHY_DUPLEX_FULL;
        phyconf.mode = PHY_MODE_AUTONEGO;
        phyconf.speed = PHY_SPEED_10;
        ctlwizchip(CW_SET_PHYCONF,(void*)&phyconf);
    }
    
    extern Semaphore_Handle w5500_dataSem;
    void w5500CallbackFxn(void)
    {
        //PRINTF("~~~~~~come int ++++++");
        Semaphore_post(w5500_dataSem);
        return;
    }
    
    
    int irq_count;
    int last_time;
    VOID spi_test_irq() {
        //Semaphore_pend(w5500_init_done, BIOS_WAIT_FOREVER); // 阻塞等待信号量
        //Semaphore_post(w5500_init_done);
        //PRINTF("irq,time = %d\n", (Timestamp_get32()-last_time)/600);
        //last_time = Timestamp_get32();
        irq_count++;
        //PRINTF("scott get timer int %d.\n", irq_count);
        Semaphore_post(w5500_dataSem);
    }
    
    void timer6_Init()
    {
        // Configure the timer for 1ms ticks, to get the timer ticks 
        TimerP_Params timerParams;
        TimerP_Status status;
        TimerP_Handle gBspOsalTimerHandle = NULL;
        uint32_t      id = 5; 
    
        TimerP_Params_init(&timerParams);
        timerParams.runMode       = TimerP_RunMode_CONTINUOUS;
        timerParams.startMode     = TimerP_StartMode_USER;
        timerParams.periodType    = TimerP_PeriodType_MICROSECS;
        timerParams.period    = 1000000;
        timerParams.intNum     = 13;
        gBspOsalTimerHandle = TimerP_create(id, (TimerP_Fxn)&spi_test_irq, &timerParams);
        PRINTF("TimerP_create timer %d \n", id);
        if (gBspOsalTimerHandle != NULL)
        {
          status = TimerP_start(gBspOsalTimerHandle);
          if (status != TimerP_OK)
          {
               PRINTF("Err: Coult not start the timer %d \n", id);
          }else {
            PRINTF("Success start the timer %d \n", id);
          }
        }
        else
        {
          PRINTF("Err: Coult not create the timer %d \n", id);
        }
    
    }
    
    
    int W5500_Init(void)
    {
        char id[6];
        GPIO_init();
    	W5500_SPI_Init();
        W5500_Reset();
    	W5500_Register();
    	if(wizchip_init(tx_size, rx_size)!= 0)
    	{
            PRINTF("W5500_Chip_Init failed !");
            return -1;
        }
        ctlwizchip(CW_GET_ID,(void *)id);
        PRINTF("get chipid :%s !", id);
    	W5500_Phy_Init();
        CSL_xbarDspIrqConfigure(1, CSL_XBAR_INST_DSP1_IRQ_55, CSL_XBAR_GPIO1_IRQ_1);
        //CSL_xbarDspIrqConfigure(1, CSL_XBAR_INST_DSP1_IRQ_68, CSL_XBAR_TIMER6_IRQ);
        GPIO_setCallback(SPI1W_INT_INDEX, w5500CallbackFxn);
        GPIO_enableInt(SPI1W_INT_INDEX);
        timer6_Init();
    	return 0;
    }
    
    extern Semaphore_Handle w5500_init_done;
    void spiw5500_mainTaskFxn(UArg arg0, UArg arg1) {
        int ret;
        uint8_t tmp;
        PRINTF("spiw5500_mainTaskFxn start!");
        ret = W5500_Init();
        //enable socket0 resv intr
        setSIMR(0x01); // enable socket0 interrupt
        setSn_IMR(0, 0x1f);//enable resv interrupt functions of socket 0.
    	if(ret!=0)
    	{
    	    PRINTF("W5500 init fail,ret is %d",ret);
    	}
    	else
    	{
    		PRINTF("W5500 init success !");
    	}
        PRINTF("W5500 initialization complete.");
        tmp = getVERSIONR();
        PRINTF("W5500 version %d.", tmp);
        Semaphore_post(w5500_init_done);
        System_flush();
    }
    
    #ifdef SPI_DMA_ENABLE
    EDMA3_RM_Handle gEdmaHandle = NULL;
    /**
     * \brief      Function to initialize the edma driver and get the handle to the
     *             edma driver;
     */
    static EDMA3_RM_Handle MCSPIApp_edmaInit(void)
    {
        EDMA3_DRV_Result edmaResult = EDMA3_DRV_E_INVALID_PARAM;
        uint32_t         edma3Id;
    
        if (gEdmaHandle != NULL)
        {
            return (gEdmaHandle);
        }
    
        edma3Id = 0;
        gEdmaHandle = (EDMA3_RM_Handle)edma3init(edma3Id, &edmaResult);
        if (edmaResult != EDMA3_DRV_SOK)
        {
            /* Report EDMA Error */
            PRINTF("EDMA driver initialization FAIL.");
        }
        else
        {
            PRINTF("EDMA driver initialization PASS.");
        }
        return(gEdmaHandle);
    }
    #endif
    

  • test code:

    void spiw5500_recvtestTaskFxn(UArg arg0, UArg arg1) {
        Semaphore_pend(w5500_init_done, BIOS_WAIT_FOREVER); // 阻塞等待信号量
        set_local_netinfo();

        int start=0;
        int end=0;
        Types_FreqHz freq;
        Timestamp_getFreq(&freq);

        while(1) {
            Semaphore_pend(w5500_dataSem, BIOS_WAIT_FOREVER);
            GPIO_write(16, 1);
            start =Timestamp_get32();
            uint8_t gw[4], sn[4], sip[4];
            //uint8_t mac[6];
            //getSHAR(mac);
            getGAR(gw);  getSUBR(sn);  getSIPR(sip); getGAR(gw);
            end =Timestamp_get32();
            GPIO_write(16, 0);
            PRINTF("timer isr,time = %d,c %d\n", (end-start)/(freq.lo/1000000), irq_count);
    //    PRINTF("MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    //    PRINTF("GW: %d.%d.%d.%d\r\n",  gw[0], gw[1], gw[2], gw[3]);
    //    PRINTF("SN: %d.%d.%d.%d\r\n",  sn[0], sn[1], sn[2], sn[3]);
    //    PRINTF("sip: %d.%d.%d.%d\r\n", sip[0], sip[1], sip[2], sip[3]);
        //Task_sleep(1);
        }
    }
  • Thank you Lin. 

    TI-RTOS engineer should help you soon.

  • HI, zekun,josue,

    The current state is in DMA mode. Reading 4B data takes 69 microseconds at this time, and there are no other tasks running at the same time.


    The goal is to reduce the time for reading 24B data to 50 microseconds, and set the current task to the highest priority so that it is not interrupted by other interrupts or other tasks. Please help check if there is any way to optimize the SPI library.

  • Hi Lin,
    I am working on this issue and I will get back to you.

    Regards,

    Karthik

  • Hi,Karthikeyan S,

     any update?

  • Hi Lin,

    Sorry for the delayed response.

    The goal is to reduce the time for reading 24B data to 50 microseconds, and set the current task to the highest priority so that it is not interrupted by other interrupts or other tasks

    Could you please confirm whether you have tried using polling on the RX path instead of interrupts? If feasible, kindly try the polling approach and let us know the observed timing.

    Regards,

    Karthik