Tux trifft MSP430-Launchpad
Aus BraLUG-Wiki
(→MSP430-Launchpad) |
(→MSP430-Launchpad) |
||
| Zeile 11: | Zeile 11: | ||
==MSP430== | ==MSP430== | ||
==MSP430-Launchpad== | ==MSP430-Launchpad== | ||
| − | ... | + | Das [http://www.ti.com/lit/ug/slau318d/slau318d.pdf MSP-EXP430G2 LaunchPad] vom TI bietet ideale Moglichkeiten für den Einstieg in die MSP430-Welt. Kauft man sich dieses Board für wenig Geld (je nach dem, wo, weit unter 10€), findet man folgendes in der kleinen Schachtel: |
| + | * das Launchpad-Board selbst | ||
| + | * ein Mini-USB-B Kabel | ||
| + | * zwei MSP430-MCUs (bei Launchpad Rev. 1.5: [[Tux trifft MSP430-Launchpad#MSP430G2553|MSP430G2553]], [[Tux trifft MSP430-Launchpad#MSP430G2452|MSP430G2452]]) | ||
| + | * einen 32,768kHz Uhrenquarz (damit kann man das Board entsprechend nachbestücken, siehe Dokumentation) | ||
| + | * zwei 10-polige Stiftleisen, eine kleine Anleitung und ein paar Sticker | ||
| + | |||
| + | |||
| + | Das Launchpad-Board ist mit allem ausgerüstet, was man für die ersten Experimente benötigt: | ||
| + | * ein 20-pin DIP Sockel, in den alle MSP430G2xxx mit 14 oder 20 Pins passen sollten (sämtliche Pins sind auf Stiftleisten herausgeführt) | ||
| + | * zwei "frei programmierbare" LEDs | ||
| + | * ein "frei programmierbarer" Taster | ||
| + | * ein Reset-Taster | ||
| + | * ein Programmier- und Debugging-Interface (cool, innerhalb der Atmel-Welt muss man sich soetwas für viel Geld dazukaufen!) | ||
| + | * ein paar Jumper zur Hardware-Konfiguration des Boards (sind beschriftet bzw. auch in der entsprechenden Dokumentation beschrieben) | ||
| + | * ein USB-Anschluß | ||
| + | |||
| + | |||
| + | Auf dem mitgelieferten MSP430G2553 ist ein [http://www.ti.com/lit/zip/slac435 Beispielprogramm] vorinstalliert (blinkende LEDs, Abfrage des internen Temperatursensors usw.), aber wir wollen ja selbst ein paar Programme schreiben... | ||
Version vom 26. Juli 2013, 12:52 Uhr
Derzeit noch Baustelle...!
Inhaltsverzeichnis |
Warum ein MSP430-Launchpad?
Hardware
MSP430
MSP430-Launchpad
Das MSP-EXP430G2 LaunchPad vom TI bietet ideale Moglichkeiten für den Einstieg in die MSP430-Welt. Kauft man sich dieses Board für wenig Geld (je nach dem, wo, weit unter 10€), findet man folgendes in der kleinen Schachtel:
- das Launchpad-Board selbst
- ein Mini-USB-B Kabel
- zwei MSP430-MCUs (bei Launchpad Rev. 1.5: MSP430G2553, MSP430G2452)
- einen 32,768kHz Uhrenquarz (damit kann man das Board entsprechend nachbestücken, siehe Dokumentation)
- zwei 10-polige Stiftleisen, eine kleine Anleitung und ein paar Sticker
Das Launchpad-Board ist mit allem ausgerüstet, was man für die ersten Experimente benötigt:
- ein 20-pin DIP Sockel, in den alle MSP430G2xxx mit 14 oder 20 Pins passen sollten (sämtliche Pins sind auf Stiftleisten herausgeführt)
- zwei "frei programmierbare" LEDs
- ein "frei programmierbarer" Taster
- ein Reset-Taster
- ein Programmier- und Debugging-Interface (cool, innerhalb der Atmel-Welt muss man sich soetwas für viel Geld dazukaufen!)
- ein paar Jumper zur Hardware-Konfiguration des Boards (sind beschriftet bzw. auch in der entsprechenden Dokumentation beschrieben)
- ein USB-Anschluß
Auf dem mitgelieferten MSP430G2553 ist ein Beispielprogramm vorinstalliert (blinkende LEDs, Abfrage des internen Temperatursensors usw.), aber wir wollen ja selbst ein paar Programme schreiben...
MSP430G2452
Datenblatt MSP430G2452 Wichtigste Hardwareeigenschaften:
- 16-Bit RISC CPU
- Versorgungsspannung: 1,8V ... 3,6V
- geringer Stromverbrauch
- CPU-Takt bis 16MHz intern konfigurierbar
- 8kByte Flash
- 256Byte RAM
- 16 I/O-Ports
- 1 16-Bit-Timer,
- WatchDog-Timer
- 1x USI (I2C/SPI)
- 8 Kanäle 10-bit ADC
MSP430G2553
Datenblatt MSP430G2553 Wichtigste Hardwareeigenschaften:
- 16-Bit RISC CPU
- Versorgungsspannung: 1,8V ... 3,6V
- geringer Stromverbrauch
- CPU-Takt bis 16MHz intern konfigurierbar
- 16kByte Flash
- 512Byte RAM
- 16 I/O-Ports
- 2 16-Bit-Timer
- WatchDog-Timer
- 1x USCI (I2C/SPI/UART/IrDA)
- 8 Kanäle 10-bit ADC
Toolchain
Von TI werden für die MSP430-Serie (und damit auch für das MSP430-Launchpad) diverse Entwicklungsumgebungen empfohlen und angeboten. Diese sind allerdings ausschließlich nur für Windows-Betriebssysteme verfügbar und in den kostenlosen Versionen im Funktionsumfang teilweise stark beschränkt...
Wir wollen uns natürlich auf die Linux-Plattform konzentrieren! Dort ist eine leistungsfähige (und 100% freie) Alternative verfügbar. Folgende Pakete sind Bestandteil vieler Debian-Derivate (z.B. auch Ubuntu):
- binutils-msp430
- gcc-msp430
- gdb-msp430
- msp430-libc
- msp430mcu
- mspdebug
Auf diese Entwicklungsumgebung beziehen sich die nachfolgenden Ausführungen in diesem Beitrag.
Wer von der Arduino-Fraktion kommt, wird vielleicht Gefallen an Energia, als "Arduino-IDE-ähnliche" Toolchain finden...
"Hello World"
In der Folge soll kurz beschrieben werden, wie man ein (einfaches) Programm für einen MSP430-Launchpad übersetzt und auf die MCU überträgt. Weiterhin wird kurz aufgezeigt, wie man mit dem Debugger direkt auf der MCU arbeiten kann.
Das Programm
Das erste Programm ist immer ein "Hello World". Bei einem Mikrocontroller bietet es sich dazu an, ein paar Ausgänge zyklisch ein- und auszuschalten. Hier der entsprechende C-Quelltext, mit dem die beiden, auf dem Launchpad vorhandenen LEDs als Wechselblinker zyklisch angesteuert werden:
#include <msp430.h>
#define LED_RED BIT0 // rote LED an PIN0
#define LED_GREEN BIT6 // gruene Led an PIN6
//***************************************
void delay_ms(unsigned int ms){
while(ms--){
__delay_cycles(1000);
}
}
//***************************************
int main(void){
WDTCTL = WDTPW + WDTHOLD; // watchdog ausschalten
P1DIR = LED_RED | LED_GREEN; // LED-Pins als Ausgaenge
P1OUT = LED_GREEN; // gruene LED ein
while(1) { // Enlosschleife
P1OUT ^= LED_RED + LED_GREEN; // LEDs toggle
delay_ms(500); // 500ms Pause
}
}
Programm übersetzen und auf MCU übertragen
C-Quelltext übersetzen, wobei der Code für einen MSP430G2452 erzeugt wird:
msp430-gcc -mmcu=msp430g2452 -o blink.elf blink.c
Die Übertragung auf den Mikrocontroller erfolgt mit Hilfe des Kommandozeilen-Tools mspdebug:
> mspdebug rf2500 ... (msdebug) prog blink.elf Erasing... Programming... Writing 186 bytes to e000 [section: .text]... Writing 32 bytes to ffe0 [section: .vectors]... Done, 218 bytes written
Innerhalb der mspdebug-Shell kann das Programm mit dem Befehl run gestartet werden:
(mspdebug) run Running. Press Ctrl+C to interrupt...
Natürlich läuft das Programm auch ohne mspdebug. Dazu beendet man das Tool mit dem Befehl exit.
Da man obige Befehlsfolgen wahrscheinlich nicht immer wieder neu eingeben möchte, hier ein entsprechendes Makefile, in dem alle notwendigen Aktionen zusammengefasst sind:
PROJ=blink
CC=msp430-gcc
MCU=msp430g2452
CFLAGS=-Os -g -Wall -mmcu=$(MCU)
LDFLAGS=-g -mmcu=$(MCU)
OBJS=$(PROJ).o
all:$(OBJS)
$(CC) $(LDFLAGS) -o $(PROJ).elf $(OBJS)
msp430-size $(PROJ).elf
clean:
rm -fr $(PROJ).elf $(OBJS)
flash:
mspdebug rf2500 'erase' 'load $(PROJ).elf' 'exit'
Debuggen
Debugproxy auf Port 2000 starten:
> mspdebug rf2500 ... (mspdebug) gdb Bound to port 2000. Now waiting for connection...
Kommadozeilen-Debugger starten und mit Debugproxy verbinden:
> msp430-gdb blink.elf ... (gdb) target remote localhost:2000 ... (gdb)
(Anmerkung: Inhalt von z.B. P1OUT ausgeben → print/x __P1OUT)
...oder etwas komfortabler, z.B. mit KDbg:
> kdbg -r localhost:2000 blink.elf
MSP430-Hardware mit Software erforschen
Port-Input
Taste betätigt?
#include <msp430.h>
#define LED BIT0
#define BUTTON BIT3
//***************************************
int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // WatchDog ausschalten
P1DIR = LED; // LED-Pin als Ausgang
P1DIR &= ~BIT3; // Button als Eingang
P1REN |= BUTTON; // Pull-Up-Widerstand einschalten
P1OUT &= ~LED; // LED ausschalten
while (1) { // Endlosschleife
if ((P1IN & BUTTON) == 0) { // Taste gedrueckt?
P1OUT |= LED; // ja --> LED an
} else {
P1OUT &= ~LED; // nein --> LED aus
}
}
}
Ein-/Aus-Schalter mit Entprellung
#include <msp430.h>
#define LED BIT0
#define BUTTON BIT3
#define DEBOUNCE_MS 50
//***************************************
void delay_ms(unsigned int ms){
while(ms--){
__delay_cycles(1000);
}
}
//***************************************
char button_pressed(void) {
if ((P1IN & BUTTON) == 0) {
delay_ms(DEBOUNCE_MS);
if ((P1IN & BUTTON) == 0) return 1;
}
return 0;
}
//***************************************
int main(void)
{
char toggle = 0;
WDTCTL = WDTPW + WDTHOLD;
P1DIR = LED;
P1DIR &= ~BIT3;
P1REN |= BUTTON;
P1OUT &= ~LED;
while (1) {
if (button_pressed()) {
if (!toggle) {
P1OUT ^= LED;
toggle = 1;
}
} else {
toggle = 0;
}
}
}
Watchdog-/Port-Interrupt
Ein-/Aus-Schalter über Port- und Watchdog-Interrupt
#include <msp430.h>
#define LED BIT0
#define BUTTON BIT3
//***************************************
int main(void)
{
WDTCTL = WDTPW+WDTHOLD; // WatchDog ausschalten
P1DIR = LED; // Ausgang
P1DIR &= ~BUTTON; // Eingang
P1REN |= BUTTON; // Pull-Up ein
P1IES |= BUTTON; // Interrupt Port 1 bei Hight --> Low
P1IFG &= ~BUTTON; // Interrupt-Flag fuer Button-Pin loeschen
P1IE |= BUTTON; // Interrupt fuer Button-Pin einschalten
P1OUT &= ~LED; // LED aus
_BIS_SR(LPM0_bits+GIE); // Low Power Mode 0 und Interrupts generell ein
return 0;
}
//***************************************
// Interrupt-Routine Port 1
//***************************************
#pragma vector=PORT1_VECTOR
__interrupt void PORT1_ISR(void)
{
static unsigned char toggle = 0;
P1IFG &= ~BUTTON; // Interrupt-Flag fuer Button-Pin loeschen
P1IE &= ~BUTTON; // Interrupt fuer Button-Pin ausschalten
WDTCTL = WDT_MDLY_32; // WatchDog-Timer 32ms starten
IFG1 &= ~WDTIFG; // Interrupt-Flag fuer WatchDog loeschen
IE1 |= WDTIE; // WatchDog-Interrupt einschalten
if (!toggle) {
P1OUT ^= LED; // LED umschalten
toggle = 1;
P1IES &= ~BUTTON; // Interrupt Port 1 bei Low --> Hight
} else {
toggle = 0;
P1IES |= BUTTON; // Interrupt Port 1 bei Hight --> Low
}
}
//***************************************
// Interrupt-Routine Watchdog
//***************************************
#pragma vector=WDT_VECTOR
__interrupt void WDT_ISR(void)
{
IE1 &= ~WDTIE; // WatchDog-Interrupt ausschalten
IFG1 &= ~WDTIFG; // Interrupt-Flag fuer WatchDog loeschen
WDTCTL = WDTPW + WDTHOLD; // WatchDog ausschalten
P1IE |= BUTTON; // Interrupt fuer Button-Pin einschalten
}
Anmerkung: Bei meinem Lauchpad scheint der Taster ab und zu länger wie 32ms zu prellen und damit verschluckt sich die Logik machmal. Eigentlich ist es also sinnvoller, die Entprellung über einen Timer zu realisieren, den man an die spezifischen Hardwaregegebenheiten anpassen kann.
Timer
Wechselblinker mit Timer
#include <msp430.h>
#define LED_RED BIT0 // rote LED an PIN0
#define LED_GREEN BIT6 // gruene Led an PIN6
//***************************************
int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // WatchDog ausschalten
P1DIR = LED_RED | LED_GREEN; // LED-Pins als Ausgaenge
P1OUT = LED_GREEN; // gruene LED ein
TACTL = TASSEL_2 + MC_2; // Timer A: SMCLCK, Continuous-Mode
CCTL0 = CCIE; // Capture-/Compare-Interrupt ein
_BIS_SR(LPM0_bits+GIE); // Low Power Mode 0 und Interrupts generell ein
return 0;
}
//***************************************
// Interrupt-Routine TimerA0
//***************************************
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A(void)
{
static unsigned char counter = 0;
counter++;
if (!(counter%4)) // Takt noch ein wenig teilen...
P1OUT ^= LED_RED + LED_GREEN; // LEDs toggle
}
PWM (LED dimmen)
#include <msp430.h>
#define LED BIT6;
//***************************************
int main(void)
{
WDTCTL = WDT_MDLY_32; // Watchdog 32ms
IE1 |= WDTIE; // Watchdog-Interrupt ein
P1DIR |= LED; // LED als Ausgang
P1SEL |= LED; // LED angesteuert via PWM (Timer A0)
TA0CCR0 = 1000; // PWM-Periode
TA0CCR1 = 1; // PWM-Duty-Cycle (initial)
TA0CCTL1 = OUTMOD_7; // PWM-Output-Mode (siehe Datenblatt...)
TA0CTL = TASSEL_2 + MC_1; // Timer A: SMCLK (1MHz) und CCR0 aufwaerts
_BIS_SR(LPM0_bits + GIE); // Low Power Mode 0 und Interrupte ein
return 0;
}
//***************************************
// Interrupt-Routine WatchDog
//***************************************
#pragma vector=WDT_VECTOR
__interrupt void watchdog_timer(void)
{
static int direction = 1;
TA0CCR1 += direction*20; // PWM-Duty-Cycle neu setzen
if( TA0CCR1 > 980 || TA0CCR1 < 20 ) // Richtung umschalten
direction = -direction;
}
Weiterführende Links
Datenblätter:
Toolchain & IDEs:
- http://wiki.ubuntuusers.de/MSP430-Toolchain
- http://recursive-labs.com/static/courses/rl100/samples/mspstart.pdf
- http://www.itopen.it/2013/03/01/msp430-energia-on-linux/
- http://launchpadlinux.blogspot.de/2012/10/making-thinks-easier-with-make-and-geany.html
mspdebug:
MSP430-Basics:
- http://processors.wiki.ti.com/index.php/Category:MSP430
- http://dbindner.freeshell.org/msp430/
- http://www.mikrocontroller.net/articles/MSP430_Codebeispiele
- http://homepages.ius.edu/RWISMAN/C335/HTML/msp430Timer.HTM
GDB:
- http://www.cs.umd.edu/~srhuang/teaching/cmsc212/gdb-tutorial-handout.pdf
- http://www.mail-archive.com/mspgcc-users@lists.sourceforge.net/msg10262.html