10 years, 9 months ago.

Small project with USBSerial library.Please help!

Hi all,

I'm doing a small project using mbed1768, in which i need to light an LED in Analog port of mbed MC through PC i.e. USB. In order to achieve that two simple solutions seems to come in to help, they are 1) Using 'USBSerial' wherein i'll have to poll for a command from PC(minicom) serial terminal. Making the device a Virtual serial port through USB, makes it. 2) Firmware API build to detect command through USB from the host using 'USBDevice' library which needs a simple driver and a small User Application in the host, I suppose.

First method seems simple even though the method 2 is preferable for my project. I'm not able to send the command from minicom terminal. What should be minicom settings for being able to send or receive data through PC terminal? What should be the Firmware code?

My Firmware code is like this, it is probably not working,

DigitalOut led(p18); USBSerial serial;

int main(void) { uint8_t buf[128] = {0}; uint8_t i = 0;

serial.scanf("%s", buf); for( i= 0; i <= 127; i++ ) if ( buf[i] == 1) { while(1) { led = !led; wait(0.5); } } }

This code was successfully compiling without errors. What am i missing, for i was not able to achieve the objective. Please help me in this regard. It is quite a bit urgent.

And what do i need to do, if the same project need to be done through making a USB Device, i mean a conventional USB device, using Firmware, Driver and Host's User API ? I just have to light and LED through a command or capture data, like from sensor and display it in the host. Kindly help me in either of the methods.

Thank you.!

3 Answers

10 years, 9 months ago.

Hi!

Using USB serial communication is the easiest way, What you need is a interrupt driven function, called when a character (data) is available in the serial buffer. Then you need a parser, to parse out directives from garbage - yes UARTs are offtenly error prone. Below is a copy paste from one of my projects. The function to get data, and a simple parser.

void Serial_get_data()
{
    if(serial.readable()) {  //if data are available

        ser_buf[i]=serial.getc();

      /*  if(ser_buf[i] == 0x08) {
            i--;
            ser_buf[i] = '\b';
        } */
       
        if (ser_buf[i] == '\r') { //if CR is recieved, we ended the sentence
            data_OK = 1; //we have something to parse
            i=0; //reset the counter
            
            Serial_parser(); //call the parser function
        } else {
            serial.putc(ser_buf[i]);
            i++;
            if(i>10) i=0; //we need only a few characters to turn a led on or off
        }
    }
}

void Serial_parser()
{

    if(data_OK) { //if everything is ok, data are available

        switch (ser_buf[0]) { 

            case 'L':
                if((ser_buf[1]=='e') && (ser_buf[2]=='1')) { //The command for turning led on is "Le1
                    led1 = 1; 
                }
                if((ser_buf[1]=='e') && (ser_buf[2]=='0')) { //the command for turning led off is "Le0"
                   led1 = 0;  
                }
                break;
        data_OK = 0; // we did what we have to do
        for(int x=0; x<10; x++) ser_buf[x] = 0; //clear buffer
    }
}

You allso need some global variable:

char ser_buf[10],i,data_OK;

and a interrupt definition in the MAIN routine:

serial.attach(&Serial_get_data);

the "serial" statement is for serial like Serial serial(USBTX,USBRX);

Hope it helps.

RGDS

Accepted Answer

Hi Mr. Gorazd,

Thank you very very much for the answer to the problem i'm facing. I have used these two functions you've provided me with. There are quite understandable ,elaborative and very good for the application i'm building and not error prone.

Still the data is not being transmitted or else something wrong going on. I don't understand what. I exactly implemented your code. That should actually work. But i dint.

Here look at the code. Am i missing anything here?

#include "mbed.h"
#include "USBSerial.h"
 
//Virtual serial port over USB

DigitalOut led1(p18);
Serial serial(USBTX,USBRX);

char ser_buf[10],i,data_OK;


void Serial_parser()                           // Parser function for Data in the Serial buffer
{
 
    if(data_OK) { //if everything is ok, data are available
 
        switch (ser_buf[0]) { 
 
            case 'L':
                if((ser_buf[1]=='e') && (ser_buf[2]=='1')) { //The command for turning led on is "Le1
                    led1 = 1; 
                }
                if((ser_buf[1]=='e') && (ser_buf[2]=='0')) { //the command for turning led off is "Le0"
                   led1 = 0;  
                }
                break;
        data_OK = 0; // we did what we have to do
        for(int x=0; x<10; x++) ser_buf[x] = 0; //clear buffer
    }
}
}

void Serial_get_data()                   // Aquiring serial data
{
    if(serial.readable()) {  //if data are available
 
        ser_buf[i]=serial.getc();
 
      /*  if(ser_buf[i] == 0x08) {
            i--;
            ser_buf[i] = '\b';
        } */
       
        if (ser_buf[i] == '\r') { //if CR is recieved, we ended the sentence
            data_OK = 1; //we have something to parse
            i=0; //reset the counter
            
            Serial_parser(); //call the parser function
        } else {
            serial.putc(ser_buf[i]);
            i++;
            if(i>10) i=0; //we need only a few characters to turn a led on or off
        }
    }
}

int main(void) {

   serial.attach(&Serial_get_data);
   Serial_get_data();
  
}

As i mentioned in the above comment to Mr. Erik, am i missing anything in the connections and minicom settings? Minicom settings are : 9600 8-N-1, H/W flow control and No S/W flow control. Connections : D+ and D- of USB connector to D+ and D- of mbed. GND, and VCC to VU of mbed. And i tried with TX p28 and RX p27 of mbed to D+, D- of USB connector. In this case the even device hasn't been detected( Known by 'dmesg' command').

