MSP430 SPI Tutorial 5


Dieses Tutorial beschreibt die MSP430 SPI-Schnittstelle anhand eines Beispiels. Zunächst werden die Grundlagen zu SPI und der MSP430-Serie erklärt, um sich abschließend auf dem Mikrocontroller MSP430G2553 und eine Beispielanwendung zu beziehen.

Was für das MSP430 SPI-Tutorial benötigt wird

Um das Tutorial nachzuvollziehen werden folgende Informationen (Links dazu) benötigt:

MSP430 SPI Grundlagen

Die SPI-Schnittstelle (Serial Peripheral Interface) ist ein synchrones serielles Bus-System welches von Motorola entwickelt, jedoch nie patentiert wurde. Hierbei werden die Teilnehmer über das Master und Slave Prinzip miteinander verbunden [1].

In diesem System kann es nur einen Master und mindestens einen Slave geben. Wann die Kommunikation startet sowie den Takt der Kommunikation bestimmt/liefert immer der Master. Es werden vier Leitungen benötigt (plus gemeinsame Masse):

  • MISO: Master In Slave Out, daher Slave sendet eine Information
  • MOSI: Master Out Slave In, daher Master sendet Information
  • SCK: Serial Clock, der Master gibt immer den Takt vor
  • CS: Chip Select, der Master wählt den Kommunikationspartner aus

Wie man ein Bussystem über SPI aufbaut, zeigt die nachfolgende Abbildung:

spi master slave prinzip

Abb. 1: Master und Slave Prinzip der SPI-Schnittstelle

Zu sehen ist Links ein einfaches System bei dem Links der Master und rechts ein Slave ist. Laut Theorie kann man sich die CS-Leitungen bei so einem System sparen. Hierbei muss dann die CS-Leitung des Slaves dauerhaft auf High/Low (je nach IC) über einen Pull-Up/Pull-Down gezogen werden. In der Praxis kommt dies jedoch nicht immer vor, da die CS-Leitung nicht nur zur Auswahl des Teilnehmers sondern auch zum Start eines Frames genutzt wird. Rechts im Bild ist ein Multi-Slave-System abgebildet. Für jeden Teilnehmer der Im diesem Bus-System hängt, wird eine CS-Leitung benötigt. Für eine CS-Leitung nimmt man typischer weise einen normalen Ein-/Ausgang des Mikrocontrollers.

Nun die Grundlagen bezogen auf der MSP430-Serie

Wir wollen nun die Grundlagen auf dem MSP430G2553 anwenden. Texas Instruments bezeichnet die MSP430 SPI-Pins (warum auch immer) anders. Aus MOSI, MISO und CLK wie man es gewohnt ist, werden bei TI als SIMO, SOMI und UCLK bezeichnet. Sofern der Mikrocontroller als Master genutzt wird, kann jeder freier GPIO-Pin als CS-Leitung fungieren. Wenn der Mikrocontroller als Slave genutzt werden soll, muss zusätzlich die STE-Leitung berücksichtigt werden. Zusammengefasst:

Theorie MSP430 als Master MSP430 als Slave Funktion
MISO SOMI SOMI Sendeleitung Slave
MOSI SIMO SIMO Sendeleitung Master
SCK UCLK UCLK Takt vom Master
CS Jeder freier GPIO-Pin STE-Pin Auswahl vom Slave

Ab hier wird auch das User’s Guide (SLAU144J) Kapitel 19, ab Seite 498 interessant. Der Mikrocontroller unterstützt folgende SPI-Funktionen:

  • Datenlänge von 7- oder 8-Bit, MSB zuerst
  • Als Master wie Slave einsetzbar
  • 3- oder 4-Pin SPI, macht jedoch nur Sinn wenn der Mikrocontroller ein Slave sein soll
  • Alle 4 SPI-Modi benutzbar (Erklärung folgt)

MSP430 SPI-Modi

Wenn Ihr euch mit SPI beschäftigt, dann werdet Ihr sehr früh auf den Begriff SPI-Modi stoßen. Was sind die SPI-Modi? Da Motorola kein Protokoll festgelegt hat, haben sich mit der Zeit 4 Modi etabliert, mit dem SPI laufen kann. Diese Modi sind Einstellungen bezüglich der Phase und Polarität des Taktes.

Die Modi – abgeleitet vom User’s Guide – sind in der nachfolgenden Tabelle zusammengefasst:

Modi CKPL (Polarität) CKPH (Phase) Erläuterung
0 0 0 Takt Inactive Low, Daten werden bei der zweiten Flanke übernommen
1 1 0 Takt Inactive High, Daten werden bei der zweiten Flanke übernommen
2 0 1 Takt Inactive Low, Daten werden bei der ersten Flanke übernommen
3 1 1 Takt Inactive High, Daten werden bei der ersten Flanke übernommen

