Go Down

Topic: USB/Serial Communication Problems Win7<-> Arduino Mega (Read 1 time) previous topic - next topic

NBGer

Hi,
I have written a Windows GUI (VS2015, MFC) for controlling the Arduino Mega Application.
The Windows program is sending cyclically (every 250 ms) Messages to Arduino by accessing virtual COM-Port of Ardunio Mega USB driver.
After a few hundret messages the calls to serial interface slow down drastically (no "done" event for several seconds).

I assume, it is a problem in the Arduino USB-Serial COM Port driver.
When using another (real) COM-Port, my Windows application runs stable.
Further, I used the serial code in many other projects already without any problem.

My communication class is based on this library: https://www.codeproject.com/Articles/992/Serial-library-for-C.

Anybody, who has same experience? Any ideas, solutions?

Many thanks

Richard


Robin2

You need to post your Arduino program and describe how the PC program works. Give some examples of the messages the PC is sending and also examples of any messages the Arduino is sending to the PC.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

NBGer

ok....

I am on the very beginning of this project, so the arduino project is quite simple right now. I copied mostly from other samples.
The PC program has a simple GUI for some mode selection, reading buttons and reading joystick X and Y via HID (Human Interface Device) SDK.
All this values are sent in serial ASCII telegram (14 Bytes only) cyclically each 250 ms.


The Arduino sketch is controlling 2 DC motors (motor shield V1), depending on the information of serial cyclic telegram. Right now there is no information send back to PC!
Later on, when basic communication is working, the sketch will be expanded by Stepper control and more complex calculations

Arduino sketch:

#include <Servo.h>
#include <AFMotor.h>

#define LINE_BUFFER_LENGTH 1024

#define SPEED_MIN 60
#define SPEED_MAX 255
#define RAMP_STEP  2

AF_DCMotor Motor1(1,MOTOR12_1KHZ);
AF_DCMotor Motor2(2,MOTOR12_1KHZ);


// Set to true to get debug output.
boolean verbose = false;

bool button1 = false;
bool button2 = false;
bool button3 = false;

int JoyX = 0;
int JoyY = 0;

int SpeedHeel = 0;
int SpeedKnee = 0;
int SpeedHip = 0;

int mode = 0;   // off

typedef struct
{
 int n;
 AF_DCMotor* pdrv;
 int speed_act;
 int speed_soll;
}m_t;

m_t Heel = { 1, &Motor1,0,0 };
m_t Knee = { 2, &Motor2,0,0 };

/**********************
* void setup() - Initialisations
***********************/
void setup() {
 //  Setup
 
 Serial.begin( 115200 );
 
 //  Notifications!!!
 Serial.println("Control Humanoid alive and kicking!");


 Motor1.setSpeed(0);
 Motor1.run(RELEASE);

 Motor2.setSpeed(0);
 Motor2.run(RELEASE);

}

