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:
Fri Apr 13 04:05:13 2018 +0000
Revision:
1:63ceee4bfd05
Parent:
0:8d19e2158eb4
Child:
2:13a89fffbb75
supported LTC output;

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 0:8d19e2158eb4 18 #define ONE_TIME_MIN 100
okini3939 0:8d19e2158eb4 19 #define ONE_TIME_MAX 250
okini3939 0:8d19e2158eb4 20 #define ZERO_TIME_MIN 300
okini3939 0:8d19e2158eb4 21 #define ZERO_TIME_MAX 500
okini3939 0:8d19e2158eb4 22
okini3939 1:63ceee4bfd05 23 #define US_TICKER_TIMER ((LPC_TIM_TypeDef *)LPC_TIM2_BASE)
okini3939 1:63ceee4bfd05 24 #define US_TICKER_TIMER_IRQn TIMER2_IRQn
okini3939 1:63ceee4bfd05 25
okini3939 1:63ceee4bfd05 26 LTC_SMPTE *LTC_SMPTE::_inst;
okini3939 0:8d19e2158eb4 27
okini3939 1:63ceee4bfd05 28 void isrTimer () {
okini3939 1:63ceee4bfd05 29 US_TICKER_TIMER->TC = 0;
okini3939 1:63ceee4bfd05 30 US_TICKER_TIMER->IR = 1;
okini3939 1:63ceee4bfd05 31 LTC_SMPTE::_inst->isr_ticker();
okini3939 1:63ceee4bfd05 32 }
okini3939 1:63ceee4bfd05 33
okini3939 1:63ceee4bfd05 34 LTC_SMPTE::LTC_SMPTE (PinName pin, enum LTC_TYPE type) {
okini3939 1:63ceee4bfd05 35
okini3939 1:63ceee4bfd05 36 _inst = this;
okini3939 0:8d19e2158eb4 37 mode = 0;
okini3939 0:8d19e2158eb4 38 count = 0;
okini3939 0:8d19e2158eb4 39 oneflg = 0;
okini3939 0:8d19e2158eb4 40 direction = 0;
okini3939 0:8d19e2158eb4 41 received = 0;
okini3939 0:8d19e2158eb4 42
okini3939 1:63ceee4bfd05 43 this->type = type;
okini3939 1:63ceee4bfd05 44 if (type == LTC_INPUT) {
okini3939 1:63ceee4bfd05 45 _input = new InterruptIn(pin);
okini3939 1:63ceee4bfd05 46 _input->mode(PullUp);
okini3939 1:63ceee4bfd05 47 _input->fall(this, &LTC_SMPTE::isr_change);
okini3939 1:63ceee4bfd05 48 _input->rise(this, &LTC_SMPTE::isr_change);
okini3939 1:63ceee4bfd05 49
okini3939 1:63ceee4bfd05 50 _timer.start();
okini3939 1:63ceee4bfd05 51 } else {
okini3939 1:63ceee4bfd05 52 _output = new DigitalOut(pin);
okini3939 1:63ceee4bfd05 53
okini3939 1:63ceee4bfd05 54 LPC_SC->PCONP |= 1 << 22; // Clock TIMER_2
okini3939 1:63ceee4bfd05 55 US_TICKER_TIMER->CTCR = 0x0; // timer mode
okini3939 1:63ceee4bfd05 56 uint32_t PCLK = SystemCoreClock / 4;
okini3939 1:63ceee4bfd05 57 US_TICKER_TIMER->TCR = 0x2; // reset
okini3939 1:63ceee4bfd05 58 uint32_t prescale = PCLK / 2400 / 2; // 80bit * 30frame
okini3939 1:63ceee4bfd05 59 US_TICKER_TIMER->PR = prescale - 1;
okini3939 1:63ceee4bfd05 60 NVIC_SetVector(US_TICKER_TIMER_IRQn, (uint32_t)&isrTimer);
okini3939 1:63ceee4bfd05 61 NVIC_EnableIRQ(US_TICKER_TIMER_IRQn);
okini3939 1:63ceee4bfd05 62 }
okini3939 0:8d19e2158eb4 63 }
okini3939 0:8d19e2158eb4 64
okini3939 0:8d19e2158eb4 65 void LTC_SMPTE::isr_change () {
okini3939 0:8d19e2158eb4 66 int b, t;
okini3939 0:8d19e2158eb4 67
okini3939 0:8d19e2158eb4 68 t = _timer.read_us();
okini3939 0:8d19e2158eb4 69 _timer.reset();
okini3939 0:8d19e2158eb4 70
okini3939 0:8d19e2158eb4 71 if (t >= ONE_TIME_MIN && t < ONE_TIME_MAX) {
okini3939 0:8d19e2158eb4 72 if (oneflg == 0) {
okini3939 0:8d19e2158eb4 73 oneflg = 1;
okini3939 0:8d19e2158eb4 74 return;
okini3939 0:8d19e2158eb4 75 } else {
okini3939 0:8d19e2158eb4 76 oneflg = 0;
okini3939 0:8d19e2158eb4 77 b = 1;
okini3939 0:8d19e2158eb4 78 }
okini3939 0:8d19e2158eb4 79 } else
okini3939 0:8d19e2158eb4 80 if (t >= ZERO_TIME_MIN && t < ZERO_TIME_MAX) {
okini3939 0:8d19e2158eb4 81 oneflg = 0;
okini3939 0:8d19e2158eb4 82 b = 0;
okini3939 0:8d19e2158eb4 83 } else {
okini3939 0:8d19e2158eb4 84 return;
okini3939 0:8d19e2158eb4 85 }
okini3939 0:8d19e2158eb4 86
okini3939 0:8d19e2158eb4 87 if (mode == 0) {
okini3939 0:8d19e2158eb4 88 // sync word
okini3939 0:8d19e2158eb4 89 if (b) {
okini3939 0:8d19e2158eb4 90 // 1
okini3939 0:8d19e2158eb4 91 if (count == 12) {
okini3939 0:8d19e2158eb4 92 // error
okini3939 0:8d19e2158eb4 93 count = 0;
okini3939 0:8d19e2158eb4 94 } else
okini3939 0:8d19e2158eb4 95 if (count == 13) {
okini3939 0:8d19e2158eb4 96 // fwd
okini3939 0:8d19e2158eb4 97 direction = 1;
okini3939 0:8d19e2158eb4 98 count = 0;
okini3939 0:8d19e2158eb4 99 mode = 1;
okini3939 0:8d19e2158eb4 100 bit = 1;
okini3939 0:8d19e2158eb4 101 } else {
okini3939 0:8d19e2158eb4 102 count ++;
okini3939 0:8d19e2158eb4 103 }
okini3939 0:8d19e2158eb4 104 } else {
okini3939 0:8d19e2158eb4 105 // 0
okini3939 0:8d19e2158eb4 106 if (count == 12) {
okini3939 0:8d19e2158eb4 107 count ++;
okini3939 0:8d19e2158eb4 108 } else
okini3939 0:8d19e2158eb4 109 if (count == 13) {
okini3939 0:8d19e2158eb4 110 // rev
okini3939 0:8d19e2158eb4 111 direction = -1;
okini3939 0:8d19e2158eb4 112 count = 0;
okini3939 0:8d19e2158eb4 113 mode = 1;
okini3939 0:8d19e2158eb4 114 bit = 1;
okini3939 0:8d19e2158eb4 115 } else {
okini3939 0:8d19e2158eb4 116 // error
okini3939 0:8d19e2158eb4 117 count = 0;
okini3939 0:8d19e2158eb4 118 }
okini3939 0:8d19e2158eb4 119 }
okini3939 0:8d19e2158eb4 120
okini3939 0:8d19e2158eb4 121 } else {
okini3939 0:8d19e2158eb4 122 // time code
okini3939 0:8d19e2158eb4 123 if (b) {
okini3939 0:8d19e2158eb4 124 code[count] |= bit; // 1
okini3939 0:8d19e2158eb4 125 } else {
okini3939 0:8d19e2158eb4 126 code[count] &= ~bit; // 0
okini3939 0:8d19e2158eb4 127 }
okini3939 0:8d19e2158eb4 128 bit <<= 1;
okini3939 0:8d19e2158eb4 129 if (bit >= 0x100) {
okini3939 0:8d19e2158eb4 130 bit = 1;
okini3939 0:8d19e2158eb4 131 count ++;
okini3939 0:8d19e2158eb4 132 if (count >= 8) {
okini3939 0:8d19e2158eb4 133 count = 0;
okini3939 0:8d19e2158eb4 134 mode = 0;
okini3939 0:8d19e2158eb4 135 parse_code();
okini3939 0:8d19e2158eb4 136 }
okini3939 0:8d19e2158eb4 137 }
okini3939 0:8d19e2158eb4 138 }
okini3939 0:8d19e2158eb4 139 }
okini3939 0:8d19e2158eb4 140
okini3939 0:8d19e2158eb4 141 void LTC_SMPTE::parse_code () {
okini3939 0:8d19e2158eb4 142 frame = (code[1] & 0x03) * 10 + (code[0] & 0x0f);
okini3939 0:8d19e2158eb4 143 sec = (code[3] & 0x07) * 10 + (code[2] & 0x0f);
okini3939 0:8d19e2158eb4 144 min = (code[5] & 0x07) * 10 + (code[4] & 0x0f);
okini3939 0:8d19e2158eb4 145 hour = (code[7] & 0x03) * 10 + (code[6] & 0x0f);
okini3939 0:8d19e2158eb4 146 drop = code[1] & (1<<2) ? 1 : 0;
okini3939 0:8d19e2158eb4 147 received = 1;
okini3939 0:8d19e2158eb4 148 }
okini3939 0:8d19e2158eb4 149
okini3939 0:8d19e2158eb4 150 void LTC_SMPTE::read (int *hour, int *min, int *sec, int *frame, int *dir) {
okini3939 0:8d19e2158eb4 151 *hour = this->hour;
okini3939 0:8d19e2158eb4 152 *min = this->min;
okini3939 0:8d19e2158eb4 153 *sec = this->sec;
okini3939 0:8d19e2158eb4 154 *frame = this->frame;
okini3939 0:8d19e2158eb4 155 if (dir) *dir = this->direction;
okini3939 0:8d19e2158eb4 156 received = 0;
okini3939 0:8d19e2158eb4 157 }
okini3939 0:8d19e2158eb4 158
okini3939 1:63ceee4bfd05 159 void LTC_SMPTE::write (int hour, int min, int sec, int frame, int dir) {
okini3939 1:63ceee4bfd05 160 if (type != LTC_OUTPUT) return;
okini3939 1:63ceee4bfd05 161
okini3939 1:63ceee4bfd05 162 US_TICKER_TIMER->TCR = 0;
okini3939 1:63ceee4bfd05 163 this->hour = hour;
okini3939 1:63ceee4bfd05 164 this->min = min;
okini3939 1:63ceee4bfd05 165 this->sec = sec;
okini3939 1:63ceee4bfd05 166 this->frame = frame;
okini3939 1:63ceee4bfd05 167 this->direction = dir;
okini3939 1:63ceee4bfd05 168 mode = 0;
okini3939 1:63ceee4bfd05 169 count = 0;
okini3939 1:63ceee4bfd05 170
okini3939 1:63ceee4bfd05 171 US_TICKER_TIMER->TCR = 0x2; // reset
okini3939 1:63ceee4bfd05 172 // set match value
okini3939 1:63ceee4bfd05 173 US_TICKER_TIMER->MR0 = 1;
okini3939 1:63ceee4bfd05 174 // enable match interrupt
okini3939 1:63ceee4bfd05 175 US_TICKER_TIMER->MCR |= 1;
okini3939 1:63ceee4bfd05 176 US_TICKER_TIMER->TCR = 1; // enable = 1, reset = 0
okini3939 1:63ceee4bfd05 177
okini3939 1:63ceee4bfd05 178 _timer.reset();
okini3939 1:63ceee4bfd05 179 _timer.start();
okini3939 1:63ceee4bfd05 180 __enable_irq();
okini3939 1:63ceee4bfd05 181 }
okini3939 1:63ceee4bfd05 182
okini3939 1:63ceee4bfd05 183 void LTC_SMPTE::isr_ticker () {
okini3939 1:63ceee4bfd05 184 if (mode) {
okini3939 1:63ceee4bfd05 185 if (bit) {
okini3939 1:63ceee4bfd05 186 phase = !phase;
okini3939 1:63ceee4bfd05 187 _output->write(phase);
okini3939 1:63ceee4bfd05 188 }
okini3939 1:63ceee4bfd05 189 mode = 0;
okini3939 1:63ceee4bfd05 190 return;
okini3939 1:63ceee4bfd05 191 }
okini3939 1:63ceee4bfd05 192
okini3939 1:63ceee4bfd05 193 phase = !phase;
okini3939 1:63ceee4bfd05 194 _output->write(phase);
okini3939 1:63ceee4bfd05 195 mode = 1;
okini3939 1:63ceee4bfd05 196
okini3939 1:63ceee4bfd05 197 if (count >= 0 && count <= 3) {
okini3939 1:63ceee4bfd05 198 bit = (frame % 10) & (1 << count);
okini3939 1:63ceee4bfd05 199 } else
okini3939 1:63ceee4bfd05 200 if (count >= 8 && count <= 9) {
okini3939 1:63ceee4bfd05 201 bit = (frame / 10) & (1 << (count - 8));
okini3939 1:63ceee4bfd05 202 } else
okini3939 1:63ceee4bfd05 203 if (count >= 16 && count <= 19) {
okini3939 1:63ceee4bfd05 204 bit = (sec % 10) & (1 << (count - 16));
okini3939 1:63ceee4bfd05 205 } else
okini3939 1:63ceee4bfd05 206 if (count >= 24 && count <= 26) {
okini3939 1:63ceee4bfd05 207 bit = (sec / 10) & (1 << (count - 24));
okini3939 1:63ceee4bfd05 208 } else
okini3939 1:63ceee4bfd05 209 if (count >= 32 && count <= 35) {
okini3939 1:63ceee4bfd05 210 bit = (min % 10) & (1 << (count - 32));
okini3939 1:63ceee4bfd05 211 } else
okini3939 1:63ceee4bfd05 212 if (count >= 40 && count <= 42) {
okini3939 1:63ceee4bfd05 213 bit = (min / 10) & (1 << (count - 40));
okini3939 1:63ceee4bfd05 214 } else
okini3939 1:63ceee4bfd05 215 if (count >= 48 && count <= 51) {
okini3939 1:63ceee4bfd05 216 bit = (hour % 10) & (1 << (count - 48));
okini3939 1:63ceee4bfd05 217 } else
okini3939 1:63ceee4bfd05 218 if (count >= 56 && count <= 57) {
okini3939 1:63ceee4bfd05 219 bit = (hour / 10) & (1 << (count - 56));
okini3939 1:63ceee4bfd05 220 } else
okini3939 1:63ceee4bfd05 221 if ((count >= 66 && count <= 77) || count == 79) {
okini3939 1:63ceee4bfd05 222 bit = 1;
okini3939 1:63ceee4bfd05 223 } else {
okini3939 1:63ceee4bfd05 224 bit = 0;
okini3939 1:63ceee4bfd05 225 }
okini3939 1:63ceee4bfd05 226
okini3939 1:63ceee4bfd05 227 count ++;
okini3939 1:63ceee4bfd05 228 if (count >= 80) {
okini3939 1:63ceee4bfd05 229 count = 0;
okini3939 1:63ceee4bfd05 230 frame ++;
okini3939 1:63ceee4bfd05 231 if (frame >= 30) {
okini3939 1:63ceee4bfd05 232 frame = 0;
okini3939 1:63ceee4bfd05 233 sec ++;
okini3939 1:63ceee4bfd05 234 if (sec >= 60) {
okini3939 1:63ceee4bfd05 235 sec = 0;
okini3939 1:63ceee4bfd05 236 min ++;
okini3939 1:63ceee4bfd05 237 if (min >= 60) {
okini3939 1:63ceee4bfd05 238 min = 0;
okini3939 1:63ceee4bfd05 239 hour ++;
okini3939 1:63ceee4bfd05 240 if (hour >= 24) {
okini3939 1:63ceee4bfd05 241 hour = 0;
okini3939 1:63ceee4bfd05 242 }
okini3939 1:63ceee4bfd05 243 }
okini3939 1:63ceee4bfd05 244 }
okini3939 1:63ceee4bfd05 245 }
okini3939 1:63ceee4bfd05 246 }
okini3939 1:63ceee4bfd05 247 }
okini3939 1:63ceee4bfd05 248
okini3939 0:8d19e2158eb4 249 int LTC_SMPTE::isReceived () {
okini3939 0:8d19e2158eb4 250 return received;
okini3939 0:8d19e2158eb4 251 }