Shop OBEX P1 Docs P2 Docs Learn Events
C Program API for P1/P2 Hardware — Parallax Forums

C Program API for P1/P2 Hardware

jazzedjazzed Posts: 11,803
edited 2013-01-05 11:21 in Propeller 1
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

Comments

  • mindrobotsmindrobots Posts: 6,506
    edited 2013-01-02 23:08
    Does it make any sense to have these mimic the PASM2 opcodes and use getpin(), clearpin(), setpin(), etc.? Then, Spin2, PASM2 and C would all present similar H/W related functions/opcodes/APIs.
  • David BetzDavid Betz Posts: 14,516
    edited 2013-01-03 04:30
    I'm wondering if there is really any reason to try to make P1 and P2 work the same. It seems like software that manipulates hardware at the lowest level should be tailored specifically to that hardware not be made generic. For instance, the P2 instruction SETPC automatically makes the pin an output. Do we really want to have a SETP macro for the P1 that always also sets the DIRA bit for the pin? Won't that be inefficient and waste valuable instruction space?

    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:
    static __inline__ void p1_setpin(uint32_t pin, uint32_t value)
    {
        uint32_t mask = 1 << pin;
        if (value)
            _OUTA |= mask;
        else
            _OUTA &= ~mask;
        _DIRA |= mask;
    }
    
    static __inline__ void p2_setpin(uint32_t pin, uint32_t value)
    {
        __asm__ volatile (
            "rcr %2, #1 wc\n\t"
            "setpc %1"
        : /* outputs */
            "=r" (value)
        : /* inputs */
            "r" (pin),
            "0" (value)
        : /* no clobbered registers */
        );
    }
    

    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.
    This means that statements like "DIRA |= pinmask;" are not suitable for P2 applications.
    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.
  • photomankcphotomankc Posts: 943
    edited 2013-01-03 06:43
    David Betz wrote: »
    I can see where these simplfied macros might be good for beginners for an API something like the Arduino though.

    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
    setpin(5,1) ;
    waitcnt(CLKFREQ/100 + CNT); 
    setpin(5,0);
    

    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.
  • David BetzDavid Betz Posts: 14,516
    edited 2013-01-03 06:50
    photomankc wrote: »
    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
    setpin(5,1) ;
    waitcnt(CLKFREQ/100 + CNT); 
    setpin(5,0);
    

    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.
    I agree and that is why I said the simpler API might make sense for beginners or infrequent users. Also, there is a reason other than performance for prefering to avoid setting DIRA pins on every call to setpin. There is only a very limited amount of COG memory and wasting even one long for an unnecessary instruction might make the difference between a program that fits and one that doesn't. This mostly applies to COG mode though where the user code is run directly in the COG. LMM or XMM are less constrained.
  • KyeKye Posts: 2,200
    edited 2013-01-03 09:02
    Just copy the Arduino API and extend the Arduino API with overloaded functions. If you don't like how some Arduino API functions are named then make function macros for them.

    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.
  • David BetzDavid Betz Posts: 14,516
    edited 2013-01-03 09:03
    Kye wrote: »
    Just copy the Arduino API and extend the Arduino API with overloaded functions. If you don't like how some Arduino API functions are named then make function macros for them.

    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.
    The only problem with using overloaded functions is that it will force everyone to compile their programs as C++ rather than plain C.
  • jazzedjazzed Posts: 11,803
    edited 2013-01-03 09:24
    photomankc wrote: »
    To weigh in here as a lightweight....

    Interpreted as in one who does not want a heavy load to get value? Not an unreasonable request.
    photomankc wrote: »
    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.

    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.
    setpin(5,1) ;
    waitcnt(CLKFREQ/100 + CNT); 
    setpin(5,0);
    

    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.
  • mindrobotsmindrobots Posts: 6,506
    edited 2013-01-03 09:53
    more random thoughts/impressions:

    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.
  • David BetzDavid Betz Posts: 14,516
    edited 2013-01-03 09:55
    mindrobots wrote: »
    setpins(pin,count,value)
    This seems like a good idea on the surface but the problem is that the P2 has four PINx registers (PINA, PINB, PINC, PIND) so you either have to figure out which one to use based on the pin number or you need separate functions for each like Steve suggested. Also, to make matters more complex, you can remap the PINx registers to point to different pin groups so PINA might now always be pins 0-31.
  • jazzedjazzed Posts: 11,803
    edited 2013-01-03 09:58
  • mindrobotsmindrobots Posts: 6,506
    edited 2013-01-03 10:17
    The port mapping is a good point. I'm not C savvy enough to know if this can be done inside a define assuming you have standard port mapping on the P2. Once you change port mappings, then you have a define dependent on run time information, which I know a define can't do. setpins() could work on the P1 and carry forward to the P2 using a mask with DIRA/OUTA but as soon as you changed port mapping you broke it.

    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.
  • mindrobotsmindrobots Posts: 6,506
    edited 2013-01-03 10:22
    jazzed wrote: »

    Is that a trick question for those of us with failing memory? I REMEMBER posting about it a few weeks ago!! :lol:

    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.
  • jazzedjazzed Posts: 11,803
    edited 2013-01-03 12:26
    mindrobots wrote: »
    Is that a trick question for those of us with failing memory? I REMEMBER posting about it a few weeks ago!! :lol:

    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.
    LOL. If I didn't have enough to do already I would contribute. I doubt that parallax will support it as is, though I could be wrong.
  • David BetzDavid Betz Posts: 14,516
    edited 2013-01-03 12:37
    mindrobots wrote: »
    Is that a trick question for those of us with failing memory? I REMEMBER posting about it a few weeks ago!! :lol:

    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 guess this all depends on what market Parallax is trying to attract. If it's commercial developers then Arduino compatiblity probably isn't very important. It might be for the hobby market though.
  • Cats92Cats92 Posts: 149
    edited 2013-01-04 03:25
    As a non professional programmer I am interested by a Simple to use API for the P1.

    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
  • Erik FriesenErik Friesen Posts: 1,071
    edited 2013-01-04 05:18
    Why can't this be done with a struct, similar to the way Microchip does theirs? IE, LATA for all 32 bits LATAbits.LATA1 = x to set or clear a single bit. This seems a bit awkward to call a function to set a pin.
  • David BetzDavid Betz Posts: 14,516
    edited 2013-01-04 06:25
    Why can't this be done with a struct, similar to the way Microchip does theirs? IE, LATA for all 32 bits LATAbits.LATA1 = x to set or clear a single bit. This seems a bit awkward to call a function to set a pin.
    That could certainly be done if you're talking about accessing the PINA-PIND registers directly but the P2 also has special instructions to set/clear/toggle individual pins.
  • Erik FriesenErik Friesen Posts: 1,071
    edited 2013-01-04 08:13
    Yes, I suppose they mirror the LATASET LATACLR, which are atomic pin set operations. MC doesn't have any special macros for those, I don't think.

    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.
  • mindrobotsmindrobots Posts: 6,506
    edited 2013-01-04 08:21

    Can the p2 pins be set both ways?

    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.
  • jazzedjazzed Posts: 11,803
    edited 2013-01-04 14:19
    Attached is the common P1/P2 API that we have so far. Please review the document for any issues and comment here.

    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
  • jazzedjazzed Posts: 11,803
    edited 2013-01-04 15:13
    Maybe we should alias OUTA and INA on P2 to PINA ... this would allow some portability for existing programs.

    Should this thread be moved to the Propeller 2 forum?
  • David BetzDavid Betz Posts: 14,516
    edited 2013-01-04 15:30
    jazzed wrote: »
    Maybe we should alias OUTA and INA on P2 to PINA ... this would allow some portability for existing programs.

    Should this thread be moved to the Propeller 2 forum?
    I don't think that's a good idea. They have different semantics.
  • 4x5n4x5n Posts: 745
    edited 2013-01-04 17:11
    David Betz wrote: »
    The only problem with using overloaded functions is that it will force everyone to compile their programs as C++ rather than plain C.

    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.
  • SRLMSRLM Posts: 5,045
    edited 2013-01-04 17:21
    4x5n wrote: »
    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
  • jazzedjazzed Posts: 11,803
    edited 2013-01-04 17:44
    David is right about semantics of INA/OUTA -vs- PINA.
    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.
  • KC_RobKC_Rob Posts: 465
    edited 2013-01-05 09:16
    David Betz wrote: »
    I guess this all depends on what market Parallax is trying to attract. If it's commercial developers then Arduino compatiblity probably isn't very important. It might be for the hobby market though.
    That's the 2^16 dollar question: What does Parallax want Prop to be when it grows up? A great deal hinges on that.
  • potatoheadpotatohead Posts: 10,261
    edited 2013-01-05 11:21
    IMHO, both!

    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.
Sign In or Register to comment.