What are your suggestions regarding this? Is there a mistake which i'm doing unknowingly?? Please let me know and help me out.

Thank you.

posted by VenkataSainath Ravikanti 03 Aug 2013
10 years, 9 months ago.

Use <<code>> and <</code>> to make code readable.

If you just want a single character you can also use serial.getc(). But your goal is now to start blinking a led when a '1' is entered in the console? The problem with your current code is that it checks if the received chars are equal to 1, which apparantly is a 'start of heading': http://www.asciitable.com/. What you want is to check if the received char is equal to '1', then it checks if it is equal to ascii '1'.

For your second part if I understand you correctly you want to look at USB HID library: http://mbed.org/handbook/USBHID. Many programming frameworks have support for USB HID devices. But USBSerial might just be easier and work as well.

Hi Mr. Erik,

Thank you and happy for the response. Sorry for the bad code readability. Yes, my goal is light an LED through a command through serial terminal. Yeah, i expected that would be wrong, the '1' part. And i made sure that i use character '1' to poll. I used serial.scanf() as well as serial.getc();. But the goal hasn't been achieved. What are the connections? Did i miss something in connections part and minicom settings?

My minicom settings are: Baud rate: 9600, 8 bits, No parity, 1 stop bit. 9600 8-N-1. and the device after 'dmesg' detected as USBACM device with all PID,VID. So the device was ttyACM0. Connections : D+ , D- of USB connector to D+ and D- of mbed. GND, VUSB to VCC. And the respective connection to LED which i'm lighting.

And in USBHID, the problem with the script that should be running on the host is not available for Linux( my OS Ubuntu 12.04) and even for Windows too. So i couldn't check the possibilities of getting this done with USBHID. It seems as a mere preferable and possible solution to my problem, but i couldn't able to do with that. Any further way in that is possible?

posted by VenkataSainath Ravikanti 03 Aug 2013
10 years, 9 months ago.

Hi Mr. Gorazd,

Thank you very very much for the answer to the problem i'm facing. I have used these two functions you've provided me with. There are quite understandable ,elaborative and very good for the application i'm building and not error prone.

Still the data is not being transmitted or else something wrong going on. I don't understand what. I exactly implemented your code. That should actually work. But i dint.

Here look at the code. Am i missing anything here?

#include "mbed.h"
#include "USBSerial.h"
 
//Virtual serial port over USB

DigitalOut led1(p18);
Serial serial(USBTX,USBRX);

char ser_buf[10],i,data_OK;


