How to correctly configuring a CTMU module to respond to positive edge triggers

Thread Starter

Mellowed

Joined Mar 6, 2016
13
Hi, I am currently having issues configure the CTMU module in a PIC18F46K80 to respond to edges.

I am trying to measure the delay between two pulses produced by two "single photon counting module" which are connected to the CTED1 and CTED2 pins. The module can produce a new TTL signal every 62.7ns which is 35ns long. I don't mind having deadtime between new measurements (Fig1) however i can't afford to have the CTMUCONLbits.EDGE1STAT triggering if the CTMU is enabled whilst the input is active (Fig2) i would rather it waited for the next rising edge.

I have configured the following
CTMUCONH 0b10001100 // Edges are not blocked and edge1 must occur before edge2
CTMUCONL 0b11011100 //edges programmed for positive edge response and CTED1 & CTED2 connected

This config doesn't seem to work, do i miss understand the "positive edge response" settings or are they specific to the special event triggers ECCP1 & CCP2?

My code is also attached. Currently i'm using coax cable to perform tests and the input signal is generated on chip and my current resolution is around 120ps. I am testing this problem by keeping CTED1/edge1 active which should result in edge1&2 not triggering due to no rising edge being produced.

I found this data sheet for the pic24xx http://ww1.microchip.com/downloads/en/DeviceDoc/39743a.pdf which suggests it has an "EDGxMOD: Input mode selection bit" not offered on the pic18xx :(

Fig1
upload_2016-4-13_21-27-43.png

Fig2
upload_2016-4-13_21-34-38.png

C:
#include <xc.h>
#define _XTAL_FREQ 16000000
#define TRUE 1
#define FALSE 0
#define LEDs PORTA
#define LED1 PORTAbits.RA2
#define COUNT  2 //500 //@ 8MHz = 125uS.
#define DELAY for(i=0;i<COUNT;i++)

//#define RCAL 19950 //R value is 19.95Kohm 19950
#define RCAL 1496000 //R value is 19.95Kohm 19950
//scaled so that result is in
//1/100th of uA
#define ADSCALE 4096 //for unsigned conversion 10 sig bits
#define ADREF 2
#define Current3 80 // current was calibrated to 80uA
#define Current1 0.28 // current was calibrated to 0.28uA
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <usart.h>
#include <plib.h>
#include <delays.h>
#include <sw_uart.h>


void IO_ports_init(void)
{
TRISA = 0x00;           //set as output
PORTA = 0x00;
TRISB = 0;
TRISD = 0;
TRISC = 0;
//PORTB = 0;

TRISBbits.TRISB2 =1;            // input for CTMU 1 edge
TRISBbits.TRISB3=1;            // input for CTMU 2 edge


//LATB = 0;
//--ADC
TRISBbits.TRISB0 = 1;   //set channel 10 as an input
PORTAbits.RA0 = 0;
LATAbits.LATA0 = 0;
//--UART
TRISCbits.TRISC6 = 0; // RC6  (TX1)
TRISCbits.TRISC7 = 1; //RC7  (RX1)
PORTC=0x00;
PORTD=0x00;

SLRCON = 0x00;
CTMUCONH = 0x00;

RCONbits.IPEN = 1;
INTCONbits.GIEH = 1;
}
void USART_init(void){
    TXSTA1 = 0b10100100;
    SPBRG1 = 103;
}
void OscillatorConfig(void){
OSCCON = 0b01111100;
OSCCON2 = 0b00010010;
}

void delayMsx(int time){
  
for(int x = 0; x < time; x++){
        __delay_ms(1);
}
}

void delayUsx(int time){
  
for(int x = 0; x < time; x++){
        __delay_us(1);
}
}


void ADCConfig(void){
ANCON1 = 3;

ADCON2bits.ADFM=1; // Result format 1= Right justified
ADCON2bits.ACQT=1; // Acquisition time 7 = 20TAD 2 = 4TAD 1=2TAD
ADCON2bits.ADCS=2; // Clock conversion bits 6= FOSC/64 2=FOSC/32
ADCON1bits.TRIGSEL=1;

ADCON1bits.VCFG0 =0; // Vref+ = AVdd
ADCON1bits.VCFG =2; // Vref+ = AVdd
ADCON1bits.VNCFG = 0; // Vref- = AVss
ADCON0bits.CHS=28; // Select ADC channel
ADCON0bits.ADON=0; // Turn on ADC     
}

