Interrupt Driven Serial Required in OS6

My many OS2 projects use the ‘BufferedSerial’ library by Sam Grove. This does what I need perfectly - interrupt driven serial, 100% reliable.
I can not use this in OS6 it seems, and whether I use BufferedSerial or UnbufferedSerial, the code is blocking. Code blocks until the last Tx char has been sent. No good. I need to implement an interrupt driven handler for Tx data at very least. To that end, I looked at ‘sigio’, the scant, terse documentation leading me to think this is used to direct serial interrupts to a handler of my own design. So please help, what’s wrong with the following, or what other methods should I look at instead.

This code does not compile,
[Error] main.cpp@31,34: expected ‘(’ for function-style cast or type construction

[ERROR] ./main.cpp:31:34: error: expected ‘(’ for function-style cast or type construction

but several hours fighting syntax - wasted.

#include "mbed.h"
BufferedSerial pc(USBTX, USBRX);

void    pc_Service ()    {
    // Need Tx and Rx interrupt redirecting to here
}

 int main()
{
    pc.set_blocking(false); //  Not convinced this has any effect.
/*
virtual void sigio 	( 	Callback< void()>  	func	) 	
	virtualinherited

Register a callback on state change of the file.

The specified callback will be called on state changes such as when the file can be written to or read from.

The callback may be called in an interrupt context and should not perform expensive operations.

Note! This is not intended as an attach-like asynchronous API, but rather as a building block for constructing such functionality.

The exact timing of when the registered function is called is not guaranteed and is susceptible to change. It should be used as a cue to make read/write/poll calls to find the current state.

Parameters
    func	Function to call on state change 
*/
    pc.sigio ( Callback< void()> pc_Service );
    printf("This is the bare metal blinky example running on Mbed OS %d.%d.%d.\n", MBED_MAJOR_VERSION, MBED_MINOR_VERSION, MBED_PATCH_VERSION);
    // Set desired properties (9600-8-N-1).
    while (1) {
    }
}

Hi Jon,

the following is probably correct

pc.sigio (callback(pc_Service));

BR, Jan

Many thanks Jan, with this the code compiles but it now seems ‘sigio’ does not work as advertised. In the following ‘globalcnt’ is never incremented. Any other thoughts much appreciated, thanks.

#include "mbed.h"
DigitalOut led1(LED1);
UnbufferedSerial pc(USBTX, USBRX);
int globalcnt = 0;

void pc_Service () { // Need Tx and Rx interrupt redirecting to here
    globalcnt++;    //  Never happens
}

 int main()
{
    char buf[25] = {0};
    pc.set_blocking(false); //  Not convinced this has any effect.
    pc.sigio (callback(pc_Service));  // Now compiles at least
   
    printf("This is the bare metal blinky example running on Mbed OS %d.%d.%d.\n", MBED_MAJOR_VERSION, MBED_MINOR_VERSION, MBED_PATCH_VERSION);
    while (1) {
        if (uint32_t num = pc.read(buf, sizeof(buf))) { //  Got 1 char
            led1 = !led1;   //  LED state toggles on each keyboard press
            printf("globalcnt %d  \r\n", globalcnt); // globalcnt stuck at 0
            // Echo the input back to the terminal.
            if(buf[0] == '\r'){
                pc.write("\n",1); // add newline to CR
            }
            pc.write(buf, num); // Correctly echo char
        }
    }
}

Hello Jon,

The following worked for me:

  • Create a new Mbed OS 6 project and copy & paste the following test code to the main.cpp:
#include "mbed.h"
#include "BufSerial.h"

BufSerial   pc(USBTX, USBRX);

int main()
{
    pc.baud(115200);

    while (1) {
        Timer   s;

        s.start();
        pc.printf("Hello World - buff\n");

        int buffered_time = s.read_us();
        ThisThread::sleep_for(100ms);  // give time for the buffer to empty
        s.reset();
        printf("Hello World - poll\n");

        int polled_time = s.read_us();
        s.stop();
        ThisThread::sleep_for(100ms);  // give time for the buffer to empty
        pc.printf("printf buffered took %d us\n", buffered_time);
        pc.printf("printf polled took %d us\n", polled_time);
        ThisThread::sleep_for(500ms);
    }
}
  • Import Sam Grove’s BufferedSerial library into the project.

To avoid name clash with the Mbed OS 6 BufferedSerial:

  • Right-click on the library’s name and select Convert to Folder.
  • Rename the BufferedSerial folder to (for example) BufSerial.
  • In the BufSerial folder rename the files BufferedSerial.h and BufferedSerial.cpp to BufSerial.h and BufSerial.cpp, respectively.
  • In the BufSerial.h and BufSerial.cpp rename the BufferedSerial class to BufSerial.
  • In the BufSerial.h file comment out the lines as below:
//#if (MBED_MAJOR_VERSION == 5) && (MBED_MINOR_VERSION >= 2)
//#elif (MBED_MAJOR_VERSION == 2) && (MBED_PATCH_VERSION > 130)
//#else
//#error "BufSerial version 13 and newer requires use of Mbed OS 5.2.0 and newer or Mbed 2 version 130 and newer. Use BufSerial version 12 and older or upgrade the Mbed version.
//#endif
  • In the BufSerial.h file replace:
#ifndef BUFFEREDSERIAL_H
#define BUFFEREDSERIAL_H
 
#include "mbed.h"
#include "MyBuffer.h"

with

#ifndef BUFSERIAL_H
#define BUFSERIAL_H
 
#include "mbed.h"
#include "RawSerial.h"
#include "MyBuffer.h"
  • In the BufSerial.cpp replace
#include "BufferedSerial.h"

with

#include "BufSerial.h"

and in the BufSerial constructor replace

    RawSerial::attach(callback(this, &BufferedSerial::rxIrq), Serial::RxIrq);

with

    RawSerial::attach(callback(this, &BufSerial::rxIrq), SerialBase::RxIrq);
  • Copy & paste the RawSerial.h and RawSerial.cpp files from the Mbed OS 2 repository to the BufSerial folder.
  • In the RawSerial.cpp file replace
#include "drivers/RawSerial.h"

with

#include "RawSerial.h"
  • Build the project and program your board.

  • Make sure you set the the serial monitor speed to 115200 when testing.

It could happen that I missed to indicate some steps I did so please let me know how it worked for you.

If it works you can use the BufSerial folder (copy & paste) as a library in your Mbed OS 6 projects :slight_smile:

Warning: Mbed OS 6 serial communication classes are POSIX 6 compliant (re-entrant and thread safe). However, the BufSerial is not. So use it with caution!

Best regards, Zoltan

1 Like

Thank you so much Zoltan, I’m working through this now and will let you know how it goes later.
Best Regards
Jon

Update - Thanks again Zoltan, having followed your instructions I now have a program running and reporting
printf buffered took 82us
printf polled took 1589us
This looks like what I expected, next I’ll try porting the new BufSerial folder to other projects, I’ll let you know how it goes later.
Best Regards
Jon

Update - Imported into a real project, all seems to work as expected. Many thanks Zoltan
Best Regards
Jon