Atmel AVR, too slow encoder tics counting

Do you have a question? Post it now! No Registration Necessary

Translate This Thread From English to

Threaded View
Hello,

I have problem with counting ticks of an encoder.
I can achieve about 5 kHz without errors.
Above this frequency, I loose ticks.

I use second AVR processor as the generator of
two signals -- I just test my device, without real encoder.

What to do to improve frequency ?

Below, I present my program.
Processor: AVR ATmega16
You should connect an Encoder in the way:
Canal A : PD2 i PD3
Canal B: PD4

#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include "lcd.h"

long int licz = 0;
int flagaA = 0, flagaB = 0;


SIGNAL (SIG_INTERRUPT0)
{
   if (!(inb(PIND) & 16))  /* if 0 on canal B */
        flagaA = 1;
    else                       /* otherwise, (1 on canal B) */
        flagaB = 1;
}


SIGNAL (SIG_INTERRUPT1)
{
    if (inb(PIND) & 16) {     /* if 1 on canal B */
        if (flagaA)               /* if flagaA is set */
            licz++, flagaA = 0;
    } else if (flagaB)            /* if flagaB is set */
        licz--, flagaB = 0;
}


int main(void)
{
    char s[16];

    outp(0, DDRD);

    /* Setting interrupts INT 0 i INT1 -- rising, falling edge
     */
    outp((1<<INT0)|(1<<INT1), GIMSK);
    outp((1<<ISC01)|(1<<ISC00) | (1<<ISC11), MCUCR);


    initLCD();

    sei();  /* star interrupts */

    for (;;) {
        cursorHome();
        sprintf(s, "%ld ", licz);
        showStringOnLCD(s);
    }

    return 0;
}



Re: Atmel AVR, too slow encoder tics counting
Quoted text here. Click to load it

If you want a lot faster, use hardware, like a CPLD.
If the AVR has an Up/Dn counter mode a la 89C52, the PLD
needs only do the conditioning to Dirn and Count signals.

If you only have UP counters, you can allocate two, and
internally take the difference. PLD then generates Clk_UP,
and Clk_DN pulse trains.

5KHz sounds about right for LONGINT SW -
To speed SW further, try assembler and do cascaded or queued BYTE
increments, rather than a full long int INC. Latter is simpler
to write, but every INC handles all bytes.

  In the AVR, register access is much better than DATA access,
so either move all the counter to regs, or if that chews too much
REG resource, move the LSB byte to one reg, and cascade into
pointer/data access only on overflow.
  For that, you will need to use assembler....

-jg


Re: Atmel AVR, too slow encoder tics counting
Thanks for smart advices.

Quoted text here. Click to load it

