C Program API for P1/P2 Hardware
jazzed
Posts: 11,803
Propeller 2 (P2) hardware access is different from the existing P8x32a Propeller (P1).
(It was stated: 'This means that statements like "DIRA |= pinmask;" are not suitable for P2 applications.' ... actually this is not necessarily true. A better example is "OUTA |= inmask;" which has no meaning on P2 unless we alias OUTA and INA to PINA although there are differences).
The goal of this thread is to come up with a suitable user Application Programming Interface (API) that can be used on P1 or P2 to perform primitive and common hardware access.
Suitable to me means:
1) Can be used with any compiler tool set that supports C or C++ according to standard industry practices.
2) API functions (and data structure elements if necessary) will have meaningful names.
3) API functions should be implemented so that only the code needed by the compiler will be included (macros).
4) Will gain approval of Parallax Staff who are working in C related projects.
5) Other requirements that may be of value.
I've started some very preliminary discussions with Parallax folks about this, and I anticipate meeting their requirements. It doesn't mean they will dictate every function name, but they will need to approve the ones to be used in PropellerGCC.
Lets see if we can get something started and/or reuse some previous interface definitions.
Thanks,
--Steve
(It was stated: 'This means that statements like "DIRA |= pinmask;" are not suitable for P2 applications.' ... actually this is not necessarily true. A better example is "OUTA |= inmask;" which has no meaning on P2 unless we alias OUTA and INA to PINA although there are differences).
The goal of this thread is to come up with a suitable user Application Programming Interface (API) that can be used on P1 or P2 to perform primitive and common hardware access.
Suitable to me means:
1) Can be used with any compiler tool set that supports C or C++ according to standard industry practices.
2) API functions (and data structure elements if necessary) will have meaningful names.
3) API functions should be implemented so that only the code needed by the compiler will be included (macros).
4) Will gain approval of Parallax Staff who are working in C related projects.
5) Other requirements that may be of value.
I've started some very preliminary discussions with Parallax folks about this, and I anticipate meeting their requirements. It doesn't mean they will dictate every function name, but they will need to approve the ones to be used in PropellerGCC.
Lets see if we can get something started and/or reuse some previous interface definitions.
Thanks,
--Steve
Comments
Here is an example of what I did in my multi-cog demo for the P2 in order to make it also work on the P1:
In the P1 version the setting of the bit in _DIRA is redundant after the first time. In addition, a P1 program would probably want to setup a mask for the pin and just use OR and ~AND to set and clear the bit rather than taking a pin number as a function argument. I can see where these simplfied macros might be good for beginners for an API something like the Arduino though.
Actually, it is possible to use DIRA in P2. In fact, there are DIRA/B/C/D that can be mapped to any 32 pin group. You have to use DIRx/PINx if you want to access multiple pins in a single instruction since the GETP/SETPx instructions only address one pin at a time.
To weigh in here as a lightweight....
I float around from a lot of interests and projects and this is but one of them. I find as soon as I want to do a quick project in C/C++ one of my early 'uggghhh' moments is remembering just how to setup the masks and toggle one pin without stepping all over everything else. That's where the gain in a simple, standard, set of functions is to me. Often the absolute maximum performance is not the issue its just far more convenient to write out
than to make up the masks and do the logic operations. And that may be far more useful to me in an app where the goal is to make an LED blink when a switch is flipped on than the number of nanoseconds it took for the LED to come on. If I want to get the high performance switching I can always hit the books and do it the hard way. I think that's what drives a lot of the Arduino appeal. People can get on with making the little bobble they were working on and not spend much time figuring out which register to stuff something in and how many bits to shift it left.
This will make the propeller chip a lot easier for Arduino people to touch it. Additionally, there's a lot of software target for the Arduino that would suddenly work with a C library for the propeller chip.
Interpreted as in one who does not want a heavy load to get value? Not an unreasonable request.
One big point in a common API is to allow beginners (or anyone else who might start a first cut) to start using resources with very little work. It is also to allow one program to run on either MCU with little effort. One thing I am hoping for is to also allow greater portability for various compilers.
If someone wants to make exceptions for the Propeller type without the help of macros in a header file, they can. Any C pre-processor can use #ifdef __PROPELLER2__ or other -D passed to the command-line or via GUI for a program to make such decisions. Agreeing on some define symbols would be useful.
This is a fine example for some naming. There are variations on the timing idea of course.
What about a group of pins?
setpins(group, start, count, value);
setpinA(start, count, value); // alias of setpins(A_group, start, count, value);
I'm inclined to avoid clearpin or clearpins as it implies the opposite of setpins.
A name that may be difficult would be for turning off output pins. offpin or offpins?
API names to me should be self explanatory without having to look at whatever some ASM language uses barring no other obvious definition.
As Kye mentions, macros can easily rename or alias things, but we need to define API of the things.
setpin(pin,value)
setpins(pin,count,value)
eliminate the need for clearpin or offpin since the provide a value parameter.
This makes for a nice compact set of pin control functions.
getpin(pin) - can it be used to handle digital and analog instead of the digitalread/digitalwrite and analogread/analogwrite Arduino functions?
The pin direction control will need to be agreed upon whether it's an extra but unneeded DIRA type instruction at the beginning of the code for P2 versus DIRA/OUTA and DIRA/INA redundant instructions for a P1 for each setpin or getpin. This may not be a big deal for leaner P1 programmers - once they understand DIRA on the P1, they could handle the pinmode() type functions.
I think there needs to be a way to be inviting to the Arduino community - a compatability library or a copy of Arduino tailored to the propeller - but it's not necessary to make the Propellers always look like Arduinos.
Issues like this bring up another question. You can make the P1 code forward compatible to the P2 in most cases (CLK access and such need to be handled differently) but should you really expect P2 code to be backward compatible to a P1? As soon as you cross one of many hardware lines with the P2 architecture, there's no going back with just a recompile.
Is that a trick question for those of us with failing memory? I REMEMBER posting about it a few weeks ago!!
It needs a LOT of work to fully support a P1 much less a P2 but when someone does all that work, you have propellers programmed through the Arduino IDE. Plus you've introduced another library/IDE to support which won't fully expose the P1/P2 features...which is fine if it's community supported but a burden if it's Parallax supported.
I used Propeller C projects on Learn Parallax : it seems clear and rather easy.
But trying some larger programs I get problems: and the big one is with include files.
I hate messages like : " file not found " : for me they stop any progress with C.
Hope a new API will make this library path problems disapear.
Thanks if it succeed doing that.
Jean Paul
Can the p2 pins be set both ways?
If so, setting and using bitmasks could be fairly straightforward macros, it seems.
Those who use the toggle operations will need to know why and where they need to use these special pin set operations. I like access to bitmasks because you can do multiple pin operations per set.
Yes, there are PINA, PINB, PINC, PIND and DIRA, DIRB, DIRC, DIRD registers. You should be able to write masks to these registers just like with the P1.
The ports, A, B, C, D, can be mapped to different PIN groups. You could have pins 0-31 in group A or you could remap so pins 0-31 were in group B.
David Betz was kind enough to add P1/P2 specific code to the Propeller-GCC propeller.h file depending on which compile flag is in use (P2 or not P2, that is the question! LOL) -mp2 (-m means machine type. -mp2 means machine type P2).
In GCC, we have built-in defines to allow choosing such things. When -mp2 is passed as the machine type, the __PROPELLER2__ "macro" is defined. If __PROPELLER2__ is not defined in the compile context, propeller.h will chose propeller1.h for hardware access. If __PROPELLER2__ is defined, propeller.h will choose propeller2.h for hardware access.
In the attachment propeller.h only includes propeller1.h, but both files are represented in the document.
Thanks,
--Steve
Should this thread be moved to the Propeller 2 forum?
In the interest of full disclosure most of what I've ever known about C was forgotten years ago. Even then I was never as good as those working on the propgcc project.
As memory serves isn't ANSI C also valid C++ code? If that's the case then all code can be compiled as C++ including C code. That would mean that overloading wouldn't be an issue and can be done transparently behind the scenes.
"C++ is not a strict superset of C": http://en.wikipedia.org/wiki/Compatibility_of_C_and_C%2B%2B
It's best to let people define aliases to PINA if it fits their needs. No point in forcing it.
There is a lot of code that uses DIRA, INA, and OUTA. One could easily do these in their own headers:
#define OUTA PINA
#define INA PINA
Some differences though (assuming DIRA properly set):
OUTA |= (1 << 30) will not set the P2 TX pin high as it would on P1. Similar issue for P2 RX.
Hard coding numbers for things like TX/RX is probably a bad idea anyway.
PINA can be redirected in P2, so OUTA/INA access may be on a different port.
Generally functions in the C global name space can be called easily from C++.
Other things are possible for code reuse and be converted as time permits.
Core development should support "Pro" use. Overlay hobby / ease of use / compatible with, etc... on top of that.
Personally, I see P2 as the much more potent C platform and as such, it should be very fully exploited in a productive way. Back-fill onto P1 as makes sense.