SPI Kommunikation mit dem PIC18F4550

Was ist SPI?

SPI (=Serial Peripheral Interface) ist, wie der Name bereits sagt, eine Schnittstelle für die serielle Übertragung von Daten zwischen zwei (oder mehr) Komponenten (das können z.B. Mikrocontroller, der serielle Port eines PCs oder sonstige periphere Komponenten mit denen Daten ausgetauscht werden sollen). Seriell heist, das die Daten in einer Richtung immer nacheinander übertragen werden, also bit für bit, im Gegensatz zur gleichzeitigen Übertragung mehrere Bits wie bei paralleln Schnitstellen.

Das MSSP Modul (mehr dazu weiter unten) von Microchips PIC18F Modellen sendet Daten dabei immer in Paketen von 8 bit, also einem byte.

SPI ist vollduplex-fähig, d.h. es koennen Daten gleichzeitig gesendet und empfangen werden, da das Senden und das Empfangen über getrennte Leitungen erfolgt.

Die Taktung des SPI Buses wird vorgeben durch den Master (in unserem Fall der PIC), die Taktung wird ueber eine dedizierte Leitung (SCK/Takleitung) an alle anderen Teilnehmer des Buses geleitet.

SPI ist jedoch nicht gleich SPI, damit sich zwei oder mehr Komponenten unterhalten koennen, muessen ein paar Parameter eingehalten werden die alle Kompoenten gemeinsam haben. Unter anderem sind das folgende:

  • Die maximale Wortlaenge, also wie viele Bits in einem rutsch uebertragen werden koennen (beim MSSP des PIC sind wir limitiert auf 8 bit, wobei das meist unerheblich ist, da auch Pausen bei der Übetragung kein Problem sein sollten, da die Clock (Taktleitung) ebenfalls in einen idle-Status (=Wartestatus / pausiert) gesetzt wird wenn keine Daten übertragen werden, die Zeit bleibt also quasi stehen für die Teilnehmer der SPI Kommunikation.
  • die maximale Taktrate die alle Komponenten zum senden und empfangen von Daten gemeinsam haben. Das MSSP Modul des PIC18F4550 kann entweder mit 1/4, 1/16 oder 1/64 des Taktes des Quarzes (FOSC) arbeiten (der PIC18F Prozessor benoetigt zur Verarbeitung eines Befehls 4 Takte, somit entspricht TOSC = 1/4*FOSC) in oder aber mit der Haelfte des Taktes von Timer 2 Ausgangs (TMR2). Mit dem PIC18F4550 der eine maximale FOSC von 48 Mhz (entspricht 12 Mhz TOSC) vertraegt (laut Datenblatt) als Master ist somit eine maximale Taktung auf dem SPI Bus von 12 Mhz moeglich (entspricht 12 MBit/s; Achtung: Im Datenblatt des PIC1844550 steht hier ein Wert von 2.00Mbps, das ist ein Typo!)
  • die Uebrtragungsreihenfolge der Bits: MSB (=most siginifacnt bit) oder LSB (=leas significant bit), also ob das „Wort“ (dit Bitfolge an Daten) in der Reihenfolge vom hoechsten bit zum niedrigsten bit (MSB) erfolgt oder umgekehrt (LSB).
  • die polaritaet des Taktes (also ob die Clock im Ruhezustand low oder high ist), diese Einstellung wird abekuerzt mit CPOL (=clock polarity) und kann im PIC ueber das bit CKP (=Clock Polarity Select) bit im Register SSPCON1 gesetzt werden
  • der Zeitpunkt wann Daten vom Slave (sofern er welche sendet) an den Master gesendet werden, gemessen an der Flanke des Taktsignals. Diese Einstellung wird mit CPHA (=clock phase) bezeichnet. Damit der Master die Daten also zum richtigen Zeitpunkt einliest muss auch diese Einstellung bei allen Komponenten gleich sein. Im PIC werden dazu die beiden bits SMP (=sample bit) und CKE (=SPI Clock Select bit) im SSPSTAT Register gesetzt. Mehr Details dazu spaeter im Sourcecode.
  • Die beiden Einstellungen CPOL und CPHA erlauben vier verschiedene Einstellungen, oder Modi, in denen eine SPI kommunikation erfolgen kann. Das MSSP Modul des PIC unterstuetzt alle 4 Modi die ueber die enstprechenden Register SSPSTAT und SSPCON1 konfiguriert werden koennen

Der PIC18F4550 (gilt gleichermaßen fuer den PIC18F4455 (40 bzw 44 Pins), PIC18F2550 (28 Pins) und PIC18F2455 (28 Pins)) besitzt ein hardware Modul für die serielle Kommunikation namens „MASTER SYNCHRONOUS SERIAL PORT“ (kurz MSSP). Mit diesem Modul ist die serielle Kommunikation mit andern ICs/MCUs (z.B. mit anderen PIC Microcontrollern, Speicherbausteinen, Port-Multipliern, Treiber-Bausteinen und vielen anderen Komponenten) moeglich. das MSSP Modul kann dabei in zwei verschiedenen Modi betrieben werden:

  • SPI Modus, dem „Serial Peripheral Interface“, also eine serielle Schnitstelle zum ansteuern von diversen peripheren Komponenten (Slaves) an einen Master (z.B. einen Microcontroller).
  • I2C Modus, dem „Inter-Integrated Circuit“ Interface, ebenfalls eine serielle Schnittstelle bei der jedoch ein paar Unterschiede zur SPI Schnittstelle gelten. Insbesondere kommt I2C mit zwei Leitungen aus (SDA(=Daten) und SCL(=Clock)) wohingegen SPI drei Leitungen benötigt. Bei I2C werden die Daten-Pakete oder Nachrichten mit Empfägeradresse versehen so das es nicht notwendig ist wie bei SPI für jeden Teilnehmer eine Slave-Select Leitung zu legen (abhängig vom Anwendungsfall kann das auch entfallen bei SPI), die Datenübertragung per SPI ist jedoch schneller und der Overhead pro Nachricht ist geringer. Weitere Infromatinen zum Vergleich der beiden Schnittstellen werden im Artikel SPI vs I2C erklärt.un

das MSSP Modul kann im SPI Modus in zwei verschiedenen Rollen agieren: als Master oder als Slave (Eine Erklärung zwischen den beiden Begriffen hier Artikel „Master und Slave…„). Zusaetzlich koennen noch grundlegende Kommunikationsparameter konfiguriert werden die klären wann genau Daten im Verhältnis zur Taktfrequenz zu senden sind von den Teilnehmern und die das Taksignal aussieht.

Zu Begin betrachten wir den Einsatz als SPI-Master, der PIC wird also als Master Daten über das SPI Interface senden.

SPI Grundlagen

Für die Kommunikation sind Hardwareseitig in einfachsten Fall mindestens drei Leitungen (gemeinsame Masse-Verbindung vorausgesetzt, andernfalls 4 Leitungen) erforderlich zwischen den Teilnehmern der Kommunikation (ein Master und ein Slave), bei mehreren Slaves die an einen Master angeschlossen werden sollen und die dediziert angesprochen werden sollen, ist zu dem pro Slave eine weitere Leitung notwendig. Zudem müssen die Teilnehmer natürlich eine gemeinsame Masse-Verbindung (Ground/GND) aufweisen, sonst fliesst ja kein Strom auf der Datenleitung.

Dabei haben die Leitungen folgende Funktionen:

Bezeichnung alternative Bezeichnung Funktion
SCK (=serial clock) SCLK (=serial clock) Transportiert das Taktsignal (=Clock), dass der Master generiert an dem sich alle Slaves orientieren
SDI (=serial data in) MOSI bzw. MISO (je nach Komponente) Der PIN eines Master oder Slaves an dem Daten eingehen, also empfangen werden
SDO (=serial data out) MOSI bzw. MISO (je nach Komponente) Der PIN eines Master oder Slaves an dem Daten ausgehen, also gesendet werden.
SS (slave select) CS (=chip select), STE (=slave transmit enable) Wird in der Regel nur bei mehreren Slaves benoetigt, pro Slave wird eine Slave Select-Leitung benötigt, in Schaubildern dann meisst durch aufsteigende Nummern gekennzeichnet: SS1, SS2, SS3… Der PIN RA5/SS des PIC wird benoetigt wenn der PIC selbst als Slave aggiert in der SPI Kommunikation. Ist der PIC der Master kann ein bzw. mehrere beliebige Asugangs PINs des PICs als CS/SS Pin gewaehlt werden und ueber die Software gesteuert werden.
Sonstige: MOSI (=Master Out, Slave In) SIMO (=Slave Out, Master In) Im Prinzip eine uebergreifende Bezeichnung fuer die DatenLEITUNG (im Gegensatz zum PIN selbst) auf welcher der Master Daten zum Slave sendet, die unabhängig davon ist ob man den Master oder den Slave Baustein betrachtet. Bei einem Slave kann MOSI auch dem SDI PIN entsprechen, da der Slave auf diesem PIN Daten empfaengt. beim Master ist jedoch der PIN SDO dem MOSI gleichzusetzen, da er ja hier Daten sendet.
MISO (=Master In, Slave Out) SOMI (=Slave Out, Master In) Im Prinzip eine übergreifende Bezeichnung fuer die DatenLEITUNG auf der der Master Daten empfängt. Dabei ist es egal ob man einen PIN beim Master oder den Slave Baustein betrachtet. Bei einem Slave führt die MISO Leitung immer zum SDO PIN, da der Slave auf diesem PIN Daten zuruük an den Master sendet. Beim Master ist der PIN SDI an der MISO Leitung angeschlossen, da er ja hier Daten sendet.

Die verwendeten IO-PINs des PIC

Die PINs fuer SCK, SDI und SDO sind bei der Verwendung des MSSP Moduls bei den meisten PICs durch das Hardware Layout fest vorgegeben (eine Ausnhame stellen die neuen PIC18F und PIC24F chips da, deren PINs dynamisch gewissen Funktionen zugewiesen werden koennen, eine sehr praktische Sache, aber das soll uns aktuell nicht weiter beschaeftigen da wir uns auf den PIC18F4550 und seine direkten Verandten konzentrieren). Die ggf. benoetigten PINs fuer die Slave Select Leitungen sind im Prinzip frei waehlbar (Achtung: gilt nur wenn der PIC der Master ist, im Slave Modus ist der Slave Select PIN vorgegeben, er liegt an PIN 5 des Ports A an RA5/SS und ist als digitaler Eingang zu konfigurieren) unter den vorhanden, freien PINs des PICs da diese spaeter ueber die Software gesteuert werden.

Im Falle des PIC18F2455/2550 bzw. PIC18F4550/2550 hilft uns ein Blick in das Datenblatt um zu sehen welche IO-PINs des Mikrochip die entstprechende Funkion aufweisen.
2550_spi

Die enstprechenden PINs für die SPI Schnittstelle sind im rechten Schaubild farblich markiert.

Wie man sieht sind bei beiden Typen die Belegung der Funktionen auf den Ports identisch (lediglich die PIN Number variiert).

SCK (Clock) liegt auf Port B und dort dem ersten PIN des Ports, also auf RB1.

SDI (Dateneingang) liegt ebenfalls auf Port B auf Pin null, also auf RB0.

SDO (Datenausgang) liegt auf Port C auf Pin sieben, also auf RC7.
pic4550_SPI

Bei anderen PIC Modellen kann die Belegung abweichen und es sollte immer das entsprechende Datenblatt herangezogen werden welches auf der microchip-webseite heruntergeladen werden kann.

Erklärung für Einsteiger: Wie man sieht haben viele PINs mehr als nur eine Funktion. So sind die PINs die wir hier im Beispiel für die SPI Kommunikation benutzen auch für andere Zwecke einsetz bar. Welche Funktion ein PIN tatsaechlich hat wird immer in der Software bestimmt die auf dem PIC laeuft. In den Datenblättern von Microchip werden in den Schaubildern der Chips immer alle PINs nummeriert und als Bezeichner werden alle Abkürzungen für all möglichen verschiednen Funktionen dieses PINs genannt. In dem Bild auf der Linken Seite vom PIC18F2455/PIC18F2550 sieht man z.B. das der PIN mit der Nummer 22 die Bezeichnung „RB1/AN10/INT1/SCK/SCL“ hat. Dies beschreibt die folgenden möglichen Funktionen zur Nutzung dieses PINs:

RB1 = es handelt sich um den zweiten PIN (es wird immer bei 0 angefangen zu zählen) aus dem PORT B des Mikrocontroller, ein Port ist quasi eine Gruppierung von einzelnen PINs. Pro Port gibts es bis zu 8 Pins. Die Ports werden meisst A, B, C, D… genannt, wobei die Anzahl an Ports variiert je nachdem wie viele PINs der eingestze Mikrocontroller hat und je nachdem wieviele IO-PINs (=Input-Output PINs, also PINs die als Ein- oder Ausgang genutzt werden können) insgesammt zur Verüfgung stehen.

AN10 = diese PIN kann auch als AD (=Analog-Digital-Wandler) genutzt werden, also ein Eingang bei dem ein analoges Signal in einer gewissen Auflösung abgetastet werden kann, z.B. um die anliegende Spanung zu messen

INT1 = diese PIN kann gentutzt werden um einen Interrupt von einer externen Komponente auslösen zu lassen, in dieser Funktion ist der PIN also auch ein Eingang

SCK = über diesen PIN kann das Taktsignal bei der Kommunikation mit dem MSSP Modul im SPI Modus ausgegeben (wenn der Mikrocontroller der Master ist) bzw. emfpangen werden (wenn der Mikrocontroller der Slave ist).

SCL = über diesen PIN kann das Taktsignal bei der Kommunikation mit dem MSSP Modul im I2C Modus ausgegeben (wenn der Mikrocontroller der Master ist) bzw. emfpangen werden (wenn der Mikrocontroller der Slave ist).

Alle Abkürzungen und Funktionen der PINs werden auch immer im Datenblatt detailiert erläutert. Die Datenblätter zu den verschiedenen Modellen von Mikrocontrollern können in der Regel immer kostenfrei auf den Seiten der Hersteller heruntergeladen werden. Für den hier vorgestellten PIC sind die Daten aller IO Pins auf Seite 12ff im Datenblatt zu finden

Ein PIN kann zu einem gewissen Zeitpunkt immer nur eine Funktion haben, jedoch kann man im Programm zur Laufzeit die Funktion des PINs aendern, wovon wir jedoch hier einmal absehen in diesem einfachen Beispiel.

In unserem Programm wird der PIN RB0 (RBO/AN12/INT0/FLT0/SDI/SDA) immer als digitaler Ausgang zum senden von seriellen Daten verwendet, der PIN RB1 (RB1/AN10/INT1/SCK/SCL) immer als digitaler Ausgang zum ausgeben des Taktes für die SPI Kommunikation und RC7 (RC7/RX/DT/SDO) immer als digitaler Eingang zum empfangen von Daten. Besonderes augenmerkt sollte hier auf das Stichwort „digital“ gelegt werden, da die PINs RB1 und RB0 auch als analoge Eingaenge genutzt werden koennen (AN10 und AN12 im Schaubild deutet an, dass hier ein Analog/Digital Wandler aktiviert werden kann), dies muss man wissen, da diese PINs explizit auf digital umgestellt werden sollten, da anonsten insbesondere der SDI Pin nicht korrekt funktionieren wird, da das MSSP Modul natuerlich logische Werte 1 und 0 erwartet und keine analogen Werte. Wir werden also spaeter sehen das wir in unserem Programm die PINs zu begin auf digital umstellen.

Hardware Layout für die Demo

Ermittlung der notwendigen SPI Parameter

Widmen wir uns nun also dem ersten Programmteil, in welchem das MSSP Modul als SPI Master konfiguriert wird.

Zuerst muss einmal geklaert werden, mit welcher Komponente unser PIC sich unterhalten soll und damit welche SPI Konfigurationsparameter diese Komponenten erwartet. Konkret muss folgendes geklaert werden (steht meist in den Datashets der Komponenten oder kann aus einem darin enhaltenen Diagramm abgelesen werden) damit wir wissen wie das MSSP Modul konfiguriert werden muss.

Konkret muss folgendes herausgefunden werden:

  • maximale SPI Taktrate der anzusprechenden Komponente [relevant fuer das Senden und das Empfangen von Daten]
  • die Clock-Polarity, also ist die Leitung SCK auf high (1) oder low (0) wenn gerade kein Takt auf der Leitung angelegt ist (der Takt wird nur angelegt wenn auch tatsaechlich Daten transferiert werden!) [relevant sowohl fuer das Senden und das Empfangen von Daten]
  • wann sollen am Master (=PIC in diesem Fall) eingehende Daten auf SDI (dem Eingang am PIC) gesampled (also abgegriffen) werden, (=Data Input Sample Phase) Soll dies bei einer steigenden Flanke des Taktsignals erfolgen oder bei der fallenden? [nur relevant fuer das Empfangen von Daten]
  • wann sollen Daten vom Master gesendet werden auf SDO, bei einer steigenden Flanke oder ein fallende Flanke des Taktsignals (=Clock Edge)? [nur relvant fuer das Senden von Daten]

Im Prinzip koennen alle Werte einfach auch durch Trial-and-Error ertestet werden, kaputt gehen kann dabei eigentlich nichts (keine Gewaehr auf diese Aussage!), es werden meist nur Daten nicht korrekt erkannt. Man kann also einfach eine niedrige Taktrate einstellen und dann alle 4 SPI Clock Modi (CKE bit im SSPSTAT Register und CKP bit im SSPCON1 Register) und zwei Input Sample Einstellungen (SMP bit im SSPSTAT Register) durchtesten. Nach spaetestens acht Tests sollte man also ein Einstellung gefunden haben die funktioniet.

Die 4 SPI Clock Modi sind wie folgt definiert:

Modus CPOL (=CKP bit) CPHA (=CKE bit) Beschreibung
0 0 0 der Ruhestatus (idle state) der SCK Leitung ist auf Low (0), der Master erwartet die eingehenden Daten auf SDI direkt zu Begin der Kommunikation, sobald er die SS/CS Leitung aktiviert (auf Low zieht) 
1 0 1 der Ruhestatus (idle state) der SCK Leitung ist auf Low (0), der Master erwartet die eingehenden Daten auf SDI erst bei der zweiten Flanke des Taktsignals, nachdem er die SS/CS Leitung aktiviert (auf Low zieht) 
2 1 0 der Ruhestatus (idle state) der SCK Leitung ist auf High (1), der Master erwartet die eingehenden Daten auf SDI direkt zu Begin der Kommunikation, sobald er die SS/CS Leitung aktiviert (auf Low zieht) 
3 1 1 der Ruhestatus (idle state) der SCK Leitung ist auf High (1), der Master erwartet die eingehenden Daten auf SDI erst bei der zweiten Flanke des Taktsignals, nachdem er die SS/CS Leitung aktiviert (auf Low zieht) 

Die input sample Einstellungen sind wie folgt zu setzen:

Die eingehenden Daten werden am in der Mitte einer ausgehenden Datenuebertragung eines jeden bits (an den Slave) gesampled
Die eingehenden Daten werden am Ende am der einer ausgehenden Datenuebertragung eines jeden bits (an den Slave) gesampled

Hinweis:

Microchip bietet in der Regel zu allen Basis-Funktionalitaeten der PICs diverse Hilfbibliotheken an, die im genutzten Compiler bereits integriert sind oder die von der microchip Webseite heruntergeladen werden koennen. Im Falle von SPI wird eine entsprechende Bibliothek bereits im C18 Compiler (und auch den anderen Compilern) mitgeliefert. Diese Bibliotheken machen einem manchmal das Leben einfacher, da sie einem Tiparbeit abnehmen fuer Standard-Aufgaben, andererseits abstrahiert man damit auch manchmal zu viel und verliehrt ein wenig die Kontrolle uber die Laufzeit von Programmen da man nicht immer genau weiss was alles in den Hilfmethoden passiert und mit welcher Auswirkung auf die Laufzeit des Programms. Gerade in Interrupt-Methoden sollte man das aufrufen von Methoden vermeiden, wenn man nicht genau weiss was diese tun und ob diese ggf. weitere Untermethoden aufrufen, da dies die Laufzeit enrom verlaengern kann wenn man nicht genau weiss was man tut (siehe dazu auch den Artikel zum effektiven Aufbau von Interrupt Methoden). Da wir hier weder mit Interrupts arbeiten, noch besonders auf geringe Laufzeiten und Speicherverbrauch achten muessen, zeige ich die Verwendung der spi bibliothek als auch einen Weg ohne diese Bibliothek.

Rahmenparameter für diese Code Beispiele

wir gehen bei allen folgenden Beispielen von folgender Grundannahme aus:

  • wir nutzen einen PIC18F4550 mit 40 Pins
  • die Taktung erfolgt extern durch ein Quarz mit 4 Mhz
  • als Slave nutzen wir einen Seriell zu USB Adapter der mit einem PC verbunden ist auf dem ein Terminal Programm laeuft
  • wir nutzen eine Datentranserrate (Baudrate) von 19800 kbit/s

SPI Schnittstelle im MSSP Modul Konfigurieren

Weitere Informationen zu dem PIC finden sich im Datenblatt:

http://ww1.microchip.com/downloads/en/devicedoc/39632c.pdf

Und manchmal sollte man auch in die ensprechenden Annotations schauen in denen Fehler in Datahseets korrigiert werden:

http://ww1.microchip.com/downloads/en/DeviceDoc/80478a.pdf

Dei entsprechende Dokumentation des MSSP / SPI moduls findet sich im Abschnitt „19.0 MASTER SYNCHRONOUS SERIAL PORT (MSSP) MODULE“ auf den Seiten 193ff.

Interrupts: ein Erklärungsversuch für Dummies ;-)

