Qmatrix - PWM Timer conflict or sucky code?

Go To Last Post
20 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have an attiny84 with a 4 segment spatially interpolated slider. The 8-bit Slider position = 8-bit PWM duty cycle for LED driver control (TPS61165). I am getting a flicker in my LED's that corresponds to the Qmatrix 4 channel Burst. I am not sure if this is because of a timer conflict or poor code. 

 

I do know that my input power is out of Vripple spec for Qmatrix(approx 20mvpp) I am about 40mvpp. I have a new hardware revision that should filter that out more (CLCLC filter before LDO). But it seems like its more of a software issue. 

 

From the following Atmel Webdoc:

 

http://www.atmel.com/webdoc/QTSoftwareLibUserGuide/QT_SQ_LIB.section_puz_yto_ag.html#QT_SQ_LIB.section_xwz_yto_ag

 

We can see that Qmatrix uses Timer1 internally all the time or just sometimes?

 

  1. General application notes

    1. The clock, host application and other peripherals needed by the host application needs to be initialized.

    2. The QMatrix acquisition method libraries internally use TIMER1 for their operation.

    3. Ensure that there are no conflicts between the resources used by the touch library and the host application

    4. Ensure that the stack size is adjusted to factor in the stack depth required for the operation of the touch libraries. 

 

   Resources used by QMatrix acquisition method libraries

   The following additional resources are used by the QMatrix acquisition method libraries.

  1. One Analog Comparator

  2. One internal Timer ( Usually Timer1 depending on the availability on particular microcontroller)

  3. One ADC Multiplexer( The critical section of the touch sensing library disables the use of ADC as conversion unit and enables the same ADC as a multiplexer, but the user can use the ADC for conversion in rest of his application  code )

  4. The ADCMUX is used by the library during the touch sensing acquisition, however it is restored with the value from host application before exiting the qt_measure_sensors() such that the ADC is available to the host application for conversion.

 

Hmm what is it? Because I am using Timer1 for my PWM output BUT my Studio code shows that Qmatrix is using Timer0 as far as I can tell. Unless I cannot see where Timer1 would be implemented by Qmatrix.

 

Here is the Code:

 

init_mcu_attiny84.c showing Timer0 being called.

 

#include <avr/io.h>
#include <avr/interrupt.h>
#include "touch.h"
/*----------------------------------------------------------------------------
                            manifest constants
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
                            type definitions
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
                                prototypes
----------------------------------------------------------------------------*/
/* configure timer ISR to fire regularly */
void init_timer_isr( void );

/* initialise host app, pins, watchdog, etc */
void init_system( void );

/*----------------------------------------------------------------------------
                            Structure Declarations
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
                                    macros
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
                                global variables
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
                                extern variables
----------------------------------------------------------------------------*/
/* Timer period in msec. */
extern uint16_t qt_measurement_period_msec;
extern uint16_t time_ms_inc;
/*----------------------------------------------------------------------------
                                static variables
----------------------------------------------------------------------------*/

/* flag set by timer ISR when it's time to measure touch */
extern volatile uint8_t time_to_measure_touch;

/* current time, set by timer ISR */
extern volatile uint16_t current_time_ms_touch;

#if defined(__ATtiny84__)
#if defined(_QTOUCH_) || defined(_QMATRIX_)

/*============================================================================
Name    :   init_timer_isr
------------------------------------------------------------------------------
Purpose :   configure timer ISR to fire regularly
Input   :   n/a
Output  :   n/a
Notes   :
============================================================================*/
void init_timer_isr( void )
{
   /*  set timer compare value (how often timer ISR will fire set to 1 ms timer interrupt) */

   OCR0A = ( TICKS_PER_MS * QT_TIMER_PERIOD_MSEC);

   /*  enable timer ISR on compare A */
   TIMSK0 |= ( 1 << OCIE0A );
   /*  timer prescaler = system clock / 64  */
   TCCR0B |= (1 << CS01) | (1 << CS00);
   /*  timer mode = CTC (count up to compare value, then reset)    */
   TCCR0A |= (1 << WGM01);
}

/*============================================================================
Name    :   timer_isr
------------------------------------------------------------------------------
Purpose :   timer 0 compare ISR
Input   :   n/a
Output  :   n/a
Notes   :
============================================================================*/
ISR(TIM0_COMPA_vect)
{
  #ifdef QDEBUG_TWI
  if (gMsTimeout)
  {
    gMsTimeout--;
  }
  #endif

  time_ms_inc += QT_TIMER_PERIOD_MSEC;

  if(time_ms_inc >= qt_measurement_period_msec)
  {
    time_ms_inc =0;
    /*  set flag: it's time to measure touch    */
    time_to_measure_touch = 1u;
  }
  else
  {

  }
  /*  update the current time */
   current_time_ms_touch += QT_TIMER_PERIOD_MSEC;
}

#endif /* TECHNOLOGY */

/*============================================================================
Name    :   init_system
------------------------------------------------------------------------------
Purpose :   initialise host app, pins, watchdog, etc
============================================================================*/
void init_system( void )
{
    /*  run at 4MHz (assuming internal clock is set to 8MHz)*/
    CLKPR = 0x80u;
    CLKPR = 0x01u;

    /*  disable pull-ups    */
    MCUCR |= (1u << PUD);

}
#endif