/**********************
* void loop() - Main loop
***********************/
void loop()
{
 char line[ LINE_BUFFER_LENGTH ];
 char c;
 int lineIndex;
 bool lineIsComment, lineSemiColon;

 lineIndex = 0;
 lineSemiColon = false;
 lineIsComment = false;

 while (1)
 {

    // Serial reception - Mostly from Grbl, added semicolon support
   while ( Serial.available()>0 )
   {
     Serial.println( "getc" );
     c = Serial.read();
     if (( c == '\n') || (c == '\r') ) {             // End of line reached
       if ( lineIndex > 0 ) {                        // Line is complete. Then execute!
         line[ lineIndex ] = '\0';                   // Terminate string
         if (verbose) {
           Serial.print( "Received : ");
           Serial.println( line );
         }
         processIncomingLine( line, lineIndex );
         lineIndex = 0;
       }
       else {
         // Empty or comment line. Skip block.
       }
       lineIsComment = false;
       lineSemiColon = false;
       Serial.println("ok");    
     }
     else {
       if ( (lineIsComment) || (lineSemiColon) ) {   // Throw away all comment characters
         if ( c == ')' )  lineIsComment = false;     // End of comment. Resume line.
       }
       else {
         if ( c <= ' ' ) {                           // Throw away whitepace and control characters
         }
         else if ( c == '/' ) {                    // Block delete not supported. Ignore character.
         }
         else if ( c == '(' ) {                    // Enable comments flag and ignore all characters until ')' or EOL.
           lineIsComment = true;
         }
         else if ( c == ';' ) {
           lineSemiColon = true;
         }
         else if ( lineIndex >= LINE_BUFFER_LENGTH-1 ) {
           Serial.println( "ERROR - lineBuffer overflow" );
           lineIsComment = false;
           lineSemiColon = false;
         }
         else if ( c >= 'a' && c <= 'z' ) {        // Upcase lowercase
           line[ lineIndex++ ] = c-'a'+'A';
         }
         else {
           line[ lineIndex++ ] = c;
         }
       }
     }
   }

   switch(mode)
   {
    case 1:
       SpeedHeel = (button1)?JoyY:0;
       SpeedKnee = (button2)?JoyY:0;
       SpeedHip = (button3)?JoyY:0;
       break;
    case 2:
       SpeedHeel = JoyY;
       SpeedKnee = JoyY;
       SpeedHip = JoyY;
       break;
     case 0: // do nothing
     default:
       int SpeedHeel = 0;
       int SpeedKnee = 0;
       int SpeedHip = 0;
       break;
   }
 
if (verbose)
{
 Serial.print( "Mode:" );
 Serial.print( mode, DEC );
 Serial.print( " / Speed Heel:" );
 Serial.print( SpeedHeel, DEC );
 Serial.print( " / Speed Knee:" );
 Serial.println( SpeedKnee, DEC );
}
 Heel.speed_soll = SpeedHeel;
 Knee.speed_soll = SpeedKnee;

 ctrl_motor(&Heel);
 ctrl_motor(&Knee);

 }
}

void processIncomingLine( char* line, int charNB )
{
 int currentIndex = 0;
 char buffer[ 128 ];                                 // Hope that 64 is enough for 1 parameter

 switch ( line[ currentIndex++ ] )
 {              // Select command, if any
   case 'I':   // Init/Configuration Mode
     mode = 1;
     break;
   case 'O':   // Operational
     mode = 2;
     break;
   default:
     mode = 0;
     break;
 }  
 

 int tmp;
 char delimiter;
 buffer[0] = line[ currentIndex++ ];          // /!\ Dirty - Only works with 2 digit commands
 buffer[1] = '\0';
 tmp = atoi( buffer );
 button1 = tmp!=0;
 buffer[0] = line[ currentIndex++ ];          // /!\ Dirty - Only works with 2 digit commands
 buffer[1] = '\0';
 tmp = atoi( buffer );
 button2 = tmp!=0;
 buffer[0] = line[ currentIndex++ ];          // /!\ Dirty - Only works with 2 digit commands
 buffer[1] = '\0';
 tmp = atoi( buffer );
 button3 = tmp!=0;
 delimiter = line[ currentIndex++ ];

 buffer[0] = line[ currentIndex++ ];          // /!\ Dirty - Only works with 2 digit commands
 buffer[1] = line[ currentIndex++ ];          // /!\ Dirty - Only works with 2 digit commands
 buffer[2] = line[ currentIndex++ ];          // /!\ Dirty - Only works with 2 digit commands
 buffer[3] = line[ currentIndex++ ];          // /!\ Dirty - Only works with 2 digit commands
 buffer[4] = '\0';
 JoyX = atoi( buffer );
 buffer[0] = line[ currentIndex++ ];          // /!\ Dirty - Only works with 2 digit commands
 buffer[1] = line[ currentIndex++ ];          // /!\ Dirty - Only works with 2 digit commands
 buffer[2] = line[ currentIndex++ ];          // /!\ Dirty - Only works with 2 digit commands
 buffer[3] = line[ currentIndex++ ];          // /!\ Dirty - Only works with 2 digit commands
 buffer[4] = '\0';
 JoyY = atoi( buffer );
   
}

