This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Taking control of the capacitive touch library

Hi. I am trying to get a capacitive sensor library using a button ( 2 plates, one to ground, one to the AIN, separated).

It's going crazy, sometimes it just get tones of callbacks, sometimes not. The docs algorithm diagram is not clear regarding the callback, when it's being called, and how to extract values.

I read this.

I was playing with the threshold value and the timer between measurements, but there are 2 problems :

  1. The "release" function will always happen, so if I put my finger on the sensor and not remove it, it will call "press" and then "release" over and over (every measurement), which is a strange way to use "release" function, because it has no meaning like that (unless the timer is too large), it should call release only when i remove my finger.

  2. So I want to do my own DSP, so I need to read the actual values from the callbacks - I couldn't learn from the docs how to extract the measured value .

        void nrf_csense_handler(nrf_csense_evt_t * p_evt)
         {
             switch (p_evt->nrf_csense_evt_type)
             {
         
                //****this is the press callback extract from here the value
                 case NRF_CSENSE_BTN_EVT_PRESSED:
                   
                     if (p_evt->p_instance == (&m_button))
                     {
                         //uint16_t * btn_cnt = ((uint16_t*)p_evt->p_instance->p_context);
    

In general the sensor requires a lot of DSP work to be able to act as a reliable button, I was thinking that the library already did all of that for me.

  • I found out that working with the driver directly will provide a more intimate relationship with the sensor , so I used the driver directly, and I can measure values and run my own dsp.

    This code will measure every 150 ticks the values, but I must say the values are strange at the moment, I will update when I get it right !

    UPDATE !

    This works REALLY good, with a resistor of 1M, where you touch directly the pad. I have to mention to anyone who reads this, this will not use the COMP since it's unstable, so you need 2 pins, a digital out with a resistor into the AIN, and from the analog , exposed pad.

    From here, any cool DSP can be implemented !

    /* Pin used to measure capacitor charging time. */
    #if USE_COMP == 0
    #ifdef ADC_PRESENT
    #define OUTPUT_PIN 30
    #elif defined(SAADC_PRESENT)
    #define OUTPUT_PIN 26
    #endif
    #endif
    
    /* Time between RTC interrupts. */
     #define APP_TIMER_TICKS_TIMEOUT APP_TIMER_TICKS(150)
     #define AIN_1                   1
     #define AIN_2                   2
     #define AIN_7                   7
     #define PAD_1_MASK              (1UL << AIN_1)
     #define PAD_2_MASK              (1UL << AIN_7)
     #define PAD_ID_0                0
     #define PAD_ID_1                1
    
    
    
    static ret_code_t clock_config(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_drv_clock_init();
        if (err_code != NRF_SUCCESS)
        {
            return err_code;
        }
    
        nrf_drv_clock_lfclk_request(NULL);
    
        return NRF_SUCCESS;
    }
    
    
     static void csense_timeout_handler(void * p_context)
    {
        ret_code_t err_code;
    
        err_code = nrf_drv_csense_sample();
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_INFO("Busy.\r\n");
            return;
        }
    }
    
      void start_app_timer(void)
    {
        ret_code_t err_code;
    
        /* APP_TIMER definition for csense example. */
        APP_TIMER_DEF(timer_0);
    
        err_code = app_timer_create(&timer_0, APP_TIMER_MODE_REPEATED, csense_timeout_handler);
        APP_ERROR_CHECK(err_code);
    
        err_code = app_timer_start(timer_0, APP_TIMER_TICKS_TIMEOUT, NULL);
        APP_ERROR_CHECK(err_code);
    }
    
    
    
    
    void csense_handler(nrf_drv_csense_evt_t * p_event_struct)
    {
        switch (p_event_struct->analog_channel)
        {
            case AIN_1:
            case AIN_2:
                     NRF_LOG_INFO("t:%d\r\n",p_event_struct->read_value);
                     break;
            case AIN_7:
    
                     NRF_LOG_INFO("t:%d\r\n",p_event_struct->read_value);
                     break;
     
            default:
                break;
        }
    }
    
    
    void csense_initialize(void)
    {
        ret_code_t err_code;
    
        nrf_drv_csense_config_t csense_config = { 0 };
    
    #if USE_COMP == 0
        csense_config.output_pin = OUTPUT_PIN;
    #endif
    
        err_code = nrf_drv_csense_init(&csense_config, csense_handler);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_csense_channels_enable(PAD_1_MASK | PAD_2_MASK);
    }
    
  • Hi Lola

    It's good to hear you found a working solution.
    If you need some inspiration for the filtering algorithm you can take a look at the old capsense example for the nRF51

    It works just like you described, by using a 1M resistor to charge the sensor through a separate GPIO.

    Best regards

Related