引き続き、MSP430 プログラミングの学習。良く判らないまま適当に書いたプログラムをあちこちいじったりして少しずつ理解を進めている…つもりなのだけれど、これがなかなか難しい。オルゴールプログラムはその後4声に発展させてみたが、いくつか難関が残っている。
こうしてみると改めて、ChaN さん(ELM)の WaveTable 電子オルゴールは凄いと思う。
それはさておき、MSP430 基板関連情報の Wiki を始めました。今のところ、主に hamayan さんに書いていただいてます。そちらもよろしく。
[2007.02.05]
プログラミングが進まないので中途のままコードを公開。DAC0 から正弦波によるメロディを出力するサンプル。試行錯誤の残骸やコメントの嘘もそのまま。エンベロープが使えなくなったため、デュレーション固定で誤魔化している。ツッコミどころ満載。
こちらはシーケンスデータ(menuet.h)。#include "msp430x42x0.h" // wave table - 64 point #define BASEFREQ 512 // 32KHz 割り込みの場合 #define WAVTBLMASK 0x3f const signed char wav_tbl[] = { 0, 11, 23, 34, 45, 55, 65, 74, 82, 89, 95, 100, 104, 107, 109, 110, 110, 109, 107, 104, 100, 95, 90, 83, 76, 68, 59, 50, 41, 31, 21, 10, 0, -10, -21, -31, -41, -50, -59, -68, -76, -83, -90, -95,-100,-104,-107,-109, -110,-110,-109,-107,-104,-100, -95, -89, -82, -74, -65, -55, -45, -34, -23, -11, }; // envelope table - 256 points - 役に立っていない const unsigned char env_tbl[] = { 255, 252, 250, 247, 245, 243, 240, 238, 235, 233, 231, 228, 226, 224, 222, 219, 217, 215, 213, 211, 209, 207, 205, 203, 201, 199, 197, 195, 193, 191, 189, 187, 185, 183, 182, 180, 178, 176, 174, 173, 171, 169, 168, 166, 164, 163, 161, 159, 158, 156, 155, 153, 152, 150, 149, 147, 146, 144, 143, 141, 140, 139, 137, 136, 134, 133, 132, 130, 129, 128, 127, 125, 124, 123, 122, 120, 119, 118, 117, 116, 115, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 87, 86, 85, 84, 83, 82, 82, 81, 80, 79, 78, 78, 77, 76, 75, 75, 74, 73, 72, 72, 71, 70, 69, 69, 68, 67, 67, 66, 65, 65, 64, 64, 63, 62, 62, 61, 60, 60, 59, 59, 58, 57, 57, 56, 56, 55, 55, 54, 54, 53, 53, 52, 51, 51, 50, 50, 49, 49, 48, 48, 48, 47, 47, 46, 46, 45, 45, 44, 44, 43, 43, 43, 42, 42, 41, 40, 40, 39, 39, 38, 38, 37, 37, 36, 35, 35, 34, 34, 33, 33, 32, 31, 31, 30, 30, 29, 29, 28, 28, 27, 26, 26, 25, 25, 24, 24, 23, 22, 22, 21, 21, 20, 20, 19, 19, 18, 17, 17, 16, 16, 15, 15, 14, 13, 13, 12, 12, 11, 11, 10, 10, 9, 8, 8, 7, 7, 6, 6, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, }; // note-freq table - 48 points const unsigned int frq_tbl[] = { // A B C D E F G 220, 233, 247, 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 493, 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988,1047,1109,1175,1245,1319,1397,1480,1568,1661, 1760,1865,1976,2093,2217,2349,2489,2637,2794,2960,3136,3322, 3520,3729,3951,4186,4435,4699,4978,5274 }; enum PITCH_NAME { A2=0,B2,H2,C2,Cis2,D2,Dis2,E2,F2,Fis2,G2,Gis2, A3,B3,H3,C3,Cis3,D3,Dis3,E3,F3,Fis3,G3,Gis3, A4,B4,H4,C4,Cis4,D4,Dis4,E4,F4,Fis4,G4,Gis4, A5,B5,H5,C5,Cis5,D5,Dis5,E5,F5,Fis5,G5,Gis5, A6,B6,H6,C6,Cis6,D6,Dis6,E6 }; typedef struct _Note { signed int frq; // frequency - 0: none signed int bh; // for bresenham unsigned char wi; // wav_tbl offset unsigned char env; // env_tbl offset } Note; #define DUPLEX 4 #define DUPMASK 0x03 #define EON 0x80 // End of Notes flag #define EOS 0xff // End of Score #include "menuet.h" // sequence data Note notes[DUPLEX]; // note data unsigned char *melp; unsigned int tick; unsigned int tick_next; unsigned char tickn; unsigned char nidx; // index to next note data: 0..3 void init_seq(void); int get_mel(void); int main(void) { WDTCTL = WDTPW + WDTHOLD; // WDTの停止 SCFQCTL = 128 - 1; // MCLK = 128 * ACLK * 2 = 8.39MHz, D = 2 FLL_CTL0 = DCOPLUS + XCAP18PF; // DCOPLUS = 1, 水晶容量負荷は18pF SCFI0 = FLLD_2 + FN_2; // D = 2, fDCOCLK = 2.2-17Mhz // DAC 設定 DAC12_0CTL = DAC12OPS + DAC12SREF_0 + DAC12LSEL_0 + DAC12AMP_7 + DAC12IR; // // DAC出力を外部端子に出力, 基準電圧はAVcc, DAC12_0DATを書込むと即DAC出力 // DAC出力の最大値は基準電圧, アンプは高速(高電流)モード init_seq(); get_mel(); // Timer A 16KHz CCR0 = 512; // 256 で 32KHz CCTL0 = CCIE; TACTL = TASSEL_2 + MC_1; // SMCLK, up-mode _BIS_SR(LPM0_bits + GIE); // LPM0に入る, 周辺モジュール割込み許可 return 0; } void init_seq(void) { // init note table for (nidx = 0; nidx < DUPLEX; nidx++) { Note *n = ¬es[nidx]; n->frq = 0; // none n->bh = 0; n->wi = 0; n->env = 0; } nidx = 0; melp = (unsigned char*)&mel_tbl[0]; tick = 0; tick_next = *melp++; tick_next += (*melp++ << 8); tickn = 0; } int get_mel(void) { unsigned char eon; unsigned char note; Note *np; if (tick != tick_next) return 0; nidx = 0; while (1) { if (*melp == EOS) init_seq(); eon = *melp & EON; note = *melp & ~EON; melp++; np = &(notes[nidx++]); nidx &= DUPMASK; np->frq = frq_tbl[note]; np->bh = 0; np->wi = 0; np->env = 0; if (eon) break; } tick_next = *melp++; tick_next += (*melp++ << 8); return 0; } // Basic Timer 割込みサービスルーチン #pragma vector=TIMERA0_VECTOR __interrupt void BasicTimer (void) { signed int n4; signed int n; int i; n4 = 0; for (i = 0; i < DUPLEX; i++) { if (notes[i].frq == 0) continue; if (notes[i].env == 255) { notes[i].frq = 0; // 消音 continue; } n = wav_tbl[notes[i].wi]; // envelope を適用すると処理が間に合わない。 // n = n * env_tbl[notes[i].env] >> 8; // 255.0; n4 += n; notes[i].bh += notes[i].frq; while (notes[i].bh >= BASEFREQ) { notes[i].bh -= BASEFREQ; (notes[i].wi)++; notes[i].wi &= WAVTBLMASK; // 64 point } } n4 += 2048; if (n4 > 4095) n4 = 4095; else if (n4 < 0) n4 = 0; DAC12_0DAT = n4; tickn++; // tickn &= 0x7f; if (!(tickn & 0x3f)) { for (int i = 0; i < DUPLEX; i++) { if (notes[i].frq) notes[i].env++; } tickn &= 0x7f; if (!tickn) { tick++; get_mel(); } } }
上記ふたつのソースコードをまとめたものは sample.zip として置きました。 ついでに Intel-Standard 形式の実行ファイル sound.hex も。// Bach Menuet const unsigned char mel_tbl[] = { 0, 0, B5, G2|EON, 60, 0, A5|EON, 120, 0, G4|EON, 180, 0, A5, F2|EON, 240, 0, D4|EON, 44, 1, D4|EON, 104, 1, G4, Dis2|EON, 164, 1, G3|EON, 194, 1, A4|EON, 224, 1, B4|EON, 254, 1, C4|EON, 28, 2, D2, D4|EON, // // 途中省略 // 128, 22, EOS, };
[2007.02.07] セルフ・ツッコミ。
そろそろこのネタは切り上げて、計測アプリケーションのほうを試そうか知らん。
Posted by masato at 11:18 PMおそらく携帯電話等からは投稿できません。日本語文字列を含まないコメントやトラックバック、および当サイトへの言及を含まないトラックバックは御遠慮いただいております。また、90日以上経過した記事へのコメントはできません。