Forum: Mikrocontroller und Digitale Elektronik MSP430 MSP430F2013 SPI Kommunikation mit D/A-Wandler


von Martin S. (martinsattler)


Angehängte Dateien:

Lesenswert?

Liebe Forengemeinde,

ich versuche mit dem MSP430F2013 den 12-Bit-D/A-Wandler MAX5530 per SPI 
anzusprechen und eine per Software einstellbare Spannung ausgeben. Wenn 
das einmal funktioniert füge ich noch einen A/D-Wandler AD7787 hinzu. 
Hardwaremäßig habe ich die Bauteile wie folgt zusammengeschlossen:

P1.0: Hier ist eine LED angeschlossen, die bei High-Pegel leuchtet
P1.1: CS-Ausgang für AD7787 = CS2 (Chip wird vorerst nicht benützt)
P1.2: CS-Ausgang für MAX5530 = CS3
P1.5: SCLK
P1.6: MOSI
P1.7: MISO (wird später für AD7787 benötigt, nicht für MAX5530)

Mein momentaner Quellcode ist im Anhang beigefügt. Ich stelle darin 
einige Parameter ein und möchte dann den Binärcode 1111 1000 0000 0000 
an den MAX5530 senden. Die vordersten 4 Bits stellen die Funktionsweise 
des Wandlers ein und die hinteren 12 Bits stellen die Spannung ein.

Am Ausgang des MAX5530 kann ich aber nach Ablauf des Programms keine 
Spannung messen. Die CS3-Leitung funktioniert und die MOSI-Leitung 
befindet sich nach dem Befehl
USICTL0 |= USIPE7 + USIPE6 + USIPE5 + USIMST + USIOE;
auf High-Pegel und nach dem Befehl USICNT = 16; wieder auf Low-Pegel. 
Sonst passiert leider nichts.

Laut meiner Entwicklungsumgebung "IAR Embedded Workbench" befinden sich 
nach Ablauf des Programms folgende Werte in den USI-Registern:

USICTL0=0xEA
USICTL1=0x01
USICKCTL=0x48
USICNT=0x40
USISR=0xF800

Wisst ihr vielleicht, warums nicht funktioniert? Fehlt noch ein Befehl 
zum Senden des USISR-Registers? Evtl. denkbar wäre natürlich auch, dass 
ich den MAX5530 beim Löten zerstört habe.

Würde mich sehr freuen, wenn mir jemand helfen kann.

Martin

von Martin S. (martinsattler)


Lesenswert?

Mir ist jetzt noch aufgefallen, dass sich das USICNT-Register nach dem 
Befehl USICNT = 16; nicht verändert hat. Das könnte der Fehler sein. 
Auch mit USICNT  = 0x10; ändert sich das Register nicht.

Gibts irgendeine Sperre, die den Schreibzugriff auf das Register 
verhindert?

von Michael (Gast)


Lesenswert?

Ich vermute mal, dass es an deiner Initialisierung der USI Schnittstelle 
liegt. Normalerweise wird der Befehl
USICTL0 &= ~USISWRST;                     // USI released for operation

als allerletztes ausgeführt. Du intialisierst aber Teile der USI noch 
nach diesem Befehl.

Viele Grüße
Michael

von Martin S. (martinsattler)


Lesenswert?

Danke für Deine Antwort. Hat ein bisschen weitergeholfen:

Ich habe jetzt USICTL0 &= ~USISWRST; erst ausgeführt, nachdem ich USICNT 
beschrieben habe.

Jetzt bringt der Befehl USICNT = 16; das gewünschte Ergebnis: Im 
USICNT-Register wird das USICNT4-Bit gesetzt. Allerdings wird dieses Bit 
nach dem Ausführen von USICTL0 &= ~USISWRST; wieder gelöscht. Das sollte 
ja denke ich nicht so sein. Der Wandler funktioniert auch noch nicht.

von Michael (Gast)


