Εισαγωγή στον MSP430 στο T.I. Launchpad

MSP430 Texas Instruments

Μία ακόμα Development Board που έπεσε στα χέρια μου είναι το Launchpad -μία υλοποίηση της Texas Instruments πάνω στην σειρά μικροελεγκτών MSP430.

Πάμε λοιπόν να φτιάξουμε ένα πολύ βασικό project για να δούμε την χρήση του.

Ο βασικός τρόπος προγραμματισμού του MSP430 είναι μέσω του Code Composer Studio -όχι ο πιο φιλικός προς τον χρήστη τρόπο, αλλά μας επιτρέπει πολύ μεγάλο έλεγχο στο project μας και πολλές επιλογές για debugging -π.χ. να βλέπουμε ανά πάσα στιγμή τις τιμές των Registers-.

Το "παράδειγμα" που δίνει η Texas Instruments αφορά την ενεργοποίηση και απενεργοποίηση του PIN P1.0 (και του κόκκινου LED που είναι συνδεδεμένο σε αυτό).

#include <msp430.h>				

int main(void) {
	WDTCTL = WDTPW | WDTHOLD;		// Απενεργοποίηση WDT για να μην γίνει Reset
	P1DIR |= 0x01;					// Ορίζουμε το Pin 1.0 ως OUTPUT

	for(;;) {
		volatile unsigned int i;

		P1OUT ^= 0x01;		// Εναλλαγή της κατάστασης του Pin 1.0 με Bitwise XOR

		i = 10000;					// Μία επανάληψη για Delay
		do i--;
		while(i != 0);
	}
	
	return 0;
}

Πάμε να εξηγήσουμε όμως λίγο το παραπάνω κομμάτι κώδικα:

Ο Register P1DIR είναι 8bit και καθορίζει το αν ένα PIN θα χρησιμοποιηθεί ως είσοδος ή ως έξοδος. Αν ο P1DIR έχει την τιμή 0x01 (00000001) τότε μόνο το πρώτο PIN (P1.0) θα λειτουργεί ως έξοδος, ενώ τα υπόλοιπα ως είσοδοι. Αν ο P1DIR πάρει την τιμή 00000111 τότε τα πρώτα 3 PINs (P1.0, P1.1 και P1.2) θα λειτουργήσουν ως έξοδοι και τα υπόπολοιπα ως είσοδοι.

Ο Register P1OUT είναι και αυτός 8bit, και καθορίζει αν ένα PIN θα είναι HIGH ή LOW. Αν στον P1OUT βάλουμε την τιμή 0x01 (00000001), τo PINs 1.0 θα γίνει HIGH.

Στο συγκεκριμένο πρόγραμμα χρησιμοποιείται Bitwise XOR για να κάνουμε το PIN 1.0 να αλλάζει καταστάσεις. Κάτι τέτοιο συνηθίζεται αν θέλουμε να αντιστρέψουμε ορισμένα bit. Δηλαδή στην 1η επανάληψη, ο P1OUT θα πάρει την τιμή 00000001, (καθότι 00000000 XOR 00000001 μας δίνει 00000001) το οποίο συνεπάγεται να ενεργοποιηθει το LED που συνδέεται στο 1ο Pin. Στην δεύτερη επανάληψη, έχουμε πάλι Bitwise XOR της τιμής που πήρε ο P1OUT (00000001) με το 00000001, το οποίο μας δίνει 00000000, και το οποίο κάνει τo LED να σβήσει, κ.ο.κ.

Όπως ανέφερα και πιο πριν, το γεγονός ότι μπορούμε να δούμε την τιμή των Registers, ενώ τρέχουμε βήμα-βήμα το sketch, μας δίνει μία πλήρη εικόνα των τιμών που παίρνουν ανά πάσα στιγμή.

Στο τέλος του κώδικα υπάρχει μία do-while loop για να προσθέσει delay στην εναλλαγή καταστάσεων του LED.

MSP430 Registers

Πάμε να εξελίξουμε λίγο το παραπάνω κομμάτι κώδικα, για να ελέξουμε και το PIN 1.6, στο οποίο είναι συνδεδεμένο και το δεύτερο (πράσινο) LED του Launchpad.

Αρχικά θέτω ως OUTPUT και το 1ο PIN, αλλά και το 7ο PIN, βάζοντας στον Register P1DIR το 01000001 (0x41).

Στην συνέχεια στον P1OUT βάζω την "παλιά" τιμή που είχε, XOR (0x41). Δηλαδή αν υποθέτω ότι αρχικά είχε την τιμή 00000000 (0x0), τότε 00000000 XOR 01000001, μας δίνει 01000001 (το οποίο συνεπάγεται να ανάψουν και τα δύο LEDs). Στην επόμενη επανάληψη, που ο P1OUT έχει την τιμή 01000001, θα γίνει 01000001 XOR 01000001, και θα μας δώσει 00000000 (άρα τα LEDS θα σβήσουν). Ο κώδικάς μας γίνεται ως εξής:

