| Author |
Message |
|
|
Posted: Apr 05, 2012 - 04:03 AM |
|

Joined: Mar 05, 2012
Posts: 9
|
|
hi. am doing a project which asks for taking 1 square wave signal of 50% duty cycle as input, get its characteristics and generate 2 signals which are in quadrature and of same frequency. am using ATmega32. the input signal frequency can vary from 100Hz to 60kHz. as of now i'am using the Input capture unit to deduce the period of the input signal and use the same to produce the output signal.
but the code is not working as expected for a sample input signal of 20kHz.
according to calculations, ICR1 register should have a value of 0x0229. but the output signal frequency is oly about 5kHz. when i manually write
tim = (0x029)/(11.0592*4), the output is proper 20kHz. am not understanding what the pronlem is.. help...
Code:
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <inttypes.h>
#include <avr/pgmspace.h>
volatile uint16_t pul = 65530;
double tim = 0;
ISR(TIMER1_CAPT_vect)
{
pul = ICR1H;
TCNT1 = 0;
}
int main(void)
{
sei();
DDRA = 0xFF;
DDRD = 0x00;
DDRC = 0xFF;
TCCR1A = 0x00;
TCNT1 = 0x0000;
TCCR1B = 0x40;
TCCR1B = 0x41;
TIMSK &= 0x20;
TIMSK |= 0x21;
_delay_ms(100);
while(1)
{
tim = pul/(11.0592*4);
PORTA = 0x0C;
_delay_us(tim);
PORTA = 0x06;
_delay_us(tim);
PORTA = 0x03;
_delay_us(tim);
PORTA = 0x09;
_delay_us(tim);
}
}
$ Fixed code tags - JS $ |
|
|
| |
|
|
|
|
|
Posted: Apr 05, 2012 - 06:44 AM |
|

Joined: Aug 07, 2007
Posts: 1477
Location: Czech
|
|
|
Code:
ISR(TIMER1_CAPT_vect)
{
pul = ICR1H;
Why do you read only high byte? |
|
|
| |
|
|
|
|
|
Posted: Apr 05, 2012 - 02:24 PM |
|


Joined: Feb 19, 2001
Posts: 25922
Location: Wisconsin USA
|
|
First, digest this recent thread:
http://www.avrfreaks.net/index.php?name ... hase+shift
Quote:
and of same frequency.
I read that, and thought that the output signal had the same frequency plus another signal phase-shifted 90 degrees. But the we see
Quote:
tim = pul/(11.0592*4);
??? IS this your AVR's frequency?
In any case, tell at least an example of the desired output frequency for an input frequency of a given value.
You say you are achieving about 5kHz on the output. That is 200us per period. Given the floating point math and the delays ... that sounds about right. there is no reason for floating-point math to manipulate "small" integer values.
Next, I'd use a timer and output compare channels to assist rather than the variable length delays.
IIRC (you'll need to ask the GCC gurus) using _delay_us_() with a variable parameter will not give you the expected time as it does everything in floating point.
The access of "pul" in the mainline will need to be done with interrupts off.
Quote:
TCCR1B = 0x40;
TCCR1B = 0x41;
An interesting instruction sequence.
For best ICP operation, let the timer free-run and subtract prev from new to get the period. With a low prescaler your method of resetting TCNT is bound to be inaccurate.
=============
For an input signal of 20kHz that is a 50us period. GCC is not known for skinny ISRs; let's give you a time budget of 10us for the ICP interrupt. Lack of global register variables is also a hindrance for calculating new-prev, but let's say it can be done in 10us.
60kHz max is only 16us per period. And there are two outputs, so any leap-frog method is going to get very tight on time.
At this time I can't even recommend what I think might be the "best" approach. Give more info and we'll go over it again. what is the AVR's clock speed? What is the min and max input frequency? What is the transfer function for output frequency? and the resulting max output frequency? |
|
|
| |
|
|
|
|
|
Posted: Apr 07, 2012 - 02:05 PM |
|

Joined: Mar 05, 2012
Posts: 9
|
|
sorry... correction.. its actually
pul = ICR1; |
|
|
| |
|
|
|
|
|
Posted: Apr 09, 2012 - 05:00 AM |
|

Joined: Mar 05, 2012
Posts: 9
|
|
the controller is clocked to 11.0592MHz. the method I'm using to produce 2 signals of the same frequency but phase shifted by 90deg is by rotating a binary sequence 1100 through the portA low register. first i find the input signal 'period' using ICR. then i rotate the register every 'peroid/4' seconds.
so for a sample input signal of 20kHz, the period should be 50u sec. so
tim = pul / 11.0592 gives the value 50u sec. where pul is the ICR1 value for every rising edge.
if this works right, the output signal will also be 20kHz. which is not happening.
to find out if its the problem with delay_us, i disabled all interrupts and manually wrote tim = 50. and then the output was as expected.
so the problem is with the statement pul = ICR1. |
|
|
| |
|
|
|
|
|
Posted: Apr 09, 2012 - 02:36 PM |
|


Joined: Feb 19, 2001
Posts: 25922
Location: Wisconsin USA
|
|
|
Quote:
so the problem is with the statement pul = ICR1.
No, it isn't.
I will re-state a few things from my more extensive post above:
-- At 20kHz you have a 50us period to do all of your output setting. That is ~550 cycles at your clock rate.
Quote:
tim = pul/(11.0592*4);
-- This is likely to take more cycles than that by itself.
Quote:
_delay_us(tim);
-- This is likely to take more cycles than that by itself.
====================
I went on to think about how this could be done with interrupts and output compare. If you want to dedicate an entire AVR to the task then you could poll timer ticks instead of using the variable delay, which isn't going to do what you think.
Also, I see >>no<< reason to have the floating point work in there, and indeed your AVR's frequency should be immaterial. The input capture gives you ICR1 counts for the period of the signal. Shouldn't you then just wait for 1/4 of those counts for each of your output stages?
Lee |
|
|
| |
|
|
|
|
|