Wobei die Bezeichnungen CKPH und CKPL wiederum TI-spezifisch sind. Allgemein werden die Eigenschaften als CPHA und CPOL bezeichnet. Was ist aber mit „Daten werden bei der zweiten Flanke eingelesen“ oder „Daten werden bei der ersten Flanke eingelesen“ gemeint? Antwort darauf gibt das User’s Guide in Seite 501. Dazu betrachtet man die Bits für SIMO/SOMI. Genau in der Mitte des Bits geht man senkrecht nach oben und betrachtet nun CKPH und CKPL. Nun zählt man – nachdem STE den Low-Pegel erreicht hat – die Anzahl der Flanken. Leider entsprechen die SPI-Modi – so wie sie TI darstellt – nicht den allgemeinen SPI-Modi die sich global etabliert haben. Bei den SPI-Modi von TI sollte die Phase immer inventiert betrachten werden. Zum Beispiel: Wenn bei einem Datenblatt eines ICs (außer vielleicht bei TI) der Modus 0,0 (CKPL, CKPH) erwünscht ist, dann muss der MSP430-Mikrocontroller als 0,1 (CKPL, CKPH) eingestellt werden. Allgemein empfehle ich im Datenblatt des ICs immer nach einem Bild ausschau zu halten, bei dem die Kommunikation visualisiert wird und es mit der SPI-Abbildung von TI zu vergleichen.

Hier werden die Modi Laut TI-User’s Guide wie folgt dargestellt:

msp430 spi modi

Abb. 2: Die 4 MSP430 SPI-Modi nach Texas Instruments

Die vorherige Tabelle gibt die wichtigsten Informationen der Abbildung wieder. Was vielleicht noch fehlt ist, dass die STE-Leitung (allgemein als CS Bezeichnet) den Start eines Frames signalisiert. Wir sehen außerdem, dass bei TI das MSB zuerst gesendet wird. Was hier nicht steht und öfters vergessen wird, ist, dass (sofern der MSP430 als Master fungiert) damit der MSP430 eine Nachricht vom Slave empfängt, er diesem einen Dummy-Wert (meist 0xFF) senden muss. Der Slave-Benötigt einen Takt um die Daten zu senden, einen Takt bekommt dieser jedoch nur wenn der Master etwas sendet. Daher wenn Master etwas empfangen soll, einen Dummy-Wert senden.

Wie erkenne ich die MSP430 SPI-Pins?

Dazu reicht ein Blick ins Datenblatt, entweder auf Seite 3 oder 4 wo das Pin-Out zu sehen oder bei den Seiten 6 bis 8 wo die Pin-Bezeichnung zu finden ist. Zu beachten ist, dass die Sende- und Empfange-Pins für UART und SPI die gleichen sind. Beim Programmieren des Moduls gibt TI dem Anwender die Möglichkeit zwischen SPI, I2C und UART auszuwählen (vgl. Programmierung).

msp430g2553 pin out

Abb. 3: MSP430G2553 Pin-Out

Bei der MSP430-Serie sind die SPI-Pins grundsätzlich als SOMI, SIMO, CLK und STE gekennzeichnet. Zum Beispiel werden beim MSP430G2553 die SPI-Pins als UCA0SOMI, UCA0SIMO, UCA0CLK und UCA0STE für Kanal UCA0 und UCB0SOMI, UCB0SIMO, UCB0CLK und UCB0STE für Kanal UCB0 bezeichnet. Der MSP430G2553 hat zwei Kanäle (den UCA0 und UCB0) für SPI zur Verfügung.

Programmierung

Vorgefertigte TI-Beispiele können auch im ZIP-Ordner von TI (SLAC485h.zip) gefunden werden und sind äußerst hilfreich.

Nun wird das User’s Guide benötigt, Kapitel 16 ab Seite 435. Wir müssen die SPI-Schnittstelle einstellen bevor wir diese nutzen können. Allgemein müssen:

  • Initialisierung vom MSP430 SPI-Modul
  • Empfangen und Senden von Daten

programmiert werden.

MSP430 SPI-Modul initialisieren

Prinzipiell kann folgender Pseudocode für die Initialisierung des MSP430 SPI-Moduls als Vorlage dienen:

// 0. Starte Mikrocontroller, wähle Frequenz

// 1. Wähle Spezialpins für SPI

// 2. Konfiguriere SPI-Register

// 3. Resete SPI-Modul um Einstellungen zu übernehmen

// 4. Aktiviere SPI-Interrupts (optional falls erwuchst)

