写真1 AD9833 DDS MSOP 0.5ピッチ 変換基板に乗せる

 

それはさておき、

 

このチップは10ピンのMSOPで、写真にようにピンセットの先ほどの大きさです。

 

変換基板に取り付けましたが、ピンのピッチは0.5なので、半田付けにはちょっと技術が必要です。

 

まずチップをゲルタイプの瞬間接着剤で正確な位置に仮止めしておきます。

 

フラックスをほんのわずか塗って、すべてのピンにわざとまたがるくらい半田を盛ります。

 

半田吸い取り線で、余分な半田を吸い取って、出来上がり。

 

慣れれば簡単ですが、最初は数個パーにする覚悟がいります(笑)。

 

このDDSは、マスタクロック(MCLK)周波数は最高25MHzで、その場合最高発振周波数(ナイキスト周波数)は12.5MHzとなり、分解能は0.1Hzです。

 

今回は手持ち部品の関係で、20MHzのクリスタルを使用したので、10MHzまでのプログラマブルオシレータとして、実験してみました。この場合の分解能は約0.075Hzです。

STM32F4 Discovery デジタル・フィルターEQ

投稿日 2014/04/17

トランジスタ技術 2014年1月号の記事「7バンド・ゲイン調整可能 ワンボードUSBオーディオ・アンプ」を少し改造してみました。

 

この記事はSTM社が無償で提供しているUSBオーディオのデモ・プログラムを改造し、IIRデジタル・フィルターで7つのピーキング・フィルターを組み込んで、イコライザーを構成したものです。7つのフィルターの特性は、スライドボリュームで変えられるようになっています。

 

ピーキング・フィルターは、特定の周波数成分を強調するフィルターです。

 

記事のソフトはCQ出版社からダウンロードできます。

 

独自のフィルターを組み込んだりする改造が容易なように、筆者がスライド・ボリュームを無効にできるようにしてくれていますし、フィルター関連の変更も容易なように考慮してくれています。

STM32F4_Discovery_filter1.jpg

写真:STM32F4 Discoveryにデジタル・フィルターで構成したイコライザー

 

今回の改造点

 

①イコライザーのフィルター係数をスライドボリュームを使わずに、プログラム設定にする。
②I2C LCDで現在のイコライザ設定を表示する。

 

開発環境はKEILのuVision4を使用しました。


 

①イコライザーのフィルター係数をスライドボリュームを使わずに、プログラム設定にする。
 

 

スライド・ボリュームを用意するのは結構面倒ですので、STM32F4 Discoveryボードに標準で搭載されているユーザ・ボタンを押すたびに、イコライザー・モードをNORMAL, JAZZ, POPULAR, CLASSICを順に切り替えられるようにしました。

 

記事のプログラムでは、STM32F4のADコンバータの読み込み値(スライド・ボリュームの電圧値)に変化があったら、対応する周波数のイコライザー・レベルを変更するようにしていますが、それらを機能しないように、projectのOption for project xxxxxx のC/C++タブにあるPreprocessor SymbolsのDefineに"DISABLE_SLIDER"を追加して、スライド・ボリュームの機能を停止させておく必要があります。

STM32F4_Discovery_filter2.jpg

写真: Option for targetのPreprocessor SysmbolsのDefineに"DISABLE_SLIDER"を追加

 

あとはmain.cにすこし変更と追加を加えるだけです。

 

(注:各イコライザー・モードのレベル設定は、効果がはっきりわかるように適当に設定してあります.
たとえばJAZZは極端な高音強調になっていますが、これでジャズが聴きやすいという訳ではありません。)

 

NORMALは以下のようにレベルは中点で、すべての周波数がフラットです。

 

set_coeff(15, 15, 15, 15, 15, 15, 15);

 

set_coeff()の最初の引数から6400Hz, 3200Hz, 1600Hz, 800Hz, 400Hz, 200Hz, 100Hzです。
0が最低レベル、31が最高レベルです。

 

今回は、音量の設定はパソコン側で変えられるので、プログラムの音量関連には変更を加えていません。(記事では音量用のスライド・ボリュームで変えられるようになっています。)


 

②I2C LCDで現在のイコライザ設定を表示する。
 

 

I2C LCDは、記事「STM32F4 DiscoveryにI2C LCDをつなぐ」で動作確認しておきました。

 

トランジスタ技術の記事のプログラムは、STMのデモプログラムで標準提供されているstm32f4_discovery_audio_codec.c(STM32F4 Discoveryに搭載されているCODECの制御用関数郡です)でI2CとそのGPIOを初期化しているので、LCDをつなぐに当たっては初期化する必要がありません。このためすぐにLCDを初期化(Init_LCD())することから始めています。(I2C_LCD_Configuration()をコールする必要はありません。)ただし、Init_LCD()をコールするのは、WavePlayBack()の後になります。

 

