f 9833 by Pico

Raspberry Pi Zeroで信号発生器9833を鳴らす

信号発生器AD9833をRaspberry Piに接続して鳴らします。 WiringPiライブラリのSPI通信で制御します。 AD9833はAmazonで購入できる信号発生器です。 Amazonのページから仕様を抜粋すると、

  1. AD9833は、周波数0 - 12.5MHzの正弦波、三角波、方形波信号を生成することができるプログラマブル波形発生器です。
  2. 調整が容易で、クロッククロックは25MHz、精度は0.1Hz、クロック周波数は1MHz、精度は最大0.004Hzです。
  3. 周波数励起/波形生成。液体、ガス流量測定。
  4. センシングアプリケーション - 近似、スポーツ、欠陥検出
  5. 線形損失、線形減衰、試験装置、スキャンクロックジェネレータ

下3つは実は意味がわかりません。ここでは波形発生器として使います。

AD9833のデータシートは 「プログマブル波形発生器AD9833」をご覧ください。
Arduinoで鳴らす方法は「Arduinoで信号発生器9833を鳴らす」をご覧ください。
Raspberry Piの初期設定は「Raspberry Piの初期設定」 をご覧ください。

Raspberry Piを接続する

+5VとGround、さらに3本のSPIに関わる信号線をつなぎます。MOSIは接続しません。 波形出力にノイズが乗っていたのでフィルターを入れています。また、出力は0V-5VでしたのでDCをカットするようにしています。

  RaspberryPi   : AD9833
  GPIO11 : SCK  : SCLK
  GPIO9  : MOSO : No Connection
  GPIO10 : MOSI : SDATA
  GPIO8  : CE0  : FSYNC
AD9833

AD9833


波形の種類と周波数の設定

AD9833は1つの16ビットの制御ビットで制御されます。このうち、波形の種類を選択しているのは下の赤で囲った OPBITEN, DIV2, MODEの3つのビットです。

AD9833

正弦波は0x0000, 三角波は0x0002、矩形波は0x0020と設定します。 下の表ではDACデータのMSB/2DACデータのMSBと書かれている欄は矩形波を表しています。 DACデータのMSB/2DACデータのMSBの違いは周期が異なります。 DACデータのMSB/2は周期が倍、すなわち周波数が1/2になります。通常はDACデータのMSBを使えば良いと思います。

AD9833

周波数を設定するためには下のsetFrequencyに書いたように、 制御ビットのB28を1にし、その後、周波数を2ワードで送信します。 下のプログラムでは、calcFreqで周波数(Hz)から周波数の32ビットのレジスタの値に変換しています。 32ビットで表された周波数は16ビットの2ワード、MSB/LSBの順で送信します。

16ビットのデータをSPI通信で送信する場合は、spiSendに示しているようにMSB/LSBの順で送信します。

サンプルプログラム

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <wiringPiSPI.h>
    
#define AD_MCLK   25000000UL    ///< Clock speed of the AD9833 reference clock in Hz
#define AD_2POW28 (1UL << 28)   ///< Used when calculating output frequency
 
// 波形選択レジスター
#define	MODE_OFF	0x00c0
#define	MODE_SINE	0x0000
#define	MODE_SQ1	0x0028
#define	MODE_SQ2	0x0020
#define	MODE_TRNG	0x0002
// 周波数を設定
#define SEL_FREQ0 0x2000

enum shape_t{
  SP_OFF=0,
  SP_SINE,
  SP_SQ1,
  SP_SQ2,
  SP_TRYG,
  SP_NUM
};

uint16_t mSHAPE[SP_NUM]={
  MODE_OFF,
  MODE_SINE,
  MODE_SQ1,
  MODE_SQ2,
  MODE_TRNG,
};
    
// 周波数(Hz)からAD9833のレジスターの値に変換
uint32_t calcFreq(float f) 
{ 
  return (uint32_t)((f * AD_2POW28/AD_MCLK) + 0.5);
}
    
uint16_t calcPhase(float a) 
// 位相(deg)からAD9833のレジスターの値に変換
{
  return (uint16_t)((512.0 * (a/10) / 45) + 0.5);
}
    
// 1wordをAD9833へ送る(MSB First)
void spiSend(uint16_t reg)
{
  unsigned char buf[2];
  buf[0] = (unsigned char)(reg>>8);   //MSB`
  buf[1] = (unsigned char)(reg&0xFF); //LSB
  wiringPiSPIDataRW(0,buf,2);
}
    
// n wordをAD9833へ送る(MSB First)
void spiSendn(uint16_t *reg, uint16_t n)
{
  unsigned char *buf=(unsigned char*)malloc(n*sizeof(uint16_t));
  for(uint16_t i=0; i<n; i++){
    buf[i*2]   = (unsigned char)(reg[i]>>8);    //MSB
    buf[i*2+1] = (unsigned char)(reg[i]&0xFF);  //LSB
  }
  wiringPiSPIDataRW(0,buf,n*sizeof(uint16_t));
}

//波形の形状
//周波数(Hz)を設定する
void setFrequency(uint16_t shape,float freq)
{
  uint32_t _regFreq = calcFreq(freq);
  uint16_t reg[3];
  reg[0]=(SEL_FREQ0 | mSHAPE[shape]);
  reg[1]=(0x4000 | (uint16_t)(_regFreq & 0x3fff));          //LSB
  reg[2]=(0x4000 | (uint16_t)((_regFreq >> 14) & 0x3fff));  //MSB
  printf("%04x\n",reg[0]);
  spiSendn(reg,3);
}

void delay(unsigned milliseconds)
{
  clock_t pause;
  clock_t start;
  pause = milliseconds * (CLOCKS_PER_SEC / 1000);
  start = clock();
  while( (clock() - start) < pause );
}
    
int main()
{
	wiringPiSPISetup(0, 500000);
  delay(100);
  spiSend(0x0100);
  delay(100);
  spiSend(MODE_OFF);  //OFF
  delay(1000);

  while(1){
    setFrequency(SP_SINE,200);
    delay(5000);

    setFrequency(SP_SQ1,100);
    delay(5000);

    setFrequency(SP_SQ2,50);
    delay(5000);

    setFrequency(SP_TRYG,100);
    delay(5000);
  }
}