In der Mikrocontroller Programmmierung ist die Nutzung von Interrupts eine sehr effektive Art um auf nicht regelmässig auftretende „Events“ (Ereignisse) zu reagieren. Ein Interrupt (=Unterbrechnung) unterbricht den Prozessor in seiner aktuellen Aufgabe und meldet mittels eines Flags in einem bestimmten Register des Mikrocontrollers das ein Vorfall eingetreten ist, über den man informiert werden wollte.

Welche Ereignisse einen Interrupt auslösen, können wir beim programmieren selbst definieren. Natürlich können Interrupts auch ganz ausgeschaltet werden, wenn wir diese nicht nutzen wollen.

Hier ein Beispiel für einen recht einfachen Interrupt (ob sinnvoll oder nicht, darf jeder für sich entscheiden):

Nehmen wir an wir möchten das unser Programm eine bestimmte Aktion ausführt wenn wir einen Druck-Taster betätigen der an einem Eingang unsere Mikrocontrollers angeschlossen ist. Wir ignorieren jetzt hier der Einfachheit halber mal den Umstand das ein Taster auch entprellt werden muss und gehen von einem per externer Schaltung enprellten Taster aus. Nun haben wir zwei Möglichkeiten abzufragen ob der Taster gerade gedrückt ist oder nicht:

  1. Wir prüfen im Hauptprogramm kontinuierlich den Status des PINs (den wir natürlich vorher als digitalen Eingang konfiguriert haben) ob dort ein bestimtes Signale anliegt (meistens logischer „1“ Wert, also z.B. ob die Leitung gegen die positive VErsorgungsspannung gezogen wurde). Im einfachsten Fall könnte man eine Endlosschleife in der main Methode nutzen, die immer abfragt ob der Wert 1 ist, dann kann der Mikrocotroller aber nichts anderes machen als diesen Wert zu prüfen, das wäre etwas dämlich, dafür kann er dann doch etwas mehr. Natürlich muss man nicht permanent den Eingang prüfen, da wir als menschen im Vergleich zu einem Mikrocontroller uns ja eher im Schneckentempo bewegen. Wenn ein Mikrocontroller also mit sagen wir 4Mhz getaktet (also das Quarz liefert 4 Mio. Takte pro Sekunde) ist und, wie im Falle eines PIC18F, vier Takte pro Befehlt benötigt, dann braucht er für die Abfrage eines Satus an einem PIN 4 Takte (entspricht 1/4.000.000/4 Sekunden = 0,000.001 Sekunden), um diesen Wert jedoch in einer IF-Abfrage oder in einer While Schleife zu prüfen ob er z.b. 1 ist benötigt man weitere 4 Takte. Pro Abfrage des PIN Status vergehen also 0,000.002 Sekunden oder mit anderen Worten wir können den Status pro Sekunde  500.000 mal abfragen. Das ist natürlich ein wenig zu viel des Guten, den wenn ein Mensch einen Taster drückt, dann wird das mit sicherheit länger dauert als 1/500.000 Sekunde. Gehen wir mal davon aus jemand tippt den Taster nur ganz kurz an, dann wird der Taster sicherlich dennoch für 1/20 oder 1/10 Sekunde (ja es gibt bestimmt Leser die meinen Sie könten das schneller, aber das ist ja hier nur ein Beispiel) gedrückt sein. Es würde also reichen 10 mal pro Sekunde abfragen ob der Taste gedrückt ist, gehen wir auf nummer sicher und fragen 20 mal pro Sekunde ab. Das heisst unser Prozessor muss statt 500.000 mal pro Sekunde nur 20 mal pro Sekunde (also alle 50 milliksekunden) prüfen und hat die restliche Zeit frei für andere Aufgaben. Nun muss man jedoch aufpassen das der Prozessor wirklich alle 50 ms prüft da wir sonst Gefahr laufen würden eine Tasterauslösung zu übersehen (wenn der Prozesseor nämlch mehr als 50 ms in einem anderen Programmteil verbringt, prüft er ggf. im entscheidenen Zeitfenster von 50 ms nicht den Zustand des Tasters und bekommt daher nicht mit das dieser gedrückt wurde). Sicherlich kein unlösbares Problem, man muss nur einfach während der gesamten Entwicklung des Hauptprogramms berücksichtigen das dieser Fall nicht eintreten darf. Aber einfache ist doch definitiv durch Benutzung eines Interrupts.
  2. Wir konfigurieren also den PIN am Mikcrocontroller als einen digitalen Eingang und sagen dem Mikcrocontroller das er einen Interrupt auslösen soll sobald eine steigende Flanke an eben diesem PIN erkannt wird. Nun wird uns der Mikrocontroller zu jedem Zeitpunkt immer genau dann informieren wenn der Taster gedrückt wird (wir gehen wie oben erwähnt davon aus das der Taster entprellt ist und keine mehrfachauslösung in einem kurzen Zeitfenster erfolgt). Der Prozessort lässt dann unverzüglich seine aktuelle Aufgabe stehen und liegen und springt direkt zu der definiertern Interrupt-Handler-Routine (Funktion) die dann eben die Aktion ausführt die geschehen soll wenn der Knopf gedrückt wurde, sofern das nur wenige Anweisungen sind oder es sich um eine zeitkritische Aktion handelt die ausgelöst werden soll, kann das direkt in der Routine erfolgen. Idealerweis setzt man jedoch in der Routine nur einen Wert einer Variable den das Hauptproramm dann irgendwann (wir sprechen hier von ehr kurzen Zeiträumen selbst 1 Sekunde für einen entsprechend getakteten Mikrocontroller ja eine Ewigkeit ist) auswertet und entsprechend reagiert. Danach muss nur noch der Interrupt-Flag gelöscht werden und zum normalen Hauptprogramm zurück zu kehren.

 