main.c showing my PWM code blush

 

#include <avr/io.h>
#include <avr/interrupt.h>
#define __delay_cycles(n)     __builtin_avr_delay_cycles(n)
#define __enable_interrupt()  sei()

#include "touch_api.h"
#include "touch.h"
/*----------------------------------------------------------------------------
                            manifest constants
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
                                    macros
----------------------------------------------------------------------------*/

#define GET_SENSOR_STATE(SENSOR_NUMBER) qt_measure_data.qt_touch_status.sensor_states[(SENSOR_NUMBER/8)] & (1 << (SENSOR_NUMBER % 8))
#define GET_ROTOR_SLIDER_POSITION(ROTOR_SLIDER_NUMBER) qt_measure_data.qt_touch_status.rotor_slider_values[ROTOR_SLIDER_NUMBER]

/*----------------------------------------------------------------------------
                            type definitions
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
                                prototypes
----------------------------------------------------------------------------*/
extern void touch_measure(void);
extern void touch_init( void );
extern void init_system( void );
extern void init_timer_isr(void);
extern void set_timer_period(uint16_t);
/*----------------------------------------------------------------------------
                            Structure Declarations
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
                                    macros
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
                                global variables
----------------------------------------------------------------------------*/
/* Timer period in msec. */
uint16_t qt_measurement_period_msec = QT_MEASUREMENT_PERIOD_MS;
uint16_t time_ms_inc=0;
/*----------------------------------------------------------------------------
                                extern variables
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
                                static variables
----------------------------------------------------------------------------*/

/* flag set by timer ISR when it's time to measure touch */
volatile uint8_t time_to_measure_touch = 0u;

/* current time, set by timer ISR */
volatile uint16_t current_time_ms_touch = 0u;

/*============================================================================
Name    :   main
------------------------------------------------------------------------------
Purpose :   main code entry point
Input   :   n/a
Output  :   n/a
Notes   :
============================================================================*/

int main( void )
{
uint8_t slider_value;									

   /* initialise host app, pins, watchdog, etc */
    init_system();

    /* configure timer ISR to fire regularly */
    init_timer_isr();

	/* Initialize Touch sensors */
	touch_init();

    /* enable interrupts */
    __enable_interrupt();

    /* loop forever */
    for( ; ; )
    {
        touch_measure();

    /*  Time Non-critical host application code goes here  */

	if (GET_SENSOR_STATE(0))
		{
			slider_value = GET_ROTOR_SLIDER_POSITION(0);

				// Doubles clock frequency, doing this because Phase Correct PWM halves frequency
				// due to Bottom-Top-Bottom counting - OSCCAL (Trim internal clock)
				//OSCCAL = 0xFF;

				// Waveform Generator Mode 11 set with WGM11 set to 1 and WGM10 set to 1
				// (1<<COM1B1) Clear OC1A/OC1B on Compare Match when up-counting.
				// Set OC1A/OC1B on Compare Match when down-counting.
				TCCR1A |= (1<<WGM11)|(1<<WGM10)|(1<<COM1B1);

				// Waveform Generator Mode 11 set with WGM13 set to 1 and WGM12 set to 0
				// (1<<CS10) = no prescaler
				TCCR1B |= (1<<WGM13)|(1<<CS10);

				// OCR1A sets TOP for Waveform Generator Mode 11
				OCR1A = 255;

				// Sets PortA Pin5 as output - IC actual pin 20 OC1B
				DDRA |= (1<<DDA5);

				// Duty cycle for waveform = (OCR1B/255) this will be the slider position variable
				OCR1B = slider_value;

		}

    }
}

 

touch.c

 

#include <avr/io.h>
#include <avr/interrupt.h>

#define __delay_cycles(n)     __builtin_avr_delay_cycles(n)

/*  now include touch api.h with the localization defined above */
#include "touch_api.h"
#include "touch.h"
#ifdef _ATXMEGA_
#include "asf.h"
#endif

#ifdef _DEBUG_INTERFACE_
/* Include files for QTouch Studio integration */
#include "QDebug.h"
#include "QDebugTransport.h"
#endif

/*----------------------------------------------------------------------------
                            manifest constants
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
                            type definitions
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
                                prototypes
----------------------------------------------------------------------------*/
/* This will initialize touch related code */
void touch_init( void );
/* This will call all the functions for touch related measurement */
void touch_measure(void);
/*  Assign the parameters values to global configuration parameter structure    */
static void qt_set_parameters( void );
/*  Configure the sensors */
static void config_sensors(void);

#ifdef _DEBUG_INTERFACE_
void set_timestamp1(void); // used for timestamping
#endif

/*----------------------------------------------------------------------------
                            Structure Declarations
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
                                    macros
----------------------------------------------------------------------------*/

#ifdef _DEBUG_INTERFACE_
 #ifdef _QDEBUG_TIME_STAMPS_