Lesenswert?

Was mir gerade noch auffällt ist, dass du gar nicht die SPI Funktion bei 
den Portpins aktivierst (P1SEL Register). Am Besten schau dir mal die 
Code Examples von TI an, da ist die Konfiguration der ganzen 
Peripheriemodule sehr gut beschrieben.

von Martin S. (martinsattler)


Angehängte Dateien:

Lesenswert?

Ich hab jetzt nach den P1OUT-Befehlen noch die Zeile
P1SEL |= BIT5 + BIT6 + BIT7;
hinzugefügt. Damit werden zwar die entsprechenden Bits gesetzt aber das 
Programm funktioniert nicht besser.

Die TI Code Examples aus SLAC080 hab ich mir angeschaut. Bei den 
dortigen SPI-Beispielen wird P1SEL nicht benützt (siehe Anhang)

von Michael (Gast)


Lesenswert?

Hmm...okay, dann hatte ich das falsch in Erinnerung mit den P1SEL Bits. 
Was mir ncoh auffällt, du setzt das Selectbit sofort wieder zurück, 
nachdem du deine Daten in den Sendebuffer geschrieben hast. Evtl. 
solltest du solange warten, bis der Sendevorgang auch abgeschlossen ist.

von Martin S. (martinsattler)


Lesenswert?

Danke für den Hinweis mit dem CS-Bit. Das war falsch. Ich hab jetzt vor 
dem Zurücksetzen noch eine Schleife eingebaut, mit der ich das USI-Flag 
abfrage:
while (!(USICTL1 & USIIFG)) {}

Das war zwar auch ein Fehler, es funktioniert aber immer noch nicht. 
Also muss noch was falsch sein.

von Martin S. (martinsattler)


Lesenswert?

Inzwischen hab ich herausgefunden, wie das Senden funktioniert:
1
#include <msp430x20x3.h>
2
3
void v_out(void);
4
5
void main(void)
6
{
7
  WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog Timer
8
9
  P1OUT |= BIT1 + BIT2;
10
  P1OUT &= ~BIT0;
11
  P1DIR |= BIT0 + BIT1 + BIT2;
12
  
13
  USICTL0 |= USIPE7 + USIPE6 + USIPE5 + USIMST + USIOE; // Port, SPI Master
14
  USICTL1 |= USICKPH + USIIE;               // Counter interrupt, flag
15
                                            //   remains set
16
  USICKCTL = USIDIV_2 + USISSEL_2;          // /4 SMCLK
17
  USICNT = 16;                              // init-load counter
18
  USICNT |= USI16B;                         // 16-bit-transmission
19
  USICTL0 &= ~USISWRST;                     // USI released for operation
20
  
21
  while (1)                                 // Loop
22
  {
23
    unsigned i;
24
    for (i = 0x0FFF; i > 0; i--);           // Delay
25
    v_out();
26
  }
27
}
28
29
30
void v_out(void)
31
{
32
/*   //send 2 times 8 bits
33
  P1OUT &= ~BIT2;                         // Enable MAX5530
34
  
35
  USICNT = 8;                             // re-load counter
36
  USISRL = 0xF4;
37
  while (!(USIIFG & USICTL1));            // Counter clear?
38
  
39
  USICNT = 8;                             // re-load counter
40
  USISRL = 0x00;
41
  while (!(USIIFG & USICTL1));            // Counter clear?
42
*/
43
     //send 1 time 16 bits 
44
  USICTL0 |= USISWRST;                    // USI stopped
45
  USICNT = 16;                            // re-load counter
46
  USICNT |= USI16B;
47
  
48
  P1OUT &= ~BIT2;                         // Enable MAX5530
49
  USICTL0 &= ~USISWRST;                   // USI released for operation
50
  USISR = 0xF400;
51
  while (!(USIIFG & USICTL1));            // Counter clear?
52
53
  P1OUT |= BIT2;                          // Disable MAX5530
54
}

