[FYI] clkfreq/2n
kuroneko
Posts: 3,623
This post has been triggered by a [post=1021211]recent 8MHz requirement[/post] (serial transfer, clkfreq/10). It didn't really need the clock generation but I did it anyway. In general, dividing by powers of two is easily done with an NCO but sometimes you may need the odd (2n) divider but not the associated (counter) jitter. What are our options?
A As in not exercising your brain enough
- plain code
- waitcnt usage
- (mis)using an NCO as a monoflop
- waitvid usage (for the time being I consider that cheatingA and it's not everyone's cup of tea anyway despite being one of the most flexible solutions)
CON
pin = 16
DAT org 0
[COLOR="blue"]entry[/COLOR][COLOR="orange"]_28[/COLOR] mov dira, :mask
mov cnt, #5{14} +4
add cnt, cnt
:loop xor outa, :mask ' toggle pin
waitcnt cnt, [COLOR="orange"]#14[/COLOR]
jmp #:loop
:mask long |< pin
fit
Which leaves range 8..26. Let's cover plain code examples first (there are less, 8/16/20/24). I'm aware that 8 and 16 are powers of two, they are included here for completeness.
CON
pin = 16
DAT org 0
[COLOR="blue"]entry_08[/COLOR] mov dira, :mask
neg outa, dira ' !dira +1
djnz outa, #$-1 ' outa -= 1
:mask long |< pin
fit
DAT org 0
[COLOR="blue"]entry_16[/COLOR] mov dira, :mask
xor outa, :mask ' toggle pin
jmp #$-1
:mask long |< pin
fit
DAT org 0
[COLOR="blue"]entry_20[/COLOR] mov dira, :mask
:loop waitpne $, #0
neg outa, dira ' !dira +1
waitpne $, #0
djnz outa, #:loop ' outa -= 1
:mask long |< pin
fit
DAT org 0
[COLOR="blue"]entry_24[/COLOR] mov dira, :mask
:loop xor outa, :mask ' toggle pin
nop
jmp #:loop
:mask long |< pin
fit
And finally, an NCO based example (clkfreq/26, the remainder is listed in the attached SPIN file).
CON
pin = 16
DAT org 0
[COLOR="blue"]entry_26[/COLOR] mov dira, :mask
movs ctra, #pin
movi ctra, #%0_00100_000 ' NCO
movi frqa, #%0000_0001_0
' SDeRSDwm-RSDwm-RSDwm-RSDeRSDeR
:loop movi phsa, #%1111_0011_0 ' XXX# ___#
waitpne $, #0 ' ######
waitpne $, #0 ' ######
waitpne $, #0 ' ______
jmp #:loop ' ____
:mask long |< pin
fit
Bean's bean [thread=123170]frequency counter[/thread] has been used to verify the generated waveforms.A As in not exercising your brain enough

Comments
-Phil
-Phil
-Phil
CON pin = 16 DAT org 0 [COLOR="blue"]entry_06[/COLOR] mov dira, :mask movs ctra, #pin movi ctra, #%0_00100_000 ' NCO movi frqa, #%0011_0000_0 ' SDeRSDeRSDeRSDeRSDeRSDeRSDeR :loop movi phsa, #%1000_0000_0 ' XXX# ___# nop ' ##__ movi phsa, #%1101_0000_0 ' _### nop ' ___# movi phsa, #%0010_0000_0 ' ##__ jmp #:loop ' _### :mask long |< pin fit-Phil
-Phil
Impressive - can you generalise that, for other divisions ? and include cases where Hi counts can be 1 different from low counts ?
Yes, those small number frequencies that are not easily reached with a simple SW loop make the most sense.
If course, if a general form for higher divides exists that is still small, then > 28+ can still be useful.
No problem. CLKFREQ/3 :
CON pin = 0 DAT org 0 entry_03 mov dira, :mask movs ctra, #pin movi ctra, #%0_00100_000 ' NCO movi frqa, #335 :loop movi phsa, #80 nop jmp #:loop :mask long |< pin fitThe driver allows you to send custom wave forms with a period of 1..32 cycles. Required parameters are period, pin and bit pattern.
In the end it is the most flexible way of sending out (custom) wave forms for this frequency range.
- setup an NCO
- set the top 12bit of frqx to ($1000_0000/period) >> 16
- preset phsx with frqx
- close the loop after period*4 cycles
High time for 2n+1 dividers is n+1, if you need opposite polarity just use a differential NCO and swap the pins. HTH