/* This below code is used for timestamping related information */

	#define TIMESTAMP0  asm("cli"); timestamp0_lword = (uint16_t)TIMER_COUNTER_L;timestamp0_lword |= (uint16_t)(TIMER_COUNTER_H << 8); timestamp0_hword = current_time_ms_touch; asm("sei");
	#define TIMESTAMP1  asm("cli"); timestamp1_lword = (uint16_t)TIMER_COUNTER_L;timestamp1_lword |= (uint16_t)(TIMER_COUNTER_H << 8); timestamp1_hword = current_time_ms_touch; asm("sei");
	#define TIMESTAMP2  asm("cli"); timestamp2_lword = (uint16_t)TIMER_COUNTER_L;timestamp2_lword |= (uint16_t)(TIMER_COUNTER_H << 8); timestamp2_hword = current_time_ms_touch; asm("sei");
	#define TIMESTAMP3  asm("cli"); timestamp3_lword = (uint16_t)TIMER_COUNTER_L;timestamp3_lword |= (uint16_t)(TIMER_COUNTER_H << 8); timestamp3_hword = current_time_ms_touch; asm("sei");
	#define TIMESTAMP4  asm("cli"); timestamp4_lword = (uint16_t)TIMER_COUNTER_L;timestamp4_lword |= (uint16_t)(TIMER_COUNTER_H << 8); timestamp4_hword = current_time_ms_touch; asm("sei");
	#define TIMESTAMP5  asm("cli"); timestamp5_lword = (uint16_t)TIMER_COUNTER_L;timestamp5_lword |= (uint16_t)(TIMER_COUNTER_H << 8); timestamp5_hword = current_time_ms_touch; asm("sei");

  #else

	#define TIMESTAMP0   {}
	#define TIMESTAMP1   {}
	#define TIMESTAMP2   {}
	#define TIMESTAMP3   {}
	#define TIMESTAMP4   {}
	#define TIMESTAMP5   {}
  #endif
#endif

/*----------------------------------------------------------------------------
                                global variables
----------------------------------------------------------------------------*/

#ifdef _DEBUG_INTERFACE_
 #ifdef _QDEBUG_TIME_STAMPS_
  uint16_t timestamp0_hword=0;
  uint16_t timestamp0_lword=0;
  uint16_t timestamp1_hword=0;
  uint16_t timestamp1_lword=0;
  uint16_t timestamp2_hword=0;
  uint16_t timestamp2_lword=0;
  uint16_t timestamp3_hword=0;
  uint16_t timestamp3_lword=0;
  uint16_t timestamp4_hword=0;
  uint16_t timestamp4_lword=0;
  uint16_t timestamp5_hword=0;
  uint16_t timestamp5_lword=0;
 #endif
#endif
/*----------------------------------------------------------------------------
                                extern variables
----------------------------------------------------------------------------*/
/* This configuration data structure parameters if needs to be changed will be
changed in the qt_set_parameters function */
extern qt_touch_lib_config_data_t qt_config_data;
/* measurement data */
extern qt_touch_lib_measure_data_t qt_measure_data;
qt_touch_lib_measure_data_t *pqt_measure_data = &qt_measure_data;
/* Get sensor delta values */
extern int16_t qt_get_sensor_delta( uint8_t sensor);

#ifdef _QMATRIX_
   extern y_line_info_t y_line_info[NUM_Y_LINES];
   extern x_line_info_t x_line_info[NUM_X_LINES];

/* Fill out the X-Line masks and  Y-Line masks on the X- Port and Y-Line Port selected.
* The order of X - Line numbering follows from the way the
*
*/

/**
  * Number of Channels(dependent on the library used and application requirement).
  * The least possible number more that the application needs.
  * Please refer to the QTouch library user guide.pdf and library selection
  * guide.xls more information on selecting the number of channels.
  *
  * Possible values: 4, 8, 12, 16, 32. in case of QTouch
  * Possible values: 4, 8, 16, 32, 56, 64. in case of QMatrix.
  */
  #define QT_NUM_CHANNELS   4
/**
  * Define the Number X lines to be used.
  * Possible values: 4 and 8
  * Depending on the library used.Please refer to the QTouch library user guide.pdf
  * and library selection guide.xls more information on selecting the number of channels.
  *
  */#define NUM_X_LINES	4
/**
  * Specify the number of ports on which X-lines that are distributed.
  * Note: Support is provided only for a maximum of 3 ports for X.
  *		 ( Maximum possible value for NUM_X_PORTS is 3)
  * Possible values: 1,2,3
  * Also, note that code memory increases with the number of ports
  * used for X lines.
  */#define NUM_X_PORTS	2
/**
  * Specify Which ports have X lines on them. These macros are used
  * to conditionally compile in support for ports driving X lines.
  */#define PORT_X_1	A
#define PORT_X_2	B

/**
  * Define the Number Y lines to be used.
  *  Possible values: 1, 2, 4 and 8
  * Depending on the library used.Please refer to the QTouch library user guide.pdf
  * and library selection guide.xls more information on selecting the number of channels.
  */
#define NUM_Y_LINES	1

/**
  * Specify the port for YA, YB,
  * For rules to specify the port for YA ,YB please go through QTouch library
  * user guide .pdf
  */
