Shop OBEX P1 Docs P2 Docs Learn Events
ASM WAITPEQ help? — Parallax Forums

ASM WAITPEQ help?

SteelSteel Posts: 313
edited 2012-01-26 23:49 in Propeller 1
Sorry for the questions...unfortunately, I am not completely confident in my coding skills and need to rely on support right now.

Below I have simple code that uses WAITPEQ in both ASM and SPIN.

When I run this program with the ASM WAITPEQ commented out (and running the SPIN WAITPEQ), it works fine.· When I run the program with the SPIN WAITPEQ commented out (and running the ASM WAITPEQ), the rest of the program does not run.


Just to understand the program, I am monitoring PIN1.· When PIN1 goes high, I toggle PIN4 high and low 5 times.

It works when I use WAITPEQ in SPIN, but it is not working when I use the WAITPEQ in ASM.

Any help would be greatly appreciated.

Shaun

con
· _clkmode = xtal1 + pll16x
· _xinfreq = 5_000_000



pub Toggle_Main
···
WAITPEQ(%1, %1,0)
cognew (@Toggle, 0)




dat
······················· org······ 0
Toggle
············· WAITPEQ·· %1, #%1·
············· mov···· Counter, #5
············· mov···· dira,·· #10·············· 'Set Pin to output
············· mov···· Time,·· cnt··············· 'Place the value of cnt into Time
············· add···· Time,·· #9
·························
············
:loop
············· waitcnt Time,·· Delay············· 'Set Pin high
············· xor···· outa,·· #10··············· 'Toggle Pin
············· waitcnt Time,·· Delay············· 'Set Pin Low
············· xor···· outa,·· #10·············· 'Toggle Pin
············· DJNZ··· Counter, #:loop
············· jmp······ #Done
·············
·Done
············· mov······ outa, #00
············· jmp······ #Done············


·············
·············
Pin···· long··········· $10
Delay·· long··········· 1_000_000

Time··················· res 1
Counter················ res 1