#include <msp430.h>				

int main(void) {
	WDTCTL = WDTPW | WDTHOLD;		// Απενεργοποίηση WDT για να μην γίνει Reset
	P1DIR |= 0x41;				// Ορίζουμε τα Pins 1.0 και 1.6 ως OUTPUT (01000001)

	for(;;) {
		volatile unsigned int i;

		P1OUT ^= 0x41;			// Εναλλαγή της κατάστασης των PINs με Bitwise XOR

		i = 10000;					// Μία επανάληψη για Delay
		do i--;
		while(i != 0);
	}
	
	return 0;
}

Μία ακόμα αλλαγή που προσωπικά θέλω να κάνω στο παραπάνω scetch είναι η τελευταία do-while loop, που απλά προσθέτει ένα delay. Πρακτικά δεν γνωρίζω όμως "πόσο" χρόνο θα κάνει να εκτελεστεί. Θα χρησιμοποιήσω την __delay_cycles(), η οποία μου επιτρέπει καλύτερο έλεγχο του χρόνου. Για να έχω όμως σωστό έλεγχο του χρόνου πρέπει να γνωρίζω την συχνότητα του ρολογιού μου. Μπορώ να διαβάσω τον Register DCOCTL -ή ακόμα καλύτερα να τον θέσω εγώ βάσει των αναγκών του συγκεκριμένου προγράμματος: Μιας και δεν έχουμε κάτι απαιτητικό από πλευράς ρολογιού, θα τον θέσω στην "ελάχιστη" συχνότητα λειτουργίας του, στο 1Mhz.Το sketch μου γίνεται ως εξής:

#include <msp430.h>				

int main(void) {
	WDTCTL = WDTPW | WDTHOLD;	// Απενεργοποίηση WDT για να μην γίνει Reset
	BCSCTL1|=CALBC1_1MHZ;
	DCOCTL|=CALDCO_1MHZ;       //Ορίζουμε την συχνότητα του DCO στο 1Mhz
	P1DIR |= 0x41;			// Ορίζουμε τα Pins 1.0 και 1.6 ως OUTPUT (01000001)

	for(;;) {
		P1OUT ^= 0x41;		// Εναλλαγή της κατάστασης των PINs με Bitwise XOR
		__delay_cycles(1000000); //Πλέον γνωρίζω ότι καθυστέρηση 10^6 κύκλων είναι 1 δευτερόλεπτο
	}
	
	return 0;
}

MSP430 Registers

Και εδώ έρχεται το point ότι υπάρχει και ένας εναλλακτικός τρόπος προγραμματισμού του MSP430 στο Launchpad -που μας δίνει ένα "γνώριμο" IDE, το Energeia. Φτιάξαμε λοιπόν και "εκεί" ένα sketch να κάνει το ίδιο με το παραπάνω.

#define LED RED_LED
#define LED2 GREEN_LED

void setup() {
  pinMode(LED, OUTPUT);
  pinMode(LED2, OUTPUT);
}

void loop() {
  digitalWrite(LED, HIGH);
  digitalWrite(LED2, HIGH);  
  delay(1000);              
  digitalWrite(LED, LOW);
  digitalWrite(LED2, LOW);
  delay(1000);             
}

MSP430 Energeia

Είναι σαφές ότι στο Energeia μπορούμε πολύ πιο εύκολα/γρήγορα να κάνουμε prototyping ενός Project. Παρ' όλα αυτά είναι πολύ χρήσιμο να γνωρίζουμε και τι γίνεται σε χαμηλότερο επίπεδο, ώστε αν χρειαστεί, να κάνουμε εκεί troubleshooting. Αναγνωρίζω ότι P1DIR |= 0x01 είναι πιο δυσνόητο από το pinMode(LED, OUTPUT), όπως και το P1OUT |= 0x01 είναι πιο δυσνόητο από το digitalWrite(LED, HIGH), αλλά υπάρχει άμεση αντιστοιχία την οποία ήθελα να δείξω.

Κατά τ' άλλα τόσο το Launchpad, όσο και ο μικροελεγκτής MSP430 με έχουν βολέψει αρκετά μέχρι σήμερα -ίσως ήταν και μία ευκαιρία να δείξω ότι ο κόσμος δεν περιστρέφεται μόνο γύρω από το Arduino και την Atmel.- Το ποιος μικροελεγτής είναι "καλύτερος" για ποιο project είναι ένα άλλο μεγάλο κεφάλαιο που θέλω στο μέλλον να καλύψω.

MSP430 Energeia

aByte