CTRMODE Confusion
I've been struggling for 'bout a day with CTRA and CTRMODE's. So far, NCO and PLL modes have yielded to dedicated work. And so have the edge-detection modes, when using Spin. However, I would like to speed the edge detection up a bit and would like to use assembly.
If any of the guru's on the forum could look at the attached code and figure out why it does not count number of edges detected, I would appreciated it.
Thanks,
Jim C
If any of the guru's on the forum could look at the attached code and figure out why it does not count number of edges detected, I would appreciated it.
Thanks,
Jim C

Comments
I believe your principal problem is the way you do the comparison. To read a phsx register, it MUST be done as a "source", you have it as a "destination".
Try the modified code:
(''************************************ ''* Hertz driver * ''* * ''************************************ '' '' Updated 5/29/06 '' '' This object starts two oscillators in a new cog '' Pin 7 at 80 KHz CON _CLKMODE = XTAL1 + PLL16X _XINFREQ = 5_000_000 'slow it down to test counter in other cog PUB Start cognew(@_Start,0) DAT org $0 _Start mov dira,#%00000000_00000001_00000000_00100011 'set portbit0, 1 and 5 to output for this COG movi ctra,#%0_00100_111 'set counter mode to NCO single ended movs ctra,#%00000101 'set APIN = portbit5 mov frqa,#1 ' shl frqa,#22 'Set freq on pin 5 to 80 KHz movi ctrb,#%0_01010_111 'Mode to POS Edge detector of Pin A movs ctrb,#%00000101 'set counter > APIN = portbit5 mov frqb,#1 ' set frqb to 1 mov phsb, #0 ' zero phsb :loop xor outa,#1 ' watch pin 1 (***pin 0***)to see if anything is happening here ' cmp phsb, #4 wc 'phsb can only be read as a "source", so a Match variable is required cmp Match,phsb wc ' If_c jmp #:loop 'I believe you intended to loop on no_carry If_nc jmp #:loop 'I believe a slightly simpler appoach is to use the zero for comparison; it gets rid of the one count skew. ' cmp Match,phsb wz 'compare phaseb to Match variable ' if_nz jmp #:Loop 'jump if no match ' xor outa,#2 'toggle P2 (***P1***) if PHSB gets to 6 mov phsb, #0 'reset phsa (***phsb***) counter jmp #:loop 'loop Match long 4 'declare and initialize Match variable)Cheers,
Peter (pjv)
Thanks for the help. The bit about phsa/b needing to be the source with the CMP command was the key. On that note, I reviewed what documentation I could find, and was unable to locate a reference. Can you direct me to info on such like?
You also pointed out an easier way to count and loop, as well as some errors in the documentation. I have included a cleaned up version of the code that incorporates these fixes, and demonstrates operation with LED's on pin 16 and 17 of the demo board. The LED's prove it's working, and an 'scope isn't needed.
Also in the code are 32-bit constant/variables, written all the way out. I keep getting tangled up by bit numbers, and binary, and literals not being full words: writing it all the way out simplifies it for the simple-minded (like me).
Gradually making progress,
Jim C
Glad you got it working!
After a bunch of searching, I located the pertinent documentation. It was by Chip Gracey in the Private Propeller Forum. I don't know how to make a link to that, so all I can do is post it here, and hope not to lose the formatting.
‣‣‣‣‣‣‣‣‣‣‣‣‣‣‣‣ CTRA / CTRB Description Each COG has two counter (CTR) modules. They are named CTRA and CTRB. Each CTR module can control or monitor up to two I/O pins and perform conditional accumulation of its FRQ register into its PHS register on every clock cycle. Each CTR module has its own phase-locked loop (PLL) which can be used to synthesize frequencies up to 128 MHz. With a little oversight from the COG, a CTR can be used for: frequency synthesis frequency measurement pulse counting pulse measurement multi-pin state measurement pulse-width modulation duty-cycle measurement digital-to-analog conversion analog-to-digital conversion ...and probably many other useful things For some of these operations, the COG can "set and forget" a CTR. For others, it may use WAITCNT to time-align CTR reads and writes within a loop, creating the effect of a more complex state machine. The overarching CTR design goal was to create a very simple subsystem which could perform some repetitive task on every clock cycle, thereby freeing the COG to perform some computationally richer super-task. While the operating modes of the CTRs are finite, there is no limit to how they might be used through COG programming. Integral to this concept is the use of the WAITPEQ, WAITPNE, and WAITCNT instructions, which can event-align or time-align the COG with its CTRs. Each CTR has three registers: CTRA / CTRB The CTR register selects the CTR operating mode. As soon as this register is written, the operating mode goes into effect. Writing a zero to CTR will immediately disable the CTR. FRQA / FRQB FRQ holds the value that will be accumulated into the PHS register. For some applications, FRQ may be written once, and then ignored. For others, it may be rapidly modulated. PHSA / PHSB The PHS register is the oddest of all COG registers. Not only can it be written and read via COG instructions, but it also functions as a free-running accumulator, summing the FRQ register into itself on potentially every clock cycle. Any instruction writing to PHS will override any accumulation for that clock cycle. PHS can only be read through the source operand (same as PAR, CNT, INA, and INB). Doing a read-modify-write instruction on PHS (ie ADD PHSA,#1) will cause the last-written value to be used as the destination operand input, rather than the current accumulation. CTRA / CTRB registers ┌────┬─────────┬────────┬────────┬───────┬──────┬──────┐ Bits │ 31 │ 30..26 │ 25..23 │ 22..15 │ 14..9 │ 8..6 │ 5..0 │ ├────┼─────────┼────────┼────────┼───────┼──────┼──────┤ Name │ ── │ CTRMODE │ PLLDIV │ ────── │ BPIN │ ──── │ APIN │ └────┴─────────┴────────┴────────┴───────┴──────┴──────┘ CTRMODE selects one of 32 operating modes for the CTR - conveniently written (along with PLLDIV) using the MOVI instruction PLLDIV selects a PLL output tap - may be ignored if not used BPIN selects a pin to be the secondary I/O - may be ignored if not used - %0xxxxx = Port A, %1xxxxx = Port B (future) - conveniently written using the MOVD instruction APIN selects a pin to be the primary I/O - may be ignored if not used - %0xxxxx = Port A, %1xxxxx = Port B (future) - conveniently written using the MOVS instruction Accumulate APIN BPIN CTRMODE Description FRQ to PHS output* output* ┌────────┬─────────────────────────────┬────────────┬────────────┬────────────┐ │ %00000 │ Counter disabled (off) │ 0 (never) │ 0 (none) │ 0 (none) │ ├────────┼─────────────────────────────┼────────────┼────────────┼────────────┤ │ %00001 │ PLL internal (video mode) │ 1 (always) │ 0 │ 0 │ │ %00010 │ PLL single-ended │ 1 ¦│ PLL │ 0 │ │ %00011 │ PLL differential │ 1 │ PLL │ !PLL │ ├────────┼─────────────────────────────┼────────────┼────────────┼────────────┤ │ %00100 │ NCO/PWM single-ended │ 1 │ PHS[noparse][[/noparse]31] │ 0 │ │ %00101 │ NCO/PWM differential │ 1 │ PHS[noparse][[/noparse]31] │ !PHS[noparse][[/noparse]31] │ ├────────┼─────────────────────────────┼────────────┼────────────┼────────────┤ │ %00110 │ DUTY single-ended │ 1 │ PHS-Carry │ 0 │ │ %00111 │ DUTY differential │ 1 │ PHS-Carry │ !PHS-Carry │ ├────────┼─────────────────────────────┼────────────┼────────────┼────────────┤ │ %01000 │ POS detector │ A¹ │ 0 │ 0 │ │ %01001 │ POS detector w/feedback │ A¹ │ 0 │ !A¹ │ │ %01010 │ POSEDGE detector │ A¹ & !A² │ 0 │ 0 │ │ %01011 │ POSEDGE detector w/feedback │ A¹ & !A² │ 0 │ !A¹ │ ├────────┼─────────────────────────────┼────────────┼────────────┼────────────┤ │ %01100 │ NEG detector │ !A¹ │ 0 │ 0 │ │ %01101 │ NEG detector w/feedback │ !A¹ │ 0 │ !A¹ │ │ %01110 │ NEGEDGE detector │ !A¹ & A² │ 0 │ 0 │ │ %01111 │ NEGEDGE detector w/feedback │ !A¹ & A² │ 0 │ !A¹ │ ├────────┼─────────────────────────────┼────────────┼────────────┼────────────┤ │ %10000 │ LOGIC never │ 0 │ 0 │ 0 │ │ %10001 │ LOGIC !A & !B │ !A¹ & !B¹ │ 0 │ 0 │ │ %10010 │ LOGIC A & !B │ A¹ & !B¹ │ 0 │ 0 │ │ %10011 │ LOGIC !B │ !B¹ │ 0 │ 0 │ │ %10100 │ LOGIC !A & B │ !A¹ & B¹ │ 0 │ 0 │ │ %10101 │ LOGIC !A │ !A¹ │ 0 │ 0 │ │ %10110 │ LOGIC A <> B │ A¹ <> B¹ │ 0 │ 0 │ │ %10111 │ LOGIC !A | !B │ !A¹ | !B¹ │ 0 │ 0 │ │ %11000 │ LOGIC A & B │ A¹ & B¹ │ 0 │ 0 │ │ %11001 │ LOGIC A == B │ !A¹ == B¹ │ 0 │ 0 │ │ %11010 │ LOGIC A │ A¹ │ 0 │ 0 │ │ %11011 │ LOGIC A | !B │ A¹ | !B¹ │ 0 │ 0 │ │ %11100 │ LOGIC B │ B¹ │ 0 │ 0 │ │ %11101 │ LOGIC !A | B │ !A¹ | B¹ │ 0 │ 0 │ │ %11110 │ LOGIC A | B │ A¹ | B¹ │ 0 │ 0 │ │ %11111 │ LOGIC always │ 1 │ 0 │ 0 │ └────────┴─────────────────────────────┴────────────┴────────────┴────────────┘ * must set corresponding DIR bit to affect pin A¹ = APIN input delayed by 1 clock A² = APIN input delayed by 2 clocks B¹ = BPIN input delayed by 1 clock ┌────────┬────────────┐ │ PLLDIV │ Output │ The PLL modes (%00001..%00011) cause FRQ-to-PHS ├────────┼────────────┤ accumulation to occur every clock cycle. This │ 0 │ VCO ÷ 128 │ creates a numerically-controlled oscillator (NCO) ├────────┼────────────┤ in PHS[noparse][[/noparse]31], which feeds the CTR PLL's reference │ 1 │ VCO ÷ 64 │ input. The PLL will multiply this frequency by 16 ├────────┼────────────┤ using its voltage-controlled oscillator (VCO). │ 2 │ VCO ÷ 32 │ ├────────┼────────────┤ For stable operation, it is recommended that the │ 3 │ VCO ÷ 16 │ VCO frequency be kept within 64 MHz to 128 MHz. ├────────┼────────────┤ This translates to an NCO frequency of 4 MHz to │ 4 │ VCO ÷ 8 │ 8 MHz. ├────────┼────────────┤ │ 5 │ VCO ÷ 4 │ The PLLDIV field of the CTR register selects ├────────┼────────────┤ which power-of-two division of the VCO frequency │ 6 │ VCO ÷ 2 │ will be used as the final PLL output. This ├────────┼────────────┤ affords a PLL range of 500 KHz to 128 MHz. │ 7 │ VCO ÷ 1 │ └────────┴────────────┘Cheers,
Peter (pjv)
In the attached document, there seemed to be one pertinent section about phsa:
>>PHSA / PHSB
The PHS register is the oddest of all COG registers. Not only can it be written
and read via COG instructions, but it also functions as a free-running
accumulator, summing the FRQ register into itself on potentially every clock
cycle. Any instruction writing to PHS will override any accumulation for that
clock cycle. PHS can only be read through the source operand (same as PAR, CNT,
INA, and INB). Doing a read-modify-write instruction on PHS (ie ADD PHSA,#1)
will cause the last-written value to be used as the destination operand input,
rather than the current accumulation.<<
I understand how a 'read-modify-write' instruction using phsx as the destination would result in a modified phsx. But, using the CMP instruction, which leaves the destination unchanged, shouldn't have modified the destination. So, why didn't the CMP work with phsx as the destination?
Thanks,
Jim C
As I'm not schooled in the inner workings of the Propeller, we'll have to leave that to Chip to answer when he has time. There are several registers that behave this way.
Cheers,
Peter (pjv)
If you could pass this question along, such that it winds up in a FAQ or assembly language manual, that would be great.
Thanks for your help.
Jim C
Like yourself, I have no "inside track" to the folks at Parallax, so the passing along is just as well done by yourself. That said, hopefully this interchange will be read by them, and nothing further needs to be done.
You could try a PM to Jeff Martin...... busy guy though!
Cheers,
Peter (pjv)