Close
0%
0%

Arduino TIMECODE smpte LTC reader generator SHIELD

Using libltc to make a SMPTE Time Code Receiver/Generator for Arduino !

Similar projects worth following
acurate timecode shield reciever generator.
SMPTE LTC. acurate TCXO clock.

MESH Network of TIMECODE shileds cameras and other timecode hardware keep perfect time.

Welcome to Arduino TIMECODE SHIELD.

This shield will allow anyone to add SMPTE TIMECODE to there project.

The shield must be able to JAM SYNC from other TIMECODE shields / professional

cameras and other timecode devices that support LTC.

The shield will have:

TCXO clock RTC ( possible GPS for TCXO conditioning or UTC time , dependoing on added overall cost ! )

Audio codec to recieve timecode and broadcast timecode at 8bit 44.1khz audio via BNC connectors

a very small screen ( OLED 1" ) to display current local timecode. ( possible minimal buttons to program in/set timecode )

2.4ghz for JAMSYNC to other TIMECODE SHIELDS in some kind of simple mesh network.

  • 1 × libltc https://github.com/x42/libltc c library
  • 1 × AudioCodecMikroe506 https://github.com/soundspotter/ArduinoUNO_AudioCodecMikroe506

  • github code here

    ben biles01/27/2017 at 14:47 0 comments

    ok, implimented some ping pong buffers.

    I think the code is making some sense on the TX but the RX code still needs looking at.

    you can't use ping pong buffers if your changing data types using bitwise operators etc to go from 8 bit to 32bit since the 2 ping pong buffers need to be the same type to work !!

    I maybe should just have the ping pong buffers in between more processes.

    The ping pong buffers might help the RF reciever and ADPCM decoder but I think I need to add another 2 pingpong buffers between the I2S output intutupt and the ADPCM decoder also.

    going to dig out the arduinos this week and test / work on this code

    I would love it if anyone has time to take a look ! code link at bottom of this log

    I think I will have more success if I load a hole array of samples into libLTC. I've set both TX and RX device to decode LTC in the hope I might get one working !

    I am using LCD screens in the effort to debug. UART serial port is not fast enough.

    the project is starting to join the digital wireless mic project. So I suppose this is becoming a digital diversity ADPCM LTC capable wireless mic system if it ever works.

    The ADPCM would ultimately be replaced by a better encoder / decoder in DSP , but I thought ADPCM would be a starting point to knock down the data rate and learn the basics.

    RF24 tx module configured at 150kbps

    The 2 RX modules are set to test RSSI, module 1 wins if its => module2's RSSI level so module 1 is more likely to win. I'm sure there is a better way !

    packet size is 240bytes of ADPCM. If I remember correctly 1 ADPCM byte is made of 4 samples. I need to check that , it would cause timing issues if it does'nt decode the same in reverse !!

    In earlier tests I tried using circular buffers and packet numbering. circular buffers just filled up or emptied and did not stay in sync at all ..

    code here: https://github.com/benbiles/UHF-digital-wireless-microphone

  • Ping Pong Buffer

    ben biles09/26/2016 at 14:49 3 comments

    its looking like i need to try using a ping pong buffer in the code. This will allow me to read the samples continuously and dump blocks of samples into LibLTC as an array with the pointer.

    I thought the circular buffer was the answer but you cannot really use a pointer to point to large block of samples this way. its hard to achieve any kind of timing with the circular buffer. Or at least I am not sure how to make the timing work !!

    If I say load a ping pong buffer of say 1920 samples 1/25th of a second ( 1 video frame in time ) of audio at 48khz sample rate. then when its full send it to LibLTC for decoding. whilst its being copied next 1920 samples are coming into array B of the ping pong buffer..

    Thats the idea but I'm new to the Ping Pong Buffer concept !!! does anyone here have any pingpong buffer example code that they think that would work on on arduino DUE??

    Will post code if I get this working....

  • project might eventully merge with the wireless mic project

    ben biles07/30/2016 at 04:24 0 comments

    Since the timecode shield is really just audio IO with the LTClib i'm thinking it may as well merge with the wireless mic project. If I get this working then the timecode coudl be sent along with the packet data.

    I dont want to abandon the shield as I think a timecode shield would have all kinds of uses other than audio video work, also the wireless mic would unlikely include a GPS. ( power and cost )

    I now have I2S audio samples coming into an arduino DUE but still I can't get LIBltc to decode the audio samples into timcode ... It could be a timing problem with the I2S library ( basically there might not be enough cpu time left to bitshift the samples and prcess them in LIBltc.

    I have added a circular buffer to the code but it still does'nt output timecode.

    well i'll keep trying to figure it out and post here if it starts working.

  • audio IO working on DUE

    ben biles07/07/2016 at 12:04 0 comments

    OK, so I built an Arduino DUE audio IO shield so I can try LIBLTC with a little more horsepower!

    I took a differnt aproach this time and used I2S audio IO with the MIKROE-506 codec shield.

    I managed to get the Codec connected with this arduino Due I2S library

    https://github.com/delsauce/ArduinoDueHiFi

    At the moment the audio is commig in at 48khz 32bit and passthrough is working.

    I just found a void ltc_decoder_write_s16 wrapper that accepts 16bit samples, so I'll try that first and report back here with code and wiring diagram if I get this working. I think even Iif I get timcode decoding working it will take longer to make the generator work.

    Stay tuned :)

  • Timecode Shield gets RTC

    ben biles12/01/2015 at 23:34 0 comments

    The Timecode Shield prototype gets an RTC clock today using the DS3231.

    this chip has an Accuracy ±3.5ppm from -40°C to +85°C which is'nt too bad. ( its cheap ! )

    next will be 2.4ghz for syncing to other shields or an oled screen, not sure in which order.

    still battling with LIBLTC and the codec library. I think I will have to try and hack the codec lib to include the 8bit copy to LIBLTC since I have no idea how to add this in the Timer1 section of the code. I'm also thinking perhpas there just is'nt enough horse power on the arduino uno to process the 16bit audio from the codec into 8bit and get LibLTC decoding the LTC.

    I might try this shield on arduino Due. I would like to get this running on the UNO if possible though !!

    anyway , heres a pic of the rough prototype with the RTC chip / battery wired up and working.

  • stuck trying to point libltc to audio codec buffer !!

    ben biles11/18/2015 at 22:39 4 comments

    The two crucial lines are below. the first copys the samples from signed 16bit int to unsigned 8bit char for libltc.

    OK, seams like the the Arduino UNO cannot copy the data quick enough as it just hangs the MC.

    Maybe I need to hack AudioCodec.h to copy from 16bit int to unsigned 8 bit char for libltc.

    would much appreciate it if anyone has any ideas?

    ____

    unsigned char sample = ((right_in + 32768) >> 8) & 0xff; // signed 16bit to unsigned 8bit char
    ltc_decoder_write (decoder, &sample, 1, 0);

    ____

    heres the whole sketch.

    // LTC TIMECODE decode from audio input and print timecode to console

    // setup codec parameters
    // must be done before #includes
    // see readme file in libraries folder for explanations
    #define SAMPLE_RATE 8 // 8kHz (WM8731@12.288MHz, Arduino@16MHz) ) mkc 9/15/13
    #define ADCS 0 // use no ADCs (potentiometers)
    #define ADCHPD 1 // High pass filter on the codec on/off
    // WM8731 Microphone control
    #define MUTEMIC 0 // disable MUTEMIC
    #define INSEL 1 // enable MIC input
    #define MICBOOST 0 // enable MICBOOST
    #define BYPASS 0 // Bypass LINEIN
    #define DACSEL 1 // Select DAC for audio loopback
    #define SIDETONE 0 // Deselect SIDETONE
    #define SIDEATT 0

    // include necessary libraries
    #include <Wire.h>
    #include <SPI.h>
    #include <AudioCodec.h>

    // define & include stuff that libltc needs here
    #include "ltc.h"
    #include "encoder.h"
    #include "decoder.h"

    #define BUFFER_SIZE (1024)

    int samplesperframe = 320; // 8khz/ 25fps samples per frame
    LTCDecoder *decoder; //

    unsigned char samples = 00000000; // maybe faster to use temp variable ( when i try i get errors )

    /// end difine things for libltc

    // create data variables for audio transfer
    // even though there is no input needed, the codec requires stereo data
    int left_in = 0; // in from codec (LINE_IN)
    int right_in = 0;
    int left_out = 0; // out to codec (HP_OUT)
    int right_out = 0;



    void setup()
    {
    // call this last if you are setting up other things
    AudioCodec_init(); // setup codec and microcontroller registers
    Serial.begin(115200);


    decoder = ltc_decoder_create(samplesperframe,0); // create ltc decoder called decoder with n samples per frame
    }
    void loop()
    {

    unsigned char sample = ((right_in + 32768) >> 8) & 0xff; // copy signed 16bit to unsigned 8bit char

    ltc_decoder_write (decoder, &sample, 1, 0); // write sample to LIBLTC

    LTCFrameExt frame;

    while (ltc_decoder_read (decoder, &frame) > 0)
    {
    SMPTETimecode stime;
    ltc_frame_to_time(&stime, &frame.ltc, 1);
    Serial.print(stime.hours);
    Serial.print(stime.mins);
    Serial.print(stime.secs);
    Serial.print(stime.frame);

    }


    // timer1 interrupt routine - all data processed here
    ISR(TIMER1_COMPA_vect, ISR_NAKED){ // dont store any registers

    // &'s are necessary on data_in variables

    AudioCodec_data(&left_in, &right_in, left_out, right_out); //

    // our sinewave is now in temp2
    left_out = right_in; // put incoming audio on left channel
    right_out = right_in; // put sinusoid out on right channel


    reti(); // dont forget to return from the interrupt
    }

  • 8bit audio 44.1khz IO from arduino uno ready for timecode ltc

    ben biles10/31/2015 at 09:09 0 comments

    hacked up an audio codec board I had doing nothing for the audio IO for LTC reciever decoder encoder genterator :)

    I left plenty of space for the RTC GPS module etc

    Its rough but only a prototype, if it all works well I may print this as a shield.

    I made it as a shield mainly so I can just plug it into my other audio mixer project.

    anyway , heres a pic of it...

    I used this

    I used this hack https://github.com/soundspotter/ArduinoUNO_AudioCodecMikroe506

    it makes use of an AudioCodecMikroe506 board I bought ages ago. I remmeber really hating this board after I bought it since they had'nt bothered to solder one of the crucial pins from the Wolfson Codec that would have made the board stereo in setero out !!

    It anoyed me so much I throw it into the bottom of my junk box , haha but a few years later and I really need it !!!

    I cant be bothered to make a video of 8bit 44.1khz audio passing through this , i'm sure you know what that sounds like !!

    But its plenty high enough quality to recieve and put out LTC biphase encoded timecode :)

    I'm just trying to copy the unsigned interger samples to the LTC decoder code now but think ltclib requires the samples to be in unsigned char , so will make a video when I get the

    LTCtimecode decoding and output to serial console.

    I also recieved some TCXO oscilators , so if I get time I'll start building an RTC too so I can make a reliable LTC generator.

  • stripped down LTC reader code for arduino

    ben biles10/29/2015 at 02:56 0 comments

    turns out that Robin Gareus who wrote the libltc had already written an arduino LTC code reader that works from audio input ! code here

    http://gareus.org/gitweb/?p=arduino.git;a=tree;f=ltcsmpte

    I'm just finding out if he ever wrote a generator too !!

    The idea now would be to edit the code from using #include <FrequencyTimer2.h>

    and somehow make the arduino use a LTXCO as the timer. or have FrequencyTimer2.h be conditioned by the TXXO oscillator + GPS ( UTC time ) if neccessery.

    as I thought 8bits audio is good enough quality to read the 80bit LTC frames.

    Robin used 8bit 16khz sample rate to recieve the samples.

    If he never wrote an encoder then I'll have to write one from scratch I think using the decoder as a guide. Robin thinks the ltclib is too heavy to run on the arduino or at least it would'nt leave much room for anything else.


  • how to load audio stream data into LTCreader code

    ben biles10/28/2015 at 03:14 0 comments

    <EDIT>

    OK., go everytihng wrong in this log !!!

    I should have just

    #defined 'ltc.h'

    and called the various void commands ,..,,.

    </EDIT>

    I think all I need to do to read timecide from input is buffer incoming audio and end the frames to the LTC library. The example code below decodes timecode from an audio file with the manchester encoded timecode. The question is how do I load the data from incoming audio source. I think I can get away with 8bit 16khz or so audio input so maybe I can just do this through the arduino PWM pins !! anyway , heres the example code that loads from file.. any ideas would be great , i'm NOT great at C. I think the audio data from file gets loaded into library in this line.

    n = fread(sound, sizeof(ltcsnd_sample_t), BUFFER_SIZE, f);

    f being the file data? and somehow its broken into frames ?

    // anayway heres the example code..

    #include <stdio.h>

    #include <math.h>

    #include <ltc.h>

    #define BUFFER_SIZE (1024)

    int main(int argc, char **argv) {

    int apv = 1920;

    ltcsnd_sample_t sound[BUFFER_SIZE];

    size_t n;

    long int total;

    FILE* f;

    char* filename;

    LTCDecoder *decoder;

    LTCFrameExt frame;

    // fIXME

    if (argc > 1) {

    filename = argv[1];

    if (argc > 2) {

    sscanf(argv[2], "%i", &apv);

    }

    } else {

    printf("Usage: %s <filename> [audio-frames-per-video-frame]\n", argv[0]);

    return -1;

    }

    f = fopen(filename, "r");

    if (!f) {

    fprintf(stderr, "error opening '%s'\n", filename);

    return -1;

    }

    fprintf(stderr, "* reading from: %s\n", filename);

    total = 0;

    decoder = ltc_decoder_create(apv, 32);

    do {

    n = fread(sound, sizeof(ltcsnd_sample_t), BUFFER_SIZE, f);

    ltc_decoder_write(decoder, sound, n, total);

    while (ltc_decoder_read(decoder, &frame)) {

    SMPTETimecode stime;

    ltc_frame_to_time(&stime, &frame.ltc, 1);

    printf("%04d-%02d-%02d %s ",

    ((stime.years < 67) ? 2000+stime.years : 1900+stime.years),

    stime.months,

    stime.days,

    stime.timezone

    );

    printf("%02d:%02d:%02d%c%02d | %8lld %8lld%s\n",

    stime.hours,

    stime.mins,

    stime.secs,

    (frame.ltc.dfbit) ? '.' : ':',

    stime.frame,

    frame.off_start,

    frame.off_end,

    frame.reverse ? " R" : ""

    );

    }

    total += n;

    } while (n);

    fclose(f);

    ltc_decoder_free(decoder);

    return 0;

    }

  • not ordered chip yet !!!!

    ben biles10/01/2015 at 08:05 0 comments

    I'm going to be honest, I have'nt even had time to order the chip yet !

    I'm full speed ahead ahead on the mixer project. but this is on the list so I will order one soon , wire it up and scratch my head looking at the data sheet some more !

