SDカードのWAVE音声をPWMで出力する、というのをLPC11U35でmbedの開発システムを利用して行いました。音声は8bit/16k/monoです。PWMは192kHzで、16kのひとコマに12周期はいる感じです。mbedで同様のことをやっている例がたくさんありましたのですんなりできると思ったのですが、結果として盛大なノイズがでてしまいました。いわゆるヒスノイズのようなものではなくブツブツという明らかに異常なノイズです。
オシロで観察したところ、たまにPWMの波形が間延びしているところがあってこれがノイズになっているようでした。調べたところ、LPC11U35にはPWMのマッチレジスタにシャドーレジスタというものがなく、デューティを書き換えるタイミングによってはH->Lの切り替えを逃してしまい1区間フラットな信号がでてしまうのが原因とのことでした。今までそんなことは気にしたこともなかったのですがたまたま「良い」マイコンを使っていたのかもしれません。
対策としてデューティ書き換え時にPWMのカウンタをチェックして0にリセットされるのを待ってから書き換えるように変更しました。一応これで音はきれいになりました。
それと、音声用とは別にTickerの割り込みを使っていたのですが、この対策を入れた途端になぜか割り込みがまったくかからなくなりました。試行錯誤の末、2つの割り込みのタイミングを調整して長いほうを短いほうの定数倍の数値にするとどういうわけかちゃんと動くようになりました。
#include "mbed.h" #include "SDFileSystem.h" SDFileSystem sd(P0_9, P0_8, P0_10, P0_11, "sd"); Ticker flipper; Ticker flipper2; //SD file FILE *fp; int result, ret; #define bufSize 128 uint8_t BufferA[bufSize]; uint8_t BufferB[bufSize]; int Flag, SDFlag; unsigned int ptr, ptrA, ptrB; void flip() { //audio while(LPC_CT16B1->TC!=0){} //<-これが対策行 if(Flag == 0){ LPC_CT16B1->MR0 = BufferA[ptrA]; ptrA++; if(ptrA >= bufSize){ Flag = 1; SDFlag = 1; ptrA = 0; } }else { LPC_CT16B1->MR0 = BufferB[ptrB]; ptrB++; if(ptrB >= bufSize){ Flag = 0; SDFlag = 1; ptrB = 0; } } } void flip2() { } int main() { flipper2.attach_us(&flip2, 434); //434(flip2)は62(flip)の定数倍 //PWM SETTINGS LPC_SYSCON->SYSAHBCLKCTRL |= (1<<8); LPC_IOCON->PIO0_21 = 1; LPC_CT16B1->MCR = 1<<10; //reset on MR3 LPC_CT16B1->MR0 = 0; //duty LPC_CT16B1->MR3 = 248; //period LPC_CT16B1->PR = 1; LPC_CT16B1->PWMC |= (1<<0); LPC_CT16B1->TCR = 1; fp = fopen("/sd/sample.wav","r"); while(1) { if(fp == NULL) { //return -1; }else{ Flag = 0; SDFlag = 0; ret = fread(BufferA, 1, bufSize, fp); //ptrA = Chunk(BufferA); ptrB = 0; SDFlag = 1; flipper.attach_us(&flip, 62); } if(SDFlag){ SDFlag = 0; if(Flag == 0){ ret = fread(BufferB, 1, bufSize, fp); ptrB = 0; }else{ ret = fread(BufferA, 1, bufSize, fp); ptrA = 0; } if(ret == 0){ fclose(fp); SDFlag = 0; ce = 1; flipper.detach(); } } } }