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.

MCU-PLUS-SDK-AM243X: MCSPI peripheral mode, how to check received dataes length

Part Number: MCU-PLUS-SDK-AM243X
Other Parts Discussed in Thread: AM2434

Tool/software:

Hi Experts,

     With SDK10, AM2434ALV EVM Board. My scenario is as follows:

     The EVM MCSPI as spi slave(peripheral) communicate with another module. The slave does know the length from the host each time, but the slave needs to synchronously send specific data (such as 0xAA 0xAA ... 0xAA) when the host send request data. So I used a GPIO to monitor the status of host CS  Pin status, and presend a maximum length of 0xAA through MCSPI_transfer() before the host transmitting (MCSPI  mode: interrupt and callback). When the GPIO/CS Pin rising edge interrupt is triggered, it is considered that completed the transmission, and then the slave parsed all received data and response.  My questions:

     1. How do I know how many bytes have actually been received?

     2. Whether the data within txfifo  that not sent out  need to be manually cleared to avoid affecting the subsequent transmission of valid data? And how to clear if need.

        

     

  • Hello,

    I am requesting you to go through this: https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1305146/sk-am64b-r5f-spi-dma-in-mcspi_ms_mode_peripheral/5064289#5064289

    . How do I know how many bytes have actually been received?

    This can be found out buy checking the the MCSPI RX Register. Have you tried looking into it?

    Regards,

    Vaibhav

  • Hi Vaibhav,

         The example you provide is suitable for the slave to know in advance how many byes the host will send. But for my scenariois, data length is unknown. For example, the host maybe send a package include 5 bytes ,7bytes or 10 bytes. In order to be compatible with both scenarios, the slave needs to fill 10 bytes 0xAA into txfifo in advance. When a communication is just 7bytes, there are 3byte left in the txfifo of the slave at end of the communication, and the SPI interupt will not be triggered because not all 10bytes have been sent.

        And MCSPI RX Register store the received data, not the length. I guess  maybe the MCSPI_CHSTAT register is appropriate, but I haven't tried that yet.

  • Hello,

    Please expect delayed responses as I am involved in a high priority debug.

    Thanks for your patience.

    Regards,

    Vaibhav

  • Hi, liang luo:
    1.

    is your data expected has concept of timing:  eg:  when your slave send  5 bytes ,7bytes or 10 bytes,  they come consecutively.   between each bytes will be 100 nano second.  then there is a interval for about  > 1 millisecond is consider to be another packet. ,  

    eg:

    x <-zns->x <-zns-> x<-zns->  x<-zns->  x <- y millisecond -> x x x x x x  (7 bytes)

    red part is 5 bytes packet,   blue is 7 bytes.  x is data it self.   z is nano second interval.  y is millisecond interval?

    2. are you able to programing slave, is possible that slave drive a pin high, pin low for indication of completion of data?

    Thanks.

  • Hi Jun, yes, that's the way it works.

        Now I have found a solution:

       Configure RXFIFO to 2, which can trigger SPI ISR every 2 bytes, so that the received length can be obtained indirectly through gMcspiConfig[0].object->mcspiLldInitObj[0].curRxBufPtr, then check CHSTAT register to confirm whether there is still a byte in the FIFO.

       I used a gpio stub to the CS pin  to monitor the end of communication. Not sure if the CS0 on the AM243X can be used for SPI CS and IO interrupt at the same time, can you help to confirm?

       In addition, I found that the  remaining data in the txfifo need to be manually cleared after communication is completed. And currently, I can only clear it by reinitilizing MCSPI, is there an earier way?

  • CS0 on the AM243X can be used for SPI CS and IO interrupt at the same time, can you help to confirm?

    I am sure pretty it can't be used for SPI CS and IO interrupt at the same time. 

    Reason:   IO interrupt means gpio input,   SPI CS means gpio output. 


    (However, you can dynamic configuration of pin.)  the pin is configurable, if you config to pin mode(7), it means gpio_42. 
    when you send, you config the pin to the pin mode0.  when you want to receive, you config it to input pin , pin mocd 7

  • Hi Jun, my question is based on spi configuration as slave.

         

  • Thanks for clarify, if your spi is a slave, then, I don't think there is any problem. your cs is configured as input pin already.  Let's wait for .

  • Hello,

    Jun, thanks for clarifying some of the doubts.

    Not sure if the CS0 on the AM243X can be used for SPI CS and IO interrupt at the same time, can you help to confirm?

    It is a good practise to use the CS0 pin for just SPI_CS even if the SPI is configured as a slave.

    Regards,

    Vaibhav

  • Hi Vaibhav,

         Update a possible bug.

         Recently, I did some worst-case test. Config AM2434 as SPI SLAVE, if the length of data prefilled through MCSPI_transfer() is less than the SPI HOST send, a system exception will be triggered.

     1) SPI Interrupt is not automatically cleared and will repeatedly enter ISR: MCSPI_lld_peripheralIsr(). 

    2) If clearing MCSPI->IRQSTATUS in callback funciton,  after some error triggered, soc will keep looping within the following assemble code, and can't exit through modify mcspi registers.Why?

      

    3) Clearing MCSPI->IRQENABLE in the callback function, there issue can be solved. I think this issue maybe belong to a SDK BUG.

  • Recently, I did some worst-case test. Config AM2434 as SPI SLAVE, if the length of data prefilled through MCSPI_transfer() is less than the SPI HOST send

    Thanks for carrying out this test.

    Can you please correct my understanding of what you just mentioned?

    So while declaring MCSPI transfer for slave, you have written some value in field count(lets say x) and the Master sends y amount of data.

    If x < y, then issue occurs, else if x = y then issue does not occurs?

    Regards,

    Vaibhav

  • Hello,

    So, this is pretty valid right?

    Imagine my controller on the SoC, is about to communicate with the slave, and I want to gather information about a basic "WHO AM I" register from any slave part.

    So in this case, if the slave is expecting a count of 1 and lets say an 8 bit command, then that is what I am going to send, in this case, if I send a count of anything less than 1, that would lead to slave not responding back with the value of the "WHO AM I" register.

    So, top level, I would say that this is an expected behaviour.

    Please correct my understanding if you feel like you have additional points, please do let me know.

    Thanks,

    Vaibhav

  • As a spi slave in my example, I assume that the host will send a maximum of 10 bytes next. To receive these 10 bytes of data, I called MCSPI_transfer() function with length=10 in advance. In fact, the host sends 12 or 20 bytes or more in one communication, and the issue then recurs.

    You can try to replicate it, if not, I'll try to show you some example code tomorrow.

  • This is a simple example code that can trigger the issue. 

    With the EVM board.

    1. Import the example project: mcspi_loopback_am243x-evm_r5fss0-0

    2. Modify SPI configuration as the below picture

    3. Add a GPIO Interrupt(I2C0_SDA/B18)

    4. Add the below code

    #include <kernel/dpl/DebugP.h>
    #include <kernel/dpl/ClockP.h>
    #include <kernel/dpl/CycleCounterP.h>
    
    #include <kernel/dpl/AddrTranslateP.h>
    #include <kernel/dpl/HwiP.h>
    #include "ti_drivers_config.h"
    #include "ti_drivers_open_close.h"
    #include "ti_board_open_close.h"
    
    #include "FreeRTOS.h"
    #include "semphr.h"
    
    #include <string.h>
    #include <stdint.h>
    
    #define GPIO_SPISLV_CS      CONFIG_GPIO0_CSISR_PIN
    
    #define APP_MCSPI_MSGSIZE                   (128U)
    #define APP_MCSPI_TRANSFER_LOOPCOUNT        (10U)
    
    uint8_t gMcspiTxBuffer[APP_MCSPI_MSGSIZE];
    uint8_t gMcspiRxBuffer[APP_MCSPI_MSGSIZE];
    
    MCSPI_Transaction spiTransaction;
    
    SemaphoreHandle_t sem;
    
    uint32_t spiBaseAddr;
    
    uint32_t            gGpioBaseAddr = CONFIG_GPIO0_CSISR_BASE_ADDR;
    HwiP_Object         gGpioHwiObject;
    
    extern void Drivers_mcspiOpen(void);
    extern void Drivers_mcspiClose(void);
    extern void Board_gpioInit(void);
    extern void Board_gpioDeinit(void);
    extern uint32_t Board_getGpioButtonIntrNum(void);
    extern uint32_t Board_getGpioButtonSwitchNum(void);
    
    void spislv_cs_isr(void *args)
    {
        BaseType_t prior = pdFAIL;
        uint32_t    pinNum = (uint32_t) args;
        uint32_t    bankNum =  GPIO_GET_BANK_INDEX(pinNum);
        uint32_t    intrStatus, pinMask = GPIO_GET_BANK_BIT_MASK(pinNum);
    
        /* Get and clear bank interrupt status */
        intrStatus = GPIO_getBankIntrStatus(gGpioBaseAddr, bankNum);
        GPIO_clearBankIntrStatus(gGpioBaseAddr, bankNum, intrStatus);
    
        if (intrStatus & pinMask)
        {
            if (sem)
            {
                xSemaphoreGiveFromISR(sem, &prior);
            }
        }
    }
    
    void spislv_transferCb(MCSPI_Handle handle, MCSPI_Transaction *transaction)
    {
        CSL_McspiRegs *spiReg = (CSL_McspiRegs *)spiBaseAddr;
        BaseType_t prior = pdFAIL;
    
        //@note: Delete this code can trigger the issue
        //spiReg->IRQENABLE = 0;   
    
        if (sem)
        {
            xSemaphoreGiveFromISR(sem, &prior);
        }
    }
    
    void spislv_reset(void)
    {
        Drivers_mcspiClose();
        MCSPI_deinit();
        MCSPI_init();
        Drivers_mcspiOpen();
    }
    
    int spislv_xfer(uint8_t *tx, uint8_t *rx, int len, int timeout)
    {
        int rcvCnt = 0;
    
        spiTransaction.txBuf = (void*)tx;
        spiTransaction.rxBuf = (void*)rx;
        spiTransaction.count = len/(spiTransaction.dataSize/8);
    
        MCSPI_transfer(gMcspiHandle[CONFIG_MCSPI0], &spiTransaction);
        if (sem && xSemaphoreTake(sem, pdMS_TO_TICKS(timeout)))
        {
            if (rx != NULL)
            {
                if ( (uint32_t)gMcspiConfig[0].object->mcspiLldInitObj.chObj[0].curRxBufPtr > (uint32_t)rx)
                    rcvCnt = (uint32_t)(gMcspiConfig[0].object->mcspiLldInitObj.chObj[0].curRxBufPtr) - (uint32_t)rx;
            }
        }
    
        spislv_reset();
        return rcvCnt;
    }
    
    
    int spislv_hw_init(void)
    {
        uint32_t        pinNum, intrNum;
        HwiP_Params     hwiPrms;
        int32_t         retVal;
    
        Board_gpioInit();
    
    
        gGpioBaseAddr = (uint32_t) AddrTranslateP_getLocalAddr(gGpioBaseAddr);
    
        pinNum          = CONFIG_GPIO0_CSISR_PIN;
        intrNum         = Board_getGpioButtonIntrNum();
    
        /* Register pin interrupt */
        HwiP_Params_init(&hwiPrms);
        hwiPrms.intNum   = intrNum;
        hwiPrms.callback = &spislv_cs_isr;
        hwiPrms.args     = (void *) pinNum;
        /* GPIO interrupt is a pulse type interrupt */
        hwiPrms.isPulse  = TRUE;
        retVal = HwiP_construct(&gGpioHwiObject, &hwiPrms);
        DebugP_assert(retVal == SystemP_SUCCESS );
    
        sem = xSemaphoreCreateBinary();
    
         MCSPI_Transaction_init(&spiTransaction);
         spiTransaction.channel  = gConfigMcspi0ChCfg[0].chNum;
         spiTransaction.dataSize = 8;
         spiTransaction.csDisable = FALSE;//TRUE;
         spiTransaction.args     = NULL;
    
         spiBaseAddr = MCSPI_getBaseAddr(gMcspiHandle[CONFIG_MCSPI0]);
    
        return 0;
    }
    
    
    void spislv_Task(void *args)
    {
        int rcvCnt;
    
        spislv_hw_init();
    
        while(1)
        {
            DebugP_log("\r\n\r\n====================================================================\r\n");
            rcvCnt = spislv_xfer(gMcspiTxBuffer, gMcspiRxBuffer, 5, 5000);
            if (rcvCnt > 0)
            {
                DebugP_log("Rcv(%d):", rcvCnt);
            }
        }
    }
    
    int spislv_init(void)
    {
        Drivers_open();
        Board_driversOpen();
    
        spislv_Task(NULL);
    
        return 0;
    }

    5.Connect with SPI host(J1-PIN2 -> mosi, J1-PIN4 -> MISO, J1-PIN16 -> CLK, J1->PIN6/J5->PIN2 -> CS, J1-PIN23 -> GND ), send 7 Bytes (>5byte), than issue replicated.

  • In fact, the host sends 12 or 20 bytes or more in one communication, and the issue then recurs.

    I am assuming that the host initially sends 10 bytes, and then at some point it sends 12/20 bytes. So is this interval fixed when it is sending 12/20 bytes?

    Or it is very random?

    Regards,

    Vaibhav

  • Please do not pay too much attention to why the host sends 12 bytes or when it sends them, it's just a worst-case test. Whenever the host sends a longer length than expected, am2434 will crash

  • Hi Liang,

    So based on your steps here, I need to configure SPI slave on AM243 and have a host send bytes of length > SPI slave's transaction length or less than SPI slave's transaction length?

    Regards,

    Vaibhav

  • Yes, in my project as show upper, AM2434 prefill 5 bytes before the host send.  Let the host send 6 or more bytes can replicate issue.

  • Hi,

    Thanks for your patience.

    5.Connect with SPI host(J1-PIN2 -> mosi, J1-PIN4 -> MISO, J1-PIN16 -> CLK, J1->PIN6/J5->PIN2 -> CS, J1-PIN23 -> GND ), send 7 Bytes (>5byte), than issue replicated.

    What is the SPI host which you are using here?

    Can you also elaborate if I need to run the applications in a certain order? 

    1. Firstly the SPI host application and then the Slave application

    2. Firstly the SPI slave application and then the Host application

    Regards,

    Vaibhav

  • Maybe you can use another EVM as SPI HOST and send  20bytes per second.

  • Hi,

    Closing the thread, as there is no response for long. Feel free to ping back, if you want to continue discussion.

    Regards

    Ashwani