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

Discussion in 'Embedded Systems and Microcontrollers' started by Mellowed, Apr 13, 2016.

  1. Mellowed

    Thread Starter New Member

    Mar 6, 2016
    10
    2
    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

    Code (C):
    1. #include <xc.h>
    2. #define _XTAL_FREQ 16000000
    3. #define TRUE 1
    4. #define FALSE 0
    5. #define LEDs PORTA
    6. #define LED1 PORTAbits.RA2
    7. #define COUNT  2 //500 //@ 8MHz = 125uS.
    8. #define DELAY for(i=0;i<COUNT;i++)
    9.  
    10. //#define RCAL 19950 //R value is 19.95Kohm 19950
    11. #define RCAL 1496000 //R value is 19.95Kohm 19950
    12. //scaled so that result is in
    13. //1/100th of uA
    14. #define ADSCALE 4096 //for unsigned conversion 10 sig bits
    15. #define ADREF 2
    16. #define Current3 80 // current was calibrated to 80uA
    17. #define Current1 0.28 // current was calibrated to 0.28uA
    18. #include <conio.h>
    19. #include <stdio.h>
    20. #include <stdlib.h>
    21. #include <string.h>
    22. #include <math.h>
    23. #include <time.h>
    24. #include <usart.h>
    25. #include <plib.h>
    26. #include <delays.h>
    27. #include <sw_uart.h>
    28.  
    29.  
    30. void IO_ports_init(void)
    31. {
    32. TRISA = 0x00;           //set as output
    33. PORTA = 0x00;
    34. TRISB = 0;
    35. TRISD = 0;
    36. TRISC = 0;
    37. //PORTB = 0;
    38.  
    39. TRISBbits.TRISB2 =1;            // input for CTMU 1 edge
    40. TRISBbits.TRISB3=1;            // input for CTMU 2 edge
    41.  
    42.  
    43. //LATB = 0;
    44. //--ADC
    45. TRISBbits.TRISB0 = 1;   //set channel 10 as an input
    46. PORTAbits.RA0 = 0;
    47. LATAbits.LATA0 = 0;
    48. //--UART
    49. TRISCbits.TRISC6 = 0; // RC6  (TX1)
    50. TRISCbits.TRISC7 = 1; //RC7  (RX1)
    51. PORTC=0x00;
    52. PORTD=0x00;
    53.  
    54. SLRCON = 0x00;
    55. CTMUCONH = 0x00;
    56.  
    57. RCONbits.IPEN = 1;
    58. INTCONbits.GIEH = 1;
    59. }
    60. void USART_init(void){
    61.     TXSTA1 = 0b10100100;
    62.     SPBRG1 = 103;
    63. }
    64. void OscillatorConfig(void){
    65. OSCCON = 0b01111100;
    66. OSCCON2 = 0b00010010;
    67. }
    68.  
    69. void delayMsx(int time){
    70.  
    71. for(int x = 0; x < time; x++){
    72.         __delay_ms(1);
    73. }
    74. }
    75.  
    76. void delayUsx(int time){
    77.  
    78. for(int x = 0; x < time; x++){
    79.         __delay_us(1);
    80. }
    81. }
    82.  
    83.  
    84. void ADCConfig(void){
    85. ANCON1 = 3;
    86.  
    87. ADCON2bits.ADFM=1; // Result format 1= Right justified
    88. ADCON2bits.ACQT=1; // Acquisition time 7 = 20TAD 2 = 4TAD 1=2TAD
    89. ADCON2bits.ADCS=2; // Clock conversion bits 6= FOSC/64 2=FOSC/32
    90. ADCON1bits.TRIGSEL=1;
    91.  
    92. ADCON1bits.VCFG0 =0; // Vref+ = AVdd
    93. ADCON1bits.VCFG =2; // Vref+ = AVdd
    94. ADCON1bits.VNCFG = 0; // Vref- = AVss
    95. ADCON0bits.CHS=28; // Select ADC channel
    96. ADCON0bits.ADON=0; // Turn on ADC    
    97. }
    98.  
    99. void CTMUInit (void){
    100.  
    101. CTMUCONH = 0; //make sure CTMU is disabled
    102. CTMUCONHbits.EDGEN=1;        // edge are not blocked 1 edges are blocked with 0
    103. CTMUCONHbits.EDGSEQEN=1;    // edge 1 then 2 for interrupt
    104. CTMUCONHbits.CTTRIG=1;
    105.  
    106. CTMUCONL = 0b11011100;  // CTMU trigger setup : net edge 1, neg edge 2, edge 1&2 source select CTED 1&2, clear event bits
    107. CTMUICON = 0b01111111; // 1= base current 0.55uA  2= 5.5uA   3=55uA // max positive trim
    108.  
    109. //INTCON = 0b11100000;
    110. //INTCON2 = 0b11111000;
    111. //INTCON3 = 0b00000000;
    112. }
    113.  
    114.  
    115. void CTMU (void){
    116. int Vread;
    117. ADCON0bits.CHS=10;
    118. CTMUCONHbits.CTMUEN = 0;
    119. CTMUCONL = 0b11011100;
    120.  
    121. LEDs = 0;
    122. CTMUCONHbits.IDISSEN = 1; //drain charge on the circuit
    123.     __delay_us(30);
    124. CTMUCONHbits.IDISSEN = 0; //end drain of circuit
    125. CTMUCONHbits.CTMUEN = 1;
    126. __delay_us(5);                                      // something is wrong here
    127. LEDs = 255;
    128. LEDs = 0;
    129.  
    130. __delay_us(5);
    131.  
    132. ADCON0bits.ADON=1;
    133. __delay_us(5);
    134. PIR1bits.ADIF = 0; //make sure A/D Interupt not set
    135. ADCON0bits.GO=1; //and begin A/D conv.
    136. while(!PIR1bits.ADIF); //Wait for A/D convert complete
    137. Vread = ADRES; //Get the value from the A/D
    138. PIR1bits.ADIF = 0; //Clear A/D Interrupt Flag
    139. ADCON0bits.CHS=28;  // disconnect the mux
    140. char ac_sample_char[12];
    141. char spacer[5];
    142.  
    143. sprintf(spacer, "   ");
    144. if(Vread > 10){
    145. sprintf(spacer, "  ");
    146.     if(Vread > 100){
    147.     sprintf(spacer, " ");
    148.         if(Vread > 1000){
    149.         sprintf(spacer, "");
    150.         }
    151.     }
    152. }
    153. sprintf(ac_sample_char, "%02d %s - CT1:%01d CT2:%01d E1:%01d E2:%01d", Vread, spacer , PORTBbits.RB2, PORTBbits.RB3 ,CTMUCONLbits.EDG1STAT, CTMUCONLbits.EDG2STAT);
    154.  
    155. puts1USART(ac_sample_char);
    156. putrs1USART(" \n\r");
    157.  
    158.  
    159. }
    160.  
    161.  
    162. void CTMU1 (void){
    163.  
    164. int Vread;
    165. CTMUCONHbits.CTMUEN = 0;
    166.  
    167.  
    168. PIR1bits.ADIF = 0; //make sure A/D Interupt not set
    169. ADCON0bits.GO=1; //and begin A/D conv.
    170. while(!PIR1bits.ADIF); //Wait for A/D convert complete
    171. Vread = ADRES; //Get the value from the A/D
    172. PIR1bits.ADIF = 0; //Clear A/D Interrupt Flag
    173.  
    174. char ac_sample_char[12];
    175. char spacer[5];
    176.  
    177. if(Vread > 10){
    178. sprintf(spacer, "  ");
    179.     if(Vread > 100){
    180.     sprintf(spacer, " ");
    181.         if(Vread > 1000){
    182.         sprintf(spacer, "");
    183.         }
    184.     }
    185. }
    186.  
    187. sprintf(ac_sample_char, "%02d %s - CT1:%01d CT2:%01d E1:%01d E2:%01d", Vread, spacer , PORTBbits.RB2, PORTBbits.RB3 ,CTMUCONLbits.EDG1STAT, CTMUCONLbits.EDG2STAT);
    188.  
    189. puts1USART(ac_sample_char);
    190. putrs1USART(" \n\r");
    191.  
    192. CTMUCONHbits.IDISSEN = 1; //drain charge on the circuit
    193.     __delay_us(1);
    194. CTMUCONHbits.IDISSEN = 0; //end drain of circuit
    195.  
    196. CTMUCONL = 0b11011100;
    197. CTMUCONHbits.CTMUEN = 1;
    198. }
    199.  
    200.  
    201.  
    202.  
    203. void CurrentCalibration (void){
    204.  
    205. int i;
    206. int j = 0; //index for loop
    207. int Vread = 0;
    208. double VTot = 0;
    209. double Vavg=0, Vcal=0, CTMUISrc = 0;
    210.  
    211. CTMUCONHbits.CTMUEN = 1; //Enable the CTMU
    212. CTMUCONHbits.IDISSEN = 1; //drain charge on the circuit
    213. __delay_ms(1); //wait 125us
    214. CTMUCONHbits.IDISSEN = 0; //end drain of circuit
    215. CTMUCONLbits.EDG1STAT = 1; //Begin charging the circuit
    216. for(j=0;j<10;j++)
    217. {
    218. delayMsx(100);  //wait for 125us
    219. PIR1bits.ADIF = 0; //make sure A/D Interupt not set
    220. ADCON0bits.GO=1; //and begin A/D conv.
    221. while(!PIR1bits.ADIF); //Wait for A/D convert complete
    222. Vread = ADRES; //Get the value from the A/D
    223. PIR1bits.ADIF = 0; //Clear A/D Interrupt Flag
    224. VTot = VTot + Vread; //Add the reading to the total
    225. }
    226. CTMUCONLbits.EDG1STAT = 0; //Stop charging circuit
    227. CTMUCONHbits.CTMUEN = 0; //Enable the CTMU
    228. Vavg = (double)(VTot/10); //Average of 10 readings
    229. Vcal = 0.0004882812;
    230. Vcal = (double)Vcal*Vavg;
    231. CTMUISrc = (double)Vcal/RCAL; //CTMUISrc is in 1/100ths of uA
    232. CTMUISrc = CTMUISrc*1000000;    // current in uA
    233.  
    234. char ac_sample_char[12];
    235.  
    236. sprintf(ac_sample_char, "%0.1f Vavg : %0.3f Voltage : %0.2f CTMUISrc ", Vavg,Vcal,CTMUISrc );
    237.  
    238. puts1USART(ac_sample_char);
    239. putrs1USART(" \n\r");
    240. }
    241.  
    242. void CapacitanceCalibration (void){
    243.  
    244.   int i;
    245. int j = 0; //index for loop
    246. int Vread = 0;
    247. float CTMUISrc, CTMUCap, Vavg, VTot, Vcal;
    248. //assume CTMU and A/D have been setup correctly
    249. //see Example 25-1 for CTMU & A/D setup
    250.  
    251. CTMUCONHbits.CTMUEN = 1; //Enable the CTMU
    252. for(j=0;j<10;j++)
    253. {
    254. CTMUCONHbits.IDISSEN = 1; //drain charge on the circuit
    255. delayUsx(125); //wait 125us
    256. CTMUCONHbits.IDISSEN = 0; //end drain of circuit
    257. CTMUCONLbits.EDG1STAT = 1; //Begin charging the circuit
    258. //using CTMU current source
    259. delayUsx(12); //wait 125us
    260. CTMUCONLbits.EDG1STAT = 0; //Stop charging circuit
    261.  
    262. PIR1bits.ADIF = 0; //make sure A/D Int not set
    263. ADCON0bits.GO=1; //and begin A/D conv.
    264. while(!PIR1bits.ADIF); //Wait for A/D convert complete
    265. Vread = ADRES; //Get the value from the A/D
    266. PIR1bits.ADIF = 0; //Clear A/D Interrupt Flag
    267. VTot += Vread; //Add the reading to the total
    268. }
    269.  
    270. Vavg = (double)(VTot/10.000); //Average of 10 readings
    271. Vcal = 0.0004882812;
    272. Vcal = (double)Vcal*Vavg;
    273. CTMUISrc = 0.28; //CTMUISrc is in 1/100ths of uA
    274. CTMUCap = (double)(CTMUISrc*12/Vcal);
    275.  
    276. char ac_sample_char[12];
    277.  
    278. sprintf(ac_sample_char, "%0.1f Vavg : %0.3f Voltage : %0.2f CTMUCap ", Vavg,Vcal,CTMUCap );
    279.  
    280. puts1USART(ac_sample_char);
    281. putrs1USART(" \n\r");
    282.  
    283. }
    284.  
    285. void interrupt isr(void)
    286. {
    287.     if (PIR3bits.CTMUIF) {                                // the current source has been on and then turned off by the edge detect inputs
    288.         int Vread;
    289.  
    290.                 ADCON0bits.GO=1;                                 // and begin A/D conv, will set adc int flag when done.
    291.                 PIR3bits.CTMUIF=0;                                // clear CTMU interrupt flag
    292.  
    293.                 PIR1bits.ADIF = 0; //make sure A/D Interupt not set
    294.                 ADCON0bits.GO=1; //and begin A/D conv.
    295.                 while(!PIR1bits.ADIF); //Wait for A/D convert complete
    296.                 Vread = ADRES; //Get the value from the A/D
    297.                 PIR1bits.ADIF = 0; //Clear A/D Interrupt Flag
    298.  
    299.                 char ac_sample_char[12];
    300.                 char spacer[5];
    301.  
    302.                 if(Vread > 10){
    303.                 sprintf(spacer, "  ");
    304.                     if(Vread > 100){
    305.                     sprintf(spacer, " ");
    306.                         if(Vread > 1000){
    307.                         sprintf(spacer, "");
    308.                         }
    309.                     }
    310.                 }
    311.              
    312.              
    313.                 sprintf(ac_sample_char, "%02d %s - CT1:%01d CT2:%01d E1:%01d E2:%01d", Vread, spacer , PORTBbits.RB2, PORTBbits.RB3 ,CTMUCONLbits.EDG1STAT, CTMUCONLbits.EDG2STAT);
    314.  
    315.                 puts1USART(ac_sample_char);
    316.                 putrs1USART(" \n\r");
    317.     }
    318.  
    319.  
    320.  
    321.  
    322.  
    323.  
    324.  
    325. }
    326.  
    327.  
    328. void adcwait(void)
    329. {
    330.  
    331.     int count = 0;
    332.  
    333.     if (count > 100){
    334.     CTMUCONHbits.CTMUEN = 0;
    335.  
    336.     }
    337.      
    338. char ac_sample_char[12];
    339. int Vread;
    340. if(PIR1bits.ADIF){
    341.  
    342. CTMUCONHbits.CTMUEN = 0;
    343. CTMUCONL = 0b11011100;
    344. Vread = ADRES; //Get the value from the A/D
    345. PIR1bits.ADIF = 0; //Clear A/D Interrupt Flag
    346.  
    347. char ac_sample_char[12];
    348. char spacer[5];
    349. if(Vread > 10){
    350. sprintf(spacer, "  ");
    351.     if(Vread > 100){
    352.     sprintf(spacer, " ");
    353.         if(Vread > 1000){
    354.         sprintf(spacer, "");
    355.         }
    356.     }
    357. }
    358. sprintf(ac_sample_char, "%02d %s - CT1:%01d CT2:%01d E1:%01d E2:%01d", Vread, spacer , PORTBbits.RB2, PORTBbits.RB3 ,CTMUCONLbits.EDG1STAT, CTMUCONLbits.EDG2STAT);
    359.  
    360. puts1USART(ac_sample_char);
    361. putrs1USART(" \n\r");
    362.  
    363. CTMUCONHbits.IDISSEN = 1; //drain charge on the circuit
    364.     __delay_us(1);
    365. CTMUCONHbits.IDISSEN = 0; //end drain of circuit
    366. PIR1bits.ADIF = 0;
    367. }
    368.  
    369.  
    370.  
    371. CTMUCONL = 0b11011100;
    372. CTMUCONHbits.CTMUEN = 1;
    373. //PIR1bits.ADIF = 0;
    374. }
    375.  
    376.  
    377.  
    378. /*******************************************/
    379. void main(void) {
    380. OscillatorConfig();
    381. IO_ports_init();
    382. USART_init();
    383.  
    384. ADCConfig();
    385. CTMUInit();
    386.  
    387. BAUDCON1bits.BRG16 = 1;
    388. 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
    389.  
    390. RCONbits.IPEN = 1;
    391. INTCONbits.GIEL = 0;
    392. INTCONbits.GIEH = 1;
    393. CTMUCONHbits.CTMUEN = 1;
    394. putrs1USART("Starting \n\r");
    395.     while(1)
    396.     {
    397. //  putrs1USART("Doing measurement: ");
    398.   CTMU();
    399. delayMsx(1000);
    400. LEDs = 0;
    401. // adcwait();
    402.     }
    403. }
     
  2. nsaspook

    AAC Fanatic!

    Aug 27, 2009
    2,913
    2,187
    I can see where actual edge synchronization is a problem.
    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.
     
  3. Mellowed

    Thread Starter New Member

    Mar 6, 2016
    10
    2
    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?
     
  4. nsaspook

    AAC Fanatic!

    Aug 27, 2009
    2,913
    2,187
    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.
    [​IMG]
    http://www.allaboutcircuits.com/textbook/digital/chpt-10/edge-triggered-latches-flip-flops/
     
    Last edited: Apr 15, 2016
  5. Mellowed

    Thread Starter New Member

    Mar 6, 2016
    10
    2
    Thanks nsaspook, I will definitely give that a try!
     
  6. dannyf

    Well-Known Member

    Sep 13, 2015
    1,835
    367
    That should have been asked before you attempted anything else.
     
Loading...