View all 10 project logs

Enjoy this project?

Share

Discussions

Dirk-WIllem van Gulik wrote 10/13/2018 at 18:52 point

I needed something fairly similar the other day; and created https://github.com/dirkx/SMPTE-EBU-TimecodeGenerator-ESP32.

Should not be hard to wire up to a TXO and a DS32231 (I take the clock from NTP, without a clock dicipline / without a phase-locked-loop).

  Are you sure? yes | no

tilllt wrote 04/05/2018 at 08:08 point

Heyho, i am interested in this project as i was considering building something similar myself. Is the project still active? I wonder if arduino (hardware) is really the best option for this... i just got an ESP32 (the sparkfun variant) coming my way, which is think would be the perfect platform for this. The ESP32 has A/D converters and BT / WiFi on board, so basically it seems as if only a TXCO is missing, i ordered a 3$ DS3231 i2c breakout board from china for that purpose. 

i have a question regarding SMPTE 12M levels, apparently those are supposed to be within audio line level range, so below 2v. I read that some of the "professional" TC sync devices support 10V input levels, so i guess an overvoltage protection would be clever. Did anyone ever find info on the the TC signal levels "in the wild"? 


 Anyway, would love to hear some updates on the progress.

  Are you sure? yes | no

Josh wrote 01/19/2017 at 17:16 point