I2C LCDはACM1602N1を使用しました。3.3VのI2Cタイプです。SCLはSTM32F4 DiscoveryボードのPB6、SDAはPB9につないでおきます。 抵抗によるプルアップは不要です。


 

〇コンパイルと実行
 

 

KEIL uVision4でコンパイルしました。

 

プログラムを実行すると、イコライザー・モードはNORMALで始まります。USERボタン(青)を押すたびにJAZZ, POPULAR, CLASSIC, NORMALと順に変わります。

 

イコライザーを実現しているピーキング・フィルターの周波数特性が変更され、特定の周波数が強調されるため、聴いた感じが明確に違うのがわかります。まったくノイズがなくクリアな音です。

 

youtubeなどで音楽を聴くほか、WaveGene等でピュアな信号を発生させて聞いてみるのも面白いと思います。

 

なお、実行中はLD6(BLUE)のLEDが点滅します。


 

〇変更、追加点
 

 

・main.cを変更する(LCDの初期化、while(1)ループの中でボタン監視とフィルター切り替え、set_coeff()の追加など

 

・Preprocessor SymbolsのDefineに"DISABLE_SLIDER"を追加(KEILのproject option)

 

・drv_i2c_lcd.cの追加(I2C LCD制御)


 

〇ソース・コード
 

 

LCD用のDelay_ms()はfor分による簡易な遅延処理をしています。
オーディオの再生はDMAで行われているため、while(1)内の処理は影響ありません。
ボタンが押されたときの判定は簡易的なものなので、チャタリングの影響が出ることがあります。
各イコライザー・モードのフィルター・レベルの設定は実験用です。NORMALは中点でフラット特性にしてあります。


 

■main.cの一部 (STM社のデモプログラムを変更したトランジスタ技術の記事にさらに変更を加えた)

 

/********************************************************************************

  • @file Audio_playback_and_record/src/main.c 

  • @author MCD Application Team

  • @version V1.0.0

  • @date 28-October-2011

  • @brief Main program body

  • ******************************************************************************

  • @attention

  •  

  • THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS

  • WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE

  • TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY

  • DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING

  • FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE

  • CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.

  •  

  • <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>


  •  

/* Includes ------------------------------------------------------------------*/
#include "main.h"

 

/** @addtogroup STM32F4-Discovery_Audio_Player_Recorder

  • @{


  •  

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
USB_OTG_CORE_HANDLE USB_OTG_dev;

 

RCC_ClocksTypeDef RCC_Clocks;
__IO uint8_t RepeatState = 0;
__IO uint16_t CCR_Val = 16826;
extern __IO uint8_t LED_Toggle;

 

static USBD_Usr_cb_TypeDef USR_cb;
extern USBD_DEVICE USR_desc;

 

#define EQ_TYPE 0
#define EQ_NORMAL 1
#define EQ_JAZZ 2
#define EQ_POPULAR 3
#define EQ_CLASSIC 4

 

/* Private function prototypes -----------------------------------------------*/
static void TIM_LED_Config(void);
/* Private functions ---------------------------------------------------------*/

 

extern void drvAD_startAd( void (*cbk)(short adCh, short val ) ); 
void ad_callback( short adCh, short val ) ;
void I2C_LCD_Configuration(void);
void Init_LCD(void);
void LCD_write(unsigned char xpos, unsigned char ypos, char* ptr);
void LCD_clear(void);
void Delay_ms(int);
void AdChanged( short adCh, short val );
void set_coeff(short, short, short, short, short, short, short);

 

/**

  • @brief Main program.

  • @param None

  • @retval None

*/
int main(void)
{
int eq_type;

/* Initialize LEDS */
STM_EVAL_LEDInit(LED3);
STM_EVAL_LEDInit(LED4);
STM_EVAL_LEDInit(LED5);
STM_EVAL_LEDInit(LED6);

/* Green Led On: start of application */
STM_EVAL_LEDOn(LED4);


STM_EVAL_PBInit(BUTTON_USER, BUTTON_MODE_GPIO);
 

/* SysTick end of count event each 10ms */
RCC_GetClocksFreq(&RCC_Clocks);
SysTick_Config(RCC_Clocks.HCLK_Frequency / 100);

/* Configure TIM4 Peripheral to manage LEDs lighting */
TIM_LED_Config();

 

/* Initialize the repeat status */
RepeatState = 0;
LED_Toggle = 7;

WavePlayBack(I2S_AudioFreq_48k); 

Init_LCD();

LCD_write(0, 0, "STM32F4 D.Filter" );
LCD_write(0, 1, "EQ: " );

 

/* Init Host Library */
// USB DAC Start
USBD_Init( &USB_OTG_dev, USB_OTG_FS_CORE_ID, &USR_desc, &AUDIO_cb, &USR_cb );

Delay_ms(500);
eq_type = EQ_NORMAL;
LCD_write(4, 1, "NORMAL " );
set_coeff(15, 15, 15, 15, 15, 15, 15);
while (1)
{
if(STM_EVAL_PBGetState(BUTTON_USER) == 1) {
eq_type++;
if(eq_type > EQ_CLASSIC) eq_type = EQ_NORMAL;
switch (eq_type) {
case EQ_NORMAL:

LCD_write(4, 1, "NORMAL " ); set_coeff(15, 15, 15, 15, 15, 15, 15);
break;

case EQ_JAZZ:

LCD_write(4, 1, "JAZZ " );
set_coeff(31, 31, 31, 0, 0, 0, 0);
break;

case EQ_POPULAR:

LCD_write(4, 1, "POPULAR " );
set_coeff(0, 0, 31, 0, 0, 0, 0);
break;

case EQ_CLASSIC:

LCD_write(4, 1, "CLASSIC " );
set_coeff(0, 0, 0, 0, 0, 31, 0);
break;

default:

LCD_write(4, 1, "NORMAL " );
set_coeff(15, 15, 15, 15, 15, 15, 15);
break;

}
}
Delay_ms(100);
}
}

 

void set_coeff(short lv64, short lv32, short lv16, short lv8, short lv4, short lv2, short lv1) {

AdChanged( 0, lv64 * 4); //6400Hz
AdChanged( 1, lv32 * 4); //3200Hz
AdChanged( 2, lv16 * 4); //1600Hz
AdChanged( 3, lv8 * 4); //800Hz
AdChanged( 4, lv4 * 4); //400Hz
AdChanged( 5, lv2 * 4); //200Hz
AdChanged( 6, lv1 * 4); //100Hz

}

 

/**

  • @brief Configures the TIM Peripheral for Led toggling.

  • @param None

  • @retval None

  • /

static void TIM_LED_Config(void)
...

 

以下省略


 

■drv_i2c_lcd.c (新しく追加した)

 

#include "main.h"

 

void I2c_LCD_IOCtl(unsigned char, unsigned char);
void Init_LCD(void);
void LCD_position(unsigned char xpos, unsigned char ypos);
void LCD_write(unsigned char xpos, unsigned char ypos, char* ptr);
void LCD_clear(void);
void LCD_str(unsigned char* ptr);
void Delay_ms(int);

 

void I2c_LCD_IOCtl(unsigned char command, unsigned char data)
{
I2C_GenerateSTART(I2C1, ENABLE); //Send START Condition
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

I2C_Send7bitAddress(I2C1, 0xA0, I2C_Direction_Transmitter); //Send Slave Address on write mode
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

I2C_SendData(I2C1, command); //Send command
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

 

I2C_SendData(I2C1, data); //Send data
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

I2C_GenerateSTOP(I2C1, ENABLE); //Send STOP Condition
}

//I2C LCD ACM1602N1

void Init_LCD(void)
{
Delay_ms(100);
I2c_LCD_IOCtl(0x00, 0x30);
Delay_ms(5);
I2c_LCD_IOCtl(0x00, 0x30);
Delay_ms(1);
I2c_LCD_IOCtl(0x00, 0x30);
Delay_ms(1);
I2c_LCD_IOCtl(0x00, 0x38);
Delay_ms(1);
I2c_LCD_IOCtl(0x00, 0x08);
Delay_ms(1);
I2c_LCD_IOCtl(0x00, 0x01);
Delay_ms(1);
I2c_LCD_IOCtl(0x00, 0x06);
Delay_ms(1);
I2c_LCD_IOCtl(0x00, 0x0C);
Delay_ms(1);

}

 

const int lcd_adrbase[2] = { 0x80, 0xC0 };

 

void LCD_position(unsigned char xpos, unsigned char ypos)
{

I2c_LCD_IOCtl(0x00, lcd_adrbase[ypos] + xpos );

}


 

void LCD_write(unsigned char xpos, unsigned char ypos, char* ptr)
{
LCD_position(xpos, ypos);
while(*ptr != 0x00)
{

I2c_LCD_IOCtl(0x80, *ptr++);

}
}


 

void LCD_clear(void)
{

I2c_LCD_IOCtl(0x00, 0x01);
Delay_ms(10);

}

 

void LCD_str(unsigned char* ptr)
{

while(*ptr != 0) I2c_LCD_IOCtl(0x80, *ptr++);

}

 

void Delay_ms(int nTime)
{
int i, j;

for(i = 0; i < nTime; i++) {
for(j = 0; j < 42000; j++){

;

}
}
}




 

(JF1VRR)