SMPTE timedode (LTC) decode library for mbed
SMPTE timedode (LTC) decode library
SMPTEタイムコードをデコード(受信)・エンコード(送信)するライブラリです。
平衡/不平衡/サウンド等によるLTC信号は、適当な回路で整形して入力してください。
出力は適当なドライバ回路を設けてください。
簡易的なプログラムのため、細かいフラグなどは無視しています。
LPC1768 専用、Timer 2 を占有します。
Sample
Import programLTC_SMPTE_sample
SMPTE timedode (LTC) decode library for mbed https://developer.mbed.org/users/okini3939/code/LTC_SMPTE/
LTC_SMPTE.cpp
- Committer:
- okini3939
- Date:
- 2018-05-14
- Revision:
- 2:13a89fffbb75
- Parent:
- 1:63ceee4bfd05
File content as of revision 2:13a89fffbb75:
/** * SMPTE timedode (LTC) decode library for mbed * Copyright (c) 2015 Suga * Released under the MIT License: http://mbed.org/license/mit */ /** @file * @brief SMPTE timedode (LTC) decode library for mbed */ #include "LTC_SMPTE.h" #if ! defined(TARGET_LPC176X) #error "this CPU is not supported. use LPC1768" #endif // pulse width: 416.7us(30fps) // 80bit x 30frame/s --> 416.7us/bit #define ONE_TIME_MIN 180 #define ONE_TIME_MAX 280 #define ZERO_TIME_MIN 390 #define ZERO_TIME_MAX 540 #define FPS24_REF 521 #define FPS25_REF 500 #define FPS30_REF 417 #define US_TICKER_TIMER ((LPC_TIM_TypeDef *)LPC_TIM2_BASE) #define US_TICKER_TIMER_IRQn TIMER2_IRQn LTC_SMPTE *LTC_SMPTE::_inst; void isrTimer () { US_TICKER_TIMER->TC = 0; US_TICKER_TIMER->IR = 1; LTC_SMPTE::_inst->isr_ticker(); } LTC_SMPTE::LTC_SMPTE (PinName pin, enum LTC_TYPE type) { _inst = this; mode = 0; count = 0; oneflg = 0; direction = 0; received = 0; this->type = type; if (type == LTC_INPUT) { _input = new InterruptIn(pin); _input->mode(PullUp); _input->fall(this, <C_SMPTE::isr_change); _input->rise(this, <C_SMPTE::isr_change); _timer.start(); } else { _output = new DigitalOut(pin); LPC_SC->PCONP |= 1 << 22; // Clock TIMER_2 US_TICKER_TIMER->CTCR = 0x0; // timer mode uint32_t PCLK = SystemCoreClock / 4; US_TICKER_TIMER->TCR = 0x2; // reset uint32_t prescale = PCLK / 2400 / 2; // 80bit * 30frame US_TICKER_TIMER->PR = prescale - 1; NVIC_SetVector(US_TICKER_TIMER_IRQn, (uint32_t)&isrTimer); NVIC_EnableIRQ(US_TICKER_TIMER_IRQn); } } void LTC_SMPTE::isr_change () { int b, t; t = _timer.read_us(); _timer.reset(); if (t >= ONE_TIME_MIN && t < ONE_TIME_MAX) { if (oneflg == 0) { oneflg = 1; return; } else { oneflg = 0; b = 1; } } else if (t >= ZERO_TIME_MIN && t < ZERO_TIME_MAX) { oneflg = 0; b = 0; if (t >= FPS24_REF - 10 && t <= FPS24_REF + 10) { fps = 0; } else if (t >= FPS25_REF - 10 && t <= FPS25_REF + 10) { fps = 1; } else if (t >= FPS30_REF - 10 && t <= FPS30_REF + 10) { fps = drop ? 2 : 3; // 29.97 / 30 } } else { oneflg = 0; count = 0; return; } for (int i = 0; i < 9; i ++) { code[i] = (code[i] >> 1) | ((code[i + 1] & 1) ? 0x80 : 0); } code[9] = (code[9] >> 1) | (b ? 0x80 : 0); count ++; if (code[8] == 0xfc && code[9] == 0xbf && count >= 80) { parse_code(); count = 0; } } void LTC_SMPTE::parse_code () { frame = (code[1] & 0x03) * 10 + (code[0] & 0x0f); sec = (code[3] & 0x07) * 10 + (code[2] & 0x0f); min = (code[5] & 0x07) * 10 + (code[4] & 0x0f); hour = (code[7] & 0x03) * 10 + (code[6] & 0x0f); drop = code[1] & (1<<2) ? 1 : 0; received = 1; } void LTC_SMPTE::read (int *hour, int *min, int *sec, int *frame, int *dir) { *hour = this->hour | (this->fps << 5); *min = this->min; *sec = this->sec; *frame = this->frame; if (dir) *dir = this->direction; received = 0; } void LTC_SMPTE::write (int hour, int min, int sec, int frame, int dir) { if (type != LTC_OUTPUT) return; US_TICKER_TIMER->TCR = 0; this->hour = hour; this->min = min; this->sec = sec; this->frame = frame; this->direction = dir; mode = 0; count = 0; US_TICKER_TIMER->TCR = 0x2; // reset // set match value US_TICKER_TIMER->MR0 = 1; // enable match interrupt US_TICKER_TIMER->MCR |= 1; US_TICKER_TIMER->TCR = 1; // enable = 1, reset = 0 _timer.reset(); _timer.start(); __enable_irq(); } void LTC_SMPTE::isr_ticker () { if (mode) { if (bit) { phase = !phase; _output->write(phase); } mode = 0; return; } phase = !phase; _output->write(phase); mode = 1; if (count >= 0 && count <= 3) { bit = (frame % 10) & (1 << count); } else if (count >= 8 && count <= 9) { bit = (frame / 10) & (1 << (count - 8)); } else if (count >= 16 && count <= 19) { bit = (sec % 10) & (1 << (count - 16)); } else if (count >= 24 && count <= 26) { bit = (sec / 10) & (1 << (count - 24)); } else if (count >= 32 && count <= 35) { bit = (min % 10) & (1 << (count - 32)); } else if (count >= 40 && count <= 42) { bit = (min / 10) & (1 << (count - 40)); } else if (count >= 48 && count <= 51) { bit = (hour % 10) & (1 << (count - 48)); } else if (count >= 56 && count <= 57) { bit = (hour / 10) & (1 << (count - 56)); } else if ((count >= 66 && count <= 77) || count == 79) { bit = 1; } else { bit = 0; } count ++; if (count >= 80) { count = 0; frame ++; if (frame >= 30) { frame = 0; sec ++; if (sec >= 60) { sec = 0; min ++; if (min >= 60) { min = 0; hour ++; if (hour >= 24) { hour = 0; } } } } } } int LTC_SMPTE::isReceived () { return received; }