Can you use C++ or Objective C with a Teensy 3.X?

Status
Not open for further replies.
Yes & no.

Arduino is really just C++ with a tiny bit of preprocessing, and you can just put an empty .ino file and add all your code in normal .cpp & .h files if you want to avoid Arduino's preprocessor.

There are also many ways to not use Arduino at all. But Arduino is by far the best supported platform, so best to start there.
 
I guess I will just have to try. I need to build an assembly like programming language to be read in via the serial port so the teensy will act as the master for some PID controllers which in turn control a single axis of a motor or actuator. I need a dynamic sized multidimensional array to hold commands read in and help deal with logic flow and command jumps / calls. The C library does not have this, but vanilla objective C and C++ do. If anything I could implement it myself in C / arduino if I have to, but I'm not very excited to do that.
 
I guess I will just have to try. I need to build an assembly like programming language to be read in via the serial port so the teensy will act as the master for some PID controllers which in turn control a single axis of a motor or actuator. I need a dynamic sized multidimensional array to hold commands read in and help deal with logic flow and command jumps / calls. The C library does not have this, but vanilla objective C and C++ do. If anything I could implement it myself in C / arduino if I have to, but I'm not very excited to do that.

For dynamically sized multidimensional arrays, my startup has ported std::vector and Eigen to work with Teensy:
https://github.com/bolderflight/Vector
https://github.com/bolderflight/Eigen
 
Teensy 3.x is very fast, relative to the task of single axis PID-based motion control, especially 3.5 & 3.6 which have floating point in hardware.

Perhaps there really is something very unusual about your application which would require such special or assembly-level programming. But I'm skeptical. We've had many, many people vastly underestimate the hardware's capability, with a belief the sort of extraordinary coding like you'd do on old 8 bit chips is needed. With these modern 32 bit parts, that sort of coding is almost never needed. When really high performance is needed, usually the path involves fairly ordinary C++ coding with effort to leverage DMA and the more advanced features of the timers.
 
Thank you a bunch brtaylor. The fragmentation between C++ and arduino (while understandable) is really throwing me off. Do you happen to have an example ino for the vector library? It's not necessary, but could be helpful for getting started. I get what you are saying PaulStoffregen but the idea is to have it interface with legacy applications so I'm a bit stuck having it take in instructions like

1PM,MN,MA3000,GO,WS100,RW495,IG300,NO,MJ7,GH,MF,RP

Which does a position move for axis 1 to position 3000 checks the position error and jumps to another execution line if the error is greater than 300 else it moves back to the home position to do the motion again and repeats indefinitely.

A lot of the other code I'm working with deals directly with this type of syntax and the teensy will be a CANopen master to these PID controllers essentially handling logic flow and converting these commands to CAN signals via the FlexCan Library.
 
Last edited:
Thank you a bunch brtaylor. The fragmentation between C++ and arduino (while understandable) is really throwing me off. Do you happen to have an example ino for the vector library? It's not necessary, but could be helpful for getting started. I get what you are saying PaulStoffregen but the idea is to have it interface with legacy applications so I'm a bit stuck having it take in instructions like

1PM,MN,MA3000,GO,WS100,RW495,IG300,NO,MJ7,GH,MF,RP

Which does a position move for axis 1 to position 3000 checks the position error and jumps to another execution line if the error is greater than 300 else it moves back to the home position to do the motion again and repeats indefinitely.

A lot of the other code I'm working with deals directly with this type of syntax and the teensy will be a CANopen master to these PID controllers essentially handling logic flow and converting these commands to CAN signals via the FlexCan Library.

I don't have a simple example available, but you just need to include the library (i.e. #include "Vector.h") and then the use is standard C++ (i.e. std::vector<double> foo; foo.push_back(123.45); Serial.println(foo.size()); etc...)
 
I need a dynamic sized multidimensional array to hold commands read in and help deal with logic flow and command jumps / calls.

I've done things like this myself in the past, and seen many other people and companies do it as well.
It feels powerful, and it's fun to work on, but it's not actually a useful tool for any other people.
If your project is intended to ship to other people, rather than just being for your own enjoyment, I highly recommend against a "custom assembly language."
If you need to support users writing custom code, just use a language that already exists, such as C or C++.
Write a library that contains whatever extra support your specific hardware needs, and make it well documented and easy to call.
The reason this is a much better is that the existing compilers have the bugs worked out, there are tons of references available for the existing languages, and the existing debugging support for existing languages is much better than a single person can build for their own language or "assembly code."

