Paul,
I have been attempting to create a high-accuracy square-wave frequency sweep generator in the 50-1000Hz range, and have tried several different techniques suggested in this forums. The best one so far has been the IntervalTimer technique, except the requirement to stop and then restart the timer creates fairly significant frequency artifacts when changing frequencies.
A friend noted that the countown registers in Kinetis K64 PIT module can, at least in theory, be reloaded with a new countdown value without having to restart the timer. This feature would make it perfect for sweep generator applications, as there would be no need for the current teardown/setup delay.
Any chance something like a 'IntervalTimer::UpdateInterval(void (*funct)(), uint32_t cycles)' function could be added to the IntervalTimer.cpp/h files? I have looked at the code (to the extent that I am able), and it seems like this function could be very similar to the current 'beginCycles()' function.
Actually, it just occurred to me that I might be able to simply call 'begin()' multiple times without calling 'end()' - would that work?
I started with Paul's IntervalTimer sample code, and set up a loop to step through several frequencies. In one test, I called begin() at the beginning of each freq step, and end() at the end. In another, I called begin() at the beginning of each step, but only called end() after all steps were completed. Nothing blew up - so that was a plus ;-). I have attached a screenshot showing the two results, and the complete code. Comments?
Frank
I have been attempting to create a high-accuracy square-wave frequency sweep generator in the 50-1000Hz range, and have tried several different techniques suggested in this forums. The best one so far has been the IntervalTimer technique, except the requirement to stop and then restart the timer creates fairly significant frequency artifacts when changing frequencies.
A friend noted that the countown registers in Kinetis K64 PIT module can, at least in theory, be reloaded with a new countdown value without having to restart the timer. This feature would make it perfect for sweep generator applications, as there would be no need for the current teardown/setup delay.
Any chance something like a 'IntervalTimer::UpdateInterval(void (*funct)(), uint32_t cycles)' function could be added to the IntervalTimer.cpp/h files? I have looked at the code (to the extent that I am able), and it seems like this function could be very similar to the current 'beginCycles()' function.
Actually, it just occurred to me that I might be able to simply call 'begin()' multiple times without calling 'end()' - would that work?
I started with Paul's IntervalTimer sample code, and set up a loop to step through several frequencies. In one test, I called begin() at the beginning of each freq step, and end() at the end. In another, I called begin() at the beginning of each step, but only called end() after all steps were completed. Nothing blew up - so that was a plus ;-). I have attached a screenshot showing the two results, and the complete code. Comments?
Code:
// Create an IntervalTimer object
IntervalTimer myTimer;
const int ledPin = LED_BUILTIN; // the pin with a LED
const int OUTPUT_PIN = 33;
const int TSTAMP_ARRAY_LENGTH = 5000;
int aTimeStamp[TSTAMP_ARRAY_LENGTH];
// The interrupt will blink the LED, and keep
// track of how many times it has blinked.
int ledState = LOW;
volatile unsigned long TransCount = 0; // use volatile for shared variables
void setup(void)
{
Serial.begin(460800);
pinMode(ledPin, OUTPUT);
pinMode(OUTPUT_PIN, OUTPUT);
for (size_t i = 0; i < TSTAMP_ARRAY_LENGTH; i++)
{
aTimeStamp[i] = 0;
}
Serial.println("Freq\tTimerVal");
for (size_t i = 501; i <= 531; i++)
{
float period = 1e6 / i;
//Serial.print(i); Serial.print("\t"); Serial.println(period);
myTimer.begin(blinkLED, period / 2);
//Serial.print(i); Serial.print("\t"); Serial.println(period);
delay(500);
myTimer.end();
}
//myTimer.end();
}
// functions called by IntervalTimer should be short, run as quickly as
// possible, and should avoid calling other functions if possible.
void blinkLED(void)
{
if (ledState == LOW)
{
ledState = HIGH;
}
else
{
ledState = LOW;
}
digitalWrite(ledPin, ledState);
digitalWrite(OUTPUT_PIN, ledState);
aTimeStamp[TransCount] = micros();
TransCount++;
if (TransCount >= TSTAMP_ARRAY_LENGTH)
{
myTimer.end();
Serial.println("TimeStamps");
for (size_t i = 0; i < TSTAMP_ARRAY_LENGTH; i++)
{
if (aTimeStamp[i] > 0)
{
Serial.println(aTimeStamp[i]);
}
}
Serial.println("Exiting - Bye!");
//infinite loop
while (true)
{
}
}
}
// The main program will print the blink count
// to the Arduino Serial Monitor
void loop(void) {
unsigned long TransCountCopy; // holds a copy of the blinkCount
//to read a variable which the interrupt code writes, we
//must temporarily disable interrupts, to be sure it will
//not change while we are reading. To minimize the time
//with interrupts off, just quickly make a copy, and then
//use the copy while allowing the interrupt to keep working.
noInterrupts();
TransCountCopy = TransCount;
interrupts();
Serial.println(TransCountCopy);
delay(100);
}
Frank