ブレッドボード配線図
デバッグ情報表示用にキャラクタ液晶を接続している。P2[6:0]。
80MHz駆動するために、20MHzの水晶と22pFのCを接続。水晶をつなぐPinは固定で、P15[0]、P15[1]。
MCP4922はSPIの信号線を割り当てた。SCK P12[0]、MOSI P12[2]、CS P12[3]。
処理タイミングを計測するPinを割り当てた。P0[0]。
内蔵DACの出力はP3[0]。
内蔵DAC(VDAC8)
TopDesign
PSoC 5LPの内蔵DACはVDAC8というコンポーネントを使う。8bit精度。VDAC8の出力は弱いのでOPAMP(Follower)で増強する。
<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 "project.h" #include <stdio.h> #include <math.h> #define TITLE_STR1 ("VDAC Test") #define TITLE_STR2 ("20170723") #define PI (3.141592653589793238462) #define AMPLITUDE (1.0) // x * 3.3V #define PHASE (PI * 1) // 2*pi is one period #define RANGE (0x7FFF) #define OFFSET (0x7FFF) // Configuration for wave output #define BUFFER_SIZE (360) uint16_t buffer_sine[BUFFER_SIZE]; char strBuffer[80]; // Create the wave buffer void calculate_sinewave(void){ for (int i = 0; i < BUFFER_SIZE; i++) { double rads = (PI * i)/180.0; // Convert degree in radian buffer_sine[i] = (uint16_t)(AMPLITUDE * (RANGE * (sin(rads + PHASE))) + OFFSET); } } int main(void) { uint8_t cnt = 0; CyGlobalIntEnable; /* Enable global interrupts. */ /* Place your initialization/startup code here (e.g. MyInst_Start()) */ LCD_Char_Start(); UART_Start(); VDAC8_1_Start(); Opamp_1_Start(); LCD_Char_PrintString(TITLE_STR1); LCD_Char_Position(1, 0); LCD_Char_PrintString(TITLE_STR2); sprintf(strBuffer, "\r\n%s %s\r\n", TITLE_STR1, TITLE_STR2); UART_PutString(strBuffer); calculate_sinewave(); for(;;) { /* Place your application code here. */ for (int i = 0; i < BUFFER_SIZE; i++) { Pin_Check1_Write(1); VDAC8_1_SetValue(buffer_sine[i] >> 8); Pin_Check1_Write(0); } cnt++; } } /* [] END OF FILE */
プログラムはNucleo F303で試したものとほぼおなじ処理で、事前にサイン波テーブルを生成しておいて、値を連続してDACに出力している。
DACに出力する前後でPin_Check1をH/Lさせているので、Highの時間を見れば処理に要した時間がわかる。
浮動小数点演算を行う場合、math libraryをリンクする必要がある。
メニューのProjectから[Build Setting...]を選択。ダイアログでコマンドラインオプションに「-lm」を設定する。
MCP4922
TopDesign
<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 "project.h" #include <stdio.h> #include <math.h> #define TITLE_STR1 ("MCP4922 Test") #define TITLE_STR2 ("20170723") #define PI (3.141592653589793238462) #define AMPLITUDE (1.0) // x * 3.3V #define PHASE (PI * 1) // 2*pi is one period #define RANGE (0x7FFF) #define OFFSET (0x7FFF) // Configuration for wave output #define BUFFER_SIZE (360) uint16_t buffer_sine[BUFFER_SIZE]; char strBuffer[80]; // Create the wave buffer void calculate_sinewave(void){ for (int i = 0; i < BUFFER_SIZE; i++) { double rads = (PI * i)/180.0; // Convert degree in radian buffer_sine[i] = (uint16_t)(AMPLITUDE * (RANGE * (sin(rads + PHASE))) + OFFSET); } } // Write to MCP4922 // v: 0..4096 void MCP4922_write_u16(uint16 v) { SPIM_WriteTxData((v >> 8) | 0x30); SPIM_WriteTxData(v & 0xff); while (! (SPIM_ReadTxStatus() & SPIM_STS_SPI_DONE)) ; } int main(void) { CyGlobalIntEnable; /* Enable global interrupts. */ /* Place your initialization/startup code here (e.g. MyInst_Start()) */ LCD_Start(); SPIM_Start(); UART_Start(); LCD_Position(0u,0u); LCD_PrintString(TITLE_STR1); LCD_Position(1u,0u); LCD_PrintString(TITLE_STR2); sprintf(strBuffer, "%s %s \r\n", TITLE_STR1, TITLE_STR2); UART_PutString(strBuffer); CyDelay(1000u); //LCD_ClearDisplay(); calculate_sinewave(); /* for (int i = 0; i < BUFFER_SIZE; i++) { sprintf(strBuffer, "%u\r\n", buffer_sine[i]); UART_PutString(strBuffer); } UART_PutString("Dump end\r\n"); */ for(;;) { for (int i = 0; i < BUFFER_SIZE; i++) { Pin_Check1_Write(1); MCP4922_write_u16(buffer_sine[i] >> 4); Pin_Check1_Write(0); } //CyDelay(1); } } /* [] END OF FILE */
処理時間の比較
VDAC8
ch2:Pin_Check1の出力
周波数は1.702MHzで1ループは約587.5ns。
DAC出力の処理時間は350.0ns
MCP4922
ch2:Pin_Check1の出力
周波数は491.0kHzで1ループは約2037ns。
DAC出力の処理時間は1800ns
DAC | LOOP(ns) | DAC(ns) | LOOP-DAC |
---|---|---|---|
VDAC8 | 587.5 | 350.0 | 237.5 |
MCP4922 | 2037 | 1800 | 237 |
PSoC 5LPはCoretex-M3でCortex-M4のNucleo F446と比較すると、
Nucleo F446の内蔵DAC(12bit精度)は700nsだったので、PSoC 5LPの内蔵DACは8bit精度ではあるが処理が速い。
SPI接続のMCP4922はNucleo F446でSPIクロックが22.44MHzのとき6.74us(6740ns)だったので、こちらもかなり速い。
PSoC Creatorはグラフィカルで使い易いが、ネイティブなので高速なコードを生成してくれるようだ。
出力波形
VDAC8サイン波の周波数:4.726kHz
MCP4922
サイン波の周波数:1.336kHz
WaveSpectraで測定
VDAC8MCP4922
周波数が違うので単純に比較はできないが、VDAC8は高調波歪がはっきり出ている。
MCP4922のSPI信号
SCK : MOSI
ch1:MOSI ch2:SCK
SPI Masterコンポーネントのクロックに40MHzを入れているがSCKは8.676MHzになっている。
SCK : CS
ch1:CS ch2:SCK
CSがアクティブ(L)の区間は目盛りから読み取って約840ns。1周期は約2026nsでPin_Check1で測定した周期とほぼ同じ。
Github:
VDAC8
https://github.com/ryood/PSoC-Creator-4.1-Test/tree/master/VDAC_Test.cydsn
MCP4922
https://github.com/ryood/PSoC-Creator-4.1-Test/tree/master/MCP4922_Test.cydsn
<追記:2017.07.26>
SCKを拡大して測定し直したら、20MHzだった。
ch1:SCK ch2:CS
8.676MHzになっている画像も、SCKは200ns×4マス=800nsで16クロックなので
800ns / 16clk = 50ns
1 / 50ns = 20MHz
になり、たまたま少ない周波数が表示されていただけだと思う。
また、SPI Masterコンポーネントに「Enable High Speed Mode」というプロパティがあり、これをチェックしない場合最大クロック9MHz、チェックすると最大クロック18MHzまで対応する。
←したがって、SCK 20MHzは仕様外。
</追記>
0 件のコメント:
コメントを投稿