Need to make some corrections to my previous posts.
The DS3231 SQW output pin can be configured to produce a square wave output of 1Hz, 1.024kHz, 4.096kHz, or 8.192kHz, there is no option for 32kHz from this pin. The 32K output pin produces a square wave of 32.678kHz.
A bit more difficult to produce the 25fps count with 32.678kHz because it does not divide evenly. A single cycle at 32.678kHz is 30.518 microSeconds, a discrepancy of that amount between one frame and the next will hopefully be tolerable, as long as the long-term timing is correct.
This code seems to work correctly for maintaining correct timing while using FastLED:
#include <FastLED.h>
#include "RTClib.h" //RTClib library
RTC_DS3231 rtc;
#define NUM_LEDS 507
#define DATA_PIN 3
CRGB leds[NUM_LEDS];
CRGB testimage[NUM_LEDS]; //for testing purposes only
volatile uint32_t frameCounter = 0;
uint32_t frameCount;
uint32_t frameCountPrev;
void setup() {
//create some random LED data to ensure compiler does not remove the FastLED code
for (size_t i = 0; i < NUM_LEDS; i++) {
testimage[i] = CRGB(random(256), random(256), random(256));
}
Serial.begin(115200);
Serial.println("startup");
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
while (1);
}
if (rtc.lostPower()) {
Serial.println("RTC lost power, setting time");
// If the RTC have lost power it will sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
if (!rtc.isEnabled32K()) { //verify 32K output is enabled
rtc.enable32K();
}
TCCR5A = 0; //clear control register A
TCCR5B = 0; //clear control register B
TCNT5 = 0; //clear counter
OCR5A = 1309; //set value for output compare register A (32768Hz * 1/25 second) - 1 = 1309
TCCR5B |= (1 << WGM52); //Set CTC mode (WGM5 = 0100);
TCCR5B |= (1 << CS52) | (1 << CS51) | (1 << CS50) ; //External Clock mode using D47 as input
TIMSK5 |= (1 << OCIE5A); //Set the interrupt request
sei(); //Enable interrupt
FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS); // GRB ordering is assumed
}
void loop() {
//temporarily disable interrupts while making a copy of frameCounter
noInterrupts();
frameCount = frameCounter;
interrupts();
if (frameCount != frameCountPrev) { //only execute once per frame
if ((frameCount - frameCountPrev) != 1) {
Serial.println("missed frame");
while (1) {};
}
frameCountPrev = frameCount;
for (size_t i = 0; i < NUM_LEDS; i++) { //copy testimage to LED array
leds[i] = testimage[i];
}
FastLED.show();
Serial.print(frameCount);
//print millis every 25 frames to test timing
if ((frameCount % 25) == 0) {
Serial.print('\t');
Serial.print(millis());
}
Serial.println();
}
}
ISR(TIMER5_COMPA_vect) { //This is the interrupt request
static byte cycleCount = 24;
//adjustment to compensate for 32768 not being evenly divisible by 25
//counter will count ( (7 * 1310) + (18 * 1311) ) = 32768 pulses over 25 frames
if ((cycleCount & 0x03) == 0) {
OCR5A = 1309; //1310 clock pulses
} else {
OCR5A = 1310; //1311 clock pulses
}
if (cycleCount == 0) {
cycleCount = 25;
}
cycleCount--;
frameCounter++; //actual frame counter
}