Timer0(CTC) and Timer2(PWM) can't run at the same time?

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

Hi, I'm working with ATMEGA328P at 8Mhz..

I have Timer0 in CTC mode with COMPA enable for receiving infrared signal..the code works and I can get the address of remote button..

Seperately, I also have Timer2 in PWM with OVF to dim LED...this also works..

The problem now is..after merging these two and compiled without errors, only my LED lights up with correct brightness...meaning PWM works..but my ir remote doesn't work anymore..

I tried to uncomment Timer2 clock prescaler that disables the LED...again the ir remote works...

How can I have both LED and ir remote to work..? I would like to adjust the brightness of LED using the ir remote..

 

I am using ir remote code from Łukasz Marcin Podkalicki

 

/**
 * Copyright (c) 2016, Łukasz Marcin Podkalicki <lpodkalicki@gmail.com>
 * IR Remote for ATtiny13
 */

#include <util/delay.h>
#include <avr/interrupt.h>
#include "ir.h"
#include "Atmel/remote.h"

volatile uint16_t IR_timeout = 0;
volatile uint16_t IR_counter = 0;
volatile uint32_t IR_rawdata = 0;

uint8_t IR_event = 0;
uint8_t IR_proto_event = 0;
uint8_t IR_index = 0;
uint32_t IR_data = 0;

void
IR_init()
{
	cli();
	DDRD &= ~_BV(IR_IN_PIN); // set IR IN pin as INPUT
	PORTD &= ~_BV(IR_IN_PIN); // set LOW level to IR IN pin
	TCCR0A = (1<<WGM01); // set timer counter mode to CTC
    TCCR0B = (0<<CS02) | (0<<CS01) | (1<<CS00); // set prescaler to 1
	TIMSK0 = (1<<OCIE0A); // enable Timer COMPA interrupt
	OCR0A = IR_OCR0A; // set OCR0n to get ~38.222kHz timer frequency
	EIMSK |= _BV(INT0); // enable INT0 interrupt handler
	EICRA &= ~_BV(ISC01); // trigger INTO interrupt on raising and falling edge
	EICRA |= _BV(ISC00);
    sei(); // enable global interrupts
}

int8_t
IR_read(uint8_t *address, uint8_t *command)
{
	if (!IR_rawdata)
		return IR_ERROR;

	*address = IR_rawdata;
	*command = IR_rawdata >> 16;
	IR_rawdata = 0;

	return IR_SUCCESS;
}

static int8_t
IR_NEC_process(uint16_t counter, uint8_t value)
{
	int8_t retval = IR_ERROR;

	switch(IR_proto_event) {
	case IR_PROTO_EVENT_INIT:
		/* expecting a space */
		if (value == HIGH) {
			if (counter > 330 && counter < 360) {
				/* a 4.5ms space for regular transmition of NEC Code; counter => 0.0045/(1.0/38222.0) * 2 = 344 (+/- 15) */
				IR_proto_event = IR_PROTO_EVENT_DATA;
				IR_data = IR_index = 0;
				retval = IR_SUCCESS;
			} else if (counter > 155 && counter < 185) {
				/* a 2.25ms space for NEC Code repeat; counter => 0.00225/(1.0/38222.0) * 2 = 172 (+/- 15) */
				IR_proto_event = IR_PROTO_EVENT_FINI;
				retval = IR_SUCCESS;
			}
		}
		break;
	case IR_PROTO_EVENT_DATA:
		/* Reading 4 octets (32bits) of data:
    		 1) the 8-bit address for the receiving device
		 2) the 8-bit logical inverse of the address
		 3) the 8-bit command
    		 4) the 8-bit logical inverse of the command
    		Logical '0' – a 562.5µs pulse burst followed by a 562.5µs (<90 IR counter cycles) space, with a total transmit time of 1.125ms
		Logical '1' – a 562.5µs pulse burst followed by a 1.6875ms(>=90 IR counter cycles) space, with a total transmit time of 2.25ms */
		if (IR_index < 32) {
			if (value == HIGH) {
				IR_data |= ((uint32_t)((counter < 90) ? 0 : 1) << IR_index++);
                		if (IR_index == 32) {
					IR_proto_event = IR_PROTO_EVENT_HOOK;
				}
			}
			retval = IR_SUCCESS;
		}
		break;
	case IR_PROTO_EVENT_HOOK:
		/* expecting a final 562.5µs pulse burst to signify the end of message transmission */
		if (value == LOW) {
			IR_proto_event = IR_PROTO_EVENT_FINI;
			retval = IR_SUCCESS;
		}
		break;
	case IR_PROTO_EVENT_FINI:
		/* copying data to volatile variable; raw data is ready */
		IR_rawdata = IR_data;
		break;
	default:
		break;
	}

	return retval;
}

