#include <avr/pgmspace.h>
#define PWM_PIN 9 // On Mega, Timer1 controls Pin 9 & 10
#define PWM_FREQ 400 // 400 Hz PWM frequency
#define F_CPU 16000000UL // Arduino Mega runs at 16 MHz
#define PRESCALER 8
#define TOP ((F_CPU / (PRESCALER * PWM_FREQ)) - 1) // Compute TOP value
// Large duty cycle array stored in PROGMEM (values are ON-time in microseconds)
const PROGMEM uint16_t dutyCycleArray1[] = {900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900
, 900, 900, 900,
...
};
...
...
const PROGMEM uint16_t dutyCycleArray5[] = {900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 9
00, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900,
...
900,
};
// Array to store chunk sizes
const uint16_t chunkSizes[] = {
10000,
10000,
10000,
10000,
501,
};
volatile uint8_t currentChunk = 0; // Track current chunk
volatile uint16_t currentIndex = 0; // Track array index
const uint16_t arraySize = sizeof(dutyCycleArray1) / sizeof(dutyCycleArray1[0]); // Compute array size
volatile uint16_t onTimeMicroseconds; // Preloaded ON-time to avoid repeated variable creation
#define PWM_PIN 5 // Pin 5 is controlled by Timer3 on Mega
void setup() {
pinMode(PWM_PIN, OUTPUT);
// Configure Timer3 (instead of Timer1)
TCCR3A = (1 << WGM31) | (1 << COM3A1);
TCCR3B = (1 << WGM33) | (1 << WGM32) | (1 << CS31);
ICR3 = TOP; // Set PWM period (400 Hz)
OCR3A = (TOP * pgm_read_word(&dutyCycleArray1[0])) / (1000000 / PWM_FREQ);
TIMSK3 |= (1 << TOIE3); // Enable Timer3 Overflow Interrupt
}
ISR(TIMER3_OVF_vect) {
// Determine which chunk to read from
switch (currentChunk) {
case 0:
onTimeMicroseconds = pgm_read_word(&dutyCycleArray1[currentIndex]);
break;
case 1:
onTimeMicroseconds = pgm_read_word(&dutyCycleArray2[currentIndex]);
break;
case 2:
onTimeMicroseconds = pgm_read_word(&dutyCycleArray3[currentIndex]);
break;
case 3:
onTimeMicroseconds = pgm_read_word(&dutyCycleArray4[currentIndex]);
break;
case 4:
onTimeMicroseconds = pgm_read_word(&dutyCycleArray5[currentIndex]);
break;
}
// Update PWM duty cycle
OCR3A = (TOP * onTimeMicroseconds) / (1000000 / PWM_FREQ);
// Increment index within the chunk
currentIndex++;
// If we reach the end of the current chunk, switch to the next one
if (currentIndex >= chunkSizes[currentChunk]) {
currentIndex = 0;
currentChunk = (currentChunk + 1) % 5; // Cycle through 4 chunks
}
}
Maybe the intermediate integer math in this expression:
// Update PWM duty cycle
OCR3A = (TOP * onTimeMicroseconds) / (1000000 / PWM_FREQ);
might exceed a uint16_t?