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.

TMS320C6678: fdPoll() invoke problem

Part Number: TMS320C6678

Hello,

I am developing the Ethernet UDP packet exchange  application with using a jumbo packets. I've rebuild the for using the jumbo packet. In order to send and receive UDP packets by using the same socket I've used the fdPoll() function for a one socket with POLLINFTIM parameter. I've tested the 8K UDP packet receive with interval more 1 ms , application received jumbo packet. And when I set a breakpoints after fdpoll() to see that recvncfrom() returned correct result.

Application needs to receive the UDP packet (600 bytes) with interval about 30 micro seconds up to 8K UDP packet with interval 250 - 300 microseconds. In order to debug short UDP packet receive I set a breakpoint on recvncfrom() function, and then start uninterrupted UDP packet transmission from other device (as UDP packet generator). But unfortunately program wasn't  stopped at the breakpoint.  Then I pulled out RJ-45 jack from a socket (break ethernet line)  and program was stopped at the breakpoint. I pressed some times the "resume" button and program was stopped  some time at the breakpoint. As I got it  some packets were received and network scheduler issued events to the a receive task. I don't understand what is the reason.

The receive function should copy the packet to a memory with edma and start the task for a packets processing on other cores. I use core 0 for communication only.

The configuration:

xdctools 3.55.2.22

NDK 3.61.1.01

SYS/BIOS 6.76.2.02

With the best regards,

