Pointer issues between AVR and ARM compilers
Shop › Forum › Everything Else › Pointer issues between AVR and ARM compilers
- This topic has 20 replies, 2 voices, and was last updated 8 years, 2 months ago by Anonymous.
-
AuthorPosts
-
2016-08-31 at 09:13 #10696AnonymousInactive
### From “2 Axis CNC Demo” – downloaded from GitHub today. ###
Been having a problem with the pointers in the processCommand() and parsenumber() routines.
Works fine with AVR but fails when compiled for ARM on the SAMD21 M0 / M0 Pro boards (I am in Europe so these are from Arduino.org).
I have hacked the code to get something to work (I think as I have dummy motor calls); not so elegant though š
N.B. The Serial.print(); stuff is just to see what is going on.
Thanks.
/**
* Read the input buffer and find any recognized commands. One G or M command per line.
*/
void processCommand()
{
long cmd;if(buffer[0] == ‘;’) return; // check for a blank line
else if(buffer[0] == ‘G’) // G Command must appear as first char on line
{
cmd = parsenumber(‘G’,-1);
Serial.print(“processCommand() G”);
Serial.println(cmd);
switch(cmd)
{
case 0:
case 1: // line
{
feedrate(parsenumber(‘F’,fr));
line( parsenumber(‘X’,(mode_abs?px:0)) + (mode_abs?0:px),
parsenumber(‘Y’,(mode_abs?py:0)) + (mode_abs?0:py) );
break;
}
case 2:
case 3: // arc
{
feedrate(parsenumber(‘F’,fr));
arc(parsenumber(‘I’,(mode_abs?px:0)) + (mode_abs?0:px),
parsenumber(‘J’,(mode_abs?py:0)) + (mode_abs?0:py),
parsenumber(‘X’,(mode_abs?px:0)) + (mode_abs?0:px),
parsenumber(‘Y’,(mode_abs?py:0)) + (mode_abs?0:py),
(cmd==2) ? -1 : 1);
break;
}
case 4: pause(parsenumber(‘P’,0)*1000); break; // dwell
case 90: mode_abs=1; break; // absolute mode
case 91: mode_abs=0; break; // relative mode
case 92: // set logical position
position( parsenumber(‘X’,0),
parsenumber(‘Y’,0) );
break;
default:
Serial.println(F(“Unrecognized G code!”));
break;
}
}else if(buffer[0] == ‘M’) // M Command must appear as first char on line
{
cmd = parsenumber(‘M’,-1);
Serial.print(“processCommand() M”);
Serial.println(cmd);
switch(cmd)
{
case 18: // disable motors
disable();
break;
case 100: help(); break;
case 114: where(); break;
default:
Serial.println(F(“Unrecognized M code!”));
break;
}
}
else
{
Serial.println(F(“Unrecognized Command!”));
}
}/**
* Look for character /code/ in the buffer and read the float that immediately follows it.
* @return the value found. If nothing is found, /val/ is returned.
* @input code the character to look for.
* @input val the return value if /code/ is not found.
**/
float parsenumber(char code, float val)
{
float local_vlaue;
uint32_t whileLoopCount = 0;Serial.print(F(“parsenumber() start = “));
Serial.println(code);char *ptr = buffer;
while(ptr && *ptr && (ptr < buffer + sofar) )
{
whileLoopCount++;
Serial.print(F(“while(…) loop = “));
Serial.println(whileLoopCount);
if(*ptr == code)
{
local_vlaue = atof(ptr+1);
Serial.print(F(“parsenumber() end float = “));
Serial.println(local_vlaue);
return local_vlaue;
}
ptr = strchr(ptr,’ ‘) + 1;
if(whileLoopCount >= MAX_BUF)
break;
}
Serial.print(F(“parsenumber() end val = “));
Serial.println(val);
return val;
}2016-08-31 at 09:16 #10697DanKeymasterI don’t have the hardware that you have and I obviously see the changes you made. Please either submit this as a github issue on the relevant project or distill this to a shorter message.
What, exactly, is the problem?
2016-08-31 at 09:29 #10698AnonymousInactiveHi Dan,
Thanks for the quick reply.
Problem seems to be here:
while(ptr && *ptr && ptr < buffer + sofar)
{
…
}where the while loop pointer test doesn’t work properly, so the loop doesn’t terminate i.e. the program hangs.
Sorry, I am not into the whole github thing as I am a hardware person who writes code sometimes (and my programming skills are obviously not up to snuff as far as pointers go).
2016-08-31 at 10:01 #10699DanKeymasterThe ptr starts at buffer and is only incrementing so it HAS to pass buffer+sofar.
I don’t believe this is the source of the problem.Are you sending the newline when you talk to the board?
What message, exactly, are you sending?
What is the output you see in the serial window?2016-08-31 at 10:44 #10700AnonymousInactiveHi Dan,
A bit of background:
I have used a stripped down version of your code for over a year in a single axis stepper controller made with an Arduino Leonardo and a Arduino A000079 L298 H-bridge Motor Shield (and the TFT display).
The whole g-code interpreter part has always worked without a hitch in this AVR setup. I have several motor controllers running 24/7 being driven from Matlab applications using the USB serial CDC.
At the hardware end I drive the motor with a synthersised DDS waveform with a 32KHz update Sine/Cosine PWM which enables me to have low-vibration operation with speeds that can go down to 0.001 steps per second (should I so wish).
I am now moving across to using the Arduino M0 (Pro) as I am wanting to implement more PWM channels plus faster inner code interrupt loop.
The application for this is controlling optical positioning systems in my group’s laser labs. These setups are very sensitive to vibration and can involve scans that take hours or even days to complete.
So yes, I am sending correct messages. What happens with the original code is that I see the > command prompt, the first command is echoed back, then the processor hangs in the while() loop.
GcodeCNCDemo2AxisV1 1
Commands:
G00 [X(steps)] [Y(steps)] [F(feedrate)]; – line
G01 [X(steps)] [Y(steps)] [F(feedrate)]; – line
G02 [X(steps)] [Y(steps)] [I(steps)] [J(steps)] [F(feedrate)]; – clockwise arc
G03 [X(steps)] [Y(steps)] [I(steps)] [J(steps)] [F(feedrate)]; – counter-clockwise arc
G04 P[seconds]; – delay
G90; – absolute mode
G91; – relative mode
G92 [X(steps)] [Y(steps)]; – change logical position
M18; – disable motors
M100; – this help message
M114; – report position and feedrate
All commands must end with a newline.
>G01 X100 Y100 F20;^^^ Hangs here, no further > prompt.
Anyway, I have done a hack that works for me to get on with whilst I look at the pointers.
Thanks.
Best,
Susan.2016-08-31 at 12:03 #10701DanKeymasterSo it hangs on the very first command? That is almost guaranteed you are not setting “newline” in the arduino serial window. the program waits for newline (\n) before processing a message.
2016-08-31 at 12:21 #10702AnonymousInactiveSorry, I am setting “newline”. I used to use Teletypes “back in the day”, I know what a CR or LF is š
The pointer handling is coming adrift; probably from casting and int or long type differences.
I am trying to reburn a Zero board with an Arduino.cc bootloader (I have the Atmel-ICE).
As/when I will let you know if that works.
Sorry for distraction BTW.
Best,
Susan.2016-08-31 at 13:41 #10704DanKeymasterI created a github issue
2016-08-31 at 13:56 #10708DanKeymasterI have updated the github repository and the issue with a possible fix. please download a fresh copy and try again. If it works I will make the same change across the rest of gcodecncdemo.
2016-09-01 at 12:55 #10714AnonymousInactiveHi Dan,
Sorry, still a problem for me.
### Console Output from IDE ###
In function ‘float parsenumber(char, float)’:
error: ISO C++ forbids comparison between pointer and integer [-fpermissive]
while(ptr > 1 && *ptr && ptr < buffer + sofar)
^
exit status 1
ISO C++ forbids comparison between pointer and integer [-fpermissive]########
For me this happens both in CC and ORG version of IDE (although having both on same machine not 100% sure they are both completely separated).
What I have done meanwhile to get something going:
/**
* Look for character /code/ in the buffer and read the float that immediately follows it.
* @return the value found. If nothing is found, /val/ is returned.
* @input code the character to look for.
* @input val the return value if /code/ is not found.
**/float parsenumber(char code, float val)
{
float local_vlaue;
uint16_t whileLoopCount = 0;char *ptr = buffer;
while(whileLoopCount++ < MAX_BUF) // Default scan through entire buffer
{
if(*ptr == code)
{
local_vlaue = atof(ptr+1);
return local_vlaue;
}
ptr = strchr(ptr,’ ‘) + 1;
}
return val;
}2016-09-01 at 13:50 #10717DanKeymasterI guess you’ll have to cast to int and see if that makes the bug go away. It’s specific to a compiler that I don’t have installed. Can you try and let me know what works, please? I’ll then add your fix to the code permanently.
2016-09-02 at 13:03 #10722AnonymousInactiveHi Dan,
This is what I have currently. No problems with compiler.
I am testing it with a version of code that has serial.prints for every interaction, haven’t managed to trip it up yet š
float parsenumber(char code, float value) { float local_value; uint16_t whileLoopCount = 0; char *ptr = buffer; while(ptr >= buffer) // Scan through received buffer { if(*ptr == ';') // Check for start of comment, needs a space before the ; to work { return value; } if(*ptr == code) // Look for specific letter command code e.g. G, M, &c. { local_value = atof(ptr+1); return local_value; } ptr = strchr(ptr,' ') + 1; // Hop to next blank space. Note this skips over ; if there is no space beforehand } return value; }
Also in the receive loop I stamped the NULL onto the termination LF or CR code, rather than after:
…
// entire message received
buffer[–sofar] = 0; // end the buffer, replace ‘\n’ or ‘\r’ with 0 so string functions work correctly
…2016-09-02 at 13:41 #10723DanKeymasterWhat about when you have
G00 X10; G00 X-10
?
while(ptr>=buffer)
could be a very long time.
2016-09-03 at 13:07 #10732AnonymousInactiveHi Dan,
Added some extra input character processing; now can handle input without spaces, lower case command letters, and ; comments:
bool commandFlag = true; ... void loop() { // listen for serial commands while(SerialUSB.available() > 0) // is something available in receive buffer? { char c = SerialUSB.read(); // get it SerialUSB.print(c); // repeat it back so I know you got the message if(commandFlag == true) { if(sofar < MAX_BUF-1) { if(c == ';') // check for a comment - ignore rest of line { commandFlag = false; } else { if(c > 96) // Check for lower case letter c = c - 32; // Turn into upper case if(sofar) // Not for first character in buffer, don't index outside array !!! { if((c >= 64) && (buffer[sofar -1] < 58) && (buffer[sofar -1] > 45)) // if letter and previous was a number { buffer[sofar++] = ' '; // add space, then post incriment sofar count } } buffer[sofar++] = c; // store it, then post incriment sofar count } } else { SerialUSB.println(F("E002 ;Command String Too Long.")); // complain to human } } if((c == '\n') || (c == '\r')) // entire message received { if(commandFlag) // look to see if command... buffer[--sofar] = 0; // end the buffer, replace '\n' or '\r' with 0 so string functions work correctly else // ... or a comment, when we do not want to back space onto previous command info buffer[sofar] = 0; // end the buffer, replace '\n' or '\r' with 0 so string functions work correctly SerialUSB.print(F("\r\n")); // echo a return character for humans if(sofar) // If we have something in buffer to process { processCommand(); // do something with the command } // The following tidy-up was in ready() - moved here for clarity of operation commandFlag = true; // Allow for new command processing - add to ready() if not here sofar = 0; // clear input buffer index pointer SerialUSB.print(F(">")); // signal ready to receive input } } // End: while(SerialUSB.available() > 0) } // End: loop()
Which gives for example the following input string: g1x-10y-10;g1x10y10;hdhddh
>g1x-10y-10;g1x10y10;hdhddh
String ready to process. buffer [G1 X-10 Y-10] & sofar = 12
parsenumber() start = G
while(…) loop = 1 : G : G1 X-10 Y-10
parsenumber() found code – return new value = 1.00
processCommand() G1
parsenumber() start = F
while(…) loop = 1 : G : G1 X-10 Y-10
while(…) loop = 2 : X : X-10 Y-10
while(…) loop = 3 : Y : Y-10
parsenumber() return original value = 50.00
parsenumber() start = X
while(…) loop = 1 : G : G1 X-10 Y-10
while(…) loop = 2 : X : X-10 Y-10
parsenumber() found code – return new value = -10.00
parsenumber() start = Y
while(…) loop = 1 : G : G1 X-10 Y-10
while(…) loop = 2 : X : X-10 Y-10
while(…) loop = 3 : Y : Y-10
parsenumber() found code – return new value = -10.00
^<^<^<^<^<^<^<^<^<^<^<^<^<^<^<^<^<^<^<^<*
Finished command.>
and this for M codes:
>m114;dfff
String ready to process. buffer [M114] & sofar = 4
parsenumber() start = M
while(…) loop = 1 : M : M114
parsenumber() found code – return new value = 114.00
processCommand() M114
X10.00
Y10.00
F50.00
ABS
Finished command.>
The processing still assumes a certain sanity of input, this just covers the basic variations.
Best,
Susan.2016-09-03 at 13:15 #10735DanKeymasterThe things you have added are not in the specs for GCODE.
Please limit your fix to the actual problem.
What do you bet there’s a compiler option that makes your system process the arduino code without error?
2016-09-03 at 13:26 #10736AnonymousInactiveMy apologies, sorry to trouble you. I will go away now.
S.
=====================================================Comments: Gcode comments begin at a semicolon, and end at the end of the line:
N3 T0*57 ; This is a comment
N4 G92 E0*67
; So is this
N5 G28*22Comments and white space will be ignored by your RepRap Printer. It’s better to strip these out on the host computer before sending the Gcode to your printer, as this saves bandwidth.
2016-09-03 at 13:51 #10738DanKeymasterYou are correct that they end with a semicolon. Does anyone put gcode AFTER the semicolon? Programmer error.
Does Gcode come with lower-case letter or no-space-before letters? No, so no need to cover those cases.
I love that you’re making an effort, that’s rare and special. I want to encourage you. How? The fixes you’re proposing create new problems. By pointing them out I’m sending the “you’re doing it wrong” message instead of the “good try!” message.
2016-09-04 at 08:06 #10741AnonymousInactiveI appreciate the G-code spec may be nice and tidy, real world examples less so. E.g. the following G-code line as per webpage from: http://www.daycounter.com/Calculators/GCode/GCode-Circle.phtml generated G-code with default settings.
G2 X0.5625Y1.0000 i0.4375j0 z-0.0625
Note mix of upper and lower case letters, and no spaces or multiple spaces between each code/number section.
With the additional input processing (and I have also now added a test to remove multiple spaces) the command input will be processed as follows:
>G2 X0.5625Y1.0000 i0.4375j0 z-0.0625
String ready to process. buffer [G2 X0.5625 Y1.0000 I0.4375 J0 Z-0.0625] & sofar = 38
parsenumber() start = G
while(…) loop = 1 : G : G2 X0.5625 Y1.0000 I0.4375 J0 Z-0.0625
parsenumber() found code – return new value = 2.00
processCommand() G2
parsenumber() start = F
while(…) loop = 1 : G : G2 X0.5625 Y1.0000 I0.4375 J0 Z-0.0625
while(…) loop = 2 : X : X0.5625 Y1.0000 I0.4375 J0 Z-0.0625
while(…) loop = 3 : Y : Y1.0000 I0.4375 J0 Z-0.0625
while(…) loop = 4 : I : I0.4375 J0 Z-0.0625
while(…) loop = 5 : J : J0 Z-0.0625
while(…) loop = 6 : Z : Z-0.0625
parsenumber() return original value = 50.00
parsenumber() start = I
while(…) loop = 1 : G : G2 X0.5625 Y1.0000 I0.4375 J0 Z-0.0625
while(…) loop = 2 : X : X0.5625 Y1.0000 I0.4375 J0 Z-0.0625
while(…) loop = 3 : Y : Y1.0000 I0.4375 J0 Z-0.0625
while(…) loop = 4 : I : I0.4375 J0 Z-0.0625
parsenumber() found code – return new value = 0.44
parsenumber() start = J
while(…) loop = 1 : G : G2 X0.5625 Y1.0000 I0.4375 J0 Z-0.0625
while(…) loop = 2 : X : X0.5625 Y1.0000 I0.4375 J0 Z-0.0625
while(…) loop = 3 : Y : Y1.0000 I0.4375 J0 Z-0.0625
while(…) loop = 4 : I : I0.4375 J0 Z-0.0625
while(…) loop = 5 : J : J0 Z-0.0625
parsenumber() found code – return new value = 0.00
parsenumber() start = X
while(…) loop = 1 : G : G2 X0.5625 Y1.0000 I0.4375 J0 Z-0.0625
while(…) loop = 2 : X : X0.5625 Y1.0000 I0.4375 J0 Z-0.0625
parsenumber() found code – return new value = 0.56
parsenumber() start = Y
while(…) loop = 1 : G : G2 X0.5625 Y1.0000 I0.4375 J0 Z-0.0625
while(…) loop = 2 : X : X0.5625 Y1.0000 I0.4375 J0 Z-0.0625
while(…) loop = 3 : Y : Y1.0000 I0.4375 J0 Z-0.0625
parsenumber() found code – return new value = 1.00
*
Finished command.>
The situation for myself is that I am using the Arduino platform and IDE so I can hand over projects to our group’s PhD students to do further work on and install and maintain on various experiments running in our laser labs. To that end I have to keep the gribly electronics and firmware coding bits as simple as possible to make it accessible to people who don’t have an electronics and hardware level coding background. They are expected to use MatLab (or LabView) so the step across to Arduino coding isn’t as steep as it might otherwise be once they get the point about the hardware not being abstracted behind high level API’s. Amongst other things I also get to teach them how to solder and use my workshop’s drilling machine safely.
Anyway, I reiterate my apologies for these digressions.
2016-09-04 at 08:08 #10742AnonymousInactiveP.S. Multiple spaces not being displayed by the web page formatting š
G2 X0.5625Y1.0000 i0.4375j0 z-0.0625
May display this properly?
2016-09-19 at 14:47 #10971DanKeymasterChecked in a fix for both firmwares that eliminates C++ error by typecasting pointers to long.
2016-09-20 at 12:59 #10974AnonymousInactiveHi Dan,
Awesome; thanks for update / letting me know.
Best,
Susan. -
AuthorPosts
- You must be logged in to reply to this topic.