1.3.2 CLC and NCO

Table 1-4. CLC and NCO Code Calculations
Modules Limit High Resolution
CLC1/2(/3) 65.54 ms 62.5 ns
NCO1

This method uses the NCO and multiple CLCs together.

OVERVIEW

Multiple CLCs can be set up as a pulse detector. Upon software reset, CLC 2 will output a low, which enables the CLC1 AND gate allowing the clock signal through when the pulse is high. When the pulse goes high, HFINTOSC will clock the NCO accumulator. When the pulse goes low, CLC1 outputs a low and stops clocking the NCO accumulator. The pulse width can now be read from the 20-bit wide NCO accumulator registers.

Figure 1-7. CLC and NCO Connections for Measuring a Single Pulse

An important aspect about this setup is that inaccurate measurements can be made if CLC2 is not reset before the rising edge of the pulse, as seen in Figure   2.

Figure 1-8. Unexpected Reset from Software Should Be Avoided when Pulse is High
Figure 1-9. Timing Diagram of the CLC/NCO Pulse Detector (Above)

SETUP

  1. Set up CLC1 as a 4-input AND gate
    1. Input 1 to VDD (invert Gate 1 output)
    2. Input 2 is the pulse to measure
    3. Input 3 is HFINTOSC
    4. Input 4 is the output of CLC2
  2. Set up CLC2 as a D-Flop
    1. Connect ‘D’ to VDD (invert Gate 2 output)
    2. Connect the clock to the pulse pin
    3. Reset connected to gate 3
  3. Set up NCO
    1. Configure the NCO for Fixed Duty Cycle (FDC) mode
    2. Choose an increment value appropriate for the pulse to be measured
  4. To start, enable the NCO module
  5. The detector waits for a high pulse and begins to counts when one is detected
  6. When a low pulse is detected, the detector stops counting
  7. Read pulse width from the accumulator
  8. Repeat steps 3-8

CLC NCO 1 Pulse Setup Operation Code (Steps 4-8)

NCO Setup
    NCO1CON = 0x00;     // Configure NCO for FDC mode (Step 3a) 
    NCO1INCU = 0x0;     // Configure the NCO increment value (Step 3b)
    NCO1INCH = 0x0;
    NCO1INCL = 0x1;                            

Operation Code
    NCO1CONbits.EN = 1;     // Enable NCO to start counting (Step 4 and Step 5)
                            // Wait until pulse low (Step 6)
    NCO1CONbits.EN = 0;     // Disable NCO to stop counting (Step 7)
    NCO_val = ((NCO1ACCH << 8) + NCO1ACCL);   // Save pulse count 
                                              // to NCO_val (Step 8) 

The NCO accumulator value is in terms of the clock source and must be scaled appropriately to find the pulse width. A common solution to this is to create a look-up table with the NCO accumulator value being the offset into it.

Problem 1:

A measured servo pulse is approximately 1 ms to 2 ms wide. Using the NCO accumulator as the counter with a clock input of 16 MHz, what is the corresponding look-up table?

Solution:

Configure the NCO to increment by 1 in FDC mode with CLC1 as its clock source. When the pulse is high, the NCO will increment by 1 every 62.5 ns. After 2 ms, the NCO accumulator will have a value of 32000. Subtract 1 ms from the accumulator value (16000), and then left shift 7 times – essentially divide by 128 in order to create a feasible look-up table of 125 values. Each value now corresponds to 8 μs.

Table 1-5. Look-up Table for Problem 1
Offset Scaled Result
0 <=1 μs
1 1.08 μs
2 1.16 μs
... ...
127 2 ms

A drawback of this method is that it requires a new configuration of the NCO module and look-up table every time the expected pulse width is changed.

Note: Maximum accumulator value is 220. This corresponds to 65.536 ms, if a clock of 16 MHz is used.

A better method will capture only a single pulse which will force the NCO to retain its accumulator value until a Reset is issued. This is useful if the circuit cannot be reset before another pulse arrives, as seen in Figure   2 above.

Figure 1-10. CLC and NCO Connections for Measuring a Single Pulse that Cannot Be Reset During Pulse

On Power-on Reset (POR), CLC2 and CLC3 outputs are both low. CLC1 is inhibited by CLC3 Q low. Upon a Pulse, the following events occur:

  1. Rising edge sets CLC2 Q, enabling CLC1 gate to pass the clock to NCO
  2. Falling edge sets CLC3 Q, disabling CLC1 gate and stocking the clock to NCO. CLC3 Q high is a count ready signal
  3. The system stays in this state until reset

Gate 3 polarity is controlled through a single bit in the CLC Configuration registers for each CLC block (see CLC2_CLC3 Reset API for code implementation). Use this to reset the circuit in this order:

  1. CLC2 reset high - pulse cannot set this while reset is high, Q is low inhibiting CLC1
  2. CLC3 reset high
  3. CLC3 reset low - pulse transition from high-to-low cannot set CLC3 because the D input is held low by CLC2
  4. CLC2 reset low - reset is complete and ready for next pulse

CLC2_CLC3 Reset API

void reset_CLC2_CLC3(void){                                 
    CLCSELECT = 0x1;                      // Select CLC2
    CLCnPOLbits.G3POL = HIGH;             // Set the Gate 3 polarity high
    CLCSELECT = 0x2;                      // Select CLC3
    CLCnPOLbits.G3POL = HIGH;             // Set the Gate 3 polarity high
    CLCnPOLbits.G3POL = LOW;              // Set the Gate 3 polarity low
    CLCSELECT = 0x1;                      // Select CLC2
    CLCnPOLbits.G3POL = LOW;              // Set the Gate 3 polarity low
}

