Shop OBEX P1 Docs P2 Docs Learn Events
Propeller 2, What does "%00110 NCO Frequency mode" do? — Parallax Forums

Propeller 2, What does "%00110 NCO Frequency mode" do?

I'm puzzled by the description of the Prop-2 "NCO Frequency." Couldn't find an example I could understand.
What does this mode do and what would someone use it for?
What should I see on my scope at the Smart-Pin output pin? A short assembly-language example would help. So would a diagram that shows what the Smart-Pin output would look like.
Specific questions re the documentation:
1. "Upon WXPIN, X[31:16] is written to Z[31:16]..." What does this value represent?
2. "Y[31:0] will be added into Z[31:0] at each base period." Where does the Y value come from and what does it do?

I volunteered to help clarify the Prop-2 documentation and appreciate the help of Forum members. Thanks. --Jon
«1

Comments

  • Definitive application note(s) on Smart Pins, with SPIN2 & PASM2 examples would be a huge help, both for ADC and DAC modes. Super simple please, I can always add features after I know and understand the basics. Smart Pins are the biggest selling points of the P2. Trial and error and spaghetti code are the pits.
  • Agreed. I have seen too many examples from other semiconductor manufacturers (not Parallax) that overcomplicate the simple. If you want an example that explains how to use an SPI port, for example, you get an app note that includes SPI control of a temperature sensor, a WiFi connection to the Internet, and a Web server--all in one. PLEASE, just the simplest SPI example and simple easy-to-understand COMMENTED code.
  • In this example a smartpin is configured for 123Hz output.
    	wrpin	#%1_00110_0,#pin	'NCO freq mode
    	wxpin	#1,#pin
    	dirh	#pin
    
    	qdiv	##_clkfreq,#123		'123 Hz
    	getqx	pa
    	qfrac	#1,pa
    	getqx	pa
    	wypin	pa,#pin			'set NCO for 123Hz
    
    
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2020-05-19 01:07
    I you want to see what wxpin does, just try it.

    edit: updated scope image links & corrected a code paste
  • Nice demo, Peter, but it doesn't explain why someone wants to do this with an MCU. And it doesn't explain this:
    There are other words such as HZ KHZ MHZ that set it to a specific frequency but they do so by calculating the NCO value derived from a known system clock frequency then passing that value to the NCO routine.
    What are the calculations, where do the values come from, which registers do they go in, and what bits will they affect?
    So without knowing beforehand what WXPIN did in this mode, it can be deduced that it must be a prescaler. Verify this yourself by writing other values to WXPIN.
    This is not obvious and will only confuse (discourage) someone what wants to learn assembly-language programming (me).

    See the attached for a prototype of how we might better explain a Smart-Pin operation. Let me know what you think. --Jon

  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2020-05-19 03:52
    Jon, I kept that example as simple as possible but think of this version of Forth as having the equivalent smartpin instructions wxpin wypin wrpin etc as high-level interactive routines.

    Your "wrpin Pulseconfig, #20" is simply a value and a pin number for wrpin. In Forth you would just test your assembly code this way:
    20 PIN F  ( use PIN 20 and float it )  
    %0000_0000_000_00000_00000000_11_00100_0 WRPIN ( write this config to the current pin 20)
    $01F4_05DC WXPIN ( Set the cycle time and logic-0 period)
    L ( make P20 an output as a low in this case to enable the smartpin function )
    $0010 WYPIN ( Send pulse count to Y register)
    

    I purposely used your absolute values rather than symbols or constants, but by all means define them and use them if you like the same way.

    Of course there are higher level functions which already set it to NCO mode and default prescale and period. But you can do it the long way too and directly translate that into assembly or vice-versa.
  • Cluso99Cluso99 Posts: 18,069
    edited 2020-05-19 04:05
    Nice writeup Jon.

    I would add after sentence "Software sets..."
    Therefore the width of the high pulse is calculated by X[15:0] less X[31:16].

    A comment prior to the "IN Flag" in the diagram "(on the second last pulse end)"

    From the calculations based on 25MHz clock which I calculated that you used
    X[15:0] = 1500 x 40ns = 60us
    X[31:16] = 500 x 40ns = 20us

    So I would replace this line
    PulseTiming long $01F4_05DC '60 usec pulse, 20 usec logic-0
    with
    ' assuming a clock frequency of 25MHz (40ns per cycle)
    PulseTiming     long   500<<16 + 1500 '$01F4_05DC = 20us logic-0, 60us total (us=microsecond)
    
  • Jon
    In your example you state the following.
    To put out logic-0 pulses, replace the dirl instruction with dirh and change the PulseConfig Mode value P5 bit to a 1:
    The DIRH/L doesn't control the output ibversion. It is done by the low level pin control bit (O).

  • Jon,
    The SmartPin NCO Frequency mode acts very similarly to the P1 Counter NCO mode.

    When running, every X[15:0] system clocks Y[31:0] is added to Z[31:0]. The output pin will be set to Z[31].

    While setting up, when you do the WXPIN instruction, X[31:16] is copied to Z[31:16]. This just offsets the initial Z value so that you can phase adjust the frequency (aka start already partially into the cycle). X[31:16] is not used after that.

    With NCO Frequency mode you do not control the high and low time (it's always 50% duty). You are just controlling the frequency.

    If X[15:0] is set to 1, then Y[31:0] will be added to Z[31:0] every system clock tick. So in order to set the frequency you desire you need to calculate how many system clocks one cycle of your given frequency takes. This can be done by using "qfrac desiredFrequency, systemClockFrequency" and then "getqx valueForY".

    If you set X[15:0] to 100, then Y[31:0 will be added to Z[31:0] every 100 system clock ticks. Thus your output frequency would be divided by 100 (e.g. 100kHz would become 1kHz).

    As for why? Well there are lots of reasons you might want to have a pin toggle at a given frequency. Sound, leds/lights, driving some external device's clock input, and much mode.

  • evanhevanh Posts: 15,182
    edited 2020-05-19 05:53
    The Y register you set yourself, like the X register. Y provides fractional accumulation of the NCO function.

    When Y is a whole division of 2^32, eg: $8000_0000, then it produces a simple square wave at the pin output (smartOUT). Y = $8000_0000 will toggle smartOUT on completion of each X period.

    When Y is not a whole division of 2^32 then it manifests as a dither at the output. This can be good for some applications but can create interference for other applications so best bet is start with nice clean fractions.

    PS: Educational trivia: X = 1 and Y = $0080_0000 produces the same frequency (sysclock/512) as X = $100 and Y = $8000_0000.

  • Great examples - But for the newbie P2 user, something like this...

    Where: Pin, Frequency, Continuous, DutyCycle, Start & Stop, etc - would be called variables / predefined functions to PASM2 code.
    In line with what Jon Titus listed for a NCO mode Smart Pin prototype App note or document.

    SineWave( Pin, Frequency, Continuous)
    SineWave( Pin, Frequency, Cycles )
    SineWave( Pin, Frequency, DutyCycle)
    SineWave( Pin, Frequency, Start )
    SineWave( Pin, Frequency, Stop )

    SquareWave( Pin, Frequency, Continuous)
    SquareWave( Pin, Frequency, Trigger )
    SquareWave( Pin, Frequency, OneShot )
    SquareWave( Pin, Frequency, DutyCycle)
    SquareWave( Pin, Frequency, Start )
    SquareWave( Pin, Frequency, Stop )

    TriangleWave( Pin, Frequency, Continuous)
    TriangleWave( Pin, Frequency, Trigger )
    TriangleWave( Pin, Frequency, OneShot )
    TriangleWave( Pin, Frequency, Start )
    TriangleWave( Pin, Frequency, Stop )

    SawtoothWave( Pin, Frequency, Continuous)
    SawtoothWave( Pin, Frequency, Trigger )
    SawtoothWave( Pin, Frequency, OneShot )
    SawtoothWave( Pin, Frequency, Start )
    SawtoothWave( Pin, Frequency, Stop )

  • That's helpful, PropGuy2. Thanks. --Jon
  • ozpropdev, thanks for your code example, but it didn't work. The compiler (FlexGUI) doesn't recognize _clkfreq. That's because it's an incomplete example. I'm not picking on you. This sort of thing pops up in many Forum discussions.
    wrpin	#%1_00110_0,#pin	'NCO freq mode
    	wxpin	#1,#pin
    	dirh	#pin
    
    	qdiv	##_clkfreq,#123		'123 Hz
    	getqx	pa
    	qfrac	#1,pa
    	getqx	pa
    	wypin	pa,#pin			'set NCO for 123Hz
    

    Should read? I know little about setting the Prop-2's operating frequency.
    COM
    _clkfreq = 100_000_000
    dat
    
    wrpin	#%1_00110_0,#pin	'NCO freq mode
    	wxpin	#1,#pin
    	dirh	#pin
    
    	qdiv	##_clkfreq,#123		'123 Hz
    	getqx	pa
    	qfrac	#1,pa
    	getqx	pa
    	wypin	pa,#pin			'set NCO for 123Hz
    

    That works.

    There's nothing in the example that sets the clock frequency. Maybe we assembly language newcomers should know that, but there's no documentation I could find about how to set the clock. Maybe I missed it.

    The two comments are a good start, but what do the other commands do? Please explain the math so we can understand the qdiv, getqx, and qfrac instructions. We can see them in the op-code spreadsheet but seeing the numeric results in the comments helps us understand what the instructions do, why you used them, and how we can use them. Examples, in my opinion, should aim to teach people how to do things, not just demonstrate them.

    Also, what is "pa," a register? The "PA" appears in the Prop-2 docs six times, none of which explain what it is, what it does, and why you used it. That information would helps us newcomers.

    Thanks for taking the time to send your example. I now see a square wave, but still don't understand the calculations and the results you used to produce it. --Jon
  • ozpropdevozpropdev Posts: 2,791
    edited 2020-05-19 23:36
    Hi Jon
    Yes the code I posted was a snippet.
    I would have to post multiple examples that work for all the compilers.
    BTW The code you posted is incomplete and won't work straight up either.

    Here's another example that is for SPIN2.
    CON
    
    	_clkfreq = 100_000_000
    	pin = 56
    	Hz = 123
    
    pub main()|y
    
    	y := Hz FRAC _clkfreq		
    	pinstart(pin,p_nco_freq + p_tt_01,1,y)
    	repeat
    
    

    The calculation is Y = (Hz << 32) / clock frequency.

  • Jon
    PA is one of the special function registers in the Propeller 2.
    PA and PB are mainly used with LOC instructions with PTRA and PTRB.
    I am using it as a general prpose register.
    IJMP3 1f0: 
    IRET3 1f1: 
    IJMP2 1f2: 
    IRET2 1f3: 
    IJMP1 1f4: 
    IRET1 1f5: 
    PA    1f6: 
    PB    1f7: 
    PTRA  1f8: 
    PTRB  1f9: 
    DIRA  1fa: 
    DIRB  1fb: 
    OUTA  1fc: 
    OUTB  1fd: 
    INA   1fe: 
    INB   1ff: 
    
  • Here's a PASM example for Pnut
    Math was reduced to a simpler form same as SPIN2 example above.
    CON
    	_clkfreq = 100_000_000
    	pin = 56
    	Hz = 123
    
    pub main()|y
    
    	coginit(16,@code,0)
    	repeat
    
    dat	org
    
    code	wrpin	#%1_00110_0,#pin
    	wxpin	#1,#pin
    	dirh	#pin
    
    	qfrac	##hz,##_clkfreq
    	getqx	pa
    	wypin	pa,#pin
    
    	jmp	#$
    
    
  • AribaAriba Posts: 2,682
    edited 2020-05-20 03:18
    Or with Spin and inline assembly. So you don't need another cog.
    I also added some comments ;)
    CON
    	_clkfreq = 100_000_000       'this defines and sets the clkfreq in Spin2
    	pin = 56
    	Hz = 123
    
    pub main()
      org
    	wrpin	#%1_00110_0,#pin	'set NCO smartpin mode
    	wxpin	#1,#pin			'clk divider = 1
    	dirh	#pin			'enable smartpin
    
    	qfrac	##Hz,##_clkfreq		'calc freq step (2^32 / clkfreq * Hz)
    	getqx	pa
    	wypin	pa,#pin			'write freq to smartpin Y reg
    
    	jmp	#$			'wait forever (smartpin does the work)
      end
    
    Andy
  • Good information! Thanks very much. --Just what this newbie needs. --Jon
  • evanhevanh Posts: 15,182
    edited 2020-05-20 03:52
    Here's an example of setting the sysclock in pure pasm2 - https://forums.parallax.com/discussion/comment/1496692/#Comment_1496692

    It is built from Cluso's original post - https://forums.parallax.com/discussion/comment/1452025/#Comment_1452025 but with one notable change: The first HUBSET #$f0 is a workaround for a hardware flaw that was later found in the sysclock switching circuit.

  • @JonTitus

    I think you missed the section of the docs on COGRAM and registers:
    DUAL-PURPOSE REGISTERS
    The RAM at addresses $1F0 through $1F7 may either be used as general purpose registers, or may be used as special-purpose registers if the associated function is enabled.

    $1F0 RAM / IJMP3 interrupt call address for INT3
    $1F1 RAM / IRET3 interrupt return address for INT3
    $1F2 RAM / IJMP2 interrupt call address for INT2
    $1F3 RAM / IRET2 interrupt return address for INT2
    $1F4 RAM / IJMP1 interrupt call address for INT1
    $1F5 RAM / IRET1 interrupt return address for INT1
    $1F6 RAM / PA CALLD-imm return, CALLPA parameter, or LOC address
    $1F7 RAM / PB CALLD-imm return, CALLPB parameter, or LOC address
  • AJL wrote: »
    @JonTitus

    I think you missed the section of the docs on COGRAM and registers:
    DUAL-PURPOSE REGISTERS
    The RAM at addresses $1F0 through $1F7 may either be used as general purpose registers, or may be used as special-purpose registers if the associated function is enabled.

    $1F0 RAM / IJMP3 interrupt call address for INT3
    $1F1 RAM / IRET3 interrupt return address for INT3
    $1F2 RAM / IJMP2 interrupt call address for INT2
    $1F3 RAM / IRET2 interrupt return address for INT2
    $1F4 RAM / IJMP1 interrupt call address for INT1
    $1F5 RAM / IRET1 interrupt return address for INT1
    $1F6 RAM / PA CALLD-imm return, CALLPA parameter, or LOC address
    $1F7 RAM / PB CALLD-imm return, CALLPB parameter, or LOC address

    PA and PB are also set by XBYTE to current bytecode and hub address of next bytecode in FIFO, respectively.
  • Thanks, folks. Yes, I saw that description, too. It didn't help. Here's why:
    PA CALLD-imm return, CALLPA parameter, or LOC address
    
    is meaningless to a newbie without a couple of sentences that explain what the above description means. If we want people to learn and use the Prop-2 assembly language, our documentation should help them rather than leaving them with the thought "I haven't a clue, so back to the Arduino or Raspberry Pi..."

    Back in the late 1960's, Digital Equipment Corp (long gone) published a book, "Introduction to Programming" for people who wanted to learn assembly-language programming for the company's PDP-8 minicomputers. It's an example of excellent documentation and I recommend anyone writing the Prop-2 assembly-language docs get a copy. The Prop-2 is orders of magnitude ahead of the old PDP-8's, but good documentation techniques are timeless. Abebooks.com has several copies for about $US 15. ISBN 13: 9780395747117. --Jon
  • That's because all the current docs are more reference-style. There isn't really a step-by-step introduction.
    In this case, just look up the CALLD, CALLPA and LOC instructions in the instruction sheet (altough last I checked, CALLD's description was a bit confusing)
  • So lets try this for the P2 newbie - I need a DAC output voltage at exactly 1.378 Volts DC, continuous. It might be for a DC motor, or instrumentation set point, or who knows what else. I really do not care about PASM2 or anything else, I just need the P2 to output 1.378 volts DC on pin 15.

    SetDCvolts( 15, 1378, DCmilliVolts, Continuous ) = Happy camper! Love the P2 !!!
    My project is a success...
  • JonTitus wrote: »
    Thanks, folks. Yes, I saw that description, too. It didn't help. Here's why:
    PA CALLD-imm return, CALLPA parameter, or LOC address
    
    is meaningless to a newbie without a couple of sentences that explain what the above description means. If we want people to learn and use the Prop-2 assembly language, our documentation should help them rather than leaving them with the thought "I haven't a clue, so back to the Arduino or Raspberry Pi..."

    Back in the late 1960's, Digital Equipment Corp (long gone) published a book, "Introduction to Programming" for people who wanted to learn assembly-language programming for the company's PDP-8 minicomputers. It's an example of excellent documentation and I recommend anyone writing the Prop-2 assembly-language docs get a copy. The Prop-2 is orders of magnitude ahead of the old PDP-8's, but good documentation techniques are timeless. Abebooks.com has several copies for about $US 15. ISBN 13: 9780395747117. --Jon

    But did you read and understand this bit?:
    DUAL-PURPOSE REGISTERS
    The RAM at addresses $1F0 through $1F7 may either be used as general purpose registers, or may be used as special-purpose registers if the associated function is enabled.

    In the example in question it is being used as a general purpose register that happens to have a name.

    If the original example had been
    wrpin	#%1_00110_0,#pin	'NCO freq mode
    	wxpin	#1,#pin
    	dirh	#pin
    
    	qdiv	##_clkfreq,#123		'123 Hz
    	getqx	$1F6
    	qfrac	#1,$1F6
    	getqx	$1F6
    	wypin	$1F6,#pin			'set NCO for 123Hz
    
    would you have found that less confusing and more newbie friendly? Maybe if it was given a different name for this use case?

    What I'm finding confusing is that you initially noted the state of the documentation, offering to contribute to cleaning it up, and then when asking for clarifications you appear to complain about the state of the documentation.

    It has been acknowledged by many that the documents aren't newbie focussed, and need more work. I'd humbly suggest that simply asking for further clarification, rather than telling people that a given explanation won't mean anything to a newbie, is probably a better approach to this.

    We have all been newbies at some point, and this community seems to maintain sympathy for newbies quite well. Some of us might take shortcuts with our explanations, but I've never seen anyone here refuse to slow down and provide a deeper understanding when asked for it.
  • PropGuy2 wrote: »
    So lets try this for the P2 newbie - I need a DAC output voltage at exactly 1.378 Volts DC, continuous. It might be for a DC motor, or instrumentation set point, or who knows what else. I really do not care about PASM2 or anything else, I just need the P2 to output 1.378 volts DC on pin 15.

    SetDCvolts( 15, 1378, DCmilliVolts, Continuous ) = Happy camper! Love the P2 !!!
    My project is a success...


    Such a library hasn't been published yet. Are you volunteering to write it?
    Most of the material available has been developed by, or in collaboration with, volunteers because Parallax isn't a huge corporation and they have taken on a fairly huge undertaking.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2020-05-21 01:39
    Setting a pin to output an voltage is very easy which is built into the standard TAQOZ "library".
    To setup P50 as a 12-bit DAC:
    50 PIN 12 DAC
    

    At any time to output a voltage (in millivolts), say 1.852 volts
    1.852 volts
    

    But there is nothing to these functions though, they are very simple. There are just two lines:
    pub DAC ( bits -- )		%101_000_0000000_01_00011 WRFNC |< WXPIN ;
    
    and
    pub VOLTS ( volts*1000 --- )	16<< 3300 U/ WYPIN ;
    

    So surely those functions could be added on the fly to suit.

    edit: Since I revisited this function I decided I should just call it "mV" instead and have it automatically set the DAC mode, plus I apply about 5mV compensation to recalibrate it. When I enter 825 mV I get 825mV.
    Now I just connect a meter to P52 and type "52 PIN 825 mV" and the meter reads .825V
  • AJL: You noted...
    What I'm finding confusing is that you initially noted the state of the documentation, offering to contribute to cleaning it up, and then when asking for clarifications you appear to complain about the state of the documentation.

    I have started to revise the SMART-PIN section of the Prop-2 reference and in explanations of two modes I have included a figure that shows timing of signals and several example codes. Several people have looked at these revisions and have commented on them. I do not use any special registers, just simple variable names, and each piece of code will operate as is--no snippets that rely on things someone might not know about. Trying to keep explanations simple and clear. I'll continue to work away at revisions for each of the Smart-Pin modes. I complain about poor documentation when I cannot understand it and usually get helpful comments so I can revise or recreate it. You'll find an example as an attachment to one of my posts close to the start of this thread. I welcome comments.

    My complaints about the Prop-2 documents might spur others to offer revisions, too.
  • Cluso99Cluso99 Posts: 18,069
    General note to all...

    Currently there are very few (if any) novices here. The docs have been quickly compiled for those "in the know". Where they lack details for us long-timers, we just ask and someone with more expertise in that area can nut it out, try it out if time permits, and report back. Sometimes we have to ask the "master". Unfortunately, time often limits us putting this info back into the documents.

    Add to this, documentation experts are usually not engineers. We tend to use a different part of the brain.

    But we will get there. And many thanks to those who help along the way :)
  • evanhevanh Posts: 15,182
    Jon,
    The main google doc is not intended as a beginners instruction manual. It is the technical reference for testing the hardware while it was being finished, also for tools developers and for the hardy folks that enjoy a challenge. And it'll likely continued to be referenced long into the future because of its extensive coverage.

    In fact I thought you had made it your mission to work through it piece by piece, writing alternative sections in simpler descriptions and with examples.

Sign In or Register to comment.