Wann ist der Einsatz von Interrupts sinnvoll?

Welche Ereignisse können typischerweise einen Interrupt auslösen bei einem Mikrocontroller?

Als auslöser für einen Interrupt kommen diverse Komponoenten in Frage, das ist immer abhängig vom Mikrocontroller und dessen hardware.

Bei den meisten PIC Microcontrollern kann (sofern konfiguriert) ein Interrupt z.B. durch folgende Ereignisse ausgelöst werden:

  • Überlauf eines Timers (also wenn einer der Hardware Zähler im Mikrocontroller sein Maximum erreicht und wieder auf Null springt)
  • Eingang einer Neuen Nachricht über eine der Kommunikations Schnittstellen (z.B. I2C, SPI, CAN oder USART)
  • Eine Flanke (= ein Wechsel von High auf Low Pegel, oder umgekehrt) an einem der PINs die einen Interrupt auslösen können (meist konfigurierbar ob steigende oder fallende Flank als Auslöser dienen soll)
  • eintreffen eines Compare Events (wenn ein Timer einen bestimmten Wert hat)

Ein Interrupt wird immer vorranging behandelt

Wenn die Nutzung von Interrupts konfiguriert ist in der Software des Mikcrcontrollers und eine Komponente löst einen Interrupt aus, so hat dieser immer Vorrang vor dem normalen Programmablauf. Der Prozessort springt dann immer an die definierte Zeile im Programm in dem der Interrupt-Handler definiert ist, also eine spezielle Methode im Programm die explizit erstellt wurde um auf die Interrupts reagieren soll. Wenn diese Interrupt-Routine (Methode) ihre arbeit abgeschlossen hat, dann kehrt der Prozessort wieder zum normalen Programmablauf zurück an der Stelle an der er vorher die Verarbeitung unterbrochen hat.