void ctrl_motor(m_t* pm)
{
 if (verbose) {
   Serial.print("M");
   Serial.print(pm->n, DEC);
 }
  if ( pm->speed_act < pm->speed_soll )
  {
     if (verbose)
     {
          Serial.println("Ramp up");
     }
     pm->speed_act += RAMP_STEP;
     if ( pm->speed_act > pm->speed_soll )
     {
       pm->speed_act = pm->speed_soll;
     }
  }
  else if ( pm->speed_act > pm->speed_soll )
  {
     if (verbose)
     {
     Serial.println("Ramp down");
     }
     pm->speed_act -= RAMP_STEP;
     if ( pm->speed_act < pm->speed_soll )
     {
       pm->speed_act = pm->speed_soll;
     }
  }
 
  if ( pm->speed_act > SPEED_MIN )
  {
     if (verbose)
     {
   Serial.print(": forward:");
   Serial.print(pm->speed_act, DEC);
     }
   pm->pdrv->setSpeed(pm->speed_act);
   pm->pdrv->run(FORWARD);
  }
  else if ( pm->speed_act < (-SPEED_MIN) )
  {
     if (verbose)
     {
   Serial.print(": backward:");
   Serial.print(pm->speed_act, DEC);
     }
   pm->pdrv->setSpeed(abs(pm->speed_act));
   pm->pdrv->run(BACKWARD);
  }
  else
  {
   pm->pdrv->setSpeed(0);
   pm->pdrv->run(RELEASE);
  }

     if (verbose)
     {
   Serial.println("...done");
     }
}



for a few seconds the serial communication works fine, but then it stucks!

JMeller

Code: [Select]

#include <Servo.h>
#include <AFMotor.h>

#define LINE_BUFFER_LENGTH 1024

#define SPEED_MIN 60
#define SPEED_MAX 255
#define RAMP_STEP  2

AF_DCMotor Motor1(1,MOTOR12_1KHZ);
AF_DCMotor Motor2(2,MOTOR12_1KHZ);


// Set to true to get debug output.
boolean verbose = false;

bool button1 = false;
bool button2 = false;
bool button3 = false;

int JoyX = 0;
int JoyY = 0;

int SpeedHeel = 0;
int SpeedKnee = 0;
int SpeedHip = 0;

int mode = 0;   // off

typedef struct
{
 int n;
 AF_DCMotor* pdrv;
 int speed_act;
 int speed_soll;
}m_t;

m_t Heel = { 1, &Motor1,0,0 };
m_t Knee = { 2, &Motor2,0,0 };

/**********************
* void setup() - Initialisations
***********************/
void setup() {
 //  Setup
 
 Serial.begin( 115200 );
 
 //  Notifications!!!
 Serial.println("Control Humanoid alive and kicking!");


 Motor1.setSpeed(0);
 Motor1.run(RELEASE);

 Motor2.setSpeed(0);
 Motor2.run(RELEASE);

}

/**********************
* void loop() - Main loop
***********************/
void loop()
{
 char line[ LINE_BUFFER_LENGTH ];
 char c;
 int lineIndex;
 bool lineIsComment, lineSemiColon;

 lineIndex = 0;
 lineSemiColon = false;
 lineIsComment = false;

 while (1)
 {

    // Serial reception - Mostly from Grbl, added semicolon support
   while ( Serial.available()>0 )
   {
     Serial.println( "getc" );
     c = Serial.read();
     if (( c == '\n') || (c == '\r') ) {             // End of line reached
       if ( lineIndex > 0 ) {                        // Line is complete. Then execute!
         line[ lineIndex ] = '\0';                   // Terminate string
         if (verbose) {
           Serial.print( "Received : ");
           Serial.println( line );
         }
         processIncomingLine( line, lineIndex );
         lineIndex = 0;
       }
       else {
         // Empty or comment line. Skip block.
       }
       lineIsComment = false;
       lineSemiColon = false;
       Serial.println("ok");   
     }
     else {
       if ( (lineIsComment) || (lineSemiColon) ) {   // Throw away all comment characters
         if ( c == ')' )  lineIsComment = false;     // End of comment. Resume line.
       }
       else {
         if ( c <= ' ' ) {                           // Throw away whitepace and control characters
         }
         else if ( c == '/' ) {                    // Block delete not supported. Ignore character.
         }
         else if ( c == '(' ) {                    // Enable comments flag and ignore all characters until ')' or EOL.
           lineIsComment = true;
         }
         else if ( c == ';' ) {
           lineSemiColon = true;
         }
         else if ( lineIndex >= LINE_BUFFER_LENGTH-1 ) {
           Serial.println( "ERROR - lineBuffer overflow" );
           lineIsComment = false;
           lineSemiColon = false;
         }
         else if ( c >= 'a' && c <= 'z' ) {        // Upcase lowercase
           line[ lineIndex++ ] = c-'a'+'A';
         }
         else {
           line[ lineIndex++ ] = c;
         }
       }
     }
   }

   switch(mode)
   {
    case 1:
       SpeedHeel = (button1)?JoyY:0;
       SpeedKnee = (button2)?JoyY:0;
       SpeedHip = (button3)?JoyY:0;
       break;
    case 2:
       SpeedHeel = JoyY;
       SpeedKnee = JoyY;
       SpeedHip = JoyY;
       break;
     case 0: // do nothing
     default:
       int SpeedHeel = 0;
       int SpeedKnee = 0;
       int SpeedHip = 0;
       break;
   }
 
if (verbose)
{
 Serial.print( "Mode:" );
 Serial.print( mode, DEC );
 Serial.print( " / Speed Heel:" );
 Serial.print( SpeedHeel, DEC );
 Serial.print( " / Speed Knee:" );
 Serial.println( SpeedKnee, DEC );
}
 Heel.speed_soll = SpeedHeel;
 Knee.speed_soll = SpeedKnee;

 ctrl_motor(&Heel);
 ctrl_motor(&Knee);

 }
}

