Shop OBEX P1 Docs P2 Docs Learn Events
Toolchain for C with pasm — Parallax Forums

Toolchain for C with pasm

Hi,

short background info.

I'm implementing a one off device (so no production) that will count and monitor STEP and DIR pulses in stepper motor control system.

As I have a propeller kit from many years ago and have searched for a worthwhile project to use it in I'm starting with that.

The device will output step counts (and min pulse widths etc) in real realtime much like a milling machine DRO (Digital Read Out),
so the VGA output from the propeller is very attractive.

My thinking is that most of the stuff I will implement in C in one COG but the fast measurement and counting will be done with Propeller assembly language one STEP/DIR monitoring per COG for four steppers.

I would really, really prefer to do this on macOS, though I have Windows 7/10 running in this Mac as well as several Linux distros under VirtualBox.

I've got +40 years of programming all the usual suspects of languages and processors under my belt.

Ok that is the background.

Now to the specific questions.

I've tried both SimpleIDE and PropellerIDE with my eval board and I can get simple example code to compile, download and execute just fine.

I then tried mixing spin and C but this fails with the propeler-elf-objcopy not being able to find the .dat file for the spin code although it seems to compile just fine and I can see the file.

(Sorry can't copy the error message here because SimpleEdit does not support that apparently.)

Reading from the web I got discouraged that maybe this (mixing C with pasm/spin) is not supported by SimpleIDE ?

Moving on I searched for other tool chains.

I see flexgui but I did not find anyone using it on Mac, looks like it [getting it run on macOS] could be done but that would be distraction from the main goal.

I noted fastspin and it seems to support mixing C and pasm but the P1 support looked like it could be sketchy?

Also I read that fastspin C compiles to pasm which is great except does that not limit the code size to very small as it will have to fit into a single COG?

My application is not going to require a lot of code or math (simple integer math and displaying the results on the VGA display) but it seems unlikely that the code would fit in 496 longs.

So please let the crowd wisdom flourish!

wbr Kusti

Comments

  • evanhevanh Posts: 15,923
    There is a lot to answer there. I'll start with the Flexgui and Fastspin. Both are new and developed by an active forum member. As you may have guessed, they are mostly being used with the almost ready Propeller 2 chip. That said, I believe Eric has tried to maintain all the support for the Propeller 1 also. See https://forums.parallax.com/discussion/164187/fastspin-compiler-for-p2-assembly-spin-basic-and-c-in-one-compiler/p1

    I haven't really used the Prop1 myself so can't give actual guidance on tool use, sorry.

    As for what you are trying to do with the Prop1, it sounds perfectly feasible.
  • I have been using SimpleIDE for years and as long as you use the LMM memory model it generates code that runs at processor speed. The CMM memory model generates sudo interpreted code to save space and effects the speed of the code.

    Counting code can be done without assemble code. I have never had to use SPIN code.
    /*
     * generate pulse every 2 milliseconds
     * 80 mhz / 80000 = 1 millisecond
     * 160000 = 2 milliseconds cut off
     */
    void sidetest()
    {
      unsigned long T;
      
      low(0);
      FRQA = 1;
      CTRA = 0x10000000 | 0;
    
      while (1)
      {
        T = CNT;
        PHSA = ~80000;
    
        while ((CNT - T) < 160000);
        PHSA = 0;
      }
      
    }
    

    Mike
  • Cluso99Cluso99 Posts: 18,069
    edited 2019-10-06 10:12
    All C compilers convert the code to PASM (assembler). Depending on the options selected, the pasm will either run in cog, from hub as LMM (a method that copies each instruction one at a time from hub into cog and execute it - this runs at 1/8 the speed of cog code) or from external memory which is even slower. There are cache methods to get some speed back for LMM and external modes.

    Combining pasm objects is possible, but its not so easy depending on which compiler you use.

    There is another solution that is much slower, but works seemlessly with pasm and that is spin. Spin is a simple high level language which has a builtin pasm interpreter in ROM. The interpreter loads into cog to run. Spin is simple to get used to if you’ve programmed in most higher level languages. If you are not speed constrained i suggest you try this. You won’t be disappointed.

    If you need speed, then what you describe sounds easy to do in pasm. P1 assembler is NOT your typical assembler. Its quite easy to learn, and there are masses of help from this forum. Your code will be small and fast. There’s no interrupts to worry about.

    Four cogs will handle the four step/dir with ease presuming its not extremely fast, with plenty of time to do basic integer arithmetic. Youll need a cog for the VGA.

    One of Eric’s compilers will translate spin or C to pasm for you and you can then take this as a base and modify it to suit.

    BTW there are inbuilt timers and counters in every cog so this will help your tasks.

    Just ask as you go. Lots of help is here for you :)
    Sorry, cannot help re mac.
  • flexgui is just a front end for fastspin. I don't have a working Mac setup right now, so I can't test it there, but the main program (flexgui.tcl) is platform independent and @dgately got it to work on MacOS, so it ought to work there.

    fastspin itself is totally supported on P1, it's actually tested more on P1 than P2.

    But the first step in all of this is to verify that you actually need to do the programming in assembly. Both PropGCC and flexspin produce pretty fast code, especially for small loops, so you may well be able to do all the capturing in C itself. You can start C functions up on other COGs using the "cogstart" function defined in propeller.h.
  • If you need to use PASM and want to use SilmpleIDE, I have my adventure getting a PASM Spin object into a SimpleIDE C program. The thread starts here:
    https://forums.parallax.com/discussion/157441/can-spi-in-simple-libraries-be-speeded-up/p1
    Tom
  • RossHRossH Posts: 5,462
    Hello @nyholku

    There is also Catalina. Catalina is known to compile on a Mac, but I have not done so recently as I no longer have access to one. However, just to try it out you could install it on Windows or Linux. There are examples of integrating Spin and PASM with C in the demos\spinc folder which is included in the distribution.

    Here is the README from that folder.
    This README file covers two different but related topics:
    
    - USING SPIN WITH CATALINA
    
    - USING PASM WITH CATALINA
    
    There are several options for both of these. Each is described separately, in
    the sections below. 
    
    1. USING SPIN WITH CATALINA
    ===========================
    
    While it is not possible to directly call Spin methods from Catalina C or to
    call Catalina C functions from Spin, it is possible to run C and Spin programs 
    concurrently, and even to communicate between the two. 
    
    To do this, Catalina provides a utility (spinc) that converts a compiled Spin 
    binary into an object that can be included in a C program, then initiated from
    C by calling a prefefined C function. The only limitation is that there must 
    be sufficient free resources (i.e. cogs, pins and RAM) for the Spin program.
    
    When a Spin program is executed from Catalina, some Hub RAM, and at least one 
    cog (i.e. the one used to run the Catalina kernel) will already be in use. In 
    most cases, several cogs will already be in use (i.e. any cogs used by a plugin
    or driver). 
    
    Any Spin program that assumes it has access to all 8 cogs, or to specific cogs, 
    or which assumes it has access to all 32k, or which uses hardcoded memory 
    addresses to access Hub RAM, will probably NOT be able to run under Catalina. 
    However, all of these are rare cases, and most Spin programs will be able to 
    be executed by Catalina.
    
    When executing Spin programs, Catalina can either use the Spin interpreter that
    is built into the Propeller ROM, or a modified spin interpreter can be provided
     - as long as it uses the same start-up parameters as the built-in interpreter. 
    
    Although all Spin programs must execute in Hub RAM, Catalina can execute Spin 
    programs even if the Catalina program itself is executing from XMM RAM.
    
    There are several demo programs provided, all of which can be built using the 
    'build_all' batch file provided. E.g:
    
       build_all C3
    
    The example Catalina programs that run Spin programs which this command will 
    build are as follows. Note - make sure to load and execute the "run_xxx.binary"
    programs (which are the Catalina programs) and not the "xxx.binary" programs
    (which are the original Spin programs!).
    
       run_flash.binary - demontrates a simple Spin program (flash.spin) which 
                          flashes a LED at the rate of 1Hz. Note that you will
                          need to modify the LED_PIN number in the Spin program 
                          if you have a Propeller platform other than a C3. This
                          program in interesting because as well as flashing the
                          LED via the Spin program, the C program also prints "on!" 
                          or "off!" ont the screen - this is done by the C program
                          reading the current value of the LED output from the Spin 
                          program's VAR array, and shows the basic mechanism for
                          having Spin and C programs interacting.
    
       run_hello.binary - demonstrates a Spin program (hello.spin) that makes
                         use of whatever HMI plugin has been loaded by Catalina.
                         Also uses the file "Catalina_HMI.spin" which provides
                         wrapper functions for all Catalina HMI functions.
    
       run_demo.binary  - runs the demo program for Bagger's 40*30 TV driver. This
                         demo is interesting because while the TV driver demo is
                         running, Catalina is running using serial HMI drivers.
                         Note that you will need to modify the pin numbers in the
                         file TV_Text_Half_Height_Demo.spin if you are not using
                         a C3. To see the serial output, use payload's interactive
                         mode:
    
                            payload -i run_demo
    
       run_kb_tv.binary  - run a simple terminal program that accepts keystrokes
                         and echoes them on the terminal, translating any numeric
                         keys to strings. This is interesting because it is using
                         standard OBEX drivers for HMI functions instead of the
                         normal Catalina HMI functions. Note that you will need to
                         modify the pin numbers in the file HMI.spin if you are
                         not using a C3. 
    
       run_tiny_hmi.binary - same as above, but uses the spinc -t option instead
                         of -c, to produce a slightly smaller binary suitable only 
                         for compiling in TINY mode (the run_hmi.binary program 
                         could be compiled to run in SMALL or LARGE mode). Note 
                         that you will need to modify the pin numbers in the file 
                         TINY_HMI.spin if you are not using a C3.
    
       run_PNut.binary - same as run_flash.binary (above), but uses a custom Spin
                         interpreter (actually, it uses the PNut interpreter).
    
    For details on the many new spinc options, execute the command
          
       spinc -h                   
    
    
    
    2. USING PASM WITH CATALINA
    ===========================
    
    The Catalina compiler conforms to the ANSI C standard. This standard does not 
    include the "asm" keyword (or function) that is sometimes added to C compilers
    to simplify the inclusion of code written in assembly language in a C program. 
    
    However, it is still possible to incorporate PASM assembly language code into 
    Catalina C programs. There are at least four different techniques that can be 
    used to do this:
    
    1. Write a target that loads the PASM program during initilization.
    
    2. Convert the PASM program into a Catalina "plugin" and load it during 
       initialization (as is done for the various HMI drivers, the floating 
       point libraries, and the SD card and clock drivers).
    
    3. Load the compiled binary version of a PASM program into a spare cog from
       within the C program (using the _coginit() function).
    
    4. Write a subroutine in LMM PASM and call it from the C program in the same 
       way that any C function is called. 
    
    Each of these techniques is described in more detail below.
    
    
    
    LOAD THE PASM PROGRAM AT INITIALIZATION TIME
    ============================================
    
    Each Catalina target is a normal SPIN program whose job is to establish the
    execution environment for the Catalina C program. However, this program can
    execute any PASM or SPIN code, including loading PASM programs into cogs to 
    be run in parallel with the C program. Of course, the PASM program must not
    read or write to Hub RAM except under well defined circumstances - e.g. by
    only writing to an area of high RAM that Catalina reserves for this purpose.
    
    For an example of this technique, see the Catalina_Cogstore.spin program. 
    This is a normal PASM program started by various Catalina targets to assist 
    in decoding command-line arguments passed to the program. In this particular
    case the PASM program is stopped again once its work is completed - but it
    could be left running if necessary. An example of the latter are the various
    'blackcat' targets (e.g. lmm_blackcat_Input.spin).
    
    This technique is not discussed any further in this document.
    
    
    
    CONVERT THE PASM PROGRAM INTO A PLUGIN
    ======================================
    
    Plugins are a very versatile solution since they can interact with the 
    Catalina C program at run time - but they can be complex to develop and can
    also be expensive in resources (since they cannot be loaded and unloaded on
    demand - they are expected to be loaded once and then remain running for 
    the duration of the C program). 
    
    However, plugins are the best solution when the PASM program and the C program 
    are required to interact since there is a well-defined interface that supports
    communication between a C program and any plugins that have been loaded to
    support it.
    
    The Catalina Reference Manual described plugins in detail, and there are many
    examples provided in the Catalina target and target\input directories. Most 
    standard Parallax drivers can be easily converted into plugins. 
    
    This technique is not discussed any further in this document.
    
    
    
    LOADING A COMPILED PASM PROGRAM INTO A COG
    ==========================================
    
    Catalina provides a _coginit() function that works in a very similar manner
    to the corresponding SPIN or PASM 'coginit' operations - i.e. it is used to 
    load a binary PASM program into a cog for execution. 
    
    A tool to assist in converting a PASM binary into a form suitable for loading 
    from C is provided - this tool is called 'spinc'. It is provided in both source 
    and executable form. Thanks go to Steve Densen for the initial version of this
    this useful tool!
    
    An example of using the spinc tool is provided. It is called 'test_spinc'. To 
    build it, use the 'build_all' batch file provided. E.g:
    
       build_all HYDRA
    
          +============================================================+
          | NOTE: Even though you specify your platform when building, |
          |       you may still need to modify the clock speed and pin |
          |       numbers defined in the file flash_led.spin           |
          +============================================================+
    
    This batch file executes the following commands:
    
    a) compiles the flash_led.spin PASM program (to produce flash_led.binary):
    
       spinnaker -p -a flash_led.spin -b
    
    b) converts the flash_led binary to a C include file:
    
       spinc flash_led.binary > flash_led_array.h
    
    c) compiles a C program which loads the resulting binary using _coginit():
    
       catalina -lc -I. test_spinc.c
    
    Examine each of the files mentioned above for more detail. To load and execute
    the resulting program, simply type:
    
      payload test_spinc
    
    
    
    WRITING AN LMM PASM FUNCTION THAT CAN BE CALLED FROM C
    ======================================================
    
    A Catalina C program can call a PASM function directly. However, the PASM must
    be specially written to allow it to be executed by the LMM Kernel.
    
    "LMM" PASM (i.e. PASM intended to be executed by the LMM Kernel) is slightly 
    different to "pure" PASM (i.e. PASM intended to be executed directly by a cog).
    While many LMM PASM instructions are identical to pure PASM, some pure PASM 
    instructions cannot be executed within the kernel. Instead, they must be 
    replaced by LMM equivalents known as "primitives".
    
    A good example of this is the PASM "jmp" instruction. If this instruction were
    executed within the LMM kernel, the program would jump to the corresponding
    location within the kernel itself, not the desired location in the PASM 
    program. So Instead of using "jmp", a new LMM PASM "primitive" (called JMPA) 
    is provided:
    
    In pure PASM, a jmp instruction might look as follows:
    
       loop jmp #loop    ' loop forever
    
    In LMM PASM, this would have to be replace by the following:
    
       loop jmp #JMPA    ' loop ...
            long @loop   ' ... forever
    
    More information on the pure PASM instructions that need to be replaced by
    LMM PASM equivalents is given in the Catalina Reference Manual. 
    
    A full working example of this technique is provided in this directory. It is 
    called 'test_pasm'. To build it, use the 'build_all' batch file provided. 
    E.g:
    
      build_all HYDRA
    
          +============================================================+
          | NOTE: Even though you specify your platform when building, |
          |       you may still need to modify the clock speed and pin |
          |       numbers defined in the file flash_led.obj            |
          +============================================================+
    
    This batch file executes the following catalina command:
    
      catalina -lc test_pasm.c flash_led.obj 
    
    The file flash_led.obj is the LMM PASM program - giving it the 'obj' extension
    tells catalina that it is not a C file that needs to be compiled, it is a PASM 
    file that is ready to be bound. In fact, all catalina 'obj' files are LMM PASM
    programs and can be viewed with any text editor. Examine both flash_led.obj
    and test_pasm.c for more details. To load and execute the resulting program, 
    simply type:
    
      payload test_pasm
    
    

    Note that this README is a little out of date - since I wrote it, I have also added a PASM function to incorporate individual PASM instructions inline into a C program. This is described in the Reference Manual. Here is a short extract:
    Using the PASM function
    
    Catalina defines a PASM function that can be used for including PASM instructions
    inline with C code. The prototype for this function (defined in propeller.h) is:
    
       extern void PASM(const char *code);
    
    However, there is no actual PASM function body. Instead, when it sees a call to this
    function, the compiler inserts the string literal given as argument (it cannot be a
    variable) into the assembly language output, to be compiled by the PASM compiler.
    For example, the following program will toggle the Propeller's P0 output every 500
    milliseconds:
    
    #include <propeller.h>
    
    void main() {
    
       PASM("or dira, #1"); // set bit 0 as output
       while(1) {
          msleep(500);
          PASM("xor outa, #1"); // toggle bit 0
       }
    }
    

    You have lots of options!

    Ross.
  • Hi,

    thanks all!

    Seems like I do have a lot of options.

    I think I will start with C-only.

    If that is not fast enough I will look into the other options.

    The goal of this device is to just to ensure (or expose) that the STEP and DIR signals meet their specifications. The step signal is max 100 kHz. What I need to ensure is that STEP is not too short. That the STEP signals never come too close together and that the time between two STEP pulses never changes too radically. Also that the time from DIR change to STEP is always higher than a limit.

    My thinking is that a single cog will monitor the signals for change and queue them for an other cog to process. This should allow for pretty tight loop in the first cog. If I can figure how ensure that the hardware detects the situation in which a pulse changes back and forth between the first cog sampling the inputs then this should be fool proof and the actual speed is not critical as I expect that this device will (should) NOT detect any violations.

    cheers Kusti
  • nyholku wrote: »
    ...
    Moving on I searched for other tool chains.
    I see flexgui but I did not find anyone using it on Mac, looks like it [getting it run on macOS] could be done but that would be distraction from the main goal.
    flexgui is a Tcl/Tk application... It runs with a just a few minor tweaks on macOS, using the Wish shell, which gets installed with the Tk framework.

    For Tk/Tcl installation, see: https://tkdocs.com/tutorial/install.html
    Install XQuartz: https://www.xquartz.org

    I execute flexgui with the following command, in the XQuartz terminal:
    $ cd flexgui_pathname         <== the file path to where our have placed flexgui's directory
    $ wish flexgui.tcl
    

    I slightly mod flexgui's source code (src/gui.tcl), to add more-typical macOS file locations, to get the following option-settings:
    Flexgui-Commands.png
    # provide some default settings
    proc setShadowP1Defaults {} {
        global shadow
        global WINPREFIX
        // mod to use fastspin, installed @ "/opt/parallax/bin/"
        set shadow(compilecmd) "\"fastspin\" -l %O -L \"./spin2cpp/include\" \"%S\""
        set shadow(runcmd) "$WINPREFIX \"proploader\" -Dbaudrate=115200 %P \"%B\" -r -t -k"
    }
    proc setShadowP2aDefaults {} {
        global shadow
        global WINPREFIX
        // mod to use fastspin & loadp2, installed @ "/opt/parallax/bin/"
        set shadow(compilecmd) "\"fastspin\" -2a -l %O -L \"./spin2cpp/include\" \"%S\""
        set shadow(runcmd) "$WINPREFIX \"loadp2\" %P -l230400 -b230400 \"%B\" -t -k"
    }
    proc setShadowP2bDefaults {} {
        global shadow
        global WINPREFIX
        // mod to use fastspin& loadp2, installed @ "/opt/parallax/bin/"
        set shadow(compilecmd) "\"fastspin\" -2b -l %O -L \"./spin2cpp/include\" \"%S\""
        set shadow(runcmd) "$WINPREFIX \"loadp2\" %P -l230400 -b230400 \"%B\" -t -k"
    }
    

    Not sure if ersmith could "#ifdef macOS" to include these types of changes for other Mac users, but they do work for me :-)


    dgately
    688 x 500 - 140K
  • dgately wrote: »
    I slightly mod flexgui's source code (src/gui.tcl), to add more-typical macOS file locations, to get the following option-settings:
    Flexgui-Commands.png

    Not sure if ersmith could "#ifdef macOS" to include these types of changes for other Mac users, but they do work for me :-)

    No need to change the flexgui source code for that. Everything in the "Configure Commands..." dialog is persistent, so you can make those changes in that dialog once and then use them in future invocations. The contents are saved in the .flexgui.config file. If you keep this file across updates you'll keep your changes.
  • ersmith wrote: »
    No need to change the flexgui source code for that. Everything in the "Configure Commands..." dialog is persistent, so you can make those changes in that dialog once and then use them in future invocations. The contents are saved in the .flexgui.config file. If you keep this file across updates you'll keep your changes.
    Excellent!
Sign In or Register to comment.