3.6
As you probably already noticed, I'm not a high level programmer. Still have to learn a lot.
What is the purpose of pin 0 in your example. ( syncpin) i left it unconnected.
3.6
As you probably already noticed, I'm not a high level programmer. Still have to learn a lot.
What is the purpose of pin 0 in your example. ( syncpin) i left it unconnected.
I have a working code for syncing the input to the output. (like a tentikal) Pulling pin 2 down to ground will set the sync.
Here is my code. (could be written better I think)
/*
Linear Timecode generation and decoding combined
Please modify as needed
(c) Frank B, 2020
(pls keep copyright-info)
To enable decoding:
#define USE_LTC_INPUT
and connect pin1 to pinA2 (=pin 16) !!!! I see no use to do this ????
PIN 2 : if set low it will sync incoming TC to the output TC . Then you can disconnect input TC and output will continue
Licence: MIT
*/
bool insync=0;
int incominghours=0;
int incomingminutes=0;
int incomingseconds=0;
int incomingframes=0;
#define USE_LTC_INPUT //comment-out for generation only
float fps = 25;
const int ltcPin = 1;
const int syncPin = 0;
#include "TimeLib.h"
#ifdef USE_LTC_INPUT
/*
Connect ltc
*/
#include <Audio.h>
#include <analyze_ltc.h>
AudioInputAnalog adc1;
AudioAnalyzeLTC ltc1;
AudioConnection patchCord2(adc1, 0, ltc1, 0);
#else
struct ltcframe_t {
uint64_t data;
uint16_t sync;
};
#endif
IntervalTimer ltcTimer;
IntervalTimer fpsTimer;
volatile int clkCnt = 0;
ltcframe_t ltc;
float ltcTimer_freq;
time_t getTeensy3Time()
{
return Teensy3Clock.get();
}
void genLtc() {
static int state = 0;
if (clkCnt++ >= 2 * 80) {
//ltcTimer.end();
clkCnt = 0;
return;
}
int bitval;
int bitcount = clkCnt / 2;
ltcframe_t ltct;
ltct = ltc;
if (bitcount < 64) {
bitval = (int) (ltct.data >> bitcount) & 0x01;
} else {
bitval = (int) (ltct.sync >> (bitcount - 64)) & 0x01; //backward
}
if ( (bitval == 1) || ( (bitval == 0) && (clkCnt & 0x01) ) == 0) {
state = !state; // toggle state
digitalWriteFast(ltcPin, state);
}
}
//https://www.geeksforgeeks.org/program-to-find-parity/
inline
int getParity(uint64_t n)
{
int parity = 0;
while (n)
{
parity = !parity;
n = n & (n - 1);
}
return parity & 0x01;
}
/*
Gets called by rising edge of syncPin
*/
void startLtc() {
ltcTimer.begin(genLtc, ltcTimer_freq);
ltcTimer.priority(0);
int t, t10;
uint64_t data = ltc.data;
clkCnt = 0;
//get frame number:
t = ((data >> 8) & 0x03) * 10 + (data & 0x0f);
//zero out ltc data, leave d+c flags and user-bits untouched:
data &= 0xf0f0f0f0f0f0fcf0ULL;
//data = 0;
//inc frame-number:
//TODO: realize "drop frame numbering" (when D-Flag is set)
t++;
if (t >= (int) fps) t = 0;
//set frame number:
t10 = t / 10;
data |= (t10 & 0x03) << 8;
data |= ((t - t10 * 10)) << 0;
printTCout();
Serial.printf("%02d\n", t);
//set time:
t = second();
t10 = t / 10;
data |= (t10 & 0x07) << 24; //Seconds tens
data |= ((t - t10 * 10) & 0x0f) << 16;
t = minute();
t10 = t / 10;
data |= (uint64_t)(t10 & 0x07) << 40; //minute tens
data |= (uint64_t)((t - t10 * 10) & 0x0f) << 32;
t = hour();
t10 = t / 10;
data |= (uint64_t)(t10 & 0x03) << 56; //hour tens
data |= (uint64_t)((t - t10 * 10) & 0x0f) << 48;
//set parity:
int parity = (!getParity(data)) & 0x01;
if ((int) fps == 25) {
data |= (uint64_t) parity << 59;
} else {
data |= (uint64_t) parity << 27;
}
ltc.data = data;
}
void initLtcData()
{
ltc.sync = 0xBFFC;
ltc.data = (uint64_t) 0; //<- place your initial data here
}
void genFpsSync() {
static int state = 0;
state = !state; // toggle state
digitalWriteFast(syncPin, state);
}
void setup() {
Serial.begin(115200);
delay(200);
#ifdef USE_LTC_INPUT
AudioMemory(4);
#endif
setSyncProvider(getTeensy3Time);
pinMode(syncPin, OUTPUT);
pinMode(ltcPin, OUTPUT);
pinMode(2, INPUT_PULLUP);
ltcTimer_freq = (1.0f / (2 * 80 * (fps ))) * 1000000.0f - 0.125f;// -0.125: make it a tiny bit faster than needed to allow syncing
initLtcData();
//set frame number to last frame to force roll-over with new second()
ltc.data &= 0xf0f0f0f0f0f0fcf0ULL; //delete all dynamic data in frame
int t, t10;
t = fps;
t10 = t / 10;
ltc.data |= (t10 & 0x03) << 8;
ltc.data |= ((t - t10 * 10));
//now wait for seconds-change
int secs = second();
while (secs == second()) {;}
//start timer and pin-interrupt:
fpsTimer.begin(&genFpsSync, (1.0f / (2 * fps)) * 1000000.0f);
fpsTimer.priority(0);
attachInterrupt(digitalPinToInterrupt(syncPin), &startLtc, RISING);
NVIC_SET_PRIORITY(88, 0); //set GPIO-INT-Priority for Pin 1
}
void loop() {
if (ltc1.available()) {
ltcframe_t ltcframe = ltc1.read();
incominghours=ltc1.hour(<cframe);
incomingminutes=ltc1.minute(<cframe);
incomingseconds=ltc1.second(<cframe);
incomingframes=ltc1.frame(<cframe);
Serial.printf("TC in : %02d:%02d:%02d.%02d\n\n", ltc1.hour(<cframe), ltc1.minute(<cframe), ltc1.second(<cframe), ltc1.frame(<cframe));
}
bool inpin = digitalRead(2);
if (inpin==0 && insync==0){
if (incomingframes==0){
detachInterrupt(digitalPinToInterrupt(syncPin));
fpsTimer.end();
setTime(incominghours,incomingminutes,incomingseco nds, 01, 01, 2022);
Teensy3Clock.set(now());
ltcTimer_freq = (1.0f / (2 * 80 * (fps ))) * 1000000.0f - 0.125f;// -0.125: make it a tiny bit faster than needed to allow syncing
initLtcData();
//set frame number to last frame to force roll-over with new second()
ltc.data &= 0xf0f0f0f0f0f0fcf0ULL; //delete all dynamic data in frame
int t, t10;
t = fps;
t10 = t / 10;
ltc.data |= (t10 & 0x03) << 8;
ltc.data |= ((t - t10 * 10));
//now wait for seconds-change
int secs = second();
while (secs == second()) {;}
//start timer and pin-interrupt:
fpsTimer.begin(&genFpsSync, (1.0f / (2 * fps)) * 1000000.0f);
fpsTimer.priority(0);
attachInterrupt(digitalPinToInterrupt(syncPin), &startLtc, RISING);
NVIC_SET_PRIORITY(88, 0); //set GPIO-INT-Priority for Pin 1
insync=1;
}
}
}
void printTCout(){
Serial.printf("TCout : %02d:%02d:%02d:", hour(), minute(), second());
}
Could you place your code between code tags using the # button.Code:/* Linear Timecode generation and decoding combined Please modify as needed (c) Frank B, 2020 (pls keep copyright-info) To enable decoding: #define USE_LTC_INPUT and connect pin1 to pinA2 (=pin 16) !!!! I see no use to do this ???? PIN 2 : if set low it will sync incoming TC to the output TC . Then you can disconnect input TC and output will continue Licence: MIT */ bool insync = 0; int incominghours = 0; int incomingminutes = 0; int incomingseconds = 0; int incomingframes = 0; #define USE_LTC_INPUT //comment-out for generation only float fps = 25; const int ltcPin = 1; const int syncPin = 0; #include "TimeLib.h" #ifdef USE_LTC_INPUT /* Connect ltc */ #include <Audio.h> #include <analyze_ltc.h> AudioInputAnalog adc1; AudioAnalyzeLTC ltc1; AudioConnection patchCord2(adc1, 0, ltc1, 0); #else struct ltcframe_t { uint64_t data; uint16_t sync; }; #endif IntervalTimer ltcTimer; IntervalTimer fpsTimer; volatile int clkCnt = 0; ltcframe_t ltc; float ltcTimer_freq; time_t getTeensy3Time() { return Teensy3Clock.get(); } void genLtc() { static int state = 0; if (clkCnt++ >= 2 * 80) { //ltcTimer.end(); clkCnt = 0; return; } int bitval; int bitcount = clkCnt / 2; ltcframe_t ltct; ltct = ltc; if (bitcount < 64) { bitval = (int)(ltct.data >> bitcount) & 0x01; } else { bitval = (int)(ltct.sync >> (bitcount - 64)) & 0x01; //backward } if ((bitval == 1) || ((bitval == 0) && (clkCnt & 0x01)) == 0) { state = !state; // toggle state digitalWriteFast(ltcPin, state); } } //https://www.geeksforgeeks.org/program-to-find-parity/ inline int getParity(uint64_t n) { int parity = 0; while (n) { parity = !parity; n = n & (n - 1); } return parity & 0x01; } /* Gets called by rising edge of syncPin */ void startLtc() { ltcTimer.begin(genLtc, ltcTimer_freq); ltcTimer.priority(0); int t, t10; uint64_t data = ltc.data; clkCnt = 0; //get frame number: t = ((data >> 8) & 0x03) * 10 + (data & 0x0f); //zero out ltc data, leave d+c flags and user-bits untouched: data &= 0xf0f0f0f0f0f0fcf0ULL; //data = 0; //inc frame-number: //TODO: realize "drop frame numbering" (when D-Flag is set) t++; if (t >= (int)fps) t = 0; //set frame number: t10 = t / 10; data |= (t10 & 0x03) << 8; data |= ((t - t10 * 10)) << 0; printTCout(); Serial.printf("%02d\n", t); //set time: t = second(); t10 = t / 10; data |= (t10 & 0x07) << 24; //Seconds tens data |= ((t - t10 * 10) & 0x0f) << 16; t = minute(); t10 = t / 10; data |= (uint64_t)(t10 & 0x07) << 40; //minute tens data |= (uint64_t)((t - t10 * 10) & 0x0f) << 32; t = hour(); t10 = t / 10; data |= (uint64_t)(t10 & 0x03) << 56; //hour tens data |= (uint64_t)((t - t10 * 10) & 0x0f) << 48; //set parity: int parity = (!getParity(data)) & 0x01; if ((int)fps == 25) { data |= (uint64_t)parity << 59; } else { data |= (uint64_t)parity << 27; } ltc.data = data; } void initLtcData() { ltc.sync = 0xBFFC; ltc.data = (uint64_t)0; //<- place your initial data here } void genFpsSync() { static int state = 0; state = !state; // toggle state digitalWriteFast(syncPin, state); } void setup() { Serial.begin(115200); delay(200); #ifdef USE_LTC_INPUT AudioMemory(4); #endif setSyncProvider(getTeensy3Time); pinMode(syncPin, OUTPUT); pinMode(ltcPin, OUTPUT); pinMode(2, INPUT_PULLUP); ltcTimer_freq = (1.0f / (2 * 80 * (fps))) * 1000000.0f - 0.125f;// -0.125: make it a tiny bit faster than needed to allow syncing initLtcData(); //set frame number to last frame to force roll-over with new second() ltc.data &= 0xf0f0f0f0f0f0fcf0ULL; //delete all dynamic data in frame int t, t10; t = fps; t10 = t / 10; ltc.data |= (t10 & 0x03) << 8; ltc.data |= ((t - t10 * 10)); //now wait for seconds-change int secs = second(); while (secs == second()) { ; } //start timer and pin-interrupt: fpsTimer.begin(&genFpsSync, (1.0f / (2 * fps)) * 1000000.0f); fpsTimer.priority(0); attachInterrupt(digitalPinToInterrupt(syncPin), &startLtc, RISING); NVIC_SET_PRIORITY(88, 0); //set GPIO-INT-Priority for Pin 1 } void loop() { if (ltc1.available()) { ltcframe_t ltcframe = ltc1.read(); incominghours = ltc1.hour(<cframe); incomingminutes = ltc1.minute(<cframe); incomingseconds = ltc1.second(<cframe); incomingframes = ltc1.frame(<cframe); Serial.printf("TC in : %02d:%02d:%02d.%02d\n\n", ltc1.hour(<cframe), ltc1.minute(<cframe), ltc1.second(<cframe), ltc1.frame(<cframe)); } bool inpin = digitalRead(2); if (inpin == 0 && insync == 0) { if (incomingframes == 0) { detachInterrupt(digitalPinToInterrupt(syncPin)); fpsTimer.end(); setTime(incominghours, incomingminutes, incomingseco nds, 01, 01, 2022); Teensy3Clock.set(now()); ltcTimer_freq = (1.0f / (2 * 80 * (fps))) * 1000000.0f - 0.125f;// -0.125: make it a tiny bit faster than needed to allow syncing initLtcData(); //set frame number to last frame to force roll-over with new second() ltc.data &= 0xf0f0f0f0f0f0fcf0ULL; //delete all dynamic data in frame int t, t10; t = fps; t10 = t / 10; ltc.data |= (t10 & 0x03) << 8; ltc.data |= ((t - t10 * 10)); //now wait for seconds-change int secs = second(); while (secs == second()) { ; } //start timer and pin-interrupt: fpsTimer.begin(&genFpsSync, (1.0f / (2 * fps)) * 1000000.0f); fpsTimer.priority(0); attachInterrupt(digitalPinToInterrupt(syncPin), &startLtc, RISING); NVIC_SET_PRIORITY(88, 0); //set GPIO-INT-Priority for Pin 1 insync = 1; } } } void printTCout() { Serial.printf("TCout : %02d:%02d:%02d:", hour(), minute(), second()); }
It makes the code much more readable and therefore more liable to get some help.
I'm really new to forums. Could you explain a bit more how to do this? Is it a button somewhere on the forum, or do I add # before I paste the code?
New to this? You've been a member since Nov 2018.
When making a post, when you want to add some code, press the # button above.
Type or paste your code between the [ CODE][/CODE ] tags generated.
Alternatively type or paste your code, highlight it and then press the # button and your code will have the tags placed before and after your code.
Has anyone tested this on Teensy 4.0? LTC input is not working for me?
No, but there is nothing what is model-depended.
Last edited by Frank B; 01-27-2022 at 05:38 PM.
It really does not work. Maybe Timelib that works different in T4?
Don't know. Have you tried USB input?
Found the solution for T4.0
You need to have the next line in your code.
AudioOutputI2S i2s1;
For T3.6 it is not necessary
Still trying to figure out on how to get this to work on a Teensy4.0, because I need (S)RTC.
So far I found out that it has something to do with the attachInterrupt on the sync pin. That part won't start until I connect a lose wire to the sync-pin. Strange to start with, A pull up resistor will stop the interrupt. But with the loose wire the TC-FRAME rate is going nuts... It will do more then 20 times 25 frames loops per second.....