MSP430 - Mixed-Signal-Module
Analog-Digital-Wandler
Übersicht
Flash- oder Parallelwandler
Prinzip der sukzessiven Approximation
Sigma-Delta-Wandler
ADC10 des MSP430F2274
-
10-bit SAR
-
Formel zur Berechnung des ADC-Ergebnisses:
\[ N\ped{ADC} = 1023 \cdot \frac{V\ped{IN} - V\ped{R-}}{V\ped{R+} - V\ped{R-}} \]
- ADC-Clock Selection:
- Typische Taktquellen: ACLK, MCLK, SMCLK
- Zusätzlich ADC10OSC mit ca. 5 MHz
- Sample & Hold-Schaltung
- Sample-Zeit kann eingestellt werden
- Hold-Zeit entsprechend der Conversion-Zeit
- Analoger Multiplexer
- Verschiedene Eingangssignale können gemessen werden
- Analoge Eingänge A0 bis A7 am Port 1 des MSP430G2553
- Temperatursensor an INCH = 10
- AVcc / 2 an INCH = 11
- Referenzspannungsquellen:
- z. B. \(V\ped{R+} = V\ped{CC}\), \(V\ped{R-} = V\ped{SS}\) oder \(V\ped{R+} = V\ped{REF+}\), \(V\ped{R-} = V\ped{SS}\)
- Interne Referenzspannungsquelle kann auf 1,5 V oder 2,5 V eingestellt werden
- Data Transfer Controller
- sinnvoll für viele schnelle Messungen hintereinander, wenn CPU es nicht schafft ADC-Ergebnis in RAM abzuspeichern
- auch genannt DMA (direct memory access)
- DTC speichert ADC-Ergebnis automatisch an gewünschter Stelle im RAM ab.
- z. B. Erstellen eines Ringspeichers: zyklisches Abspeichern eines Messwertes
-
Programmierung
Auslesen des analogen Potentiometer-Eingangs
#include <msp430.h>
#include <stdint.h>
int main(void) {
WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer
BCSCTL1 = CALBC1_1MHZ;
DCOCTL = CALDCO_1MHZ;
ADC10CTL0 = ADC10ON + ADC10IE;
ADC10CTL1 = INCH_7;
ADC10AE0 |= BIT7;
// RGB LED
P2OUT &= ~(BIT1 + BIT3 + BIT5);
P2DIR |= BIT1 + BIT3 + BIT5;
__enable_interrupt();
while (1) {
ADC10CTL0 |= ENC + ADC10SC;
__low_power_mode_0();
uint16_t result = ADC10MEM;
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);
}
}
}
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR() {
__low_power_mode_off_on_exit();
}
Anmerkungen zur Sampling-Zeit
\[ R\ped I < 2\,\text k\Omega,\quad C\ped I < 27\,\text{pF} \]
\[ t_{\text{sample}} > R_{\text{ges}} \cdot C\ped I \cdot \ln(2^{11}) \]
Integrierter Operationsverstärker
- Manche MSP430 haben einen integrierten OPV - der MSP430G2553 nicht!
- Verschiedene Funktionen des OA-Moduls:
- Aufbau des OA-Moduls:
- Ausgangssignale:
- Analoger Ausgang durch OAxO an Pins
- Verwendung als Eingangssignal des ADC-Wandlers (z. B. Vorverstärkung des Eingangssignals durch OA)
Integrierter Komparator
Übersicht
- Das Comparator A+ Modul ist im MSP430G2553 verbaut.
- Aufbau des Comparator A+
- Vergleich des Spannungslevels verschiedener Eingangssignale
- Vergleich mit verschiedenen Referenzspannungen: Vcc/2, Vcc/4, 0.55 V
- Weiterverarbeiten des Komparatorausgangs durch Interrupt, TimerA, CAOUT-Ausgang
Beispiel der Widerstandsmessung
Kapazitives Touch
- Grundprinzip: Menschliche Körper stellt eine zusätzliche Kapazität gegen Masse dar
- Vorteile:
- Simples Sensordesign:
- Ledglich zusätzliche Leiterbahn auf Leiterplatte
- Keine mechanischen Bauelemente, wie Taster notwendig
- Vorteile bei wasserfesten Anwendungen
- Simples Sensordesign:
Programmierung beliebiger Mikrocontroller
- Ablauf des Programms:
- Pin wird als Ausgang, High geschaltet
- Circa. \(500\,\mu\text s\) warten, bis alle Kondensatoren auf 3,3 V geladen sind
- Pin wird als Ausgang, Low geschaltet → interne Kondensator entlädt sich
- Pin wird als Eingang geschaltet → externen Kondensatoren laden internen Kondensator auf
- Nach ca. \(30\,\mu\text s\) wird der Eingangswert des Pins gelesen
- Wenn der Eingang auf Low liegt, wird der Sensor nicht berührt
- Wenn der Eingang auf High liegt, wird der Sensor berührt
Touchsensor mit einem regulären GPIO
#include <msp430.h>
#include <stdint.h>
int main(void) {
WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer
P1DIR |= BIT0;
__enable_interrupt();
while (1) {
P1OUT |= BIT4;
P1DIR |= BIT4;
__delay_cycles(500);
P1OUT &= ~BIT4;
P1DIR &= ~BIT4;
__delay_cycles(30);
if (P1IN & BIT4) {
P1OUT |= BIT0;
} else {
P1OUT &= ~BIT0;
}
}
}
Möglichkeiten der Pin Oscillator-Funktion
- Automatisches Umladen der Pin-Kapazität durch eine Inverterschaltung
- Frequenz der entstehenden Schwingung ist abhängig von der Umladegeschwindigkeit
- Umladegeschwindigkeit ist abhängig von dem internen Ladewiderstand und der Pin-Kapazität
- Durchführen einer Frequenzmessung durch Timer
- Mit Pin Oscillator kann eine deutlich empfindlichere Kapazitätsmessung durchgeführt werden
→ Berührungsdetektion ohne galvanische Verbindung ist möglich
→ Entscheidend für wasserdichtes Gehäuse und Korrosionsschutz der Kontaktfläche
Touchsensor mit der MSP430 Pin Oscillator-Funktion
#include <msp430.h>
#include <stdint.h>
void uart_print(char *str) {
while (*str != 0) {
while (!(IFG2 & UCA0TXIFG)) {
}
UCA0TXBUF = *str;
*str++;
}
}
void uart_hex(uint8_t number) {
char str[3];
for (uint8_t i = 0; i < 2; i++) {
uint8_t digit = number & 0xf;
if (digit < 10) {
str[1 - i] = '0' + digit;
} else {
str[1 - i] = 'a' + digit - 10;
}
number >>= 4;
}
str[2] = 0;
uart_print(str);
}
int main(void) {
WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer
BCSCTL1 = CALBC1_1MHZ;
DCOCTL = CALDCO_1MHZ;
// LED
P1DIR |= BIT0;
// UART
P1SEL |= BIT2;
P1SEL2 |= BIT2;
UCA0CTL1 |= UCSWRST;
UCA0CTL0 = 0;
UCA0CTL1 |= UCSSEL_2;
UCA0BR0 = 104;
UCA0BR1 = 0;
UCA0MCTL = (1 << 1);
UCA0CTL1 &= ~UCSWRST;
IE1 |= WDTIE;
__enable_interrupt();
while (1) {
TA0CTL = TASSEL_3 + MC_2; // TACLK, cont mode
TA0CCTL1 = CM_3 + CCIS_2 + CAP; // Pos&Neg,GND,Cap
P1DIR &= ~ BIT4;
P1SEL &= ~ BIT4;
P1SEL2 |= BIT4;
WDTCTL = WDTPW + WDTTMSEL + WDTCNTCL + WDTSSEL + WDTIS1; // WDT, ACLK, interval timer
TA0CTL |= TACLR; // Clear Timer_A TAR
__low_power_mode_0(); // Wait for WDT interrupt
TA0CCTL1 ^= CCIS_1; // Create SW capture of CCR1
uint16_t meas_cnt = TACCR1; // Save result
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
P1SEL2 &= ~BIT4;
uart_hex(meas_cnt >> 8);
uart_hex(meas_cnt & 0xFF);
uart_print("\r\n");
if (meas_cnt < 0x5000) {
P1OUT |= BIT0;
} else {
P1OUT &= ~ BIT0;
}
}
}
#pragma vector=WDT_VECTOR
__interrupt void watchdog_timer(void) {
TA0CCTL1 ^= CCIS_1; // Create SW capture of CCR1
__low_power_mode_off_on_exit();
}
Einführung in die digitale Signalverarbeitung
Überblick
- Entscheidend für alle Schritte des digitalen Signalverarbeitung: Abtastzeit TS
- TS bestimmt die Grenzfrequenzen des Eingangs- und Ausgangstiefpass
- Nicht alle digitalen Signalverarbeitungskette besitzen ein Ausgangssignal
- Datenanalyse im digitalen Signalprozessor möglich
Beispiel eines digitalen Filter
-
Differenzengleichung
\[y[k] = 0{,}25 \cdot u[k] + 0{,}25 \cdot u[k-1] +0{,}25 \cdot u[k-2] + 0{,}25 \cdot u[k-3]\]
-
Analyse des Frequenzgangs des digitalen Filters
-
Übertragungsfunktion:
\[ G(z) = 0{,}25 \cdot (1+z^{-1}+z^{-2}+z^{-3}) = 0{,}25 \cdot \frac{z^3+z^2+z+1}{z^3} \]
-
Analyse des Frequenzgangs mit MATLAB:
freqz([.25, .25, .25, .25], [1])
-
- Erstellen des Blockschaltbildes
- Wichtigste Funktionen der DSV:
- Verzögerungsglied (Zugriff auf vergangene Abtastwerte)
- Verstärkungsglied (Multiplikation mit festen Faktor)
- Additionsglied (Addition zweier Signale)
Multiplikation in einem MCU / DSP
- Eine Multiplikation benötigt eine Vielzahl von Schiebe- und Additionsoperationen
- Das Ergebnis einer Multiplikation ist immer doppelt so groß, wie die Eingangswerte:
Bsp. \(15 \cdot 15 = 225\) → \(2\cdot 4\,\text{Bit} = 8\,\text{Bit}\) - Implementierung einer Multiplikation mit Assembler-Sprache: langsamer Programmablauf
- Manche MCU und DSP haben daher einen Hardware-Multiplizierer eingebaut
z. B. Aufbau eines 4-bit Multiplizierer
- Hardware-Multiplizierer des MSP430 (eingebaut in manchen MSP430 der x2xx-Familie)
- Verschiedene Operationen sind möglich:
- Unsigned / Signed Multiply
- Multiply / Multiply Accumulate
- 8bit oder 16bit Operatoren
- Operatoren werden in den entsprechenden Speicherzellen geladen
- Das Ergebnis ist innerhalb eines CPU-Taktes in den Ergebnis-Speicherzellen verfügbar und kann weiterverarbeitet werden
- Verschiedene Operationen sind möglich:
- Beim DSP auch MAC-Einheit genannt
Programmierung von Verzögerungen
Programmieren von Verzögerungen - Erste Idee
uint16_t u_speicher[4] = {0, 0, 0, 0};
uint16_t filter(uint16_t u) {
u_speicher[3] = u_speicher[2];
u_speicher[2] = u_speicher[1];
u_speicher[1] = u_speicher[0];
u_speicher[0] = u;
uint16_t y = 0;
y += 0.25 * u_speicher[0];
y += 0.25 * u_speicher[1];
y += 0.25 * u_speicher[2];
y += 0.25 * u_speicher[3];
return y;
}
- Problem: Werte des Datenspeichers müssen immer "weitergerückt" werden
→ erhöhte CPU-Laufzeit - Verwenden eines Ringspeichers
Programmieren von Verzögerungen - mit Ringspeicher
uint16_t u_speicher[4] = {0, 0, 0, 0};
uint16_t filter2(uint16_t u, uint16_t k) {
u_speicher[k & 0b11] = u;
uint16_t y = 0;
for (uint8_t i = 0; i<4; i++) {
y += 0.25 * u_speicher[i];
}
return y;
}
- Verkettete Verzögerungen von Signalen immer als Ringspeicher implementieren!
- Ringspeicher mit vielen Elementen möglich
- Vereinfachen der Programmierung bei Verwendung einer Zweierpotenz als Größe des Ringspeichers (32, 64, 128, 256, ...)
- Vereinfacher Modulo-Operator
- Division durch Bitverschiebung bei gleichgewichteten Filter → auch ohne MAC-Einheit schnelle Laufzeit!
- Downsampling einer digitalen Signales mit Hilfe eines Ringspeichers
- Erzeugen eines Hall-Effektes mit circa 40000 Verzögerungselementen
Weitere Besonderheiten eines DSP
- Mehrere Bussysteme gleichezeitig aufrufbar
- Hardwaregesteuerte Schleifen: Befehle 50mal ausführen, kein Softwarezähler nötig
- Shifter: Umwandeln von 32bit in 16bit Ergebnissen
- Begrenzer: verhindert Überlauf von Ergebnissen
- Round to nearest:
- MSP430 schneidet Ergebnisse beim Runden immer ab → Ergebnisse werden immer kleiner
- DSP können automatisch Ergebnisse mathematisch runden → <0.5 abrunden, >0.5 aufrunden
Sprungvorhersage
- CPU benötigt mehrere Schritte zum Ausführen eines CPU-Befehls:
- FETCH: Befehl aus den Speicher auslesen
- DECODE: Befehl wird durch Steuerwerk dekodiert
- READ: Operanden werden aus den Speicher geholt
- EXECUTE: Befehl wird ausgeführt
- WRITE BACK: Schreiben des Resultats
- Pipelining: 5 Schritte werden für die vermutlich nächsten fünf Befehle ausgeführt
- Problem: Durch Sprungbefehle können nächsten fünf Befehl meist nicht bestimmt werden
→ Sprungvorhersage (engl. branch prediction) - Verfolgen von unbedingten Sprüngen (JMP, CALL, RETURN)
- Compiler kündigen Schleifen auf eine bestimmte Art an, die vom Prozessor dann erkannt wird
- 95% Genauigkeit der Sprungvorhersage ist erreichbar
Beispiel für die Sprungvorhersage beim Lesen von Datensätzen verschiedener Größe und Reihenfolge:
Gleitkommazahlen
- engl. floating point number → C:
float
- Idee: Abspeichern einer Zahl in Exponentialdarstellung
z. B. \(172{,}625 = 1{,}72625 \cdot 10^2\) - Verwenden der Darstellung mit Basis 2
- Aufbau des Datentypes
float
- Deutlich erhöhter Wertebereich: \(\pm 1.18\cdot 10^{-38} ... \pm 3.4\cdot 10^{38}\)
- Achtung! Diskretisierungsabstand ist nicht konstant:
- Weitere Beispiele:
- Verwendung von Gleitkommazahlen in einen DSP benötigt zwingend eine FPU (floating point unit)
- Verwendung des Datentyps
float
beim MSP430 bedeutet, dass eine Bibliothek verwendet wird, die die Gleitkommazahlen in den MSP430 implementiert.
→ Für Addition und Multiplikation werden viele Taktzyklen benötigt!!!