Simple asm delay ?


Closed Thread
Results 1 to 23 of 23
  1. #1
    Join Date
    Apr 2006
    Location
    GearSweaterMountain, The Netherlands
    Posts
    52

    Default Simple asm delay ?

    Hi All !

    I'm kinda stuck @ the moment. I have a 12F683 and i need to do a variable delay ranging from 1us to 1000us.

    The problem is that at 8Mhz the pauseus can't go as low as 12us.

    Does anybody have a asm routine or macro that can be used here ?

    Something like :
    Code:
    Macro delay(time in us)
    if time = 1 then
    nop
    nop
    if time = 2 then
    nop
    nop
    nop
    nop
    if time = 3 then
    
    etc, etc ...
    Thanks !

  2. #2
    Join Date
    Jun 2007
    Posts
    24


    Did you find this post helpful? Yes | No

    Default Use a FOR NEXT

    I think that you could use something like.

    Delay Var Word ' Pause in us
    Counter Var Word

    FOR Counter = 1 to Delay
    @nop
    @nop
    NEXT Counter

    It's untested so I'm guessing it should work but I don't know how long the LOOP will add to the pause.

    Regards, Mike
    Last edited by mikendee; - 10th November 2009 at 10:52. Reason: Revision

  3. #3
    Join Date
    Nov 2005
    Location
    Bombay, India
    Posts
    947


    Did you find this post helpful? Yes | No

    Default

    Assuming a 8MHz clock, some ASM macros
    Code:
    delay1us macro
        goto $+1      ;  2 cycle delay
                    endm
    
    delay2us macro
        delay1us
        delay1us
                   endm
    
    delay4us macro
        delay2us
        delay2us
                   endm
    
    delay8us macro
        delay4us
        delay4us
                   endm
    Now, you may want to get something like 5 us. For that you can
    @ delay4us
    @ delay1us
    in your code

    Hope this is helpful to you.

  4. #4
    Join Date
    Apr 2006
    Location
    GearSweaterMountain, The Netherlands
    Posts
    52


    Did you find this post helpful? Yes | No

    Default

    Wow, Thanks.

    I'm gonna try this. Tried the for..next just yet but it won't go below 5us delay.

    Jerson, i think this would do the trick, but i need to figure out how to let the software 'choose' the right delay .. I need to be able to feed the number of uS to delay to the asm macro.

    Something like ...
    Code:
    ASM
    Delay1us  macro time
    for x = 0 to time
        goto $+1
    next
    ENDASM
    Last edited by ultiblade; - 10th November 2009 at 12:36. Reason: Typo

  5. #5
    Join Date
    May 2004
    Location
    NW France
    Posts
    3,614


    Did you find this post helpful? Yes | No

    Wink

    Hi,

    The 683 has a TMR1 and also a CCP module ...

    just use one of them for variable delays !!!

    see asm examples in the relevant Datasheet chapter ...

    may be 1 and 2 microseconds will need a "special treatment" ...

    Alain
    ************************************************** ***********************
    Why insist on using 32 Bits when you're not even able to deal with the first 8 ones ??? ehhhhhh ...
    ************************************************** ***********************
    IF there is the word "Problem" in your question ...
    certainly the answer is " RTFM " or " RTFDataSheet " !!!
    *****************************************

  6. #6
    Join Date
    Apr 2006
    Location
    GearSweaterMountain, The Netherlands
    Posts
    52


    Did you find this post helpful? Yes | No

    Default

    You are so right !

    The thing is however, i have tmr1 setup as a counter and i use its overflow to sync the whole program on 100hz.

    I have three different led's that are driven by fet's. Each led has it's own channel and due to the design of the driver, at a given moment only 1 led me be high.

    To be able to shift the colors around, i turn on a certain channel for a certain ammount of time.

    Code:
    RED con %001
    GRN con %010
    BLU con %100 
    
    loop60
        if ledred = 0 then goto noRED
        GPIO = red
        pauseus ledred
    noRED:
        if ledgrn = 0 then goto noGRN
        GPIO = grn
        pauseus ledgrn
    noGRN:
        if ledblu = 0 then goto noBLU  
        GPIO = blu
        pauseus ledblu  
    noBLU:
    goto loop60
    Once interrupted the ledred / ledgrn / ledblu values are altered, but always in a way that ledred+ ledgrn + ledblu = 1000, the timer get's a reset and it then jumps back into the loop.

    The example above works but pauseus can't delay faster then 12us ...

  7. #7
    Join Date
    May 2004
    Location
    NW France
    Posts
    3,614


    Did you find this post helpful? Yes | No

    Default

    Hi,

    1µs to drive leds may really be overkill ...

    but I stil think the CCP module can do the trick ...

    Alain
    ************************************************** ***********************
    Why insist on using 32 Bits when you're not even able to deal with the first 8 ones ??? ehhhhhh ...
    ************************************************** ***********************
    IF there is the word "Problem" in your question ...
    certainly the answer is " RTFM " or " RTFDataSheet " !!!
    *****************************************

  8. #8
    Join Date
    Apr 2006
    Location
    GearSweaterMountain, The Netherlands
    Posts
    52


    Did you find this post helpful? Yes | No

    Default

    You are right about the 1us. I'm using this to be able to fade between colors.

    If I turn on the red led, wait 333uS, then turn on the green led, wait 333uS, and then the blue led and wait 333uS and then loop again, i have a white color at about 1000Hz, with no flickering. If i then increment the pauseus 333 for red and decrement the pauseus 333 for blu the color shifts smooth from white to about orange.

    I use the pauseus command at 8Mhz, which has a shortest delay of 12us. In the fade cycle this results in that one (or two) led are almost off, but not completely. The last 12 cycles the led stay on for 12us, and in the last cycle it will turn off.

    It works perfect except for the last few cycles ....

  9. #9
    Join Date
    Apr 2006
    Location
    GearSweaterMountain, The Netherlands
    Posts
    52


    Did you find this post helpful? Yes | No

    Default

    Google came up with an interesting piece of code.
    I did some tests and it seems to do the trick.

    If called using "@ wait 0" it delays 1uS,
    if called using "@ wait 1" it delays about 2,5uS,
    if called using "@ wait 2" it delays about 3uS.

    Code:
    asm
    shortwait macro del  ; used by main wait macro
        if (del>3) && (del<8) 
            call del7+(7-(del)) 
        endif 
        if del <4 
            if del>=2 
                goto $+1
            endif
            if ((del) & 1) == 1
                nop
            endif
        endif
        endm
    endasm
    
    asm
    wait macro del 
    ;    if (del)<0 error 'negative delay' 
    ;    endif 
        if (del)>=8 
            movlw ((del)-8) /4 
            call delay
            shortwait ((del-8) % 4) 
        else
            shortwait (del)
         endif
        endm
    
    delay  
        addlw 0xff 
        skpnc 
        goto delay
        return
     
    del7 goto del5      ; 7 cycle delay
    del6 goto del4      ; 6 cycle delay
    del5 nop            ; 5 cycle delay
    del4 return         ; 4 cycle delay
    ENDasm
    So, the delay is not the problem anymore.
    However, when called from picbasic like :
    Code:
    led1 var word
    led2 var word
    
    led1 = 2
    led2 = 2
    
    start:
    
    GPIO = %01
    @ wait _led1
    GPIO = %10
    @ wait _led2
    
    goto start
    The delay is about 33uS instead of 2. I understand that the delay would be longer, but 30uS extra ??

    Can someone, please, point me in the right direction ?
    Last edited by ultiblade; - 12th November 2009 at 13:18. Reason: Typo

  10. #10
    Join Date
    Nov 2005
    Location
    Bombay, India
    Posts
    947


    Did you find this post helpful? Yes | No

    Default

    Once you start counting instruction cycles, you will realize how they all add up to get you to the 30uS extra that you see. A call takes 2 cycles, a return another 2, and so on.

    I am a bit curious about your application and how you achieve colour fading. According to what you have shown here, you seem to be lighting the leds one behind the other with a fixed pause in between. I do not know why you have it that way, but, I would think it would be better to have them work in tandem unless you want just 1 led on at a time.

    Why not use 3 PWM channels one per colour to control the intensity of each?
    Now, the refresh rate for all the channels will be the same, but, the on-time for each led will be decided by its on-time variable.

    Would this work for you?

  11. #11
    Join Date
    Apr 2006
    Location
    GearSweaterMountain, The Netherlands
    Posts
    52


    Did you find this post helpful? Yes | No

    Default

    Hi Jerson,

    I understand your questions, let me explain some more :

    I drive 3 powerled's directly from the mains using a led driver board. These led's are switched by FET's, each on it's own channel. The driver board itself is about 10x10mm, a pic with 3 pwm channels in a SO8 package is just not available. Everything larger won't fit the enclosure.

    The driver cannot drive 2 or 3 led's at once, that's why i'm switching between the three. Doing so at a total delay (led1 delay + led2 delay + led3 delay)=1000Hz + some overhead.

    Pauseus does it's work, and all is fading smoothly. Except for the first start of a color. This sticks to 12us. When a fade is started, the color that is being faded in does not start at 1 or 2 us but starts with an initial delay of 12uS.

    Hope this makes my problem somewhat clearer ...

    I did count the instruction cycles, i even did a cross comparison of the asm files, the one using a number @ wait 0 and the one using @ wait _ledRED both files are exactly the same and have the exact same length ! I played around with the variables, changed them to byte's, putting them in bank0 ....

    Why would changing from a numeric value to a numeric value stored in a variable result in an overhead of 30uS, i just don't understand.

  12. #12
    Join Date
    Apr 2006
    Location
    GearSweaterMountain, The Netherlands
    Posts
    52


    Did you find this post helpful? Yes | No

    Default

    Small update :

    Declaring the variables as:

    ledRED VAR WORD BANK0

    Does reduce the total delay somewhat, the shortest delay (0) now results in 20uS ..

  13. #13
    Join Date
    Nov 2005
    Location
    Bombay, India
    Posts
    947


    Did you find this post helpful? Yes | No

    Default

    Try declaring your variable as BYTE instead of word. It will shave more time from the 20uS.

  14. #14
    Join Date
    Nov 2005
    Location
    Bombay, India
    Posts
    947


    Did you find this post helpful? Yes | No

    Default

    Assuming you have TMR0 (8 bit timer) free, you can try this code

    Code:
    AsmDelay macro  delayus
          movlw  0FFh-delayus    ; delayus to overflow                          1T
          movwf  TMR0                                                                            1T
          bcf        INTCON, T0IF    ; clear the timer0 Overflow flag          1T
          btfss     INTCON, T0IF    ; wait till it overflows                          1T/2T
          goto      $-1                   ; back to the btfss                              2T
      
          endm
    The minimum delay you will achieve will be 4T cycles or roughly 2uS at 8MHz.


    The way to use it would be
    Code:
          GPIO = %01
          @ AsmDelay 12
          GPIO = %10
          @ AsmDelay 24
    I hope this takes you closer to your goal. The code is just a concept, you may have to correct it. One important point you should note - the maximum delay will be 255uS
    Last edited by Jerson; - 12th November 2009 at 18:00.

  15. #15
    Join Date
    Jul 2003
    Posts
    2,405


    Did you find this post helpful? Yes | No

    Default

    Try this.
    Code:
    asm
    DelayCycles macro ncy ; ncy can be from 1 up to 256
      local n
    n set   (ncy)   ; assign ncy value to label n
    
      while n > 2   ; inserts goto $+1 while n > 2
        goto $+1    ; burn 2 cycles
    n   set   n - 2 ; n = n - 2
      endw
                    ; handle left-overs
      while n > 0   ; 1 nop for odd numbers
        nop         ; burn 1 cycle
    n   set   n - 1 ; n = n - 1
      endw
      endm
    endasm
    
    Main:
      HIGH 0
      @ DelayCycles 1  ; adds 1 nop
      LOW 0
      @ DelayCycles 5  ; adds 2 x goto $+1 and 1 x nop
      GOTO Main
    Regards,

    -Bruce
    tech at rentron.com
    http://www.rentron.com

  16. #16
    Join Date
    Nov 2005
    Location
    Bombay, India
    Posts
    947


    Did you find this post helpful? Yes | No

    Default

    Brilliant work.

    PS. It has a catch though. Te macro expansion occurs at compile time. So, you will not be able to "feed" the delay value at runtime
    Last edited by Jerson; - 13th November 2009 at 06:13. Reason: PS

  17. #17
    Join Date
    Apr 2006
    Location
    GearSweaterMountain, The Netherlands
    Posts
    52


    Did you find this post helpful? Yes | No

    Default

    Dear Jerson & Bruce,

    I could not get here earlier, sorry. I appreciate your efforts !

    Jerson, if i declare the delay variable as a byte, it takes even longer.
    I just don't understand .. The delay macro i found works perfect if given a number straight from the call, if it is fed by a variable the delay jumps to 20 or 30us. It also seems that the delay is fixed after that, if i compile @ wait 1000, it delays a perfect 1000 cycles, if i compile @ wait ledred (i.e. ledred = 100) it delays 20uS no matter what ledred is ?

    Bruce, your asm code also does the trick, perfect 1us or 50us delays, pretty neat. But it also suffers from the same problem. If i compile @ Delaycycles 200 if works perfect, if i compile ledred var byte, ledred = 200, @ delaycycles _ledred it gives a delay of 33uS no matter what the value of the leded var is ??

    Apart from that, i need to do a delay between 1 and 1000uS, using tmr0 the max delay will be 256, and i can use the Bruce asm up to 512, the ASM code i posted earlier can go up to about 1024.

    I would use the 16-bit TMR1 if it was available but i need that to do a 100Hz sync (count) interrupt...

    Any ideas ?

  18. #18
    Join Date
    Jul 2003
    Posts
    2,405


    Did you find this post helpful? Yes | No

    Default

    @ delaycycles _ledred it gives a delay of 33uS no matter what the value of the leded var is ??
    That's because when you pass _ledred to the macro as the argument, it uses the 'address'
    of ledred, and not the actual value in RAM. Look at the address PBP places ledred at to see
    why that happens.

    You can't put a macro inside a loop with a variable as the argument. What you're looking to do just
    isn't possible (as far as I know) with a macro inside the loop, and calls to any .asm routine, timer, etc,
    just aren't going to give you from 1uS to 1000uS delay periods you need immediately after
    placing a value on GPIO.

    I would re-think the whole process if I'm stuck at 8MHz, or switch osc speed & PIC to support using
    the pauseus commands.
    Last edited by Bruce; - 13th November 2009 at 23:42. Reason: Macros
    Regards,

    -Bruce
    tech at rentron.com
    http://www.rentron.com

  19. #19
    Join Date
    Apr 2006
    Location
    GearSweaterMountain, The Netherlands
    Posts
    52


    Did you find this post helpful? Yes | No

    Default

    Hi Bruce,

    Thank you for your detailed answer ! All is clear now.

    I have adapted the code in a way that the led's never go below 12uS, that way the 'color' switch on and off effect (color switches on for 12uS instead of 1uS) does not occur. This makes the colors somewhat more pastel, but it is still a smooth fade and a cool effect.

    And, yes, if i'm going to make a new design i will certainly use a larger external osc ..

    Thanks for all your answers and information !

    Best regards,
    UB

  20. #20
    Join Date
    Jul 2003
    Posts
    2,405


    Did you find this post helpful? Yes | No

    Default

    Grab a new 8-pin PIC12F1822 with 32MHz internal osc when they come out. Then you can
    get PAUSEUS down to 2uS. These even have an onboard EUSART.
    Regards,

    -Bruce
    tech at rentron.com
    http://www.rentron.com

  21. #21
    Join Date
    Apr 2006
    Location
    GearSweaterMountain, The Netherlands
    Posts
    52


    Did you find this post helpful? Yes | No

    Default

    Yep, if only it had eeprom .... :-(

  22. #22
    Join Date
    Jul 2003
    Posts
    2,405


    Did you find this post helpful? Yes | No

    Default

    The preliminary specs state it does. Data EEPROM (bytes) 256
    Regards,

    -Bruce
    tech at rentron.com
    http://www.rentron.com

  23. #23
    Join Date
    Apr 2006
    Location
    GearSweaterMountain, The Netherlands
    Posts
    52


    Did you find this post helpful? Yes | No

    Default

    You are right ! Missed that one, sorry ..

    Will order some samples as soon as possible, hoping that support for the part in PBP will be available soon ..

    Best regards,
    UB

Similar Threads

  1. 16F628A - Stops if release power switch.
    By dene12 in forum General
    Replies: 16
    Last Post: - 14th February 2009, 07:57
  2. Old and beyond help ?
    By DavidFMarks in forum mel PIC BASIC Pro
    Replies: 46
    Last Post: - 11th December 2008, 15:23
  3. RF Transmitter
    By et_Fong in forum mel PIC BASIC Pro
    Replies: 4
    Last Post: - 27th October 2005, 16:34
  4. Memory Space of the PIC16F84...
    By Tear in forum mel PIC BASIC Pro
    Replies: 7
    Last Post: - 1st July 2005, 19:55
  5. Problem with saving to EEPROM...
    By Tear in forum mel PIC BASIC Pro
    Replies: 5
    Last Post: - 1st July 2005, 00:10

Members who have read this thread : 1

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts