avr timer1 16bit fast PWM - timer

I am using an Atmega328p-pu. I am trying to use the timer 1 for both a 16 bit PWM as well as using the overflow inturrupt to increment a timer. My code is below, I also set the F_CPU to 8000000UL in the make file.
I would like the to have a variable that counts up for a defined amount of time and then resets and continues. so far I would expect it to count up for 7.5 seconds. I believe I should have a clock frequency of 8 MHz, then with fast PWM with a 1 prescaler and ICR1 at 5000 I would expect the inturrupt to happen at 1600 Hz. Then I let it count up for 12000 counts. I would expect this to take 7.5 seconds. but I've measured it at around 57 seconds. I'm not sure what I'm missing, maybe something in the setting of the registers, but I'm not sure where. thanks for your help,
here is what I think is most important,
// values for timer1
// WGM 13 12 11 10 is
// fast PWM 1 1 1 0
TCCR1A |= (1 << 7); // output on A pin (COM1A1)
TCCR1A |= (1 << 1); // WGM 11
TCCR1A &= ~(1 << 0); // WGM 10
TCCR1B |= (1 << 4); // WGM 13
TCCR1B |= (1 << 3); // WGM 12
//for prescaler of 1 set CS12 CS11 CS10
0 0 1
TCCR1B &= ~(1 << 2); // set prescaler to 1x CS12
TCCR1B &= ~(1 << 1); // set prescaler to 1x CS11
TCCR1B |= (1 << 0); // set prescaler to 1x CS10
TIMSK1 = 0; // enable output compare A inturrupt
TIMSK1 |= (1 << 0); // Set the Overflow inturrupt
TCNT1 = 0; // set the counter to zero on startup
ICR1 = 5000; //Set the top of the counter
OCR1A = 0; //set the duty cycle
....
ISR(TIMER1_OVF_vect){
longTimer++;
....
if (longTimer >= 12000){
longTimer = 0;
and here is the entire code
/* Light Control */
// ------- Preamble -------- //
#include <avr/io.h> /* Defines pins, ports, etc */
#include <avr/interrupt.h>
// Global variables
volatile uint8_t tick = 0;
volatile uint8_t fastTimer = 0;
volatile uint16_t longTimer = 0;
volatile uint16_t fader = 0;
volatile uint16_t dayBrightness = 0;
volatile uint8_t nightBrightness = 0;
uint8_t Day = 0;
void init(void) {
// values for push button inturrupt
EIMSK = (1 << 0);
EICRA = (1 << 1) & (1 << 0);
// values for timer1
// WGM 13 12 11 10 is
// fast PWM 1 1 1 0
TCCR1A |= (1 << 7); // output on A pin (COM1A1)
TCCR1A |= (1 << 1); // WGM 11
TCCR1A &= ~(1 << 0); // WGM 10
TCCR1B |= (1 << 4); // WGM 13
TCCR1B |= (1 << 3); // WGM 12
//for prescaler of 1 set CS12 CS11 CS10
0 0 1
TCCR1B &= ~(1 << 2); // set prescaler to 1x CS12
TCCR1B &= ~(1 << 1); // set prescaler to 1x CS11
TCCR1B |= (1 << 0); // set prescaler to 1x CS10
TIMSK1 = 0; // enable output compare A inturrupt
TIMSK1 |= (1 << 0); // Set the Overflow inturrupt
TCNT1 = 0; // set the counter to zero on startup
ICR1 = 5000; //Set the top of the counter
OCR1A = 0; //set the duty cycle
sei();
// values for IO
DDRB |= 0b00000011; /* Data Direction Register B: writing a one to the bit enables output. */
DDRD = 0x00; /* zero sets all as input */
PORTD = 0xff; /* set all inputs as pull ups */
}
ISR(INT0_vect){
//longTimer = 0;
}
ISR(TIMER1_OVF_vect){
longTimer++;
if(Day){
fader++;
}
else{
if(fader > 0){
fader--;
}
}
}
int main(void) {
init();
// ------ Event loop ------ //
while (1) {
if(Day) {
if (fader >= 5000){
OCR1A = 5000;
}
else {
OCR1A = fader;
}
}
else {
OCR1A = fader;
}
if (longTimer >= 12000){
longTimer = 0;
if(Day){
fader = 5000;
}
else{
fader = 0;
}
tick = 1;
}
if (tick == 1){
Day ^= 1;
tick = 0;
}
} /* End event loop */
return 0; /* This line is never reached */
}

Whenever I'm using the internal oscillator and things are running either way (8x) faster, or way (8x) slower, I check the CKDIV8 bit setting. Almost always that's the culprit.
If using an external oscillator or clock, weird timings are often from not switching the the external clock in the fuse settings, or from having F_CPU set differently from actual frequency.
Also, off-topic a bit, but code such as this is redundant:
TCCR1B &= ~(1 << 2); // set prescaler to 1x CS12
TCCR1B &= ~(1 << 1); // set prescaler to 1x CS11
Those bits are zeroes by default so no reason to clear them unless it's just for clarity as you're learning.

Related

Creating a 10 second delay using ISR in TIMER1 of atmega328p

I'm trying to create a 10 second delay using TIMER1(16 bit) in atmega328p, I don't know if the delay has been created or not because it takes longer duration than 10 seconds and expected output( which is to create pwm waves) is not obtained. Here I have created a 1second delay and looped it 10 times, TIMER0 is used for creating pwm waves.
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "interrupt.h"
#define SET_BIT(PORT,BIT) PORT |= (1<<BIT)
#define CLR_BIT(PORT,BIT) PORT &= ~(1<<BIT)
struct {
volatile unsigned int BIT: 1;
}
FLAG_TIMER;
void timer_configuration() //16 bit timer
{
TCCR1A = 0x00; // Normal mode of operation
TCNT1 = 0xC2F8;
TCCR1B |= ((1 << CS10) | (1 << CS12));
TCCR1B &= ~(1 << CS11); //101
sei(); // Global interrupt
}
void timer_on()
{
TIMSK1 |= (1 << TOIE1);
}
void pwm_configuration() //TIMER0 - 8 bit
{
TCCR0A |= ((1<<WGM00) | (1<<WGM01)); //setting it to fast PWM mode
TCCR0A |= (1<<COM0A1);
TCCR0A &= ~(1<<COM0A0);
TCNT0 = 0x00;
TCCR0B |= ((1<<CS00) | (1<<CS02)); //Prescaler setting 1024
TCCR0B &= ~(1<<CS01);
sei();
}
ISR(TIMER1_OVF_vect)
{
static unsigned int counter;
counter++;
if(counter >= 10)
{
FLAG_TIMER.BIT=1;
counter = 0;
TCNT1 = 0xC2F8;
TIMSK &= ~(1<< TOIE1);
}
else
{
FLAG_TIMER.BIT=0;
}
}
int main(void)
{
SET_BIT(DDRD,PD6); //CRO
timer_configuration();
pwm_configuration();
while(1)
{
timer_on();
if(FLAG_TIMER.BIT == 1)
{
OCR0A = 128; //50% dutycycle
}
}
You set the counter to 49912 on initialisation and increment your count when it overflows, but it will then start from 0, so if 15624 counts = 1 second, then your counter will increment to 10 after 15624 + 9 x 216 counts or about 38.75 seconds.
Move the TCNT1 = 0xC2F8; line in the ISR:
ISR(TIMER1_OVF_vect)
{
static unsigned int counter;
TCNT1 = 0xC2F8;
counter++;
if(counter >= 10)
{
FLAG_TIMER.BIT=1;
counter = 0;
TIMSK &= ~(1<< TOIE1);
}
else
{
FLAG_TIMER.BIT=0;
}
}
I am not familiar with ATmega, but I cannot believe that is an appropriate way to use the timer. Normally you'd up-count to a compare value with auto reset to zero, or down-count from an auto reload value to zero and let the hardware reload the counter.

Atmega328p only one ISR handled

I'm trying to run two functions 'similtaniously' via interrupts:
1) Measure ADC via timing of timer 0 (100Hz) and show results on pin 0-5
2) Blink a led via timer 1 (10Hz) on pin 6.
Problem seems to be that the ISR of timer 1 blocks the function, so nothing else is executed. Here is the code:
(Please don't be offended by any styling mistakes, the code is under development)
#define F_CPU 16000000UL // 16MHz Clock speed
#include <avr/io.h>
#include <avr/interrupt.h>
void ADC_init(void);
void SetTimer0(void);
void SetTimer1(void);
int main(void)
{
DDRB |= (1<<DDB0) + (1<<DDB1) + (1<<DDB2) + (1<<DDB3) + (1<<DDB4) + (1<<DDB5) + (1<<DDB6);
PORTB = 0b00000000;
DDRB &= ~(1<<DDB7);
ADC_init();
SetTimer0();
SetTimer1();
while(1){
}
}
void ADC_init(void)
{
cli();
// Select Vref=AVcc
// and set left adjust result
// select pin ADC0 (PC0)
ADMUX |= (1<<REFS0)|(1<<ADLAR);
//and enable ADC
//enable ADC interupt
//enable autotriggering
//set prescaller to 128
ADCSRA |= (1<<ADEN) | (1<<ADATE) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
//set ADC trigger source - Timer0 compare match A
ADCSRB |= (1<<ADTS1)|(1<<ADTS0);
// StartADC
ADCSRA |= (1<<ADSC);
sei();
}
//initialize timer0 match A on 100hz
void SetTimer0(void)
{
cli();
TCCR0A = 0; // set entire TCCR0A register to 0
TCCR0B = 0; // same for TCCR0B
TCNT0 = 0; // initialize counter value to 0
// set compare match register for 100Hz increments
OCR0A = 155; // = 16000000 / (1024 * 100.16025641025641)-1
// toggle PD6/OC0A pin on compare match
TCCR0A |=(1<<COM0A0)|(1<<WGM01);
//Set CTC mode
TCCR0B |= (1 << WGM01);
// Set CS02, CS01 and CS00 bits for 1024 prescaler
TCCR0B |= (1 << CS02) | (0 << CS01) | (1 << CS00);
// enable timer compare interrupt
TIMSK0 |= (1 << OCIE0A);
sei();
}
//initialize timer1 10hz
void SetTimer1(void){
cli();
TCCR1A = 0; // set entire TCCR1A register to 0
TCCR1B = 0; // same for TCCR1B
TCNT1 = 0; // initialize counter value to 0
// set compare match register for 10 Hz increments
OCR1A = 24999; // = 16000000 / (64 * 10) - 1 (must be <65536)
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS12, CS11 and CS10 bits for 64 prescaler
TCCR1B |= (0 << CS12) | (1 << CS11) | (1 << CS10);
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
sei();
}
// ADC done interrupt
ISR(ADC_vect)
{
// Clear timer compare match flag
TIFR0=(1<<OCF0A);
// save ADC measurement
uint16_t val = ADC;
// show ADC results
if (val < 100)
{ PORTB = 0b00000000; }
else if (val < 300)
{ PORTB = 0b00000001; }
else if (val < 550)
{ PORTB = 0b00000011; }
else if (val < 850)
{ PORTB = 0b00000111; }
else if (val < 1020)
{ PORTB = 0b00001111; }
else
{ PORTB = 0b00011111; }
}
ISR(TIMER1_COMPA_vect)
{
//PORTB ^= PINB5;
static uint16_t on = 0;
if (on == 1){
PORTB = 0b00100000;
on = 0;
}
else {
PORTB = 0b00000000;
on = 1;
}
}
When the SetTimer1() function is disabled the DCA runs as expected. So individually are are both ISR's working fine, but together not. Could someone help me solve this problem?
You have output compare interrupt enabled fro Timer0:
// enable timer compare interrupt
TIMSK0 |= (1 << OCIE0A);
but no ISR handler for that interrupt.
The default __bad_interrupt handler just performs jump to zero interrupt vector, i.e. restarts the program.
That means if you have an interrupt enabled there should be an ISR for that interrupt.

Why is my Atmega644 TIMER0 running at half the speed of the expected clock speed?

I am trying to build a drum machine using an Atmega644. The drum machine will have 16 LED's which will show which 16th of the beat it is at. The user should be able to set the BPM and therefore the updating of the LED will be different for different BPM.
I have a 16 MHz Crystal set at XTAL1 and XTAL2. I used a FUSE calculator to write the FUSE bits to a "Full Swing Oscillator" and remove the internal clock divide 8. I then set up the TIMER0 to perform this task
#define F_CPU 16000000UL // 1MHz internal clock
unsigned int tempo = 250; // Default BPM of 120.
volatile unsigned int seq_timer = 0;
//set-up timer for 0.5 ms update
TIMSK0 = (1<<OCIE0A);
TCCR0A = (1 << WGM01) |(1<<WGM00);
TCCR0B = (0 << WGM02) | (0<< CS02) | (1 << CS01) | (1 << CS00); //divide by 64
OCR0A = 125;
ISR (TIMER0_COMPA_vect) {
if (seq_timer>0) {seq_timer--;}
}
//Update which 16th note we are at.
void step(void){
update_led();
step_number = step_number < 15 ? step_number +1 : 0;
}
//Shift the LED such that the LED corresponding to step_number is lit up.
void update_led(void) {
for (int j = 16; j>=0; j--)
{
if ((((1 << step_number))>>j) & 0x01) {
PORTD |= (1 << PD5); //Serial Input
}
else {
PORTD &= ~(1 << PD5);
}
PORTD |= (1 << PD4); //Read clock
PORTD &= ~(1<< PD4);
}
PORTD |= (1 << PD3); //Shift clock
_delay_ms(40);
PORTD &= ~(1 << PD3);
}
while (1)
{
if ((seq_timer == 0)) {
seq_timer = tempo;
step();
}
Step functions calls a "update_led()" function which light up the LED corresponding to the step_number. This should according to my calculations occur (16e6 / (64*250*125)) = 8 updates/sec. But instead it does 4 updates/sec.
Am I missing something crucial?

Variable being reset upon completion of function C

I am trying to initiate a timer with CTC and external interrupts that will count to 60 seconds and use a function to display the output to LEDs on an ATmega128. The function, as follows, will count all the way to the first iteration of the tens place when debugging, but on the next run-through the tens variable is reset to zero and I cannot understand why it is resetting. Can anyone see where I might have made an error?
#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>
#include <util/delay_basic.h>
volatile uint8_t passval = 0;
void display(uint8_t value);
int main(void)
{
DDRC = 0xFF; //PORTC output for two seven segment displays(tenths and ones place)
DDRD = 0x0F; //PORTD output for one seven segment display(tens place)
EICRA = ((1 << ISC01) | (1 << ISC00) | (1 << ISC11) | (1 << ISC10)); //Interrupt set to trigger on rising edge for PINA1...0
TCCR1B |= (1 << WGM12); //Sets CTC Mode
OCR1A = 24999; //Prescaler as 64 with a count of 25000
TCNT1 = 0; //Clears clock
TIMSK |= (1 << OCIE1A); //Enables interrupt
sei(); //Enable Global Interrupt
while (1)
{
TCCR1B |= ((1 << CS11) | (1 << CS10));
display(passval);
}
return 0;
}
void display(uint8_t value)
{
static uint8_t tenths, ones, tens;
tenths = value;
if (tenths > 0x09) //Rolls Over tenths place at 10
{
passval = 0x00;
tenths = 0x00;
ones++; //Advances ones place
if (ones > 0x09) //Rolls over ones places at 10
{
ones = 0x00;
tens++; //Advances tens place
if (tens > 0x06) //Rolls over tens place at 6
{
tens = 0x00;
}
}
}
PORTC = ((ones << 4) + tenths); //Display Output
PORTD = tens;
}
ISR (TIMER1_COMPA_vect) //Timer ISR
{
passval++; //Advance tenths place
}

AVR Butterfly - Timer reuse after internal oscillator calibration

I am calibrating the AVR Butterfly internal oscillator for being able to use USART, based on the sample code provided by AVR (see code below). As I also wanted to use two timer-controlled servo motors, I am wondering whether it is possible to reuse 16-bit timer 1 after the calibration process - I tried resetting the TCCR1A/B but it did not work out (code also below). I hope you can help me out with this.
void OSCCAL_Calibrate(void){
unsigned char calibrate = 0;
int temp;
unsigned char tempL;
CLKPR = (1<<CLKPCE); // set Clock Prescaler Change Enable
// set prescaler = 8, Inter RC 8Mhz / 8 = 1Mhz
CLKPR = (1<<CLKPS1) | (1<<CLKPS0);
TIMSK2 = 0; //disable OCIE2A and TOIE2
ASSR = (1<<AS2); //select asynchronous operation of timer2 (32,768kHz)
OCR2A = 200; // set timer2 compare value
TIMSK0 = 0; // delete any interrupt sources
TCCR1B = (1<<CS10); // start timer1 with no prescaling
TCCR2A = (1<<CS20); // start timer2 with no prescaling
while((ASSR & 0x01) | (ASSR & 0x04)); //wait for TCN2UB and TCR2UB to be cleared
delayMs(1000); // wait for external crystal to stabilise
while(!calibrate)
{
cli(); // disable global interrupt
TIFR1 = 0xFF; // delete TIFR1 flags
TIFR2 = 0xFF; // delete TIFR2 flags
TCNT1H = 0; // clear timer1 counter
TCNT1L = 0;
TCNT2 = 0; // clear timer2 counter
while ( !(TIFR2 & (1<<OCF2A)) ); // wait for timer2 compareflag
TCCR1B = 0; // stop timer1
sei(); // enable global interrupt
if ( (TIFR1 & (1<<TOV1)) )
{
temp = 0xFFFF; // if timer1 overflows, set the temp to 0xFFFF
}else
{ // read out the timer1 counter value
tempL = TCNT1L;
temp = TCNT1H;
temp = (temp << 8);
temp += tempL;
}
if (temp > 6250)
OSCCAL--; // the internRC oscillator runs to fast, decrease the OSCCAL
else if (temp < 6120)
OSCCAL++; // the internRC oscillator runs to slow, increase the OSCCAL
else
calibrate = 1; // the interRC is correct
TCCR1B = (1<<CS10); // start timer1
}
}
void motorInit(){
// reset timer 1
TCCR1A = 0;
TCCR1B = 0;
// initialize Servo Pins
DDRB |= (1<<PB5) | (1<<PB6);
ICR1H = ICR_VALUE >> 8;
ICR1L = ICR_VALUE & (TOP_VALUE);
// reset OCRs
setServoSpeed(0, 0);
setServoSpeed(1, 0);
// Set Timer mode (PWM Phase & Freq. correct, clear on compare match)
// and prescaler (8)
TCCR1A = ((1<<COM1A1) | (1<<COM1B1));
TCCR1B = ((1<<WGM13) | (0<<CS12) | (1<<CS11) | (0<<CS10));
}
Maybe you can check code which I used for a project while ago, but you should take care that I decreased the system frequency to 7.3768 MHz for 56700 baudrate, which maybe you need to adjust.
void OSCCAL_Calibrate(void)
{
uint8_t LoopCount = (0x7F / 2);
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
// Make sure all clock division is turned off (8MHz RC clock)
CLKPR = (1 << CLKPCE);
CLKPR = 0x00;
// Inital OSCCAL of half its maximum
OSCCAL = (0x7F / 2);
// Disable timer interrupts
TIMSK1 = 0;
TIMSK2 = 0;
// Set timer 2 to asyncronous mode (32.768KHz crystal)
ASSR = (1 << AS2);
// Ensure timer 1 control register A is cleared
TCCR1A = 0;
// Start both counters with no prescaling
TCCR1B = (1 << CS10);
TCCR2A = (1 << CS20);
// Wait until timer 2's external 32.768KHz crystal is stable
while (ASSR & ((1 << TCN2UB) | (1 << TCR2UB) | (1 << OCR2UB)));
// Clear the timer values
TCNT1 = 0;
TCNT2 = 0;
while (LoopCount--)
{
// Wait until timer 2 overflows
while (!(TIFR2 & (1 << TOV2)));
// Stop timer 1 so it can be read
TCCR1B = 0x00;
// Check timer value against ideal constant
if (TCNT1 > OSCCAL_TARGETCOUNT) // Clock is running too fast
OSCCAL--;
else if (TCNT1 < OSCCAL_TARGETCOUNT) // Clock is running too slow
OSCCAL++;
// Clear timer 2 overflow flag
TIFR2 |= (1 << TOV2);
Check this out!

Resources