PR

ATtiny202で正弦波を作ったらノイズが入る

なぜか下りカーブにノイズが乗る。

すべての下りカーブにノイズが乗っているわけではないようだが、乗るのは必ず下りカーブ。上りカーブは常にきれい。アンプに入れて耳で聞くと音が濁って聞こえる。

やっていることは、こちらの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);」の文。情報元はこちらの記事。

上の図は、TB3214から引用。

しかしノイズの原因が分からず、お手上げ状態。


この実験用にUPDIライタ(というか、インタフェース)も作った。


コメント