I'm very interested in this project too. I'm wondering if it might make things easier to move to a heftier processor like the Teensy 3.2. It's running an ARM Cortex chip and runs a bit faster than the Due. They've even just released two new versions (3.5 and 3.6) that are faster still. In addition there is a fantastic audio library that might be of some help, though I imagine integrating it with libltc might be tricky. 

I'm curious how hard it was to port libltc to the Arduino environment. 

@Silver Kits I'd be interested to see your generator code once you're willing to share.

  Are you sure? yes | no

ben biles wrote 01/19/2017 at 18:00 point

Hi Josh, I think your right , it would be easier to run the code on a teensy or more powerful processer, better librarys etc. If I used a rasbery pie or edison or something LTC would probebly work right away. I will try the ping pong buffer soon and hopfully get better results. My circular buffer idea was a disaster, it just fills up or runs out of samples and stops :) The only reason I was using the DUE is that there is an I2S audio library but I have since found out the interrupt routine leaves little time time do much else appart from copy samples to a from the M3 ! still I think the ping pong buffer may well work. I'll report back here if I get time to try it next weel. bust making porting code from my arduino project to Eclipse edison one for recording audio in my other project.

  Are you sure? yes | no

ben biles wrote 01/27/2017 at 14:54 point

Hi Josh , started to do some work on this again, just added some ping pong buffers to the code and will try working on this over the next few days. hopfuly I will be able to fix the anoying LCD screen problem I'm having with the DUO's, it would really help to debug things, UART serial to slow to use with this type of code.. 

