Shop OBEX P1 Docs P2 Docs Learn Events
My first PropGCC attempt, a CW keyer — Parallax Forums

My first PropGCC attempt, a CW keyer

pinedustpinedust Posts: 19
edited 2012-03-25 18:56 in Propeller 1
I used SimpleIDE on a Ubuntu 10.04 64 bit system along with my Gadget Gangster USB.

It works great, and what better solution for my home brew iambic key?

I am very impressed with the work and progress on both the compiler and SimpleIDE. I look forward to updates and enhancements as both continue to mature, but they are very usable now.

Mostly I wanted to try out the IDE itself, cog threads and synchronization with locks, but this little project let try out quite a few things. I am a little fuzzy on coming up with the stack size though.

Any comments are appreciated.

Jim, W

Comments

  • jazzedjazzed Posts: 11,803
    edited 2012-03-23 21:27
    It's good to hear a report from a 64 bit Ubuntu10.04 user. Thanks for posting.

    Nice code!

    For COG threads stack size 16 is required to save call contexts (R0-R14 & SP).
    You probably need to multiply that size by the number of function levels called by the COG thread.

    I'll be posting updated packages next week.

    Thanks,
    --Steve
  • denominatordenominator Posts: 242
    edited 2012-03-23 21:54
    Jim,

    In an embedded system making sure you've properly planned memory is always one of the biggest challenges.

    I don't know if there are any more established mechanisms to do this, but I've always done something like the following. Note that I just included relevant snippets from your program; to test this yourself, you have to integrate it back into your program:
    #define STACK_SIZE      256
    
    static int guard1 = 0xDEADBEEF;
    static int cog_stack[STACK_SIZE][2];
    static int guard2 = 0xDEADBEEF;
    static _thread_state_t thread_data[2];
    
    _atomic_t lock;
    
    /**
     * Main program function.
     */
    int main(void)
    {
        int    cog_id_dit;
        int    cog_id_dah;
    
        memset(cog_stack, 0xA5, sizeof(cog_stack));
        cog_id_dit = _start_cog_thread(cog_stack[DIT]+STACK_SIZE, cog_func_dit, (void*)0, &thread_data[DIT]);
        cog_id_dah = _start_cog_thread(cog_stack[DAH]+STACK_SIZE, cog_func_dah, (void*)0, &thread_data[DAH]);
    
        waitcnt(CNT + CLKFREQ * 10);
    
        int i;
        for (i = 0;  i < 2;  i++)
        {
            int j;
            for (j = 0;  j < STACK_SIZE; j++)
                if (cog_stack[i][j] != 0xA5A5A5A5)
                    break;
            printf("Stack %d used %d longs\n", i, STACK_SIZE - j);
        }
        if (guard1 != 0xDEADBEEF)
            printf("Guard 1 was whacked\n");
        if (guard2 != 0xDEADBEEF)
            printf("Guard 2 was whacked\n");
    
        return 0;
    }
    

    Things to note:

    - For testing, use a much bigger stack size than you think you need.
    - Fill the stack with a known pattern.
    - Run your program, exercising the stack to what you believe is its maximum (your program just does one thing, so we just wait 10 seconds).
    - Scan the stack looking for entries that changed from the known pattern (this scheme can be off an entry or two if your program uses the known pattern in its local variables)
    - I always put a guard before and after the stack in case I passed the stack end address incorrectly.

    In your case, the answers came up like this:
    Propeller Version 1 on COM3
    Writing 18592 bytes to Propeller RAM.
    18592 bytes sent
    Verifying ... Download OK!
    [ Entering terminal mode. Type ESC or Control-C to exit. ]
    Stack 0 used 3 longs
    Stack 1 used 5 longs
    
  • pinedustpinedust Posts: 19
    edited 2012-03-24 20:03
    Thanks for the comments and the code, pretty simple and straight forward, I should have thought of something like that myself.

    I played with it today, all kinds of various values, funny thing, I could never get it to fail. I even set the stack size to 0 and everything worked,
    Stack 0 used 0 longs
    Stack 1 used 0 longs
    

    The program acted as it should and I was still able to produce recognizable morse, I have no idea what was going on internally though, I will probably see things happen as I add more. I wish everything was like this... failing at making software fail.

    I will continue experimenting and learn what I can, that is the fun in this, right?

    DEADBEEF, I haven't seen that in a while, :smile:

    Oh, what do I need to do to make a printf work from within a cog thread? I tried inside and outside of locks but never got it to work. The only thing I was able to do was set a variable and print it from the calling, or original cog. It works, but was just wondering.
  • denominatordenominator Posts: 242
    edited 2012-03-25 07:02
    pinedust wrote: »
    I even set the stack size to 0 and everything worked.

    If your stack is too small, the program is still using the stack; it's just overwriting other memory. It's surprising how often programs that smash memory seem to work properly - sometimes I've found memory problems that have been in production for years with no (seemingly) ill effect. However, if you program is stack-bashing, then your program will tend to be unstable, and any "strange" and "unexplainable" bug is most likely the fact that your stack is improperly sized.
    pinedust wrote: »
    Oh, what do I need to do to make a printf work from within a cog thread? I tried inside and outside of locks but never got it to work. The only thing I was able to do was set a variable and print it from the calling, or original cog. It works, but was just wondering.

    Could you post your code that tries to printf within the thread so we can see what you're trying to do?
  • pinedustpinedust Posts: 19
    edited 2012-03-25 15:44
    Here is a very simple example.

    There is an LED on P20 that lights when it should, when P16 goes low (no longer than 1/4 second), but I never see the message, "Hello".

    I added a loop in main().

    In the main() loop, the led goes on and off as expected and the count is printed out. When I drop P16 to low, not only do I not see the output "hello", the loop quits displaying the output from the count printf. The two LEDs continue to operate normally.

    if I comment out the printf("hello\n"); statement, the main() loop continues to output the count regardless.

    I hope I am making sense.

    I am using LMM and not Simple printf.
    #include <stdio.h>
    #include <propeller.h>
    #include <sys/thread.h>
      
    #include "../utils/include/bit_macros.h"
    
    #define STACK_SIZE 16
    
    static int cog_stack[STACK_SIZE];
    
    static _thread_state_t thread_data;
    
    void cog_func_one(void *arg)
    {
        BIT_SET(DIRA, 20);
        BIT_CLR(DIRA, 16);
    
        for(;;) {
            if(!BIT_VAL(INA, 16)) {
                printf("hello\n");
                BIT_SET(OUTA, 20);
                waitcnt(CNT + CLKFREQ);
                BIT_CLR(OUTA, 20);
            }
        }    
    }
    
    int main(void)
    {
        int i;
        int cog_id;
    
        cog_id = _start_cog_thread(cog_stack+STACK_SIZE, cog_func_one, (void*)0, &thread_data);
        printf("cog_id: %d\n", cog_id);
    
        for(i=0;; i++) {
            printf("%d\n", i);
            waitcnt(CNT + CLKFREQ*5);
        }
    
        return 0;
    }
    

    I dropped pin 16 after the count of 3 was displayed, at that point the LEDs continued to work normal but no printf output of any kind.
    $ propeller-load -b HUB -p /dev/ttyUSB0 -I /opt/parallax/propeller-load/ a.out -r -t
    Propeller Version 1 on /dev/ttyUSB0
    Writing 15116 bytes to Propeller RAM.
    Verifying ... Download OK!
    [ Entering terminal mode. Type ESC or Control-C to exit. ]
    cog_id: 1
    0
    1
    2
    3
    
  • denominatordenominator Posts: 242
    edited 2012-03-25 18:16
    Jim,

    When I run your program, the "hello" from the cog gets printed as gibberish! By default, you're using the SimpleSerial driver. It doesn't require an extra cog, but it is a littler bigger in code size and is not thread safe.

    Instead, use the FullDuplexSerial driver. It's smaller in code size, but it does most of its work in a separate assembly-language cog. It's thread safe and your program will work as expected. Just include this after your existing includes and before your code:
    #include <unistd.h>
    #include <driver.h>
    extern _Driver _FullDuplexSerialDriver;
    
    _Driver *_driverlist[] = {
      &_FullDuplexSerialDriver,
      NULL
    };
    

    Note that the STACK_SIZE of 16 is a bit more suspect when using printf; if I were you I'd set it to a bigger size and recheck the stack size requirements.

    - Ted
  • pinedustpinedust Posts: 19
    edited 2012-03-25 18:56
    Thank you! That works great! I didn't know.

    I will use the code you gave earlier for getting a handle on stack size too.

    Thanks again!
Sign In or Register to comment.