1.3.2 CLC and NCO
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.
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.
SETUP
- Set up CLC1 as a 4-input AND
gate
- Input 1 to VDD (invert Gate 1 output)
- Input 2 is the pulse to measure
- Input 3 is HFINTOSC
- Input 4 is the output of CLC2
- Set up CLC2 as a D-Flop
- Connect ‘D’ to VDD (invert Gate 2 output)
- Connect the clock to the pulse pin
- Reset connected to gate 3
- Set up NCO
- Configure the NCO for Fixed Duty Cycle (FDC) mode
- Choose an increment value appropriate for the pulse to be measured
- To start, enable the NCO module
- The detector waits for a high pulse and begins to counts when one is detected
- When a low pulse is detected, the detector stops counting
- Read pulse width from the accumulator
- 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.
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.
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.
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:
- Rising edge sets CLC2 Q, enabling CLC1 gate to pass the clock to NCO
- Falling edge sets CLC3 Q, disabling CLC1 gate and stocking the clock to NCO. CLC3 Q high is a count ready signal
- 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:
- CLC2 reset high - pulse cannot set this while reset is high, Q is low inhibiting CLC1
- CLC3 reset high
- CLC3 reset low - pulse transition from high-to-low cannot set CLC3 because the D input is held low by CLC2
- 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
- Set up CLC1 as a 4-input AND
gate
- Input 1 to VDD (invert gate 1 output)
- Input 2 is the clock source (HFINTOSC)
- Input 3 is the CLC2 output
- Input 4 is the inverse of CLC3 output
- Set up CLC2 as a D-FLOP
- Data to VDD (invert gate 2 output)
- Clock source is the pulse
- Invert Gate 3 to hold in reset. Release this after releasing CLC3 reset when starting pulse measurement
- Set up CLC3 as a D-flop
- Data is CLC2 output
- Clock source is the inverse of the pulse input
- Invert Gate 3 to hold in reset. Release this after releasing CLC3 reset when starting pulse measurement
- Set up NCO
- Configure the NCO for FDC mode
- 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.
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.
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.
Offset | Scaled Result |
---|---|
0 | 0 ms |
1 | 3.92 μs |
2 | 7.84 μs |
... | ... |
255 | 1 ms |
SETUP
- Configure CLC1 out pin as a digital output
- Set up CLC1 as 4-input AND
gate
- Input 2 is VDD (Invert Gate 1 output)
- Input 1 is the NCO output
- Input 3 is the output from CLC2
- Input 4 is the inverse of CLC3 output
- Set up CLC2 as D-FLOP
- Connect D to VDD (Invert Gate 3 output)
- Clock source is the pulse
- Invert gate 3 to hold in reset. Release this after releasing CLC3 reset when starting pulse measurement
- Set up CLC3 as a D-FLOP
- Connect D to CLC2 output
- Clock source is the inverse of the pulse
- 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.