Shop OBEX P1 Docs P2 Docs Learn Events
CTRMODE Confusion — Parallax Forums

CTRMODE Confusion

Jim CJim C Posts: 76
edited 2006-05-31 02:01 in Propeller 1
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

Comments

  • pjvpjv Posts: 1,903
    edited 2006-05-30 01:20
    Hi Jim;

    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)
  • Jim CJim C Posts: 76
    edited 2006-05-30 15:44
    Peter:

    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
  • pjvpjv Posts: 1,903
    edited 2006-05-30 17:41
    Hi Jim;

    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          │
    &#9474; %10110 &#9474; LOGIC A <> B                &#9474;  A¹ <> B¹  &#9474; 0          &#9474; 0          &#9474;
    &#9474; %10111 &#9474; LOGIC !A | !B               &#9474; !A¹ | !B¹  &#9474; 0          &#9474; 0          &#9474;
    &#9474; %11000 &#9474; LOGIC A & B                 &#9474;  A¹ &  B¹  &#9474; 0          &#9474; 0          &#9474;
    &#9474; %11001 &#9474; LOGIC A == B                &#9474; !A¹ == B¹  &#9474; 0          &#9474; 0          &#9474;
    &#9474; %11010 &#9474; LOGIC A                     &#9474;  A¹        &#9474; 0          &#9474; 0          &#9474;
    &#9474; %11011 &#9474; LOGIC A | !B                &#9474;  A¹ | !B¹  &#9474; 0          &#9474; 0          &#9474;
    &#9474; %11100 &#9474; LOGIC B                     &#9474;        B¹  &#9474; 0          &#9474; 0          &#9474;
    &#9474; %11101 &#9474; LOGIC !A | B                &#9474; !A¹ |  B¹  &#9474; 0          &#9474; 0          &#9474;
    &#9474; %11110 &#9474; LOGIC A | B                 &#9474;  A¹ |  B¹  &#9474; 0          &#9474; 0          &#9474;
    &#9474; %11111 &#9474; LOGIC always                &#9474; 1          &#9474; 0          &#9474; 0          &#9474;
    &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9524;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9524;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9524;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9524;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
     * 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
    
    &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;         
    &#9474; PLLDIV &#9474; Output     &#9474;     The PLL modes (%00001..%00011) cause FRQ-to-PHS                
    &#9500;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9508;     accumulation to occur every clock cycle. This                  
    &#9474;  0     &#9474; VCO ÷ 128  &#9474;     creates a numerically-controlled oscillator (NCO)              
    &#9500;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9508;     in PHS[noparse][[/noparse]31], which feeds the CTR PLL's reference              
    &#9474;  1     &#9474; VCO ÷ 64   &#9474;     input. The PLL will multiply this frequency by 16              
    &#9500;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9508;     using its voltage-controlled oscillator (VCO).                 
    &#9474;  2     &#9474; VCO ÷ 32   &#9474;                                                                    
    &#9500;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9508;     For stable operation, it is recommended that the               
    &#9474;  3     &#9474; VCO ÷ 16   &#9474;     VCO frequency be kept within 64 MHz to 128 MHz.                
    &#9500;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9508;     This translates to an NCO frequency of 4 MHz to                
    &#9474;  4     &#9474; VCO ÷ 8    &#9474;     8 MHz.                
    &#9500;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9508;                   
    &#9474;  5     &#9474; VCO ÷ 4    &#9474;     The PLLDIV field of the CTR register selects              
    &#9500;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9508;     which power-of-two division of the VCO frequency                 
    &#9474;  6     &#9474; VCO ÷ 2    &#9474;     will be used as the final PLL output. This
    &#9500;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9508;     affords a PLL range of 500 KHz to 128 MHz.       
    &#9474;  7     &#9474; VCO ÷ 1    &#9474;                                                      
    &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9524;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
     
    

    Cheers,

    Peter (pjv)
  • Jim CJim C Posts: 76
    edited 2006-05-30 17:48
    Peter:

    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
  • pjvpjv Posts: 1,903
    edited 2006-05-30 22:07
    Hi Jim;

    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)
  • Jim CJim C Posts: 76
    edited 2006-05-31 01:14
    Peter:

    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
  • pjvpjv Posts: 1,903
    edited 2006-05-31 02:01
    Hi Jim;

    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)
Sign In or Register to comment.