SMPTE timedode (LTC) decode library for mbed

Dependents:   LTC_SMPTE_sample

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/

Committer:
okini3939
Date:
Mon May 14 08:50:39 2018 +0000
Revision:
2:13a89fffbb75
Parent:
1:63ceee4bfd05
Supported 24, 25fps, Fix algorithm

Who changed what in which revision?

UserRevisionLine numberNew contents of line
okini3939 0:8d19e2158eb4 1 /**
okini3939 0:8d19e2158eb4 2 * SMPTE timedode (LTC) decode library for mbed
okini3939 0:8d19e2158eb4 3 * Copyright (c) 2015 Suga
okini3939 0:8d19e2158eb4 4 * Released under the MIT License: http://mbed.org/license/mit
okini3939 0:8d19e2158eb4 5 */
okini3939 0:8d19e2158eb4 6 /** @file
okini3939 0:8d19e2158eb4 7 * @brief SMPTE timedode (LTC) decode library for mbed
okini3939 0:8d19e2158eb4 8 */
okini3939 0:8d19e2158eb4 9
okini3939 0:8d19e2158eb4 10 #include "LTC_SMPTE.h"
okini3939 0:8d19e2158eb4 11
okini3939 1:63ceee4bfd05 12 #if ! defined(TARGET_LPC176X)
okini3939 1:63ceee4bfd05 13 #error "this CPU is not supported. use LPC1768"
okini3939 1:63ceee4bfd05 14 #endif
okini3939 1:63ceee4bfd05 15
okini3939 0:8d19e2158eb4 16 // pulse width: 416.7us(30fps)
okini3939 0:8d19e2158eb4 17 // 80bit x 30frame/s --> 416.7us/bit
okini3939 2:13a89fffbb75 18 #define ONE_TIME_MIN 180
okini3939 2:13a89fffbb75 19 #define ONE_TIME_MAX 280
okini3939 2:13a89fffbb75 20 #define ZERO_TIME_MIN 390
okini3939 2:13a89fffbb75 21 #define ZERO_TIME_MAX 540
okini3939 2:13a89fffbb75 22
okini3939 2:13a89fffbb75 23 #define FPS24_REF 521
okini3939 2:13a89fffbb75 24 #define FPS25_REF 500
okini3939 2:13a89fffbb75 25 #define FPS30_REF 417
okini3939 0:8d19e2158eb4 26
okini3939 1:63ceee4bfd05 27 #define US_TICKER_TIMER ((LPC_TIM_TypeDef *)LPC_TIM2_BASE)
okini3939 1:63ceee4bfd05 28 #define US_TICKER_TIMER_IRQn TIMER2_IRQn
okini3939 1:63ceee4bfd05 29
okini3939 1:63ceee4bfd05 30 LTC_SMPTE *LTC_SMPTE::_inst;
okini3939 0:8d19e2158eb4 31
okini3939 1:63ceee4bfd05 32 void isrTimer () {
okini3939 1:63ceee4bfd05 33 US_TICKER_TIMER->TC = 0;
okini3939 1:63ceee4bfd05 34 US_TICKER_TIMER->IR = 1;
okini3939 1:63ceee4bfd05 35 LTC_SMPTE::_inst->isr_ticker();
okini3939 1:63ceee4bfd05 36 }
okini3939 1:63ceee4bfd05 37
okini3939 1:63ceee4bfd05 38 LTC_SMPTE::LTC_SMPTE (PinName pin, enum LTC_TYPE type) {
okini3939 1:63ceee4bfd05 39
okini3939 1:63ceee4bfd05 40 _inst = this;
okini3939 0:8d19e2158eb4 41 mode = 0;
okini3939 0:8d19e2158eb4 42 count = 0;
okini3939 0:8d19e2158eb4 43 oneflg = 0;
okini3939 0:8d19e2158eb4 44 direction = 0;
okini3939 0:8d19e2158eb4 45 received = 0;
okini3939 0:8d19e2158eb4 46
okini3939 1:63ceee4bfd05 47 this->type = type;
okini3939 1:63ceee4bfd05 48 if (type == LTC_INPUT) {
okini3939 1:63ceee4bfd05 49 _input = new InterruptIn(pin);
okini3939 1:63ceee4bfd05 50 _input->mode(PullUp);
okini3939 1:63ceee4bfd05 51 _input->fall(this, &LTC_SMPTE::isr_change);
okini3939 1:63ceee4bfd05 52 _input->rise(this, &LTC_SMPTE::isr_change);
okini3939 1:63ceee4bfd05 53
okini3939 1:63ceee4bfd05 54 _timer.start();
okini3939 1:63ceee4bfd05 55 } else {
okini3939 1:63ceee4bfd05 56 _output = new DigitalOut(pin);
okini3939 1:63ceee4bfd05 57
okini3939 1:63ceee4bfd05 58 LPC_SC->PCONP |= 1 << 22; // Clock TIMER_2
okini3939 1:63ceee4bfd05 59 US_TICKER_TIMER->CTCR = 0x0; // timer mode
okini3939 1:63ceee4bfd05 60 uint32_t PCLK = SystemCoreClock / 4;
okini3939 1:63ceee4bfd05 61 US_TICKER_TIMER->TCR = 0x2; // reset
okini3939 1:63ceee4bfd05 62 uint32_t prescale = PCLK / 2400 / 2; // 80bit * 30frame
okini3939 1:63ceee4bfd05 63 US_TICKER_TIMER->PR = prescale - 1;
okini3939 1:63ceee4bfd05 64 NVIC_SetVector(US_TICKER_TIMER_IRQn, (uint32_t)&isrTimer);
okini3939 1:63ceee4bfd05 65 NVIC_EnableIRQ(US_TICKER_TIMER_IRQn);
okini3939 1:63ceee4bfd05 66 }
okini3939 0:8d19e2158eb4 67 }
okini3939 0:8d19e2158eb4 68
okini3939 0:8d19e2158eb4 69 void LTC_SMPTE::isr_change () {
okini3939 0:8d19e2158eb4 70 int b, t;
okini3939 0:8d19e2158eb4 71
okini3939 0:8d19e2158eb4 72 t = _timer.read_us();
okini3939 0:8d19e2158eb4 73 _timer.reset();
okini3939 0:8d19e2158eb4 74
okini3939 0:8d19e2158eb4 75 if (t >= ONE_TIME_MIN && t < ONE_TIME_MAX) {
okini3939 0:8d19e2158eb4 76 if (oneflg == 0) {
okini3939 0:8d19e2158eb4 77 oneflg = 1;
okini3939 0:8d19e2158eb4 78 return;
okini3939 0:8d19e2158eb4 79 } else {
okini3939 0:8d19e2158eb4 80 oneflg = 0;
okini3939 0:8d19e2158eb4 81 b = 1;
okini3939 0:8d19e2158eb4 82 }
okini3939 0:8d19e2158eb4 83 } else
okini3939 0:8d19e2158eb4 84 if (t >= ZERO_TIME_MIN && t < ZERO_TIME_MAX) {
okini3939 0:8d19e2158eb4 85 oneflg = 0;
okini3939 0:8d19e2158eb4 86 b = 0;
okini3939 2:13a89fffbb75 87
okini3939 2:13a89fffbb75 88 if (t >= FPS24_REF - 10 && t <= FPS24_REF + 10) {
okini3939 2:13a89fffbb75 89 fps = 0;
okini3939 2:13a89fffbb75 90 } else
okini3939 2:13a89fffbb75 91 if (t >= FPS25_REF - 10 && t <= FPS25_REF + 10) {
okini3939 2:13a89fffbb75 92 fps = 1;
okini3939 2:13a89fffbb75 93 } else
okini3939 2:13a89fffbb75 94 if (t >= FPS30_REF - 10 && t <= FPS30_REF + 10) {
okini3939 2:13a89fffbb75 95 fps = drop ? 2 : 3; // 29.97 / 30
okini3939 2:13a89fffbb75 96 }
okini3939 0:8d19e2158eb4 97 } else {
okini3939 2:13a89fffbb75 98 oneflg = 0;
okini3939 2:13a89fffbb75 99 count = 0;
okini3939 0:8d19e2158eb4 100 return;
okini3939 0:8d19e2158eb4 101 }
okini3939 0:8d19e2158eb4 102
okini3939 2:13a89fffbb75 103 for (int i = 0; i < 9; i ++) {
okini3939 2:13a89fffbb75 104 code[i] = (code[i] >> 1) | ((code[i + 1] & 1) ? 0x80 : 0);
okini3939 2:13a89fffbb75 105 }
okini3939 2:13a89fffbb75 106 code[9] = (code[9] >> 1) | (b ? 0x80 : 0);
okini3939 2:13a89fffbb75 107 count ++;
okini3939 0:8d19e2158eb4 108
okini3939 2:13a89fffbb75 109 if (code[8] == 0xfc && code[9] == 0xbf && count >= 80) {
okini3939 2:13a89fffbb75 110 parse_code();
okini3939 2:13a89fffbb75 111 count = 0;
okini3939 0:8d19e2158eb4 112 }
okini3939 0:8d19e2158eb4 113 }
okini3939 0:8d19e2158eb4 114
okini3939 0:8d19e2158eb4 115 void LTC_SMPTE::parse_code () {
okini3939 0:8d19e2158eb4 116 frame = (code[1] & 0x03) * 10 + (code[0] & 0x0f);
okini3939 0:8d19e2158eb4 117 sec = (code[3] & 0x07) * 10 + (code[2] & 0x0f);
okini3939 0:8d19e2158eb4 118 min = (code[5] & 0x07) * 10 + (code[4] & 0x0f);
okini3939 0:8d19e2158eb4 119 hour = (code[7] & 0x03) * 10 + (code[6] & 0x0f);
okini3939 0:8d19e2158eb4 120 drop = code[1] & (1<<2) ? 1 : 0;
okini3939 0:8d19e2158eb4 121 received = 1;
okini3939 0:8d19e2158eb4 122 }
okini3939 0:8d19e2158eb4 123
okini3939 0:8d19e2158eb4 124 void LTC_SMPTE::read (int *hour, int *min, int *sec, int *frame, int *dir) {
okini3939 2:13a89fffbb75 125 *hour = this->hour | (this->fps << 5);
okini3939 0:8d19e2158eb4 126 *min = this->min;
okini3939 0:8d19e2158eb4 127 *sec = this->sec;
okini3939 0:8d19e2158eb4 128 *frame = this->frame;
okini3939 0:8d19e2158eb4 129 if (dir) *dir = this->direction;
okini3939 0:8d19e2158eb4 130 received = 0;
okini3939 0:8d19e2158eb4 131 }
okini3939 0:8d19e2158eb4 132
okini3939 1:63ceee4bfd05 133 void LTC_SMPTE::write (int hour, int min, int sec, int frame, int dir) {
okini3939 1:63ceee4bfd05 134 if (type != LTC_OUTPUT) return;
okini3939 1:63ceee4bfd05 135
okini3939 1:63ceee4bfd05 136 US_TICKER_TIMER->TCR = 0;
okini3939 1:63ceee4bfd05 137 this->hour = hour;
okini3939 1:63ceee4bfd05 138 this->min = min;
okini3939 1:63ceee4bfd05 139 this->sec = sec;
okini3939 1:63ceee4bfd05 140 this->frame = frame;
okini3939 1:63ceee4bfd05 141 this->direction = dir;
okini3939 1:63ceee4bfd05 142 mode = 0;
okini3939 1:63ceee4bfd05 143 count = 0;
okini3939 1:63ceee4bfd05 144
okini3939 1:63ceee4bfd05 145 US_TICKER_TIMER->TCR = 0x2; // reset
okini3939 1:63ceee4bfd05 146 // set match value
okini3939 1:63ceee4bfd05 147 US_TICKER_TIMER->MR0 = 1;
okini3939 1:63ceee4bfd05 148 // enable match interrupt
okini3939 1:63ceee4bfd05 149 US_TICKER_TIMER->MCR |= 1;
okini3939 1:63ceee4bfd05 150 US_TICKER_TIMER->TCR = 1; // enable = 1, reset = 0
okini3939 1:63ceee4bfd05 151
okini3939 1:63ceee4bfd05 152 _timer.reset();
okini3939 1:63ceee4bfd05 153 _timer.start();
okini3939 1:63ceee4bfd05 154 __enable_irq();
okini3939 1:63ceee4bfd05 155 }
okini3939 1:63ceee4bfd05 156
okini3939 1:63ceee4bfd05 157 void LTC_SMPTE::isr_ticker () {
okini3939 1:63ceee4bfd05 158 if (mode) {
okini3939 1:63ceee4bfd05 159 if (bit) {
okini3939 1:63ceee4bfd05 160 phase = !phase;
okini3939 1:63ceee4bfd05 161 _output->write(phase);
okini3939 1:63ceee4bfd05 162 }
okini3939 1:63ceee4bfd05 163 mode = 0;
okini3939 1:63ceee4bfd05 164 return;
okini3939 1:63ceee4bfd05 165 }
okini3939 1:63ceee4bfd05 166
okini3939 1:63ceee4bfd05 167 phase = !phase;
okini3939 1:63ceee4bfd05 168 _output->write(phase);
okini3939 1:63ceee4bfd05 169 mode = 1;
okini3939 1:63ceee4bfd05 170
okini3939 1:63ceee4bfd05 171 if (count >= 0 && count <= 3) {
okini3939 1:63ceee4bfd05 172 bit = (frame % 10) & (1 << count);
okini3939 1:63ceee4bfd05 173 } else
okini3939 1:63ceee4bfd05 174 if (count >= 8 && count <= 9) {
okini3939 1:63ceee4bfd05 175 bit = (frame / 10) & (1 << (count - 8));
okini3939 1:63ceee4bfd05 176 } else
okini3939 1:63ceee4bfd05 177 if (count >= 16 && count <= 19) {
okini3939 1:63ceee4bfd05 178 bit = (sec % 10) & (1 << (count - 16));
okini3939 1:63ceee4bfd05 179 } else
okini3939 1:63ceee4bfd05 180 if (count >= 24 && count <= 26) {
okini3939 1:63ceee4bfd05 181 bit = (sec / 10) & (1 << (count - 24));
okini3939 1:63ceee4bfd05 182 } else
okini3939 1:63ceee4bfd05 183 if (count >= 32 && count <= 35) {
okini3939 1:63ceee4bfd05 184 bit = (min % 10) & (1 << (count - 32));
okini3939 1:63ceee4bfd05 185 } else
okini3939 1:63ceee4bfd05 186 if (count >= 40 && count <= 42) {
okini3939 1:63ceee4bfd05 187 bit = (min / 10) & (1 << (count - 40));
okini3939 1:63ceee4bfd05 188 } else
okini3939 1:63ceee4bfd05 189 if (count >= 48 && count <= 51) {
okini3939 1:63ceee4bfd05 190 bit = (hour % 10) & (1 << (count - 48));
okini3939 1:63ceee4bfd05 191 } else
okini3939 1:63ceee4bfd05 192 if (count >= 56 && count <= 57) {
okini3939 1:63ceee4bfd05 193 bit = (hour / 10) & (1 << (count - 56));
okini3939 1:63ceee4bfd05 194 } else
okini3939 1:63ceee4bfd05 195 if ((count >= 66 && count <= 77) || count == 79) {
okini3939 1:63ceee4bfd05 196 bit = 1;
okini3939 1:63ceee4bfd05 197 } else {
okini3939 1:63ceee4bfd05 198 bit = 0;
okini3939 1:63ceee4bfd05 199 }
okini3939 1:63ceee4bfd05 200
okini3939 1:63ceee4bfd05 201 count ++;
okini3939 1:63ceee4bfd05 202 if (count >= 80) {
okini3939 1:63ceee4bfd05 203 count = 0;
okini3939 1:63ceee4bfd05 204 frame ++;
okini3939 1:63ceee4bfd05 205 if (frame >= 30) {
okini3939 1:63ceee4bfd05 206 frame = 0;
okini3939 1:63ceee4bfd05 207 sec ++;
okini3939 1:63ceee4bfd05 208 if (sec >= 60) {
okini3939 1:63ceee4bfd05 209 sec = 0;
okini3939 1:63ceee4bfd05 210 min ++;
okini3939 1:63ceee4bfd05 211 if (min >= 60) {
okini3939 1:63ceee4bfd05 212 min = 0;
okini3939 1:63ceee4bfd05 213 hour ++;
okini3939 1:63ceee4bfd05 214 if (hour >= 24) {
okini3939 1:63ceee4bfd05 215 hour = 0;
okini3939 1:63ceee4bfd05 216 }
okini3939 1:63ceee4bfd05 217 }
okini3939 1:63ceee4bfd05 218 }
okini3939 1:63ceee4bfd05 219 }
okini3939 1:63ceee4bfd05 220 }
okini3939 1:63ceee4bfd05 221 }
okini3939 1:63ceee4bfd05 222
okini3939 0:8d19e2158eb4 223 int LTC_SMPTE::isReceived () {
okini3939 0:8d19e2158eb4 224 return received;
okini3939 0:8d19e2158eb4 225 }