11 years, 3 months ago.

Controller hangs once a serial interrupt is detected when listening for client

Hi All,

I'm trying to create a simple Serial-to-Ethernet converter using a MBED development board. I've chosen to use the 'TCPEchoSever' example (http://mbed.org/handbook/Socket) as a starting point, and then bolted on the serial interface using the serial API protocols (http://mbed.org/handbook/Serial). Unfortunately due to its intended application I need to use TCP go guarantee reliable transmission.

The problem I’m having is that the controller appears to hang after receiving data on the serial interface (using interrupts) whilst the TCP socket server is listening for a new client. I know that the controller has reached the serial RX interrupt routing as I’ve configure the device to illuminate an LED, unfortunately after that it becomes unresponsive. Independently the code works perfectly, it only happens once the two are merged together. Unfortunately the forum won’t allow me to attach the source code, as its not that much different from the examples used on the website (effectively a combination of the 'TCPEchoSever’ and ‘Attach to RX Interrupt’ examples) there’s probably no point.

Does anyone have any ideas as to why this is happening? Has any used the device as a Server-Client with the serial interrupts active?

#include "mbed.h"
#include "EthernetInterface.h"
#include "main.h"

#define ECHO_SERVER_PORT   7

DigitalOut myled1(LED1);
DigitalOut myled2(LED2);
DigitalOut myled3(LED3);
DigitalOut myled4(LED4);
Serial pc(USBTX, USBRX); // MC to PC serial port (debug);
LocalFileSystem local("local");

char address[]="192.168.1.101";

void comms::PcTransmit (const char * tx_buffer)
{
    pc.printf("%s", tx_buffer);
}

void callback()
{
    // Note: you need to actually read from the serial to clear the RX interrupt
    while(1) {
        if(pc.readable()) {
             myled4 = !myled4;
             pc.printf("%c\n", pc.getc());
        }
    }
}

int main()
{
    static char cipaddress[16];  // ip address
    static char csubnetmask[16];  // mac address
    static char cgateway[16];  // mac address
    bool icheckstring;
    int x = 0;

    myled3 = 0;
    wait(2);

    EthernetInterface eth;
/****************************** not used due to other issues ****************************************/
    pc.printf("\n\rOpening File...\n\r"); // Drive should be marked as removed

    FILE *fp = fopen("/local/config.txt", "r");
    if(!fp) {
        fprintf(stderr, "File /local/config.txt could not be opened!\n\r");
        //turn on LED
        myled3 = 1;
        exit(1);
    }

    wait(2);

    pc.printf("Reading Data...\n\r");

    //scan untill you hit then end of the document and put everything in YourText as a string
    while (!feof(fp)) {
        fscanf (fp,"%*s %s %*s %s %*s %s",cipaddress,csubnetmask,cgateway);
    }
    pc.printf("IP Address = %s\n\r",cipaddress);
    pc.printf("size of IP Address = %d\n\r",sizeof(cipaddress));
    pc.printf("Subnet Mask = %s\n\r",csubnetmask);
    pc.printf("Default Gateway = %s\n\r",cgateway);

    wait(2);

    pc.printf("Closing File...\n\r");
    fclose(fp);

    // Drive should be restored. this is the same as just returning from main
/********************************************************************************************/
    wait(2);

    // Setup Ethernet port
    eth.init("192.168.1.101","255.255.255.0","192.168.1.4");
    //eth.init(cipaddress,csubnetmask,cgateway);
    eth.connect();
    pc.printf("IP Address is %s\n\r", eth.getIPAddress());

    TCPSocketServer server;
    server.bind(ECHO_SERVER_PORT);
    server.listen();
    pc.attach(&callback);

    while (true) {
        pc.printf("Wait for new connection...\n\r");
        TCPSocketConnection client;
        server.accept(client);
        client.set_blocking(false, 1500); // Timeout after (1.5)s
        pc.printf("Connection from: %s\n\r", client.get_address());
        char buffer[1542]; //was 256
        while (true) {
            int n = client.receive(buffer, sizeof(buffer));
            if (n <= 0) break;
            client.send_all(buffer, n);
            x=n;
        }
        pc.printf("Payload size = %d\n\r", x);

        if (x > 0) {
            int i = 0;
            while (i<=x){
               pc.putc(buffer[i]);
               i++;
            }
            pc.printf("\n\r");
        }

        client.close();
    }

    pc.printf("Client Session Closed\n\r");
}

Question relating to:

Two ways to attach source code, short, simple programs simply copy them and put <<code>><</code>> around them (on seperate lines). Longer programs, or with specific libraries, right mouse button on them in the compiler and publish them. Then place the link towards them. Without code it is very hard to guess the problem, it reaches your interrupt, so what happens next depends on your code.

posted by Erik - 19 Dec 2012

Hi Erik,

Apologies, this is my first time posting to one of these forums, attaching the code seemed the easiest method. Your see there is an unused section code above, this is another bug which I’ve been unable to rectify. All I was trying to do here was read the IP, SUBNET and GATEWAY from a config file (format of which is shown below). The code does seem to work in the sense that its parses the correct values to ‘eth.init’ (line 79), but the IP address that is replies with is completely different. Annoyingly using a literal appears to work fine (line 78).

local_IP_address: 192,168,1,101
mac_address: 255,255,255,0
default_gateway: 192.168.1,4
posted by Alan Matthews 19 Dec 2012

Sorry Erik,

Tried to clean it up before I posted it, obviously missed abit. It was originally hanging when callback function read:

void callback()
{
    myled4 = !myled4;
    pc.printf("%c\n", pc.getc());
}

Thanks for the extremely quick response though!

posted by Alan Matthews 19 Dec 2012

Does the printf work, and does the interrupt keep working, so if you send several chars, do you get them all back?

posted by Erik - 19 Dec 2012

No, printf doesn't work, neither does the LED change state when I enter several other characters afterwards. Also, during the test The board happily responded to pings up until the point a character is received, at this point the board failed to respond.

posted by Alan Matthews 19 Dec 2012

No experience myself with ethernet, my last few ideas: If you add a short wait after printf, does it then print? If you remove printf? And try in your main setting: NVIC_SetPriority(UART0_IRQn, 1);. That lowers priority of serial interrupts.

posted by Erik - 19 Dec 2012

Hi Erik, tried your suggestions and unfortunately no change.

I've done a little more digging by butchering the code and the problem doesn’t appear to stem from the ‘EthernetInterface’ libraries at all, the controller appears to hang following an RX interrupt on the serial port when the 'rtos' libraries are included within project (irregardless of it being used or not).

I’m really stumped? In order to see if the problems isolate to only the serial interrupt I'm planning to try a GPIO interrupt instead.

posted by Alan Matthews 20 Dec 2012

Can you post the simplest example with least amount of code where you still get the error? Just to be sure btw: are you using the latest mbed library? If you made this project recently, then yes. If more than 2 weeks ago, click on the mbed library in your project, and at right side you got update option. There have been errors in serial IRQ handler which have been fixed in later releases.

posted by Erik - 20 Dec 2012

OK, it seems someone else found this issue:

http://mbed.org/users/tylerjw/notebook/buffered-serial-with-rtos/

posted by Alan Matthews 20 Dec 2012

Erik, Started this project on Monday therefore the 'mbed' library is upto date. Just to confirm this statement was true I updated the mbed library with the latest version and I still get the same issues.

The simplest example of the bug is shown below, same issue occurs when the RTOS library is included within the project but not used.

#include "mbed.h"

DigitalOut myled1(LED1);
DigitalOut myled4(LED4);
Serial pc(USBTX, USBRX); // MC to PC serial port (debug);

void callback(){
    myled4 = !myled4;
}

int main()
{  
    pc.attach(&callback);
    
    while (1) 
    {
        myled1 = !myled1;
        wait(1);        
    }
}

(EDIT) Also I have revision 8 of the 'mbed_rtos' libraries.

posted by Alan Matthews 20 Dec 2012

Just found this code which actually resolves the problem, it does look like a bug!

http://mbed.org/users/alexwhittemore/code/threadinterrupt/file/32a3e697c11f/main.cpp

#include "mbed.h"

DigitalOut myled1(LED1);
DigitalOut myled4(LED4);
Serial pc(USBTX, USBRX); // MC to PC serial port (debug);
uint32_t UART_0_RBR;

void callback(){
    	UART_0_RBR = LPC_UART0->RBR;            // Clear the RBR flag to make sure the interrupt doesn't loop
myled4 = !myled4;
}

int main()
{  
    pc.attach(&callback);
    
    while (1) 
{
        myled1 = !myled1;
        wait(1);        
    }
}
posted by Alan Matthews 20 Dec 2012

What you now show is a completely seperate issue. You need to read from the interrupt to clear it, which was going wrong in the one you posted above. In this one a method is added to manually clear the interrupt, however pc.getc() should do the same and is present. You can try adding that line in your code though, depending on printf implementation it might be an issue.

posted by Erik - 20 Dec 2012

I originally tried both 'pc.getc()' and 'printf' which supposedly cleared the interrupt, unfortunately neither worked which resulted in me posting this question. On re-instating 'pc.getc()' after the interrupt has been manually cleared using 'UART_0_RBR = LPC_UART0->RBR;' results in the same issue, device hangs. The only way it appears you can do anything with the incoming data is to use a thread as per my previous link.

posted by Alan Matthews 20 Dec 2012

1 Answer

11 years, 3 months ago.

I quickly checked your code, and it is a little, although important, mistake. Your serial IRQ handler:

void callback()
{
    // Note: you need to actually read from the serial to clear the RX interrupt
    while(1) {
        if(pc.readable()) {
             myled4 = !myled4;
             pc.printf("%c\n", pc.getc());
        }
    }
}

There is a while(1) there, unless there is also a break, a while(1) will never stop. So it is forever stuck in the IRQ handler. What you probably wanted is:

void callback()
{
    // Note: you need to actually read from the serial to clear the RX interrupt
    while(pc.readable()) {
        myled4 = !myled4;
        pc.printf("%c\n", pc.getc());
    }
}