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.

TMS320F28388D: TMS320F28388D lwip freertos issue

Part Number: TMS320F28388D
Other Parts Discussed in Thread: C2000WARE

Hi,
I am also having problems running the lwIP FreeRTOS example.
I haven't found a solution yet, and the related link below was not helpful:
https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1563127/tms320f28388d-lwip-with-freertos?keyMatch=lwip%20freertos&tisearch=universal_search

The only way I found to run the lwIP FreeRTOS example on the TMS320F28388D is by using CCS 12.8. I guess if I had installed the correct compiler in CCS 20.3.1, it might work, but the problem is in the import project—CCS 20.3.1 doesn’t have the right compiler.

For the import project, I used ethernet_ipc_ex1_basic_c28x1 and changed the code to keep the CPU1 line, like putting a while(1); there. I think the example ethernet_ipc_ex1_basic_c28x1 initializes the correct pins necessary to run lwIP.

So, I used the ethernet_ipc_ex1_basic_c28x1 project as the base for CPU1 and also added the enet_lwip_freertos project to my workspace. To debug and run lwIP, I flashed CPU1 with ethernet_ipc_ex1_basic_c28x1 selected, and CM selected enet_lwip_freertos. I started debugging and ran CPU1, then ran CM, but the software stopped at least 6 times on an assert.

I also modified lwIP to create a UDP server that runs properly. To test the interface, I developed a small tool to connect to the TMS320F28388D. Basically, the tool connects, sends a message, waits for a reply, then disconnects. The tool has a loop to send the same message multiple times at a 10 ms frequency.

On the server side (TMS320F28388D), it receives the message, turns a GPIO on or off, and sends a message back to the client (my tool). The system runs for roughly 30 minutes, then the TMS320F28388D hits the same assert function: vAssertCalled.

Sometimes I stop my client tool, wait about 5 minutes, then the TMS320F28388D recovers, and I can send messages from the client tool again.

My main questions are:

  1. What is the correct way to run the TMS320F28388D lwIP FreeRTOS example?

  2. Using the infrastructure I mentioned, I would expect the system to run from the start without hitting the assert breakpoint 6 times.

Additional information: In the connection accept, I only keep references to active connections, and in the main loop, I clean up connections that are no longer in use. I assume lwIP should manage this, but I do it anyway.

