Using WiflyInterface together with RTOS

07 Jul 2014

Hi,

I'm trying to use WiflyInterface together with RTOS, and I've run in to some problems.

It works fine as long as it is the only thread running (along with the main thread, which does nothing but wait for mail from other threads, so when they are not activated it essentially does nothing).

Once I start another thread, the WiflyInterface thread will almost immediately deadlock.

I searched around a bit, and found this: https://mbed.org/users/leihen/notebook/using-wifly-interface-with-rtos-to-implement-a-htt/

It suggests replacing the tx interrupt with this, instead of using getc:

while (wifi.readable()) { char c = LPC_UART3->RBR; buf_wifly.queue(c); }

This does not seem to help, and when I look inside the WiflyInterface classes, I see that it is using RawSerial, which I thought was supposed to be a thread safe version of Serial, thus making it ok to call getc in an interrupt handler.

For reference, the two other threads on the system are as follows:

  • Communicating with serial bluetooth tranceiver on serial port (p27,p28) by polling, no interrupts
  • Communicating with an SPI device

It doesn't seem to matter what the other threads do or if I enable only one or two of them. The two threads work together just fine when I do not enable the network thread.

10 Jul 2014

I've been using the WiFly module off and on for some time, but I have not yet coupled it with the RTOS. Can you simplify your program as much as possible while still demonstrating the failure? Perhaps instead of the serial BT module you could use the USB serial port? This may make it easier for others to try to help you out.

15 Jul 2014

That's a good idea... I'll give it a go.

16 Jul 2014

I've condensed my code down to this example that shows the failure.

When I run this code, the network thread will crash after 5-10 iterations, and only the serial thread will continue running.

If I comment out Thread t2(serial_thread); the network code runs just fine (although it tends to lose network connection after a few minutes, but that is probably a different issue).

wifly failing with rtos example

#include "mbed.h"
#include "rtos.h"

#include "WiflyInterface.h"
#include "HTTPClient.h"

#define WIFI_SSID               "xxx"
#define WIFI_SECURITY           WPA    // NONE, WEP_128 or WPA
#define WIFI_PASSWORD           "yyy"

WiflyInterface* wifly;
RawSerial* serial;

typedef struct {
    char message[32];
} mail_t;

Mail<mail_t, 16> mail_box;

bool serial_init()
{
    serial = new RawSerial(p13, p14);
    return true;    
}

void serial_thread(void const *args)
{
    DigitalOut serial_led(LED2);
    char buf[64];
    strncpy(buf, "hello is there anybody out there", 64);
    
    while (1) {
        serial_led = !serial_led;
        serial->printf(buf);
        
        mail_t *mail = mail_box.alloc();
        strncpy(mail->message, "Sent serial message", 32);
        mail_box.put(mail);

        Thread::wait(1000);
    }    
}


bool network_init()
{
    wifly = new WiflyInterface(p9, p10, p8, p30, WIFI_SSID, WIFI_PASSWORD, WIFI_SECURITY);
    
    if (wifly->init() < 0) // Init with DHCP
        return false;
        
    if (wifly->connect() < 0)
        return false;
    
    printf("IP Address is %s\n", wifly->getIPAddress());

    return true;
}

void network_thread(void const *args)
{
    DigitalOut network_led(LED1);
    HTTPClient http;
    char str[512];

    while (1) {
        network_led = !network_led;

        //GET data
        int ret = http.get("http://mbed.org/media/uploads/donatien/hello.txt", str, 128);

        if (!ret) {
            mail_t *mail = mail_box.alloc();
            strncpy(mail->message, str, 32);
            mail_box.put(mail);
        }
        else {
            mail_t *mail = mail_box.alloc();
            strncpy(mail->message, "Network error", 32);
            mail_box.put(mail);            
        }
        
        Thread::wait(1000);
    }
}


int main(void)
{
    DigitalOut main_led(LED4);
    printf("WIFLY test with RTOS");
    
    if (network_init()) {
        printf("Network init OK\n");
    }
    else {
        printf("Network init failed\n");
        while (1) {}    
    }
    
    serial_init();
        
    Thread t1(network_thread);
    Thread t2(serial_thread);
    char buf[32];

    while (1) {
       osEvent evt = mail_box.get();
        
        if (evt.status == osEventMail) {
            mail_t *mail = (mail_t*)evt.value.p;

            strncpy(buf, mail->message, 32);
            mail_box.free(mail);
            
            printf("Message: '%s'\n", buf);
        }
    }
}
16 Jul 2014

Another observation:

If I change the serial thread to only send mail messages and not touch the RawSerial interface, the network thread will still crash, but it seems to stay alive a bit longer.

17 Jul 2014

Hi Per J, G.

I'm some days away from being able to look at this myself. When you create the threads, there are optional parameters, including one to set the stack size. I can't help but wonder two scenarios at this moment - 1) the default stack size is too small and after some combination of execution, there is corrupted data, resulting in the crash. 2) there is a memory leak in one of the components, and after a while it is used up and corruption/allocation failure occurs.

For the default thread stack size - I wish I had advice other than to try values. I don't think there are any readily accessible tools to assess how much of the stack is used / free. I'm not used to this situation with other environments I've used. With a JTAG debugger, likely some inspection tools would be available. maybe the CMIS-DAP will do what you need, but I haven't experience with that.

Memory leak is another concerning item. I and others have attempted creating a some simple tool to find the largest free block, but in the presence of the RTOS, it too generally faults the system.

More recently, I came across this discussion on hard fault handlers. You can drop these in to your code and it might give a clue to what type of fault you are experience. There are other threads about dumping the stack on occurrence of a hard fault - but I haven't had a chance to try those out.

18 Jul 2014

No luck with any of the hard fault handlers.

Looks like it is stack size related: Changing the stack size for the network thread to DEFAULT_STACK_SIZE*2 made no difference, but DEFAULT_STACK_SIZE*4 seems to work.

My full app is better behaved with this change too, but the network thread still dies there after a while.

It would be nice to have some way to know when you have a stack overflow in one of your threads. I'll try and move more of the data I use in the threads to the heap (each thread currently allocates buffers on the stack), and maybe that will help further.