信号発生器AD9833をRaspberry Piに接続して鳴らします。 WiringPiライブラリのSPI通信で制御します。 AD9833はAmazonで購入できる信号発生器です。 Amazonのページから仕様を抜粋すると、
下3つは実は意味がわかりません。ここでは波形発生器として使います。
AD9833のデータシートは
「プログマブル波形発生器AD9833」をご覧ください。
Arduinoで鳴らす方法は「Arduinoで信号発生器9833を鳴らす」をご覧ください。
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は1つの16ビットの制御ビットで制御されます。このうち、波形の種類を選択しているのは下の赤で囲った OPBITEN, DIV2, MODEの3つのビットです。

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

周波数を設定するためには下の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);
}
}