freeRTOS + lwIP + ppp

nobody wrote on Tuesday, August 22, 2006:

Hello everybody!

Has anybody implemented ppp with lwIP?

I’m trying to do it on AT91SAM7S256. In first i want to notice a little bug in ppp.c:
pppMain() should end by
    …
    vTaskDelete(NULL);
}

Best regards
Janusz

nobody wrote on Wednesday, August 23, 2006:

I think the ppp file in the download has not been used, so is exactly as per the lwIP download. 

nobody wrote on Wednesday, August 23, 2006:

I have noticed that too.

nobody wrote on Saturday, August 26, 2006:

Hi Janus,

I’m trying to do the same thing (freeRTOS+lwIP+PPP) but not on an Atmel, I will be using an STR712 from ST. I just started working on the project yesterday so there’s not much working so far, but I will get it running eventually and I will post my findings here. Did you get the PPP to work on your Atmel?

Thanks,
Vard

nobody wrote on Monday, August 28, 2006:

hi Vard,

I run the PPP. It works but I have still some problems. I have debug port for PPP. I have timeout for ICMP ping about 400ms for 115200 bauds and 750ms for 57600. I tried run http server from GCC-lwIP at91sam7 example. When I open the socket, port 80 TCP, system crashes.
Today I started to fight with lwIP stack - I tried to enable lwIP debug but something is wrong.

some advices for tests:
- I used Mepis Linux distribution (it supports USB-serial converters and runs from CD)
- ppp demon: pppd /dev/ttyUSB0 57600 noauth nocrtscts debug kdebug 7 10.0.0.1:10.0.0.2
- debug view: tail -f /var/log/messages (in other distrib.) or tty5 in the Mepis.
- after I run ppp with pppd I connected my device to Motorola G20 serial GSM/GPRS modem - connection was created! :slight_smile:
- to be careful with sio_read and sio_read_abort, it is simple brigde function but there is possible to do a lot of mistakes!
- ppp.c bugs:
   * task pppMain requires vTaskDelete(NULL) at the end;
   * http://savannah.nongnu.org/bugs/?func=browse&set=open&group=lwip :
    #16602 -> you should add “netif_set_up(&pc->netif);” after “pc->errCode = PPPERR_NONE;” in “int sifup(int pd)” - otherwise ping will not response!;
    #13315 - i’m not sure this bug but I commented “//if (u->us_clientstate == UPAPCS_AUTHREQ)” in “static void upap_lowerdown(int unit)” via pap.c

best rgs
Janusz

nobody wrote on Monday, August 28, 2006:

I have to make better tests of PPP stability in the future. I noticed after 30 minutes sending the ICMP ping in a loop ppp stopped to response (reason: pppd disconnected). When I turn on lwip debug OS crashes even during ping:/
My http server on the device crashes in ip layer (ip_input)! I don’t know why. There is possible not enought of memory:/ - there is pbuf declaration…

Janusz

nobody wrote on Wednesday, August 30, 2006:

Hi Janusz,

Thank you very much for the info, you gave me some very good tips.
You mentioned the system crashing: stack overflow problems maybe?

Also, if you want to look at a simplified version of a PPP+TCP implementation here’s a project that may also do the trick for us: http://www.avrfreaks.net/index.php?module=Freaks%20Academy&func=viewItem&item_type=project&item_id=199

If I have enough time I’ll see if I can port it on my STR712.

Many thanks,

Vard

nobody wrote on Wednesday, August 30, 2006:

sys_msleep(1) in ppp.c sometimes was reason of ppp hangs - I commented this line, you can change this line to taskyield or vdelay but this function is not good for 1ms (because it operates on semaphores).

For lwIP debug you shoudn’t use brackets for LWIP_PLATFORM_DIAG(x):
#define LWIP_DEBUG
extern void kprintf(const char *format,…);
#define LWIP_PLATFORM_DIAG(x) kprintf x