void CTMUInit (void){

CTMUCONH = 0; //make sure CTMU is disabled
CTMUCONHbits.EDGEN=1;        // edge are not blocked 1 edges are blocked with 0
CTMUCONHbits.EDGSEQEN=1;    // edge 1 then 2 for interrupt
CTMUCONHbits.CTTRIG=1;

CTMUCONL = 0b11011100;  // CTMU trigger setup : net edge 1, neg edge 2, edge 1&2 source select CTED 1&2, clear event bits
CTMUICON = 0b01111111; // 1= base current 0.55uA  2= 5.5uA   3=55uA // max positive trim

//INTCON = 0b11100000;
//INTCON2 = 0b11111000;
//INTCON3 = 0b00000000;
}


void CTMU (void){
int Vread;
ADCON0bits.CHS=10;
CTMUCONHbits.CTMUEN = 0;
CTMUCONL = 0b11011100;

LEDs = 0;
CTMUCONHbits.IDISSEN = 1; //drain charge on the circuit
    __delay_us(30);
CTMUCONHbits.IDISSEN = 0; //end drain of circuit
CTMUCONHbits.CTMUEN = 1;
__delay_us(5);                                      // something is wrong here
LEDs = 255;
LEDs = 0;

__delay_us(5);

ADCON0bits.ADON=1;
__delay_us(5);
PIR1bits.ADIF = 0; //make sure A/D Interupt not set
ADCON0bits.GO=1; //and begin A/D conv.
while(!PIR1bits.ADIF); //Wait for A/D convert complete
Vread = ADRES; //Get the value from the A/D
PIR1bits.ADIF = 0; //Clear A/D Interrupt Flag
ADCON0bits.CHS=28;  // disconnect the mux
char ac_sample_char[12];
char spacer[5];

sprintf(spacer, "   ");
if(Vread > 10){
sprintf(spacer, "  ");
    if(Vread > 100){
    sprintf(spacer, " ");
        if(Vread > 1000){
        sprintf(spacer, "");
        }
    }
}
sprintf(ac_sample_char, "%02d %s - CT1:%01d CT2:%01d E1:%01d E2:%01d", Vread, spacer , PORTBbits.RB2, PORTBbits.RB3 ,CTMUCONLbits.EDG1STAT, CTMUCONLbits.EDG2STAT);

puts1USART(ac_sample_char);
putrs1USART(" \n\r");


}


void CTMU1 (void){

int Vread;
CTMUCONHbits.CTMUEN = 0;


PIR1bits.ADIF = 0; //make sure A/D Interupt not set
ADCON0bits.GO=1; //and begin A/D conv.
while(!PIR1bits.ADIF); //Wait for A/D convert complete
Vread = ADRES; //Get the value from the A/D
PIR1bits.ADIF = 0; //Clear A/D Interrupt Flag

char ac_sample_char[12];
char spacer[5];

if(Vread > 10){
sprintf(spacer, "  ");
    if(Vread > 100){
    sprintf(spacer, " ");
        if(Vread > 1000){
        sprintf(spacer, "");
        }
    }
}

sprintf(ac_sample_char, "%02d %s - CT1:%01d CT2:%01d E1:%01d E2:%01d", Vread, spacer , PORTBbits.RB2, PORTBbits.RB3 ,CTMUCONLbits.EDG1STAT, CTMUCONLbits.EDG2STAT);

puts1USART(ac_sample_char);
putrs1USART(" \n\r");

CTMUCONHbits.IDISSEN = 1; //drain charge on the circuit
    __delay_us(1);
CTMUCONHbits.IDISSEN = 0; //end drain of circuit

CTMUCONL = 0b11011100;
CTMUCONHbits.CTMUEN = 1;
}




