DDS-Signalgenerator per USB
von M. Dittrich
Einleitung
Wer kennt es nicht: eine Simulation bringt schönste Ergebnisse und der Testaufbau zeigt starke Abweichungen. Solche Probleme könnte man umgehen, wenn man frühzeitig an realen Bauteilen testen könnte. Ein Signalgenerator wäre das Werkzeug der Wahl! Der Trend elektrischer Geräte geht mehr und mehr in Richtung USB. So laufen moderne Logic Analyzer genau wie moderne Messgeräte über USB. Lösung ist ein DDS, dies steht für Direct Digital Synthesis und ist ein Verfahren zur Erzeugung periodischer Signale. Dies kann sowohl ein Sinus-, Dreieck- oder Rechtecksignal sein. Nimmt man nun noch einen PWM-Kanal dazu, so hat man wirklich alles Wünschenswerte an Signalen parat.
Dieses Projekt beschreibt, wie man sich einen qualitativ sehr hochwertigen Signalgenerator für unter 25€ selbst zusammenbauen kann.
Mehr zum Thema DDS findet ihr hier.
Wer jetzt noch der Meinung ist, ein digitaler Signalgenerator sollte auch Protokolle wie I2C oder SPI ausgeben können, der darf gerne weiterlesen! Es gibt eine Extended Edition, welche dies unterstützt. Preislich kommen dann noch eine Platine und ein paar Bauteile für ca. 25€ dazu.
Hardware
Die verwendete Hardware besteht aus einem Infineon XMC2Go und einem AD9833 Modul.
XMC2Go
Die von Infineon entwickelte Hardware basiert auf dem XMC1100 32-bit ARM® Cortex™-M0 Prozessor:
- 32MHz CPU
- 64k Flash
- 16k RAM
- On-Board J-Link Debugger
Besonders von Bedeutung ist das XMC4200 Debug IC. Dies erlaubt uns, Breakpoints im Programm zu definieren, wodurch ein stückweises Abarbeiten des Programmablaufs ermöglicht wird. Es ist dabei möglich, zwischen jedem Schritt die Werte von Variablen zu beobachten und somit Fehler im Programmcode schnell zu entdecken.
AD9833
Der von Analog Devices entwickelte Chip hat folgende Eckdaten:
- 25MHz Clock
- 28bit Resolution
- 2,3V to 5,5V Power supply
- 12,65mW Power consumption at 3V
In diesem Projekt können damit Frequenzen bis zu 10MHz generiert werden. Man sollte noch erwähnen, dass bei der Umrechnung nach Integer Rundungsfehler auftreten. Ein Beispiel:
- [math]\displaystyle{ \frac{2^{28\;bit}}{25\cdot 10^6\;Hz}=10,73741824s }[/math]
Gerundet ergibt dies 11, jedoch als Integer nur 10! Dieses Beispiel sollte zeigen, dass es nicht immer möglich ist, die Frequenz exakt vorzugeben.
GPIO
Das Kürzel GPIO steht für General Purpose Input/Output und kennzeichnet Pins, welche man wahlweise als Ein- oder Ausgang konfigurieren kann. Das XMC2Go hat 14 Ports, die diverse Funktionen übernehmen können. Welche genau das sind, sieht man hier. In diesem Projekt werden die folgenden Pins verwendet:
- T1 = P0.6
- LED1 = P1.0
- LED2 = P1.1
Mehr dazu und zu den folgenden Punkten findet ihr im XMC2Go Users Manual.
PWM
Das Kürzel PWM steht für Pulse-Width Modulation und beschreibt ein Rechtecksignal mit einstellbarem Tastverhältnis (engl. Duty Cycle). Zum Betrieb dieses Moduls werden lediglich die Frequenz und das Tastverhältnis angegeben. In diesem Projekt wird der folgende Pin verwendet:
- PWM = P0.5
Auf die Programmierung des Moduls wird später genauer eingegangen.
SPI
Das Kürzel SPI steht für Serial Peripheral Interface und beschreibt ein Modul zur seriellen Datenübertragung. Zum Betrieb dieses Moduls werden maximal 4 GPIO Pins benötigt:
- SDI/MISO = P0.6
- SDO/MOSI = P0.7
- CLK/SCLK = P0.8
- CS/SS/FSYNC = P0.9
Man unterscheidet jedoch zwischen Vollduplex, Halbduplex und Simplex. Wenn Daten nur in der Richtung XMC -> AD9833 gesendet werden sollen, spricht man auch von MTSR, also Master Transmit Slave Receive. Dies wird dann als Simplex-Kommunikation beschrieben und benötigt lediglich die SDO, CLK und CS Pins des XMC. Halbduplex beschreibt den Fall, dass man wechselweise senden oder empfangen kann. Vollduplex bedeutet gleichzeitiges Senden und Empfangen. Hierbei benötigt man die SDI, SDO, CLK und CS Pins des XMC. Mehr dazu findet Ihr hier.
UART
Das UART Modul ist anfangs sehr komplex, es erweist sich jedoch als sehr nützlich. Wenn man die interne USB <-> UART Bridge verwenden möchte, konfiguriert man wie folgt:
- Tx = P2.1
- Rx = P2.2
Man beachte, dass diese Pins auf dem XMC2Go nicht herausgeführt wurden! Nach Inbetriebnahme kann man mit beliebigen Terminal-Programmen mit dem XMC kommunizieren. Ich empfehle hierzu HTerm.
Extended Edition
Vorteil der Extended Edition sind nicht nur die zusätzlichen Funktionen, sondern auch ein schickes Gehäuse. Jedoch reicht in diesem Fall der Hardwareumfang des XMC2Go nicht mehr ganz aus. Die Begründung, warum zusätzliche Hardware vonnöten ist, ist einfach: Der XMC2Go verfügt nur über zwei USIC Channel. Einer wird für die Kommunikation über UART reserviert, der andere für die Kommunikation über SPI. Dies ist aber keineswegs schlecht, weil sowieso ein Kurzschlußschutz der GPIO Pins benötigt wird! Diese Fähigkeit sowie die Spannungsfestigkeit bis 5V aller GPIO's bringt der SC18IS600 Chip mit sich.
Zusammengefasst liefert die Erweiterung folgende Schnittstellen:
- PWM out
- AD in
- GPIO in/out
- SPI in/out
- I2C in/out
Das erweitert die Einsetzbarkeit dieses Werkzeugs enorm!
NXP SC18IS600 Chip
Bei diesem IC handelt es sich um einen SPI-zu-I2C-Umsetzer. Desweiteren ergänzt dieser Chip ein vorhandenes System um sechs GPIO Pins, von denen zwei quasi-bidirectional arbeiten können.
Software
Als Entwicklungsumgebung bietet Infineon DAVE3 an. Der Vorteil dieser IDE ist eine grafische Benutzeroberfläche. Diese bietet vorgefertigte Apps, quasi Templates, zur schnellen Initialisierung verschiedenster Module.
App Connectivity
Frequency Calculation
/*/ Calculation of the 28bit stream /*/
long CalcFreqValue(uint32_t hz) {
uint64_t temp;
uint32_t freq;
temp = hz*(pow(2,28)/25e6);
freq = temp;
return freq;
}
Phase Calculation
/*/ Calculation of the 14bit stream /*/
int CalcPhaseValue(uint32_t deg) {
uint32_t phase;
phase = deg*(pow(2,11)/180);
return phase;
}
UART Communication
/*/ If data received via UART /*/
if((USIC0_CH0->TRBSR & 0x00000008) == 0) {
bool stop_bit = 0;
uint8_t cnt = 0;
uint8_t pos = 0;
/*/ Turn on LED1 to show there are incoming data /*/
LED(1, 1);
/*/ Clear all Arrays to avoid Errors /*/
bzero(&Buffer, sizeof(Buffer));
bzero(&Freq, sizeof(Freq));
bzero(&Phase, sizeof(Phase));
bzero(&Value, sizeof(Value));
/*/ Store FIFO data into Buffer[0...n] /*/
while(!stop_bit) {
Buffer[pos] = (USIC0_CH0->OUTR & 0x0000FFFF);
if(Buffer[pos] == '\0')
stop_bit = 1;
pos++;
}
.
.
.
}
SPI Communication
/*/ Clear status flags /*/
void SPI001_Clear() {
SPI001_ClearFlag(&SPI001_Handle0,SPI001_RECV_IND_FLAG);
SPI001_ClearFlag(&SPI001_Handle0,SPI001_ALT_RECV_IND_FLAG);
}
/*/ Wait until data has been sent /*/
void SPI001_WaitForOK() {
uint8_t Status1 = 0;
uint8_t Status2 = 0;
do {
Status1 = SPI001_GetFlagStatus(&SPI001_Handle0,SPI001_RECV_IND_FLAG);
Status2 = SPI001_GetFlagStatus(&SPI001_Handle0,SPI001_ALT_RECV_IND_FLAG);
} while(!((Status1 == SPI001_SET) || (Status2 == SPI001_SET)));
}
/*/ Shifting 2x 14bit /*/
Data[1] = (CalcFreqValue(DesiredFreq) & 0x3FFF) + 0x4000;
Data[2] = (CalcFreqValue(DesiredFreq) >> 14) + 0x4000;
/*/ Shifting 12bit /*/
Data[5] = (CalcPhaseValue(DesiredPhase) & 0x3FFF) + 0xC000;
/*/ Send data to Chip /*/
SPI001_Clear();
EnableStartOfFrame(SPI001_Handle0);
for(int i=0; i<sizeof(Data)/sizeof(Data[0]); i++) {
SPI001_WriteData(&SPI001_Handle0,&Data[i],SPI001_STANDARD);
}
SPI001_WaitForOK();
EnableEndOfFrame(SPI001_Handle0);
Special GPIO Pins
This is a user defined Area. You can write any kind of code inside this Prototype or leave it blank if it's not used.
In this case, the <io:***> Parameter is unused.
Example: <io:255> gives the following
uint8_t Special[] = {2, 5, 5, \0}
Testing with HTerm
For first Tests we can use HTerm. Take advantage of the following settings:
- 115200 Baud
- 8 Data bits
- 1 Stop bit
- Parity: none
Example ASC-Command: s,f:2000000,p:180,io:63 <NULL on Enter>
Or the same in short form: s,2000000,180,63 <NULL on Enter>
Result: Sine Wave, 2MHz, 180° Phase shift, 6-bit special GPIO register
Windows Application
Die Software wurde in Microsoft® VisualStudio C# programmiert und ist auch als Sourcecode im Downloadbereich zu finden. Es wurde während der Programmierung besonders auf ein sauberes Exception Handling geachtet, um Programmabstürze zu verhindern.
Die Special GPIO Version gibt dem Nachbauer außerdem die Möglichkeit, seinen eigenen Code auf einfache Weise zu ergänzen, um z.B. Ausgänge zu schalten, welche weitere Funktionen triggern uvm.
Fertigung
Die Fertigung der Einzelteile beschränkt sich auf die Extended Edition, da nur für diese Version externe Hardware benötigt wird. Daher kann dieser Schritt für den Bau der Basic Edition übersprungen werden.
Leiterplatte
Die Platine wurde in Eagle entworfen. Diese beinhaltet einen 1AD8368 VGA/AGC amplifier und einen 1SC18IS600 IO-Interface Chip.
1optional
Gehäuse
Bei dem Gehäuse habe ich mich, passend zum Wettbewerb, an ein 3D-gedrucktes Teil aus ABS gehalten. Dieses wurde mir netterweise von Claudio H. (siehe Beitrag) angefertigt. Entworfen wurde das Gehäuse in SolidWorks. Dabei wurde auch die Montagefähigkeit überprüft, da die Platine schräg eingeklappt wird. Die STL-Dateien findet man ebenfalls im Downloadbereich.
Bilder zum Projekt
Downloads
XMC2Go Sourcecode (basic, newest)
XMControl Sourcecode (basic, newest)
XMControl GUI v1.1.2 (basic)
XMControl GUI v1.0.4 (basic)
Eagle CAD-Daten v1.2 (extended)
Gehäuse STL-Daten (extended)
Weblinks
http://de.wikipedia.org/wiki/Direct_Digital_Synthesis
http://de.wikipedia.org/wiki/Serial_Peripheral_Interface
http://de.wikipedia.org/wiki/Duplex
http://de.wikipedia.org/wiki/Kippschwingung
http://de.wikipedia.org/wiki/Pulsweitenmodulation
http://www.infineonforums.com/forums/8-XMC-Forum