void Serial_parser()                           // Parser function for Data in the Serial buffer
{
 
    if(data_OK) { //if everything is ok, data are available
 
        switch (ser_buf[0]) { 
 
            case 'L':
                if((ser_buf[1]=='e') && (ser_buf[2]=='1')) { //The command for turning led on is "Le1
                    led1 = 1; 
                }
                if((ser_buf[1]=='e') && (ser_buf[2]=='0')) { //the command for turning led off is "Le0"
                   led1 = 0;  
                }
                break;
        data_OK = 0; // we did what we have to do
        for(int x=0; x<10; x++) ser_buf[x] = 0; //clear buffer
    }
}
}

void Serial_get_data()                   // Aquiring serial data
{
    if(serial.readable()) {  //if data are available
 
        ser_buf[i]=serial.getc();
 
      /*  if(ser_buf[i] == 0x08) {
            i--;
            ser_buf[i] = '\b';
        } */
       
        if (ser_buf[i] == '\r') { //if CR is recieved, we ended the sentence
            data_OK = 1; //we have something to parse
            i=0; //reset the counter
            
            Serial_parser(); //call the parser function
        } else {
            serial.putc(ser_buf[i]);
            i++;
            if(i>10) i=0; //we need only a few characters to turn a led on or off
        }
    }
}

int main(void) {

   serial.attach(&Serial_get_data);
   Serial_get_data();
  
}

As i mentioned in the above comment to Mr. Erik, am i missing anything in the connections and minicom settings? Minicom settings are : 9600 8-N-1, H/W flow control and No S/W flow control. Connections : D+ and D- of USB connector to D+ and D- of mbed. GND, and VCC to VU of mbed. And i tried with TX p28 and RX p27 of mbed to D+, D- of USB connector. In this case the even device hasn't been detected( Known by 'dmesg' command').

What are your suggestions regarding this? Is there a mistake which i'm doing unknowingly?? Please let me know and help me out.

Thank you.

I would first try to add a serial.printf, and see if you receive that on your PC. You need the D+ and D- pins, otherwise it really cannot work.

If printf works fine, see if you can change the transmit settings. Not sure if minicom by default sends a '\r' or '\n' as enter.

posted by Erik - 03 Aug 2013

Hmmm, as I can see, you are using virtual serial USB, but the "Serial serial (USBTX,USBRX) is for the mbed serial port though the mini USB. Try to use the MBED com port instead. You can allso define a faster bitrate with serial.baud(115200) if you want. For using USBserial (virtal com), you have to use :

USBSerial serial;

instead. I hope you understand, what I tried to tell you. English is not my primary language, and I have sometimes troubles to clear myself ;)

RGDS

Ok, just some update. I unintentionlly made a mistake while deleting some stuff from the code. A bracket wasn't at the right position. Now this piece of code works, but WITH MBED com port, not with the USBserial. I was not able to make the code work properly. So far I used USBserial only with RTOS, and that worked for me, but with the classic type of programming, I'm not able to make it run. I'm able to read 1 character, after that the code freeze. But for now, I hope this will be good for your project. I will do some more debugging, and post a new piece of code.

RGDS

#include "mbed.h"
//#include "USBSerial.h"

//Virtual serial port over USB

DigitalOut led1(LED1);
Serial serial(USBTX,USBRX); //uncomment this for serial comm via mini USB - MBED
//USBSerial serial; //use this for a virtual com port on D+ & D-

char ser_buf[10],i,data_OK;

void Serial_parser()                           // Parser function for Data in the Serial buffer
{

    if(data_OK) { //if everything is ok, data are available

        switch (ser_buf[0]) {

            case 'L':
                if((ser_buf[1]=='e') && (ser_buf[2]=='1')) { //The command for turning led on is "Le1
                    led1 = 1;
                }
                if((ser_buf[1]=='e') && (ser_buf[2]=='0')) { //the command for turning led off is "Le0"
                    led1 = 0;
                }
                break;
            default:
            serial.printf("Command unkonwn \r\n");
        }
        data_OK = 0; // we did what we have to do
        for(int x=0; x<10; x++) ser_buf[x] = 0; //clear buffer
    }
}


