====== ChipKit Boards (PIC32 chips von Microchip) ====== ===== Allgemeines zu ChipKit ===== Wenn man sich die Produktpalette von Microchip anschaut, wird man als erstes von der Vielfalt der über 800 Typen erschlagen. Dabei war es beim Arduino so überschaubar: * UNO mit dem ATmega328 * MEGA mit dem ATmega2560 * ATtinys * und den Due hat man sich vorgenommen, mal anzuschauen ;-) Bei den PIC Prozessoren von Microchip hat man eine ähnliche Vorauswahl gemacht und das Ganze unter dem Projekt chipKIT ins Leben gerufen. Dabei hat man sich beim IDE direkt beim Arduino bedient und das zu chipKIT passende IDE heißt MPIDE. Die Software gibt es auf der [http://chipkit.org|Projektseite]] als Download. Um mit dem chipKIT vertraut zu werden, möchte ich erst einmal mit dem einfachen Selbstbau beginnen. Der dabei verwendete Chip ist der PIC32MX250F128B, der das gleiche 28-pin Gehäuse hat wie der ATmega328. Seine Parameter sind: * 32 bit Architektur * 40 MHz * 128 kB Flash Memory * 32 kB RAM * USB 2.0 on board (kein FTDI Chip nötig) Die Pinbelegung ist hier wiedergegeben: {{:chipkit:bb32_1_crs.png?600|}} Durch die eingebaute Unterstützung von USB 2.0 ist mit wenigen Bauteilen eine lauffähige Breadboardversion erstellt. Man benötigt * Breadboard USB Adapter * 4 100nF Keramikkondensatoren * 4 10 kOhm Widerstände * 1 150 Ohm Widerstand (Strombegrenzung für die LED) * 1 LED * 1 10 uF Tantal Kondensator * 2 Taster * 1 3.3V Spannungsregler (Transistorgehäuse TO-92) * 8 MHz Quarz * 2 33 pF Keramikkondensatoren Der Chip hat einen internen Quarz, so dass der externe Quarz nicht unbedingt nötig ist. Er wird aber in allen Beschreibungen empfohlen. Für die beiden Kondensatoren am Quarz habe ich Werte von 22, 33, 36 pF gefunden. Ein Aufbau mit 33 pF läuft problemlos. Der Chip kann bei BoxTec gekauft werden und ist ab Werk mit dem chipKit Bootloader geflasht. Im MPIDE verwende ich als Board das //Digilent chipKIT DP32// welches diesen Chip einsetzt. Der Aufbau ist überschaubar und hier abgebildet: {{:chipkit:bb32_chipkit_s.png?600|}} Eine detaillierte Aufbauanleitung findet man [[http://chipkit.net/diy-chipkit-board/|hier]]. Statt dem dort angegebenen Fubarino Board wie gesagt das DP32 board auswählen, da der Fubarino einen anderen Chip verwendet. Hier noch der Schaltplan: {{:chipkit:breadboard_cr.png|}} Mir hat der Aufbau viel Spass bereitet und mir gefällt die Einfachheit des Boards. Es liegt also nahe, dass man ein eigenes Board analog zum Helvetino aufbaut. ====== Der HelvePic32 ====== * [[assembly:|Aufbauanleitung]] ===== Das BoxTec ChipKit Board ===== Die Designvorgaben für das Board sind folgende: * alles PTH, also Durchsteckmontage, keine SMD, so dass das Board auch von Kindern gelötet werden kann * Herausführung der verwendbaren Pins zur Seite, alle Pins stehen auf 0.1" Rastermaß * Gleiche Pinauslegung auf beiden Seiten, so dass Module zwischen den Seiten gewechselt werden können * die Pinreihen sind so weit vom Rand entfernt, dass gewinkelte Stiftleisten eine Auflage haben * Die Boardgröße entspricht dem Rastermaß der Camdenboss Hutschienenhalterungen (72x42mm) * USB Mini Gehäuse, da Microgehäuse zu störanfällig sind * I2C und SPI werden getrennt herausgeführt * PicKit Pins herausgeführt für die direkte Programmierung des Chips * automatische Selektion der Spannungsquelle * 8 MHz externes Quarz, Chip läuft auf 40 MHz und ist damit kompatibel zum ChipKit-DP32 Die finale Version V1.0 der Umsetzung dieser Vorgaben sieht dann so aus: {{:chipkit:helvepic32.png?600|}} * Rechts und links sind je eine Stiftleiste mit 12 Pins, 8 davon sind GPIO Pins, die jeweils letzten Pins sind Reset, 3.3V, 5V und GND. Mit den letzten vier Pins hat man alle Spannungen zur Hand und kann damit auch problemlos Levelshifter versorgen, wenn man mit der 5V- Welt arbeitet. * Am oberen USB Port befindet sich eine Stiftleiste mit allen USB Pins. Die GPIO-Pins RB10 und RB11 sind nicht zur Seite herausgeführt, da sie mit D+ und D- belegt sind. Hier kann man sie aber dennoch abgreifen * Neben den USB Pins befinden sich RX/TX der beiden UARTs des Chips, UART2 ist 5V tolerant * Direkt am Quarz können die Pins RA2 and RA3 abgegriffen werden, sofern man den Chip ohne Quarz betreibt * Neben dem Reset Taster befinden sich die SPI Anschlüsse in der gewohnten ICSP-Anordnung. (Der Chip kann hierüber nicht programmiert werden) * Neben dem Program Taster befidnen sich zwei Jumper, mit denen die SDA und SCL Leitung über 4.7kOhm auf Plus gehoben werden (pull-up), wenn gewünscht. * Darunter liegt der I2C Bus * Daneben die Programmier-Pins für den PicKit Programmierer. Das Dreieck muss mit dem Programmierer ausgerichtet werden (Pin-1) Das Bild gibt die Belegung der einzelnen GPIO Pins wieder und die entsprechende Pinnummer des DP32 bootloaders. ===== Tests und Anwendungsbeispiele ===== ==== Sketch Upload ==== Der HelvePic32 schaltet nicht automatisch in den Bootloader Modus, sondern vor einem Upload eines Sketches muss dieser durch Drücken der Program- und Reset-Taste in den Bootloadermodus schalten. Dabei ist es wichtig, dass erst die Program-Taste gedrückt wird und dann Reset. Man erkennt den Bootloader daran, dass ein serieller Port erscheint, der dann vom IDE verwendet werden kann. ==== PinMap ==== Für den HelvePic32 wird die Boardeinstellung **ChipKitDP32** verwendet, da dieses Board von Digilent den gleichen Chip verwendet. Leider sind die Pins auf unserem HelvePic32 etwas anders angeordnet, so dass wir ein Array verwenden, das die Pinnummer umsetzt. Dieses Array besteht aus zwei Vektoren, welche die jeweils linke (Index 0) oder die rechte (Index 1) Seite widerspiegeln: const uint8_t LEFT=0; const uint8_t RIGHT=1; uint8_t nP[2][8] = {{0,17, 9,10,11,12,13,14},{18,17, 1, 2, 3, 6, 7, 8}}; // pins of version 1.0 using DP32 board definitions Die Definition der ersten beiden Konstanten ist optional, macht den Code aber lesbarer. Die LED ist auf der rechten Seite an Pin 2 angeschlossen, kann also über nP[RIGHT][2] angesprochen werden. Man sieht in der Liste der Pins, dass der Pin 17 auf beiden Seiten angegeben ist. Das hängt damit zusammen, dass der Pin 17 der Programmierpin ist. Da auf beiden Seiten 8 Pins, zusammen also 16 Pins zur Verfügung stehen, der Chip aber nur 15 nutzbare Pins bietet, lag es nahe, den Programmierpin auf beiden Seiten an der gleichen Stelle anzubieten. Über den zusätzlich verfügbaren Reset-Pin kann so das Board von einem Wing sowohl resettet als auch in Bootloadermodus verbracht werden. Außer den beiden Pinleisten gibt es noch weitere Pins, die hier dargestellt sind: {{:chipkit:helvepic32_pins_sml.png?600|}} * Direkt an der USB Buchse sind die Pins der USB Buchse herausgeführt. Damit sind auch die beiden Pins verfügbar, welche mit D+ und D- verbunden sind. * Direkt daneben liegen die Pins für die beiden UARTs. * Unten links sind die Pins des SPI Busses in der beim Arduino üblichen Anordnung zu finden. * Neben dem Quarz sind die beiden Pins herausgeführt, welche mit dem Quarz verbunden sind * Unten Rechts sind zwei pull-up Widerstände (4.7 kΩ) über Jumper erreichbar, welche bei Bedarf dem I2C-Bus dienen. * Ganz unten sind die Pins zur Programmierung über den PicKit3 Adapter und daneben * die I2C Pins ==== Blink ==== In guter Tradition ist der erste Test eines Boards der, die User-LED zum blinken zu bringen. Beim HelvePic32 gibt es da zwei Möglichkeiten: === 1) Traditionell digitalWrite() === const uint8_t LEFT=0; const uint8_t RIGHT=1; uint8_t nP[2][8] = {{0,17, 9,10,11,12,13,14},{18,17, 1, 2, 3, 6, 7, 8}}; // pins of version 1.0 using DP32 board definitions void setup() { pinMode(nP[RIGHT][2],OUTPUT); } void loop() { digitalWrite(nP[RIGHT][2], HIGH); delay(250); digitalWrite(nP[RIGHT][2], LOW); delay(250); } === 2) Register Manipulation === Hier bedienen wir uns eines Tricks, den wir uns in der UTFT Library abgeschaut haben. Statt das Register und die zugehörige Bitmask selbst zusammen zu suchen, kann man eine entsprechende Routine aufrufen, die einem das Portregister als auch die passende Bitmask zu einem Pin ausrechnet. Das funktioniert übrigens auch beim Arduino... Zusätzlich zum Pin-Array definieren wir ein Pointerarray pP, welches auf die Portregister zeigt und ein Bitmaskarray bP, welches die Bitmask speichert. Der nachfolgende Code verwendet dann zwei Pre-Prozessor Macros um das jeweilige Bit zu setzen (sbi) oder zu löschen (cbi). Der Code prüft auch die Architektur, so dass der Code auch auf einem Arduino laufen kann. #define cbi(reg, bitmask) *reg &= ~bitmask #define sbi(reg, bitmask) *reg |= bitmask const uint8_t LEFT=0; const uint8_t RIGHT=1; uint8_t nP[2][8] = {{0,17, 9,10,11,12,13,14},{18,17, 1, 2, 3, 6, 7, 8}}; // pins of version 1.0 using DP32 board definitions #if defined(__AVR__) volatile uint8_t *pP[2][8]; uint8_t bP[2][8]; #elif defined(__PIC32MX__) volatile uint32_t *pP[2][8]; uint32_t bP[2][8]; #endif void _IO_Init() { for (uint8_t i=0; i<2; i++){ for (uint8_t j=0; j<8; j++){ pP[i][j] = portOutputRegister(digitalPinToPort(nP[i][j])); bP[i][j] = digitalPinToBitMask(nP[i][j]); } } } void setup() { _IO_Init(); for (uint8_t i=0; i<8; i++){ pinMode(nP[RIGHT][i],OUTPUT); } } void loop() { sbi(pP[RIGHT][2], bP[RIGHT][2]); delay(500); cbi(pP[RIGHT][2], bP[RIGHT][2]); delay(100); } (zur Unterscheidung sind die Delays unterschiedlich gewählt) === Was ist der Unterschied? === Das nachfolgende Bild zeigt erst das Setzen des Pins auf HIGH mit digitalWrite gefolgt von einem Aufruf zu digitalWrite, um den Pin auf LOW zu setzen. Danach die gleiche Aktion mit sbi und cbi: {{:chipkit:digitalwritevssbi_cbi.png?300|}} Man sieht, dass mit digitalWrite der kürzeste Puls 1.2 μs lang ist, mit sbi/cbi nur 140 nS, also um einen Faktor 8-10 schneller. ==== Serielle Schnittstelle ==== Als nächstes testen wir die serielle Schnittstelle. Deren hat es drei: - Serial.begin(9600) : die normale serielle Schnittstelle via der USB-Schnittstelle. Nach einem Reset braucht diese etwa eine Sekunde um bereit zu sein - Serial0.begin(9600) : UART1 auf dem Board - Serial1.begin(9600) : UART2 auf dem Board Der Code ist entsprechend einfach: void setup() { Serial.begin(9600); Serial0.begin(9600); Serial1.begin(9600); } void loop() { Serial.println("Hello World 1"); Serial0.println("Hello World 2 UART1"); Serial1.println("Hello World 3 UART2"); delay(1000); } Mit diesem Code sieht man in drei Terminalfenstern die unterschiedlichen Ausgaben. Die hier verwendete Baudrate von 9600 kann natürlich gegen höhere Baudraten ausgetauscht werden. Als Verbindung habe ich zwei FOCA Breakout verwendet. Man beachte, dass RX des FOCA an TX des Boards geht sowie TX des FOCA an RX des Boards. Mit diesem Setup ist es möglich, eine serielle Kommunikation unabhängig vom USB Anschluss aufzubauen, z.B mit einem Bluetooth Adapter. ==== Servo ==== Spätestens jetzt ist es an der Zeit etwas Bewegung an das Board zu bringen: Der Anschluss eines Servos. Dazu bietet es sich an, gleich die SoftPWMServo Bibliothek zu verwenden. Damit ist es möglich, jeden IO Pin zur Steuerung des Servos zu verwenden. {{:chipkit:helvepic32_servo_sml.png?300|}} Der zugehörige Code ist entsprechend einfach: const uint8_t LEFT=0; const uint8_t RIGHT=1; uint8_t nP[2][8] = {{0,17, 9,10,11,12,13,14 },{18,17, 1, 2, 3, 6, 7, 8 }}; // pins of version 1.0 using DP32 board definitions #include int pos = 0; // variable to store the servo position, in microseconds const int pin = nP[RIGHT][3]; // Choose _any_ pin number on your board, i.e. pin 3, right side void setup() { } void loop() { for(pos = 1000; pos < 2000; pos += 10) // goes from 1ms to 2ms { // in steps of 10us SoftPWMServoServoWrite(pin, pos); // tell servo to go to position in variable 'pos' delay(25); // waits 25ms for the servo to reach the position } } Auffällig ist, wie glatt und fließend der Servo sich bewegt. ==== 16 x 2 LCD Anzeige ==== Als nächstes wollen wir eine Anzeige an den HelvePic32 anschließen. Wie beim Arduino bietet sich hier eine zweizeilige LCD-Anzeige an. Da ChipKit das Ziel hat, den Code weitestgehend gleich zum Arduino zu halten, gibt es auch hier die Bibliothek LiquidCrystal und der Code ist identisch zum Arudino Code, hier "Hello World". Der Anschluss ist dementsprechend sehr ähnlich: {{:chipkit:helvepic32_lcdsml.png?600|}} Und der Code bedarf nur der Pin-Definition von oben. Die #define Anweisungen dienen nur der Lesbarkeit: /* Code based on: LiquidCrystal Library - Hello World Library originally added 18 Apr 2008 by David A. Mellis library modified 5 Jul 2009 by Limor Fried (http://www.ladyada.net) example added 9 Jul 2009 by Tom Igoe modified 22 Nov 2010 by Tom Igoe modified for HelvePic32 30 Dec 2014 by Mathias Wilhelm This example code is in the public domain. */ const uint8_t LEFT=0; const uint8_t RIGHT=1; uint8_t nP[2][8] = {{0,17, 9,10,11,12,13,14},{18,17, 1, 2, 3, 6, 7, 8}}; // pins of version 1.0 using DP32 bootloader #define RS nP[RIGHT][0] #define EN nP[RIGHT][1] #define D4 nP[RIGHT][2] #define D5 nP[RIGHT][3] #define D6 nP[RIGHT][4] #define D7 nP[RIGHT][5] #include LiquidCrystal lcd(RS, EN, D4, D5, D6, D7); void setup() { lcd.begin(16, 2); lcd.print("hello, world!"); } void loop() { lcd.setCursor(0, 1); lcd.print(millis()/1000); } Noch ein Tipp: Der Poti, der über V0 den Kontrast einstellt muss bei 3.3V fast ganz aufgedreht werden. Als Poti habe ich 10kOhm verwendet. Bei einem 5kOhm Poti blieb das LCD dunkel, was mich einige Stunden der Fehlersuche gekostet hat. Die LCD Hintergrundbeleuchtung auf den LCD-pins 15 und 16 ist nicht angeschlossen, da für das Beispiel unwichtig. ==== Analog Input ==== Der PIC32MX250F128B hat 9 analoge Input Pins, welche als A0 ... A8 vordefiniert sind. Der Einfachheit des Codes zu Liebe bleiben wir bei der Notation mit dem oben eingeführten Pin-Arrays. Dazu schliessen wir ein Potentiometer (10 kOhm) an GND und 3.3V an. Den Mittenabgriff geben wir auf der linken Seite auf den Pin 2, den ersten analogen Input dieser Seite (siehe Diagramm oben).Das Auslesen des analogen Inputs geht wie beim Arduino: /* Code based on Analog Input Created by David Cuartielles Modified 4 Sep 2010 by Tom Igoe modified 31 Dec 2014 by Mathias Wilhelm This example code is in the public domain. http://arduino.cc/en/Tutorial/AnalogInput */ const uint8_t LEFT=0; const uint8_t RIGHT=1; uint8_t nP[2][8] = {{0,17, 9,10,11,12,13,14},{18,17, 1, 2, 3, 6, 7, 8}}; // pins of version 1.0 using DP32 bootloader int sensorPin = nP[LEFT][2]; // select the input pin for the potentiometer int ledPin = nP[RIGHT][2]; // select the pin for the LED int sensorValue = 0; // variable to store the value coming from the sensor void setup() { pinMode(ledPin, OUTPUT); } void loop() { sensorValue = analogRead(sensorPin); digitalWrite(ledPin, HIGH); delay(sensorValue); digitalWrite(ledPin, LOW); delay(sensorValue); } Es bietet sich natürlich an, diesen Sketch mit dem Servo Sketch zu verbinden und den Servo über den Poti zu steuern: {{:chipkit:helvepic32_servopoti_sml.png?600|}} /* Control a Servo via a poti Created 31 Dec 2014 by Mathias Wilhelm */ const uint8_t LEFT=0; const uint8_t RIGHT=1; uint8_t nP[2][8] = {{0,17, 9,10,11,12,13,14},{18,17, 1, 2, 3, 6, 7, 8}}; // pins of version 1.0 using DP32 bootloader #include int pos = 0; // variable to store the servo position, in microseconds const int pin = nP[RIGHT][4]; // Choose _any_ pin number on your board int sensorPin = nP[LEFT][2]; // select the input pin for the potentiometer int ledPin = nP[RIGHT][2]; // select the pin for the LED int sensorValue = 0; // variable to store the value coming from the sensor void setup() { pinMode(ledPin, OUTPUT); } void loop() { sensorValue = analogRead(sensorPin); pos = map(sensorValue,0, 1023, 1000, 2000); SoftPWMServoServoWrite(pin, pos); delay(25); } ==== Step Motor ==== Statt eines Servos kann man auch einen Schrittmotor anschließen. Für den Test verwenden wir den weit verbreiteten 28BYJ-48 in der 5V Ausführung und den günstigen ULN2003 Treiber: {{:chipkit:helvepic32_steppersml.png?800|}} Da die Anschlusskabel oft variieren, ist die Motorbeschaltung auch gezeichnet. Der Code kann ohne Veränderung vom Arduino übernommen werden: /* Based on Stepper exemple V1.01 11/30/2013 by terry@yourduino.com */ #define LEFT 0 #define RIGHT 1 uint8_t nP[2][8] = {{0,17, 9,10,11,12,13,14},{18,17, 1, 2, 3, 6, 7, 8}}; // pins of version 1.0 using DP32 bootloader #include #define FULLSTEP 4 #define HALFSTEP 8 // motor pins #define motorPin1 nP[RIGHT][3] // Blue - 28BYJ48 pin 1 #define motorPin2 nP[RIGHT][2] // Pink - 28BYJ48 pin 2 #define motorPin3 nP[RIGHT][1] // Yellow - 28BYJ48 pin 3 #define motorPin4 nP[RIGHT][0] // Orange - 28BYJ48 pin 4 // Red - 28BYJ48 pin 5 (VCC) // NOTE: The sequence 1-3-2-4 is required for proper sequencing of 28BYJ48 AccelStepper stepper1(HALFSTEP, motorPin1, motorPin3, motorPin2, motorPin4); void setup() { stepper1.setMaxSpeed(1000.0); stepper1.setAcceleration(50.0); stepper1.setSpeed(200); stepper1.moveTo(2048); // 1 revolution } void loop() { //Change direction at the limits if (stepper1.distanceToGo() == 0) stepper1.moveTo(-stepper1.currentPosition()); stepper1.run(); } Warnung: Ein Schrittmotor zieht recht viel Strom, so dass die USB Versorgung gegebenenfalls durch eine stärkere Stromversorgung ersetzt werden muss. Der ULN2003 kann auch 12V schalten. ==== Servo Detailsteuerung ==== Wenn man sich die PWM Signale der normalen Servo Bibliothek anschaut, sieht man, dass die Puls-weite zwischen ca. 500 μs und 2300 μs variiert. Das bedeutet, dass man mit Hilfe der SoftPWMServo Bibliothek die Position eines Servos in Zehntel-Grad ansteuern kann. Da die Bibliothek aber in der Voreinstellung die Puls-weite auf 2 ms begrenzt, muss man diese Werte anpassen. Der zugehörige Code sieht so aus: const uint8_t LEFT=0; const uint8_t RIGHT=1; uint8_t nP[2][8] = {{ 0,17, 9,10,11,12,13,14},{18,17, 1, 2, 3, 6, 7, 8}}; const int Smax=1800; const int Smin=500; #include int pos = 0; const int pin = nP[RIGHT][7]; // Choose _any_ pin number on your board void setup() { SoftPWMServoInit(); SoftPWMServoSetFrameTime(100000); // 2500 us are 100000 tics for 40 MHz CPU! SoftPWMServoSetServoFrames(8); // 8 frames make 20 ms wavelength } void loop() { for (pos=0; pos <= 1800; pos+=2) // use deci-degree in 0.2 degree steps { SetServoPos_decidegree(pos); delay(5); } for (pos=0; pos <= 1800; pos+=2) // use deci-degree in 0.2 degree steps { SetServoPos_decidegree(1800-pos); delay(5); } for (pos=0; pos <= 180; pos++) // use degree in 1 degree steps { SetServoPos_degree(pos); delay(25); } for (pos=0; pos <= 180; pos++) // use degree in 1 degree steps { SetServoPos_degree(180-pos); delay(25); } SetServoPos_degree(90); delay(1000); SetServoPos_degree(180); delay(1000); SetServoPos_degree(0); delay(1000); } void SetServoPos_degree(int degree) { SoftPWMServoServoWrite(pin, 10*degree+Smin); } void SetServoPos_decidegree(int decidegree) { SoftPWMServoServoWrite(pin, decidegree+Smin); } Der Code fährt einmal den Servo von 0 bis 180 Grad in 0.2 Grad Schritten und dann wieder zurück, danach die gleiche Aktion aber in Gradschritten. Zum Schluss werden die Positionen 90°, 180° und 0° für je eine Sekunde angefahren. ==== Grafik LCD mit SPI (320x240 Pixel TFT) ==== Richtig interessant wird es für mich, wenn ich mit dem Mikrocontroller ein farbiges LCD ansteuern kann. Hier gibt es eine Reihe von günstigen TFT und hier sei das 2.2" TFT mit 320x240 Pixeln Auflösung beschrieben, welches über SPI angesprochen wird: {{:chipkit:helvepic32_tft320x240sml.png?800|}} Um das TFT anzusteueren brauchen wir die UTFT Bibliothek von Henning Karlsen. Diese Bibliothek ist sowohl für Arduino als auch für ChipKit geschrieben. Leider hat Henning keinen PIC32MX250F128B Prozessor zum testen gehabt, wesshalb der Code im Original nicht funktioniert. Mit einigen leichten Änderungen läuft dieser aber problemlos mit unserem HelvePic32. Die modifizierte Bibliothek kann man [[http://www.mathias-wilhelm.de/arduino/assets/downloads/UTFT4PIC32MX250.ZIP|hier]] herunterladen. Als Test kann man das UTFT Beispiel für UTFT_Demo_320x240_Serial mit folgender Pindefinitionen verwenden: const uint8_t LEFT=0; const uint8_t RIGHT=1; uint8_t nP[2][8] = {{ 0,17, 9,10,11,12,13,14},{18,17, 1, 2, 3, 6, 7, 8}}; const uint8_t TFT_CS = nP[RIGHT][7]; const uint8_t TFT_RST = nP[RIGHT][6]; const uint8_t TFT_RS = nP[RIGHT][5]; const uint8_t TFT_SDA = nP[RIGHT][4]; const uint8_t TFT_SCL = nP[RIGHT][3]; #include // Declare which fonts we will be using extern uint8_t SmallFont[]; // Usage: myGLCD(, SDA, SCL, CS, RST[, RS]); // Serial 2.2" TFT 320x240 UTFT myGLCD(TFT22SHLD, TFT_SDA, TFT_SCL, TFT_CS, TFT_RST, TFT_RS); ==== Neopixel ==== Bei den Anwendungsbeispielen darf natürlich nicht die Anbindung der beliebten NeoPixel fehlen. Die beim Arduino verwendete Bibliothek kann dabei nicht benutzt werden, da diese auf den Atmel-Chip ausgelegt ist und Maschinencode dieses Prozessors verwendet. Andererseits gibt es eine Bibliothek, welche für chipKit geschrieben wurde und mit den Standard-Boards funktioniert. Da der HelvePic32 aber mit einer anderen Taktfrequenz arbeitet, musst der Code leicht angepasst werden. DIe Neopixel Strips können an jeden Pin angeschlossen werden. Es gelten die gleichen Regeln bezüglich der Stromversorgung. 30 Pixel liefen problemlos mit der Stromversorgung des Boards. {{:chipkit:helvepic32_neopixel.jpg|}} Die Bibliothek wurde so angepasst, dass die Funktionsaufrufe der Adafruit Bibliothek verwendbar sind. Es muss also nur die Einbindung der Bibliothek und der Generierung des Objekts geändert werden: #include ChipKitPixel strip1(30, nP[RIGHT][6], GRB); ChipKitPixel strip2(8, nP[RIGHT][7], GRB); Bei beiden Strip bitte beachten, dass die Datenleitung an DIN angeschlossen ist (Daher ist der Stick von der Rückseite her gezeigt) ==== LED Wings ==== Beim HelvePic32 gibt es nicht primär Shields sondern Winds, welche zur Seite hin angeschlossen werden. Shields sind derzeit in der Entwicklung. Aufgrund dieser Wings sind die Stiftleisten an der Seite rotations-symmetrisch, so dass ein Wing an beide Seiten angeschlossen werden kann. ALs ersten Wing bietet es sich an, jeden Pin mit einer LED gegen GND mit Widerstand zu versorgen: {{:chipkit:helvepic32_ledwing.jpg|}} Im Betrieb werden dabei vier LED auffallen: * die LED np[LEFT][7] blinkt, wenn der PIC im bootloader modus ist * die LED nP[LEFT][6] leuchtet, wenn der Sketch geladen wird * die LED nP[RIGHT][3] und nP[RIGHT][4] leuchten, wenn der I2C Bus mit pull-up Widerständen versehen sit und wenn Aktivität auf dem Bus herrscht. Es hat sich gezeigt, dass ein Wing auf der linken Seite sehr hilfreich ist, wenn die Pins nicht gebraucht werden. Der LED-Wing kann im Betrieb abgezogen und aufgesteckt werden. ==== I2C Bus ==== Über den I2C Bus kann man sehr elegant Module anbauen. Um dies zu veranschaulichen, sind in diesem Beispiel drei I2C Module angeschlossen: * Adafruit 8x8 Mini Matrix (Adresse 0x72) * Adafruit 14-Segemnt AlphaNum Anzeigt (Adresse 0x70) * 128x64 OLED mit SSD1306 (Adresse 0x3c) {{:chipkit:helvepic32_i2c.jpg|}} Beim I2C ist die Adresse des Moduls am wichtigsten. Um zu sehen, ob man das Modul richtig angweschlossen hat, kann man den Code i2cscanner verwenden (identisch zum Arduino code bis auf den Aufruf der wire Unterroutine twi_writeTo) /** * I2CScanner.pde -- I2C bus scanner for Arduino * based on the work of 2009, Tod E. Kurt, http://todbot.com/blog/ */ #include "Wire.h" extern "C" { #include "utility/twi.h" // from Wire library, so we can do bus scanning } int devfnd=0; void scanI2CBus(byte from_addr, byte to_addr, void(*callback)(byte address, byte result) ) { byte rc; byte data = 0; // not used, just an address to feed to twi_writeTo() for( byte addr = from_addr; addr <= to_addr; addr++ ) { // rc = twi_writeTo(addr, &data, 0, 1, true); // last argument: send stop at the end rc = twi_writeTo(addr, &data, 0, 1); // last argument: send stop at the end callback( addr, rc ); } } void scanFunc( byte addr, byte result ) { char str[40]; sprintf(str,"addr: %3d 0x%02x",addr,addr); Serial.print(str); Serial.print( (result==0) ? " DEV!":" "); Serial.print( (addr%5) ? "\t":"\n\r"); if (!result) devfnd++; } byte start_address = 16; byte end_address = 123; // standard Arduino setup() void setup() { Wire.begin(); pinMode(1,OUTPUT); Serial.begin(9600); delay(2000); Serial.println("\nI2CScanner ready!"); } // standard Arduino loop() void loop() { Serial.print("starting scanning of I2C bus from "); Serial.print(start_address,DEC); Serial.print(" to "); Serial.print(end_address,DEC); Serial.println("..."); devfnd=0; // start the scan, will call "scanFunc()" on result from each address scanI2CBus( start_address, end_address, scanFunc ); Serial.println("\ndone"); Serial.print("I2C devices found: "); Serial.println(devfnd); for (int i=0;i Im Serial Monitor zeigen sich die Module an den erhofften Adressen: starting scanning of I2C bus from 16 to 123... addr: 16 0x10 addr: 17 0x11 addr: 18 0x12 addr: 19 0x13 addr: 20 0x14 addr: 21 0x15 addr: 22 0x16 addr: 23 0x17 addr: 24 0x18 addr: 25 0x19 addr: 26 0x1a addr: 27 0x1b addr: 28 0x1c addr: 29 0x1d addr: 30 0x1e addr: 31 0x1f addr: 32 0x20 addr: 33 0x21 addr: 34 0x22 addr: 35 0x23 addr: 36 0x24 addr: 37 0x25 addr: 38 0x26 addr: 39 0x27 addr: 40 0x28 addr: 41 0x29 addr: 42 0x2a addr: 43 0x2b addr: 44 0x2c addr: 45 0x2d addr: 46 0x2e addr: 47 0x2f addr: 48 0x30 addr: 49 0x31 addr: 50 0x32 addr: 51 0x33 addr: 52 0x34 addr: 53 0x35 addr: 54 0x36 addr: 55 0x37 addr: 56 0x38 addr: 57 0x39 addr: 58 0x3a addr: 59 0x3b addr: 60 0x3c DEV! addr: 61 0x3d addr: 62 0x3e addr: 63 0x3f addr: 64 0x40 addr: 65 0x41 addr: 66 0x42 addr: 67 0x43 addr: 68 0x44 addr: 69 0x45 addr: 70 0x46 addr: 71 0x47 addr: 72 0x48 addr: 73 0x49 addr: 74 0x4a addr: 75 0x4b addr: 76 0x4c addr: 77 0x4d addr: 78 0x4e addr: 79 0x4f addr: 80 0x50 addr: 81 0x51 addr: 82 0x52 addr: 83 0x53 addr: 84 0x54 addr: 85 0x55 addr: 86 0x56 addr: 87 0x57 addr: 88 0x58 addr: 89 0x59 addr: 90 0x5a addr: 91 0x5b addr: 92 0x5c addr: 93 0x5d addr: 94 0x5e addr: 95 0x5f addr: 96 0x60 addr: 97 0x61 addr: 98 0x62 addr: 99 0x63 addr: 100 0x64 addr: 101 0x65 addr: 102 0x66 addr: 103 0x67 addr: 104 0x68 addr: 105 0x69 addr: 106 0x6a addr: 107 0x6b addr: 108 0x6c addr: 109 0x6d addr: 110 0x6e addr: 111 0x6f addr: 112 0x70 DEV! addr: 113 0x71 addr: 114 0x72 DEV! addr: 115 0x73 addr: 116 0x74 addr: 117 0x75 addr: 118 0x76 addr: 119 0x77 addr: 120 0x78 addr: 121 0x79 addr: 122 0x7a addr: 123 0x7b done I2C devices found: 3 Zur Ansteuerung der Module können die Adafruit Bibliotheken fast unverändert verwendet werden. Lediglich beim Code für das 14-Segment Modul musste der Aufruf von pgm_read_word entfernt werden, da PIC32 kein PROGMEM kennt. ===== Ausblick ===== Bau von "Wings", welche an die Seite angesteckt werden: * I2C Bus Wing * Motor Wing (4 Motoren oder 2 Stepper) * Servo Wing (8 Servos, der Chip kann theoretisch bis zu 85 Servos steuern) * Prototyping ===== Eagle Dateien ===== [[http://www.mathias-wilhelm.de/arduino/assets/Embedded-boards/HelvePic32/HelvePic32eaglefiles.zip|Eagle Quellendateien]] ... wird fortgesetzt ...