Atmel AVR, too slow encoder tics counting

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 #include #include #include #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

Reply to
Umpa
Loading thread data ...

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 to
Jim Granville

How fast are you running the clock on your CPU? What is your clock src?

Phil W

Reply to
Phil W

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 to
Rob Turk

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

Reply to
Umpa

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

Did I do something wrong?

Umpa.

Reply to
Umpa

Thanks for smart advices.

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 to
Umpa

This code:

#include #include #include #include

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

Reply to
Umpa

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 to
Umpa

Now, I did loops at the begining of main():

for(i=0;i

Reply to
Umpa

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?

Reply to
jetmarc

That needs a "volatile".

Reply to
jetmarc

Umpa schrieb:

Have you checked the correct setup for the internal oscillator? The ATmegas are shipped with internal RC @ 1MHz...

Alexander

Reply to
Alexander Peter

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.

Reply to
Umpa

10 kHz would be enough. But, above two people have said that my ATmega16 works with 1MHz frequency, and I need to attach cristal. I think, it solves my problem.

Umpa.

Reply to
Umpa

In article , Umpa

Reply to
Tim Mitchell

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.

Reply to
Umpa

Umpa schrieb:

You can set up your internal RC to 8 or 16MHz by progamming the corrseponding fuses. Look at the datasheet!

Alexander

Reply to
Alexander Peter

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.

Reply to
jetmarc

The above most definitely needs to be 'volatile' to keep the optimizer from caching the value in registers since it has no idea it might be updated out of band in the interrupt routine.

Hmmm ... these are probably OK as is.

-Brian

--
Brian Dean
http://www.bdmicro.com/
Reply to
Brian Dean

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.