• Resolved

RTOS/TMS320C6678: NIMU (Ethernet) interrupting SPI_Transfer() - error:MCSPI_INT_RX_FULL

Part Number: TMS320C6678

Tool/software: TI-RTOS

Hi

We're having a problem with running Ethernet and SPI at the same time.

It appears that the Ethernet is interrupting/crashing the SPI_Transfer() function (MCSPI_INT_RX_FULL).

  • When we run SPI on its own = no problem.
  • When we run SPI and Ethernet, with no traffic on Ethernet = no problem
  • When we run SPI and Ethernet, with normal traffic on Ethernet = SPI CRASH

So I have some questions:

  1. What is the maximum rate at which the SPI_Transfer() can be called? Is there a specific delay that needs to be placed between calls?
  2. I've read that SPI_Transfer() is an atomic operation, so it is possible that an Ethernet call can interrupt it and cause a RX_BUF_FULL error).
  3. Can the use of SYS/BIOS tasks & CPP threads cause this problem? Our application is setup as follow: (Our Ethernet stack is in one SYS/BIOS task & our Ethernet calls and SPI_Transfer are in another SYS/BIOS task, but different threads)

Initially we had a setup issue (HWI conflicts), but resolved it under https://e2e.ti.com/support/arm/sitara_arm/f/791/t/664242?tisearch=e2e-sitesearch&keymatch=nimu%20spi%20conflict
However, I can't find the Ethernet IntNum in the ROV output, so can't confirm that the Ethernet is NOT a higher priority (lower IntNum value) than SPI.


