
CY8CKIT-059 PSOC 5LPで波形生成
投稿日 2015/07/19
PSOC 5LPの廉価ボードCY8CKIT-059で遊んでいます。
今回はトランジスタ技術2013年12月号の記事「高速DMA転送とD-Aコンバータを使った任意波形の生成」を参考にして再現してみました。
この記事では三角波を生成していますが、今回はそれに加え正弦波も生成させてみました。

波形生成のコンポーネントと配線
使用するコンポーネントは、
Clock 1MHz
DMA Direct Memory Access SRAM->VDAC8
VDAC8 電圧出力8ビットDAコンバータ 1.02V Strobe(External) High Speed
Opamp 出力バッファ
Pin 波形信号出力用 P3[6]
シールバッテリ簡易充電回路

生成した12.5KHzの正弦波
1.02Vpp
波形生成の原理は、メモリ(配列)に生成する波形のデータを予め計算で求めセットしておき、それを所定の間隔(今回は1uS)でDAコンバータに送るだけです。
配列の内容(つまりSRAMの内容)をDMA経由でDAコンバータに送り、アナログ信号に変換します。
DMAは1MHzのクロックでトリガがかかるので、1uS毎にDAコンバータに変換を要求します。
VDAC8は電圧レンジ 0 - 1.020Vで使います。この場合精度は4mV/bitとなり、変換スピードは1Mspsです。ですからこれ以上クロックの速度は上げられません。
DMAはメモリ->ペリフェラル転送モードで使います。メモリは波形データを入れた配列です。配列には波形の1周期分のデータを入れておきます。要素数は任意ですが、正弦波の生成は80ポイントとしました。1us/ポイントなので1周期80uSの正弦波です。つまり周波数は1/80us = 12.5KHzです。
DMAの設定は面倒なのでDMA Wizardを使います。PSoC CreatorのToolメニューから呼び出せます。DMA WizardでSourceをSRAM, DestinationをVDAC8_1にします。Length(配列の長さ)はsizeof(配列名)で与えます。Sourceは配列名で与えます。設定は簡単です。DMA関連部分のCコードが表示されるので、Main.cにコピペすればOKです。DMA Wizardが出力したソースコードはDMA_Initialize()にそのまま放り込んであります。(main.cの青い部分)
正弦波のデータは計算で求めておきます。エクセルで計算するのが便利です。計算はエクセルのsin()関数に角度をラジアンで渡してやるだけです。
だたしDAコンバータが8ビットなので0から255(2**8)の範囲に収まるようにします。0が128です。
1周期80ポイントとしたので、1データ当たり4.5度となります。(360 / 80 = 4.5)
SIN(RADIANS(角度0 - 355.5度 4.5ステップ)) * 127 + 128
トランジスタ技術の記事で生成している三角波は、triangle_wave[] という配列です。要素数は30まので1/30us = 33.333KHzとなります。(Clockが1MHzの場合)
正弦波のデータはsin_wave[]という配列です。こちらは要素数80です。1/80us = 12.5KHzとなります。
三角波か正弦波かはDMAの設定部分で決まります。下のmain.cでは三角波のコードはコメントアウトしてあります。(赤の部分)
波形生成はDMAでDAコンバータにデータを転送しているので、初期設定以外にはCPUは関与していません。(設定後for(;;)ループ)
以下はmain.cです。
(トランジスタ技術の記事に追加した部分は緑色で表示)
/* ========================================
*
* Copyright YOUR COMPANY, THE YEAR
* All Rights Reserved
* UNPUBLISHED, LICENSED SOFTWARE.
*
* CONFIDENTIAL AND PROPRIETARY INFORMATION
* WHICH IS THE PROPERTY OF your company.
*
* ========================================
*/
#include <device.h>
uint8 triangle_wave[] = {20, 30, 40, 50, 60, 70, 80, 90,
100, 110, 120, 130, 140, 150, 160,
170, 160, 150, 140, 130, 120, 110,
100, 90, 80, 70, 60, 50, 40, 30,};
uint8 sin_wave[] = {
128,138,148,158,167,177,186,194,203,210,
218,225,231,236,241,245,249,251,253,255,
255,255,253,251,249,245,241,236,231,225,
218,210,203,194,186,177,167,158,148,138,
128,118,108,98,89,79,70,62,53,46,
38,31,25,20,15,11,7,5,3,1,
1,1,3,5,7,11,15,20,25,31,
38,46,53,62,70,79,89,98,108,118};
void DMA_Initialize()
{
/* Variable declarations for DMA_1 */
/* Move these variable declarations to the top of the function */
uint8 DMA_1_Chan;
uint8 DMA_1_TD[1];
/* DMA Configuration 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)
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], sizeof(triangle_wave), DMA_INVALID_TD, TD_INC_SRC_ADR);
//CyDmaTdSetAddress(DMA_1_TD[0], LO16((uint32)triangle_wave), LO16((uint32)VDAC8_1_Data_PTR));
CyDmaTdSetConfiguration(DMA_1_TD[0], sizeof(sin_wave), DMA_INVALID_TD, TD_INC_SRC_ADR);
CyDmaTdSetAddress(DMA_1_TD[0], LO16((uint32)sin_wave), LO16((uint32)VDAC8_1_Data_PTR));
CyDmaChSetInitialTd(DMA_1_Chan, DMA_1_TD[0]);
CyDmaChEnable(DMA_1_Chan, 1);
}
void main()
{
/* Place your initialization/startup code here (e.g. MyInst_Start()) */
VDAC8_1_Start();
Opamp_1_Start();
DMA_Initialize();
/* CyGlobalIntEnable; */ /* Uncomment this line to enable global interrupts. */
for(;;)
{
/* Place your application code here. */
}
}
/* [] END OF FILE */
(JF1VRR)