von Christian R. (supachris)


Lesenswert?

Wieso initialisierst du vor jedem Senden die SPI neu? Musst du meines 
Wissens nicht, jedenfalls bei den MSP430F1xx nicht.

Empfangen geschieht gleichzeitig, wie ich eben in dem anderen Thread 
schrieb. Nachdem du 8 Bits heraus gesendet hast, hast die 8 Bits, die 
der DA Wandler VOR dem Start der Übertragung zur Verfügung gestellt hat, 
im Empfangspuffer.

von Martin S. (martinsattler)


Lesenswert?

Danke für den Tipp, dass Senden und Empfangen gleichzeitig geht.. So hab 
ichs dann schließlich hinbekommen.

von Christoph Beyer (Gast)


Lesenswert?

Hallo Martin und alle Forenmitglieder!
Ich arbeite mich auch in den MSP430F2013 ein und will über das SPI einen 
DigitalUpconverter programmieren(also erst mal ein paar Register 
beschreiben
und auslesen) Vom Prinzip her ist es ähnlich wie bei deinem DA Wandler.
Hast du mittlerweile ein lauffähiges Programm, was die korrekte 
Initialisierung und Sende/Empfangsvorgänge darstellt. Das könnte mir 
helfen, ich versuche auch die Flagbedeutungen richtig zu verstehen, die 
TI Programme helfen mir nur bedingt. Vielleicht kannst du mal deine 
neueste Version hier posten! Danke

von Martin S. (martinsattler)


Angehängte Dateien:

Lesenswert?

Servus Christoph,

im Anhang findest du ein funktionierendes Programm (habs grad nochmal 
getestet). Zuerst wird die SPI-Schnittstelle initialisiert, dann wird 8 
Mal die Spannung an einem A/D-Wandler eingelesen, der Wert gemittelt und 
der gleiche Spannungswert am D/A-Wandler ausgegeben.

Das Programm war für mich ein Test, ob meine Wandler und meine 
SPI-Befehle funktionieren. Ich hoffe, es hilft dir weiter.

Gruß
Martin

von Christoph B. (beyarea)


Lesenswert?

Hi!
Danke für dein Programm, hat mir auf jeden Fall geholfen.
Ich hätte da noch ne Frage zum Empfangen von Daten( deine v_in())
Also wenn man ein Byte empfangen will, muss man erst vorher senden!?
Was ist das 0x38, was du versendest, die Info an den AD Wandler, welches 
Register er auslesen soll?
Und was ist genau die Aktion, die festlegt, dass man etwas empfangen 
will?
(muss man immer USISR = 0xFFFF  setzen? ). Sonst würde man ja bei jedem 
Senden auch etwas empfangen.
Danke für deine Hilfe!

Gruß

Christoph

von Martin S. (martinsattler)


Lesenswert?

Servus

Ja, wenn man empfangen will, muss man immer zuerst senden. Wenn das 
Senden erledigt ist, befinden sich die empfangen Bits automatisch wieder 
im USISR Register.

Das 0x38 ist spezifisch für den AD7790. Das wird in sein configuration 
register geschrieben, damit er weiß, dass ich als nächstes den 
gewandelten Wert auslesen will. Steht so im Datenblatt.

Wenn ich das 0x38 sende stehen am Ende des Sende-Vorgangs tatsächlich 
empfangene Bits im USISR. Das sind bei diesem Wandler die Bits des 
Status Registers. Weil mich die aber nicht interessieren, lese ich das 
USISR nicht aus, sondern überschreibe einfach das USISR mit 0xFFFF. Laut 
Datenblatt muss nämlich mein MOSI-Pin High-Pegel besitzen (also muss der 
MSP 16 mal eine Eins senden), wenn ich das Daten-Register mit dem 
gewandelten Wert lesen will.

Gruß
Martin

von Christoph B. (beyarea)


Lesenswert?

