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
- 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
- Der MCP3004 ist ein 10bit A/D-Wandler mit SPI.
- Der MCP3004 besitzt 4 analoge Kanäle, der MCP3008 8 Kanäle.
- Datenblatt: https://ww1.microchip.com/downloads/en/DeviceDoc/21295d.pdf
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
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.
- 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
- 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
undUCCKPH=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 vonUCB0CTL1 = 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.
- Durch das Schreiben des Registers
UCB0TXBUF
werden die Daten automatisch versendet.
- 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:
- 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:
- 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);
}
}