Serial write OS6xx usage

Can someone help me with OS 6xx serial functions (using Mbed Studio)?
Mbed continuing to redesign the wheel, I was hoping they had got bored by now :slight_smile:

I’m updating from earlier versions with serial put and get but hit a small snag.

Sending a bunch of characters is okay but,
To send a single byte or character I’m using this:

oled.write((char*)0x55,1);   // send byte for OLED to autodetect baudrate 

No red or yellow squiggly underlines with that so it might work, can’t tell until I’ve fixed the rest of the code.

However one function needs some extra bit manipulation, last two commands, not sure if I can do this inside the command or if I have to handle it outside…

void OLED160G1::drawLine(char x1, char y1, char x2, char y2, int color) {
    oled.write(OLED_LINE);      // Line
    oled.write(x1);
    oled.write(y1);
    oled.write(x2);
    oled.write(y2);
    oled.write(color >> 8);      // MSB      stuck here    
    oled.write(color & 0xFF);    // LSB      and here
    getResponse();
}

Any help would be appreciated.

Hello Paul,

that is nothing new, Mbed OS 6 was released in middle of 2020.

try it like this

   oled.write(&y2, sizeof(y2));
   char msb = color >> 8;
   char lsb = color & 0xFF;
   oled.write(&msb, sizeof(msb ));  
   oled.write(&lsb, sizeof(lsb));

BR, Jan

Hello Paul,

Your code can become something like this.

void OLED160G1::drawLine(char x1, char y1, char x2, char y2, int color) {
    char buffer[] = { OLED_LINE, x1, y1, x2, y2, color >> 8, color & 0xFF };
    oled.write(buffer, 7);
    getResponse();
}

Best regards,
Yannic

Thank you Yannic.

That looks a bit more os6 compliant. I’ll try that and later but this is far as I got, but not working.
Can’t seem to get serial interrupt callback working like before.

OLED160G1::OLED160G1(PinName serialTx, PinName serialRx, PinName resetPin)
    : Oled(serialTx, serialRx), reset(resetPin) {
  Oled.baud(BAUDRATE);
  Oled.format(8,                // bits
              SerialBase::None, // parity
              1                 // stop bit
  );
  resetDisplay();
}

void OLED160G1::oledcb() {    // serial callback if serial port receives data
    while (Oled.readable()){
        Oled.read(&oledbuff[bufferIndex],1);
        bufferIndex++;
        }
    oledrx=1;
}

void OLED160G1::resetDisplay() {
    char c;
    reset = 0;
    wait_us(10000);
    reset = 1;
    wait_us(500000);
    while (Oled.readable()){
        Oled.read(&c,1);     
        }
    c = 0x55;

    Oled.attach(callback(this,&OLED160G1::oledcb),SerialBase::RxIrq); 
    Oled.write(&c,1); // send byte for OLED to autodetect baudrate 

    getResponse();    
    setFontSize(FONT5X7);
    setTextBackgroundType(TEXT_OPAQUE);
    setFontColor(WHITE); 
    drawText(0,0,(FONT5X7),(char*)"Oled160g1",toRGB(100,100,100));
    drawText(0,2,(FONT5X7),(char*)"Ready > ",toRGB(100,100,100));       
}

void OLED160G1::getResponse() {  
  t.reset(); t.start();
  while (chrono::duration_cast<chrono::milliseconds>(t.elapsed_time()).count() < 500) {
    if (oledrx) {
        oledrx = 0;
        //debug("response: %d\n",oledbuff[0]);
      if (oledbuff[0] == 6) { // 0x06 byte sent successful
        break;
      }
      if (oledbuff[0] == 21) { // 0x15 byte sent unsuccessful
        break;
      }
    }
  }
  bufferIndex=0;
  t.stop();
  return;
}

Hello Paul,

The only part of your code that I find problematic is the oledcb() function.

It’s an IRQ function so there is nothing blocking it.
It is triggered with each received character, so there is no need to loop or test the return of readable().

void OLED160G1::oledcb() {    // serial callback if serial port receives data
    Oled.read(&oledbuff[bufferIndex++],1);
    oledrx=1;
}

Best regards,
Yannic

For what it’s worth, this is actually a good use case for the new Mbed 6 asynchronous buffered serial.

You can actually completely remove the attach() call and the callback, and replace your waiting loop with something like this:

while (chrono::duration_cast<chrono::milliseconds>(t.elapsed_time()).count() < 500) {
    while (Oled.readable()){
           // read a byte using Oled.read() and process it
        }
  }

You will also need to make sure Oled is a BufferedSerial and set it to nonblocking mode, e.g. by adding this to the constructor:

Oled.set_blocking(false);

There’s more info in my guide here: Hitchhiker's Guide to Printf in Mbed 6

This goes back a while so I thought I would have another go.
All the suggestions were very helpful, thank you.
I now have it working reliably.
I’m using Nucleo L476, mbed-os 6.16.0, Mbed Studio.
The L476 didn’t like baud rates above 128k, where the F401 works stable up to 256k, the displays maximum rate. A bit strange, the L476 RM states up to 10Mbps with oversampling and I’m sure I’ve used this MCU serial up to 921600Bps on OS2.

The snip bellow does work, different display but same serial interface .
Problem I have using Unbuffered Serial is serial.read() is blocking no matter what I do.
With or without oled.set_blocking(false) , if there is no serial data the program hangs when it reaches it.
I do not need Buffered Serial particularly because I know when and how much data is being sent/received for each command.

So to get round this problem I used a timer to timeout oled.readable() after 100mS.
Now if there is a break in serial communication to the display for any reason it does not lock up the MCU and I can recover the display function.

bool oled32028::getResponse() {
  int ready = false;
  t.reset();
  while (!ready && t.elapsed_time().count() < 100000) { // 100mS timeout
    while (oled.readable()) {
      oled.read(&c, 1);
      ready = true;
    }
  }
  if (c == 0x06) { // byte sent successful
    // debug_if(dbg_on, "Okay c: %d\n", c);
    return 1;
  }
  if (c == 0x15) { // byte sent unsuccessful
    //debug_if(dbg_on, "Fail c: %x\n", c);
  }
  return 0; // timeout, fail
}

This proved the most efficient way to send data to the display;

void oled32028::drawLine(int x1, int y1, int x2, int y2, int color) {
char buffer[16];
  buffer[0] = 0x4C;
  buffer[1] = x1 >> 8;
  buffer[2] = x1 & 0xFF;
  buffer[3] = y1 >> 8;
  buffer[4] = y1 & 0xFF;
  buffer[5] = x2 >> 8;
  buffer[6] = x2 & 0xFF;
  buffer[7] = y2 >> 8;
  buffer[8] = y2 & 0xFF;
  buffer[9] = color >> 8;
  buffer[10] = color & 0xFF;
  oled.write(buffer, 11);
  getResponse();
}

oooh, the advantage of chrono is that you can deal directly with time units. Peeling of the count and comparing against unknown integer units is so ugly…

simply use:

	Timer t;
	t.start();

	while(t.elapsed_time() < 10s) {
		ThisThread::sleep_for(500ms);
	}

	// same as:
	while(t.elapsed_time() < 10'000ms) {
		ThisThread::sleep_for(500ms);
	}
1 Like

Thanks’ Johannes,
That is a lot neater, I’ve added that that to my “how to use Mbed 6” list.
Not so sure about the serial part if its the way to go.

ready = false;
t.reset();
while (!ready && t.elapsed_time() < 100ms){ // 100mS timeout
  while (oled.readable()) {
    oled.read(&c, 1);
    ready = true;
  }
}