Das Einstellen des Registers möchte ich an einem kleinen Beispiel demonstrieren (vgl. auch beispielprogram msp530g2xx3_uscia0_spi_09.c von ZIP-Ordner SLAC485h). Der Mikrocontroller soll folgender Einstellungen vorweisen:

  • 8 Bit Datenlänge
  • MSB zuerst senden
  • Mikrocontroller ist Master
  • SPI-Frequenz 500 kHz
  • Empfange Daten per Interrupt
  • TI Modi 1-1
// 0. Starte Mikrocontroller, wähle Frequenz

WDTCTL = WDTPW + WDTHOLD; // Stoppe WDT

DCOCTL = 0; // Stelle Frequenz ein …

BCSCTL1 = CALBC1_1MHZ; // …

DCOCTL = CALDCO_1MHZ; //.-

 

// 1. Wähle Spezialpins für SPI

P1SEL = BIT1 + BIT2 + BIT4; // P1.1=MISO, P1.2=MOSI, P1.4=CLK

P1SEL2 = BIT1 + BIT2 + BIT4; // P1.1=MISO, P1.2=MOSI, P1.4=CLK

P1DIR |= BIT5; // P1.5 als Ausgang für CS

P1OUT |= BIT5; // CS soll Inactive High sein

 

// 2. Konfiguriere SPI-Register

UCA0CTL1 |= UCSSEL_2; // Wähle Clock des MCUs, hier Haupt-Clock

UCA0CTL0 |= UCCKPH+UCCKPL+UCMSB+UCMST+UCSYNC;// TI 1-1, MSB zuerst, 8-Bit

UCA0BR0 |= 0x02; // Clock prescaler, Low Byte …

UCA0BR1 = 0; // High Byte für Clock /2 (ca. 500kHz).-

UCA0MCTL = 0; // Kein Modulation

 

// 3. Resete SPI-Modul um Einstellungen zu übernehmen

UCA0CTL1 &= ~UCSWRST; // Resete UART-Modul

 

// 4. Aktiviere SPI-Interrupts (optional falls erwuchst)

IE2 |= UCA0RXIE; // Aktiviere Receive-Interrupt

Zu 0: Zunächst (und das gilt für jeden MSP430er) muss der Watchdog gestoppt werden. Sonst verharrt der Mikrocontroller in diesem Zustand und das Programm läuft nicht. Daraufhin sollte die Frequenz – mit der der Mikrocontroller laufen soll – eingestellt werden. Hat der Anwender keine ausgewählt, läuft der Mikrocontroller mit seinem Standardwert von ca. 1,2 MHz.

Zu 1: Der MSP430G2553 verfügt über 2 SPI-Kanäle die UCA0 und UCB0. Für das Beispiel wurde willkürlich der Kanal UCA0 genommen (vgl. Pins 1.1, 1.2 und 1.4 vom Pin-Out der Abbildung 3). Das Spezialregister des Kontrollers spricht man über PxSEL und PxSEL2 an (falls MCU die Option PxSEL2 anbietet, die meisten verfügen über kein PxSEL2). Um einen Slave auszuwählen, benötigen wir auch eine Chip-Select-Leitung (CS). Dazu wird willkürlich der GPIO-Pin 1.5 ausgewählt und als Ausgang und auf High-Pegel gesetzt.

Zu 2: Der komplizierteste Teil der Initialisierung. Zunächst stellen wir über dem UCA0CTL1-Register die Clock ein. Es können verschieden Clock-Quellen genutzt werde. Für das Beispiel nehme ich die Haupt-Clock.

Nun stelle ich die erwünschten SPI-Einstellungen ein. Dazu ist die Seite 445 (vgl. auch Abbildung 4) interessant.

msp430g2553 usci register ucaxctl0

Abb. 4: SPI UCAxCTL0-Register

Zu beachten ist, dass ich die 8-Bit Datenlänge nutze, indem ich das Bit UC7BIT nicht setze. Für die restlichen Einstellungen muss ich die Bits: UCCKPH, UCCKPL, UCMS, UCMST und UCSYNC setzen. Da ich außerdem kein UCMODEx ausgewählt habe, nimmt der MCU automatisch den Modus 0 an. Beachte die Modi 1 und 2 machen nur sin, wenn der MCU als Slave eingestellt ist.

Nun haben wir die Möglichkeit über UCA0BR0 und UCA0BR1 einen Prescaler einzustellen. Die Werte zusammen ergeben einen 16-Bit Wert und sollten zusammenbetrachtet werden. Auf Seite 446 sehen wir das UCA0BR0 das Low- und UCA0BR1 das High-Byte ist (vgl. auch Abbildung 5).

msp430g2553 usci register uca0brx

Abb. 5: USPI UCAxR0- und UCAxR1-Register