code here:   https://github.com/benbiles/UHF-digital-wireless-microphone

  Are you sure? yes | no

Josh wrote 01/28/2017 at 22:30 point

Hey Ben,

I don't have time to dig deeply into the code right now, but I am curious, are you trying to transmit the LTC over the wireless link, or are you decoding it at the transmitter and just sending the digital data?

Keep up the good work!

  Are you sure? yes | no

ben biles wrote 01/29/2017 at 01:51 point

hi josh, I'm trying to decode ltc at transmitter and generate at reciever. I'd send a time stamp to sync generator at reciever over RF. Generator wise I suppose I'm going to need to add an rtc clock. Have'nt started that yet, Code is mixed up with the digital audio transmitter stuff now so not very tidy. I'll post here if I get it half working.. 

  Are you sure? yes | no

Silver Kits wrote 01/19/2017 at 08:45 point

Hi there

are you still working on this project?

I have developed LTC generator "test/trials device" based on Arduino Mega. I have not used DAC. I'm just generating SMPTE with general purpose output. As ardu xtal is drifting a lot I'm also using DS3234 RTC to get more stable time reference.

Source code is not public jet (i need to tidy it up first). Let me know if we can share experience and co-operate somehow.

  Are you sure? yes | no

ben biles wrote 01/19/2017 at 17:49 point