#define PORT_YA 	A
#define PORT_YB 	A

/**
  * SHARED_YA_YB should be 1 if YA and YB lines are on same port else 0
  */
#define SHARED_YAYB 	1
/**
  * Specify the port for SMP.
  * And Specify the pin for SMP on selected SMP port.
  * Any GPIO pin not conflicting with the other touch pins used for the application
  */
#define PORT_SMP 	A
#define SMP_PIN 	0

#define PORT_NUM_1	1
#define PORT_NUM_2	2

x_line_info_t x_line_info[NUM_X_LINES]= {
FILL_OUT_X_LINE_INFO(1,7),
FILL_OUT_X_LINE_INFO(2,2),
FILL_OUT_X_LINE_INFO(2,1),
FILL_OUT_X_LINE_INFO(2,0)};

y_line_info_t ya_line_info[NUM_Y_LINES]={
FILL_OUT_YA_LINE_INFO(3),
};

y_line_info_t yb_line_info[NUM_Y_LINES]={
FILL_OUT_YB_LINE_INFO(2),
};

#endif/*_QMATRIX_*/

extern uint8_t time_to_measure_touch;
extern uint16_t current_time_ms_touch;

/*----------------------------------------------------------------------------
                                static variables
----------------------------------------------------------------------------*/

/*============================================================================
Name    :   touch_init
------------------------------------------------------------------------------
Purpose :   This will initialize touch related code.
Input   :   n/a
Output  :   n/a
Notes   :
============================================================================*/

void touch_init( void )
{
#ifdef _ATXMEGA_
    /* Enable clocks for the modules used by
    * QMatrix library */

    /* Enable Event System module in Power reduction register */
    sysclk_enable_module(SYSCLK_PORT_A, SYSCLK_AC);
    /* Enable Analog comparator module in Power reduction register */
    sysclk_enable_module(SYSCLK_PORT_GEN, SYSCLK_EVSYS);
    /* Enable Timer/Counter1 in Power reduction register */
    sysclk_enable_module(SYSCLK_PORT_C, SYSCLK_TC1);
#endif

    /* Configure the Sensors as keys or Keys With Rotor/Sliders in this function */
    config_sensors();

    /* initialise touch sensing */
    qt_init_sensing();

    /*  Set the parameters like recalibration threshold, Max_On_Duration etc in this function by the user */
    qt_set_parameters( );

    /*  Address to pass address of user functions   */
    /*  This function is called after the library has made capacitive measurements,
    *   but before it has processed them. The user can use this hook to apply filter
    *   functions to the measured signal values.(Possibly to fix sensor layout faults)    */
    #ifdef _DEBUG_INTERFACE_
        qt_filter_callback = &set_timestamp1;
    #else
        qt_filter_callback = 0;
    #endif

    #ifdef _DEBUG_INTERFACE_
        /* Initialize debug protocol */
        QDebug_Init();

        /* Process commands from PC */
        QDebug_ProcessCommands();
    #endif

}
#ifdef _DEBUG_INTERFACE_
void set_timestamp1(void)
{
	TIMESTAMP1;
}
#endif

/*============================================================================
Name    :   touch_measure
------------------------------------------------------------------------------
Purpose :   This will call all the functions for touch related measurement.
Input   :   n/a
Output  :   n/a
Notes   :
============================================================================*/
void touch_measure(void)
{
   /*status flags to indicate the re-burst for library*/
   static uint16_t status_flag = 0u;
   static uint16_t burst_flag = 0u;

	  if( time_to_measure_touch )
        {

            /*  clear flag: it's time to measure touch  */
            time_to_measure_touch = 0u;

            do {
				#ifdef _DEBUG_INTERFACE_
				    TIMESTAMP0;
				#endif
                /*  one time measure touch sensors    */
                status_flag = qt_measure_sensors( current_time_ms_touch );

				#ifdef _DEBUG_INTERFACE_
				    TIMESTAMP2;
				#endif
                burst_flag = status_flag & QTLIB_BURST_AGAIN;

				#ifdef _DEBUG_INTERFACE_
                    /* send debug data */
                    QDebug_SendData(status_flag);
    				/* Process commands from PC */
                	QDebug_ProcessCommands();
				#endif

				#ifdef _DEBUG_INTERFACE_
				    TIMESTAMP3;
				#endif
				/* Time-critical host application code goes here */

            }while (burst_flag) ;

        }

        #ifdef _DEBUG_INTERFACE_
            TIMESTAMP4;
        #endif

        /* Non-Time critical host application code goes here */

        #ifdef _DEBUG_INTERFACE_
            TIMESTAMP5;
        #endif
        /* Host sleep code goes here */
}

/*============================================================================
Name    :   qt_set_parameters
------------------------------------------------------------------------------
Purpose :   This will fill the default threshold values in the configuration
            data structure.But User can change the values of these parameters .
Input   :   n/a
Output  :   n/a
Notes   :   Generated Code from QTouch Studio. Do not change
============================================================================*/

