Skip to content

MSP430 - SPI

Übersicht

  • Serial Peripheral Interface
  • synchroner serieller Datenbus → zusätzliche Taktleitung
  • deutlich schnellere Übertragungen möglich im Vergleich zu UART
  • Takt wird vom Master festgelegt
  • 1 Taktperiode ← Master sendet 1 Bit an Slave, Slave sendet 1 Bit an Master
  • nach 8 Taktperioden wurde 1 Byte zwischen Master ⇆ Slave ausgetauscht

alt: "SPI-Bustopologie: 1 Slave", src:"Wikipedia-Commons", w:50
alt: "SPI-Bustopologie: mehrere Slaves, Verkettung (daisy-chain)", src:"Wikipedia-Commons", w:50
alt: "SPI-Bustopologie: mehrere Slaves, mehrere SS- oder CS-Pins", src:"Wikipedia-Commons", w:50

  • SPI-Signalleitungen:
    • SCLK: serial clock
    • MOSI: master out slave in
    • MISO: master in slave out
    • SS or CS: slave or chip select, active low

MCP3004/MCP3008 - SPI-ADC

MCP3004/8

alt: "SPI-Protokoll des MCP3004/8", src: "Datenblatt, S. 21", w:75

Verbindungsleitungen

  • Im unteren Teil der Abbildung sind die gesendeten und empfangenen Bytes und deren Interpretation zu sehen.
  • Der MSP430 muss konfiguriert werden, um exakt diese Daten über SPI zu senden und zu empfangen.
  • Die beiden Schnittstellen USCIA und USCIB des MSP430G2553 unterstützen das SPI-Protokoll.
  • Da USCIA für UART verwendet wird, wird USCIB für die SPI-Kommunikation im folgenden Beispiel verwendet.
  • Stellen Sie die Verbindung zum MCP3004 entsprechend der folgenden Tabelle her.
Pin MCP3004 MSP430
1 3V3 3V3
2 CS P2.0
3 MOSI P1.7
4 MISO P1.6
5 SCK P1.5
6 GND GND
  • Die Pins MOSI, MISO und SCK sind durch die zugehörige Pins der USCIB-Schnittstelle festgelegt.
  • Für CS kann jedoch fast jeder Pin des MSP430 verwendet werden muss.
    Es handelt sich hierbei um einen normalen digitalen Pin, der zwischen H- und L-Pegel geschaltet werden muss.

MSP430 Register

alt: "Register UCxxCTL0 für SPI", src: "Family Guide, S. 445", w:75

alt: "Register UCxxCTL1 für SPI", src: "Family Guide, S. 445", w:75

Detaillierte Beschreibung

Initialisierung

  • Setzen des CS an Pin 2.0 als Ausgang. Der Standard-Zustand sollte H-Pegel sein. Der SPI-Slave wird aktiviert, wenn CS = L.
  • Setzen der RGB-LED Pins als Ausgang.
  • Verbinden der Pins P1.5, P1.6 und P1.7 mit der USCIB-Schnittstelle durch setzten der PxSELx-Register.
    P1SEL |= BIT5 + BIT6 + BIT7;
    P1SEL2 |= BIT5 + BIT6 + BIT7;
    
  • USCI-Intialisierung:
    UCB0CTL1 |= UCSWRST;
    UCB0CTL0 = UCCKPH + UCMSB + UCMST + UCSYNC; // SPI phase, MSB first, master mode, synchronous
    UCB0BR0 = 1;
    UCB0BR1 = 0;
    UCB0CTL1 = UCSSEL_2;
    
    • Halten des Reset-Bits während der Komminikation
    • MSB first (UCMSB)
    • MSP430 ist Master (UCMST)
    • Einstellen der Clock-Phase und Polarität
      alt: "Einstellen der Clock-Phase und Polarität", src: "Family Guide, S. 442", w:75
      • Clock Phase and Polarity müssen entsprechend des SPI-Slaves eingestellt werden.
      • Der Quasi-Industriestandard ist dabei:
        • Startwert der SCLK ist L.
        • Die Daten werden bei einer steigenden Flanke von SCLK eingelesen und bei einer fallenden Flanke verändert.
        • Die resultiert im MSP430 in UCCKPL=0 und UCCKPH=1.
        • Es gibt jedoch immer wieder SPI-Slaves die von diesem Schema abweichen!
    • Die SMCLK wird als Taktquelle verwendet (UCSSEL_2).
    • Der Taktteiler wird auf 1 gesetzt.

      $$ \text{Divider} = \text{UCB0BR0} + 256 \cdot \text{UCB0BR1} $$
      - Resultierende Taktfrequenz: 1 MHz
      - Das Reset-Signal wird gelöscht beim Schreiben von UCB0CTL1 = UCSSEL_2.

