Precision frequency generation

Is it possible to use the Arduino to generate a set of pulses at a given frequency? The code to calculate the pulses will take much longer to run than the intervals, so I would assume I have to use interrupts and timers.

I can't use a PWM channel because the pulses must be very close 50 microseconds each and not change as a function of frequency.

The frequency will range from 1 to 200Hz with a resolution of 0.1Hz, so an 8-bit timer won't handle it.

I'm assuming I can use floating point math to convert the frequency to a period, maybe simply the number of microseconds of the period, but I don't know how slow floating point division is.

Also, it will have to be impossible for the system to fail during the high part of the pulse, I will be switching several amps and even half a second of on-time will cause very expensive damage.

Thanks,
Jason

You can probably do your timing with delayMicroseconds() driving a digital output high and low. If your Arduino isn't doing anything other than generating the pulse train, play it safe and disable interrupts ('cli()') while the pulse train is running.

Since an error would be so expensive, consider an external missing pulse detector circuit that would fire some protection logic and generate an alarm condition if your ON pulse doesn't go low in, say, 75 microseconds. It could be something like a 555 and some logic, or even another micro.

Good luck!

Tom

I'm assuming I can use floating point math to convert the frequency to a period, maybe simply the number of microseconds of the period, but I don't know how slow floating point division is.

Stay away from floating point. Just multiply by 10 until you dont need it any more.
The AVR doesnt support it natively so it has to be emulated which is slow.

You can probably do your timing with delayMicroseconds() driving a digital output high and low. If your Arduino isn't doing anything other than generating the pulse train, play it safe and disable interrupts ('cli()') while the pulse train is running.

Since an error would be so expensive, consider an external missing pulse detector circuit that would fire some protection logic and generate an alarm condition if your ON pulse doesn't go low in, say, 75 microseconds. It could be something like a 555 and some logic, or even another micro.

The problem with delayMicroseconds is even my the Arduino isn't doing anything else, it has to calculate the amount of time to delay. A maximum pulse speed of 200Hz means I only have 5000 microseconds to do everything. I have to do an analog read, update an LCD and translate from frequency to period. The Arduino can't do it in so little time, which is why I think a timer interrupt is the way to go.

I suppose it could work if I have a PC connected to do the brute force work, but I want it to be standalone and pocket sized.

On the PIC I felt safe enough with the WDT and lots of places telling the pulse to turn off in every loop. Does Arduino have a WDT available?

Slave two Arduinos together (I2C, rs232, SPI, etc). Use one to calculate the delays, the other to generate the signal.

if one arduino is good, two is better, right? :slight_smile:

-j

I'm assuming I can use floating point math to convert the frequency to a period, maybe simply the number of microseconds of the period, but I don't know how slow floating point division is.

Stay away from floating point. Just multiply by 10 until you dont need it any more.
The AVR doesnt support it natively so it has to be emulated which is slow.

If my calculation is a number basically 10,000,000 divided by a number from 10 to 2,000 as would be needed for my frequency to period conversion, I'm not sure how that will help.

The problem with delayMicroseconds is even my the Arduino isn't doing anything else, it has to calculate the amount of time to delay. A maximum pulse speed of 200Hz means I only have 5000 microseconds to do everything. I have to do an analog read, update an LCD and translate from frequency to period. The Arduino can't do it in so little time, which is why I think a timer interrupt is the way to go.

I suppose it could work if I have a PC connected to do the brute force work, but I want it to be standalone and pocket sized.

On the PIC I felt safe enough with the WDT and lots of places telling the pulse to turn off in every loop. Does Arduino have a WDT available?

Ah, yes. That clarifies matters.

I agree. With everything else you're doing, timer interrupts are the way to go.

Unfortunately, I'm a PIC guy, too. I haven't explored the gizzard of the Arduino yet, so you'll have to rely on local expertise. Fortunately, there are a lot of folks around who know the inner workings well.

Good luck!

Tom

If my calculation is a number basically 10,000,000 divided by a number from 10 to 2,000 as would be needed for my frequency to period conversion, I'm not sure how that will help.

It doesnt but it all depends on the precision required.

You say you need 1Hz to 200Hz in 0.1Hz increments?
Multiply it by 10 so its 1 to 2000 in increments of 1.