SETUP

  1. Set up CLC1 as a 4-input AND gate
    1. Input 1 to VDD (invert gate 1 output)
    2. Input 2 is the clock source (HFINTOSC)
    3. Input 3 is the CLC2 output
    4. Input 4 is the inverse of CLC3 output
  2. Set up CLC2 as a D-FLOP
    1. Data to VDD (invert gate 2 output)
    2. Clock source is the pulse
    3. Invert Gate 3 to hold in reset. Release this after releasing CLC3 reset when starting pulse measurement
  3. Set up CLC3 as a D-flop
    1. Data is CLC2 output
    2. Clock source is the inverse of the pulse input
    3. Invert Gate 3 to hold in reset. Release this after releasing CLC3 reset when starting pulse measurement
  4. Set up NCO
    1. Configure the NCO for FDC mode
    2. Choose an increment value appropriate for the pulse to be measured

CLC NCO 2 Pulse Setup and Operation Code

NCO Setup
    NCO1CON = 0x00;     // Configure NCO for FDC mode (Step 4a) 
    NCO1INCU = 0x0;     // Configure the NCO Increment value (Step 4b)
    NCO1INCH = 0x0;
    NCO1INCL = 0x1;                         
  
Operation Code              
    reset_CLC2_CLC3();     // Reset CLC2 and CLC3 for new pulse
    NCO1CONbits.EN = 1;    // Enable NCO to start counting
    NCO1CONbits.EN = 0;    // Disable NCO to stop counting
    NCO_val = ((NCO1ACCH << 8) + NCO1ACCL);   // Save pulse count 
                                              // to NCO_val (Step 8)  
     

Division and subtraction is a time consuming process for 8-bit microcontrollers. Because of this, a third method using the CLC and NCO blocks is presented.

Figure 1-11. CLC and NCO Connections to Provide a Normalized Clock for Timer0

This method uses Timer0 multiplexed on the same pin as CLC1 out. The NCO is configured for FDC mode as it was previously, although now the output is used as a clock for Timer0. Since the NCO can produce up to 20 bits of resolution as a linear frequency generator, the look-up table values can be derived directly from the NCO period.

Problem 2:

A measured servo pulse is approximately 0 ms to 1 ms wide. Using Timer0 as the counter, what is the maximum NCO frequency without TMR0 experiencing an undetectable overflow/underflow condition?

Solution:

Calculate the NCO frequency that will scale Timer0 so that a value of 255 corresponds to 1 ms. Configure the NCO for Pulse Frequency Mode. Divide the expected pulse width by the width of Timer0 (1 ms/255 bits). Take the inverse of that to arrive at a frequency of 255 kHz for the NCO.

Equation 1-2. Problem 2 Equation

F o v e r f l o w = ( N C O C l o c k F e q u e n c y * I n c r e m e n t V a l u e ) 2 n

255 k H z = 16 M H z * I n c r e m e n t V a l u e 2 20

Solve Figure   6 for the increment value and the answer is approximately 16711. This will configure the NCO to output a single pulse to clock TMR0 at a rate of 255 kHz. If the timer overflows due to an error in the clock frequency, check the Timer0 interrupt flag and account for the overflow in software.

Table 1-6. Look-up Table for Problem 2
Offset Scaled Result
0 0 ms
1 3.92 μs
2 7.84 μs
... ...
255 1 ms

SETUP

  1. Configure CLC1 out pin as a digital output
  2. Set up CLC1 as 4-input AND gate
    1. Input 2 is VDD (Invert Gate 1 output)
    2. Input 1 is the NCO output
    3. Input 3 is the output from CLC2
    4. Input 4 is the inverse of CLC3 output
  3. Set up CLC2 as D-FLOP
    1. Connect D to VDD (Invert Gate 3 output)
    2. Clock source is the pulse
    3. Invert gate 3 to hold in reset. Release this after releasing CLC3 reset when starting pulse measurement
  4. Set up CLC3 as a D-FLOP
    1. Connect D to CLC2 output
    2. Clock source is the inverse of the pulse
    3. Invert Gate 3 to hold in reset. Release this before releasing CLC2 reset when starting pulse measurement

CLC NCO 3 Pulse Setup and Operation Code

NCO Setup
    NCO1CON = 0x80;      // Configure NCO for FDC mode, and enable NCO 
    NCO1INCU = 0x0;      // Configure the NCO Increment value
    NCO1INCH = 0x82;
    NCO1INCL = 0x8F;                    

TMR0 Setup
    TMR0H = 0xFF;         // Set byte as a comparison for TMR0L (8-bit mode)
    TMR0L = 0x00;         // Clear byte to be able to start counting
    T0CON1 = 0xE0;     // T0CS CLC1_OUT; T0CKPS 1:1; T0ASYNC synchronised;     
    T0CON0 = 0x0;         // T0OUTPS 1:1; T0EN disabled; T016BIT 8-bit; 

Operation Code 
    reset_CLC2_CLC3();    // Reset CLC2 and CLC3 for new pulse
    T0CON0bits.T0EN = 1;  // Enable TMR0 to start counting (increments TMR0L)
    T0CON0bits.T0EN = 0;  // Disable TMR0 to stop counting
    TMR0_val = (TMR0L);   // Save pulse count to TMR0_val

LIMITATIONS

Since the measurement is done in hardware, there is no software overhead with the exception of resetting CLC2 and CLC3 if another pulse measurement is to be made. Uncertainty is minus 0, plus one clock period.