Can anyone answer my questions above and possibly give me some insights into this problem?

  • The team is notified. They will post their feedback directly here.

    BR
    Tsvetolin Shulev
  • In reply to Cvetolin Shulev-XID:

    Hi,

    The C6678 NIMU driver interrupt is setup inside pdk_c667x_2_0_\packages\ti\transport\ndk\nimu\src\v1\nimu_eth.c

    Regards, Eric
  • In reply to lding:

    Hi Eric

    I forgot to give info on the libraries I'm using:

    • Compiler v8.2.2
    • BIOS 6.52.00.12
    • PDK 2.0.7
    • NDK 2.26.00.08
    • XDCTools 3.50.3.33

    I had a look, and here is a list of my interrupts:

    • NIMU_ETH_INTERRUPT = 7
    • SPI int = 6
    • UART int = 4
    • GPIO int = 10

    I've just seen that the Tasks also have priorities. Do these priorities interfere with the SPI interrupts?
    We've tried to set the StackStart Task_priority to 8 (higher number, but lower priority than SPI) and the Task that our SPI calls are being called from to 1.
    This has not solved the problem.

    I'm attaching our ROV output (Hwi, Swi, Tasks).

    Any thoughts/guidance on how to set the Hwi IntNum and Task IntNum so that the low-level SPI_Transfer is not interrupted?

    6406.ROV screen shots.zip

  • In reply to Ruan de Hart:

    I'm adding my main.cpp and app.cfg as well.
    Hope this gives a bit more clarity.

    0726.main.cpp

    1057.app.cfg

  • In reply to Ruan de Hart:

    Hi,

    NIMU_ETH_INTERRUPT = 7
    SPI int = 6
    UART int = 4
    GPIO int = 10

    I thought above are the host interrupt numbers, but not interrupt priorities. Are they all created as HWI? When creating HWI, there is HwiP_Params which you can give priority. Smaller number means higher priority. If Ethernet Rx cause the SPI crash, you may try give SPI higher priority than Ethernet.

    Regards, Eric
  • In reply to lding:

    Hi Eric

    We discovered something yesterday, which makes me think it may not be a Hwi_priority issue, but we'll try.
    Is there a way to view the interrupt priorities (possibly in ROV or similar)?

    What we did find is this:
    When we call the SPI_Transfer() with SPI_Transaction.rxBuf = NULL (not pointing to any buffer) then the SPI runs without crashing.
    So it appears that the problem is with the SPI's rxBuf...

    We are calling the SPI_Transfer from within a C++ class.
    The rxBuf that we assign, we have tried to declare as follows:
    - In the same function (doesn't work)
    - In the class's .h file (doesn't work)

    We are using SPI in Blocking mode.
    I've read that that if the rxBuf goes out of scope, you can get weird behaviour.
    In our case I can't see how any weird behaviour can happen, but I guess we are missing something.

    What is the suggestion on where to define the rxBuf?
    Are there special precautions that need to be taken when calling SPI_Transfer from within a c++ class?
  • Hi

    So I've done some more digging and I'm now stuck in the SPI driver.
    I've updated to PDK 2.0.9, since there seem to be some improvements.

    When calling SPI_Transfer() the SPI driver seems to get stuck in the SPI_v0.c file, specifically in SPI_v0_hwiFxn():

    When debugging (with the Blackhawk XDS560v2-USB) tt gets stuck in the WHILE loop that services all the SPI interrupts. This is defined as

    while (((intCode & SPI_INT_MASK) != 0) && (loop == true))

    intCode is refreshed at the end of the WHILE loop

    intCode = SPIIntStatusGet(hwAttrs->baseAddr);

    I set a breakpoint at the WHILE loop to check the intCode value. At this point none of the interrupt flags are set, but there is a bit set in the reserved section (sprugp2a, March 2012, section 3.5 SPI Flag register(SPIFLG) ) = 0b0010000000000000.
    So it is clear that the WHILE loop should exit....but it DOESN'T????

    If I do a single step, the intCode value changes to have the TXINTFLG bit set...and the WHILE loop runs again.

    It then appears that the SPI driver then remains in this loop.

    Why is the TXINTFLG bit not correctly cleared????
    Why does the intCode variable magically change during 1 step?????

    My SPI setup function looks as follows:

    SPI_v0_HWAttrs spi_cfg;
    SPI_socGetInitCfg( 0, &spi_cfg );
    spi_cfg.csNum = 1;
    SPI_socSetInitCfg( 0, &spi_cfg );
    
    Board_initCfg  cfg = BOARD_INIT_ETH_PHY | BOARD_INIT_MODULE_CLOCK | BOARD_INIT_UART_STDIO;
    Board_init(cfg);
    
    SPI_Params spiParams;
    SPI_Params_init( &spiParams );
    spiParams.frameFormat = SPI_POL0_PHA1;
    spiParams.bitRate = 1000000;
    spiParams.dataSize = SPI_v0_8bit;
    spiParams.transferMode = SPI_MODE_BLOCKING;
    SPI_init();
    spiHandle_ = SPI_open( portNumber_, &spiParams );
    
    // Enable the SPI port
    uint32_t xferEnable = 1;
    SPI_control( spiHandle_, SPI_V0_CMD_XFER_ACTIVATE, (void *)&xferEnable );

  • In reply to Ruan de Hart:

    Hi all

    I'm posting this, so that others can hopefully have the benefit.
    WE HAVE FOUND A PROBLEM IN THE PDK V2.0.9, SPI_v0_hwiFxn

    In our application the DSP seems to be processing the SPI so fast, that RX data is not ready directly after the TX data is sent.
    When TX data is completed, the SPI_INT_TX_EMPTY flag is set.
    Immediately after this, we are expecting the SPI_INT_RX_FULL to be set...BUT THIS ASSUMPTION ISN'T TRUE.
    We have found that the SPI_INT_RX_FULL flag isn't always already set, which causes the TX & RX buffer processing to get out of sync.
    This eventually hangs the SPI driver.

    SOLUTION:
    (NOTE: Not pretty, but it works)
    We put a WHILE loop in after the SPI_INT_TX_EMPTY is processed, to wait for the SPI_INT_RX_FULL to be set. This ensure the TX & RX buffers stay in sync.

    I'm attaching the SPI_v0.c file.
    You should be able to merge the SPI_v0_hwiFxn function into your PDK and rebuild your PDK.  ()

    NOTE: Not all DSPs use the SPI_v0 driver. If your DSP uses the SPI_v1, you will need to merge it in there.

    Good luck!

    SPI_v0.c

  • In reply to Ruan de Hart:

    Hi,

    Thanks for debugging into this and sharing the solution! I looked at code change and will open a ticket for it.

    Regards, Eric