static void
IR_process()
{
	uint8_t value;
	uint16_t counter;

	/* load IR counter value to local variable, then reset counter */
	counter = IR_counter;
	IR_counter = 0;

	/* read IR_IN_PIN digital value (NOTE: logical inverse value = value ^ 1 due to sensor used) */
	value = (PIND & (1 << IR_IN_PIN)) > 0 ? LOW : HIGH;

	switch(IR_event) {
	case IR_EVENT_IDLE:
		/* awaiting for an initial signal */
		if (value == HIGH) {
			IR_event = IR_EVENT_INIT;
		}
		break;
	case IR_EVENT_INIT:
		/* consume leading pulse burst */
		if (value == LOW) {
			if (counter > 655 && counter < 815) {
				/* a 9ms leading pulse burst, NEC Infrared Transmission Protocol detected,
				counter = 0.009/(1.0/38222.) * 2 = 343.998 * 2 = 686 (+/- 30) */
				IR_event = IR_EVENT_PROC;
				IR_proto_event = IR_PROTO_EVENT_INIT;
				IR_timeout = 7400;
			} else {
				IR_event = IR_EVENT_FINI;
			}
		} else {
			IR_event = IR_EVENT_FINI;
		}
		break;
	case IR_EVENT_PROC:
		/* read and decode NEC Protocol data */
		if (IR_NEC_process(counter, value))
			IR_event = IR_EVENT_FINI;
		break;
	case IR_EVENT_FINI:
		/* clear timeout and set idle mode */
		IR_event = IR_EVENT_IDLE;
		IR_timeout = 0;
		break;
	default:
		break;
	}

}

extern char eKEY;//from remote.c emergency key interrupt

ISR(INT0_vect)
{
	IR_process();
}

ISR(TIMER0_COMPA_vect)
{
	/* When transmitting or receiving remote control codes using the NEC IR transmission protocol,
	the communications performs optimally when the carrier frequency (used for modulation/demodulation)
 	is set to 38.222kHz. */
	if (IR_counter++ > 10000)
		IR_event = IR_EVENT_IDLE;
	if (IR_timeout && --IR_timeout == 0)
		IR_event = IR_EVENT_IDLE;

}

In main:

/*
 * TEST.c
 *
 * Created: 7/24/2019 2:39:37 PM
 * Author : User10
 */ 

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdio.h>
#include "Andy Gock/uartlibrary/uart.h"
#include "Lukasz Marcin Podkalicki/013_ir_receiver_38khz_nec_proto_analyzer/ir.h"

double dutyCycle = 10;
char sprinf_buff[50];

int main(void)
{
	uart_init(UART_BAUD_SELECT_DOUBLE_SPEED(9600,F_CPU));
	uart_puts("ready\r\n");

	//init led pin
	DDRD |= (1<<DDD3);

	//init timer
	TCCR2A = (1 << COM2B1) | (1 << WGM21) | (1 << WGM20);
	TCCR2B = (0 << CS22) | (1 << CS21) | (1 << CS20);/////////I uncommented this to get Timer0 to work
	TIMSK2 = (1 << TOIE2);

	OCR2B = (dutyCycle/100.0)*255.0;

	sei();

	uint8_t addr, cmd;
	IR_init();

	while(1)
    {
		//_delay_ms(1000);

		//dutyCycle += 10;

		if(dutyCycle > 100)
		{
			dutyCycle = 0;
		}

		if (IR_read(&addr, &cmd) == IR_SUCCESS)
		{
			//method 1
			sprintf(sprinf_buff, "addr=0x%x\r\ncmd=0x%x\r\n", addr, cmd);
			uart_puts(sprinf_buff);
		}
    }
}

ISR(TIMER2_OVF_vect)
{
	OCR2B = (dutyCycle/100.0)*255;
}

EDIT: I meant to say Timer2..not Timer1...But even if I use Timer1 the outcome is exactly the same

This topic has a solution.

Hobbyist
Language:C
IDE:Atmel Studio v7.0.1931
Compiler:gcc v5.4.0 (AVR_8_bit_GNU_Toolchain_3.6.1_1750)
Tool:Atmel-ICE v1.27

Last Edited: Tue. Nov 12, 2019 - 07:32 AM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

if timer2 is generating pwm, why do you have the overflow interrupt? I've not looked at what settings you have for timer2, but my guess is the timer2 interrupt is stealing too much cpu time. Coupled with that is the floating point calculations you are doing. With avrgcc, double is only single precision floating point, but more so, you really only need integer calcs and you don't need to calculate them each cycle - only do the duty cycle scaling when you need to change the pwm value. Or simply use 0..255 rather than 0..100 and skip the scaling.

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

Kartman wrote:
if timer2 is generating pwm, why do you have the overflow interrupt?

I deleted the interrupt and now its working like I wanted..thank you..

 

Kartman wrote:
Or simply use 0..255 rather than 0..100 and skip the scaling.

I will do this...thank you again :)

Hobbyist
Language:C
IDE:Atmel Studio v7.0.1931
Compiler:gcc v5.4.0 (AVR_8_bit_GNU_Toolchain_3.6.1_1750)
Tool:Atmel-ICE v1.27