Shop OBEX P1 Docs P2 Docs Learn Events
I am too stupid to blink a LED .-. — Parallax Forums

I am too stupid to blink a LED .-.

Hey,
I am currently struggling to make a LED blink every second - I'm not sure wether I should laugh or cry xD But whatever, here is my code (thanks in advance to anyone who reads it in order to help me :))
CON
  _CLKMODE = XTAL1 + PLL16X ' The clock frequency is equal to 96MHz = 6MHz * 16X PLL.
  _XINFREQ = 6_000_000 '

PUB start
  cognew(@INIT, 96_000_000)

  repeat                         

DAT
            org 0
INIT        or      dira,   LED
            mov     tmp,    cnt
            add     tmp,    delay
            waitcnt tmp,    #0  
:loop       or      outa,   LED

            mov     tmp,    cnt
            add     tmp,    delay
            waitcnt tmp,    #0

            andn    outa,   LED

            mov     tmp,    cnt
            add     tmp,    delay
            waitcnt tmp,    #0
            jmp     #:loop

tmp         res     1
LED         long    %1_0000_0000_0000_0000_0000
delay       long    96_000_000
It blinks the LED but in an interval of like 10 - 12 seconds :/

DragonRaider5

Comments

  • JonnyMacJonnyMac Posts: 9,105
    edited 2016-05-07 17:06
    You need to define long values before using RES in your assembly code. Move the declaration of tmp to the end of the listing.

    Here's a version that lets you pass pin#, on-, and off-timing values (in milliseconds) to the background cog; this will let you create the same blink output regardless of system frequency.
    con { timing }
    
      _clkmode = xtal1 + pll16x                                     
      _xinfreq = 5_000_000                                          ' use 5MHz crystal
    
      CLK_FREQ = (_clkmode >> 6) * _xinfreq                         ' system freq as a constant
      MS_001   = CLK_FREQ / 1_000                                   ' ticks in 1ms
      US_001   = CLK_FREQ / 1_000_000                               ' ticks in 1us
    
    
    con { io pins }
    
      RX1 = 31                                                      ' programming / terminal
      TX1 = 30
    
      SDA = 29                                                      ' eeprom / i2c
      SCL = 28
    
      LED = 26
    
                                                              
    var
    
      long  bcog
                                                                     
                                                                     
    pub main                                                         
                                                                     
      start_blink(LED, 100, 400)                                    ' PAB led, 2Hz
    
      repeat
        waitcnt(0)                                           
                                                                     
    
    pub start_blink(pin, onms, offms)
    
      stop_blink
    
      onms  *= MS_001                                               ' convert ms to ticks
      offms *= MS_001
    
      bcog := cognew(@blinker, @pin) + 1
      repeat until (ina[pin])                                       ' wait for cog to start
    
    
    pub stop_blink
    
      if (bcog)
        cogstop(bcog - 1)
        bcog := 0
        
    
    dat { blinker }
    
                    org     0
    
    blinker         mov     t1, par                                 ' get address of parameters
                    rdlong  t2, t1                                  ' read pin #
                    mov     pinmask, #1                             ' convert to mask
                    shl     pinmask, t2
                    or      dira, pinmask                           ' set to output
    
                    add     t1, #4
                    rdlong  ontix, t1                               ' read on timing
    
                    add     t1, #4
                    rdlong  offtix, t1                              ' read off timing
    
                    mov     t1, cnt                                 ' sync timer
                    add     t1, ontix
    
    :loop           or      outa, pinmask                           ' pin on
                    waitcnt t1, offtix                              ' wait, reload with off timing
                    andn    outa, pinmask                           ' pin off
                    waitcnt t1, ontix                               ' wait, rload with on timing
                    jmp     #:loop
    
    
    pinmask         res     1
    ontix           res     1
    offtix          res     1
    
    t1              res     1                                       ' temp vars
    t2              res     1
    
                    fit     496
    

    Note that I have start and stop methods so I can change the blink behavior at any time. Note, too, that the second parameter of cognew() is intended -- though it can be used for other things -- to pass the hub address of parameters used by the background cog. It can only pass one address, so the background cog assumes the others are in a specific order.

    Final note: This program doesn't keep track of the blinking pin or timing once started. This is why I can point to the parameters block of the start_blink() method. Method parameters are always longs, and stored on the stack in the order they're defined. The timing is converted from milliseconds to ticks and then the address of the method parameters is used to start the background cog. It doesn't take long to start that cog but it's a good idea to ensure it's started before returning when you use the method's parameters when starting the background cog. Since the background takes the pin high first, we just watch for that.

    Yes, this is more than simple blinking. What I'm encouraging you to do is think beyond where you are in the moment and how you might apply it to future projects.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2016-05-07 16:48
    tmp needs to be placed after longs but try this;
    CON
      _CLKMODE = XTAL1 + PLL16X ' The clock frequency is equal to 96MHz = 6MHz * 16X PLL.
      _XINFREQ = 6_000_000 '
    
    PUB start
      cognew(@INIT, 96_000_000)
    
      repeat
    
    DAT
                org 0
    INIT        or      dira,   LED
                mov     tmp,    delay
                add     tmp,    cnt
    :loop       xor      outa,   LED
                waitcnt tmp,    delay
                jmp     #:loop
    
    
    LED         long    |<20
    delay       long    96_000_000
    tmp         res     1
    
  • SeairthSeairth Posts: 2,474
    edited 2016-05-07 17:07
    We'll get you going yet! A couple notes:

    Move your
    tmp         res     1
    

    after
    LED         long    %1_0000_0000_0000_0000_0000
    delay       long    96_000_000
    

    For an explanation of why this is important, it's best to read Page 340 of the Propeller Manual (v 1.2).

    Also, after your initial delay is calculated in tmp, all you need to do is
    waitcnt tmp, delay
    

    each time you pause. This will automatically increment tmp by the amount in delay. That way you can get rid of the
    mov     tmp, cnt
    add     tmp, delay
    


    (Edit: LOL! That's what I get for stepping away in the middle of the reply to eat a waffle! At any rate, still make sure to read the PDF reference above.)
  • AribaAriba Posts: 2,690
    edited 2016-05-07 17:15
    Some more notes:

    If you not want to hardcode the clkfreq (96000), you can not pass the value 96000 as parameter in cognew. This par register is only 14 bit wide and the 2 LSBs are '00', it is meant for passing an address of a long variable.

    But you can read the clkfreq from hub address 0 in the PASM code:
    rdlong  delay,#0
    
    so the delay is always correct also with different crystals or PLL factors.

    Andy
  • Hi,
    thanks alot. This code was just to test if my pasm code works with my c code, that's why it wasn't as extensive ;) also I know about the incrementive feature of waitcnt, I just didn't use it to avoid any problems - thx for the reference page, that's what "caught me".

    DragonRaider5
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2016-05-08 02:01
    The reason for all res directives to go at the end of a PASM segment is because no actual space is allocated for them in the compiled image as you could imagine a 20 long PASM object with 476 res longs doesn't need to take up 2k of precious Propeller EEPROM then RAM just to load 20 longs into a cog. So even though the addresses are correct the longs that get compiled afterwards are in the wrong place. Have a look at this listing where the res is before the long and see the blank space knowing that the compiled object will now have the next long in that position instead. So your code ends up overwriting the LED long while the LED long is pointing to the delay long etc. Btw, this code can be optimized even further but works as is (assuming tmp is after the longs).
    0018(0000)             |             org 0
    0018(0000) 07 EC BF 68 | INIT        or      dira,   LED
    001C(0001) 08 0C BC A0 |             mov     tmp,    delay
    0020(0002) F1 0D BC 80 |             add     tmp,    cnt
    0024(0003) 07 E8 BF 6C | :loop       xor      outa,   LED
    0028(0004) 08 0C BC F8 |             waitcnt tmp,    delay
    002C(0005) 03 00 7C 5C |             jmp     #:loop
    0030(0006)             | tmp        res     1
    0030(0007) 00 00 10 00 | LED         long    |<20
    0034(0008) 00 D8 B8 05 | delay       long    96_000_000
    
Sign In or Register to comment.