void CurrentCalibration (void){
  
int i;
int j = 0; //index for loop
int Vread = 0;
double VTot = 0;
double Vavg=0, Vcal=0, CTMUISrc = 0;

CTMUCONHbits.CTMUEN = 1; //Enable the CTMU
CTMUCONHbits.IDISSEN = 1; //drain charge on the circuit
__delay_ms(1); //wait 125us
CTMUCONHbits.IDISSEN = 0; //end drain of circuit
CTMUCONLbits.EDG1STAT = 1; //Begin charging the circuit
for(j=0;j<10;j++)
{
delayMsx(100);  //wait for 125us
PIR1bits.ADIF = 0; //make sure A/D Interupt not set
ADCON0bits.GO=1; //and begin A/D conv.
while(!PIR1bits.ADIF); //Wait for A/D convert complete
Vread = ADRES; //Get the value from the A/D
PIR1bits.ADIF = 0; //Clear A/D Interrupt Flag
VTot = VTot + Vread; //Add the reading to the total
}
CTMUCONLbits.EDG1STAT = 0; //Stop charging circuit
CTMUCONHbits.CTMUEN = 0; //Enable the CTMU
Vavg = (double)(VTot/10); //Average of 10 readings
Vcal = 0.0004882812;
Vcal = (double)Vcal*Vavg;
CTMUISrc = (double)Vcal/RCAL; //CTMUISrc is in 1/100ths of uA
CTMUISrc = CTMUISrc*1000000;    // current in uA

char ac_sample_char[12];

sprintf(ac_sample_char, "%0.1f Vavg : %0.3f Voltage : %0.2f CTMUISrc ", Vavg,Vcal,CTMUISrc );

puts1USART(ac_sample_char);
putrs1USART(" \n\r"); 
}

void CapacitanceCalibration (void){
  
  int i;
int j = 0; //index for loop
int Vread = 0;
float CTMUISrc, CTMUCap, Vavg, VTot, Vcal;
//assume CTMU and A/D have been setup correctly
//see Example 25-1 for CTMU & A/D setup

CTMUCONHbits.CTMUEN = 1; //Enable the CTMU
for(j=0;j<10;j++)
{
CTMUCONHbits.IDISSEN = 1; //drain charge on the circuit
delayUsx(125); //wait 125us
CTMUCONHbits.IDISSEN = 0; //end drain of circuit
CTMUCONLbits.EDG1STAT = 1; //Begin charging the circuit
//using CTMU current source
delayUsx(12); //wait 125us
CTMUCONLbits.EDG1STAT = 0; //Stop charging circuit

PIR1bits.ADIF = 0; //make sure A/D Int not set
ADCON0bits.GO=1; //and begin A/D conv.
while(!PIR1bits.ADIF); //Wait for A/D convert complete
Vread = ADRES; //Get the value from the A/D
PIR1bits.ADIF = 0; //Clear A/D Interrupt Flag
VTot += Vread; //Add the reading to the total
}

Vavg = (double)(VTot/10.000); //Average of 10 readings
Vcal = 0.0004882812;
Vcal = (double)Vcal*Vavg;
CTMUISrc = 0.28; //CTMUISrc is in 1/100ths of uA
CTMUCap = (double)(CTMUISrc*12/Vcal);

char ac_sample_char[12];

sprintf(ac_sample_char, "%0.1f Vavg : %0.3f Voltage : %0.2f CTMUCap ", Vavg,Vcal,CTMUCap );

puts1USART(ac_sample_char);
putrs1USART(" \n\r"); 
  
}

void interrupt isr(void)
{
    if (PIR3bits.CTMUIF) {                                // the current source has been on and then turned off by the edge detect inputs
        int Vread;

                ADCON0bits.GO=1;                                 // and begin A/D conv, will set adc int flag when done.
                PIR3bits.CTMUIF=0;                                // clear CTMU interrupt flag

                PIR1bits.ADIF = 0; //make sure A/D Interupt not set
                ADCON0bits.GO=1; //and begin A/D conv.
                while(!PIR1bits.ADIF); //Wait for A/D convert complete
                Vread = ADRES; //Get the value from the A/D
                PIR1bits.ADIF = 0; //Clear A/D Interrupt Flag

                char ac_sample_char[12];
                char spacer[5];

                if(Vread > 10){
                sprintf(spacer, "  ");
                    if(Vread > 100){
                    sprintf(spacer, " ");
                        if(Vread > 1000){
                        sprintf(spacer, "");
                        }
                    }
                }
              
              
                sprintf(ac_sample_char, "%02d %s - CT1:%01d CT2:%01d E1:%01d E2:%01d", Vread, spacer , PORTBbits.RB2, PORTBbits.RB3 ,CTMUCONLbits.EDG1STAT, CTMUCONLbits.EDG2STAT);

                puts1USART(ac_sample_char);
                putrs1USART(" \n\r");
    }




  
  
  
}