Danke!
Ich brauch einen SCLK von 10 MHz.
Der DCO lässt sich auf 2,4,8 oder 16 MHZ einstellen.
Das passt für mich nicht. Weisst du welche Register ich beschreiben muss
um per Hand den Takt einzustellen?

von Christian R. (supachris)


Lesenswert?

Du kannst mit Hilfe des Programms aus dem TI-Codebeispiel 
"msp430x20xx_dco_flashcal.c" den DCO auf beliebige Vielfache des ACLKs 
einstellen und die Werte Speichern. Genau 10.0000 MHz trifft man aber 
mit einem Uhrenquarz nicht.

von Christoph B. (beyarea)


Angehängte Dateien:

Lesenswert?

Ich will in meinem ersten Programm über SPI die Kontrollregister eines 
AD9857
beschreiben. Also möchte ich jeweils 3 mal 16 Byte an die Adressen 00h 
02h und 04h versenden. Zuvor muss ich jeweils ein Instruction Byte 
versenden, damit der AD9857 weiss dass 2Byte an die übermittelte Adresse 
geschrieben werden sollen.
Also hab ich eine Sendefunktion geschrieben, in der erst 8 Bit dann 16 
gesendet werden sollen. Hab das Senden wie bei Vorgängerprogrammen 
implementiert. Hab aber wieder das Problem, dass nach beschreiben des 
USCNT Registers mit der Bitanzahl das USIIFG nicht gelöscht wird und 
somit wohl auch nix gesendet wird(hab dein Programm gedebuggt da klappt 
das).
Auch die 8 Bit tauchen im USCNT Register nicht auf(es bleibt der Wert 0)
Also muss irgendwas falsch sein. Hab mein Programm mal angehängt, 
vielleicht findet ihr Fehler und ich kriege die Erleuchtung.

von Martin S. (martinsattler)


Lesenswert?

Ich hab ein paar Fehler in deinem Code gefunden:

In der spi_init sind entweder die Kommentare falsch oder die Befehle:

P1DIR: mit BIT1 wird P1.1 und nicht P1.2 als Ausgang definiert!
mit P1OUT &= ~BIT0; wird der CS-Pegel auf 0V gesetzt und somit wird CS 
aktiviert! Das ist hast du aber wahrscheinlich so gewollt, dann ist der 
Kommentar falsch

Und noch ein Problem mit den Variablen:
Vor deiner Main-Funktion definierst du ein paar Variablen als char. char 
kann aber soweit ich weiß nur 8 Bit speichern und du willst 16 oder 
sogar 32 Bit darin speichern! Du musst das 0x20 als unsigned int 
(positive 16-Bit-integer-Zahl) definieren und 0x0481 usw. als unsigned 
long (positive 32-Bit-long-integer-Zahl). Sonst werden die Zeichen 
gekürzt und du hast nur Unsinn in deinen Variablen gespeichert.

von Christoph B. (beyarea)


Lesenswert?

Danke, diese Fahler hab ich schon korrigiert. Es sind dann wohl 
Kommentare falsch. Der CS ist bei mir für den Code nicht so wichtig, den 
will ich dann dauerhaft aktiviert haben, da ich immer nur 1 Slave 
dranhängen hab, mit P1.0
wollte ich einfach nur die LED mit einbeziehen.

von Jonas E. (joenten)


Lesenswert?

Hallo zusammen,
ich versuche zur Zeit mit dem USI im SPI Modus des MSP430G2232 ein 
Serielles Signal an ein 74HC595 Schieberigsister auszugeben.
Ich hab bis jetzt ziemlich viele Beträge im Internet zu dem Thema 
gefunden und gelese.

Ich hab aber noch eine Frage und ich finde auch keine Antwort im 
Internet darauf:
Wie kann ich festlegen an welchem Port bzw. Pin der MISO, MOSI usw. 
ausgeben wird?

von Jörg S. (joerg-s)


Angehängte Dateien:

Lesenswert?

Bei dem kleinen MSP gibt's keine Auswahl dafür. Die Signale kommen also 
immer an dem entsprechenden Pin raus.
Bei den größeren sind dafür das die PxSEL Enstellungen vorgesehen.


Im Anhang der Auszug aus dem Datenblatt für den 20x2. Die PxSEL 
Einstellungen sind da z.B. für SPI egal.

von Jonas E. (joenten)


Lesenswert?

Ok danke für die schnelle Antwort, hat mir sehr weitergeholfen.

von MSPler (Gast)


Lesenswert?

Hi,
Ich verstehe das nicht ganz. Ich habe meinen MSP430F2013 genauso 
programmiert (kopiert) wie Martin Sattler es geschrieben hat. Trotzdem 
hängt der gute immer bei der SPI Übertragung an der Zeile:
>   while (!(USIIFG & USICTL1));            // Counter clear?

Das ist doch nur eine Abfrage, ob das USIIFG 0 ist, und wenn es 0 ist, 
dann soll es weitergehen oder?
Im Register wird dieses Flag immer als 0 angezeigt...

Martin Sattler schrieb:
> Inzwischen hab ich herausgefunden, wie das Senden funktioniert:
> #include <msp430x20x3.h>
>
.
.
.
> void v_out(void)
> {
> /*   //send 2 times 8 bits
>   P1OUT &= ~BIT2;                         // Enable MAX5530
>
>   USICNT = 8;                             // re-load counter
>   USISRL = 0xF4;
>   while (!(USIIFG & USICTL1));            // Counter clear?
>
>   USICNT = 8;                             // re-load counter
>   USISRL = 0x00;
>   while (!(USIIFG & USICTL1));            // Counter clear?
> */
>      //send 1 time 16 bits
>   USICTL0 |= USISWRST;                    // USI stopped
>   USICNT = 16;                            // re-load counter
>   USICNT |= USI16B;
>
>   P1OUT &= ~BIT2;                         // Enable MAX5530
>   USICTL0 &= ~USISWRST;                   // USI released for operation
>   USISR = 0xF400;
>   while (!(USIIFG & USICTL1));            // Counter clear?
>
>   P1OUT |= BIT2;                          // Disable MAX5530
> }

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

MSPler schrieb:
>> while (!(USIIFG & USICTL1));            // Counter clear?
>
> Das ist doch nur eine Abfrage, ob das USIIFG 0 ist, und wenn es 0 ist,
> dann soll es weitergehen oder?

Nein.

Es geht solange nicht weiter (d.h. die While-Schleife wird nicht 
verlassen) wie das Bit USIIFG nicht gesetzt ist.


Die Zeile wartet also, bis das Bit gesetzt wird.

von MSPler (Gast)


Lesenswert?

Hmm sorry, hab mich falsch ausgedrückt, aber genau das hab ich gemeint 
:)

Irgendwie scheint der µC keine Daten raus zu takten. Keine Ahnung warum 
:(

von Cervisia (Gast)


Lesenswert?

Du hast exakt die selbe Hardware (MAX5539)? Und am Programm kein 
einziges Zeichen geändert?

von MSPler (Gast)


Lesenswert?

Nein, ich habe eine andere Hardware, bzw. es auch komplett ohne 
angeschlossene Hardware versucht, aber laut Programm müssten die Daten 
ja dennoch rausgeschickt werden.
Ich habe es auch mit mehreren µC`s versucht um einen defekt 
auszuschließen, aber mein Oszilloskop gibt mir recht. Es wird nicht 
einmal das clk Signal sichtbar...

von MSPler (Gast)


Lesenswert?

Sorry fürs stehlen der Zeit wegen Blödheit....
Habe herausgefunden, dass man vielleicht von Simulation auf Debugger 
Modus umschalten sollte.... Dann läuft der µC auf jeden Fall deutlich 
effizienter :/
Sorry nochmal :)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.