#define DBG_TYPES_ON                    0xff
#define ETHARP_DEBUG                    DBG_OFF
#define NETIF_DEBUG                     DBG_ON
#define PBUF_DEBUG                      DBG_OFF
#define API_LIB_DEBUG                   DBG_OFF
etc.

IP_DEBUG is powerful debug but unfortunately slow (generates text tables). PBUF_DEBUG causes I can’t connect via ppp. I guess because of slow debug kprintf…

I have found another my mistake: bad declaration of SP (top of stack pointer) for supervisor mode in startup.S, the stack was for 16kB of RAM and now my arm has 64kB.

thanks,
Janusz

P.S. There are 3 stacks:
- natural for main function during start, IRQ, FIRQ etc.
- freeRTOS: xHeap[] (heap_2.c), queues.c (for their data) and tasks.c (for task contexts) uses the stack
- lwIP: ram[] (mem.c) and memp.c, pbuf.c uses mem.c and ppp uses pbuf…

My http server is still cashing after port opening even when MEM_SIZE is 4000. I have not idea.

nobody wrote on Friday, September 01, 2006:

My PPP, IP, ICMP is stable. I made tests by "ping ip -f" command. Problem was bad service of usart interrupt because I did not use loop for usart status word. It caused the interrupt was blocked.

I hope I have the last problem with my OS and TCPIP stack: system crashes after TCP establish:/ But I can talk the PPP (it is from BSD at least!), after some bugs removing, is ok.

best rgs
Janusz

nobody wrote on Sunday, September 03, 2006:

problem is solved but I am fraid now - it works only with -O1 and -O2 (this was reason of my problems!!! horrible), does not with -Os and -O0(there is problem on OS level)

Janusz

nobody wrote on Monday, September 04, 2006:

Hello,

I also did a port of lwIP + ppp for FreeRTOS on a STR711 device. The device works with 115200 baud and a typical latency of 34ms for ping requests. I did some basic testing with flood pings and a parallel Modbus/TCP application and it seems stable.
In addition I improved the lwIP/FreeRTOS port and fixed some bugs in the PPP implementatin (pppClose crashes system, …). The port is part of my Modbus RTU/ASCII stack and can be found on http://freemodbus.berlios.de. The files in question are in demo/STR71XTCP/ where the lwIP specifics can be found in demo/STR71XTCP/lwip/contrib/…

Regards,
  Christian Walter

nobody wrote on Monday, September 04, 2006:

great work! thanks a lot!
Unfortunately my OS crashes (stack overflow/data abort irq/memory errors) even if I used your lwip/src directory and corrected lwip/contrib. PPP was working and is working, lwIP too. Pings are ok but my http server not always (I used code from FreeRTOS demo lwIP_Rowley for at91sam7x256). I think I have problem with gcc compiler (I can’t run stable FreeRTOS with either -O0 or -Os) or with lwipopt.h and FreeRTOSConfig.h configuration files.

best regards
Janusz

nobody wrote on Tuesday, September 05, 2006:

The WEB server can take a lot of stack under GCC due to the inclusion of string handling functions.  Do you make use of stdio functions such as sprintf?

The lwIP code used by freertos provides lots of stack to -all- the tasks used by lwIP.  lwIP creates and deletes tasks itself, so the tasks it creates, plus your web server task, need big stack.  Other compilers this is not such an problem as their libraries are written specifically for embedded systems.  The GCC libraries unfortunately are not.

Take a look constants netifINTERFACE_TASK_STACK_SIZE, lwipTCP_STACK_SIZE and lwipBASIC_SERVER_STACK_SIZE in the lwip demo.

nobody wrote on Wednesday, September 06, 2006:

thanks for the info
Janusz

nobody wrote on Wednesday, September 06, 2006:

Hi Christian,