I need an official infrastructure or method to at least successfully run the TI lwIP FreeRTOS example. Suggestions regarding the TMS320F28388D stopping after about 30 minutes of running are also welcome.

  • Hi,

    So, I used the ethernet_ipc_ex1_basic_c28x1 project as the base for CPU1 and also added the enet_lwip_freertos project to my workspace. To debug and run lwIP, I flashed CPU1 with ethernet_ipc_ex1_basic_c28x1 selected, and CM selected enet_lwip_freertos. I started debugging and ran CPU1, then ran CM, but the software stopped at least 6 times on an assert.

    Can You explain where did the code hits the assert . Can You share me the call stack?

    What is the correct way to run the TMS320F28388D lwIP FreeRTOS example?

    The way you have done is fine. You can also import the project from driverlib/f2838x/example/cm/ethernet and use ethernet_cm_config to build and run on CPU1.

    Can you also define ETHERNET_DEBUG and share g_uiEnetStats after the assert being hit.

  • Hi,
    Gouri, thank you for looking into the issue.
    I ran some tests using the other example for CPU1 (driverlib/f2838x/example/cm/ethernet) and utilized ethernet_cm_config.
    The behavior is the same; it still stops at the assert. I also noticed that when I start both cores (CPU1 and CM) without the network cable connected, the problem does not occur.
    But when I start both cores (CPU1 and CM) with the network cable connected, it stops at the assert. After several “play” actions in the Debug, it keeps running normally—like I mentioned, there are around six or more stops at asserts.
    For example, I left my application running for about 72 hours, sending UDP messages every 10 ms, and it did not freeze even once until I manually turned it off.
    But when I start it again, the same behavior happens.
    I gathered the call stack information and the g_uiEnetStats variable; I’m attaching some images of the times it stops at the assert.

  • It seems that any instability, for example plugging in or removing a network cable, causes it to stop at the assert.

  • Hi,

    I assume even before the initialization of Rx Channel with Buffers, it will have to face some of the incoming packet. Can you confirm that once?

    So it will get into a state called RBU (Receive Buffer Unavailable), which will generate an Interrupt.

    Currently software re-initializes the rx channel when the interrupt occurs. So here we are calling critical section from interrupt context, it is the reason for config_assert right now. From the next release of C2000ware onwards this issue will be resolved.

    You can try Disable RBU interrupt when it occurs and Re-enable once the Rx Task completes one execution.

  • Hi,

    I assume even before the initialization of Rx Channel with Buffers, it will have to face some of the incoming packet. Can you confirm that once?

    I'm not always receiving packets, but the TMS320F28388D is connected to a switch, so there can be network traffic, yes.

    You can try Disable RBU interrupt when it occurs and Re-enable once the Rx Task completes one execution.

    Could you please provide a patch or indicate in the code how to do this?

    I assume the point to disable would be here:

    if((ETHERNET_DMA_CH0_STATUS_AIS |
                                       ETHERNET_DMA_CH0_STATUS_RBU) ==
                                       (HWREG(Ethernet_device_struct.baseAddresses.enet_base +
                                       ETHERNET_O_DMA_CH0_STATUS) &
                                       (uint32_t)(ETHERNET_DMA_CH0_STATUS_AIS |
                                       ETHERNET_DMA_CH0_STATUS_RBU)))
    {

       //Disable here

       ENET_DRIVER_STATS_INC(RBUinterrupt);
    }

    and to enable would be here:

    void RxTask(void *pvParameters)
    {
      while(1)
      {
       if(xSemaphoreTake(RxSem, portMAX_DELAY) == pdTRUE)
       {
         Ethernet_removePacketsFromRxQueueCustom(
         &Ethernet_device_struct.dmaObj.rxDma[ETHERNET_DMA_CHANNEL_NUM_0], ETHERNET_COMPLETION_NORMAL);

               //Enable here
       }
      }
     }

    By the way, for now I have commented out the breakpoint in the assert function, but if another problem occurs I will not have the context of the call stack. It would be better to disable/enable the RBU.

    void vAssertCalled(const char *file, int line)
    {
     lastline = line;
     lastfile = (char *)file;
     //__asm(" bkpt #0");
    }

  • Hi, 

    You are correct.

    Could you please provide a patch or indicate in the code how to do this?

    Patch is attached here.

    diff --git a/driver/ethernet.c b/driver/ethernet.c
    index a2e40df..5c31424 100644
    --- a/driver/ethernet.c
    +++ b/driver/ethernet.c
    @@ -693,55 +693,59 @@ interrupt void Ethernet_genericISRCustom(void)
                */
     
                 /* Upon RBU error, discard all previously received packets */
    -            if(Ethernet_device_struct.initConfig.pfcbDeletePackets != NULL)
    -                (*Ethernet_device_struct.initConfig.pfcbDeletePackets)();
    -
    -            rxChan =
    -               &Ethernet_device_struct.dmaObj.rxDma[ETHERNET_DMA_CHANNEL_NUM_0];
    -            txChan=
    -               &Ethernet_device_struct.dmaObj.txDma[ETHERNET_DMA_CHANNEL_NUM_0];
    -
    -            /*
    -            * Need to disable multiple interrupts, so protect the code to do so within
    -            * a global disable block (to prevent getting interrupted in between)
    -            */
    -
    -            if(NULL!= Ethernet_device_struct.ptrPlatformInterruptDisable)
    -            {
    -                (*Ethernet_device_struct.ptrPlatformInterruptDisable)(
    -                    Ethernet_device_struct.interruptNum[
    -                        ETHERNET_RX_INTR_CH0 + rxChan->chInfo->chNum]);
    -
    -                (*Ethernet_device_struct.ptrPlatformInterruptDisable)(
    -                    Ethernet_device_struct.interruptNum[
    -                        ETHERNET_GENERIC_INTERRUPT]);
    -            }
    -            /* verify we have full capacity in the descriptor queue */
    -            if(rxChan->descQueue.count < rxChan->descMax) {
    -              /* The queue is not at full capacity due to OOM errors.
    -              Try to fill it again */
    -                Ethernet_addPacketsIntoRxQueue(rxChan);
    -            }
    -
    -            Ethernet_initRxChannel(
    -                    &Ethernet_device_struct.initConfig.chInfo[ETHERNET_CH_DIR_RX][0]);
    -
    -            Ethernet_writeRxDescTailPointer(
    -                Ethernet_device_struct.baseAddresses.enet_base,
    -                0,
    -                (&Ethernet_device_struct.rxDesc[
    -                 ((uint32_t)ETHERNET_DESCRIPTORS_NUM_RX_PER_CHANNEL) *
    -                  (0 + (uint32_t)1U)]));
    -
    -            if(NULL!= Ethernet_device_struct.ptrPlatformInterruptEnable)
    -            {
    -                (*Ethernet_device_struct.ptrPlatformInterruptEnable)(
    -                    Ethernet_device_struct.interruptNum[
    -                        ETHERNET_RX_INTR_CH0 + rxChan->chInfo->chNum]);
    -                (*Ethernet_device_struct.ptrPlatformInterruptEnable)(
    -                    Ethernet_device_struct.interruptNum[
    -                        ETHERNET_GENERIC_INTERRUPT]);
    -            }
    +            // if(Ethernet_device_struct.initConfig.pfcbDeletePackets != NULL)
    +            //     (*Ethernet_device_struct.initConfig.pfcbDeletePackets)();
    +
    +            // rxChan =
    +            //    &Ethernet_device_struct.dmaObj.rxDma[ETHERNET_DMA_CHANNEL_NUM_0];
    +            // txChan=
    +            //    &Ethernet_device_struct.dmaObj.txDma[ETHERNET_DMA_CHANNEL_NUM_0];
    +
    +            // /*
    +            // * Need to disable multiple interrupts, so protect the code to do so within
    +            // * a global disable block (to prevent getting interrupted in between)
    +            // */
    +
    +            // if(NULL!= Ethernet_device_struct.ptrPlatformInterruptDisable)
    +            // {
    +            //     (*Ethernet_device_struct.ptrPlatformInterruptDisable)(
    +            //         Ethernet_device_struct.interruptNum[
    +            //             ETHERNET_RX_INTR_CH0 + rxChan->chInfo->chNum]);
    +
    +            //     (*Ethernet_device_struct.ptrPlatformInterruptDisable)(
    +            //         Ethernet_device_struct.interruptNum[
    +            //             ETHERNET_GENERIC_INTERRUPT]);
    +            // }
    +            // /* verify we have full capacity in the descriptor queue */
    +            // if(rxChan->descQueue.count < rxChan->descMax) {
    +            //   /* The queue is not at full capacity due to OOM errors.
    +            //   Try to fill it again */
    +            //     Ethernet_addPacketsIntoRxQueue(rxChan);
    +            // }
    +
    +            // Ethernet_initRxChannel(
    +            //         &Ethernet_device_struct.initConfig.chInfo[ETHERNET_CH_DIR_RX][0]);
    +
    +            // Ethernet_writeRxDescTailPointer(
    +            //     Ethernet_device_struct.baseAddresses.enet_base,
    +            //     0,
    +            //     (&Ethernet_device_struct.rxDesc[
    +            //      ((uint32_t)ETHERNET_DESCRIPTORS_NUM_RX_PER_CHANNEL) *
    +            //       (0 + (uint32_t)1U)]));
    +
    +            // if(NULL!= Ethernet_device_struct.ptrPlatformInterruptEnable)
    +            // {
    +            //     (*Ethernet_device_struct.ptrPlatformInterruptEnable)(
    +            //         Ethernet_device_struct.interruptNum[
    +            //             ETHERNET_RX_INTR_CH0 + rxChan->chInfo->chNum]);
    +            //     (*Ethernet_device_struct.ptrPlatformInterruptEnable)(
    +            //         Ethernet_device_struct.interruptNum[
    +            //             ETHERNET_GENERIC_INTERRUPT]);
    +            // }
    +
    +            Ethernet_disableDmaInterrupt(Ethernet_device_struct.baseAddresses.enet_base,
    +                                 0, (ETHERNET_DMA_CH0_INTERRUPT_ENABLE_AIE |
    +                                     ETHERNET_DMA_CH0_INTERRUPT_ENABLE_RBUE));
     
     
         }
    diff --git a/examples/enet_lwip_freertos/cm/enet_lwip_freertos.c b/examples/enet_lwip_freertos/cm/enet_lwip_freertos.c
    index f2caba6..3949e56 100644
    --- a/examples/enet_lwip_freertos/cm/enet_lwip_freertos.c
    +++ b/examples/enet_lwip_freertos/cm/enet_lwip_freertos.c
    @@ -546,6 +546,13 @@ void RxTask(void *pvParameters)
             {
                  Ethernet_removePacketsFromRxQueueCustom(
                     &Ethernet_device_struct.dmaObj.rxDma[ETHERNET_DMA_CHANNEL_NUM_0], ETHERNET_COMPLETION_NORMAL);
    +
    +            if((HWREG(EMAC_BASE + ETHERNET_O_DMA_CH0_INTERRUPT_ENABLE) & ETHERNET_DMA_CH0_INTERRUPT_ENABLE_RBUE) == 0U)
    +            {
    +                Ethernet_enableDmaInterrupt(EMAC_BASE,
    +                                 0, (ETHERNET_DMA_CH0_INTERRUPT_ENABLE_AIE |
    +                                     ETHERNET_DMA_CH0_INTERRUPT_ENABLE_RBUE));
    +            }
             } 
         }
     }