My processor has 16 MHz.
Even if execution of interrupt procedure lasts 1000 cycles
(I don`t think so it lasts as long), we should have
16000000 / 1000 = 16 kHz.
I think, my program should be able to count with
higher frequencies according to high processor
speed, and not so slow (I think not slower than e.g. 1000 cycles)
interrupt procedure.

Umpa.



Re: Atmel AVR, too slow encoder tics counting
This code:

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

unsigned long int licz = 0;
unsigned char flagaA = 0, flagaB = 0;


SIGNAL (SIG_INTERRUPT0)
{
//    cli();
   if (PIND & 4) {
       (!(PIND & 16)) ? (flagaA = 1) : (flagaB = 1);
   } else {
        if (PIND & 16) {
            if (flagaA)
                licz++, flagaA = 0;
        } else {
            if (flagaB)
                licz--, flagaB = 0;
        }
   }
// sei();
}

int main(void)
{
    outp(0, DDRD);

    outp((1<<INT0), GIMSK);
    outp((1<<ISC00), MCUCR);

    sei();

    for (;;)
        ;

    return 0;
}




Looks that in assembler:


encoder.elf:     file format elf32-avr

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         0000014a  00000000  00000000  00000094  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000000  00800060  0000014a  000001de  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000006  00800060  00800060  000001de  2**0
                  ALLOC
  3 .noinit       00000000  00800066  00800066  000001de  2**0
                  CONTENTS
  4 .eeprom       00000000  00810000  00810000  000001de  2**0
                  CONTENTS
Disassembly of section .text:

00000000 <.text>:
   0: 0c 94 2a 00  jmp 0x54
   4: 0c 94 47 00  jmp 0x8e
   8: 0c 94 45 00  jmp 0x8a
   c: 0c 94 45 00  jmp 0x8a
  10: 0c 94 45 00  jmp 0x8a
  14: 0c 94 45 00  jmp 0x8a
  18: 0c 94 45 00  jmp 0x8a
  1c: 0c 94 45 00  jmp 0x8a
  20: 0c 94 45 00  jmp 0x8a
  24: 0c 94 45 00  jmp 0x8a
  28: 0c 94 45 00  jmp 0x8a
  2c: 0c 94 45 00  jmp 0x8a
  30: 0c 94 45 00  jmp 0x8a
  34: 0c 94 45 00  jmp 0x8a
  38: 0c 94 45 00  jmp 0x8a
  3c: 0c 94 45 00  jmp 0x8a
  40: 0c 94 45 00  jmp 0x8a
  44: 0c 94 45 00  jmp 0x8a
  48: 0c 94 45 00  jmp 0x8a
  4c: 0c 94 45 00  jmp 0x8a
  50: 0c 94 45 00  jmp 0x8a
  54: 11 24        eor r1, r1
  56: 1f be        out 0x3f, r1 ; 63
  58: cf e5        ldi r28, 0x5F ; 95
  5a: d4 e0        ldi r29, 0x04 ; 4
  5c: de bf        out 0x3e, r29 ; 62
  5e: cd bf        out 0x3d, r28 ; 61
  60: 10 e0        ldi r17, 0x00 ; 0
  62: a0 e6        ldi r26, 0x60 ; 96
  64: b0 e0        ldi r27, 0x00 ; 0
  66: ea e4        ldi r30, 0x4A ; 74
  68: f1 e0        ldi r31, 0x01 ; 1
  6a: 02 c0        rjmp .+4       ; 0x70
  6c: 05 90        lpm r0, Z+
  6e: 0d 92        st X+, r0
  70: a0 36        cpi r26, 0x60 ; 96
  72: b1 07        cpc r27, r17
  74: d9 f7        brne .-10      ; 0x6c
  76: 10 e0        ldi r17, 0x00 ; 0
  78: a0 e6        ldi r26, 0x60 ; 96
  7a: b0 e0        ldi r27, 0x00 ; 0
  7c: 01 c0        rjmp .+2       ; 0x80
  7e: 1d 92        st X+, r1
  80: a6 36        cpi r26, 0x66 ; 102
  82: b1 07        cpc r27, r17
  84: e1 f7        brne .-8       ; 0x7e
  86: 0c 94 9a 00  jmp 0x134
  8a: 0c 94 00 00  jmp 0x0
  8e: 1f 92        push r1
  90: 0f 92        push r0
  92: 0f b6        in r0, 0x3f ; 63
  94: 0f 92        push r0
  96: 11 24        eor r1, r1
  98: 8f 93        push r24
  9a: 9f 93        push r25
  9c: af 93        push r26
  9e: bf 93        push r27
  a0: 82 9b        sbis 0x10, 2 ; 16
  a2: 0a c0        rjmp .+20      ; 0xb8
  a4: 84 99        sbic 0x10, 4 ; 16
  a6: 04 c0        rjmp .+8       ; 0xb0
  a8: 81 e0        ldi r24, 0x01 ; 1
  aa: 80 93 64 00  sts 0x0064, r24
  ae: 39 c0        rjmp .+114     ; 0x122
  b0: 81 e0        ldi r24, 0x01 ; 1
  b2: 80 93 65 00  sts 0x0065, r24
  b6: 35 c0        rjmp .+106     ; 0x122
  b8: 84 9b        sbis 0x10, 4 ; 16
  ba: 1a c0        rjmp .+52      ; 0xf0
  bc: 80 91 64 00  lds r24, 0x0064
  c0: 88 23        and r24, r24
  c2: 79 f1        breq .+94      ; 0x122
  c4: 80 91 60 00  lds r24, 0x0060
  c8: 90 91 61 00  lds r25, 0x0061
  cc: a0 91 62 00  lds r26, 0x0062
  d0: b0 91 63 00  lds r27, 0x0063
  d4: 01 96        adiw r24, 0x01 ; 1
  d6: a1 1d        adc r26, r1
  d8: b1 1d        adc r27, r1
  da: 80 93 60 00  sts 0x0060, r24
  de: 90 93 61 00  sts 0x0061, r25
  e2: a0 93 62 00  sts 0x0062, r26
  e6: b0 93 63 00  sts 0x0063, r27
  ea: 10 92 64 00  sts 0x0064, r1
  ee: 19 c0        rjmp .+50      ; 0x122
  f0: 80 91 65 00  lds r24, 0x0065
  f4: 88 23        and r24, r24
  f6: a9 f0        breq .+42      ; 0x122
  f8: 80 91 60 00  lds r24, 0x0060
  fc: 90 91 61 00  lds r25, 0x0061
 100: a0 91 62 00  lds r26, 0x0062
 104: b0 91 63 00  lds r27, 0x0063
 108: 01 97        sbiw r24, 0x01 ; 1
 10a: a1 09        sbc r26, r1
 10c: b1 09        sbc r27, r1
 10e: 80 93 60 00  sts 0x0060, r24
 112: 90 93 61 00  sts 0x0061, r25
 116: a0 93 62 00  sts 0x0062, r26
 11a: b0 93 63 00  sts 0x0063, r27
 11e: 10 92 65 00  sts 0x0065, r1
 122: bf 91        pop r27
 124: af 91        pop r26
 126: 9f 91        pop r25
 128: 8f 91        pop r24
 12a: 0f 90        pop r0
 12c: 0f be        out 0x3f, r0 ; 63
 12e: 0f 90        pop r0
 130: 1f 90        pop r1
 132: 18 95        reti
 134: cf e5        ldi r28, 0x5F ; 95
 136: d4 e0        ldi r29, 0x04 ; 4
 138: de bf        out 0x3e, r29 ; 62
 13a: cd bf        out 0x3d, r28 ; 61
 13c: 11 ba        out 0x11, r1 ; 17
 13e: 80 e4        ldi r24, 0x40 ; 64
 140: 8b bf        out 0x3b, r24 ; 59
 142: 81 e0        ldi r24, 0x01 ; 1
 144: 85 bf        out 0x35, r24 ; 53
 146: 78 94        sei
 148: ff cf        rjmp .-2       ; 0x148




Re: Atmel AVR, too slow encoder tics counting
How fast are you running the clock on your CPU?
What is your clock src?

Phil W



Quoted text here. Click to load it



Re: Atmel AVR, too slow encoder tics counting
Quoted text here. Click to load it
I have ATmega16 -- 16 MHz.
Clock source is internal I think, I didn`t connect any quartz.

Did I do something wrong?

Umpa.



Re: Atmel AVR, too slow encoder tics counting
Umpa schrieb:
Quoted text here. Click to load it
Have you checked the correct setup for the internal oscillator?
The ATmegas are shipped with internal RC @ 1MHz...

Alexander


Re: Atmel AVR, too slow encoder tics counting

Quoted text here. Click to load it
Hurrayy !!!
Maybe it is a cause !!
Tell me please, what cristal shall I attach, where, and what
to set up in my program ?
Or provide me with any document.

Umpa.



Re: Atmel AVR, too slow encoder tics counting
Quoted text here. Click to load it
If you don't have the Mega16 data sheet you can download it from
www.atmel.com, it contains all the information you need to either attach
a crystal or change the internal RC oscillator speed.
--
Tim Mitchell

Re: Atmel AVR, too slow encoder tics counting
Quoted text here. Click to load it

I have published an article that may be of some revelance on this topic.

http://www.embedded-designer.com/articles/c1201lt.pdf

Hope this helps
George

Re: Atmel AVR, too slow encoder tics counting

[snip]

Quoted text here. Click to load it

I couldn't read it (Acrobat 5.0 under Linux)

    -frank
--

Re: Atmel AVR, too slow encoder tics counting
One more thing.
I need to use UART transmision.
I bought 11,059 MHz cristal.
If I attach this cristal, will processor
run with 11,059 MHz frequency ?

Umpa.



Re: Atmel AVR, too slow encoder tics counting
Quoted text here. Click to load it

Your interrupt service routines will translate to only a few assembler
instructions. There's plenty processing power in the AVR to cope with this
at 5 kHz and higher.

You may want to check your LCD output routines. Check if it's disabling
interrupts somewhere.

How do you determine that you loose ticks, not by reading the the LCD I
suppose?

Rob



Re: Atmel AVR, too slow encoder tics counting

Quoted text here. Click to load it
My generator generates known numer of ticks on both chanels with
different phase.
Yea, I read LCD -- it shows smaller numer at higher frequencies.

When I add "cli" at begining of interrupt function and "sei" at the end
-- LCD shows "0" at higher frequencies. And it works correctly at
smaller frequencies.
So, I think, that processor tries to run interrupt function when
previous hasn`t finished yet.
I think, I must optimalize my code and write it in assembler.

The second thing is, when I change type of "licz" to
int (not long int), it can count ticks faster.

So, I`m almost sure, my code is too slow.

Now, I use only INT0 in my program, and I can
count ticks with a little bit more frequency -- but
not enough still.
I need about 10 kHz.

unsigned long int licz = 0;
unsigned char flagaA = 0, flagaB = 0;

SIGNAL (SIG_INTERRUPT0)
{
    // cli();
    if (PIND & 4) {
        (!(PIND & 16)) ? (flagaA = 1) : (flagaB = 1);
    } else {
        if (PIND & 16) {
            flagaA && (licz++, flagaA = 0);
        } else {
            flagaB && (licz--, flagaB = 0);
        }
    }
    // sei();
}

int main(void)
{
char s[16];
outp(0, DDRD);
outp((1<<INT0), GIMSK);
outp((1<<ISC00), MCUCR);
sei();
....
}



Re: Atmel AVR, too slow encoder tics counting
Quoted text here. Click to load it

Well, you also have to protect the reading of "licz" by a pair
of CLI/SEI (in the main code).  Don't protect the whole LCD call,
but rather copy it to a local autovar in protected fashion, and
then use the copy in the printf/LCD calls.

Re: Atmel AVR, too slow encoder tics counting
Quoted text here. Click to load it

32 bits integers are very time consuming on 8 bit uP's.
Perhaps you can use an 8 bit, and use that to adjust
a 32 bit value in your main code.

main()
{
  while(1)
  { cli()
    32bitlicz += 8bitlicz;
    8bitlicz = 0;
    sei()
    ..........
  }
}

Well, something like that. I'm not in favor of using interrupts
for encoder inputs. There are dedicated encoder frontend chips,
such as HCTL2000 etcetera, which would be my preference for reading
encoders at this speed. For reading hand turned encoders, such
as digital pots, a timer interrupt does pretty well.

The risk with this all-software method, and the speeds you have,
is loosing/gaining a few steps perhaps. Imagine the encoder/shaft is
stopped,
but vibrates. You can get nasty bursts of pulses in such situations,
as the encoder is actually going back and forth. Of course, in
many systems it may not matter much if a few steps are missed.

--
Thanks, Frank.
(remove 'x' and 'invalid' when replying by email)



Re: Atmel AVR, too slow encoder tics counting
Quoted text here. Click to load it
Hello,

My code (I posted above) counts correctly -- I know about
problem of "vibrating encoder shaft", and prepared correct
code.

Umpa.



Re: Atmel AVR, too slow encoder tics counting
Quoted text here. Click to load it
I didn`t disable interrupts myself in any code.
But, after translating code to assembler, I can see many "cli"
instructions in my source code.
When I cut LCD library and left pure interrupt function and
main(), there were no "cli" instructions in source code.

Umpa.



Re: Atmel AVR, too slow encoder tics counting
Now, I did loops at the begining
of main():

 for(i=0;i<10000;i++)
    for(j=0;j<10000;j++)
        ;

after that I initialize LCD and
display counter -- to avoid "cli"
instructions (there are no such instructions
in C code, but they apear in assembler code
generated by winavr) which could be in
LCD library.
It improved situation (I can count with a little
bit more frequencies), but not as much I would like.

Umpa.



Re: Atmel AVR, too slow encoder tics counting
Quoted text here. Click to load it

Re-write the interrupt code in assembler.  Make sure that your LCD output
function does not disable interrupts.

How fast do you want to go?

Site Timeline