Wenn man mit Interrupts arbeitet, sollte man sich also immer bewusst sein, dass das Hauptprogramm jederzeit in seiner Abarbeitung unterbrochen (pasuiert) werden könnte. Würde man also im Hauptprogramm mit zeitkritischen Aufgaben arbeiten, so besteht die Möglichkeit das durch einen Interrupt der Programmablauf empfindlich gestört wird und ggf. dann fehl Schlägt.

Aus diesem und anderen Gründen sollte man versuchen die abarbeitung von Interrupt-Routinen immer so kurz wie möglich zu halten. Das heisst es sollten so wenige Prozessortakte wie möglich verwendet werden zur Abarbeitung aller Aufgaben in der Routine.

Der Aufruf von anderen Methoden (wohlmöglich aus irgendwelchen Bibliotheken) innerhalb der Interrupt Routine sollte wenn möglich auch vermieden werden, da man hier zum einen Gefahr läuft das nicht abschätzen kann wie lange diese Methoden benötigen und ob diese ggf. wieder andere Methoden aufrufen. Noch kritischer ist es jedoch wenn man in der defintion der Interrupt Routine dem Compiler nicht explizit sagt welche Variablen, Speicherbereich und Werte benötigt werden beim aufruf einer anderen Methode, dann geht der Comipler vom schlimmsten Fall aus und muss erst alle Variablen und Speicherbereiche die das normale Programm nutzt auch im Context der Interrupt Routine bekannt machen, das führt dann dazu das sehr viel Zeit vergeht bis überhaupt einmal die erste Zeile Code der Interrupt Routine ausgeführt wird. Wenn man jedoch innerhalb der Interrupt Routine keine anderen Methoden aufruft, dann weisse der Compiler genau welche Variablen benötigt werden und kann den Kontext sehr schnell bereitstelen für die Interrupt Routine.