Lesen des Kanal 0

  • Aktivieren des Slaves durch CS = L.
  • Als erstes Byte muss der Wert 0b00000001 übertragen werden.
  • Durch die folgende Schleife wird sichergestellt, dass keine Kommunikation mehr auf dem Bus läuft.
    while (!(IFG2 & UCB0TXIFG)) {
    }
    
  • Durch das Schreiben des Registers UCB0TXBUF werden die Daten automatisch versendet.
    UCB0TXBUF = 0b00000001;
    
  • Eine weitere Schleife muss eingefügt werden, bevor das 2. Byte übertragen werden kann.
  • Das 2. Byte ist 0b1000000 → Single-Mode + Channel 0
  • Fügen Sie eine weitere Schleife ein.
  • Vor dem Senden des letzten Bytes müssen jedoch die empfangenen Daten abgespeichert werden:
    uint8_t msb = UCB0RXBUF;
    
  • Der Wert des letztens Bytes hat keinen Einfluss auf die Kommunikation: Verwenden Sie z. B. 0x00.
  • Einfügen einer weiteren Schleife und abspeichern des empfangenen Wertes:
    uint8_t lsb = UCB0RXBUF;
    
  • Deaktivieren des Gerätes durch CS = H.

Ausgabe des Ergebnisses

  • Der folgende Quelltext stellt das Ergebnis als Farbwert (rot, gelb, grün, türkis, blau) dar.
  • Der ADC-Wert wird erstellt, indem MSB und LSB zusammengefügt werden.
  • Der maximale Wert eines 10bit-ADC ist 1023. Es ergibt sich daher 1023 / 5 = 204 als Schrittweite.
// Set LEDs
uint16_t result = (((uint16_t) msb & 0x03) << 8) + lsb;

if (result < 204) {
  // red
  P2OUT |= BIT1;
  P2OUT &=~ (BIT3 + BIT5);
}
else if (result < 409) {
  // yellow
  P2OUT |= BIT1 + BIT3;
  P2OUT &= ~ BIT5;
}
else if (result < 613)
{
  // green
  P2OUT |= BIT3;
  P2OUT &= ~(BIT1 + BIT5);
}
else if (result < 818) {
  // cyan
  P2OUT |= BIT3 + BIT5;
  P2OUT &= ~BIT1;
}
else {
  // blue
  P2OUT |= BIT5;
  P2OUT &= ~(BIT1 + BIT3);
}

__delay_cycles(10000);

Lösung

Gesamtes Programm

int main(void) {
  WDTCTL = WDTPW | WDTHOLD;  // stop watchdog timer

  // CS
  P2OUT |= BIT0;
  P2DIR |= BIT0;

  // SPIB
  P1SEL |= BIT5 + BIT6 + BIT7;
  P1SEL2 |= BIT5 + BIT6 + BIT7;

  // RGB LED
  P2OUT &= ~(BIT1 + BIT3 + BIT5);
  P2DIR |= BIT1 + BIT3 + BIT5;

  UCB0CTL1 |= UCSWRST;
  UCB0CTL0 = UCCKPH + UCMSB + UCMST + UCSYNC; // SPI phase, MSB first, master mode, synchronous
  UCB0BR0 = 1;
  UCB0BR1 = 0;
  UCB0CTL1 = UCSSEL_2;

  while (1) {
    // Read Channel 0
    P2OUT &= ~ BIT0;

    while (!(IFG2 & UCB0TXIFG)) {
    }
    UCB0TXBUF = 0b00000001;

    while (!(IFG2 & UCB0TXIFG)) {
    }
    UCB0TXBUF = 0b10000000;

    while (!(IFG2 & UCB0TXIFG)) {
    }
    uint8_t msb = UCB0RXBUF;
    UCB0TXBUF = 0x00;

    while (!(IFG2 & UCB0TXIFG)) {
    }

    uint8_t lsb = UCB0RXBUF;

    P2OUT |= BIT0;

    // Set LEDs
    uint16_t result = (((uint16_t) msb & 0x03) << 8) + lsb;

    if (result < 204) {
      // red
      P2OUT |= BIT1;
      P2OUT &= ~(BIT3 + BIT5);
    }
    else if (result < 409) {
      // yellow
      P2OUT |= BIT1 + BIT3;
      P2OUT &= ~ BIT5;
    }
    else if (result < 613)
        {
      // green
      P2OUT |= BIT3;
      P2OUT &= ~(BIT1 + BIT5);
    }
    else if (result < 818) {
      // cyan
      P2OUT |= BIT3 + BIT5;
      P2OUT &= ~BIT1;
    }
    else {
      // blue
      P2OUT |= BIT5;
      P2OUT &= ~(BIT1 + BIT3);
    }

    __delay_cycles(10000);
  }
}