void adcwait(void)
{
  
    int count = 0;
  
    if (count > 100){
    CTMUCONHbits.CTMUEN = 0;
  
    }
      
char ac_sample_char[12];
int Vread;
if(PIR1bits.ADIF){

CTMUCONHbits.CTMUEN = 0;
CTMUCONL = 0b11011100;
Vread = ADRES; //Get the value from the A/D
PIR1bits.ADIF = 0; //Clear A/D Interrupt Flag

char ac_sample_char[12];
char spacer[5];
if(Vread > 10){
sprintf(spacer, "  ");
    if(Vread > 100){
    sprintf(spacer, " ");
        if(Vread > 1000){
        sprintf(spacer, "");
        }
    }
}
sprintf(ac_sample_char, "%02d %s - CT1:%01d CT2:%01d E1:%01d E2:%01d", Vread, spacer , PORTBbits.RB2, PORTBbits.RB3 ,CTMUCONLbits.EDG1STAT, CTMUCONLbits.EDG2STAT);

puts1USART(ac_sample_char);
putrs1USART(" \n\r");

CTMUCONHbits.IDISSEN = 1; //drain charge on the circuit
    __delay_us(1);
CTMUCONHbits.IDISSEN = 0; //end drain of circuit
PIR1bits.ADIF = 0;
}



CTMUCONL = 0b11011100;
CTMUCONHbits.CTMUEN = 1;
//PIR1bits.ADIF = 0;
}



/*******************************************/
void main(void) {
OscillatorConfig();
IO_ports_init();
USART_init();

ADCConfig();
CTMUInit();

BAUDCON1bits.BRG16 = 1;
Open1USART(USART_TX_INT_OFF & USART_RX_INT_OFF & USART_ASYNCH_MODE & USART_CONT_RX & USART_BRGH_HIGH, 68); //103 for 16 mhz 51 for 8mhz

RCONbits.IPEN = 1;
INTCONbits.GIEL = 0;
INTCONbits.GIEH = 1;
CTMUCONHbits.CTMUEN = 1;
putrs1USART("Starting \n\r");
    while(1)
    {
//  putrs1USART("Doing measurement: "); 
  CTMU();
delayMsx(1000);
LEDs = 0;
// adcwait();
    }
}
 

nsaspook

Joined Aug 27, 2009
6,729
I can see where actual edge synchronization is a problem.
18.2.3 EDGE SELECTION AND CONTROL CTMU measurements are controlled by edge events occurring on the module’s two input channels. Each channel, referred to as Edge 1 and Edge 2, can be configured to receive input pulses from one of the edge input pins (CTED1 and CTED2) or CCPx Special Event Triggers (ECCP1 and CCP2). The input channels are level-sensitive, responding to the instantaneous level on the channel rather than a transition between levels. The inputs are selected using the EDG1SEL and EDG2SEL bit pairs (CTMUCONL<3:2>, 6:5>).
You might try to monitor the condition of CTED1 to be sure it makes a high to low transition (or is just low) before clearing the EDGxSTAT bits and enabling edge detection again before repeated event measurements.
 

Thread Starter

Mellowed

Joined Mar 6, 2016
13
Thanks nsaspook!

I'm a little confused about the Edge selection, what purpose does it serve then?

Also since my signal is potentially repeating every 67ns and the pic is running at 64Mhz (thats an instruction every 63ns), would it even be possible to check the CTED1 is low before enabling the CTMU module?
 

nsaspook

Joined Aug 27, 2009
6,729
At the full data rate your're right, there's no time for a proper software measurement trigger sequence from monitoring data levels.

You can always use a little high speed glue logic to make edge detectors for the CTMU inputs to narrow the false detection window. By using identical circuits on both inputs the AND gate delays will be matched.

Implementing this timing function with semiconductor components is actually quite easy, as it exploits the inherent time delay within every logic gate (known as propagation delay). What we do is take an input signal and split it up two ways, then place a gate or a series of gates in one of those signal paths just to delay it a bit, then have both the original signal and its delayed counterpart enter into a two-input gate that outputs a high signal for the brief moment of time that the delayed signal has not yet caught up to the low-to-high change in the non-delayed signal. An example circuit for producing a clock pulse on a low-to-high input signal transition is shown here:
http://www.allaboutcircuits.com/textbook/digital/chpt-10/edge-triggered-latches-flip-flops/
 
Last edited:

dannyf

Joined Sep 13, 2015
2,197
Also since my signal is potentially repeating every 67ns and the pic is running at 64Mhz (thats an instruction every 63ns), would it even be possible to check the CTED1 is low before enabling the CTMU module?
That should have been asked before you attempted anything else.
 
Top