Attiny85 Manchester Encoding Timing Problem

Thread Starter

Obreezy

Joined Aug 9, 2014
11
Hello, I've been having trouble getting this little timer routine to work correctly. I started out with a little program that switches the output of a pin every 240µs which turned out to work as expected:

C:
// This program switches the output of PB3 every 240µs.

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

ISR(TIMER0_COMPA_vect)
{
        PORTB ^= _BV(PB3);
}

int main()
{
        DDRB |= _BV(PB3);
        TCCR0A = _BV(WGM01);
        TCCR0B = _BV(CS00);
        TIMSK = _BV(OCIE0A);
        OCR0A = 240;
        sei();
     
        while(1);
}


Then I started on the manchester encoding program building on the first program.
C:
// This program shifts out one byte on PB3 manchester encoded.
#include <avr/interrupt.h>
#include <avr/io.h>
#include <stdbool.h>
#include <stdint.h>

#define set(X) PORTB |= _BV(X)
#define clr(X) PORTB &= ~_BV(X)
#define tgl(X) PORTB ^= _BV(X)

volatile bool waiting;

ISR(TIMER0_COMPA_vect)
{
        waiting = 0;
}


void delay(uint8_t t)
{
        waiting = 1;

        TCCR0A = _BV(WGM01);
        TCCR0B = _BV(CS00);
        TIMSK = _BV(OCIE0A);
        OCR0A = t;
        sei();

        while(waiting);

        cli();
        TCCR0B = 0; // stop timer
        TCNT0 = 0; // reset timer counter

        return;
}

int main()
{
        DDRB |= _BV(PB3);
        set(PB3); // 1. Begin with the output signal high.

        uint8_t byte = 0X55;

        int i;
        for(i = 0; i < 8; i++) // 2. check if all bits have been sent
        {       // 3. 4. 5.
                if(byte & 1)
                {       // ManchesterOne
                        clr(PB3);
                        delay(200);
                        set(PB3);
                        delay(200);
                }
                else      
                {       // ManchesterZero
                        set(PB3);
                        delay(200);
                        clr(PB3);
                        delay(200);
                }
                byte >>= 1;
        }         // 6. Return to step 2.

        set(PB3); // 7. Set output signal high and return.
                     
     
        while(1);
}
The output was really unexpected, I put in mid-bit time(T) of 200µs so it would be easy to see if it was working right with the oscilloscope grid at 200µs per div (I zoomed out to 400µs/div when I saw it), it ended up looking like this:


Realizing something was wrong with the timing, I took the new delay function and put it in its own program to try to figure out where I messed up. I noticed that it seems to take a long time to access certain registers, when I change TCCR0B to turn the timer on and off from inside the delay function, it adds a lot of extra delay in the function.

C:
// This program is a simple delay routine from 1 to 255 µs.
#include <avr/interrupt.h>
#include <avr/io.h>
#include <stdbool.h>
#include <stdint.h>

#define set(X) PORTB |= _BV(X)
#define clr(X) PORTB &= ~_BV(X)
#define tgl(X) PORTB ^= _BV(X)

volatile bool waiting;

ISR(TIMER0_COMPA_vect)
{
        waiting = 0;
}


void delay(uint8_t t)
{
        waiting = 1;
        TCNT0 = 0;
        OCR0A = t;
        sei();

        while(waiting);

        cli();

        return;
}

int main()
{
        DDRB |= _BV(PB3);

        TCCR0A = _BV(WGM01);
        TCCR0B = _BV(CS00);
        TIMSK = _BV(OCIE0A);

        set(PB3); // 1. Begin with the output signal high.


        while(1)
        {
                delay(200);
                tgl(PB3);
        }
     
}


The call to the function calls it with the value 200, so I would have liked to see 200µs between toggles on the scope. But it's actually toggling it at around 235µs. I know it's a software issue because the first basic timer program worked just fine. I'm just not seeing where I messed up in making the software. Also if I made some mistakes in the manchester encoding part please let me know, I haven't really gotten that far yet. I used this guide by atmel to put together the manchester encoding part.
 
Last edited:

Thread Starter

Obreezy

Joined Aug 9, 2014
11
Nice I got it working after moving some stuff around. Turns out resetting the counter was the problem. so this one works now.

C:
// This program is a simple delay routine from 1 to 255 µs.
#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>
#include <stdbool.h>
#include <stdint.h>

#define set(X) PORTB |= _BV(X)
#define clr(X) PORTB &= ~_BV(X)
#define tgl(X) PORTB ^= _BV(X)

volatile bool waiting;

ISR(TIMER0_COMPA_vect)
{
        waiting = 0;
}


void delay(uint8_t t)
{
        waiting = 1;
        OCR0A = t;
        sei();

        while(waiting);

        cli();

        return;
}

int main()
{
        DDRB |= _BV(PB3);

        TCCR0A = _BV(WGM01);
        TCCR0B = _BV(CS00);
        TIMSK = _BV(OCIE0A);

        set(PB3); // 1. Begin with the output signal high.


        while(1)
        {
                delay(200);
                tgl(PB3);
        }
      
}
 
Good deal that you got it working.

Since you are not returning a value in void delay(uint8_t t), and the return (in line 31) is the last statement in the function, it seems unnecessary. I just thought off the top of my head that it might be adding some overhead, but it clearly does not..
 

Thread Starter

Obreezy

Joined Aug 9, 2014
11
Actually it is working pretty good. But now I have a weird problem. It works fine when it has a delay of 200µs, but when I had a bunch of calls that were 100µs apart, it alternates between 110µs and 90µs. I tested the function in <util/delay.h>, and it has almost the same result, 110µs and 100µs. Maybe it's still good enough for this encoding though.
 
Top