void processIncomingLine( char* line, int charNB )
{
 int currentIndex = 0;
 char buffer[ 128 ];                                 // Hope that 64 is enough for 1 parameter

 switch ( line[ currentIndex++ ] )
 {              // Select command, if any
   case 'I':   // Init/Configuration Mode
     mode = 1;
     break;
   case 'O':   // Operational
     mode = 2;
     break;
   default:
     mode = 0;
     break;
 } 
 

 int tmp;
 char delimiter;
 buffer[0] = line[ currentIndex++ ];          // /!\ Dirty - Only works with 2 digit commands
 buffer[1] = '\0';
 tmp = atoi( buffer );
 button1 = tmp!=0;
 buffer[0] = line[ currentIndex++ ];          // /!\ Dirty - Only works with 2 digit commands
 buffer[1] = '\0';
 tmp = atoi( buffer );
 button2 = tmp!=0;
 buffer[0] = line[ currentIndex++ ];          // /!\ Dirty - Only works with 2 digit commands
 buffer[1] = '\0';
 tmp = atoi( buffer );
 button3 = tmp!=0;
 delimiter = line[ currentIndex++ ];

 buffer[0] = line[ currentIndex++ ];          // /!\ Dirty - Only works with 2 digit commands
 buffer[1] = line[ currentIndex++ ];          // /!\ Dirty - Only works with 2 digit commands
 buffer[2] = line[ currentIndex++ ];          // /!\ Dirty - Only works with 2 digit commands
 buffer[3] = line[ currentIndex++ ];          // /!\ Dirty - Only works with 2 digit commands
 buffer[4] = '\0';
 JoyX = atoi( buffer );
 buffer[0] = line[ currentIndex++ ];          // /!\ Dirty - Only works with 2 digit commands
 buffer[1] = line[ currentIndex++ ];          // /!\ Dirty - Only works with 2 digit commands
 buffer[2] = line[ currentIndex++ ];          // /!\ Dirty - Only works with 2 digit commands
 buffer[3] = line[ currentIndex++ ];          // /!\ Dirty - Only works with 2 digit commands
 buffer[4] = '\0';
 JoyY = atoi( buffer );
   
}

void ctrl_motor(m_t* pm)
{
 if (verbose) {
   Serial.print("M");
   Serial.print(pm->n, DEC);
 }
  if ( pm->speed_act < pm->speed_soll )
  {
     if (verbose)
     {
          Serial.println("Ramp up");
     }
     pm->speed_act += RAMP_STEP;
     if ( pm->speed_act > pm->speed_soll )
     {
       pm->speed_act = pm->speed_soll;
     }
  }
  else if ( pm->speed_act > pm->speed_soll )
  {
     if (verbose)
     {
     Serial.println("Ramp down");
     }
     pm->speed_act -= RAMP_STEP;
     if ( pm->speed_act < pm->speed_soll )
     {
       pm->speed_act = pm->speed_soll;
     }
  }
 
  if ( pm->speed_act > SPEED_MIN )
  {
     if (verbose)
     {
   Serial.print(": forward:");
   Serial.print(pm->speed_act, DEC);
     }
   pm->pdrv->setSpeed(pm->speed_act);
   pm->pdrv->run(FORWARD);
  }
  else if ( pm->speed_act < (-SPEED_MIN) )
  {
     if (verbose)
     {
   Serial.print(": backward:");
   Serial.print(pm->speed_act, DEC);
     }
   pm->pdrv->setSpeed(abs(pm->speed_act));
   pm->pdrv->run(BACKWARD);
  }
  else
  {
   pm->pdrv->setSpeed(0);
   pm->pdrv->run(RELEASE);
  }

     if (verbose)
     {
   Serial.println("...done");
     }
}


