dirkx/SMPTE-EBU-TimecodeGenerator-ESP32

'RMT' was not declared in this scope

Opened this issue · 6 comments

I can't compile this for the ESP32-S3, por likely due to changes in interrupts. Unfortunately, I am not proficient in handling this on ESP32.

C:\Users\seeb7\Documents\Arduino\SMPTE-EBU-TimecodeGenerator-ESP32-master\SMPTEGenerator\RMT.ino: In function 'void rmt_isr_handler(void*)':

RMT:104:3: error: 'RMT' was not declared in this scope

104 | RMT.int_clr.ch0_tx_thr_event = 1;

  |   ^~~

C:\Users\seeb7\Documents\Arduino\SMPTE-EBU-TimecodeGenerator-ESP32-master\SMPTEGenerator\RMT.ino: In function 'void fill()':

RMT:196:5: error: 'RMTMEM' was not declared in this scope

196 | RMTMEM.chan[RMT_TX_CHANNEL].data32[at].val = w.val;
| ^~~~~~

exit status 1

'RMT' was not declared in this scope

Hi,
First, thanks a lot for this project. I own a Leitch 5212 and it's now NTP sync'd thanks to your project.
I had to revert to SDK 2.x to run and took a look at migrating to 3.x, but in my view RMT is rather immature (the doc itself says it's a work in progress) so I retrieved an old Timecode generator code I had for Arduino using only a timer interrupt and adapted it, and I think it's much simpler and futureproof.
Basically a timer ticks twice per bit, iterates on the bits in the block[] array and toggles the output at the start of each bit, and at the middle of the bit if it is a 1.
Not counting the comments, the full class is less than 50 lines long:

hw_timer_t *timer = NULL;

volatile bool isNextMessageRequired = false;
volatile int outputValue = 0;
volatile unsigned char bitIndex = 0;
volatile boolean isStartOfBit = true;

void ARDUINO_ISR_ATTR timerInterrupt() {
  if (isStartOfBit) {
    outputValue = !outputValue;
    digitalWrite(RED_PIN, outputValue);
    isStartOfBit = false;    
  }
  else {
    if (1 & ((block[bitIndex >> 3] >> (bitIndex & 0b111)))) {
      outputValue = !outputValue;
      digitalWrite(RED_PIN, outputValue);
    }
    bitIndex++;
    if (bitIndex == 80) {
      isNextMessageRequired = true;
      bitIndex = 0;
    }
    isStartOfBit = true;
  }
}

void timer_setup(int fps) {
  timer = timerBegin(80 * 2 * fps); // trigger timer twice per bit
  timerAttachInterrupt(timer, &timerInterrupt);
  timerAlarm(timer, 1, true, 0);
  Serial.println("Starting to emit SMPTE stream");
}

void timer_loop() {
  if (isNextMessageRequired) {
    if (ntpValueChanged) {
      fillNextBlock();
      ntpValueChanged = false;
    }
    else {
      incsmpte();
      fillNextBlock();
    }  
    isNextMessageRequired = false;
  }
}

If you are interested, I can prepare a PR to replace the RMT logic with that Timer.
Among the changes, I also removed the FIDDLE_BUFFER_DELAY because AFAICT it was only needed for RMT (or I didn't understand its goal :-)) and had to do some refactoring such as fillNextBlock() that now only does the conversion (HMSF to block[]) but keeping the increment logic independant.
I tested it for a few hours and it seems OK.
But if you'd rather stick to the RMT version, no problem. As you like, just tell me :-)

My original looked virtually identical to yours -- that technically worked. But tiny timing differences every 10-30 seconds would throuw the master-sync off enough to cause the red LED on the clock to go flashing

Hi,
Don't know if you received my sample code but... don't bother testing it if you didn't already.
When I freshly flashed it last month, I stared at it for minutes and could not catch a single "desync flash". But just yesterday, I stumbled upon a flashing led. I waited and sure enough, one minute later, I got it again. I guess network activity is higher now or the chip somehow has other things to do...

So clearly, you're right, that timer solution is not 100% reliable, It's a pity it worked flawlessly on an Arduino Nano, but admittedly the Nano didn't manage tons of tasks in parallel :-)...

I am surprised that the Leitch clock does not have a better PLL to "stick" to the incoming signal, even if 1 or 2% off. Manchester encoding is designed for that and they don't seem to leverage it... Anyway.

If I have time, I'll try to see if the new RMT interface is an option, but knowing they call it "work in progress", and the use of RMT in this context is already a bit of a hack, I'm not sure it's worth it...

KR,

Vincent