6
\$\begingroup\$

I'm trying to implement a basic touch sensor using the CTMU on my PIC24F04KA200. Reading the datasheet and application notes provided by Microchip I was expecting this to be an easy endeavor. In this question I will just explain what I'm doing, post my C code and hopefully someone can point me in the right direction.

I have connected my sensor which is a copper plate on top of PCB board material about the size of a postcard. The kind of thing you buy to DIY your own circuit board. I have this connected this to AN4(RA2) pin. I have an LED and current limiting resistor connected to RA4. The only other circuit items I have are a decoupling cap .1uF on power pins and the PicKit3 powering the circuit (I've also tried with separate power supply).

All I've tried to do is follow the code example given by Microchip and essentially turn on the current source to allow my copper pad to charge and measure the voltage with A/D (as explained in the App Note) and when I touch the pad and the capacitance increases it would follow that the voltage would be lower and it would detect the touch.

My problem is that I get nothing out of the pin and it's not charging; my ADC value is always zero and on my scope it just shows 0 volts. I assume that my CTMU is not turning on, as the ADC cap should at least charge with it. I've searched the internet and Microchip forums and haven't found many people having problems so I think I must be making a simple mistake.

#define CLK 8000000L //8MHZ
#define FCY (CLK/2)

#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include <libpic30.h>
//#include "p24Fxxxx.h"
#include "uart.h"
#include "p24F04KA200.h"

#pragma config MCLRE = ON, GCP = OFF, FNOSC = FRC, FWDTEN = OFF, ICS = PGx2, PWRTEN = ON, OSCIOFNC = ON

void setup()
{
    //setup CTMU
    CTMUCONbits.CTMUEN = 0; //make sure CTMU is disabled
    CTMUCONbits.CTMUSIDL = 0; //CTMU continues to run in idle mode
    CTMUCONbits.TGEN = 0; //disable edge delay generation mode of the CTMU
    CTMUCONbits.EDGEN = 0; //edges are blocked
    CTMUCONbits.EDGSEQEN = 0; //edge sequence not needed
    CTMUCONbits.IDISSEN = 0; //Do not ground the current source
    CTMUCONbits.CTTRIG = 0; //Trigger Output is disabled
    CTMUCONbits.EDG2POL = 0;
    CTMUCONbits.EDG2SEL = 0x3; //Edge2 Src = OC1 (don?t care)
    CTMUCONbits.EDG1POL = 1;
    CTMUCONbits.EDG1SEL = 0x3; //Edge1 Src = Timer1 (don?t care)
    //CTMUICON
    CTMUICONbits.ITRIM = 0x3F; //Maximum Positive Adjustment
    CTMUICONbits.IRNG = 0x3; //55 uA
    CTMUCONbits.CTMUEN = 1; //Enable CTMU

    //setup A/D converter
    AD1PCFG = 0x0000;
    AD1CON1 = 0x0000;
    AD1CON1bits.FORM = 0x0; //Unsigned fractional format
    AD1CON2 = 0x0000;
    AD1CON3 = 0x0000; //bits.ADRC=0;
    AD1CON3bits.SAMC = 0xB; //12 TAD
    AD1CON3bits.ADCS = 0x60; //Used formula for ADCS with 12 TAD
    AD1CHS = 0x04; //select the analog channel 4
    AD1CSSL= 0x0000;
    AD1CON1bits.ADON = 1; //Turn On A/D
}

unsigned short runCTMU()
{
    AD1CON1bits.SAMP = 1; //Manual sampling start
    CTMUCONbits.IDISSEN = 1; //drain charge on the circuit
    __delay_us(125); //wait 125us
    CTMUCONbits.IDISSEN = 0; //end drain of circuit
    CTMUCONbits.EDG1STAT = 1; //Begin charging the circuit using CTMU current source
    __delay_us(125); //wait for 125us
    CTMUCONbits.EDG1STAT = 0; //Stop charging circuit
    IFS0bits.AD1IF = 0; //make sure A/D Int not set
    AD1CON1bits.SAMP = 0; //and begin A/D conv.
    while(!IFS0bits.AD1IF); //Wait for A/D convert complete
    AD1CON1bits.DONE = 0;

    return ADC1BUF0;
}

unsigned short getVbaseline()
{
    unsigned short vRead = 0;

    for(k = 0; k < 50; k++)
    {
        vRead = vRead + runCTMU();
    }

    return (vRead/50);
}

void main()
{
    unsigned short vRead;
    unsigned short vBaseline;

    setup();

    //Set up sensor pin
    TRISA = 0x2;
    AD1CHS = 0x4;   //select AN04 as input
    AD1PCFG = ~(0x4);

    //get untouched value on start up
    vBaseline = getVbaseline();

    while(1)
    {   
        vRead = runCTMU();

        //Touch sensed
        if (vRead < vBaseline)
        {
            LATAbits.LATA4 = 1; //output LED

            //Send ADC value over UART
            UART1PutChar(vRead >> 1);
            UART1PutChar(vRead);
        }
        else //Touch not sensed
        {
            LATAbits.LATA4 = 0;
        }

    }
}

I've used this Application Note for code examples.

\$\endgroup\$
2
\$\begingroup\$

I just ran across this very old (and unanswered) question during a Google search.

The problem is that during setup, the CTMU is disabled, but it is never re-enabled:

CTMUCONbits.CTMUEN = 0; //make sure CTMU is disabled

At the very beginning of your runCTMU function, you should have:

CTMUCONbits.CTMUEN = 1; //make sure CTMU is enabled

And then disable it again just before your return in that function.

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$
#include <stdint.h>
#include <stdio.h>
#include <libpic30.h>
#include "p24FJ64GB004.h"
#include "CTMU.h"
#include "main.h"

void InitCTMU(void){

    /**************setup CTMU*************/
     //CTMUCON
    CTMUCONbits.CTMUEN = 0; //make sure CTMU is disabled
    CTMUCONbits.CTMUSIDL = 1; //Discontinue module operation when device enters Idle mode
    CTMUCONbits.TGEN = 0; //disable edge delay generation mode of the CTMU
    CTMUCONbits.EDGEN = 0; //edges are blocked
    CTMUCONbits.EDGSEQEN = 0; //edge sequence not needed
    CTMUCONbits.IDISSEN = 0; //Do not ground the current source
    CTMUCONbits.CTTRIG = 0; //Trigger Output is disabled
    CTMUCONbits.EDG2POL = 0;
    CTMUCONbits.EDG2SEL = 0x3; //Edge2 Src = OC1 (don?t care)
    CTMUCONbits.EDG1POL = 1;
    CTMUCONbits.EDG1SEL = 0x3; //Edge1 Src = Timer1 (don?t care)
    //CTMUICON
    CTMUICON = 0x300; //55uA
    CTMUICONbits.ITRIM = 0; //Nominal - No Adjustment

    /***************setup A/D converter************///////////////
    AD1PCFGL = 0xEFFF; //chanel 12
    TRISCbits.TRISC3=1;
    AD1CON1 = 0x0000;
    AD1CHS = 0x000C; //Channel 0 positive input is AN12
    AD1CSSL=0x0000; //Analog channel is disabled from input scan
    AD1CON1bits.ADSIDL = 1; //Discontinue module operation when device enters Idle mode
    AD1CON1bits.FORM = 0x0; //Integer (0000 00dd dddd dddd)
    AD1CON3bits.ADRC = 0; // Clock derived from system clock
    AD1CON3bits.SAMC = 0b10000; //16TAD
    AD1CON3bits.ADCS = 0x01; //2Tcy
    AD1CON2 = 0x0000; //Interrupts are at the completion of conversion for each sample/convert sequence
    AD1CON1bits.ADON = 1; //Turn On A/D
    CTMUCONbits.CTMUEN = 1; //Enable CTMU
}

unsigned int runCTMU(void){

    uint16_t immediateValue;

    CTMUCONbits.IDISSEN = 1; //drain charge on the circuit
    __delay32(80); //wait 20us
    CTMUCONbits.IDISSEN = 0; //end drain of circuit
    Nop(); Nop();
    IFS0bits.AD1IF = 0; //Make sure A/D interrupt flag = 0
    AD1CON1bits.SAMP = 1; //Manual sampling start
    CTMUCONbits.EDG2STAT = 0;
    CTMUCONbits.EDG1STAT = 1; //Begin charging the circuit using CTMU current source
    __delay32(40); //wait for 10us
    CTMUCONbits.EDG1STAT = 0; //Stop charging circuit
    IFS0bits.AD1IF = 0; //make sure A/D Int not set
    AD1CON1bits.SAMP = 0; //and begin A/D conv.
    while(!IFS0bits.AD1IF);//Wait for A/D convert complete
    immediateValue = ADC1BUF0;
    AD1CON1bits.SAMP = 0;
    IFS0bits.AD1IF = 0;
    AD1CON1bits.DONE = 0; //Make sure A/D bits are cleared

    return immediateValue;
}

unsigned int getVbaseline(void){

    unsigned int vRead = 0, k;

    for(k = 0; k < 50; k++){
        vRead = vRead + runCTMU();
    }

    return (vRead/50);
}
| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ I've just formatted your code but please explain at least briefly what your code does. \$\endgroup\$ – PeterJ Jan 15 '14 at 7:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.