thanks for the answers !
i solve part of the problem , the interrupts triggers be still behave wierdly (the signal was bad )
description of the setup :
ltc signal is outputed from a Decklink card on a XLR output.
arduino (both leonardo and R4 ) receive the LTC Signal on D3 : pinMode(3,INPUT_PULLUP);
"optionnal an op amp is used for ltc input, leonardo works fine without it"
(code at the end of the post)
the result :
- on the leonardo or uno r3 , things runs fine.
- on the R4 WIFI , it looks like interrupts are too slow and the lcd displays erratic values ).
video here : VID_20230807_114617.mp4 - Google Drive
i tried disabling and re-enabling the interrupts routine and it doesn t fix it.
the original creator of the code gave me a direction to look into :
on ESP32 , the interrupt should be declared like this
void IRAM_ATTR ISR() {
Statements;
}
but IRAM_ATTR is not recognized on compile :
C:\Users\julien\Documents\Arduino\just_tc\just_tc.ino:127:16: error: expected initializer before 'ISR'
void IRAM_ATTR ISR() {
but if i switch to a esp32 board, the IDE recognize it
any hints for me ?
Thanks in advance.
the code ::
volatile bool test = false;
#include <LiquidCrystal.h>
char lastframenum,lastdecnum;
byte maxframe=0;
int timer1_compare_match;
volatile int uMax0 = 625; // Any time greater than this is to big
volatile int uMax1 = 375 ;// Midpoint timing between a 1 and 0 bit length
volatile int uMin1 = 125; // Any time less than this is to short
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
unsigned long int testmillis =0;
bool TCVALID =false;
byte blinkx = 12;
int sequence[6] = {0,0,0,4,1,5};
volatile uint8_t tc[10] = {0}; // ISR Buffer to store incoming bits
volatile uint8_t xtc[8] = {0}; // Buffer to store valid TC data - sync bytes
volatile uint8_t tcFlags = 0; // Various flags used by ISR and main code
volatile uint32_t uSeconds;
volatile bool recording = false;
volatile bool ismenu = false;
int pressedbutton = 100;
const word sync = 0xBFFC; // Sync word to expect when running tape forward
enum flagBits {
tcValid, // TC copied to xtc is valid (Used by main loop to determing if a timecode has arrived)
tcFrameError, // ISR edge out of timing bounds (only gets reset after next valid TC read)
tcOverrun, // TC was not read from xtc by main loop before next value was ready (so main loop can tell if timecodes have been lost)
tcForceUpdate, // Valid TC will always be copied to buffer even if last value not read (if set by main code then TC will always be copied)
tcHalfOne // ISR is reading a 1 bit so ignore next edge (Internal to ISR)
};
class cHeartBeat
{
private:
unsigned long m_count;
int m_pinLED;
int m_pin_state, m_pin_state_old;
unsigned long m_mask_result, m_mask_result_old;
const unsigned long m_mask = B01111110;
public:
cHeartBeat(const int pinLED) // define heartbeat LED pin
{
pinMode(pinLED, OUTPUT);
digitalWrite(pinLED, LOW);
m_pinLED = pinLED;
m_count = 0;
m_pin_state = 1;
m_pin_state_old = !m_pin_state;
m_mask_result_old = 0;
}
void run()
{
// Serial.println(m_mask);
m_count++;
m_mask_result = m_count & (m_mask << 11);
m_pin_state = m_mask_result && 1;
if (m_pin_state != m_pin_state_old)
{
digitalWrite(m_pinLED, m_pin_state);
m_pin_state_old = m_pin_state;
}
}
};
struct FLAGS
{
uint8_t drop_frame, color_frame;
char drop[2], color[2];
};
// ISR store of last edge change time
char timeCode[13]; // For example code another buffer to write decoded timecode
char userBits[12]; // For example code another buffer to write decoded user bits
char tc_send[9]; // For 4 bit decimal communication (HHMMSSff + FINISH CODE)
bool DCBconversion[][4] = {{0,0,0,0}, // Number 0
{0,0,0,1},
{0,0,1,0},
{0,0,1,1},
{0,1,0,0},
{0,1,0,1},
{0,1,1,0},
{0,1,1,1},
{1,0,0,0},
{1,0,0,1}, // Number 9
{1,0,1,0}}; // Number 10 (Finish signal)
//led_fback debug_ledA(12); // LED for debugging
//led_fback debug_ledB(11);
cHeartBeat Heartbeat(13); // start heartbeat with LED pin number
FLAGS signal_flag;
void setup(){
lcd.begin(16,2);
Serial.begin(115200);
lcd.setCursor(0,0);
lcd.print("LOADING ");
lcd.setCursor(0,1);
lcd.print(" LOADING");
/////Pinhere
pinMode(3,INPUT_PULLUP); // Setup interrupt pin
pinMode(10,OUTPUT);
digitalWrite(10, HIGH); // LCD Backlight on
pinMode(A1, OUTPUT);
pinMode(A2, OUTPUT);
pinMode(A3, OUTPUT);
pinMode(A4, OUTPUT);
pinMode(A5, OUTPUT);
digitalWrite(A1, LOW);
digitalWrite(A2, LOW);
digitalWrite(A3, LOW);
digitalWrite(A4, LOW);
digitalWrite(A5, LOW);
Serial.println(F("Waiting For TC"));
lcd.setCursor(0,0);
lcd.print(" ");
lcd.setCursor(0,1);
lcd.print(" ");
Serial.flush();
signal_flag.drop[0] = ' ';
signal_flag.drop[1] = 'd';
signal_flag.color[0] = ' ';
signal_flag.color[1] = 'c';
attachInterrupt(digitalPinToInterrupt(3), int0ISR, CHANGE);
interrupts();
}
bool CheckTC(){
lcd.setCursor(11,0);
lcd.print(" ");
lcd.setCursor(14,0);
lcd.print(maxframe);
if (lastframenum == timeCode[10] && lastdecnum ==timeCode[7])
{
//TCVALID=false;
return false;
}
else
{
TCVALID=true;
//return true;
}
lastframenum = timeCode[10];
lastdecnum = timeCode[7];
return TCVALID;
}
void loop(){
CheckTC();
lcd.setCursor(3,1);
lcd.print(timeCode);
if (millis()>= testmillis+ 1000)
{
testmillis=millis();
lcd.setCursor (2,0);
lcd.print(millis()/1000);
}
/*
while(!bitRead(tcFlags, tcValid)){
Heartbeat.run();
}; // Wait for valid timecode
*/
timeCode[0] = (xtc[0] & 0x03) + '0'; // 10's of hours
timeCode[1] = (xtc[1] & 0x0F) + '0'; // hours
timeCode[2] = ':';
timeCode[3] = (xtc[2] & 0x07) + '0'; // 10's of minutes
timeCode[4] = (xtc[3] & 0x0F) + '0'; // minutes
timeCode[5] = ':';
timeCode[6] = (xtc[4] & 0x07) + '0'; // 10's of seconds
timeCode[7] = (xtc[5] & 0x0F) + '0'; // seconds
timeCode[8] = '.';
timeCode[9] = (xtc[6] & 0x03) + '0'; // 10's of frames
timeCode[10] = (xtc[7] & 0x0F) + '0'; // frames
//char fr[2]={timeCode[9],timeCode[10]};
bitClear(tcFlags, tcValid); // Finished with TC so signal to ISR it can overwrite it with next TC
}
void int0ISR(){
uint32_t edgeTimeDiff = micros() - uSeconds; // Get time difference between this and last edge
uSeconds = micros(); // Store time of this edge
if ((edgeTimeDiff < uMin1) or (edgeTimeDiff > uMax0)) { // Drop out now if edge time not withing bounds
bitSet(tcFlags, tcFrameError);
test=true;
return;
}
test=false;
if (edgeTimeDiff > uMax1) // A zero bit arrived
{
if (bitRead(tcFlags, tcHalfOne) == 1){ // But we are expecting a 1 edge
bitClear(tcFlags, tcHalfOne);
clearBuffer(tc, sizeof(tc));
interrupts();
return;
}
// 0 bit
shiftRight(tc, sizeof(tc)-1); // Rotate buffer right
// Shift replaces top bit with zero so nothing else to do
bitClear(tc[0], 7); // Reset the 1 bit in the buffer
}
else // Not zero so must be a 1 bit
{ // 1 bit
if (bitRead(tcFlags, tcHalfOne) == 0){ // First edge of a 1 bit
bitSet(tcFlags, tcHalfOne); // Flag we have the first half
interrupts();
return;
}
// Second edge of a 1 bit
bitClear(tcFlags, tcHalfOne); // Clear half 1 flag
shiftRight(tc, sizeof(tc)-1); // Rotate buffer right
bitSet(tc[0], 7); // Set the 1 bit in the buffer
}
// Congratulations, we have managed to read a valid 0 or 1 bit into buffer
if (word(tc[0], tc[1]) == sync){ // Last 2 bytes read = sync?
//debug_ledB.toggle(); // Feedback LED for every sync
bitClear(tcFlags, tcFrameError); // Clear framing error
bitClear(tcFlags, tcOverrun); // Clear overrun error
if (bitRead(tcFlags, tcForceUpdate) == 1){
bitClear(tcFlags, tcValid); // Signal last TC read
}
if (bitRead(tcFlags, tcValid) == 1){ // Last TC not read
bitSet(tcFlags, tcOverrun);
Serial.println("notc"); // Flag overrun error
interrupts();
return; // Do nothing else
}
for (uint8_t x = 0; x < sizeof(xtc); x++){ // Copy buffer without sync word
xtc[x] = tc[x + 2];
}
bitSet(tcFlags, tcValid);
// Signal valid TC
}
interrupts();
return;
}
void clearBuffer(volatile uint8_t theArray[], uint8_t theArraySize){
for (uint8_t x = 0; x < theArraySize - 1; x++){
theArray[x] = 0;
}
}
void shiftRight(volatile uint8_t theArray[], uint8_t theArraySize){
uint8_t x;
for (x = theArraySize; x > 0; x--){
uint8_t xBit = bitRead(theArray[x - 1], 0);
theArray[x] = theArray[x] >> 1;
theArray[x] = theArray[x] | (xBit << 7);
}
theArray[x] = theArray[x] >> 1;
}