I have a project going on where everything is working as it should, except that a routine that relies on micros is off by a factor of 2 when using 8 or 16 MHz internal, and off by a factor of 2.4 when using internal 1 MHz clock. I am assuming there is simply something I am unaware of, but can't figure out what, for the life of me.
I have stripped the code down to its barebones essentials in the block below. The idea is that I have a lookup table for a single full cycle of a sine wave and I am going to be outputting the sine wave as a series of PWM steps. So in the updatePWM() routine, it uses micros() to get the current time, compare to the last time I updated the PWM, and then updates if it is longer than the amount of time to dwell at each step. So I am just holding the PWM duty cycle constant until it's time for moving on to the next entry. The LED flashes just like I would expect, except for the fact that the amount of time to complete a cycle is wrong. Am I doing something wrong here? I will eventually have a time control to allow for full cycle times of 100 ms to 5 seconds. Any help would be greatly appreciated. Thanks!
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/atomic.h>
// Assign pins of ATTiny85, make sure it runs at 8 MHz internal oscillator
//DigitalPin Assignments
const unsigned int pwm2 = 4; //PWM out on OC1B/PCINT4/Pin3
const unsigned int pwm1 = 1; //PWM out on OC1A/PCINT1/Pin6
//Analog Pin Assignments
const unsigned int rate = A1; //This will be an analog read of speed pot 1 on ADC1/PCINT2/Pin7
unsigned long rateTime; // Current time value compared to the previous time to see if we need to move to the next table entry.
unsigned long lastTime; // Used for keeping track of whether we move to the next entry in our sineTable or not
unsigned long maxTime = 5e6; // Max time of 5s. This doesn't seem actually achievable, but whatever.
unsigned long minTime = 1e4; // Min time of 100 ms. This doesn't seem actually achievable, but whatever.
const uint8_t tableLength = 255; //Number of entries in our tables below
uint8_t inx = 0; //Index to read out of the table for PWM1, start at the beginning
int dutyCycle;
const uint8_t OCR1C_val = 127;
// Create a table for the PWM wave. Values are for 8 bit PWM (max value 255).
// Put it in flash memory so that it doesn't eat up our dynamic SRAM
//Sine
const uint8_t sineTable[] PROGMEM = {127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,179,181,184,187,190,193,195,198,200,203,205,208,210,213,215,217,219,221,223,225,227,229,231,233,235,236,238,239,
241,242,243,245,246,247,248,249,250,250,251,252,252,253,253,253,254,254,254,254,254,254,254,253,253,252,252,251,251,250,249,248,247,246,245,244,243,241,240,239,237,235,234,232,230,228,226,224,222,220,218,216,214,211,209,
207,204,202,199,196,194,191,188,186,183,180,177,174,171,168,166,163,159,156,153,150,147,144,141,138,135,132,129,125,122,119,116,113,110,107,104,101,98,95,91,88,86,83,80,77,74,71,68,66,63,60,58,55,52,50,47,45,43,40,38,36,
34,32,30,28,26,24,22,20,19,17,15,14,13,11,10,9,8,7,6,5,4,3,3,2,2,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,4,5,6,7,8,9,11,12,13,15,16,18,19,21,23,25,27,29,31,33,35,37,39,41,44,46,49,51,54,56,59,61,64,67,70,73,75,78,81,84,87,90,93,
96,99,102,105,108,111,115,118,121,124};
void setup() {
//Define pin modes
pinMode(pwm1, OUTPUT);
pinMode(pwm2, OUTPUT);
pinMode(rate, INPUT);
// Initialize pin states
digitalWrite(pwm1,LOW);
digitalWrite(pwm2, LOW);
lastTime = micros(); // Get an initial value
// Set up timer/PWM items
PLLCSR |= (1 << PLLE); //Enable PLL
//Wait for PLL to lock
while ((PLLCSR & (1<<PLOCK)) == 0x00)
{
// Do nothing until plock bit is set
}
// Enable clock source bit
PLLCSR |= (1 << PCKE);
// Set prescaler to PCK, turn on PWM1A, and set COM1A bits to match the COM1B bits due to attiny bug
TCCR1 = 0;
TCCR1 |= (1 << CS10) | (1<<PWM1A) | (1 << COM1A1);
// Enable OCRB output on PB4, configure compare mode and enable PWM B
DDRB |= (1 << PB4) | (1 << PB1);
GTCCR |= (1 << PWM1B) | (1 << COM1B1);
// Set OCR1A and OCR1B compare values and OCR1C TOP value
OCR1C = OCR1C_val;
OCR1A = 20; // Give an initial PWM duty cycle
OCR1B = 20; // Give an initial PWM duty cycle
}
void loop() {
updatePWM();
}
//Update PWM outputs based on above settings
void updatePWM() {
rateTime = 5e5; //Should be 0.5 seconds for a full cycle
//Convert microsecond period into amount of time between subsequent samples
unsigned long rateStep = round(rateTime/OCR1C_val);
//Get the current time
unsigned long currTime = micros();
//Compare current time to last time we updated for each PWM out
if ((currTime - lastTime) > rateStep) {
//We have met the time threshold for PWM, so go to the next value in the table
dutyCycle = pgm_read_byte(sineTable + inx);
// Set both PWM's
int mappedPWM = map(dutyCycle,0,255,0,OCR1C_val);
OCR1B = mappedPWM;
OCR1A = mappedPWM;
inx += 1; //Increment the read index for PWM
// Go back to the beginning of the table if we have gotten to the end
if (inx == tableLength) {
inx = 0;
}
lastTime = micros();
}//End of if ((currTime - lastTime) > rateStep)
}// end of updatePWM()