By the way, 5 milliseconds is absolutely tons for the Arduino.
Its at least a few hundred instructions (calculator not working because I'm doing a really stupid system upgrade).
I'd drive the LCD with another AVR however. It takes more time than you have with a safety net of a few instructions.

I agree with cheater that you can do lots of stuff on the arduino in 5ms, and it is easier if you use a second AVR for the display, but it is possible to do the analogRead, calculations and LCD updates in the timeframe you have.

If you need to squeeze the app down to one processor then the LCD library referenced on this page http://homepage.hispeed.ch/peterfleury/avr-lcd44780.html can write two 16 character lines in just over 3 milliseconds in 4 bit mode. The more common 4bit library linked in the playground is too slow for your requirements.

Your app is a little similar to something I had done so I modified some code to create a little test sketch to enable actual time measurements using a Logic Analyzer (HP/Agilent 16500C)

Here is the test sketch:

#include <lcd.h>

// an arduino sketch to test the LCD Library  speed

// macros to fast pulse arduino pins (over 35 times quicker than digitalWrite)
#define fastWrite2(_state_)   (_state_ ? PORTD |= (0x04) : PORTD &= (~0x04)) 
#define fastWrite3(_state_)   (_state_ ? PORTD |= (0x08) : PORTD &= (~0x08))
 
void setup(){
    lcd_init(LCD_DISP_ON);
    pinMode(2,OUTPUT);  
    pinMode(3,OUTPUT);  
    lcd_clrscr();
    delay(2);
}
#define MS_TIMES_TEN 10000L  // number of milliseconds in a second times ten, (avoids floating point)
unsigned int   period;
unsigned int    freq ;


void display(unsigned int freq, unsigned int period){
// display frequency as 1.0 to 200.0 with .1 sec increments on line 1
// display period in ms on line 2
  char buf[17];
  
       lcd_clrscr();

       lcd_gotoxy(0,0);          // first line
       lcd_puts("Frequency = ");                
       itoa(freq / 10,buf,10); 
       lcd_puts(buf);        
       lcd_puts("."); 
       itoa(freq %10,buf,10); 
       lcd_puts(buf); 
       

       lcd_gotoxy(0,1);    // second line
       lcd_puts("Period = ");                
       itoa(period,buf,10); 
       lcd_puts(buf);           
}


void loop(){
       fastWrite2(HIGH);
       freq = analogRead(0) * 10 ;
       period = MS_TIMES_TEN / freq;
       fastWrite3(HIGH);
       display(freq, period);         
       fastWrite2(LOW);                         
       fastWrite3(LOW);  
}

The total time was just under 3 ¼ milliseconds so you have elbow room to do other stuff.

I hope that helps.

Here is the test sketch:
...
I hope that helps.

It looks like pretty much exactly what I'm trying to do. I'm surprised you needed the fastwrite macros, I didn't realize arduino was slow to do digital IO.

Also, I'm a bit confused by your analog read:
"freq = analogRead(0) * 10 ;"

Don't you have to normalize the number? It looks like this line will give you a number from 0 to 10230 in steps of 10, when what you really need is a number from 10-2000 in steps of 1 (which you can't do with a 10-bit ADC, but that's another issue).

Also, when I said 5ms wasn't enough time, I my problems on the PIC were mostly waiting for the LCD to update.

Do you think Ardunio will add native support for timer interrupts in the future?

It looks like pretty much exactly what I'm trying to do. I'm surprised you needed the fastwrite macros, I didn't realize arduino was slow to do digital IO.

Also, I'm a bit confused by your analog read:
"freq = analogRead(0) * 10 ;"

Don't you have to normalize the number? It looks like this line will give you a number from 0 to 10230 in steps of 10, when what you really need is a number from 10-2000 in steps of 1 (which you can't do with a 10-bit ADC, but that's another issue).

Also, when I said 5ms wasn't enough time, I my problems on the PIC were mostly waiting for the LCD to update.

Do you think Ardunio will add native support for timer interrupts in the future?

> I'm surprised you needed the fastwrite macros, I didn't realize arduino was slow to do digital IO.
The Arduino takes under 5 microseconds so its plenty fast enough for your app but I wanted the minimum overhead because the pulses were triggering timing measurements on a logic analyzer to see exactly how long it took to do the math and analogRead

> Also, I'm a bit confused by your analog read: "freq = analogRead(0) * 10 ;"
Yes, it does need to be normalized. I just wanted to get any old reading for timing purposes.

>I really need a number from 10-2000 in steps of 1 (which you can't do with a 10-bit ADC?
Could you have the steps change from .1 to 1 for frequencies above 90hz?
If not, you could use the pot value to control incrementing and decrementing the frequency, with the rate of change proportional to how far the pot is moved CW or CCW off center.
I would recommend the latter with a bit of dead band in the center if you need it to be stable to .1hz because there can be jitter in the pot value.

>Also, when I said 5ms wasn't enough time, I my problems on the PIC were mostly waiting for the LCD to update.
Yes, as cheater pointed out, the LCD can be a bottleneck but there are ways to overcome this.

>Do you think Ardunio will add native support for timer interrupts in the future?
Perhaps one of the Arduino development team members could comment on this?