Motherboard Forums


Reply
Thread Tools Display Modes

Atmel AVR, too slow encoder tics counting

 
 
Umpa
Guest
Posts: n/a
 
      05-06-2004, 10:54 PM
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;
}


 
Reply With Quote
 
 
 
 
Jim Granville
Guest
Posts: n/a
 
      05-06-2004, 11:28 PM
Umpa wrote:
> 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 ?


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

 
Reply With Quote
 
 
 
 
Phil W
Guest
Posts: n/a
 
      05-07-2004, 02:45 AM
How fast are you running the clock on your CPU?
What is your clock src?

Phil W



"Umpa" <@umpaumpalala.com> wrote in message
news:c7efnb$qna$(E-Mail Removed)...
> 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;
> }
>
>



 
Reply With Quote
 
Rob Turk
Guest
Posts: n/a
 
      05-07-2004, 07:23 AM
"Umpa" <@umpaumpalala.com> wrote in message
news:c7efnb$qna$(E-Mail Removed)...
> 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 ?


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


 
Reply With Quote
 
Umpa
Guest
Posts: n/a
 
      05-07-2004, 08:03 AM

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

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();
.....
}


 
Reply With Quote
 
Umpa
Guest
Posts: n/a
 
      05-07-2004, 08:07 AM
> How fast are you running the clock on your CPU?
> What is your clock src?
>

I have ATmega16 -- 16 MHz.
Clock source is internal I think, I didn`t connect any quartz.

Did I do something wrong?

Umpa.


 
Reply With Quote
 
Umpa
Guest
Posts: n/a
 
      05-07-2004, 08:37 AM
Thanks for smart advices.

> 5KHz sounds about right for LONGINT SW -


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.


 
Reply With Quote
 
Umpa
Guest
Posts: n/a
 
      05-07-2004, 08:48 AM
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



 
Reply With Quote
 
Umpa
Guest
Posts: n/a
 
      05-07-2004, 08:54 AM
> You may want to check your LCD output routines. Check if it's disabling
> interrupts somewhere.
>

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.


 
Reply With Quote
 
Umpa
Guest
Posts: n/a
 
      05-07-2004, 09:08 AM
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.


 
Reply With Quote
 
 
 
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Atmel AT91SAM7S Manchester encoder/decoder Stef Embedded 8 08-14-2006 06:55 PM
Problem with Atmel 90s2313 / Probleem met Atmel 90s2313 Erwin Rensink Embedded 5 02-19-2004 03:45 PM
Re: Atmel Avr, encoder's ticks counting (was: Atmel Avr, n-coder`s ticks counting) Jan-Hinnerk Reichert Embedded 0 08-23-2003 12:38 AM
Re: Atmel Avr, n-coder`s ticks counting Rich Webb Embedded 0 08-22-2003 11:53 PM
Re: Atmel Avr, n-coder`s ticks counting Rikko Embedded 0 08-22-2003 06:18 PM


All times are GMT. The time now is 01:28 AM.


Welcome!
Welcome to Motherboard Point
 

Advertisment