SMPTE timedode (LTC) decode library for mbed

Dependents:   LTC_SMPTE_sample

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers LTC_SMPTE.cpp Source File

LTC_SMPTE.cpp

Go to the documentation of this file.
00001 /**
00002  * SMPTE timedode (LTC) decode library for mbed
00003  * Copyright (c) 2015 Suga
00004  * Released under the MIT License: http://mbed.org/license/mit
00005  */
00006 /** @file
00007  * @brief SMPTE timedode (LTC) decode library for mbed
00008  */
00009 
00010 #include "LTC_SMPTE.h"
00011 
00012 #if ! defined(TARGET_LPC176X)
00013 #error "this CPU is not supported. use LPC1768"
00014 #endif
00015 
00016 // pulse width: 416.7us(30fps)
00017 // 80bit x 30frame/s --> 416.7us/bit
00018 #define ONE_TIME_MIN  180
00019 #define ONE_TIME_MAX  280
00020 #define ZERO_TIME_MIN 390
00021 #define ZERO_TIME_MAX 540
00022 
00023 #define FPS24_REF 521
00024 #define FPS25_REF 500
00025 #define FPS30_REF 417
00026 
00027 #define US_TICKER_TIMER      ((LPC_TIM_TypeDef *)LPC_TIM2_BASE)
00028 #define US_TICKER_TIMER_IRQn TIMER2_IRQn
00029 
00030 LTC_SMPTE *LTC_SMPTE::_inst;
00031 
00032 void isrTimer () {
00033     US_TICKER_TIMER->TC = 0;
00034     US_TICKER_TIMER->IR = 1;
00035     LTC_SMPTE::_inst->isr_ticker();
00036 }
00037 
00038 LTC_SMPTE::LTC_SMPTE (PinName pin, enum LTC_TYPE type) {
00039 
00040     _inst = this;
00041     mode = 0;
00042     count = 0;
00043     oneflg = 0;
00044     direction = 0;
00045     received = 0;
00046 
00047     this->type = type;
00048     if (type == LTC_INPUT) {
00049         _input = new InterruptIn(pin);
00050         _input->mode(PullUp);
00051         _input->fall(this, &LTC_SMPTE::isr_change);
00052         _input->rise(this, &LTC_SMPTE::isr_change);
00053 
00054         _timer.start();
00055     } else {
00056         _output = new DigitalOut(pin);
00057 
00058         LPC_SC->PCONP |= 1 << 22; // Clock TIMER_2
00059         US_TICKER_TIMER->CTCR = 0x0; // timer mode
00060         uint32_t PCLK = SystemCoreClock / 4;
00061         US_TICKER_TIMER->TCR = 0x2;  // reset
00062         uint32_t prescale = PCLK / 2400 / 2; // 80bit * 30frame
00063         US_TICKER_TIMER->PR = prescale - 1;
00064         NVIC_SetVector(US_TICKER_TIMER_IRQn, (uint32_t)&isrTimer);
00065         NVIC_EnableIRQ(US_TICKER_TIMER_IRQn);
00066     }
00067 }
00068 
00069 void LTC_SMPTE::isr_change () {
00070     int b, t;
00071 
00072     t = _timer.read_us();
00073     _timer.reset();
00074 
00075     if (t >= ONE_TIME_MIN && t < ONE_TIME_MAX) {
00076         if (oneflg == 0) {
00077             oneflg = 1;
00078             return;
00079         } else {
00080             oneflg = 0;
00081             b = 1;
00082         }
00083     } else
00084     if (t >= ZERO_TIME_MIN && t < ZERO_TIME_MAX) {
00085         oneflg = 0;
00086         b = 0;
00087 
00088         if (t >= FPS24_REF - 10 && t <= FPS24_REF + 10) {
00089             fps = 0;
00090         } else
00091         if (t >= FPS25_REF - 10 && t <= FPS25_REF + 10) {
00092             fps = 1;
00093         } else
00094         if (t >= FPS30_REF - 10 && t <= FPS30_REF + 10) {
00095             fps = drop ? 2 : 3; // 29.97 / 30
00096         }
00097     } else {
00098         oneflg = 0;
00099         count = 0;
00100         return;
00101     }
00102 
00103     for (int i = 0; i < 9; i ++) {
00104         code[i] = (code[i] >> 1) | ((code[i + 1] & 1) ? 0x80 : 0);
00105     }
00106     code[9] = (code[9] >> 1) | (b ? 0x80 : 0);
00107     count ++;
00108 
00109     if (code[8] == 0xfc && code[9] == 0xbf && count >= 80) {
00110         parse_code();
00111         count = 0;
00112     }
00113 }
00114 
00115 void LTC_SMPTE::parse_code () {
00116     frame = (code[1] & 0x03) * 10 + (code[0] & 0x0f);
00117     sec   = (code[3] & 0x07) * 10 + (code[2] & 0x0f);
00118     min   = (code[5] & 0x07) * 10 + (code[4] & 0x0f);
00119     hour  = (code[7] & 0x03) * 10 + (code[6] & 0x0f);
00120     drop  = code[1] & (1<<2) ? 1 : 0;
00121     received = 1;
00122 }
00123 
00124 void LTC_SMPTE::read (int *hour, int *min, int *sec, int *frame, int *dir) {
00125     *hour = this->hour | (this->fps << 5);
00126     *min = this->min;
00127     *sec = this->sec;
00128     *frame = this->frame;
00129     if (dir) *dir = this->direction;
00130     received = 0;
00131 }
00132 
00133 void LTC_SMPTE::write (int hour, int min, int sec, int frame, int dir) {
00134     if (type != LTC_OUTPUT) return;
00135 
00136     US_TICKER_TIMER->TCR = 0;
00137     this->hour = hour;
00138     this->min = min;
00139     this->sec = sec;
00140     this->frame = frame;
00141     this->direction = dir;
00142     mode = 0;
00143     count = 0;
00144 
00145     US_TICKER_TIMER->TCR = 0x2;  // reset
00146     // set match value
00147     US_TICKER_TIMER->MR0 = 1;
00148     // enable match interrupt
00149     US_TICKER_TIMER->MCR |= 1;
00150     US_TICKER_TIMER->TCR = 1; // enable = 1, reset = 0
00151 
00152     _timer.reset();
00153     _timer.start();
00154     __enable_irq();
00155 }
00156 
00157 void LTC_SMPTE::isr_ticker () {
00158     if (mode) {
00159         if (bit) {
00160             phase = !phase;
00161             _output->write(phase);
00162         }
00163         mode = 0;
00164         return;
00165     }
00166 
00167     phase = !phase;
00168     _output->write(phase);
00169     mode = 1;
00170 
00171     if (count >= 0 && count <= 3) {
00172         bit = (frame % 10) & (1 << count);
00173     } else
00174     if (count >= 8 && count <= 9) {
00175         bit = (frame / 10) & (1 << (count - 8));
00176     } else
00177     if (count >= 16 && count <= 19) {
00178         bit = (sec % 10) & (1 << (count - 16));
00179     } else
00180     if (count >= 24 && count <= 26) {
00181         bit = (sec / 10) & (1 << (count - 24));
00182     } else
00183     if (count >= 32 && count <= 35) {
00184         bit = (min % 10) & (1 << (count - 32));
00185     } else
00186     if (count >= 40 && count <= 42) {
00187         bit = (min / 10) & (1 << (count - 40));
00188     } else
00189     if (count >= 48 && count <= 51) {
00190         bit = (hour % 10) & (1 << (count - 48));
00191     } else
00192     if (count >= 56 && count <= 57) {
00193         bit = (hour / 10) & (1 << (count - 56));
00194     } else
00195     if ((count >= 66 && count <= 77) || count == 79) {
00196         bit = 1;
00197     } else {
00198         bit = 0;
00199     }
00200 
00201     count ++;
00202     if (count >= 80) {
00203         count = 0;
00204         frame ++;
00205         if (frame >= 30) {
00206             frame = 0;
00207             sec ++;
00208             if (sec >= 60) {
00209                 sec = 0;
00210                 min ++;
00211                 if (min >= 60) {
00212                     min = 0;
00213                     hour ++;
00214                     if (hour >= 24) {
00215                         hour = 0;
00216                     }
00217                 }
00218             }
00219         }
00220     }
00221 }
00222 
00223 int LTC_SMPTE::isReceived () {
00224     return received;
00225 }