Alex

    

  • Hi,

    Is this application based on TI NIMU example, do you use TI Processor SDK RTOS on C667x? What release? Can you show a code snippet where you set breakpoint and Rx process call flow?

    What is the targeted Ethernet bandwidth with your application?

    "The receive function should copy the packet to a memory with edma and start the task for a packets processing on other cores"=======>The packet DMA (not EDMA) place the received packets in the memory. It is up to your application to use EDMA to move it to another location, and other cores to process it. 

    Regards, Eric

  • Hello Eric,

    Yes my application is based on NIMU example. I attached the code. I've used fdPoll function in order to have possibility start transaction with packet sending and then receive packets through the same socket as first packet is sent.

    As I mentioned I need to receive UDP packet with 600 bytes payload with interval 30 microsecond. After receiving the first packet I need to send it with DMA, release input buffer and be ready to receive next packet. You mentioned that I need to use the packet DMA. It means NIMU + PDMA. That's right?  Because I tried to utilize edma. Then I commented edma code and tried to see that NDK received packet. I putted breakpoint to  "if (res > 0) " to detetect that packet received in a a buffer. 

    Best regards,

    Alex

    /*
     * Copyright (c) 2012-2018, Texas Instruments Incorporated
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     * */
    /*
     * ======== newservers.c ========
     *
     * This module demonstrates the use of the server daemon added in NDK 1.7.
     *
     * It provides all the functionality of:
     *     echosrv() : echosrv.c
     *     datasrv() : datasrv.c
     *     nullsrv() : nullsrv.c
     *     oobsrv()  : oobsrv.c
     *
     * The original source files are still provided to illustrate a traditional
     * server. This file contains only the daemon service task functions
     * required when using the server daemon.
     *
     */
    
    #include <stdint.h>
    #include <stdio.h>
    #include <ti/ndk/inc/stkmain.h>
    #include <ti/ndk/inc/netmain.h>
    #include <ti/ndk/inc/socket.h>
    
    #include <xdc/runtime/System.h>
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Task.h>
    #include <ti/sysbios/knl/Semaphore.h>
    #include <ti/sysbios/knl/Mailbox.h>
    #include <ti/sysbios/hal/Cache.h>
    #include <ti/sysbios/knl/Queue.h>
    
    #include <ti/ndk/inc/_stack.h>
    #include <ti/csl/csl.h>
    #include <ti/csl/csl_cache.h>
    #include <time.h>
    #include <c6x.h>
    #include "PCIeFunctions.h"
    #include "PCIeEDMA2.h"
    #include "Sem_bundle.h"
    #include "Queues_.h"
    #include "Queues_names.h"
    #include "Mailbox_bundle.h"
    #include "Network_Test.h"
    
     /* ���������� EDMA */
    extern EDMA3_DRV_Handle* phEdma1;
    
    /* message struct for udp_send_queue */
    CoreSendStruct_t udpMsg;
    CoreSendStruct_t *pudpMsg = &udpMsg;
    
    extern CoreSendStruct_t* pPCIeEvent_Msg;
    /**
     * @brief
     *  The structure describes the Daemon Entry.
     */
    typedef struct
    {
        /**
         * @brief   Type of socket. For V4 this could be SOCK_STREAM,
         * SOCK_STREAMNC, SOCK_DGRAM But for V6 this can only be
         * SOCK_STREAM and SOCK_DGRAM.
         */
        uint32_t    Type;
    
        /**
         * @brief   Local V4 Address to which the socket is bound to
         *  For most cases this is passed as INADDR_ANY
         */
        uint32_t    LocalAddress;
    
        /**
         * @brief   Local Port to which the daemon will be bound to
         * This cannot be NULL.
         */
        uint32_t    LocalPort;
    
        /**
         * @brief   Call back function which is invoked when data is
         * received on the registered daemon.
         */
    //    int         (*pCb)(SOCKET,uint32_t);
    
        /**
         * @brief   Priority of the child task.
         */
    //    uint32_t    Priority;
    
        /**
         * @brief   Stack size of the child task.
         */
    //    uint32_t    StackSize;
    
        /**
         * @brief   Argument which is to passed to the call back routine.
         */
    //    uint32_t    Argument;
    
        /**
         * @brief   Maximum number of tasks which can be spawned to handle
         * the daemon.
         */
    //    uint32_t    MaxSpawn;
    
        /**
         * @brief   Internal socket created by the daemon for use.
         */
        SOCKET      s;
    
        /**
         * @brief   Number of tasks spawned to handle the daemon.
         */
    //    uint32_t    TasksSpawned;
    
        /**
         * @brief   Pointer to children.
         */
    //    struct _child *pC;
    } socketREC;
    
    
    #define DATASRV_BUFSIZE 512
    #define NULLSRV_BUFSIZE 1500
    #define MAX_PORT_NUMBER 1
    #define MAX_SendPORT_NUMBER 1
    #define UDP_PORT_NUMBER_REMOTE 1234
    #define UDP_PORT_NUMBER 52000
    
    //char *DefaultRemoteIP = "192.168.3.20";
    char *DefaultRemoteIP = "192.168.5.7";
    
    //char *LocalIPAddr_ = "192.168.3.77";
    char *LocalIPAddr_ = "192.168.5.10";
    
    //static socketREC mySOCK[MAX_PORT_NUMBER];
    static socketREC transceiverSOCK = {.Type = SOCK_DGRAM,
                                        .s = INVALID_SOCKET,
                                        .LocalAddress = 0,
                                        .LocalPort = UDP_PORT_NUMBER};
    static FDPOLLITEM poll_item;
    
    //static FDPOLLITEM pollitem[MAX_PORT_NUMBER];
    uint32_t UDPPortNumber[MAX_PORT_NUMBER];
    uint32_t SendUDPPortNumber[MAX_SendPORT_NUMBER];
    
    clock_t t_start,
            t_stop,
            t_overhead, t_cn;
    
    SynchroStruct InitFile = {
          .Type = 1,
          .Reserve = 0,
          .Size = 140,
          .HeaderCRC = 248409918,
          .Identifier = 0,
          .Bank = 0,
          .SI_Time = 30,
          .SRDTime = 1000,
          .GapTime = 0,
          .Params = 1,  // 1 - ��������� �������
          .wwwwwww = 0,
          .TxEna = 0,
          .ADC_Blank = 0,
          {0},
          {0},
          {0}};
    
    typedef struct
    {
        unsigned long long time;
        uint32_t packetNumber;
    } packetDetection_t;
    
    static unsigned long long WH_time, WH_time_old, Next_time, WH_delta;
    static const size_t packetNumber = 100;
    //static packetDetection_t UDPFind[100];
    static size_t intervalsIncr = 0;
    
    /* �������� �������: task_UDP_Tranceiver
     * ����������: �����/�������� ������� UDP
     */
    
    void task_UDP_Tranceiver(UArg a0, UArg a1)
    {
    
        struct sockaddr_in sin_rec, sin_send, sin_peer;
        void *pBuf;
        static void *hBuffer;
    //    double turnInMicro = 10E6;
        uint32_t PacketCounter = 0;
    //    uint32_t TotalBytes, ACount, BCount, CCount;
    //    uint8_t* pByte;
    //    uint8_t offsetBytes;
    //    unsigned long totalTime=0;
    //    unsigned long* totalTimePointer = &totalTime;
     //   EDMA3_DRV_Result edmaResult = EDMA3_DRV_SOK;
     //   uint32_t LengthtoSend;
        int res;
    
        // C�������� ��� �������
        CoreSendStruct_t taskPCIeSend_queue;
        memset(InitFile.a, 1, sizeof(InitFile.a));
    
        /* 1. Initialization */
    
        // Allocate the file environment for this task
        if (fdOpenSession(TaskSelf()) == 0) {
            printf("Receive thread unable to open file descriptor session.");
            return;
        }
    
        // Create UDP or TCP as needed
        if (transceiverSOCK.Type == SOCK_DGRAM)
            transceiverSOCK.s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
        else
            transceiverSOCK.s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    
        transceiverSOCK.LocalAddress = inet_addr(LocalIPAddr_);
    
        // Bind to the specified Server port
        memset(&sin_rec, 0, sizeof(struct sockaddr_in));
        sin_rec.sin_family      = AF_INET;
        sin_rec.sin_addr.s_addr = transceiverSOCK.LocalAddress;
        sin_rec.sin_port        = NDK_htons(transceiverSOCK.LocalPort);
    
        if (bind(transceiverSOCK.s, (struct sockaddr *)&sin_rec, sizeof(sin_rec)) < 0) {
            fdClose(transceiverSOCK.s);
            transceiverSOCK.s = INVALID_SOCKET;
        } else {
            printf ("Transceiver socket is created \r\n");
        }
    
        // Set the fdPoll
        poll_item.fd = transceiverSOCK.s;
        poll_item.eventsRequested = POLLIN;
    
        // Sending struct
        memset(&sin_send, 0, sizeof(struct sockaddr_in));
        sin_send.sin_family = AF_INET;
        sin_send.sin_addr.s_addr = inet_addr(DefaultRemoteIP);
        sin_send.sin_port = NDK_htons(UDP_PORT_NUMBER_REMOTE);
    
        // Initialize timer for clock
        TSCL= 0,TSCH=0;
    
        // Compute the overhead of calling _itoll(TSCH, TSCL) twice to get timing info
        t_start = _itoll(TSCH, TSCL);
        t_stop = _itoll(TSCH, TSCL);
        t_overhead = t_stop - t_start;
    
    
      // 2. Processing loop
      while (1)
      {
    
          /* Poll with a timeout of 10 second - to try and catch */
          res = fdPoll(&poll_item, MAX_PORT_NUMBER, POLLINFTIM);
          if (res == SOCKET_ERROR) {
            printf(" fdPoll break \r\n ");
            break;
          }
    
          if (res > 0) {
    
              /* If no poll results or the mySOCK has been freed, skip it */
               if (!poll_item.eventsDetected || !transceiverSOCK.Type) {
                   continue;
               }
    
               /* If the socket is invalid, close it */
               if (poll_item.eventsDetected & POLLNVAL) {
                   fdClose(transceiverSOCK.s);
                   transceiverSOCK.s = INVALID_SOCKET;
                   printf("fdPoll break \r\n");
                   break;
               }
    
               /*  Valid flags for POLLIN */
               if (poll_item.eventsDetected & POLLIN) {
                   if (transceiverSOCK.Type == SOCK_DGRAM) {
                       int bytesNum,
                           sin_size = sizeof(sin_peer);
                       int* pInt = (int*)&pBuf;
                       bytesNum = (int)recvncfrom(transceiverSOCK.s, &pBuf, 0,(struct sockaddr *)&sin_peer, &sin_size, &hBuffer);
                       // timestamp
                       WH_time = _itoll(TSCH, TSCL);
                      // UDPFind[intervalsIncr].time = WH_time;
                      // UDPFind[intervalsIncr].packetNumber = pInt[1];
                       intervalsIncr++;
                       if (intervalsIncr == packetNumber)
                       {
                           intervalsIncr = 0;
                       }
    
                       //printf ("r %d b %d count\r\n", bytesNum, pInt[1]);
                       PacketCounter++;
    
                       /* Copy to buffer
                        * buffer structure:
                        * 1. local packet number
                        * 2. Time stamp
                        * 3. UDP packet size
                        * 4. Stuffing
                        * 5. UDP packet
                        */
    
    //                   pByte = (uint8_t*)pPcieBAR3Structure;
    //                   offsetBytes = 0;
    //                   pByte += offsetBytes;
    //                   *pByte = PacketCounter;
    //                   offsetBytes = sizeof(PacketCounter);
    //                   LengthtoSend = offsetBytes;
    //                   pByte += offsetBytes;
    //                   memcpy(pByte, &WH_time, sizeof(WH_time));
    //                   offsetBytes = sizeof(WH_time);
    //                   LengthtoSend += offsetBytes;
    //                   pByte += offsetBytes;
    //                   memcpy(pByte, &bytesNum, sizeof(bytesNum));
    //                   offsetBytes = sizeof(bytesNum);
    //                   LengthtoSend += offsetBytes;
    //                   pByte += offsetBytes;
    //                   LengthtoSend += bytesNum;
    /*
                       // ������ ACount, BCount
                       if (bytesNum > ACOUNT_MAX) {
                           ACount = 16384; // ��� ������� ��� �������
                           BCount = bytesNum / 16384;
    
                           if (BCount > BCOUNT_MAX)
                               BCount = BCOUNT_MAX;
                       }
                       else {
                              ACount = bytesNum;
                              BCount = 1;
                       }
    
                       CCount = 1;
                       edmaResult = edma3_test(*phEdma1, (unsigned int*) pBuf,
                                               (unsigned int*) pByte, ACount, BCount, CCount,
                                               EDMA3_DRV_SYNC_AB, totalTimePointer, &semNets);
    
                       if (edmaResult == EDMA3_DRV_SOK) {
                           // Send data to RC
                           taskPCIeSend_queue.Header.msgDestID = ObjID_TransmitterPCIe;
                           taskPCIeSend_queue.Header.msgtSourceID = ObjID_Ethernet;
                           taskPCIeSend_queue.Header.timeStamp = WH_time;
                           taskPCIeSend_queue.msgSendMsg.Data = (uint8_t *) pPcieBAR3Structure;
                           taskPCIeSend_queue.msgSendMsg.DataSize_Bytes = LengthtoSend;
                           taskPCIeSend_queue.msgTypeID = PCIeSend;
                           Queue_put(PCIeSendMsg_Queue, &taskPCIeSend_queue.elem);
                           Semaphore_post(semTaskPCIeSend);
                       } */
                       // free buffer
                       recvncfree(hBuffer);
                       Next_time = _itoll(TSCH, TSCL);
                       Networktest_MsgObj msg;
                       msg.id = 2;
                       msg.val = bytesNum;
                       Mailbox_post(mailbox0, &msg, 10);
                   }
               }
    
          } else if (res == 0) {
    
    // No detected flags and time out has occurred
    // No detected flags and a fdSelectAbort() was issued
    // No detected flags and an internal resource allocation failed
    
              /* �������� ������� ������ ������� */
              if (!Queue_empty(udp_send_queue)) {
                  // get a new message
                  pudpMsg = Queue_get(udp_send_queue);
                  if (pudpMsg->msgTypeID == UDPSend) {
                       if ((pudpMsg->msgUDPSend.DataSize_Bytes > 0) && (pudpMsg->msgUDPSend.Data != NULL)) {
                           res = sendto(transceiverSOCK.s,
                                        (void*) pudpMsg->msgUDPSend.Data,
                                        pudpMsg->msgUDPSend.DataSize_Bytes,
                                        0,
                                        (struct sockaddr *)&sin_send,
                                        sizeof(sin_send));
                       } else {
                           res = 0;
                       }
    
                      /* send reply to networktest task */
                      Networktest_MsgObj msg;
                      msg.id = 1;
                      msg.val = res;
                      Mailbox_post(mailbox0, &msg, 10);
                  }
              }
    
              /* system handle used to free the buffer */
              printf ("Send %d bytes, need %d \r\n", res, sizeof(InitFile));
              continue;
          } else if (res == SOCKET_ERROR) {
    
    
          }
    
      }
    
     // 3. ����������
    
    
    
    
    
    }
    
    

  • Alex,

    "I've tested the 8K UDP packet receive with interval more 1 ms , application received jumbo packet". This is 64Mbps and you were able to see the incoming data from recvncfrom().

    600 bytes at 30 us is 160Mbps, the Ethernet should be able to handle that. The C6678 has packet DMA to put the data into the buffer, it is transparent to the user as long as you use the NIMU driver. It is different from EDMA, it is up to you to move the data from the buffer to another location by EDMA for further processing. 

    I saw you already commented out the EDMA code, so this is just a code to receive packets from socket. If you can't stop at the recvncfrom() sometimes, it meant you lost some packets. Do you have an idea how frequent it is? Do you used any optimization like -O3 to compile the source code? 

    Regards, Eric

  • Eric,

    today I've tried -03 optimization. A result is a same. But when I break Ethernet connection and stop at recvncfrom()  breakpoint,   recvncfrom() returns -2147348596. I've done the optimization in release mode, but in debug mode I get 408 (as example) with the same code. 

    You mentioned "If you can't stop at the recvncfrom() sometimes", but really I can't stop at the recvncfrom() never until I break connection physically.  Can you advise if I can check that Ethernet driver receives packet and issues stack event? I'd like to put breakpoints in the driver or check the full NDK stack. 

    Regards, Alex 

  • Alex,

    If you want to trace the receive process, you can add pdk_c667x_2_0_xx\packages\ti\transport\ndk\nimu\src\v1\nimu_eth.c into your application to build. Then it is easier to set break point (otherwise the functions are inside the nimu library, code optimized). Look at the EmacRxPktISR().

    Some key points:

    /* Copy the data buffer received to the allocated PBM packet */
    mmCopy((uint8_t* )rx_pbm_pkt->pDataBuffer, (uint8_t* )pBuffer, pktLen) ;

    /* Notify NDK stack of pending Rx Ethernet packet */
    STKEVENT_signal( ptr_pvt_data->pdi.hEvent, STKEVENT_ETHERNET, 1 );

    You may starting with just use the packet generator to send 1 packet to trace the the call flow.

    Regards, Eric