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
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?
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
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.
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.
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)
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.
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.
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 | }
|
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.
Danke für den Tipp, dass Senden und Empfangen gleichzeitig geht.. So hab ichs dann schließlich hinbekommen.
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
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
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
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
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?
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.
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.
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.
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.
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?
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.
Ok danke für die schnelle Antwort, hat mir sehr weitergeholfen.
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 > }
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.
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 :(
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...
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.