Go Down

Topic: Realizing an SMPTE TimeCode reader/generator with arduino. (Read 12716 times) previous topic - next topic

Grag38

Oct 11, 2012, 12:27 pm Last Edit: Oct 11, 2012, 12:31 pm by Grag38 Reason: 1
I would like to use an arduino to do either an reader or an smpte time code genrator.

to explain what is an smpte linear timecode, it's very simple :

http://en.wikipedia.org/wiki/Linear_timecode

in fact this is just an 80 bits message that is sent (european broadcast) 25 time per seconds. It works on the biphase coded way, it's just an square signal with 2 frequencies.

here is an sample of one packet :



If we are considering an 48khz audio signal (broadcast frequency). it means  :

1 seconds is 25 SMPTE packet of 80bits each, that mean a total of 2000 bits for 48000 samples.

So from 1 bit needs 24 samples length.

In the smpte biphase coded way an '0' is an half of period and an '1' is one period as you can see in the following picture :



How would I be able to translate an 80bit packet to an audio signal with arduino ?

I suppose pwm can help me but I don't know how to gnenerate a mix of 1khz and 2khz signal ?

(1 khz = 80bits with '0' and 2khz = 80bits of '1', but the result is a mixing of '0' and '1').

In the second way, I would like to get an smpte audio signal into the arduino (I need only the positive of the signal) to count the pulses and their duration to decode it into an time code value as HH:MM:SS:FF (hours, minutes, seconds and frames).

If people are interesting by smpte linear timecode, they can read this site :  http://www.philrees.co.uk/articles/timecode.htm#smpte

thanks if you can give me some way of doing it. I know to program in C without trouble, and I know some bases of electronic.

Best regards.

Grag38

ok, seems not interesting few people...

I try to reduce some questions...

the one I would try get an answer is :

"How can I generate a square signal with only 2 different kind of frequences, one will be 1khz and the other 2khz ?"

to do it very simple, I think about :

Considering one string of char like '010001111101101110011100...."

each '0' will be generated by an half period of 1khz (|___| or |---|) and the '1' will be generated by a full period (|_|-| or |-|_|) ?

For reading time code, after looking for this forum, I know I just  have to use puleIn() fonction from arduino. So from I looking for at begining a very simple way of (for my basic tests) 'translating' audio signal from -2V +2V into 0-5V. After I will use OPAMP to do it.

If you just can help me of generating this square signal, it will gives me the bases of doing it.

Best regards.


Grag38

#3
Oct 13, 2012, 02:41 pm Last Edit: Oct 13, 2012, 02:42 pm by Grag38 Reason: 1

Maybe this posting about a SMPTE timecode decoder is helpful. Or this blogpost about generating it.


Thanks a lot ! I'll try it this week.

I'll try also the generator version !!!!

I'll be back on this post to give you some comments !

Great, this forum is marvellous !

edzy


Maybe this posting about a SMPTE timecode decoder is helpful. Or this blogpost about generating it.


note that there is an error in that old post's code, the bit for the drop-frame is the wrong one.
You can replace with:

drop_frame_flag = (tc[1]&0x04)!=0;

daviddd

How precise would such a smpte generator be?
1 frame/h, 1frame per 10hours?

thanks
klaus

FredericSegard

Hello,

I'm curious if there's been some development with this topic? I'd like to create a timecode reader and generator using the Arduino Uno. Alas, in my initial tests, timing was an big problem. Is it because of the overhead of the C compiler? I've tried compiling using Arduino and Codebreaker compilers (but not Atmel Studio yet). But when testing micros() in a very simple program to check for timer overflow, not only is there a 4us resolution issue, but sometimes, the results between loops vary constantly from 4, 8, 12, and even 16 us. This is a big problem if you want to generate (or read) a byphase signal by software only.

I wonder if there isn't a better way to do things? Perhaps using interrupts for reading... but what about generating? Faster processor to compensate for the micros() 4us resolution maybe? 40MHz+? Code in assembler instead? An external circuit perhaps?

Anybody out there ever successfuly do a project to read and generate timecode? If so, what are your recommendations? And where you able to auto detect (or manually select) frame rates? (24, 25, 30, 50 and 60)

Thanks,

Frederic

DMike92

Hi,
I have some experience in reading this code. Are you still interested ?
Le savoir ne vaut que lorsqu'il est partagé.
Knowledge only worth when shared.

DMike92

First :
The sync word may look at the end of the frame (in your picture) but in fact it is always at the begining of a frame (the next one if you are going forward)
Because time is binary-coded decimal, you cannont have more than 3 'ones' in a row (because max is 59).
Ok, maybe 4...
So the good start is to begin by searching the sync word.
Any time you get 5 or 6 ones (short) in a row you are listening to this word.
Then you wait for a zero (long) and, depending if the next is 0 or 1, you can even get the direction of flow (I would say 1 is forward and 0 backwards - to be confirmed).

How to proceed ?
In the arduino the best method is to use interrupt pin.

// Global variables (among other)
unsigned long lastTime=0;
unsigned int duration;
unsigned int average;

In the setup part :
   noInterrupts(); // do not allow interrupts now (I'm just starting...)
   attachInterrupt(0, handleInterrupt, CHANGE); // Receiver on interrupt 0 => that is pin #2
This means that every time a change is detected on pin #2, handleInterrupt() will be called.
(you can choose any other name instead of 'handleInterrupt')
   interrupts(); // Now I'm ready, LET'S GO


In the handleInterrupt() code :

handleInterrupt() {
  noInterrupts(); // stop being interrupted (got to hurry not to miss the next one)
  long time = micros(); // record curent time (in micro-seconds)
  duration = time - lastTime; // Get the duration from the last interrupt
  ...
  compare with average lenth of a one (have some margin at least of 1/4 of average - see further)
  (Calculate 1/4 by bit shifting to be quick).
  decide if it is a long (0) or a short (1)
  ...
  lastTime = time;
  if is was a one {
     long average = duration; // average time for a one (short)
  }
}


With this technique, you can even accelerate and still get sync'ed

In the loop, you will wait for a complete frame and print it or whatever you like.
You can set up a flag in the handleInterrupt routine that tells you a bit was get or wait for 4 bits and make a digit from them.

I would do 3 other routines :

LookForSync() {
   // Wait for more than 6 'ones' until frst 0 and a next bit (for direction but also end of sync)
   // Might call LookForCompleteTime() at the end
}

LookForDigit() {
   // Wait for 4 bits and return the number get
}

LookForCompleteTime() {
   // use LookForDigit()
}


With the handleInterrupt() method, I decoded a more complex code and, to be honest, all the decoding was done in the handleInterrupt() part (no need for a flag telling me if a bit has come). The loop only cared about writing on the console.

If you need help for more or for the electric part, let me know.

Forgive my bad english, I'm just French ;-)
Michel
Le savoir ne vaut que lorsqu'il est partagé.
Knowledge only worth when shared.

Go Up