Hi , thanks for the interest in the project ! it sounds like your ahead of me if your already using a DS3234 as a conditioning clock for the LTC output? how are you outputing LTC on GPO ? are you making noises with PWM and a timer or something? I am busy on the other project porting code from arduino IDE to intel edison eclipse IDE for audio recording from my ADC-DSP-DAC board at the moment. I have the bluetooth app up and runnning controlling things. I'm still very interested in getting the LTC reciever/gen running on as small / low power device as possible ! and if its possible without an ADC / DAC even better ! I think I am very close to getting things working , I just have'nt had time to make a ping pong buffer and replace the circular buffer I'm using now. I need to load an array of samples and point at that with LTC while I copy to another array from sound card. its possible I need to use DMA for that but not sure.

  Are you sure? yes | no

ben biles wrote 01/27/2017 at 14:49 point

Hi Silver kits, heres a link to my code , its a bit of a mess , but it will hopfuly get better this week.. code here:   https://github.com/benbiles/UHF-digital-wireless-microphone

  Are you sure? yes | no

Silver Kits wrote 02/09/2017 at 14:19 point

Sorry for communications break. I have ported code to be usable both in Ardu Mega and Uno. From MCU performance side there is no need for MCU change. But I myself will change probably to ARM cortex M0 or M3 as soon as I have selected suitable MCU. It is because AVR is 8-bit, 5 V, legacy and quite expensive.


