2016年1月18日月曜日

PSoC 5LPでI2Sのテスト TDA1543編 サイン波を出力

この間やった実験の出力がおかしかった原因はいろいろあった。

ソースコード

#include <project.h>  
   
 #define TABLE_LENGTH 128  
   
 /* Defines for DMA_1 */  
 #define DMA_1_BYTES_PER_BURST 1  
 #define DMA_1_REQUEST_PER_BURST 1  
 #define DMA_1_SRC_BASE (CYDEV_SRAM_BASE)  
 #define DMA_1_DST_BASE (CYDEV_PERIPH_BASE)  
   
 /* Variable declarations for DMA_1 */  
 /* Move these variable declarations to the top of the function */  
 uint8 DMA_1_Chan;  
 uint8 DMA_1_TD[1];  
   
 int8 sineTable[TABLE_LENGTH*2];  
   
 const uint8 sineTable8[TABLE_LENGTH] =   
 {  
     128, 134, 140, 147, 153, 159, 165, 171,  
     177, 183, 188, 194, 199, 204, 209, 214,  
     218, 223, 227, 231, 234, 238, 241, 244,  
     246, 248, 250, 252, 253, 254, 255, 255,  
     255, 255, 255, 254, 253, 252, 250, 248,  
     246, 244, 241, 238, 234, 231, 227, 223,  
     218, 214, 209, 204, 199, 194, 188, 183,   
     177, 171, 165, 159, 153, 147, 140, 134,   
     128, 122, 115, 109, 103, 97, 91, 85,  
      79, 73, 68, 62, 57, 52, 47, 42,  
      37, 33, 29, 25, 22, 18, 15, 12,  
      10,  7,  6,  4,  2,  1,  1,  0,  
      0,  0,  1,  1,  2,  4,  6,  7,  
      10, 12, 15, 18, 22, 25, 29, 33,  
      37, 42, 47, 52, 57, 62, 68, 73,  
      79, 85, 91, 97, 103, 109, 115, 122  
 };       
   
 int main()  
 {  
   int i;  
   
   // 符号付き16bit sineTableの生成  
   for (i = 0; i < TABLE_LENGTH; i++) {  
     sineTable[i*2]  = (int)sineTable8[i] - 128;  
     sineTable[i*2+1] = 0;  
   }  
     
   CyGlobalIntEnable; /* Enable global interrupts. */  
   
   /* Place your initialization/startup code here (e.g. MyInst_Start()) */  
     
   I2S_1_Start();  
   
   /* DMA Configuration for DMA_1 */  
   DMA_1_Chan = DMA_1_DmaInitialize(DMA_1_BYTES_PER_BURST, DMA_1_REQUEST_PER_BURST,   
     HI16(DMA_1_SRC_BASE), HI16(DMA_1_DST_BASE));  
   DMA_1_TD[0] = CyDmaTdAllocate();  
   CyDmaTdSetConfiguration(DMA_1_TD[0], (TABLE_LENGTH*2), DMA_1_TD[0], TD_INC_SRC_ADR);  
   CyDmaTdSetAddress(DMA_1_TD[0], LO16((uint32)sineTable), LO16((uint32)I2S_1_TX_CH0_F0_PTR));  
   CyDmaChSetInitialTd(DMA_1_Chan, DMA_1_TD[0]);  
   CyDmaChEnable(DMA_1_Chan, 1);  
   
   while(0u != (I2S_1_ReadTxStatus() & I2S_1_TX_FIFO_0_NOT_FULL))  
   {  
     /* Wait for TxDMA to fill Tx FIFO */  
   }  
   CyDelayUs(1);  
     
   I2S_1_EnableTx();  
   
   for(;;)  
   {  
     /* Place your application code here. */  
   }  
 }  
   
 /* [] END OF FILE */  
   


DMAの設定

16bitデータなので1度に2Byte送るつもりで「DMA_1_BYTES_PER_BURST」を2に設定していたが、よくわからないので1に戻した。要求1回で1度に1Byte送る。「DMA Wizard」ではDestinationをI2Sコンポーネントに設定すると「Byptes per Burst:」の項が1しか選択できなくなるのでこういう仕様なんだろう。

I2Sのデータは符号付き

WindowsのWavフォーマットも16bitPCMは符号付きだが、TDA1543の受け取るデータも符号付きらしい。サイン波形の配列がたまたま符号なし8bitのものしかなかったので(作るのがめんどくさい)プログラムで
// 符号付き16bit sineTableの生成
for (i = 0; i < TABLE_LENGTH; i++) {
sineTable[i*2]   = (int)sineTable8[i] - 128;
sineTable[i*2+1] = 0;
}
として符号付き16bitのデータを作った。

インターリーブなので左右のチャンネルで代わりばんこにデータが送られる。

I-V変換

配線

抵抗一本で電流電圧変換しているが、ここの抵抗値を決めるのがなかなか難しい。値を変えて出力波形を見てみた。

2.2kΩ

上側がつぶれている

1.5kΩ

上下とも少しずつつぶれている。

1.2kΩ

下側がつぶれている。

上側のつぶれは電源電圧を上げれば改善された。PSoC 5LPは5.5VまでなのでTDA1543のVDDだけ自作の電流/電圧計付可変両電源を使って電源電圧を上げてみた。

I/V変換用抵抗:2kΩ
電源電圧:5.51V

電源電圧:6.00V

電源電圧:6.49V

電源電圧:6.99V

2kΩの抵抗だとVDD:6V程度でフルスケール出力できるようだ。

電圧を変更しても消費電流は43mA程度だった。

拡大

2kΩだとまだ下側つぶれているようなのでもう少し抵抗値を上げたほうがよさそうだ。

周波数のチェック

今回はI2Sコンポーネントに12MHzのクロックを入力したので、I2Sのクロックは1/2の6MHzになる。16bitの2chなのでサンプルリング周波数は
6MHz / (16 * 2) = 187.5kHz
サンプルデータの周期は128/2=64なので
187.5kHz / 64 ≒ 2.93kHz
オシロでの計測値も2.9kHz程度になっているのでこれでだいたいOK。

メモ:

TDA1543の7PinはVrefとなっていて電圧を測ると2.13V程度。波形の中点としてはちょっとずれてる?(オシロの計測値だと3.35V程度)1.5kΩの抵抗を入れているが、このRを取り去ると波形が出力されなくなる。

音楽の再生ではなくてDDSで波形を生成するならサンプリング周波数はきっちり48kHzとか96kHzにしなくてもいい?安定度を上げるためには外付けの水晶を使う必要はありそう。

TDA1543である程度ファンクションジェネレータとしてテストしてみてからDACをPCM5102Aに変更

Github
https://github.com/ryood/TDA1543