Comments

  • Graham StablerGraham Stabler Posts: 2,510
    edited 2007-07-12 23:48
    Try

    WAITPEQ #%1, #%1

    As both are literals.

    Graham
  • Mike GreenMike Green Posts: 23,101
    edited 2007-07-13 00:08
    Graham,
    You can't have a literal value in the destination field. The %1 means memory location 1. The easiest way to do this is to have another location, like "PinMask long %1" and then use "WAITPEQ PinMask,PinMask".· This will cause the cog to pause until pin zero is a logic one.· If you want some other pin, change PinMask.
  • Graham StablerGraham Stabler Posts: 2,510
    edited 2007-07-13 00:18
    Well I knew it couldn't be just %1 but I should have kept my big mouth shut beyond that [noparse]:)[/noparse]
  • SteelSteel Posts: 313
    edited 2007-07-13 15:05
    Unfortately, Mike's solution isn't working either. :S

    Even when I assign Pinmask as a long = %1, and put in the 'WAITPEQ PinMask, PinMask' it still doesn't function correctly.

    I have verified that it works in SPIN, but for some reason it is not functioning in ASM...
    The below code can be verified by putting an oscope on Pin4, and toggling pin1 from low to high...

    _______________________________________________________________________
    Toggle

    mov Counter, #5
    mov dira, #10 'Set Pin to output
    mov Time, cnt 'Place the value of cnt into Time
    add Time, #9 'Add 9 to time
    WAITPEQ PinMask, PinMask

    :loop
    waitcnt Time, Delay 'Set Pin high
    xor outa, #10 'Toggle Pin
    waitcnt Time, Delay 'Set Pin Low
    xor outa, #10 'Toggle Pin
    DJNZ Counter, #:loop
    jmp #Done

    Done
    mov outa, #00
    jmp #Done



    Delay long 1_000_000
    PinMask long %1

    Time res 1
    Counter res 1
    ______________________________________________________________
  • Mike GreenMike Green Posts: 23,101
    edited 2007-07-13 15:10
    The example I gave was for pin zero, not pin one. If you want to use pin one, define "PinMask long %10"
  • SteelSteel Posts: 313
    edited 2007-07-13 15:33
    Oh...Im sorry...I am on pin0 and trying the code. Just for kicks, I did try it on Pin1 also (with %10)...but to no avail....
  • Mike GreenMike Green Posts: 23,101
    edited 2007-07-13 15:44
    If you look at your code, you are using decimal "10" to set pin directions and to toggle output pins. You probably meant to use "%10" for an output pin. What you wrote will use pins 1 and 3 for output (since decimal 10 is %1010).
  • SteelSteel Posts: 313
    edited 2007-07-13 16:00
    Yeah...I understand that...the only issue is that I am not having any problems with the output pins.· I can control those the way I want just fine.

    The problem is that I am able to get WAITPEQ in Spin to work.· When I have it in spin, the output is correct (See first picture· -· Top trace is me changing the state of Pin0 from Low to High, bottom trace is monitoring the output pin.)

    When I put....
    ·______________________________
    ······· WAITPEQ· pinmask, pinmask
    ········ ....output code here.....···
    ······· Pinmask·· long·· %1
    · _____________________________

    ....I am not changing any of the output code...The only change is putting in the WAITPEQ command.· The output code never executes (output pin toggling 5 times) with the ASM WAITPEQ.· See second picture.· The only thing that I am changing is where the WAITPEQ is...SPIN vs ASM.







    Post Edited (Steel) : 7/13/2007 4:12:23 PM GMT
  • Mike GreenMike Green Posts: 23,101
    edited 2007-07-13 16:34
    The way you select your direction bits is important. The WAITPEQ tests the I/O pin state. If you're driving them as outputs, the WAITPEQ may fail (and you may damage the I/O circuitry if you try to force the pin to the opposite state).

    Another complication is that separate cogs have their own DIRA and OUTA registers. They're OR'd together among cogs to set the actual state of the I/O pin. Your Spin code and the assembly routine run in different cogs, so this affects what you're seeing.

    In any event, WAITPEQ works in assembly the same way it works in Spin. What would be the "port" parameter is ignored in both Spin and assembly and the mask and compare state values work the same way. The example I wrote waits until the I/O pins marked by the mask (PinMask) are all one bits. To work properly, the direction register has to have those pins set as inputs (direction bit == zero) and no other cog can have those pins set as outputs.
  • AribaAriba Posts: 2,690
    edited 2007-07-13 23:39
    The problem in your code is not the WAITPEQ but the WAITCNT Time,Delay. You prepare the Time value before the WAITPEQ with CNT+9 and wait then for the Pin-change. After the Pin has changed, the CNT is certainly higher as Time.
    Try it this way:

    WAITPEQ PinMask, PinMask
    mov Time, cnt 'Place the value of cnt into Time
    add Time, #9 'Add 9 to time

    Andy
  • nmz787nmz787 Posts: 24
    edited 2012-01-26 08:56
    Not sure why this isn't working for me... I set up timer A and B, then sync the two (they are both 2^N for freq, so no overflow jitters)... but when I try to OR OUTA at the same time as, or just after timer B toggles it's pin, the timer PWM doesn't work. Does WAITPEQ actually take 4 cycles to complete? (What about WAITCNT, also referring to Assembly)

    here's the code I've been working with, its a little messy, but I'll leave it so you maybe can get an idea of what I was tryin to do
    ''Demonstration of PWM version of NCO counter mode
    CON _clkmode = xtal1 + pll16x
    _xinfreq = 6_000_000
    VAR long parameter
    PUB go | x
      parameter := 50 'unused
      cognew(@entry, @parameter) 'start assembly cog       
    DAT
    ''assembly cog fetches the value in parameter for PWM percentage
    org
    entry   mov dira, diraval  'set pins to output
            or outa, ICGpin   'set ICG high to begin
            'NOP
            mov 20, masterFreq 'copy masterFreq to register 20
            shr 20, #4         'shift the contents of register 20 to the right by two places, divide by 
            
            mov frqa, masterFreq  'set counter to increment 1 each cycle
            mov frqb, exposureTime  'set counter to increment 1 each cycle
    
    
            mov ctra, ctraval             'establish counter A mode and APIN
        
            
           ' NOP   
            
            mov 18, exposureTime            'move current time to a register
            shr 18, #12 'divide exposure time a lot... seems weird, need to figure out this math
            mov 19, 18  'copy exposure time to reg 19
            sub 19, #4  'subtract 4 (cpu cycles) from register 19
            'mov 19, 18
            'add 19, 18 
            mov ctrb, ctrbval   'both counters are now going, master clock and SH line
            'add 19, CNT      'add the exposure time to the current register
            NOP   
    :ccdStart            
            'andn   outa, ICGpin
            'mov 21, numActivePixels
            'mov 17, #0 'needed a register that held 0 for waitcnt     
    
            'waitcnt 17, 18     'wait til 0 on the counter, add 1/2 exposure time (from register 18)
            'add 17, 18         'now 17 should hold exposureTime worth of cpu cycles
    
            'waitcnt 17, 18     'wait til 1/2 exposure time, add 1/2 exposure time
            
            waitpeq     SHsensePin, SHsensePin
            'NOP
            andn     outa, ICGpin
            
            waitpeq     SHsensePin, SHsensePin
            'NOP 
            'waitcnt 17, 18
            'NOP
            or   outa, ICGpin
            jmp #:ccdStart
    ':pixelLoop
            'waitcnt 17, 20
            'djnz 21, #:pixelLoop
            'or     outa, ICGpin 
            'jmp #:ccdStart' rdlong value, par 'get an up to date pulse width
            'waitcnt time, period 'wait until next period
            'neg phsa, value 'back up phsa so that it trips "value" cycles from now
            'jmp #:loop 'loop for next cycle
    diraval long |< 6 | 1<<8 | 1<<7 'Direction of pin 6,7,8 == outputs
    ctraval long %00100 << 26 + 7 'NCO/PWM APIN=7, master clock
                                
    ctrbval long %00100 << 26 + 6 'NCO/PWM BPIN=6
    SHpin long 1<<6
    SHsensePin long %10000         'this is just a physical loopback from SHpin
    ICGpin long 1<<8
    period long 96 '1000kHz period (_clkfreq / period)
    masterFreq  long 134217728     'master CCD frequency, ~3Mhz
    exposureTime long 4194304      '~10uSecs
    fourExposureTimes long 16777216
    halfExposureTime long 2097152
    
    numActivePixels long 3648   
    
    maxVal long $FFFF
    time res 1
    value res 1
    
  • nmz787nmz787 Posts: 24
    edited 2012-01-26 09:07
  • ChrisGaddChrisGadd Posts: 310
    edited 2012-01-26 13:41
    I'm not quite sure what this program is supposed to do, however these lines execute in rapid succession.
            waitpeq         SHsensePin,SHsensePin
            andn            outa,ICGpin
            waitpeq         SHsensePin,SHsensePin
            or              outa,ICGpin
    
    The andn instruction takes 4 clocks, the following waitpeq takes a minimum of 5. Using a 6MHz xtal with 16x PLL that's one instruction every 10.4ns, so approximately 94ns from one waitpeq to the other. If SHsensePin is high for longer than 94ns the routine will set ICGpin high right after setting it low ... is that what you intended? If you're looking for SHsense to transition, you need to insert a waitpne to detect a low before using waitpeq to detect a following high.

    I don't see how the Z flag is used at all in this routine.
  • MagIO2MagIO2 Posts: 2,243
    edited 2012-01-26 14:53
    @nmz787:
    baaaad!
    1. Not a good idea to hijack the thread of someone else
    2. The code you posted ..... brrrrr

    You should not use direct addresses in your instructions. This is simply not maintainable code! You uncomment one line of code and have to shift all the direct addresses manually. If you constantly use labels the compiler takes care of that! If I counted right 18 is exactly where you placed the label diraval. Is this intended?
    If I see it right you want to reuse a register after it's no longer needed, but you want to avoid using that label?!
    Then you should know that you can set as many labels for one memory location as you want:

    label1
    label2
    label3 long 1234

    All 3 labels point to the same long! So, please use meaningfull labels also for the temporary registers - something like tmpcalc1
  • frank freedmanfrank freedman Posts: 1,983
    edited 2012-01-26 16:53
    Mike Green wrote: »
    The way you select your direction bits is important. The WAITPEQ tests the I/O pin state. If you're driving them as outputs, the WAITPEQ may fail (and you may damage the I/O circuitry if you try to force the pin to the opposite state).

    Another complication is that separate cogs have their own DIRA and OUTA registers. They're OR'd together among cogs to set the actual state of the I/O pin. Your Spin code and the assembly routine run in different cogs, so this affects what you're seeing.

    In any event, WAITPEQ works in assembly the same way it works in Spin. What would be the "port" parameter is ignored in both Spin and assembly and the mask and compare state values work the same way. The example I wrote waits until the I/O pins marked by the mask (PinMask) are all one bits. To work properly, the direction register has to have those pins set as inputs (direction bit == zero) and no other cog can have those pins set as outputs.

    Mike,

    The statement that "no other cog can have those pins set as outputs" is not entirely correct. In the attached bit of code, I am using a separate cog for timing generation. The cog using WAITPNE and WAITPEQ monitors the pin to determine when the chip select is high and then when the chip select has gone low to begin sampling on an MCP3201 ADC.

    Better to say watch out for where you set pins to output highs on the cog executing the WAITPXX since logic highs rule in the ORed scheme of prop I/O. If a WAITPEQ is looking for a low (maskbit=0), it will wait until the pin goes low to continue and if the cog waiting set the pin high prior to the WAITPEQ running, it will wait forever as the pins are now permanently unequal and there is no way to clear the pin to low. For WAITPNE, if the test is set to look for a high bit (maskbit=1), if the pin is low, passes through, but if the input gets set high on the pin in question prior to the WAITPNE executing, again the cog will wait forever since now they are always equal.
    main    waitpeq cselp,cselp       ' wait for csel high
            waitpne cselp,cselp       ' when csel goes low, start acq capture/store
    
    
    
    
    cselp         res       1         ' will contain 1 where the chip select is assigned.  (%0---01 say for pin 0 monitoring) Passed in via PAR+4(N) 
    
    
    

    As I understand it and it worked for me,

    Frank
  • nmz787nmz787 Posts: 24
    edited 2012-01-26 20:44
    ChrisGadd wrote: »
    I'm not quite sure what this program is supposed to do, however these lines execute in rapid succession.
            waitpeq         SHsensePin,SHsensePin
            andn            outa,ICGpin
            waitpeq         SHsensePin,SHsensePin
            or              outa,ICGpin
    
    The andn instruction takes 4 clocks, the following waitpeq takes a minimum of 5. Using a 6MHz xtal with 16x PLL that's one instruction every 10.4ns, so approximately 94ns from one waitpeq to the other. If SHsensePin is high for longer than 94ns the routine will set ICGpin high right after setting it low ... is that what you intended? If you're looking for SHsense to transition, you need to insert a waitpne to detect a low before using waitpeq to detect a following high.

    I don't see how the Z flag is used at all in this routine.

    Ohhhh, that's a good point. SHpin is timer B's pin, which I literally have a wire looping from it to SHsensePin, Its 50% duty @ ~10 microsecond period
  • nmz787nmz787 Posts: 24
    edited 2012-01-26 21:00
    MagIO2 wrote: »
    @nmz787:
    baaaad!
    1. Not a good idea to hijack the thread of someone else

    Is that a rule here? This is a 5 year old thread, how am I hijacking anything? If you would have posted this question to a new thread, would you have told me to "try using the forum search before asking questions"?

    Its just keeping information aggregated, google already has this page linked in their database, people may have quoted this page on blogs, code, etc...
    2. The code you posted ..... brrrrr

    You should not use direct addresses in your instructions. This is simply not maintainable code! You uncomment one line of code and have to shift all the direct addresses manually. If you constantly use labels the compiler takes care of that! If I counted right 18 is exactly where you placed the label diraval. Is this intended?

    Hmm, no, that wasn't intended. I didn't know those longs were in registers... are they really? Why isn't that on the stack? (or doesn't the propeller work like that!???)
    If I see it right you want to reuse a register after it's no longer needed, but you want to avoid using that label?!
    Then you should know that you can set as many labels for one memory location as you want:

    label1
    label2
    label3 long 1234

    good to know, thanks.
    All 3 labels point to the same long! So, please use meaningfull labels also for the temporary registers - something like tmpcalc1

    yeah... I'm just learning Assembly for the first time because I want to use the propeller (I don't know spin either, though I'm getting familiar with the function and register vocabulary, etc..

    Its not C!
  • MagIO2MagIO2 Posts: 2,243
    edited 2012-01-26 23:49
    "Is that a rule here?" ... yes, that's a general rule in all forums that I know. But I have to admit that I did not recognize the date of the thread and thus you are right and I would not count it as hijacking under these circumstances!

    "... would you have told me to "try using the forum search before asking questions"? ... My feeling is that nobody here would have said something like this! There are a lot of questions that come again and again and I can't remember a thread where someone has been blamed for not using the forum search - at least not in the same way as they do this in other forums. Most propable reaction would be to answer the thread pointing you the other thread where this question has been asked before.

    The propeller does not have registers like other microprocessor designs. The propeller only has COG-RAM! Each COG-RAM can be anyting, a variable that contains a value, a variable that contains a pointer inside COG-RAM, a variable that contains a pointer to HUB-RAM ... you can do calculations with each COG-RAM long ...
    In other words all the COG-RAM that is not occupied by code can be used as a register for storing whatever you need to store.
    mov x,y
    long 10
    both will occupy one long in the COG-RAM in the order you use them in your program.

    A technique I often use is to have an initialization-routine which by nature only runs once and then I reuse those COG-RAM positions for doing temporal calculations or for keeping loop-counters .... And then it makes sense to use the multi-label feature to write readable, self-explanatory code. For example:
    dat
    org 0
    temp
    Init        mov hub_pointer_par1, par
                add  hub_pointer_par2, par
    
    mainloop
                rdlong  temp    , hub_pointer_par1
                rdlong  temp+1, hub_pointer_par2
    
                ' do something
                jmp #mainloop
    
    hub_pointer_par1  long  0
    hub_pointer_par2  long  4
    

    "good to know, thanks." - you're welcome!
Sign In or Register to comment.