here is small bug i think (sys_arch.c):
sys_thread_t
sys_arch_thread_new( void ( *thread ) ( void *arg ), void *arg, int prio, size_t ssize )
{
    sys_thread_t    thread_hdl = SYS_THREAD_NULL;
    static int      i = 0;
    sys_tcb_t      *p;

    /* We disable the FreeRTOS scheduler because it might be the case that the new
     * tasks gets scheduled inside the xTaskCreate function. To prevent this we
     * disable the scheduling. Note that this can happen although we have interrupts
     * disabled because xTaskCreate contains a call to taskYIELD( ).
     */
    vPortEnterCritical(  );
    vTaskSuspendAll(  );

    p = tasks;
//    i = 0;
    /* We are called the first time. Initialize it. */
    if( p == NULL )

best regards
Janusz

nobody wrote on Wednesday, September 06, 2006:

sorry, my mistake, it was ok in code, but I have two tasks lwIP0?!

Janusz

nobody wrote on Wednesday, September 06, 2006:

Dear Christian,

is it necessery dual section:
    vPortEnterCritical(  );
    vTaskSuspendAll(  );
in sys_arch_thread_new?

I think sys_arch_thread_remove inludes mistakes. It does not free tcb memory. After many ppp connection attempts system does not create any ppp task -> heap is full.

What do you think about?

Janusz

nobody wrote on Wednesday, September 06, 2006:

Look, I think it is ok now:

sys_thread_t
sys_arch_thread_new( void ( *thread ) ( void *arg ), void *arg, int prio, size_t ssize )
{
    sys_thread_t    thread_hdl = SYS_THREAD_NULL;
    int             i;
    sys_tcb_t      *p;

    /* We disable the FreeRTOS scheduler because it might be the case that the new
     * tasks gets scheduled inside the xTaskCreate function. To prevent this we
     * disable the scheduling. Note that this can happen although we have interrupts
     * disabled because xTaskCreate contains a call to taskYIELD( ).
     */
    vPortEnterCritical(  );
//    vTaskSuspendAll(  );

    p = tasks;
    i = 0;
    /* We are called the first time. Initialize it. */
    if( p == NULL )
    {
        p = pvPortMalloc( sizeof( sys_tcb_t ) );
        if( p != NULL )
        {
            tasks = p;
        }
    }
    else
    {
        i++;
        while( p->next != NULL )
        {
            p = p->next;
            i++;
        }
        p->next = pvPortMalloc( sizeof( sys_tcb_t ) );
        p = p->next;
    }

    if( p != NULL )
    {
        /* Memory allocated. Initialize the data structure. */
        THREAD_INIT( p );
        ( void )snprintf( p->name, THREAD_NAME_LEN_MAX, "lwIP%d", i );

        /* Now q points to a free element in the list. */
        if( xTaskCreate( thread, p->name, ssize, arg, prio, &p->pid ) == pdPASS )
        {
            thread_hdl = p;
        }
        else
        {
            vPortFree( p );
        }
    }

//    ( void )xTaskResumeAll(  );
    vPortExitCritical(  );
    return thread_hdl;
}

void
sys_arch_thread_remove( sys_thread_t hdl )
{
    sys_tcb_t      *current = tasks, *prev;
    sys_tcb_t      *toremove = hdl;
    xTaskHandle     pid = ( xTaskHandle ) 0;

  //  LWIP_ASSERT( "sys_arch_thread_remove: assertion hdl != NULL failed!", hdl != NULL );

    /* If we have to remove the first task we must update the global “tasks”
     * variable. */
    vPortEnterCritical(  );
    if( hdl != NULL )
    {
        prev = NULL;
        while( ( current != NULL ) && ( current != toremove ) )
        {
            prev = current;
            current = current->next;
        }
        /* Found it. */
        if( current == toremove )
        {
            /* Not the first entry in the list. */
            if( prev != NULL )
            {
                prev->next = toremove->next;
            }
            else
            {
                tasks = toremove->next;
            }
      //      LWIP_ASSERT( “sys_arch_thread_remove: can’t remove thread with timeouts!”,
      //                   toremove->timeouts.next == NULL );
            pid = toremove->pid;
            vPortFree( toremove );
        }
    }
    /* We are done with accessing the shared datastructure. Release the
     * resources.
     */
    vPortExitCritical(  );
    if( pid != ( xTaskHandle ) 0 )
    {
        vTaskDelete( pid );
        /* not reached. */
    }
}

best rgs
Janusz

nobody wrote on Wednesday, September 06, 2006:

Hello,

You are right. vTaskSuspendAll is no longer necessary. It was in there in the first version of my code because it was based on the FreeRTOS for the AT91SAM7X example. If you look at that ( old )code it contains the following lines:

result = xTaskCreate( thread, ( signed portCHAR * ) "WEBSvr", lwipBASIC_SERVER_STACK_SIZE, arg, prio, &CreatedTask );
}