void Serial_get_data()                   // Aquiring serial data
{
    if(serial.readable()) {  //if data are available - uncomment this for mini usb MBED
//      if(serial.available()) { //use this for virtual com port on D+ & D-
      
			ser_buf[i]=serial.getc();

        if (ser_buf[i] == '\r') { //if CR is recieved, we ended the sentence
            data_OK = 1; //we have something to parse
            i=0; //reset the counter

            Serial_parser(); //call the parser function
        } else {
            serial.putc(ser_buf[i]);
            i++;
            if(i>10) i=0; //we need only a few characters to turn a led on or off
        }
    }
}

int main(void)
{
    serial.attach(&Serial_get_data);
    
    while(1) {
			
    }

}
posted by Gorazd Rosbach 03 Aug 2013

Finally I got it working, but is not interrupt driven yet, but it works. I'll try with interrupts tomorrow. But if you hook your Virtual USB port, and type Le1 or Le0 into your terminal program, you will be able to turn on or off your led. Hit return for make the changes available.

RGDS

#include "mbed.h"
#include "USBSerial.h"

//Virtual serial port over USB

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);
USBSerial serial; //use this for a virtual com port on D+ & D-
Ticker t;


void Hartbeat()  //just for debugging  - to see if the program hangs
{
    led2 = !led2;
}

char i = 0;
char buf[30];


int main(void)
{
    t.attach(&Hartbeat,1.0);      //we periodically call the hartbeat function
    while(1) {
        if(serial.available()) {      //if there are data in the rxbuffer
            led3=!led3;                 //flash a led, to tell, that data is recieved
            buf[i]=serial._getc();        //store the character into buffer
            i++;                            //increment buffer index
            if (buf[i-1] == '\r') {       //if the last character was CR
                led4=!led4;                 //let me know eith a led
                if(buf[0]=='L' &&  buf[1]=='e' &&  buf[2]=='1')led1=1;        //Le1 turns led1 on
                if(buf[0]=='L' &&  buf[1]=='e' &&  buf[2]=='0')led1=0;        //Le0 turns led1 off
                i=0;                                                      //reset the index and start over
            }

        }
    }
}

posted by Gorazd Rosbach 03 Aug 2013

Hi Mr. Gorazd,

You made it happen. It is working. I tried it with other Command patterns and all other ports. It is successfully working. Finally i can contact my mbed through USBSearial.

Another point, you said MBED COM port, is that UART tx,rx of the mbed? Do we have connect D+ ,D- to tx and rx of any UART terminal of mbed? Because i wanna try that code too, which you said will only work with COM port, not USBSerial.

And your English is so good, i wonder why are you worrying about that.

Thank you Mr. Gorazd and Mr.Erik for helping me through. Both of you gave me the idea of how it is done. You guys are wonderful. Thank you once again. :) :)

posted by VenkataSainath Ravikanti 13 Aug 2013

What Gorazd meant (I think) is that there are two USB serial options for the mbeds: One is the USBSerial option which you now have working. This is done with the D+ and D- pins, and then you directly connect your computer to the USB pins of the LPC1768.

Then there is what Gorazd called the mbed com port, which is the USB connector on your mbed board. This is connected via another microcontroller that among other things implement a Serial <> USB bridge. You talk to it with Serial(USBTX, USBRX). Both result in serial over USB, but the first one the USB part is done by the LPC1768, the second one the LPC1768 just uses its UART to send serial messages, which are by anothr IC converted to USB.

posted by Erik - 13 Aug 2013

Thank you Mr. Erik. I'll look forward in that. But any micro-controller(which has UART) can do that?

posted by VenkataSainath Ravikanti 13 Aug 2013

With another IC added? Yes. But that other IC is required, you cannot connect a random microcontrollers UART to a USB connector.

On mbed it is done by a second microcontroller, which also allows the drag and drop programming. If you have a random other microcontroller, the FTDI chips are popular to convert Serial to USB: http://www.ebay.com/itm/FTDI-Basic-FT232R-FT232RL-Arduino-USB-to-RS232-TTL-Program-Download-/360717429961?pt=LH_DefaultDomain_0&hash=item53fc6f2cc9

posted by Erik - 13 Aug 2013

Hi Mr.Erik, I got it. I understood. It is available in our institute and i'll try with that too. Thank you Erik.

posted by VenkataSainath Ravikanti 13 Aug 2013