static void qt_set_parameters( void )
{

/*  This will be modified by the user to different values   */

qt_burst_lengths[0]= 64;
qt_burst_lengths[1]= 64;
qt_burst_lengths[2]= 64;
qt_burst_lengths[3]= 64;

qt_config_data.qt_di              = 20;
qt_config_data.qt_neg_drift_rate  = 10;
qt_config_data.qt_pos_drift_rate  = 10;
qt_config_data.qt_max_on_duration = 20;
qt_config_data.qt_drift_hold_time = 1;
qt_config_data.qt_recal_threshold = 0;
qt_config_data.qt_pos_recal_delay = 10;

}

/*============================================================================
Name    :   config_sensors -
------------------------------------------------------------------------------
Purpose :   Configure the sensors
Input   :   n/a
Output  :   n/a
Notes   :   Generated code from QTouch Studio. Do not change
============================================================================*/
static void config_sensors(void)
{
	qt_enable_slider( CHANNEL_0, CHANNEL_3, NO_AKS_GROUP, 20u, HYST_25, RES_8_BIT, 0u  );

}

 

touch.h

 

#define _QMATRIX_

/**
  * Device Name.
  *
  */
#define __ATtiny84__

/**
  * Delay cycles that determine the capacitance charge pulse width. Value of 0
  * will enable charge pulse width of 1 clock cycle, 1 will enable a width of 2
  * clock cycles and so on...
  *
  * Possible values: 1,2,3,4,5,10,25,50
  */
#ifndef QT_DELAY_CYCLES
#define QT_DELAY_CYCLES 1
#endif

/**
  * Define the Number of ROTORS/SLIDERS used.
  * Possible values: 0             ( if _ROTOR_SLIDER_ is not defined)
  *                  1, 2, 4 and 8 ( if _ROTOR_SLIDER_ is defined)
  * Depending on the library used..
  */
#define QT_MAX_NUM_ROTORS_SLIDERS 1
#define _ROTOR_SLIDER_ 

/**
  * Number of Channels(dependent on the library used and application requirement).
  * The least possible number more that the application needs.
  * Please refer to the QTouch library user guide.pdf and library selection
  * guide.xls more information on selecting the number of channels.
  *
  * Possible values: 4, 8, 12, 16, 32. in case of QTouch
  * Possible values: 4, 8, 16, 32, 56, 64. in case of QMatrix.
  */
  #define QT_NUM_CHANNELS   4
/**
  * Define the Number X lines to be used.
  * Possible values: 4 and 8
  * Depending on the library used.Please refer to the QTouch library user guide.pdf
  * and library selection guide.xls more information on selecting the number of channels.
  *
  */#define NUM_X_LINES	4
/**
  * Specify the number of ports on which X-lines that are distributed.
  * Note: Support is provided only for a maximum of 3 ports for X.
  *		 ( Maximum possible value for NUM_X_PORTS is 3)
  * Possible values: 1,2,3
  * Also, note that code memory increases with the number of ports
  * used for X lines.
  */#define NUM_X_PORTS	2
/**
  * Specify Which ports have X lines on them. These macros are used
  * to conditionally compile in support for ports driving X lines.
  */#define PORT_X_1	A
#define PORT_X_2	B

/**
  * Define the Number Y lines to be used.
  *  Possible values: 1, 2, 4 and 8
  * Depending on the library used.Please refer to the QTouch library user guide.pdf
  * and library selection guide.xls more information on selecting the number of channels.
  */
#define NUM_Y_LINES	1

/**
  * Specify the port for YA, YB,
  * For rules to specify the port for YA ,YB please go through QTouch library
  * user guide .pdf
  */
#define PORT_YA 	A
#define PORT_YB 	A

/**
  * SHARED_YA_YB should be 1 if YA and YB lines are on same port else 0
  */
#define SHARED_YAYB 	1
/**
  * Specify the port for SMP.
  * And Specify the pin for SMP on selected SMP port.
  * Any GPIO pin not conflicting with the other touch pins used for the application
  */
#define PORT_SMP 	A
#define SMP_PIN 	0

#define PORT_NUM_1	1
#define PORT_NUM_2	2

/**
  * Provide the number of timer clock ticks (cycles) required to provide a 1 millisecond time interval.
  * TICKS_PER_MS = (CLK_FREQ/TIMER_PRESCALER)*(1/1000)
  * Example, TICKS_PER_MS = (8MHz/64)*(1/1000) = 125
  */
#define TICKS_PER_MS 63u

/**
  * Provide the periodic interrupt interval for which the timer is configured.
  * Example, QT_TIMER_PERIOD_MSEC  2u
  * Timer ISR will fire at every 2 milliseconds.
  */
#define QT_TIMER_PERIOD_MSEC  1u

/**
  * Provide the periodic interval for touch measurement.
  * Example, QT_MEASUREMENT_PERIOD_MS 50u
  * Perform a single touch measurement every 50msec.
  */
#define QT_MEASUREMENT_PERIOD_MS 25u

 

Here are the captured waveforms showing the issue. CH1 is the 4 channels of burst and CH2 is my PWM output to the LED Driver.

 

 

 

Any ideas?

 

Should I abandon the attiny84 and use the atmega328PB with its 3 timers and PTC? I do have 16 boards that use this attiny84 revision so that would suck a bit.

