Shop Learn
Can't Wait for PropGCC on the P2? - Page 16 — Parallax Forums

Can't Wait for PropGCC on the P2?

1131416181926

Comments

  • Dave HeinDave Hein Posts: 6,331
    edited 2019-01-22 18:33
    I added this code to primos.c, and called init_stacks at the beginning of main, and check_stacks at the end of the big while loop. All of the cogs used 56 ints. So your stack needs to be at least 56 ints in size.
    void init_stacks(int num)
    {
        int i, j;
        for (i = 0; i < 7; i++)
        {
            for (j = 0; j < num; j++)
                stacks[i][j] = 0xdeadbeef;
        }
    }
    
    void check_stacks(int num)
    {
        int i, j;
        for (i = 0; i < 7; i++)
        {
            for (j = 0; j < num; j++)
            {
                if (stacks[i][j] != 0xdeadbeef) break;
            }
            printf("stack %d used %d ints\n", i, num - j);
        }
    }
    
  • pmrobertpmrobert Posts: 636
    edited 2019-01-22 19:08
    @jmg, Yes I did. Apparently the loadp2 terminal only supports the baked-in Linux Baud rates, e.g.
    #ifdef B460800
            case 460800:
                tbaud = B460800;
                break;
    #endif
    #ifdef B230400
            case 230400:
                tbaud = B230400;
                break;
    #endif
            case 115200:
                tbaud = B115200;
                break;
            case 57600:
                tbaud = B57600;
                break;
    
    if they correspond with the calculated terminal rate elsewhere in loadp2. A few messages back Dave Hein mentioned that he was going to fix this issue. I can live with the 320MHz/460800 environment for now. Addendum: 320MHz exhibits ~39C via IR thermo on bottom of ES board. No worries there.
  • pmrobertpmrobert Posts: 636
    edited 2019-01-22 19:06
    @jmg, I see what you were getting at after a little thought! Unfortunately, that doesn't fly either.
    pmrobert@odin:~/p2gcc-master$ loadp2 -v -f 240000000 -b 342857 -t a.out
    Searching serial ports for a P2
    P2 version A found on serial port /dev/ttyUSB0
    Setting load_mode to LOAD_CHIP
    Setting clock_mode to 12477f8
    Loading a.out - 2548 bytes
    a.out loaded
    Unsupported baudrate. Use cfsetispeed failed
    cfsetospeed failed
    ( Entering terminal mode.  Press Ctrl-] to exit. )
    ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
    
  • Dave Hein wrote: »
    I added this code to primos.c, and called init_stacks at the beginning of main, and check_stacks at the end of the big while loop. All of the cogs used 56 ints. So your stack needs to be at least 56 ints in size.
    void init_stacks(int num)
    {
        int i, j;
        for (i = 0; i < 7; i++)
        {
            for (j = 0; j < num; j++)
                stacks[i][j] = 0xdeadbeef;
        }
    }
    
    void check_stacks(int num)
    {
        int i, j;
        for (i = 0; i < 7; i++)
        {
            for (j = 0; j < num; j++)
            {
                if (stacks[i][j] != 0xdeadbeef) break;
            }
            printf("stack %d used %d ints\n", i, num - j);
        }
    }
    

    Clever! Thanks for that idea. I'll have to stash that away somewhere... maybe put it in PropWare's utilities :smile:
  • I thought the P2 was designed to run at 180Mhz. How come non of the code here is set use that?

    I see the compilers are set to run at 80Mhz which is what a P1 was set for.

    I don't get it.

    Mike

  • jmgjmg Posts: 14,811
    pmrobert wrote: »
    @jmg, I see what you were getting at after a little thought! Unfortunately, that doesn't fly either.[code]pmrobert@odin:~/p2gcc-master$ loadp2 -v -f 240000000 -b 342857 -t a.out
    Hmm, I forgot you were on Linux, that works fine on Windows. I can set and connect at 342857 ok.
    Seems like Linux needs to catch up there !


  • Part of the reason is for compatibility with the FPGA boards that run at 80MHz. Another reason for p2gcc is that the clock frequency affects the serial board baud rate, so it's just easier to run at 80MHz. Also, a lot of the waitcnt's in my test code are hardcoded for 80MHz. Once I clean all that up I'll probably change the default to a higher frequency, such as 180MHz.
  • jmgjmg Posts: 14,811
    iseries wrote: »
    I thought the P2 was designed to run at 180Mhz. How come non of the code here is set use that?

    I see the compilers are set to run at 80Mhz which is what a P1 was set for.

    I don't get it.

    Mike

    simple really... The P2 FPGA Development boards all ran 80MHz, FPGA existed long before P2 silicon.
    P2 Silicon can run at 80MHz, if someone chooses to. Or 100MHz, or 180MHz, or even 240MHz is looking maybe practical ...
  • So basically we have a P2 but were not allowed to put it in fourth gear for now. If we do get it into fourth gear we can't talk to it.

    Mike
  • iseries wrote: »
    So basically we have a P2 but were not allowed to put it in fourth gear for now. If we do get it into fourth gear we can't talk to it.

    Mike
    It's not really that constrained. However, the Linux environment at least is constrained in that you must use multiples of 80MHz with corresponding multiples of a 115200 Baud rate. 320MHz with a 460800 Baud rate has been working very well for the last several hours for me. We are still very, very early in the tool development stage so testing and feedback to the developers is very important. I wonder if Parallax ever scheduled a Tools Developer meeting?

    Mike R...
  • iseries wrote: »
    So basically we have a P2 but were not allowed to put it in fourth gear for now. If we do get it into fourth gear we can't talk to it.

    Mike

    No. Right now some tools might have trouble talking to it in some use cases, but there's nothing preventing you from manually setting the clock frequency and using your own serial routines (or modifying the p2gcc routines -- the source code is available, after all!) to send whatever baud rate you want.

    Not to mention that there are other tools than p2gcc, but that's a whole different topic :).
  • pmrobert wrote: »
    I wonder if Parallax ever scheduled a Tools Developer meeting?

    Nope.
    iseries wrote: »
    So basically we have a P2 but were not allowed to put it in fourth gear for now. If we do get it into fourth gear we can't talk to it.

    Mike

    You are not limited to 3rd gear - you can write code that changes clock speed and baud rates at runtime from within the P2. That's what I have begun t do with my own code by got sidetracked by writing (attempting to write) interrupt service routines. But I did do enough playing around with the serial funcitonality of the smartpins to prove that I could send 0xA5 over UART at 115,200 baud while the P2 chugged along at 180 MHz. But you then have to write your own printing function(s). All this will get fixed someday of course, but as pmrobert said a minute ago, we're VERY early in the tool development phase. Parallax have not even held their official meeting to kick off the crowd sourced tool development.
  • pmrobert wrote: »
    I wonder if Parallax ever scheduled a Tools Developer meeting?
    The last I heard Parallax was going to have an internal meeting at the end of this week. That will presumably be followed by the meeting without outside developers.

  • evanhevanh Posts: 11,609
    samuell wrote: »
    If the clock frequency is set to 80MHz by default, that means the P2 architecture is already much more efficient than the former. I saw a tenfold increase in terms of speed. That is insane!

    I'll have to try this at 240MHz. Is there any way to define the clock speed inside the code so that the baud rate stays correct. I'm using these two steps on terminal:

    Whoa! You're way off track trying to fiddle the loader clock frequency to speed up runtime clock frequency.

    All you do is add a few instructions to the start of your program to set the clock frequency you want to run at. Cluso posted a nicely descriptive piece of source that everyone can use, a bunch of settable constants with four instructions you just place at the start of each program - https://forums.parallax.com/discussion/comment/1452025/#Comment_1452025

  • evanhevanh Posts: 11,609
    Note that _XTALFREQ is set to 12 MHz. That'll be the P2D2 board. For the P2ES board, change that to 20 MHz.

    And unless there is a reason to be more exact in the clock frequency, I'll use a _XDIV of just 2 and _XMUL of whatever multiple of 10 MHz I want at the time.
  • evanh wrote: »
    samuell wrote: »
    If the clock frequency is set to 80MHz by default, that means the P2 architecture is already much more efficient than the former. I saw a tenfold increase in terms of speed. That is insane!

    I'll have to try this at 240MHz. Is there any way to define the clock speed inside the code so that the baud rate stays correct. I'm using these two steps on terminal:

    Whoa! You're way off track trying to fiddle the loader clock frequency to speed up runtime clock frequency.

    All you do is add a few instructions to the start of your program to set the clock frequency you want to run at. Cluso posted a nicely descriptive piece of source that everyone can use, a bunch of settable constants with four instructions you just place at the start of each program - https://forums.parallax.com/discussion/comment/1452025/#Comment_1452025

    And based on Cluso's Spin work (and the manual, of course) I created a C version in https://github.com/DavidZemon/HelloP2GCC:
    #define RCFAST_FREQ 22600000
    
    typedef enum {
        XI_IGNORED,
        XI_NO_LOADING_CAPS,
        XI_15PF,
        XI_30PF
    }                        xi_status_t;
    
    typedef enum {
        CLK_SRC_RC_FAST,
        CLK_SRC_RC_SLOW,
        CLK_SRC_XI,
        CLK_SRC_PLL
    }                        clock_source_t;
    
    typedef enum {
        NO_ERROR,
        INVALID_INPUT_DIVIDER,
        INVALID_VCO_MULTIPLIER,
        INVALID_FINAL_DIVIDER
    }                        error_t;
    
    error_t set_clock_mode (const bool enablePll, uint32_t inputDivider, uint32_t vcoMultiplier, uint32_t finalDivider,
                            const xi_status_t xiStatus, const clock_source_t clockSource);
    
    /**
     * @brief       Set the clock based on the external crystal with the PLL
     *
     * Resulting clock frequency will be XI * vcoMultiplier / (inputDivider * finalDivider)
     *
     * @param[in]   inputDivider
     * @param[in]   vcoMultiplier
     * @param[in]   finalDivider
     *
     * @return      0 upon success, error code otherwise
     */
    static inline error_t set_clock_pll (uint32_t inputDivider, uint32_t vcoMultiplier, uint32_t finalDivider) {
        return set_clock_mode(true, inputDivider, vcoMultiplier, finalDivider, XI_15PF, CLK_SRC_PLL);
    }
    
    static inline uint32_t compute_clock (const uint32_t xi, const uint32_t inputDivider,
                                          const uint32_t vcoMultiplier, const uint32_t finalDivider) {
        return xi * vcoMultiplier / inputDivider / finalDivider;
    }
    
    static inline void set_clock_rcfast () {
        set_clock_mode(false, 0, 0, 0, XI_IGNORED, CLK_SRC_RC_FAST);
    }
    
    static inline void set_clock_rcslow () {
        set_clock_mode(false, 0, 0, 0, XI_IGNORED, CLK_SRC_RC_SLOW);
    }
    
    static inline void set_clock_xi (const xi_status_t xiStatus) {
        set_clock_mode(false, 0, 0, 0, XI_IGNORED, CLK_SRC_XI);
    }
    error_t set_clock_mode (const bool enablePll, uint32_t inputDivider, uint32_t vcoMultiplier, uint32_t finalDivider,
                            const xi_status_t xiStatus, const clock_source_t clockSource) {
        __asm__ __volatile("hubset #0");
    
        uint32_t configuration = 0;
    
        if (enablePll) {
            configuration = 1 << 24;
        }
    
        if (64 >= inputDivider) {
            --inputDivider;
            inputDivider &= 0b11111;
            configuration |= inputDivider << 18;
        } else {
            return INVALID_INPUT_DIVIDER;
        }
    
        if (1024 >= vcoMultiplier) {
            --vcoMultiplier;
            vcoMultiplier &= 0b1111111111;
            configuration |= vcoMultiplier << 8;
        } else {
            return INVALID_VCO_MULTIPLIER;
        }
    
        if ((finalDivider % 2 && 1 != finalDivider) || 30 < finalDivider) {
            return INVALID_FINAL_DIVIDER;
        } else {
            finalDivider = (finalDivider >> 1) + 15;
            configuration |= (finalDivider & 0b1111) << 4;
        }
    
        configuration |= xiStatus << 2;
    
        // enable crystal+PLL, stay in 20MHz+ mode
        __asm__ __volatile("hubset %[_configuration]" : :[_configuration] "r"(configuration));
    
        // wait ~10ms for crystal+PLL to stabilize
        waitx(RCFAST_FREQ / 100);
    
        // now switch to PLL
        configuration |= clockSource;
        __asm__ __volatile("hubset %[_configuration]" : :[_configuration] "r"(configuration));
    
        return NO_ERROR;
    }
    

    You just paste that in your file and then use it like so:
    static const uint32_t XI             = 20000000;
    static const uint32_t INPUT_DIVIDER  = 1;
    static const uint32_t VCO_MULTIPLIER = 4;
    static const uint32_t FINAL_DIVIDER  = 1;
    uint32_t              CLOCK_FREQ;
    
    void main () {
        // Set the clock
        CLOCK_FREQ = compute_clock(XI, INPUT_DIVIDER, VCO_MULTIPLIER, FINAL_DIVIDER);
        const error_t err = set_clock_pll(INPUT_DIVIDER, VCO_MULTIPLIER, FINAL_DIVIDER);
    
        // Do other stuff...
    }
    

    Just know that, if you select any frequency other 80 MHz, the default print functions (like printf) will stop working because they have hardcoded waits expecting the 80 MHz clock. So, that's why I have the above code set to use 80 MHz still. But changing to 180 MHz is as simple as changing the constants at the top, recompiling, and reloading your program (just like the Spin versions... but it actually works in C).

    See the fully working example here: https://github.com/DavidZemon/HelloP2GCC/blob/master/blinky.c
  • David Z - would it be easily possible to edit the appropriate library code and rebuild the library functions for one's desired freq?
  • pmrobert wrote: »
    David Z - would it be easily possible to edit the appropriate library code and rebuild the library functions for one's desired freq?

    No need to rebuild the library code - just those three constants at the top of blinky.c need to be changed. common.c and common.h are meant to be exactly that: common to any app. Then you invoke set_clock_pll(INPUT_DIVIDER, VCO_MULTIPLIER, FINAL_DIVIDER) with the appropriate three values (presumably those values would be set as constants in your app) and you're done. The compute_clock() function exists as a way to verify that your math matches the P2's math ;), and I use the output of that function in all of my wait* calls throughout the rest of the app (which is why it's assigned to a global).
  • samuellsamuell Posts: 554
    edited 2019-01-23 02:03
    pmrobert wrote: »
    Dave, this is what I'm getting with the suggested arguments, just an FYI. I understand the garbage characters in the terminal but thought you'd like to know about the "Unsupported baudrate. Use cfsetispeed failed" message. Thanks for all you do!
    pmrobert@odin:~/p2gcc-master$ loadp2 -f 180000000 -b -1 -t a.out
    Unsupported baudrate. Use cfsetispeed failed
    cfsetospeed failed
    ( Entering terminal mode.  Press Ctrl-] to exit. )
    ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒pmrobert@odin:~/p2gcc-master$
    pmrobert@odin:~/p2gcc-master$
    
    I was getting that too.
    Dave Hein wrote: »
    Can you try 160MHz? That would produce a baud rate of 230400, which is a standard baud rate. You might also try 320MHz, which would produce a baud rate of 460800.

    At the higher clock frequencies I also get garbage characters on startup, but the program works normally after I press enter. It takes a fraction of a second for loadp2's terminal emulator to start up, and the program must be reading garbage characters at the beginning. I added a waitcnt(80000000+CNT); at the beginning of the main routine, and it fixes the problem.
    I'm already performing a test at 160MHz. Works fine!
    Dave Hein wrote: »
    samuell wrote: »
    Anyways, I now can go up to 160MHz, but no more than that. I've noticed that my program is unstable. It displays garbage numbers and rights itself after a few attempts, even at 80MHz. It was acting like that before the edit.
    samuell, what version of loadp2 are you using? You can see the version by typing loadp2 without any parameters. Older version of loadp2 did not configure the clock mode correctly above 200MHz. I believe I fixed that in version 0.008. The current version of loadp2 is 0.009.

    EDIT: I tried your new code, and it does not produce the correct numbers. The old code worked correctly.
    It is version 0.008. Date is 2018-1-11.
    Dave Hein wrote: »
    I did a diff of the new primos.c and the old one, and I found the problem. You declare the array stacks as "unsigned int stacks[7][44]". It appears that 44 is not large enough. In my old version I added a zero to make it stacks[7][440], and this works correctly. I'm sure that 440 ints is much more than needed, and some smaller value should work. I tried 100, and that works. 50 doesn't work. I would go with 100 to be safe.

    You could analyze your stack usage by prefilling it with a known value, and then checking the stacks after you run the program. I'll give it a try and let you know what I find.
    Strange, I don't recall changing the stack size, but probably since I've changed the algorithm many times, I might have done this too. The size of 44 ints for each stack is what it was used for the P8X32A. I never though that problem was due to a limited stack size. In the P8X32A, a too small stack size would usually break the program right away. Never happened to me having the program working with undefined behavior, but that explains it.

    To profile stack usage, I could modify the program to print the stacks at the end of each run. The issue is very repeatable if I try to test 10 or 100 numbers. It clears away if I test 10000 numbers. Anyway, unlike the old Propeller, the P2 doesn't have limited RAM, so 100 ints for the stack size would not be unreasonable, for an interim version.

    Kind regards, Samuel Lourenço
  • samuellsamuell Posts: 554
    edited 2019-01-23 02:38
    Only now I saw this!
    Dave Hein wrote: »
    I added this code to primos.c, and called init_stacks at the beginning of main, and check_stacks at the end of the big while loop. All of the cogs used 56 ints. So your stack needs to be at least 56 ints in size.
    void init_stacks(int num)
    {
        int i, j;
        for (i = 0; i < 7; i++)
        {
            for (j = 0; j < num; j++)
                stacks[i][j] = 0xdeadbeef;
        }
    }
    
    void check_stacks(int num)
    {
        int i, j;
        for (i = 0; i < 7; i++)
        {
            for (j = 0; j < num; j++)
            {
                if (stacks[i][j] != 0xdeadbeef) break;
            }
            printf("stack %d used %d ints\n", i, num - j);
        }
    }
    
    Nice! I guess it is safe to assume that the correct stack size would be 56 ints then. I didn't tested this, though. But I should see the effect right away.
    DavidZemon wrote: »
    evanh wrote: »
    samuell wrote: »
    If the clock frequency is set to 80MHz by default, that means the P2 architecture is already much more efficient than the former. I saw a tenfold increase in terms of speed. That is insane!

    I'll have to try this at 240MHz. Is there any way to define the clock speed inside the code so that the baud rate stays correct. I'm using these two steps on terminal:

    Whoa! You're way off track trying to fiddle the loader clock frequency to speed up runtime clock frequency.

    All you do is add a few instructions to the start of your program to set the clock frequency you want to run at. Cluso posted a nicely descriptive piece of source that everyone can use, a bunch of settable constants with four instructions you just place at the start of each program - https://forums.parallax.com/discussion/comment/1452025/#Comment_1452025

    And based on Cluso's Spin work (and the manual, of course) I created a C version in https://github.com/DavidZemon/HelloP2GCC:
    #define RCFAST_FREQ 22600000
    
    typedef enum {
        XI_IGNORED,
        XI_NO_LOADING_CAPS,
        XI_15PF,
        XI_30PF
    }                        xi_status_t;
    
    typedef enum {
        CLK_SRC_RC_FAST,
        CLK_SRC_RC_SLOW,
        CLK_SRC_XI,
        CLK_SRC_PLL
    }                        clock_source_t;
    
    typedef enum {
        NO_ERROR,
        INVALID_INPUT_DIVIDER,
        INVALID_VCO_MULTIPLIER,
        INVALID_FINAL_DIVIDER
    }                        error_t;
    
    error_t set_clock_mode (const bool enablePll, uint32_t inputDivider, uint32_t vcoMultiplier, uint32_t finalDivider,
                            const xi_status_t xiStatus, const clock_source_t clockSource);
    
    /**
     * @brief       Set the clock based on the external crystal with the PLL
     *
     * Resulting clock frequency will be XI * vcoMultiplier / (inputDivider * finalDivider)
     *
     * @param[in]   inputDivider
     * @param[in]   vcoMultiplier
     * @param[in]   finalDivider
     *
     * @return      0 upon success, error code otherwise
     */
    static inline error_t set_clock_pll (uint32_t inputDivider, uint32_t vcoMultiplier, uint32_t finalDivider) {
        return set_clock_mode(true, inputDivider, vcoMultiplier, finalDivider, XI_15PF, CLK_SRC_PLL);
    }
    
    static inline uint32_t compute_clock (const uint32_t xi, const uint32_t inputDivider,
                                          const uint32_t vcoMultiplier, const uint32_t finalDivider) {
        return xi * vcoMultiplier / inputDivider / finalDivider;
    }
    
    static inline void set_clock_rcfast () {
        set_clock_mode(false, 0, 0, 0, XI_IGNORED, CLK_SRC_RC_FAST);
    }
    
    static inline void set_clock_rcslow () {
        set_clock_mode(false, 0, 0, 0, XI_IGNORED, CLK_SRC_RC_SLOW);
    }
    
    static inline void set_clock_xi (const xi_status_t xiStatus) {
        set_clock_mode(false, 0, 0, 0, XI_IGNORED, CLK_SRC_XI);
    }
    error_t set_clock_mode (const bool enablePll, uint32_t inputDivider, uint32_t vcoMultiplier, uint32_t finalDivider,
                            const xi_status_t xiStatus, const clock_source_t clockSource) {
        __asm__ __volatile("hubset #0");
    
        uint32_t configuration = 0;
    
        if (enablePll) {
            configuration = 1 << 24;
        }
    
        if (64 >= inputDivider) {
            --inputDivider;
            inputDivider &= 0b11111;
            configuration |= inputDivider << 18;
        } else {
            return INVALID_INPUT_DIVIDER;
        }
    
        if (1024 >= vcoMultiplier) {
            --vcoMultiplier;
            vcoMultiplier &= 0b1111111111;
            configuration |= vcoMultiplier << 8;
        } else {
            return INVALID_VCO_MULTIPLIER;
        }
    
        if ((finalDivider % 2 && 1 != finalDivider) || 30 < finalDivider) {
            return INVALID_FINAL_DIVIDER;
        } else {
            finalDivider = (finalDivider >> 1) + 15;
            configuration |= (finalDivider & 0b1111) << 4;
        }
    
        configuration |= xiStatus << 2;
    
        // enable crystal+PLL, stay in 20MHz+ mode
        __asm__ __volatile("hubset %[_configuration]" : :[_configuration] "r"(configuration));
    
        // wait ~10ms for crystal+PLL to stabilize
        waitx(RCFAST_FREQ / 100);
    
        // now switch to PLL
        configuration |= clockSource;
        __asm__ __volatile("hubset %[_configuration]" : :[_configuration] "r"(configuration));
    
        return NO_ERROR;
    }
    

    You just paste that in your file and then use it like so:
    static const uint32_t XI             = 20000000;
    static const uint32_t INPUT_DIVIDER  = 1;
    static const uint32_t VCO_MULTIPLIER = 4;
    static const uint32_t FINAL_DIVIDER  = 1;
    uint32_t              CLOCK_FREQ;
    
    void main () {
        // Set the clock
        CLOCK_FREQ = compute_clock(XI, INPUT_DIVIDER, VCO_MULTIPLIER, FINAL_DIVIDER);
        const error_t err = set_clock_pll(INPUT_DIVIDER, VCO_MULTIPLIER, FINAL_DIVIDER);
    
        // Do other stuff...
    }
    

    Just know that, if you select any frequency other 80 MHz, the default print functions (like printf) will stop working because they have hardcoded waits expecting the 80 MHz clock. So, that's why I have the above code set to use 80 MHz still. But changing to 180 MHz is as simple as changing the constants at the top, recompiling, and reloading your program (just like the Spin versions... but it actually works in C).

    See the fully working example here: https://github.com/DavidZemon/HelloP2GCC/blob/master/blinky.c
    Couldn't this be implemented inside "propeller.h"? It it is common to all P2 programs, it only makes sense to implement the clock related functions there. The main program would have the variable definitions and the function calls to calculate the clock and set the PLL. IMHO, I see no need to have a "common.c" and "common.h" for functions that could be inside "propeller.h" and the respective c/lib.

    P.S.: I think that printf() needs some heavy modification, either to support long long ints and float variables, and also to support diverse clock settings. I'm aware that this a tall order. But since the P2 has lots of RAM to spare, there is no need to use a simplified version of printf().

    Kind regards, Samuel Lourenço
  • David BetzDavid Betz Posts: 14,385
    edited 2019-01-23 02:46
    Does someone have a cheat sheet showing how to get a program that writes to the console serial port working on the Mac? I've been trying to use Eric's fastspin to compile the code but I don't see any output when I load it with loadp2. Does loadp2 give some indication of whether the load worked? Would I get an error if it failed like I do on the P1? I tried this command:
    loadp2 -p /dev/tty.usbserial-P2EEQXU -b 115200 -l 115200 test.binary -t
    
  • samuell wrote: »
    Only now I saw this!
    Dave Hein wrote: »
    I added this code to primos.c, and called init_stacks at the beginning of main, and check_stacks at the end of the big while loop. All of the cogs used 56 ints. So your stack needs to be at least 56 ints in size.
    void init_stacks(int num)
    {
        int i, j;
        for (i = 0; i < 7; i++)
        {
            for (j = 0; j < num; j++)
                stacks[i][j] = 0xdeadbeef;
        }
    }
    
    void check_stacks(int num)
    {
        int i, j;
        for (i = 0; i < 7; i++)
        {
            for (j = 0; j < num; j++)
            {
                if (stacks[i][j] != 0xdeadbeef) break;
            }
            printf("stack %d used %d ints\n", i, num - j);
        }
    }
    
    Nice! I guess it is safe to assume that the correct stack size would be 56 ints then. I didn't tested this, though. But I should see the effect right away.
    DavidZemon wrote: »
    evanh wrote: »
    samuell wrote: »
    If the clock frequency is set to 80MHz by default, that means the P2 architecture is already much more efficient than the former. I saw a tenfold increase in terms of speed. That is insane!

    I'll have to try this at 240MHz. Is there any way to define the clock speed inside the code so that the baud rate stays correct. I'm using these two steps on terminal:

    Whoa! You're way off track trying to fiddle the loader clock frequency to speed up runtime clock frequency.

    All you do is add a few instructions to the start of your program to set the clock frequency you want to run at. Cluso posted a nicely descriptive piece of source that everyone can use, a bunch of settable constants with four instructions you just place at the start of each program - https://forums.parallax.com/discussion/comment/1452025/#Comment_1452025

    And based on Cluso's Spin work (and the manual, of course) I created a C version in https://github.com/DavidZemon/HelloP2GCC:
    #define RCFAST_FREQ 22600000
    
    typedef enum {
        XI_IGNORED,
        XI_NO_LOADING_CAPS,
        XI_15PF,
        XI_30PF
    }                        xi_status_t;
    
    typedef enum {
        CLK_SRC_RC_FAST,
        CLK_SRC_RC_SLOW,
        CLK_SRC_XI,
        CLK_SRC_PLL
    }                        clock_source_t;
    
    typedef enum {
        NO_ERROR,
        INVALID_INPUT_DIVIDER,
        INVALID_VCO_MULTIPLIER,
        INVALID_FINAL_DIVIDER
    }                        error_t;
    
    error_t set_clock_mode (const bool enablePll, uint32_t inputDivider, uint32_t vcoMultiplier, uint32_t finalDivider,
                            const xi_status_t xiStatus, const clock_source_t clockSource);
    
    /**
     * @brief       Set the clock based on the external crystal with the PLL
     *
     * Resulting clock frequency will be XI * vcoMultiplier / (inputDivider * finalDivider)
     *
     * @param[in]   inputDivider
     * @param[in]   vcoMultiplier
     * @param[in]   finalDivider
     *
     * @return      0 upon success, error code otherwise
     */
    static inline error_t set_clock_pll (uint32_t inputDivider, uint32_t vcoMultiplier, uint32_t finalDivider) {
        return set_clock_mode(true, inputDivider, vcoMultiplier, finalDivider, XI_15PF, CLK_SRC_PLL);
    }
    
    static inline uint32_t compute_clock (const uint32_t xi, const uint32_t inputDivider,
                                          const uint32_t vcoMultiplier, const uint32_t finalDivider) {
        return xi * vcoMultiplier / inputDivider / finalDivider;
    }
    
    static inline void set_clock_rcfast () {
        set_clock_mode(false, 0, 0, 0, XI_IGNORED, CLK_SRC_RC_FAST);
    }
    
    static inline void set_clock_rcslow () {
        set_clock_mode(false, 0, 0, 0, XI_IGNORED, CLK_SRC_RC_SLOW);
    }
    
    static inline void set_clock_xi (const xi_status_t xiStatus) {
        set_clock_mode(false, 0, 0, 0, XI_IGNORED, CLK_SRC_XI);
    }
    error_t set_clock_mode (const bool enablePll, uint32_t inputDivider, uint32_t vcoMultiplier, uint32_t finalDivider,
                            const xi_status_t xiStatus, const clock_source_t clockSource) {
        __asm__ __volatile("hubset #0");
    
        uint32_t configuration = 0;
    
        if (enablePll) {
            configuration = 1 << 24;
        }
    
        if (64 >= inputDivider) {
            --inputDivider;
            inputDivider &= 0b11111;
            configuration |= inputDivider << 18;
        } else {
            return INVALID_INPUT_DIVIDER;
        }
    
        if (1024 >= vcoMultiplier) {
            --vcoMultiplier;
            vcoMultiplier &= 0b1111111111;
            configuration |= vcoMultiplier << 8;
        } else {
            return INVALID_VCO_MULTIPLIER;
        }
    
        if ((finalDivider % 2 && 1 != finalDivider) || 30 < finalDivider) {
            return INVALID_FINAL_DIVIDER;
        } else {
            finalDivider = (finalDivider >> 1) + 15;
            configuration |= (finalDivider & 0b1111) << 4;
        }
    
        configuration |= xiStatus << 2;
    
        // enable crystal+PLL, stay in 20MHz+ mode
        __asm__ __volatile("hubset %[_configuration]" : :[_configuration] "r"(configuration));
    
        // wait ~10ms for crystal+PLL to stabilize
        waitx(RCFAST_FREQ / 100);
    
        // now switch to PLL
        configuration |= clockSource;
        __asm__ __volatile("hubset %[_configuration]" : :[_configuration] "r"(configuration));
    
        return NO_ERROR;
    }
    

    You just paste that in your file and then use it like so:
    static const uint32_t XI             = 20000000;
    static const uint32_t INPUT_DIVIDER  = 1;
    static const uint32_t VCO_MULTIPLIER = 4;
    static const uint32_t FINAL_DIVIDER  = 1;
    uint32_t              CLOCK_FREQ;
    
    void main () {
        // Set the clock
        CLOCK_FREQ = compute_clock(XI, INPUT_DIVIDER, VCO_MULTIPLIER, FINAL_DIVIDER);
        const error_t err = set_clock_pll(INPUT_DIVIDER, VCO_MULTIPLIER, FINAL_DIVIDER);
    
        // Do other stuff...
    }
    

    Just know that, if you select any frequency other 80 MHz, the default print functions (like printf) will stop working because they have hardcoded waits expecting the 80 MHz clock. So, that's why I have the above code set to use 80 MHz still. But changing to 180 MHz is as simple as changing the constants at the top, recompiling, and reloading your program (just like the Spin versions... but it actually works in C).

    See the fully working example here: https://github.com/DavidZemon/HelloP2GCC/blob/master/blinky.c
    Couldn't this be implemented inside "propeller.h"? It it is common to all P2 programs, it only makes sense to implement the clock related functions there. The main program would have the variable definitions and the function calls to calculate the clock and set the PLL. IMHO, I see no need to have a "common.c" and "common.h" for functions that could be inside "propeller.h" and the respective c/lib.

    P.S.: I think that printf() needs some heavy modification, either to support long long ints and float variables, and also to support diverse clock settings. I'm aware that this a tall order. But since the P2 has lots of RAM to spare, there is no need to use a simplified version of printf().

    Kind regards, Samuel Lourenço

    You're absolutely right on both accounts - the compiler package (which is what you really meant by "propeller.h" I'm sure :smile: ) should really include some equivalent of my "common.c/common.h" files and printf should be updated to include support for more data types. However - p2gcc is currently a (very cool) wrapper around PropGCC for the P8X32A, not the P2X8C4M64P. Work has not yet begun on a C/C++ compiler for the P2X8C4M64P. p2gcc actually takes assembly output from PropGCC and translates the necessary instructions from P1 opcodes to P2 opcodes and then assembles that into a binary for us (sorry if I missed a step or two, Dave... hopefully I came close). I think (hope) the goal is that all of the customization work that is going into p2gcc (like Dave's standard library implementations, maybe some of my common.* contents) will end up being used in the next iteration of PropGCC for the P2. Until then... life will just be difficult.

    But you have to remember, Parallax's primary goal (as far as I know...) in sending out these engineering sample P2 boards was to encourage tool developers to begin their work. They were not selling these chips in order for application developers to start developing applications because they know critical pieces are still missing.
  • David Betz wrote: »
    Does someone have a cheat sheet showing how to get a program that writes to the console serial port working on the Mac? I've been trying to use Eric's fastspin to compile the code but I don't see any output when I load it with loadp2. Does loadp2 give some indication of whether the load worked? Would I get an error if it failed like I do on the P1? I tried this command:
    loadp2 -p /dev/tty.usbserial-P2EEQXU -b 115200 -l 115200 test.binary -t
    

    Have you tried the commands used in my makefile? Maybe that will work for you? https://github.com/DavidZemon/HelloP2GCC/blob/master/Makefile
  • DavidZemon wrote: »
    David Betz wrote: »
    Does someone have a cheat sheet showing how to get a program that writes to the console serial port working on the Mac? I've been trying to use Eric's fastspin to compile the code but I don't see any output when I load it with loadp2. Does loadp2 give some indication of whether the load worked? Would I get an error if it failed like I do on the P1? I tried this command:
    loadp2 -p /dev/tty.usbserial-P2EEQXU -b 115200 -l 115200 test.binary -t
    

    Have you tried the commands used in my makefile? Maybe that will work for you? https://github.com/DavidZemon/HelloP2GCC/blob/master/Makefile
    Do you mean I should just add the "-m 010c1f08" parameter to the loadp2 command? That didn't seem to help. Maybe this is because I'm using fastspin to compile my code instead of p2gcc?
  • David Betz wrote: »
    DavidZemon wrote: »
    David Betz wrote: »
    Does someone have a cheat sheet showing how to get a program that writes to the console serial port working on the Mac? I've been trying to use Eric's fastspin to compile the code but I don't see any output when I load it with loadp2. Does loadp2 give some indication of whether the load worked? Would I get an error if it failed like I do on the P1? I tried this command:
    loadp2 -p /dev/tty.usbserial-P2EEQXU -b 115200 -l 115200 test.binary -t
    

    Have you tried the commands used in my makefile? Maybe that will work for you? https://github.com/DavidZemon/HelloP2GCC/blob/master/Makefile
    Do you mean I should just add the "-m 010c1f08" parameter to the loadp2 command? That didn't seem to help. Maybe this is because I'm using fastspin to compile my code instead of p2gcc?

    Oh I have no idea what changes might make it work or not. I just know that that command has worked quite reliably for me on Linux, based on Dave's suggestion many forum pages ago and it might work for you too. I do know it's starting the chip up assuming a 20 MHz external crystal and running at 80 MHz and using a baudrate of 115200. And I'm pretty sure it's using the 2-stage loader because loads are darn near instant.
  • DavidZemon wrote: »
    David Betz wrote: »
    DavidZemon wrote: »
    David Betz wrote: »
    Does someone have a cheat sheet showing how to get a program that writes to the console serial port working on the Mac? I've been trying to use Eric's fastspin to compile the code but I don't see any output when I load it with loadp2. Does loadp2 give some indication of whether the load worked? Would I get an error if it failed like I do on the P1? I tried this command:
    loadp2 -p /dev/tty.usbserial-P2EEQXU -b 115200 -l 115200 test.binary -t
    

    Have you tried the commands used in my makefile? Maybe that will work for you? https://github.com/DavidZemon/HelloP2GCC/blob/master/Makefile
    Do you mean I should just add the "-m 010c1f08" parameter to the loadp2 command? That didn't seem to help. Maybe this is because I'm using fastspin to compile my code instead of p2gcc?

    Oh I have no idea what changes might make it work or not. I just know that that command has worked quite reliably for me on Linux, based on Dave's suggestion many forum pages ago and it might work for you too. I do know it's starting the chip up assuming a 20 MHz external crystal and running at 80 MHz and using a baudrate of 115200. And I'm pretty sure it's using the 2-stage loader because loads are darn near instant.
    I see the message "Loading test.binary - 3264 bytes" but then nothing else. This is with the -v option to loadp2. How can I tell if the load succeeded or failed?
  • I'd try doing an LED blinking program (or even one that just lights up an LED) first. It's also worth trying the -SINGLE flag to loadp2 to use the single stage loader, which is simpler than the multi-stage one. The main drawback of -SINGLE is that you have to do the clock setup yourself in your main program, but that's not too big of a deal.

    There were definitely some hoops we had to jump through to get loadp2 working on Linux (the Linux kernel insists on manipulating the DTR pin when the baud is changed, which can lead to the P2 being reset immediately after the program is loaded). I wouldn't be surprised if there's some similar but slightly different issue on the Mac.
  • samuellsamuell Posts: 554
    edited 2019-01-23 03:21
    DavidZemon wrote: »
    samuell wrote: »
    Only now I saw this!
    Dave Hein wrote: »
    I added this code to primos.c, and called init_stacks at the beginning of main, and check_stacks at the end of the big while loop. All of the cogs used 56 ints. So your stack needs to be at least 56 ints in size.
    void init_stacks(int num)
    {
        int i, j;
        for (i = 0; i < 7; i++)
        {
            for (j = 0; j < num; j++)
                stacks[i][j] = 0xdeadbeef;
        }
    }
    
    void check_stacks(int num)
    {
        int i, j;
        for (i = 0; i < 7; i++)
        {
            for (j = 0; j < num; j++)
            {
                if (stacks[i][j] != 0xdeadbeef) break;
            }
            printf("stack %d used %d ints\n", i, num - j);
        }
    }
    
    Nice! I guess it is safe to assume that the correct stack size would be 56 ints then. I didn't tested this, though. But I should see the effect right away.
    DavidZemon wrote: »
    evanh wrote: »
    samuell wrote: »
    If the clock frequency is set to 80MHz by default, that means the P2 architecture is already much more efficient than the former. I saw a tenfold increase in terms of speed. That is insane!

    I'll have to try this at 240MHz. Is there any way to define the clock speed inside the code so that the baud rate stays correct. I'm using these two steps on terminal:

    Whoa! You're way off track trying to fiddle the loader clock frequency to speed up runtime clock frequency.

    All you do is add a few instructions to the start of your program to set the clock frequency you want to run at. Cluso posted a nicely descriptive piece of source that everyone can use, a bunch of settable constants with four instructions you just place at the start of each program - https://forums.parallax.com/discussion/comment/1452025/#Comment_1452025

    And based on Cluso's Spin work (and the manual, of course) I created a C version in https://github.com/DavidZemon/HelloP2GCC:
    #define RCFAST_FREQ 22600000
    
    typedef enum {
        XI_IGNORED,
        XI_NO_LOADING_CAPS,
        XI_15PF,
        XI_30PF
    }                        xi_status_t;
    
    typedef enum {
        CLK_SRC_RC_FAST,
        CLK_SRC_RC_SLOW,
        CLK_SRC_XI,
        CLK_SRC_PLL
    }                        clock_source_t;
    
    typedef enum {
        NO_ERROR,
        INVALID_INPUT_DIVIDER,
        INVALID_VCO_MULTIPLIER,
        INVALID_FINAL_DIVIDER
    }                        error_t;
    
    error_t set_clock_mode (const bool enablePll, uint32_t inputDivider, uint32_t vcoMultiplier, uint32_t finalDivider,
                            const xi_status_t xiStatus, const clock_source_t clockSource);
    
    /**
     * @brief       Set the clock based on the external crystal with the PLL
     *
     * Resulting clock frequency will be XI * vcoMultiplier / (inputDivider * finalDivider)
     *
     * @param[in]   inputDivider
     * @param[in]   vcoMultiplier
     * @param[in]   finalDivider
     *
     * @return      0 upon success, error code otherwise
     */
    static inline error_t set_clock_pll (uint32_t inputDivider, uint32_t vcoMultiplier, uint32_t finalDivider) {
        return set_clock_mode(true, inputDivider, vcoMultiplier, finalDivider, XI_15PF, CLK_SRC_PLL);
    }
    
    static inline uint32_t compute_clock (const uint32_t xi, const uint32_t inputDivider,
                                          const uint32_t vcoMultiplier, const uint32_t finalDivider) {
        return xi * vcoMultiplier / inputDivider / finalDivider;
    }
    
    static inline void set_clock_rcfast () {
        set_clock_mode(false, 0, 0, 0, XI_IGNORED, CLK_SRC_RC_FAST);
    }
    
    static inline void set_clock_rcslow () {
        set_clock_mode(false, 0, 0, 0, XI_IGNORED, CLK_SRC_RC_SLOW);
    }
    
    static inline void set_clock_xi (const xi_status_t xiStatus) {
        set_clock_mode(false, 0, 0, 0, XI_IGNORED, CLK_SRC_XI);
    }
    error_t set_clock_mode (const bool enablePll, uint32_t inputDivider, uint32_t vcoMultiplier, uint32_t finalDivider,
                            const xi_status_t xiStatus, const clock_source_t clockSource) {
        __asm__ __volatile("hubset #0");
    
        uint32_t configuration = 0;
    
        if (enablePll) {
            configuration = 1 << 24;
        }
    
        if (64 >= inputDivider) {
            --inputDivider;
            inputDivider &= 0b11111;
            configuration |= inputDivider << 18;
        } else {
            return INVALID_INPUT_DIVIDER;
        }
    
        if (1024 >= vcoMultiplier) {
            --vcoMultiplier;
            vcoMultiplier &= 0b1111111111;
            configuration |= vcoMultiplier << 8;
        } else {
            return INVALID_VCO_MULTIPLIER;
        }
    
        if ((finalDivider % 2 && 1 != finalDivider) || 30 < finalDivider) {
            return INVALID_FINAL_DIVIDER;
        } else {
            finalDivider = (finalDivider >> 1) + 15;
            configuration |= (finalDivider & 0b1111) << 4;
        }
    
        configuration |= xiStatus << 2;
    
        // enable crystal+PLL, stay in 20MHz+ mode
        __asm__ __volatile("hubset %[_configuration]" : :[_configuration] "r"(configuration));
    
        // wait ~10ms for crystal+PLL to stabilize
        waitx(RCFAST_FREQ / 100);
    
        // now switch to PLL
        configuration |= clockSource;
        __asm__ __volatile("hubset %[_configuration]" : :[_configuration] "r"(configuration));
    
        return NO_ERROR;
    }
    

    You just paste that in your file and then use it like so:
    static const uint32_t XI             = 20000000;
    static const uint32_t INPUT_DIVIDER  = 1;
    static const uint32_t VCO_MULTIPLIER = 4;
    static const uint32_t FINAL_DIVIDER  = 1;
    uint32_t              CLOCK_FREQ;
    
    void main () {
        // Set the clock
        CLOCK_FREQ = compute_clock(XI, INPUT_DIVIDER, VCO_MULTIPLIER, FINAL_DIVIDER);
        const error_t err = set_clock_pll(INPUT_DIVIDER, VCO_MULTIPLIER, FINAL_DIVIDER);
    
        // Do other stuff...
    }
    

    Just know that, if you select any frequency other 80 MHz, the default print functions (like printf) will stop working because they have hardcoded waits expecting the 80 MHz clock. So, that's why I have the above code set to use 80 MHz still. But changing to 180 MHz is as simple as changing the constants at the top, recompiling, and reloading your program (just like the Spin versions... but it actually works in C).

    See the fully working example here: https://github.com/DavidZemon/HelloP2GCC/blob/master/blinky.c
    Couldn't this be implemented inside "propeller.h"? It it is common to all P2 programs, it only makes sense to implement the clock related functions there. The main program would have the variable definitions and the function calls to calculate the clock and set the PLL. IMHO, I see no need to have a "common.c" and "common.h" for functions that could be inside "propeller.h" and the respective c/lib.

    P.S.: I think that printf() needs some heavy modification, either to support long long ints and float variables, and also to support diverse clock settings. I'm aware that this a tall order. But since the P2 has lots of RAM to spare, there is no need to use a simplified version of printf().

    Kind regards, Samuel Lourenço

    You're absolutely right on both accounts - the compiler package (which is what you really meant by "propeller.h" I'm sure :smile: ) should really include some equivalent of my "common.c/common.h" files and printf should be updated to include support for more data types. However - p2gcc is currently a (very cool) wrapper around PropGCC for the P8X32A, not the P2X8C4M64P. Work has not yet begun on a C/C++ compiler for the P2X8C4M64P. p2gcc actually takes assembly output from PropGCC and translates the necessary instructions from P1 opcodes to P2 opcodes and then assembles that into a binary for us (sorry if I missed a step or two, Dave... hopefully I came close). I think (hope) the goal is that all of the customization work that is going into p2gcc (like Dave's standard library implementations, maybe some of my common.* contents) will end up being used in the next iteration of PropGCC for the P2. Until then... life will just be difficult.

    But you have to remember, Parallax's primary goal (as far as I know...) in sending out these engineering sample P2 boards was to encourage tool developers to begin their work. They were not selling these chips in order for application developers to start developing applications because they know critical pieces are still missing.
    Well, I had the impression that PropGCC, as used in SimpleIDE, had two flavors of printf(). To my knowledge, Dave is using the simplified version, if I recall correctly. As for the mechanics, I didn't know it was a wrapper.

    Regarding your last statement, it makes sense that tools need to be developed first. I'm not developing final software either, but I want to explore the possibilities. One of them was experimenting with the prime number program, which is practically done, despite the crudity of the code and the need for some fixing. Other possibility is testing and doing things using smart pins.

    I acknowledge that I'm not a person that has the capacity to develop a compiler for the P2, although I certainly can create a GUI in Qt that runs commands in the background. Already did that, when I developed several commands to control a CP2130 chip (for a function generator, for a power supply...) and the GUI that goes with them. But developing a compiler requires a steep learning curve.

    Kind regards, Samuel Lourenço
  • DavidZemon wrote: »
    You're absolutely right on both accounts - the compiler package (which is what you really meant by "propeller.h" I'm sure :smile: ) should really include some equivalent of my "common.c/common.h" files and printf should be updated to include support for more data types. However - p2gcc is currently a (very cool) wrapper around PropGCC for the P8X32A, not the P2X8C4M64P. Work has not yet begun on a C/C++ compiler for the P2X8C4M64P.

    A small correction: work has not yet begun on a *GCC* port for the Propeller 2. There is a C compiler work in progress (inside fastspin). It's not quite up to p2gcc's level of utility yet, but it does have a "native" P2 code generator.
    But you have to remember, Parallax's primary goal (as far as I know...) in sending out these engineering sample P2 boards was to encourage tool developers to begin their work. They were not selling these chips in order for application developers to start developing applications because they know critical pieces are still missing.

    That's worth repeating. The P2 boards are "Engineering Samples", not finished products, and the tools are very much under development.
  • evanhevanh Posts: 11,609
    DavidZemon wrote: »
    Just know that, if you select any frequency other 80 MHz, the default print functions (like printf) will stop working because they have hardcoded waits expecting the 80 MHz clock. So, that's why I have the above code set to use 80 MHz still. But changing to 180 MHz is as simple as changing the constants at the top, recompiling, and reloading your program (just like the Spin versions... but it actually works in C).

    See the fully working example here: https://github.com/DavidZemon/HelloP2GCC/blob/master/blinky.c

    Doh! I keep forgetting about C even though this is the C topic.

Sign In or Register to comment.