timeoutlist[nextthread++].pid = CreatedTask;

Within xTaskCreate a context switch occurs when the calling thread has lower priority than the created one. This can lead to bugs because the timeoutlist pid member is not initialized. Code typically then break when the timeouts function is called.

Anyway - With the new code it is solved because everything is initialized before calling xTaskCreate.

Kind regards,
  Christian

nobody wrote on Wednesday, September 06, 2006:

I hope without bugs:

sys_thread_t
sys_arch_thread_new( void ( *thread ) ( void *arg ), void *arg, int prio, size_t ssize )
{
    sys_thread_t    thread_hdl = SYS_THREAD_NULL;
    int             i;
    sys_tcb_t      *p;

    /* We disable the FreeRTOS scheduler because it might be the case that the new
     * tasks gets scheduled inside the xTaskCreate function. To prevent this we
     * disable the scheduling. Note that this can happen although we have interrupts
     * disabled because xTaskCreate contains a call to taskYIELD( ).
     */
    vPortEnterCritical(  );
//    vTaskSuspendAll(  );

    p = tasks;
    i = 0;
    /* We are called the first time. Initialize it. */
    if( p == NULL )
    {
        p = pvPortMalloc( sizeof( sys_tcb_t ) );
        if( p != NULL )
        {
            tasks = p;
        }
    }
    else
    {
        i++;
        while( p->next != NULL )
        {
            p = p->next;
            i++;
        }
        p->next = pvPortMalloc( sizeof( sys_tcb_t ) );
        p = p->next;
    }

    if( p != NULL )
    {
        /* Memory allocated. Initialize the data structure. */
        THREAD_INIT( p );
        ( void )snprintf( p->name, THREAD_NAME_LEN_MAX, "lwIP%d", i );

        /* Now q points to a free element in the list. */
        if( xTaskCreate( thread, p->name, ssize, arg, prio, &p->pid ) == pdPASS )
        {
            thread_hdl = p;
        }
        else
        {
            vPortFree( p );
        }
    }

//    ( void )xTaskResumeAll(  );
    vPortExitCritical(  );
    return thread_hdl;
}

void
sys_arch_thread_remove( sys_thread_t hdl )
{
    sys_tcb_t      *current = tasks, *prev;
    sys_tcb_t      *toremove = hdl;
    xTaskHandle     pid = ( xTaskHandle ) 0;

  //  LWIP_ASSERT( "sys_arch_thread_remove: assertion hdl != NULL failed!", hdl != NULL );

    /* If we have to remove the first task we must update the global “tasks”
     * variable. */
    vPortEnterCritical(  );
    if( hdl != NULL )
    {
        prev = NULL;
        while( ( current != NULL ) && ( current != toremove ) )
        {
            prev = current;
            current = current->next;
        }
        /* Found it. */
        if( current == toremove )
        {
            /* Not the first entry in the list. */
            if( prev != NULL )
            {
                prev->next = toremove->next;
            }
            else
            {
                tasks = toremove->next;
            }
      //      LWIP_ASSERT( “sys_arch_thread_remove: can’t remove thread with timeouts!”,
      //                   toremove->timeouts.next == NULL );
            pid = toremove->pid;
            vPortFree( toremove );
        }
    }
    /* We are done with accessing the shared datastructure. Release the
     * resources.
     */
    vPortExitCritical(  );
    if( pid != ( xTaskHandle ) 0 )
    {
        vTaskDelete( pid );
        /* not reached. */
    }
}

Janusz