Raspberry Pi and mbed communication using the USB virtual com port

In some cases, it might be useful to use mbed with a Raspberry Pi. Mbed could do some real-time I/O tasks that might run too slow on the Pi under Linux or perhaps some extra I/O features on mbed are needed. The mbed could be plugged into the Pi's USB port for both power and communication using the USB virtual com port. A demo program will be provided for each device showing how to communicate between the two devices. If a lot of commands are needed, the mbed serial RPC library could be used.

On a Pi Zero W, the mbed board's USB virtual com port shows up in Linux as "/dev/ttyACM0". Using standard Linux file system I/O API calls it is possible to communicate with mbed just like a serial port by opening this device (when mbed is attached to one of it's USB ports) and using file write and read commands. Screen or minicom using this device name could also be used to type Linux commands to send to mbed without any code to check the hardware setup, but they must be installed first using apt-get in most Pi Linux distributions. It is possible that the device name might change if several other USB devices are plugged in (especially if they also have USB virtual com ports). One way to check for this is to type "ls /dev/ttyACM*" in the Pi console window to list any similar devices. If it does have a slightly different device name it will need to be changed in the open call in the demo code. The mbed device name will not show up unless it is plugged in.

mbed side demo code

To demo this communication setup, a short test program is needed for mbed. The code below reads in characters from the USB virtual com port and echoes them back using interrupts. Led1 on mbed toggles indicating interrupt character receive activity. To show that commands from the Pi can control the mbed, whenever the receive character is a '1' led2 turns on, and when a '0' is received led2 turns off. The mbed led pin assignments are for the LPC1768, if another mbed board is used change the led pins names.

#include "mbed.h"
//Pi mbed USB Slave function
// connect mbed to Pi USB
RawSerial  pi(USBTX, USBRX);

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);
 
void dev_recv()
{
    char temp = 0;
    led1 = !led1;
    while(pi.readable()) {
        temp = pi.getc();
        pi.putc(temp);
        if (temp=='1') led2 = 1;
        if (temp=='0') led2 = 0;
    }
}
int main()
{
    pi.baud(9600);
    pi.attach(&dev_recv, Serial::RxIrq);
    while(1) {
        sleep();
    }
}

Pi side demo code

The code for the Pi will open the USB virtual com port checking for errors, then write out a header message, read it back and display it in a terminal window. It then sends the led off/on commands (i.e., a '1' and then '0') to mbed ten times with a one second delay using sleep(). Finally, it closes the port and exits. There are a lot of options to setup the serial port in Linux on the Pi!

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>

int main(int argc, char ** argv) {
  int fd;
  char buf[256];
  int n;
  // Open the Port. We want read/write, no "controlling tty" status, 
  // and open it no matter what state DCD is in
  fd = open("/dev/ttyACM0", O_RDWR | O_NOCTTY | O_NDELAY);  
  //open mbed's USB virtual com port
  if (fd == -1) {  
    perror("open_port: Unable to open /dev/ttyACM0 - ");
    return(-1);
  }
  // Turn off blocking for reads, use (fd, F_SETFL, FNDELAY) if you want that
  fcntl(fd, F_SETFL, 0);
  //Linux Raw serial setup options
  struct termios options; 
  tcgetattr(fd,&options);   //Get current serial settings in structure
  cfsetspeed(&options, B9600);   //Change a only few
  options.c_cflag &= ~CSTOPB;
  options.c_cflag |= CLOCAL;
  options.c_cflag |= CREAD;
  cfmakeraw(&options);
  tcsetattr(fd,TCSANOW,&options);    //Set serial to new settings
  sleep(1);
  // Write to the port
  n = write(fd,"Hello mbed\r",11);
  if (n < 0) {
    perror("Write failed - ");
    return -1;
  }
  // Read the characters from the port if they are there
  sleep(2);
  n = read(fd, buf, 11);
  if (n < 0) {
    perror("Read failed - ");
    return -1;
  } else if (n == 0) printf("No data on port\n");
  else {
    buf[n] = 0;
    printf("%i bytes read back: %s\n\r", n, buf);
  }
  sleep(1);
  //Send command to blink mbed led 10 times at one second rate
  //mbed code turns on led2 with a '1' and off with a '0'
  //mbed echoes back each character
  buf[1] = '\r'; // end of line
  buf[2] = 0; // end of string
  for(int i=0;i<10;i++) {
	  write(fd,"1",1);        //led on
	  sleep(1);	              //one second delay  
	  read(fd,buf,1); //read echo character
	  printf("%s\n\r",buf);   //print in terminal window
	  write(fd,"0",1);        //led off
	  sleep(1);	  
	  read(fd,buf,1);
	  printf("%s\n\r",buf);
  }
  // Don't forget to clean up and close the port
  tcdrain(fd);
  close(fd);
  return 0;
}

Running the Demo

Download the earlier code to mbed, and then plug it into the Pi's USB connector. Then run the code above on the Pi. The leds will blink on the mbed, and a new terminal window on the Pi will show the printf's output while the program is running. It outputs error messages, if there is a open or read error return. Errors will occur if the mbed is not plugged in and running the test code, or an open error might indicate the device name needs to be changed.

/media/uploads/4180_1/pi2mbed.png

Pi terminal output window sending data to and receiving data from mbed using the USB virtual com pot. '1's and '0's from the Pi toggle an led on the mbed board.

BeagleBone Boards

Mbed can also be plugged into a BeagleBone Board's USB connector for the same purpose. The device name is the same (i.e., dev/ttyACM0), so the same two demo programs work. It was tested on a BeagleBone Black Wireless board. If mbed has any external I/O devices drawing power, a powered USB hub may be needed.


Please log in to post comments.