なぜか下りカーブにノイズが乗る。
すべての下りカーブにノイズが乗っているわけではないようだが、乗るのは必ず下りカーブ。上りカーブは常にきれい。アンプに入れて耳で聞くと音が濁って聞こえる。
やっていることは、こちらのArduinoでやったことと同じ。
簡単にまとめるとこんな内容。
- タイマ・カウンタを二つ使う
- 一方で高速PWM
- もう一方で周期割込み
- 正弦波データを予め用意しておく
- 周期割込みによって正弦波データに基づいたPWMを出力する(デューティ比を変える)
- その出力をLPFに通してリプルを除去する
ATtiny202での高速PWMと周期割込みは、それぞれこちらの記事(ATtiny202とATtiny402の違いはメモリの量だけ)。
Arduino IDEでのコードはこれ。
#define N_WAVE 32 /* 正弦波テーブルの数(一周期分) */
unsigned char wave[N_WAVE]; // 正弦波テーブル
volatile unsigned char i_wave; // 正弦波テーブルの参照ポインタ
void setup() {
float unit_deg;
int i;
i_wave = 0;
/* 正弦波テーブル作成 */
unit_deg = (2.0 * 3.141592) / (float)(N_WAVE);
for (i = 0; i < N_WAVE; i++) {
wave[i] = (unsigned int)((((sin(unit_deg * (float)i) + 1.0) / 2.0) * 255.0) + 0.5);
}
/* TCA0: 正弦波出力割込み周期設定 */
takeOverTCA0();
TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm;
TCA0.SINGLE.PER = 624; // 20MHz / 625 = 32kHz → 32kHz / 32 = 1000Hz
//TCA0.SINGLE.PER = 311; // 10MHz / 312 = 32kHz → 32kHz / 32 = 1000Hz
TCA0.SINGLE.INTCTRL = TCA_SINGLE_OVF_bm;
/* TCB0: 正弦波用PWM周波数設定 */
TCB0.CTRLA = TCB_CLKSEL_CLKDIV1_gc | TCB_ENABLE_bm; // TCB0 enabled, CLK_PER/1
//TCB0.CTRLA = TCB_CLKSEL_CLKTCA_gc | TCB_ENABLE_bm; // TCB0 enabled, CLK_TCA
TCB0.CTRLB = TCB_CCMPEN_bm | TCB_CNTMODE_PWM8_gc; // Single slope PWM, CCMPEN enabled
TCB0.CCMPL = 255; // Set TOP value: 周期(PWM分解能)
//TCB0.CCMPH = 127; // Set duty cycle CCMPH/CCMPL: デューティ比
TCB0.CCMPH = 0; // 正弦波出力停止
PORTA.DIR |= PIN6_bm; // TCBによる信号出力はPA6(pin 2)に固定されている(書かなくても出力された)
}
/* 割込みハンドラ: 正弦波出力 */
ISR(TCA0_OVF_vect) {
TCB0.CCMPH = wave[i_wave];
i_wave++;
if (i_wave >= N_WAVE) {
i_wave = 0;
}
//TCA0.SINGLE.INTFLAGS = TCA_SINGLE_OVF_bm; // 割込み要求フラグ解除
}
void loop() {
}
int main() {
init();
setup();
while(1) {
loop();
}
}
Arduino IDEの環境だと裏でやっていることが影響しているのかと思って、Microchip Studio用に書き換えてみたけど、同じように下りカーブにノイズが乗った。
#include <avr/io.h>
#include <avr/cpufunc.h>
#include <avr/interrupt.h>
#include <math.h>
#define N_WAVE 32 /* 正弦波テーブルの数(一周期分) */
unsigned char wave[N_WAVE]; // 正弦波テーブル
volatile unsigned char i_wave; // 正弦波テーブルの参照ポインタ
void setup() {
float unit_deg;
int i;
i_wave = 0;
ccp_write_io((void*)&(CLKCTRL.MCLKCTRLB), 0x00); // クロックプリスケーラ禁止
/* 正弦波テーブル作成 */
unit_deg = (2.0 * 3.141592) / (float)(N_WAVE);
for (i = 0; i < N_WAVE; i++) {
wave[i] = (unsigned int)((((sin(unit_deg * (float)i) + 1.0) / 2.0) * 255.0) + 0.5);
}
/* TCA0: 正弦波出力割込み周期設定 */
//takeOverTCA0();
TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm;
TCA0.SINGLE.PER = 624; // 20MHz / 625 = 32kHz → 32kHz / 32 = 1000Hz
//TCA0.SINGLE.PER = 311; // 10MHz / 312 = 32kHz → 32kHz / 32 = 1000Hz
TCA0.SINGLE.INTCTRL = TCA_SINGLE_OVF_bm;
sei();
/* TCB0: 正弦波用PWM周波数設定 */
TCB0.CTRLA = TCB_CLKSEL_CLKDIV1_gc | TCB_ENABLE_bm; // TCB0 enabled, CLK_PER/1
//TCB0.CTRLA = TCB_CLKSEL_CLKTCA_gc | TCB_ENABLE_bm; // TCB0 enabled, CLK_TCA
TCB0.CTRLB = TCB_CCMPEN_bm | TCB_CNTMODE_PWM8_gc; // Single slope PWM, CCMPEN enabled
TCB0.CCMPL = 255; // Set TOP value: 周期(PWM分解能)
//TCB0.CCMPH = 127; // Set duty cycle CCMPH/CCMPL: デューティ比
TCB0.CCMPH = 0; // 正弦波出力停止
PORTA.DIR |= PIN6_bm; // TCBによる信号出力はPA6(pin 2)に固定されている(書かなくても出力された)
}
/* 割込みハンドラ: 正弦波出力 */
ISR(TCA0_OVF_vect) {
TCB0.CCMPH = wave[i_wave];
i_wave++;
if (i_wave >= N_WAVE) {
i_wave = 0;
}
TCA0.SINGLE.INTFLAGS = TCA_SINGLE_OVF_bm; // 割込み要求フラグ解除
}
void loop() {
}
int main() {
setup();
while(1) {
loop();
}
}
Microchip Studioでは、当初PWMの出力が13kHzくらいで悩んだ。本来なら20MHz÷256なので78kHz位になるはずで、それが13kHzってどういうことだろうかと。
あちこち調べたら、マイコン内部でクロックを6分周していることがわかった。なるほど、それで2の巾乗の関係の周波数になっていないのか。分周を禁止してやることで解決。それが「ccp_write_io((void*)&(CLKCTRL.MCLKCTRLB), 0x00);」の文。情報元はこちらの記事。
しかしノイズの原因が分からず、お手上げ状態。
この実験用にUPDIライタ(というか、インタフェース)も作った。
コメント