For example, current instructions and data memory static footprint for Uno is:
AVR Memory Usage
----------------
Device: atmega328p
Program:    4212 bytes (12.9% Full)
(.text + .data + .bootloader)

Data:        293 bytes (14.3% Full)
(.data + .bss + .noinit)


Data usage is so big because I have 2 128 byte buffers for configuration interface via UART in USB.


Biggest issue what i currently have is "clock" drift and even jitter in Uno. DS3234 RTC can output 1 Hz, 1024 Hz and so on square wave. I use 1Hz to correct Ardu system timer after every second. I know, it is not good solution, but I have not figured out any better solution.


Currently I have implemented only 25 FPS. Seems that LTC encoder is working. I have tested it with various LTC reader apps for smartphones and for PC. In addition with one Panasonic professional camera and even for old Betamax recorder. NB! Be aware that Ardu output level is almost 5V and you need to make signal level suitable for your LTC device input (or line/mic in for PC). I have not used LTC library but I have implemented my own BMC encoder working via interrupt service routine. LTC message is kept in 10 byte char array. Frame no. and time changed from main program.


I'm waiting to get U Blox Neo-M8T timing GPS module for testing. If it is suitable I will swap RTC module so that I can get accurate clock for LTC encoder and UTC time.


As current solution is practically not usable I will make it public later on if it can be used in reality. If you want to have access to current source, please have GitLab account and press request button https://gitlab.com/time-code-pen

  Are you sure? yes | no

Richard Crowley wrote 10/25/2015 at 00:44 point

I would like to take a GPS-disciplined clock, and the extracted V-sync from a composite video signal (MUCH easier than decoding HDMI or SDI digital video!) and generate wall-clock LTC. These are all rather simple things. I am assembling a clock kit right now which includes a GPS receiver. I would like to take the GPS time and feed it into an Arduino or something to create SMPTE LTC timecode

  Are you sure? yes | no

ben biles wrote 03/25/2016 at 00:51 point

Hi Richard, sorry I did'nt read your comment correctly months ago !

did you ever manage to encode your GPS clock source into LTC timcode ?

I would be interested in this also especially if the clock was shared over a wifi network to multiple devices that can output ltc.

I think your best bet would be use an arduino or something similar that includes a DAC / soundcard so you can use libltc to generate LTC and output it to our DAC / soundcard.

My issue is that the arduino UNO does'nt seam to have enough memory for libltc and the audio library to run. I don't think if the Mikroe hacked audio board does'nt work then any other boards are capable with the UNO. perhaps a more powerful arduino? the zero? I don't have one yet and have'nt had time to try.

I think extracting hdmi / sdi timecode would be very interesting to learn. would you start with an hdmi / sdi IO ic ? not sure my scope is fast enough to decode anything that fast. maybe timcode is documented in the hdmi / sdi IO ic datasheets?

  Are you sure? yes | no

ben biles wrote 07/07/2016 at 17:58 point

I should also mention, I think my problem on the Uno could also to do with  inturupts. I think on arduino R3 there are 2 main ISR inturupts and one is used here , ISR(TIMER1_COMPA_vect, ISR_NAKED){ // dont store any registers

I don't fully understand ISR inturipts and barely understnad normal pin driven inturupts ! my idea is that maybe I can use the second inturrupt for LibLTC but thats pushing the boundrys of my knolledge !!! I also found out arduino DUE inturrupt service routeens ISR's are completely differnt to AVR. So if I find a solution on the DUE its unlikely to work on the UNO,..

  Are you sure? yes | no

JDias wrote 10/15/2015 at 16:26 point

This chip is out of production and is now very very rare...

  Are you sure? yes | no

ben biles wrote 10/15/2015 at 18:09 point

mmm, ok maybe I should be doing this in MC in code.. whats the modern way to read write LTC smpte ? any ideas?

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates