Amtel Qmatrix - PWM Timer conflict or sucky code? - Page 1
Forum section: electronics / projects

author: amitchell
author_rank: Regular Contributor
timestamp: August 17, 2016, 12:21:56 am
content: My name is Adam and I will use this as a hello if that is ok with folks. I am a long time lurker. I have banged my head long enough with this and now I will suck it up and as for help.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_agWe can see that Qmatrix uses Timer1 internally all the time or just sometimes?QuoteandQuoteHmm 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.Code:#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 regularlyInput : n/aOutput : n/aNotes :============================================================================*/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 ISRInput : n/aOutput : n/aNotes :============================================================================*/ISR(TIM0_COMPA_vect){#ifdef QDEBUG_TWIif (gMsTimeout){gMsTimeout--;}#endiftime_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);}#endifmain.c showing my PWM codeCode:#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/*----------------------------------------------------------------------------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 pointInput : n/aOutput : n/aNotes :============================================================================*/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 prescalerTCCR1B |= (1<<WGM13)|(1<<CS10);// OCR1A sets TOP for Waveform Generator Mode 11OCR1A = 255;// Sets PortA Pin5 as output - IC actual pin 20 OC1BDDRA |= (1<<DDA5);// Duty cycle for waveform = (OCR1B/255) this will be the slider position variableOCR1B = slider_value;}}}Captured waveforms are attached 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.Adam