Does my code stink?

 

I appreciate all the help. 

Last Edited: Wed. Aug 17, 2016 - 12:46 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The flickering may be somewhat normal as you are changing the value of OCR1B "on the fly' so to speak, and it also depends on what the frequency your output is as well.  A low frequency output will show the little update glitches more so than a higher frequency output.

 

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jgmdesign wrote:

The flickering may be somewhat normal as you are changing the value of OCR1B "on the fly' so to speak, and it also depends on what the frequency your output is as well.  A low frequency output will show the little update glitches more so than a higher frequency output.

 

Ahh thank for this, I need to clarify my statement.

The flicker persists when the touch is lifted and the position and duty value is set.

My output frequency is about 13KHz.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

13khz! To dim an LED?

I have four led panels lightng the front of my home and they are dimmed using PWM phase correct at 250hz.

The transition is seamless. Try lowering the PWM frequency

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jgmdesign wrote:

13khz! To dim an LED?

I have four led panels lightng the front of my home and they are dimmed using PWM phase correct at 250hz.

The transition is seamless. Try lowering the PWM frequency

Jim

The TPS61165 LED driver requires a PWM input between 5KHz and 100KHz for proper operation. It doesn't state why though.

I can test at a lower frequency to see what happens though.

Last Edited: Wed. Aug 17, 2016 - 04:16 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I see what you mean with the frequency.

 

I find it odd that the PWM stops running when the QTOUCH does a scan.

 

Will have to look at this some more later.

 

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is definitely a timer conflict issue. As stated in the QTouch library user guide - "The QMatrix acquisition method libraries internally use TIMER1 for their operation."

Note the word 'internally'. This means to say that Timer1 is configured and used within the QMatrix library and cannot be viewed in user application code.

 

The Timer0 that is shown in the studio code is to provide current time to the library. This is utilized to perform time dependent functions like drifting, max-on time outs etc...

Timer1 is internally used by library during every acquisition. This is why you don't see PWM pulse during touch bursting.

 

Thus using Timer1 for PWM is not advisable.

However all is not lost, if you can use Timer0 for your PWM(providing the 8-bit timer is sufficient for your duty cycle).

 

As you can see, Timer0 is used by the touch library to update the time_ms_inc and current_time_ms_touch flags. You can modify the code to use Timer1 for updating these flags and Timer0 for the PWM.

Even here Timer1 will be modified during touch acquisition, which will affect time_ms_inc and current_time_ms_touch.

But these are less time critical than the PWM. Say, a touch measurement which was supposed to happen at 20ms might take place at 23ms or drifting time may change by couple of ms once in a while.

 

This would be worth a try for the sake of 16 boards wink.

 

"Conversation enriches the mind, but solitude is the school of genius".

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

why_me wrote:
As you can see, Timer0 is used by the touch library to update the time_ms_inc and current_time_ms_touch flags. You can modify the code to use Timer1 for updating these flags and Timer0 for the PWM. Even here Timer1 will be modified during touch acquisition, which will affect time_ms_inc and current_time_ms_touch. But these are less time critical than the PWM. Say, a touch measurement which was supposed to happen at 20ms might take place at 23ms or drifting time may change by couple of ms once in a while.

 

I think you have to set the parameters of your timer always after measuring touch and set it back before measuring. Because you don't know what setting the touch uses (OK, with debugging you could see it for this project). I did this with the ADC on tiny88 which is also used by the touch.

Like this:

init_QTouch();
save_timer1_parameters();
while(1){
    if (doTouch) {
        restore_timer1_parameters();
        measure_touch(time_in_ms);
        init(timer1);   // for your touch period
    }
}

