Shop OBEX P1 Docs P2 Docs Learn Events
FlexProp: a complete programming system for P2 (and P1) - Page 12 — Parallax Forums

FlexProp: a complete programming system for P2 (and P1)



  • FlexProp version 5.0.7 is now available, both on github ( and on my Patreon page. It has some important bug fixes in the compiler:
    - Added code to support _ret_ in inline assembly
    - Fixed rdlong x, ptra[##BIG] instruction form
    - Fixed some bugs in cog_run
    - Fixed bit references in arrays like A[x].[y]
    - Fixed uhex() bug where it only output 1 bit
    - Fixed a serious off-by-one error in garbage collection code

    Plus the 5.0.6 changes listed in the previous message. It's definitely worth updating to this version.
  • Cluso99Cluso99 Posts: 18,069
    Thanks Eric :smiley:
  • Hello,

    Completely new to the P2 and Spin. I am having an issue running flexprop on mac iOS 11.1. When I click on the flexprop.tcl I get an error that says "Wish quit unexpectedly". The following is the details that it provides.
    Process: Wish [11530]
    Path: /System/Library/Frameworks/Tk.framework/Versions/8.5/Resources/
    Identifier: com.tcltk.wish
    Version: 8.5.9 (8.5.9)
    Build Info: tcl-129040001000000~536
    Code Type: X86-64 (Native)
    Parent Process: ??? [1]
    Responsible: Wish [11530]
    User ID: 501

    Date/Time: 2021-01-21 13:22:47.584 -0800
    OS Version: macOS 11.1 (20C69)
    Report Version: 12
    Bridge OS Version: 5.1 (18P3030)
    Anonymous UUID: 2289C300-CA2A-6AE8-B66A-19DC2A2F99DB

    Sleep/Wake UUID: 69F2F6CF-3BFC-4CAC-920A-13F9A17B1164

    Time Awake Since Boot: 20000 seconds
    Time Since Wake: 1000 seconds

    System Integrity Protection: enabled

    Crashed Thread: 0 Dispatch queue:

    Exception Type: EXC_CRASH (SIGABRT)
    Exception Codes: 0x0000000000000000, 0x0000000000000000
    Exception Note: EXC_CORPSE_NOTIFY

    Application Specific Information:
    dyld3 mode
    abort() called

    Thread 0 Crashed:: Dispatch queue:
    0 libsystem_kernel.dylib 0x00007fff20306462 __pthread_kill + 10
    1 libsystem_pthread.dylib 0x00007fff20334610 pthread_kill + 263
    2 libsystem_c.dylib 0x00007fff20287720 abort + 120
    3 Tcl 0x00007fff6fe05b55 Tcl_PanicVA + 398
    4 Tcl 0x00007fff6fe05bd5 Tcl_Panic + 128
    5 Tk 0x00007fff6ff05ad5 TkpInit + 385
    6 Tk 0x00007fff6fe85788 0x7fff6fe54000 + 202632
    7 Wish 0x000000010404654c 0x104043000 + 13644
    8 Tk 0x00007fff6fe77a2b Tk_MainEx + 1201
    9 Wish 0x0000000104046523 0x104043000 + 13603
    10 libdyld.dylib 0x00007fff2034f621 start + 1

    Thread 1:
    0 libsystem_pthread.dylib 0x00007fff20330458 start_wqthread + 0

    Thread 2:
    0 libsystem_pthread.dylib 0x00007fff20330458 start_wqthread + 0

    Thread 3:
    0 libsystem_pthread.dylib 0x00007fff20330458 start_wqthread + 0

    Thread 4:
    0 libsystem_pthread.dylib 0x00007fff20330458 start_wqthread + 0

    Thread 0 crashed with X86 Thread State (64-bit):
    rax: 0x0000000000000000 rbx: 0x000000010a134e00 rcx: 0x00007ffeebbbbf18 rdx: 0x0000000000000000
    rdi: 0x0000000000000603 rsi: 0x0000000000000006 rbp: 0x00007ffeebbbbf40 rsp: 0x00007ffeebbbbf18
    r8: 0x00000000000130a8 r9: 0x00007fff889940e8 r10: 0x000000010a134e00 r11: 0x0000000000000246
    r12: 0x0000000000000603 r13: 0x00007ff4b5818910 r14: 0x0000000000000006 r15: 0x0000000000000016
    rip: 0x00007fff20306462 rfl: 0x0000000000000246 cr2: 0x00007ff4b4850000

    Logical CPU: 0
    Error Code: 0x02000148
    Trap Number: 133

    Thread 0 instruction stream not available.

    Thread 0 last branch register state not available.

    **A bunch of binary stuff here**

    How do I go about this?

  • dgatelydgately Posts: 1,623
    edited 2021-01-22 00:38
    Tk tcl (8.5.n) which comes installed on macOS 11.1 seems broken as it asks for macOS 11 or later (odd???)... So, you need to get a different version of tcl-tk (8.6.n)...

    EDIT: Try this:

    wish running on macOS 11.1 as installed:
    $ /System/Library/Frameworks/Tk.framework/Versions/8.5/Resources/
    macOS 11 or later required !
    [1]    15789 abort

    Most macOS users use homebrew (or get sources and build from: to install a version of tcl-tk that will run without problems. I'm running tcl-tk with version 8.6.9 successfully.


  • iseriesiseries Posts: 1,464
    edited 2021-01-23 14:30
    Converting some code and getting this error:
    var1 = ((int32_t) temp_adc >> 3) - ((int32_t) dev->calib.par_t1 << 1); error: Cannot handle expression yet


    Never mind, I see that var1 is defined as 64 bits or long long which is not supported.
  • I've released version 5.0.8 of FlexProp. The changes are all in the compiler, and include:
    - Added a warning for casting const pointers to non-const
    - Added missing tan function to math.h
    - Fixed Spin2 pinread to work correctly with multiple pins
    - Fixed an optimizer bug that could cause corruption of small multi-word structs being returned from a C function
    - Properly implemented compile time optimization of BASIC ASC("x") function
    - New BASIC string functions from JRoark: improved implementations of some existing functions, and added functions CountStr, RemoveChar$, ReplaceChar$, and StrInt$

    Links to the download are in my signature and in the first post on this thread.
  • Thank you for the help! Worked after I installed Wish 8.6!

  • I'm trying to compile this code which has the typedefs from hell in it.

    Anyway I have worked through most of it and stopped with "error: syntax error, unexpected type name `spiffs_page_header'"

    Can you take a peek at it and tell me what's going on.

    I have attached the include files and a sample program that should compile.


  • Seeing this error now. I guess over defined.

    warning: Preprocessor warnings:

    D:/flexprop/include/simpletools.h:10: warning: The macro is redefined

      #define cogstart _cogstart

      from D:/Documents/My Projects/P2/moo.c: 12:  #include "simpletools.h"

      previously macro "cogstart" defined as: #define cogstart(func,par,stack,stacksize) __builtin_cogstart(func(par), stack) /* D:/flexprop/include/propeller.h:51 */


  • It's missing the flash.h header file. Looking at the code the error happens on a line with offsetof(), which is supposed to be defined in <stddef.h>, but I don't see that header file included anywhere. Try adding #include <stddef.h> to spiffs_nucleus.c.

  • iseriesiseries Posts: 1,464
    edited 2021-01-27 21:31

    Smile, I thought I got all of it. Well here's that file.


    Ok, Now a can't read either.

    Here everything you should need again....

  • Is the full Debug feature not supported on Flexprop? I am able to do some commands, but nothing related to the backticks (`).

  • @iseries : It's the stddef.h, you need to add #include <stddef.h> to the top of the file that's throwing the error.

    @arkret : No, only a subset of debug is supported. I'm hoping Chip will release a stand-alone debug window to allow other applications/compilers to access the graphical features.

  • iseriesiseries Posts: 1,464
    edited 2021-01-28 12:34

    Seeing this verbiage in the code:

      // align cand_scores on s32_t boundary

     cand_scores = (s32_t*)(((intptr_t)cand_scores + sizeof(intptr_t) - 1) & ~(sizeof(intptr_t) - 1));

    Does intptr_t do anything.


    Getting this error: error: Expected integer type for parameter of bit operation

    cand_scores is a pointer to long. If I cast it to a long it's fine.

  • intptr_t is the type of an integer that's the same size as a pointer. It's defined in <stdint.h>. For us, it's 32 bits long, which is also the size of "int" and "long". But the code really should be including <stdint.h> to get that size!

  • Almost forgot, I had to add these defs for some code for bme280, bme680 modules:

    #define INT8_C(x)  (x)
    #define INT16_C(x)  (x)
    #define INT32_C(x)  (x)
    #define INT64_C(x)  (x ## LL)
    #define UINT8_C(x)  (x)
    #define UINT16_C(x) (x)
    #define UINT32_C(x) (x ## U)
    #define UINT64_C(x) (x ## ULL)
    #define INTMAX_C(x) INT64_C(x)
    #define UINTMAX_C(x) UINT64_C(x)


  • Having a issue with my SPIFFS call back code.

       res = spiffs_obj_lu_find_entry_visitor(d->fs,

    spiffs_read_dir_v is a function with this definitions:

    // callback func for object lookup visitor
    typedef s32_t (*spiffs_visitor_f)(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry,
        const void *user_const_p, void *user_var_p);

    In the other calls the ampersand is not need and calls the correct function. For this one item it fails to create a method pointer.

    Here is the definition of the function:

    s32_t spiffs_obj_lu_find_entry_visitor(
        spiffs *fs,
        spiffs_block_ix starting_block,
        int starting_lu_entry,
        u8_t flags,
        spiffs_obj_id obj_id,
        spiffs_visitor_f v,
        const void *user_const_p,
        void *user_var_p,
        spiffs_block_ix *block_ix,
        int *lu_entry);

    Here is a test program that doesn't make sense to me. I thought it would print the address of the function but got a strange answer.

    #include <stdio.h>
    #include <propeller.h>
    typedef long (*test)(int x, int y);
    int main(int argc, char** argv)
        printf("Call Back: %x\n", callback);
    	callit(16, 20, callback);
        while (1)
    long callback(int x, int y)
        printf("X: %d, Y: %d\n", x, y);
        return -1;
    void callit(int x, int y, test v)
        int i;
        printf("call back: %x\n", v);
        i = v(x, y);
        printf("I: %d\n", i);
    Call Back: 6d0
    call back: 63802748
    X: 16, Y: 20
    I: -1

    Here is a working copy of the SPIFFS file system:

    Here is a program that will create a SPIFFs file system on the last 512K bytes of the P2 flash.

    #include <stdint.h>
    #include <stdio.h>
    #include <propeller.h>
    #include "flash.h"
    #include "spiffs.h"
    #define MOSI 59
    #define MISO 58
    #define CLK  60
    #define CS   61
    #define LOG_PAGE_SIZE 256
    static spiffs fs;
    static char spiffs_work_buf[LOG_PAGE_SIZE*2];
    static char spiffs_fds[32*4];
    static char spiffs_cache_buf[(LOG_PAGE_SIZE+32)*4];
    flash_t *flash;
    char Buffer[256];
    struct spiffs_dirent xentry;
    struct spiffs_dirent *pentry;
    spiffs_DIR dir;
    spiffs_config cfg;
    int main(int argc, char** argv)
        int i;
        flash = Flash_Init(MOSI, MISO, CLK, CS);
        if (flash == NULL)
            printf("Flash Not Found!\n");
            while (1)
        i = SpiffsMount();
        if (i == 0)
        	printf("Spiffs Mount Error: %d\n", i);
        while (1)
    int SpiffsMount()
        int res;
        cfg.hal_read_f = SpiffsRead;
        cfg.hal_write_f = SpiffsWrite;
        cfg.hal_erase_f = SpiffsErase;
        res = SPIFFS_mount(&fs,	&cfg, spiffs_work_buf, spiffs_fds,
          	sizeof(spiffs_fds),	spiffs_cache_buf, sizeof(spiffs_cache_buf), NULL);
        if (res < 0)
    	    res = SPIFFS_mount(&fs,	&cfg, spiffs_work_buf, spiffs_fds,
        	  	sizeof(spiffs_fds),	spiffs_cache_buf, sizeof(spiffs_cache_buf), NULL);
        return res;
    void SpiffsTest()
        spiffs_file fd;
        memset(Buffer, 0, sizeof(Buffer));
        fd = SPIFFS_open(&fs, "my_file", SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_RDWR, 0);
        if (SPIFFS_write(&fs, fd, (u8_t *)"Hello world", 12) < 0)
        	printf("errno %i\n", SPIFFS_errno(&fs));
        SPIFFS_close(&fs, fd);
        fd = SPIFFS_open(&fs, "my_file", SPIFFS_RDONLY, 0);
        if (SPIFFS_read(&fs, fd, (u8_t *)Buffer, 12) < 0)
        	printf("errno %i\n", SPIFFS_errno(&fs));
        SPIFFS_close(&fs, fd);
        printf("--> %s <--\n", Buffer);
    void SpiffsTest2()
        spiffs_file fd;
        fd = SPIFFS_open(&fs, "index.html", SPIFFS_RDWR, 0);
        if (fd < 0)
        	printf("File Error %d\n", fd);
    void SpiffsTest3()
        int i;
        pentry = &xentry;
        printf("Starting Directory\n");
        i = SPIFFS_opendir(&fs, "/", &dir);
        pentry = SPIFFS_readdir(&dir, pentry);
        while (pentry)
            printf("%s [%04x] size:%i\n", pentry->name, pentry->obj_id, pentry->size);
            pentry = SPIFFS_readdir(&dir, pentry);
    	printf("Ending Directory\n");
    void SpiffsCheck()
        int i;
        i = SPIFFS_check(&fs);
        printf("Check: %d\n", i);
    void SpiffsStats()
    	u32_t total, used;
    	int res;
      	res = SPIFFS_info(&fs, &total, &used);
      	printf("Total: %d, Used: %d\n", total, used);
    long SpiffsRead(unsigned long addr, unsigned long size, char *dst)
        Flash_Read(flash, addr, dst, size);
        //printf("Read: %x, Size: %d\n", addr, size);
        return SPIFFS_OK;
    long SpiffsWrite(unsigned long addr, unsigned long size, char *src)
        Flash_Write(flash, addr, src, size);
        //printf("Write: %x, Size: %d\n", addr, size);
        return SPIFFS_OK;
    long SpiffsErase(unsigned long addr, unsigned long size)
        Flash_Erase(flash, addr, size);
        //printf("Erase: %4x, Size: %d\n", addr, size);
        return SPIFFS_OK;


  • @ersmith the first two links shown in the first post of this forum thread are 404 errors. Could you correct them?

    We're starting to feature FlexProp in Quick Bytes and I'm checking to see that the user will succeed when they follow our instructions.


    Ken Gracey

  • Thanks @"Ken Gracey" . For some reason the forum software was incorporating the closing parenthesis into the URL. I've added a space and now I think all is well.

  • Looking good on this end now.

  • I've released FlexProp 5.1.0. This is a fairly big update, with some new features and many bug fixes. Among the new features are:

    • ASMCLK support for Spin2
    • FRAC support for Spin1
    • improved strings support for BASIC (thanks to @JRoark )
    • vsnprintf in C
    • more accurate floating point routines for C and BASIC
    • faster I/O for C and BASIC

    and of course many bug fixes.

  • RsadeikaRsadeika Posts: 3,824
    edited 2021-02-20 14:42

    Installed the latest FlexProp on the Raspberry Pi and when I switch over to P1 mode and scan for ports:

    couldn't execute "bin/proploader": no such file or directory
    while executing
    "exec -ignorestderr bin/proploader$EXE -W"
    (procedure "rescanPorts" line 18)
    invoked from within
    invoked from within
    ".#mbar.#mbar#comport invoke active"
    ("uplevel" body line 1)
    invoked from within
    "uplevel #0 [list $w invoke active]"
    (procedure "tk::MenuInvoke" line 50)
    invoked from within
    "tk::MenuInvoke .#mbar.#mbar#comport 1"
    (command bound to event)

    I have not tried this on my regular PC, I want to get this to work on my Raspberry Pi.


  • ersmithersmith Posts: 5,954
    edited 2021-02-20 15:36

    In order to build proploader (the P1 loader tool) you have to have openspin installed. The WiFi support in proploader depends on some funky loading stuff that doesn't seem to work with flexspin (I think they make assumptions about the format of the compiled bytecodes). You'll either have to find a pre-built package for openspin or else build it from source, which isn't too hard. To completely build openspin + flexprop on Raspberry Pi do:

    mkdir src
    cd src
    git clone --recursive
    cd openspin
    sudo cp build/openspin /usr/local/bin
    cd ..
    git clone --recursive
    cd flexprop
    make install
  • The following C code hangs for some reason:

    #include <stdio.h>
    #include <propeller.h>
    #define PIN 15
    int main(int argc, char** argv)
        int i;
        while (1)
            while (_pinr(PIN) == 1);
            while (_pinr(PIN) == 0);
            i = _getus();
            while (_pinr(PIN) == 1);
            i = _getus() - i;
            printf("Value: %d\n", i);

    If I uncomment the _pinl(56) the code runs just fine.
    The assembly code looks good but it may be the fache stuff.


  • @iseries : Hmmm, it actually looks like the original code (without the _pinl) is the one with the bug, as it's putting too much stuff (including the call to _getus) into the fcache. This happens to be harmless in this particular case, but I'm guessing that the corrected version (with _pinl) exhibits different timing. _getus() is a fairly expensive operation since it involves a divide. How sensitive is your hardware to timing? How many microseconds is the pin likely to be high or low?

    You'll probably have better luck capturing the system frequency timer directly (counting cycles rather than microseconds) and then converting to microseconds after the timing sensitive code.

    Also note that _pinr() does *not* set the pin as an input. I guess it's defaulting to input, so it's fine, but you can force it with a _fltl(PIN).

  • This code hangs or crashes as well:

    #include <stdio.h>
    #include <propeller.h>
    #define PIN 15
    int main(int argc, char** argv)
        int i;
        while (1)
            i = getAngle(PIN);
            printf("Value: %d\n", i);
    int getAngle(int p)
        int i;
        while (_pinr(p) == 1);
        while (_pinr(p) == 0);
        i = _getus();
        while (_pinr(p) == 1);
        i = _getus() - i;
        return i;

    This is measuring a 360 servo input which goes from 30us to 1030us. I checked it with a scope.
    When the code works it's dead on reporting 36 to 1030.
    P2 running at 200MHz.


  • ersmithersmith Posts: 5,954
    edited 2021-02-20 22:12

    Mike, I really suspect that _getus() is too slow (I can't see any other reason why that program would hang). Does it work if you change the timing to:

        i = _getcnt();
        while (_pinr(p) == 1) ;
        i = _getcnt() - i;
        return i / 200;  // convert ticks to microseconds, assumes 200 MHz clock

    Also, you probably want to make the variable i in that function "unsigned" rather than "int".

  • I've released FlexProp 5.1.1. The major new change is a CHAIN function in BASIC (and execve in C) to allow running another P2 binary from host or SD card. Note that the new binary will completely take over the machine when it's running and will not return to the original -- it's a one way transfer. Other restrictions:

    • during the load the original program has to remain resident (it's busy doing the load) so both programs must fit into HUB memory together. Once the load is finished the original program is erased (overwritten by copying the new one down to address 0).
    • the clock frequency is reset to RCFAST before the new program is started
    • COGs are not stopped, nor are pin states reset. This is deliberate, but it's dangerous because HUB RAM is being completely overwritten by the new program, so the COGs cannot rely on anything in HUB.
    • The new binary can be any compiled P2 program, it doesn't have to be built with flexspin or with any particular memory layout
  • Also of note is the "shell" sample, which I posted elsewhere on the forums, and which allows you to copy files between the host PC and the P2 board's SD card.

    • during the load the original program has to remain resident (it's busy doing the load) so both programs must fit into HUB memory together.

    Lame :)
    P1 SD drivers can boot full 32k executables, P2 surely should be able to manage it, too.

Sign In or Register to comment.