My guess would be that the arduino is constantly printing to the serial port due to the:
Code: [Select]

while (1)
 {
....
}



I would only send Serial.Print statements when needed.

Robin2

I am on the very beginning of this project, so the arduino project is quite simple right no
You have a very long program for a beginning simple project.

Presumably you have been testing it piece by piece as you developed it. At what stage in the development did the problem of the project freezing arise?

...R

PS ... I hope you say "thank you" to @JMeller for posting your code properly.
Two or three hours spent thinking and reading documentation solves most programming problems.

NBGer

Hi, again...

based on the hint of JMeller I verified my Arduino program. Actually I thought, every serial.print was disabled by setting "verbose" to false.
But there were still some active serial.print statements.
Because I have not implemented any receive handler on PC side, seems that the driver was stucked, when receive queue was full.

So this problem is solved now!

further many thanks to JMeller for formatting my code...the next time I will not forget to do it by myself! ;)

80% of the program code of my arduino sketch was copied from samples from internet, so I had not the fully overview of the used code.

In general...actually I am a very experienced software developer, but it is my very first time using Arduino. I am trying Arduino, because a bunch of shields are available like motor drivers, sensors.... and it is easy to integrate them to an application.

But....I am quite disappointed about the IDE! There is absolutely nothing to test a sketch. No variable watch, single step, breakpoints. Serial printouts for debugging are "Stone Age"...further, if I need the serial line for application issues, I do not have any debugging possibilities!

Are there any other IDEs for Arduino?
 
I am not sure, if I would use Arduino again for other projects. Maybe I will search for a platform, which have same pinout for the shields.



 

NBGer

hmm...

I found hints, that it's maybe possible to work with an JTAG debugger on my Arduino Mega board.
I have already several JTAG interfaces (e.g. Segger J-Link).
I will investigate further in this issue, maybe it is possible to work with Eclipse and JTAG for development.
 

Robin2

But....I am quite disappointed about the IDE! There is absolutely nothing to test a sketch. No variable watch, single step, breakpoints. Serial printouts for debugging are "Stone Age"...further, if I need the serial line for application issues, I do not have any debugging possibilities!
Remember that the program that you want to monitor (single-step, breakpoints) is running on the Arduino board whereas the programs you are probably more used to working with are running on the PC on which you are developing the code.

The only communication between the Arduino board and the IDE (any IDE) is via the serial port.

The Atmega328 chip used in the Uno has no provision for hardware debugging.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

NBGer

I am using Arduino Mega, the Atmega2560 has hardware debugging option!

I verified other boards, PCDuino and Arduino Due are very interesting, because of ARM Architecture, but both are only 3.3 V; so I assume I would have problems with most of the existing shields.

Additionally I found, that with ATATMEL-ICE and Atmel Studio7 I could debug Arduino Mega.

Right now my ardunio program is small, but it's just the starting point; it will grow.... ;)


sorry...maybe my intention is not typically for Arduino users....I am professional software developer, I am used to develop for several embedded realtime systems, using microcontrollers from Atmel, NXP, TI, Xilinx, Infineon, Intel,.....

for private ideas I want to use Arduino. I like the bunch of shields, available for this platform and easy to use.
With other systems, I would need to develop hardware as well (which is not my profession and not my intention).

 

Robin2

I am using Arduino Mega, the Atmega2560 has hardware debugging option!
But the Arduino Atmega2560 board does not.

And, to be fair, the Arduino IDE was not designed for professional software development. Its primary purpose is to make microprocessors accessible to non-professionals by shielding them from the need to learn lots of gory details.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

NBGer

am I wrong with ICSP?? please have a look on the attached picture (the orange arrows)

Robin2

Image from Reply #10 so we don't have to download it. See this  Simple Image Guide



...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Robin2

am I wrong with ICSP??
I'm not sure what point you are making. It would not surprise me if you know more than I do.

You can certainly program an Arduino board using ICSP. But if that allows for breakpoints and the like then I am not aware of any PC software that facilitates that.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Go Up