Weitere Infos zum effektiven Aufbau einer Interrupt-Routine und was beachtet werden muss wenn man andere Funktionen in dieser aufruft finden sich hier: Grundlagen effekiver Interrupt-Routinen

Verschiedene Prioritäten bei Interrupts

TBD

Grundlagen effekiver Interrupt-Routinen

Interrupts sind ein mächtiges Mittel in der Mikrocontroller Entwicklung wenn es darum geht die begrenzte Rechenleistung eines Mikrocontroller effektiv zu nutzen.

Nutzt man jedoch ineffizienten Code in einer Interrupt Routine kann dieser Vorteil schnell zu nichte gemacht werden.

Hier daher ein paar grundlegende Tips zum design von Interrupt Routinen:

  • Interrupt Routinen sollten so kurz wie möglich sein (auf Anzahl der Prozessortakte bezogen, was nicht unbedingt heisst das es wenige Zeilen Code sein müssen. Wie wir später sehen werden kann es durchaus sein dass 20 Zeilen Code schneller ausgeführt werden als 3 Zeilen Code)
  • Interrupt Routinen sollten keine anderen Funktionen/Methoden aufrufen sofern man nicht genau weiss was man tut und den Scope der Interrupt Routine definiert
  • Man sollte sich immer genau überlegen was in einer Interrupt Routine erledigt werden muss und was ggf. besser vom Hauptprogramm des Mikrocontrollers verarbeitet werden sollte (manchmal reicht es ja auch einen Flag in einer Variablen zu setzen auf die das Hauptprogramm dann bei nächster Gelegenheit reagiert um weitere, ggf. Zeitintensivere Berechnungen anzustoßen

Definition: Master und Slave in der Kommunikation mit Mikrocontrollern und peripheren Komponenten

Wenn Mikrocontroller mit anderen Mikrocontrollern oder sonstigen ICs (z.B. Speicherbausteinen, Temperaturfühlern, Treiber-Bausteinen etc.) kommunizieren so erfolgt dies entweder über serielle oder parallele Protokolle. Es gibt eine Vielzahl an Protokollen mit diversen Vor- und Nachteilen, die sich je nach Anwendungsfall besser oder schlechter eignen für die Übertragung von Daten.

Sie unterscheiden sich unter anderem durch die Anzahl der benötigten Leitungen (und somit durch die benötigte Anzahl an IOs des Mikrocontrollers was gerade beim MCU mit wenigen Pins ein wichtiges Kriterium sein kann) , die maximal erreichbare Datenübertragungsrate, die Anzahl der Ansprechbaren peripheren Komponenten (Adressierung von mehreren Kompoenten), Fehleranfälligkeit gegen Störungen, maximale Leitungslänge und vielen anderen Parametern.

Die Unterschiede zwischen paralleler und serieller Kommunikation werden im Artikel „serielle vs. parallele Datenübertragung beschrieben“ und sollen nicht weiter behandelt werden in diesem Artikel. Vielmehr sollen hier die Begriffe „Master“ und „Slave“ genauer betrachtet werden.

Wenngleich die Begriffe „Master“ (auch als „aktiver Knoten“ bezeichnet) und „Slave“ (=Sklave auch als passiver Knoten bezeichnet) recht drastisch klingen so beschreiben Sie doch recht gut wer in der Kommunikation zwischen den Komponenten das sagen hat. Der „Master“ in der Datenkommunikation ist immer das Gerät welches die Kontrolle über das „Gespräch“ (die Unterhaltung in Fomr von Datenübertragung zwischen den Komponenten) hat.

Ein Master und ein Slave

Man stelle sich zum Vergleich ein Gespräch mit einer Autoritätsperson, einem Manager (in diesem Fall der Master) und einem oder mehreren Untergebenen (der Begriff „Sklave“ ist hier vielleicht etwas drastisch, wenngleich der ein odere andere Chef diesen Begriff vielleicht als treffend ansieht 😉 ) vor.

Der Manager delegiert die Aufgaben im Gespräch oder holt Statusinformationen ein. Er duldet es nicht das ein „Slave“ von sich aus die Kommunikation anstösst, sondern nur auf Anfragen reagiert.

Spricht nun ein Master mit nur einem „Slave“, da kein anderer in Reichweite ist, so ist es nicht zwingend notwendig das er diesen explizit Addressiert, er redet einfach los und der Slave weiss das er gmeint ist.

Diese konstrukt besteht also nur aus genau einem Master und genau einem Slave.

Ein Master, mehrere Slaves

Ein Beispiel wäre also ein Mikrocontroller der an der Datenleitung nur einen einzigen Slave angeschlossen hat. Alles was er an Daten über die Leitung sendet erreicht also nur genau einen Slave.

Manche Schnittstellen/Protokolle lassen solch eine einfache Verdrahtung zu (z.B. SPI mit nur einem Master und einem Slave oder kaskadierten Slaves, oder diverse parallele Schnittstellen), während andere unabhängig von der Anzahl der Slaves immer eine Form der Adressierung vorschreiben (z.B. I2C oder diverse komplexe Bus Systeme).

Wenn nun jedoch unser Manager in einem Raum (die Räumlichkeit dient nur dem Vergleich mit der menschlichen Kommunikation, im bereich der Datenkommunikation ist der Raum gleichzusetzen mit dem Interface welches genutzt wird, alle Komponenten die am selben Interface hängen, sind also im selben „Raum“ können aber natürlich über lange Leitungen durchaus verteilt posiioniert sein) mit mehreren Angestellten eine Order ausruft, so muss er diese addressieren, damit sich ein oder mehrere seiner Untergebenen angesprochen fühlt. Das Adressieren geschieht z.B durch einen Fingerzeig.

Übetragen auf die Kommunikation zwischen elekronischen Komponenten heisst das nun das es in diesem Besipiel einen Master und mehrere Slaves gibt. Der Master muss vor jedem Befehl mitteilen an welchen Slave er diese Nachricht senden möchte. In einfachen seriellen Schnittstellen wie z.B. SPI erfolgt dies durch eine separate Leitung vom Master zu jedem einzelnen Slave diese Leitungen werden meist als „CS“ (=Chip select) oder „SS“ (=Slave select) Leitungen bezeichnet, je nach Protokoll zieht der Master die Leitung des Slave für den die Nahricht bestimmt ist auf logisch 0 oder 1 (bei SPI meist auf logish 0 = Masse), alle Leitungen zu den Slaves die NICHT angesprochen werden sind dabei im komplementären Zustand (also bei SPI z.B. auf logisch 1, bzw VCC). Der Master zeigt also mittels der CS Leitung genau auf den Slave den er ansprechen möchte.

Der Slave erkennt nun dass „auf ihn gezeigt wird“, da seine Slave-Select Leitung in dem als aktiv definierten Zustand ist und die nun folgenden Daten für Ihn bestimmt sind. Alle anderen Slaves auf die nicht gezeigt wird ignorieren die Nachricht einfach. Es kann dabei durchaus sein das der Master auch mehrere Slaves gleichzeitig aktiviert wenn die Narchricht für alle aktivierten Teilnehmer relevant ist, der Erfolg einer solchen Aktion ist jedoch abhängig vom Protokoll und der Reaktion der Slaves.

Man stelle sich der Manager spricht eine Gruppe von angstellten mit einer Frage an und alle wollen gleichzeitig antworten, das füht natürlich zu Chaos und der Manager versteht garnichts. Verteilt er stattdessen eine eindeutig definierte Aufgabe an eine Gruppe die keine Rückantwort erfordert, so können alle gleichzeitig die Arbeit aufnehmen. Meist wird in solch einem Anwendungsfall jedoch eher auf ein Bus-System gesetzt in dem Narichten flexibler addresisert werden können.

Adressierung von Datenpaketen / Nachrichten bei mehreren Slaves

Da jedoch die Verdrahtung eines jeden Slaves an dem Master mit einer dedizierten Leitung recht Ressourcenintensiv (benötigte Anzahl an IO-Pins am Mikrocontroller bzw. Master) ist (unser Microcontroller hat ja nur eine begrenzte Zahl an PINs die in der Regel bei komplexeren Projekten immer zu gering ist 😉 ) wird diese Art der Adressierung bei einer steigenden Anzahl an Slaves zunehmend unhandlicher bis sie irgendwann schlicht unmöglich wird ohne weitere Bausteine (Port-Multiplier etc.). Übetragen auf die menschlische Kommunikation zeigt der Manager also mit dem Finger auf einen oder zwei seiner Angstellten und stellt dann die Aufgabe. Da er aber nur eine begrenzte Anzahl an Händen und Fingern (entspricht dem IO-PIN des Mikrocontroller) hat, kann gehen im irgendwann die Möglichkeiten aus auf mehrere Angestellte gleichzeitig zu zeigen, zum Glück sind Mikrocontroller da meist besser ausgestattet, aber auch Ihre Anzahl an PINs ist endlich.

Hier bieten sich dann BUS-Systeme an, in denen jeder Teilnehmer eine eindeutige Adresse hat mit der er angesprochen werden kann oder auch Nachrichten mit bestimmten Kategoriekennungen zu versehen auf die die angeschlossenen Slaves dann Filtern.

In einem Bus-System wird demnach die Addressierung nicht mehr über dedizierte CS-Leitungen vom Master zu jedem einzelnen Slave geregelt, sondern über eine Addresse die entweder in jeder Nachricht die über den Daten-Bus gesendet wird enthalten ist, oder über einen separaten Adress-Bus gesetzt wird. Wir sprechen hier nun von der Adressierung innerhalb der Nachricht auf dem Datenbus. Im Falle des I2C Interface besteht eine Nachricht immer aus mehreren Teilen: einem Startbit, den Adress bits (7-10 bit je nachdem was der Slave Baustein unterstützt), den eigentlichen Datenbytes und einem Stop Bit. Zusätzlich gibt es noch weitere Bestätigungsbits die aber im Moment nicht weiter relevant sind, da wir über die Adressierung sprechen.

Da nun also in jeder Nachricht ein bestimmte Empfänger enthalten ist, können alle Teilnehmer (aktuell sprechen wir von Slaves) die Nachricht untersuchen und prüfen ob die Empfängeradresse mit Ihrer eigenen Adresse übereinstimmt. Die Adresse der einzelnen ICs sind je nach Baustein bereits vom Hersteller fest im Chip hinterlegt oder können über PINs/Schnittstellen von extern gesetzt werden.

In manchen Bus-Systemen ist es auch möglich mit Sub-Adressen zu arbeiten (z.B. die ersten 3 bits einer Adresse) und somit eine Nachricht an eine Gruppe von Slaves zu addressieren.

Multi-Master Konstellation

Bisher sprachen wir immer davon das es nur einen Master gibt der die Kommunikation regelt, der also Arbeit verteilt und ggf. Informationen abruft. Ein Slave wird also von sich aus niemals etwas senden wenn er nicht explizit dazu aufgefordert wird. Dies dient dazu Kollisionen auf der Datenleitung zur vermeiden. Je nach Bus-System und dem eingesetzten Protokoll ist es jedoch Möglich das es nicht nur einen Master sondern mehrere Master gibt, das heisst es gibt mehrere Teilnehmer die von sich aus Nachrichten senden können ohne vorher dazu aufgefordert zu werden. Solche Konstrukte nennt man dann „Multi-Master“ Konstellationen.

Damit es hier jedoch nicht zu Kollisionen kommt wenn alle teilnehmer gleichzeitig versuchen eine Nachricht zu senden, muss eine Kollisionserkennung im Protokoll vorgesehen werden, die definiert wie Kollisionen von Nachrichten erkannt werden und wie darauf zu reagieren ist, das z.B. also sendende Teilnehmer im Falle einer Kollision die Nachricht erneut senden und auch Quittungs-Nachrichten von den Teilnehmern an die die Nachrichten gerichtet sind, abgefragt werden. Zudem kann auch mit Prüfbytes gearbeitet werden um zu prüfen ob die gesammte Nachricht erfolgreich übertragen wurde. Da dies jedoch nun den Umfang dieses Artikels sprengen würde sei hier nur beispielhaft auf den CAN-BUS (Controller Area Network) verwiesen, ein Feldbus der usprünglich für die Automobilindustrie zum Einsatz in Fahrzeugen entwickelt wurde, jedoch heute in unterschiedlichen Ausprägungen auch in vielen Anderen Bereichen zur Vernetzung von Komponenten im Einsatz ist. Weitere Information dazu z.B. hier: http://www.itwissen.info/definition/lexikon/controller-area-network-CAN-CAN-Bus.html

Weiterführende Informationen zu Master/Slave anhand des SPI Interface sind hier zu finden:

http://de.wikipedia.org/wiki/Serial_Peripheral_Interface

Weitere Informationen zu BUS-Systemen sind unter anderem hier zu finden:

http://de.wikipedia.org/wiki/Bus_%28Datenverarbeitung%29

ICD 3 Anschlussbelegung

Die PIN Belegung beim ICD 3:

Hat man einmal die Belegung nicht parat, so kann man einfach den ICD 3 anschließen und in MPLAB X die Stromversorgung einschalten und dann einfach von beiden Seiten den zweiten und driten PIN mit einem Voltmeter messen auf welchem der beiden PINs die eingstellte Spannung anliegt. Diese PINs sind dann Nummer 4 und 5.

just another blog is born…

hin und wieder überkommt mich die Lust etwas neues oder, so meist der Fall, bereits dagewesenes selbst bauen zu wollen. Der DIY-Gedanke (=Do It Yourself: quasi, selber bauen, statt fertig kaufen), getrieben entweder durch die Tatsache das das da gewesene nicht genau meinen Anforderungen entspricht, zu teuer ist oder schlichtweg weil ich dessen Funktion selbst verstehen moechte und ueberhaupt: ist es nicht grossartig dieses Gefühl etwas selbst gebaut zu haben das dann sogar noch funktioniert?

Da meine Projekte meist nur zwischen Tür und Angel entstehen und dann wieder in Vergessenheit geraten möchte ich diese auf einer einheitlichen Platform dokumentieren, für mich aber auch für andere die ggf. die gleiche Lernkurve wie ich durchmachen und den ein oder anderen Tip gebrauchen können, dessen Erkenntnis mich selbst vielleicht schon viel Zeit und auch mal Nerven gekostet hat.Diese Blog soll also eine Art persönliches Nachschlagewerk sein, genau so wie eine Inspiration, HIlfestellung oder als Plattform zum Austausch von Ideen, Anregungen und Verbesserungsvorschlägen.

Ich versuche sowohl deutschsprachige wie auch, im internationlen Kontext, englischsprachige Texte zu verfassen, da jedoch die Fülle an Informaitonen im technischen Bereich im Internet meist Englisch ist, versurche ich ein wenig das deutschsprachige Forum der Beginner DIY-ler zu bedienen, in der Hoffnung das diese Seite in Zukunft eine gewisse Anerkennung findet und dem ein oder anderen als gute Startpunkt dient.

Viele meiner Erkennnisse verdanke ich ebenfalls Blogs und Foren mit Ihren unermuetlichen Mitgliedern mir den Stein der Weisheit einpruegeln zu wollen. Nicht immer ist der Weg über Foren ein einfacher, da es auch immer die Leute gibt weniger Tutor als mehr Kritiker sind und gerade Neulingen dem Spass an der Sache gerne einmal einen Dämpfer verpassen. Für mich selbst war jedoch auch diese Erkenntnis wertvoll und ich habe mehr denn je gelernt mich selbst durch Datenblätter und bestehende Blogs und Fornebeiträge zu wühlen, zu versuchen die Sache im Kern zu verstehen und dann wenn es einfach nicht weiter geht eine Frage in einem Forum zu posten. Das ist nicht immer der einfachste Weg, aber der einzige bei dem ich für mich persönlich festegestellt habe, wirklich ewas zu lernen und von Grund auf zu verstehen.

Leider fehlt mir meist die Zeit mich in allen technischen Fragen von Grund auf einzuarbeiten, dennoch versuche ich in meinen Postings wo immer möglich, so viele Grundlagen und Erklärungen beizusteuern wie es mir möglich ist. Das mag für den ein oder anderen fortgeschrittenen Besucher ein wenig zu viel des Guten sein. Angesichts meines Kenntnisstands in den Bereichen in denen ich mich bewegen werde, denke ich jedoch ohnehin, dass ich mit meinen Beiträgen aus der Sicht eines erfahrenen Lesers in den Bereichen, zum aktuellen Zeitpunkt bestenfalls Eulen nach Athen tragen würde.

Diese Blog erhebt keinen Anspruch darauf nur absolutes Expertenwissen zu vermitteln, uneingeschränkte Richtigkeit seiner Beiträge zu garantieren oder schlichtweg der Stein der Weisen zu sein. Es soll eine Quelle der Information für Menschen sein, die gerne selbst etwas Tüfteln, keine Angst haben eine neue Aufgaben trotz unkenntnis der Materie anzugehen, die Inspirationen suchen und Ihr Wissen gemeinsam mit anderen vertiefen wollen.

In diesem Sinne: Happy DIY-ing