interrupt timer1() {
    /* not sure if interrupt will be called while measuring touch */
    if (!doTouch) {
        doTouch = true;
    }
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK, I think I have a few things to try out now, I will do some bodge wiring. It happens that my X channel runs on the Timer0 PWM output pins so I will need to switch my Timer1 PWM output pin and one of the X channel pins around... Should be fine for testing.

 

As a worst case I just received the AtMega328PB Xplained mini that has a 4 channel touch PWM LED demo with it. It seams PTC Touch is easier to implement than Qmatrix.

 

Thank you all for the support, I will check back in on the weekend hopefully with some news. 

 

Just for fun this is the AtMega328PB Demo code.

 

/* == include files ==========================================================*/
#include <avr/sleep.h>
#include "touch_api_ptc.h"

/* == #defines ================================================================ */

#define JOIN( x, y )				x ## y
#define REG( REGISTER, SIDE )		JOIN( REGISTER, SIDE )

#define SET_GPIO_PIN(port , pin)	REG(PORT, port) |= (1 << pin)
#define RESET_GPIO_PIN(port, pin)	REG(PORT, port) &= ~(1 << pin)

/* == types ==================================================================== */

/* == constants ================================================================= */
#define DEF_MCU_CLOCK_PRESCALER		1u
#define DEF_TIME_PERIOD_1MSEC       8u

#define LED_0_PORT					B
#define LED_0_PIN					5u

/* == global constants ========================================================== */

/* == global variables ========================================================== */
volatile uint16_t touch_time_counter = 0u;

/* == file-scope (static) variables ============================================= */

/* == file-scope (static) function prototypes =================================== */

/*! \brief MCU clock prescaler configuration routine
 *
 */
static void configure_prescaler(const uint8_t MCU_Clock_Prescaler);

/*! \brief Timer initialization routine
 *
 */
static void timer_init(void);

/*! \brief Timer initialization routine
 *
 */
static void configure_port_pins(void);

/* == file-scope (static) functions defines =================================== */

/*! \brief Set the system prescaler to 1 to ensure main clock is running at 8Mhz
 *
 * \param Sys_Clock_Prescaler	MCU clock prescaler value
 * \param MCU_Clock_Prescaler   MCU main clock prescaler.
 *
 * \return void
 */
static void configure_prescaler(const uint8_t MCU_Clock_Prescaler)
{
    /* set the prescaler of SYS Clock to 1 - 8 MHz */
    /* all these have 4 cycles*/
    __asm__ __volatile__  (
        "ldi r16, 0x80; \n\t"
        "sts 0x61, r16; \n\t"
        "sts 0x61, %0; \n\t "
        : /* no output registers */
        : "r"(MCU_Clock_Prescaler) /* Input register List */
        : "r17" /* Clobber List */
    );

}/*configure_prescaler*/


/*! \brief Timer0 overflow ISR
 *
 * \param void
 * \return void
 */
ISR(TIMER0_OVF_vect)
{
	SET_GPIO_PIN(LED_0_PORT,LED_0_PIN) ;
}

/*! \brief Timer0 compareA ISR
 *
 * \param void
 * \return void
 */
ISR(TIMER0_COMPA_vect)
{
	RESET_GPIO_PIN(LED_0_PORT,LED_0_PIN) ;
}

/*! \brief Configures the timer 2 for Output compare A interrupt at every 1 ms
 *
 * \param void
 * \return void
 */
static void timer_init(void)
{
    /* Setup Timer 2 for Clear Timer on Compare (CTC) mode of operation */
    TCCR2A = 0x00u | (1u << WGM21) ;

    /* Clear the Timer2 to zero */
    TCNT2 = 0x00u;

    /* Set the Output compare match A to Measurement period */
    OCR2A = DEF_TIME_PERIOD_1MSEC ;

    /* Clear the timer 2 compare Match A flag*/
    TIFR2 = 0x00 | (1u << OCF2A);

    /*Enable the Interrupt for Timer 2 Output compare match A */
    TIMSK2 = 0x00 | ( 1u << OCIE2A);

    /* Start timer.Set the prescaler to 7 */
    TCCR2B = ((1 << CS20) | (1 << CS21) | (1<< CS22)) ;

	/* setup timer0 for soft PWM*/
	TCCR0A = 0x00u;

	/* Start timer with 32 prescaling */
	TCCR0B = ((1 << CS01) | (1<< CS00)) ;

	/* Enable compare A and over flow interrupt enable*/
	TIMSK0 = ((1 << OCIE0A) | (1<< TOIE0)) ;

	/* Set the initial compare value or the soft PWM duty cycle*/
	OCR0A = 0x01u;	
}/*timer_init*/



/*! \brief Configures the port pins to output push - pull to drive LED
 *
 * \param void
 * \return void
 */
static void configure_port_pins(void)
{
    REG(DDR , LED_0_PORT)  |= (1 << LED_0_PIN);
}/*configure_port_pins*/



/* == public function(global function) defines =================================== */

/*! \brief Main function
 *
 */
int main(void)
{
	uint8_t timer_running  =  0u;
	uint8_t slider_position;

	/* Configure the sys_clock prescaler */
	configure_prescaler(DEF_MCU_CLOCK_PRESCALER);

	/* Configure the Timer 2 */
	timer_init();
	timer_running = 1u;
	
	/* Enable global interrupts */
	cpu_irq_enable();

	/* Initialize QTouch library and configure touch sensors. */
	touch_sensors_init();

	configure_port_pins();


	while(1){
		
		touch_sensors_measure();

		if ((p_selfcap_measure_data->measurement_done_touch == 1u)) {
			p_selfcap_measure_data->measurement_done_touch = 0u;

			slider_position= GET_SELFCAP_ROTOR_SLIDER_POSITION(0);
			
			if(slider_position < 3 ) {
				timer_running =0u;
				/* disable timer 0 interrupts */
				TIMSK0 = 0x0u; 
				
				/* clear pending flags */
				TIFR0 = ((1 << OCF0A) | (1<< TOV0)) ; 
				
				RESET_GPIO_PIN(LED_0_PORT,LED_0_PIN) ;
			}else if(slider_position > 252 ) {
				timer_running =0u;
				
				/* disable timer 0 interrupts */
				TIMSK0 = 0x0u; 
				
				/* clear pending flags */
				TIFR0 = ((1 << OCF0A) | (1<< TOV0)) ;
				
				SET_GPIO_PIN(LED_0_PORT,LED_0_PIN) ;

			/* 
				# if slider position is less than 3 LED is switched OFF
				# if slider position is greater than 252 LED is permanently switched 
				# ON slider position is duty cycle of soft PWM when slider position 
				# is between 5 and 252 slider position between 2 and 5 is no change 
				# zone, if this small hysteresis is not given then LED will flicker 
				# when slider position value oscillates between values 
				# < than 3  and > than 3 Ex:- say 2 and 4 value 2 will make 
				# first if to execute causing LED to OFF and 4 will cause the 
				# LED to ON executing the else part. 
			*/
				
			}else if((slider_position <= 252) && (slider_position >= 5))	{
				if(!timer_running) {
					timer_running = 1u;
					/* clear pending flags */
					TIFR0 = ((1 << OCF0A) | (1<< TOV0)) ;
					
					/* Restart the timer */
					TIMSK0 = ((1 << OCIE0A) | (1<< TOIE0)) ;					
				}
				OCR0A = slider_position;				
			}



        }/*if*/

    }/*while*/
}/*main*/



/* == Interrupt =================================== */

/*! \brief ISR routine for Timer 2 output compare match A
 *
 */
ISR(TIMER2_COMPA_vect)
{
    /* Clear the timer flag */
    TIFR2 |= OCF2A;

    /* Do something on RTC overflow here */
    if (touch_time_counter == touch_time.measurement_period_ms){
        touch_time.time_to_measure_touch = 1u;
        touch_time.current_time_ms = touch_time.current_time_ms + 
									touch_time.measurement_period_ms;
        touch_time_counter = 0u;
    }else {
        touch_time_counter++;
    }
}/*ISR(TIMER2_COMPA_vect)*/

 

Last Edited: Thu. Aug 18, 2016 - 09:40 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

amitchell wrote:
PTC Touch is easier to implement than Qmatrix

 

You can say that again!

Definitely PTC is much more user friendly and configurable compared to the traditional QTouch.

"Conversation enriches the mind, but solitude is the school of genius".

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well I have spent the last few days redesigning everything for an Atmega328PB.

 

I thought I better do a more proper job of things, any comments on the PCB design?

 

After I have the PCB finished up I will work on the code. 

 

 

Attachment(s): 

Last Edited: Thu. Aug 25, 2016 - 06:33 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So PTC got the better of QMatrix. and you decided to go ahead with that! laugh

 

The slider design looks good to me. Looking at the dead band correct towards end segments, seems that you have referred the "Capacitive Touch Long Slider Design with PTC" guide.

Hope all dimensions are as suggested in the guide.

How much is the total length of your slider? And the length of individual segments?

"Conversation enriches the mind, but solitude is the school of genius".

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You bet I read that, and about 10 other data sheets!

 

The end channels are 16mm and the middle channels are 40mm, total 196mm. Height is 24mm, I used 4mm per division with a 3mm "tooth" .3mm seperation between segments and .3mm wide traces. 

 

 

Last Edited: Thu. Aug 25, 2016 - 06:41 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hmmm, great!

 

But the height is what concerns me. 24mm, isn't that a bit too thick for a slider?

If it is going to be operated by a finger, 10~15mm should be sufficient.

 

You may consider reducing the thickness, unless you have a strong reason behind the 24mm height.

"Conversation enriches the mind, but solitude is the school of genius".

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The last slider was 24mm in height and it seems reasonable with it in hand. The slider will be completely hidden in a panel that is 500x70mm the user has no outside indication of where the slider is. I thought the height would be a benefit here, and the scale in comparison to the panel seems "nice". smiley With the angle that I think a finger will slide (quite shallow) on the panel I get about 18mm of contact. 

 

Do you see an issue with the operation of a slider this tall (24mm)?

Last Edited: Thu. Aug 25, 2016 - 07:09 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Not any concrete issues. Just that I haven't seen such a thick slider wink. With a PTC self capacitance slider, bigger electrodes will have undesirable effects such as saturation, proximity etc...

For your mutual capacitance slider, this should not be a major issue.

 

And since it has design and aesthetic significance, you can go ahead with this one.

"Conversation enriches the mind, but solitude is the school of genius".

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Looking back at the data sheet you linked. Section 3.2.2 figure 3-5 looks like I am on point... if we can trust Atmel :p.

I am liking the fact that I can use Atmel data gateway interface with the Ice to analyze the atmega328pb slider. couldn't do that with the tiny!

Last Edited: Thu. Aug 25, 2016 - 07:29 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Update:

I have new populated boards, however can't get the ICE to enter programming mode. I am looking for another laptop to test with.

I have created a new thread about the ice windows issue, if people could add known good configurations that would be great.

http://www.avrfreaks.net/forum/atmel-ice-known-good-computer-and-os

Hoping to get some real results up here soon.

Adam

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

We have progress.

ICE and an ATmega328PB working well together. And my fancy LEGO PCB jig.

now I need to combine the PWM code and the Slider code.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

amitchell wrote:
We have progress

Good to hear! :)

And the LEGO PCB looks cool!!!!

 

Just curious, 

amitchell wrote:
can't get the ICE to enter programming mode
,

How did you fix this?

"Conversation enriches the mind, but solitude is the school of genius".