Was dort nicht steht ist, dass nur Werte ab 1 für die Register eingestellt werden können (UCA0BR0 = 0 würde nichts bringen).

Abschließend wähle ich keine Modulation aus. Diese Zeile könnte man sich sparen, da das Register Default auf 0 gesetzt ist.

Zu 3: Damit der Mikrocontroller die SPI-Einstellungen übernimmt, muss zwingend das SPI-Modul neu gestartet werden. Ähnliches verhalten gilt für jedes MSP430-Modul.

Zu 4: Dieser Teil ist optional (macht öfters sin). Hier aktivieren wir das Empfangs-Interrupt für das SPI-Modul. Trotz dessen muss im nachfolgenden Code, irgendwo noch die globalen Interrupt für den Mikrocontroller – über den Befehl _EINT(); – aktiviert werden.

MSP430 SPI-Modul Senden und Empfangen

Optional kann man anstatt zwei Funktionen zum Senden und Empfangen von Daten, eine Funktion die Beides macht, implementieren. Im Beispiel habe ich jedoch zwei Funktionen genutzt, wobei das Empfangen per Interrupt geschieht.

Der Pseudocode zum Senden von Nachrichten, kann wie folgt aussehen:

// Signalisiere Slave, dass Übertragung startet indem ich CS auf Low ziehe

// Sende meine Information

// Warte bis ganze Information gesendet wurde

// Signalisiere Slave, dass die Übertragung fertig ist, indem ich CS wieder auf High ziehe

Und zum Empfangen von Nachrichten:

// Warte solange SPI-Modul intern noch beschäftigt ist

// Lese die Nachricht aus

Der Quellcode zum Senden und Empfangen von Nachrichten mit dem MSP430G2553 sieht wie folgt aus:

//

// Sende Daten über UCA0

//

void SPI_send(unsigned char data)

{

P1OUT &= ~BIT5; // Ziehe CS auf Low, Frame startet

UCA0TXBUF = data; // Sende Wert

while(UCA0STAT & UCBUSY); // Warte bis Wert gesendet wurd, Alternativ: while (!(IFG2 & UCA0TXIFG));

P1OUT |= BIT5; // Ziehe CS wieder auf High, Frame beendet

}

 

//

// Receive Interrupt über UCA0

//

#pragma vector=USCIAB0RX_VECTOR

__interrupt void SPI_USCIA0RX_ISR(void)

{

while(UCA0STAT & UCBUSY);//while (!(IFG2 & UCA0RXIFG)); // USCI_A0 TX buffer fertig?

rcv = UCA0RXBUF; // Wobei rcv globale Variable, Lese Daten aus

}

Der Vollständigkeit halber nun auch der gesamte Quellcode zum MSP430 SPI Tutorial:


Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

*

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.

5 Gedanken zu “MSP430 SPI Tutorial

  • Helmi

    Hallo,
    super Tutorial zu SPI, aber was bedeutet die Variable data?
    Ist es ein generischer Name bzw. was verbirgt sich hinter dieser Bezeichnung?
    Auf github gibt es ein ähnliches Programm (kilork/ Msp430OLED).
    Hier tauchen auch die Variablen data und size auf.
    Sind diese Variablen in einer include-Datei definiert?

    • k.t.evangelos Autor des Beitrags

      Hallo,
      freut mich das die das Tutorial gefallen hat!
      Nun zur Variable „data“. Im Beispielcode taucht die Variable bei der Funktion „void SPI_send(unsigned char data)“ auf. Die Bezeichnung ist willkürlich von mir ausgewählt worden (könnte wie auch immer heißen). Bei Aufruf der Funktion muss der Nutzer einen unsigned char Wert der Funktion mitgeben. Dies ist die Information die der Nutzer über SPI senden möchte und wird in der Funktion als „data“ bezeichnet. Im Beispiel vom Github ist es Zufall (aber sehr wahrscheinlich), dass beide den gleichen Namen benutzen.
      Ich habe mir mal den Quellcode vom Github angeschaut. Bei der Funktion: „void oled_write(unsigned char* data, unsigned int size)“ nutzt der Progammierer, wie ich, den Namen „data“ als Platzhalter. Die Variable „data“ ist die Information die er senden möchte. Auch er wird den Namen „data“ willkürlich ausgewählt haben. Ein kleiner Unterschied ist jedoch, dass der Code von Github einen Pointer nutzt.
      Hoffe dir geholfen zu haben.
      Mfg

    • k.t.evangelos Autor des Beitrags

      Vielen Dank!!!
      Ich arbeite mittlerweile auch seit ein paar Jahren mit dem MSP430 und bin auch sehr zufrieden mit den MCUs.