Now, if the reason you need the custom code is because of some pre-existing protocol that already exists, you have to do what you do.
But saying "I can't do this in C" doesn't make sense -- you can do anything that a computer is capable of doing in C. C++ used to compile to C which was then compiled to assembly, and although the language these days compiles straight to assembly, it's very much designed and specified in terms that a C program can implement -- the compiler just helps you by automatically generating a bunch of code that you'd have to write manually in C.
Then again, when you need the smallest code possible, that automatic code may get in the way, and you may be better off with plain C.

So, when you say "I can't do this in C" perhaps what you should do is study the basics of C programming, rather than trying to apply bigger, heavier tools (like C++ or Objective C) to solve the problem.
Parsing a serial protocol, and emulating an instruction stream, should be fairly straightforward for any C programmer. Depending on the specifics of the bytecode you are reading, you can parse straight out of a byte array, or you can store the program as some array of structs that contain pre-parsed instructions.
Similarly, if you have strings literals, binary literals, float values, and so forth, those can go in a big byte array, or they can go into some arrays (tables) of values and be referenced by index or by pointer.
There are tons of ways of doing this, so it sounds to me like the problem really isn't what language you're using.

The particular "G-code-like" code that you show in the last post, should be quite simple to parse in C using either pain pointer arithmetic, or the strtok() function.
If you need a table of line numbers, you can either just scan the program (doing so will be fast!) or you can use a separate table of "line number to array pointer" and binary search through it.

I'd recommend trying two separate implementations:

Store the program as a big char array, and pre-parse where lines live:
Code:
struct Line {
  int line;
  char const *instr;
};
struct Line lineNumbers[MAX_LINE_NUMBERS];
char program[MAX_PROGRAM_SIZE];
To execute a line of code, simply follow the char pointer, and parse each instruction in the line.
When moving to another line, look up the line number in the table, and start executing that line.

Pre-parse each line into an array of instructions:
Code:
struct Instruction {
  uint16_t kind;
  uint16_t argument; /* do you need 32-bit values? */
};
struct Instruction program[MAX_INSTRUCTIONS];

To execute, keep an instruction pointer which points to the "next instruction to run."
One of the instructions would be "start of line X"
Each opcode has a value for "kind" and to run an opcode, you switch() on all the kind values (or look up a function pointer in a table of function pointers indexed by kind) and do what's needed.
After executing an opcode, increment the instruction pointer.
To go to another line, simply scan the entire program from the start until you find the opcode "start of line" with the value of the line number you're looking for.
 
Wow jwatte thank you a ton for your response. It is the first very direct and applicable help I've gotten (got downvoted on stackoverflow). It is definitely the second scenario, it's company standard and there is already a ton of code / GUI's that operate using this "assembly" code as well as many clients using it in the field. I think you are right that I am better off using plain C, although I'm not a very competent C programmer (guess this is my chance to change that). I was hired primarily to build GUI's in C#, but i'm really the only programmer. The only thing similar to this that I have done is a pure C programming assignment that parsed math expressions. I know that I can write my own dynamic multidimensional array in C, but I was trying to avoid it for the reason stated previously.

As for the programming language I explained a bit more of it on the stackoverflow post but commands can be stored in "macros" by defining a macro (MD)

MD1,1PM,MN,MA3000,GO,WS100,RW495,IG300,NO,MJ7,GH,MF,RP is now stored in macro 1 and can be called with MS1

There are macro calls which return and macro jumps that don't as well as conditional statements such as IGn or IBn which will skip the next two commands if the main register is not above / below the value n.

There is the repeat command (RPn) which will repeat indefinitely if n is not defined or n=0 else it will loop n many times from the start of the macro until the RP is reached again.

Macros typically will continually run if they are numberd consecutively like and will stop execution if there is break in between. so if macro 1 is called 2 and 3 will automatically run

MD1
MD2
MD3

MD5


That pretty much encompasses all of the logic flow. Loops are done via macro calls or jumps.
 
Last edited:
Status
Not open for further replies.
Back
Top