m2c_tn10.h、m2c_tn10_c
「m2c_tn10.h」内の #define で、GATE 出力などのピン・アサインを変更できますが、CV 出力については PB0 (1 番ピン) に固定です。
シリアル MIDI (38.4 kbps) 時の CPU クロック周波数を 7.9872 MHz に、および、レガシー MIDI (31.25 kbps) 時のクロック周波数を 6.5 MHz に設定するための OSCCAL の補正値が、それぞれ OSCCAL_ADJ_8M、OSCCAL_ADJ_6M5 です。
あるサンプル 1 個についての測定データから求めた値なので、厳密には、各個体ごとに測定を行って決定する必要があります。
他のサンプル 2 個について、そのままプログラムを書きこんで実行してみましたが、特に問題はありませんでした。
CPU クロック周波数を調整する場合には次のようにします。
CPU クロックを 512 分周したものが PWM 周波数となっているので、まず、PB0 (1 番ピン) の周波数を測って 512 倍して CPU クロック周波数を求め、目的の周波数との差を算出します。
OSCCAL の値を 1 増減すると、CPU クロック周波数は約 40 kHz 増減するので、CPU クロック周波数差を 40 kHz で割れば、OSCCAL_ADJ のおよその修正量が計算できます。
あとは、修正したプログラムを書いてみて、クロック周波数を再測定し、精度が十分でなければ、数値の微調整、再書き込み、再測定を必要なだけ繰り返します。
/*************************************************/ /* m2c_tn10.h : MIDI to CV converter */ /* for ATtiny10 */ /* */ /* 2012/01/16 : Created by pcm1723 */ /*************************************************/ #ifndef _M2C_TN10_H_ #define _M2C_TN10_H_ // uncomment following '#define' // to use GATE output as UART DEBUG output //#define UART_DEBUG // Synth CV output port bit assign (PWM DAC) #define CV_BIT (PORTB0) // Synth GATE output port bit assign #define GATE_BIT (PORTB1) // MIDI RxD input port bit assign #define RXD_BIT (PORTB2) // serial MIDI / legacy MIDI sense input port bit assign #define SENS_BIT (PORTB1) // Synth GATE delay queue length (1..16) // in terms of Timer0 OVerFlow count // at 15.625 kHz (serial MIDI) // 12.695 kHz (legacy MIDI) rate // 16 / 15.625 [kHz] = 1.024 [ms] #define GATE_QUE_LEN (16) // // OSCCAL byte adjustment value @ 5 V // for serial MIDI (38.4 kbps) // for 7.9872 MHz CPU clock // #define OSCCAL_ADJ_8M (0x9E - 0x98) // // OSCCAL byte adjustment value @ 5 V // for (legacy) MIDI (31.25 kbps) // for 6.5 MHz CPU clock // #define OSCCAL_ADJ_6M5 (0x78 - 0x98) #endif
/*************************************************/ /* m2c_tn10.c : MIDI to CV converter */ /* for ATtiny10 */ /* */ /* 2012/01/16 : Created by pcm1723 */ /*************************************************/ #include <avr/io.h> #include <avr/interrupt.h> #include "m2c_tn10.h" #include "sw_uart_rx.h" #include "mididec.h" #include "midifunc.h" typedef union tag_u16_u8_union_t { uint16_t u16; uint8_t u8[2]; } u16_u8_union_t; void tn10_port_setup( void ) { // set serial MIDI / legacy MIDI SENS input DDRB &= ~(_BV(SENS_BIT)); // input mode PUEB |= _BV(SENS_BIT); // enable pull up // wait a while to stabilize port input ch_prop[0].MD_bend_range = 0xff; MD_ch = 255; do { calc_pitch(0); // dummy call to spent time } while (0 != (--MD_ch)); if (_BV(SENS_BIT) & PINB) { // SENS input == 'H' // add OSCCAL offset for 8 MHz (serial MIDI, 38.4 kbps) CCP = 0xD8; // set protection signature OSCCAL += OSCCAL_ADJ_8M; // add OSCCAL offset for 8 MHz } // if if (0 == (_BV(SENS_BIT) & PINB)) { // SENS input == 'L' // add OSCCAL offset for 6.5 MHz (legacy MIDI, 31.25 kbps) CCP = 0xD8; // set protection signature OSCCAL += OSCCAL_ADJ_6M5; // add OSCCAL offset for 6.5 MHz } // if (_BV(CV_BIT) ... // set clock prescaler to 1/1 (8 MHz clock) CCP = 0xD8; // set protection signature CLKPSR = 0; // clock prescale = 1/1 (8 MHz clock) // disable pull up for SENS port PUEB &= ~(_BV(SENS_BIT)); // setup PWM (fs = 31.25 kHz @ 8 MHz, fs = 12.695 kHz @ 6.5 MHz) // timer mode = 9 bit Fast PWM (WGM0[3:0] = 0110) TCCR0A = _BV(WGM01); // WGM01:WGM00 = 10 TCCR0B = (_BV(WGM02) // WGM03:WGM02 = 01 |_BV(CS00)); // CS02:CS00 = 001 (clk/1) // set compare output mode to set at BOTTOM TCCR0A |= _BV(COM0A1); // COM0A1:COM0A0 = 10 DDRB |= (_BV(DDB0) // set OC0A (pin 1) to output (PWM-CV) |_BV(GATE_BIT)); // set PB1 (pin 3) to output (GATE) OCR0A = 0x00; // TIMSK0 = _BV (TOIE0); // timer overflow interrupt enable tn10_sw_uart_setup(); // software UART setup sei(); // enable global interrupt flag } // void tn10_port_setup() int main() { cli(); // disable interrupt SP = RAMEND; // re-initialize SP to save SRAM tn10_port_setup(); // hardware and software setup GM_reset(); for (;;) { // infinite loop if (_BV(sw_RXC) & uart_flag) { // UART Rx ready? uart_flag &= ~(_BV(sw_RXC)); // clear UART flag if (0x80 & uart_rx_buf) { // MIDI status byte mididec(uart_rx_buf); // decode MIDI status byte } else { // MIDI data byte MD_data = uart_rx_buf; // received data if (md_data_byte()) { // process data byte md_cc_func(); // process Control Change } // if (md_data_byte()) { ... } // if(0x80 & ... } // if (_BV(sw_RXC) ... if (_BV(TOV0) & TIFR0) { // Timer0 OVerFlow detected? TIFR0 |= _BV(TOV0); // clear TOV0 flag #if !defined(UART_DEBUG) if ((1 << (16-GATE_QUE_LEN)) & unit_prop[0].gate_que) { GATE_ON; } else { GATE_OFF; } // if ((1 << (16-GATE_QUE_LEN)) & unit_prop[0].gate_que) #endif unit_prop[0].gate_que >>= 1; } // if (_BV(TOV0) & TIFR0) { ... } // for (;;) } // int main()