Hallo Freunde!Nikolay ist wieder bei Ihnen. Im letzten Artikel "
DevBoy - wie ich ein Open-Source-Geräteprojekt erstellt und ein Projekt auf Kickstarter gestartet habe " lag der Schwerpunkt mehr auf Aussehen und Hardware. Heute werden wir darüber sprechen, wie dies "
innen " gemacht wird, und den Softwareteil analysieren.

Wen kümmert es - ich bitte um eine Katze.
Wie bereits erwähnt, basiert das Projekt auf dem Mikrocontroller
STM32F415RG von STMicroelectronics auf dem ARM Cortex-M4-Kern. Es gibt verschiedene IDEs für die Entwicklung von Mikrocontrollern für diese Mikrocontroller. Für ein Open Source-Projekt benötigen Sie jedoch mindestens eine kostenlose IDE und vorzugsweise Open Source. Darüber hinaus muss die IDE in
STM32CubeMX weiterhin unterstützt
werden . Als ich anfing, an diesem Projekt zu arbeiten, gab es nur eine IDE, die all diese Anforderungen erfüllte -
System Workbench für STM32 .
Im Moment gibt es Atollic TrueStudio, das kostenlos wurde, nachdem STMicroelectronics sie gekauft hatte.
Das nächste verwendete Programm ist
STM32CubeMX . Dieses Programm ist ein Dienstprogramm zum Konfigurieren der Mikrocontroller-Peripheriegeräte mithilfe einer grafischen Oberfläche.

Das Ergebnis ist ein Code, der Hardware
A bstraction
L ayer (HAL) enthält. Viele Programmierer mögen diese "
Kreation " nicht wirklich, sie ist nicht ohne Fehler, aber sie vereinfacht die Entwicklung erheblich und verbessert die Portabilität von Programmen zwischen verschiedenen Mikrocontrollern von STMicroelectronics.
Darüber hinaus können Sie während der Konfiguration die Verwendung von Open Source-Software von Drittanbietern wie
FreeRTOS ,
FatFS und einigen anderen
festlegen .
Wir haben die Beschreibung der verwendeten Software
fertiggestellt .
Kommen wir nun zum interessantesten Teil -
DevCore . Der Name kommt von der "
Core Development ", lass uns in Ordnung gehen.
Zunächst ist es
C ++ RTOS Wrapper (
in diesem Fall FreeRTOS ). Vrapper wird aus zwei Gründen benötigt:
- Es ist viel schöner, ein Objekt zu erstellen und dann beispielsweise mutex.Take () aufzurufen, als ein Handle zu erstellen, die Funktion create aufzurufen und dieses Handle dann an alle Mutex-Funktionen zu übergeben
- Wenn RTOS ersetzt werden muss, reicht es aus, den Wrapper zu ersetzen und nicht alle Aufrufe von RTOS-Funktionen aus dem Code
Es macht keinen Sinn, den Wrapper-Code hierher zu bringen, wen interessiert das?
Wir schauen uns GitHub an und gehen weiter.
Der nächste Teil ist das
Application Framework . Dies ist die Basisklasse für alle Aufgaben. Da dies nur zwei relativ kleine Dateien sind, ist es sinnvoll, sie vollständig aufzulisten:
Vererbte Klassen können 4 virtuelle Funktionen überschreiben:
- Setup () ist eine Funktion, die vor dem Starten einer Aufgabe aufgerufen wird. Die Code-Vervollständigung ist in all diesen Funktionen aller Aufgaben vor der Ausführung der Hauptzyklen garantiert.
- Loop () - der Hauptaufgabenzyklus, in dem die Aufgabe selbst organisiert, was sie will. Kann nicht in Verbindung mit den folgenden beiden Funktionen verwendet werden.
- TimerExpired () - eine Funktion, die regelmäßig mit einem bestimmten Intervall aufgerufen wird. Praktisch, um beispielsweise die Abfrage eines Sensors zu implementieren.
- ProcessMessage () - Funktion zum Verarbeiten von Nachrichten aus anderen Aufgaben.
Die ersten beiden Funktionen implementieren "
Arduino-Style " für Aufgaben.
Die nächsten beiden implementieren das "
Ereignis " -System, das die Interaktion von Aufgaben vereinfacht. Bei diesem Ansatz implementiert die Aufgabe eine externe Schnittstelle in Form von Funktionen, die Sendedaten über eine interne Mailbox an die Aufgabe senden. Bei diesem Ansatz muss sich der Benutzer, der diese Schnittstelle verwendet, keine Gedanken darüber machen, in welchem Kontext Aktionen ausgeführt werden. Dies ist zwar nur für Setter oder Teams möglich. Für Getter ist es am besten, Mutexe und Datenkopien zu verwenden, um die Mutex-Erfassung für lange Zeit zu verhindern.
Dieser Ansatz wurde entdeckt, als ich Software für medizinische Geräte entwickelte. Der Mikrocontroller verfügt über einen
Watchdog, und bei vielen Aufgaben müssen Sie alle verfolgen. Zu diesem Zweck gab es eine separate Aufgabe, die den Watchdog bediente und Nachrichten von anderen Aufgaben empfing, die von der Funktion TimerExpired () gesendet wurden. Wenn während des Timer-Zeitraums der Aufgabe * n keine Nachrichten vorhanden waren, die Aufgabe gestorben ist,
löschen wir
das Licht und ergreifen Maßnahmen, um alle Drüsen auszuschalten, die den Patienten betreffen.
Alle Aufgaben sind Singleton-Aufgaben. Sie können sie nicht direkt erstellen, aber Sie können einen Link zur Aufgabe erhalten. Zu diesem
Zweck implementiert jede Aufgabe die statische
GetInstance () -Methode:
Ebenfalls enthalten sind Aufgaben für die
Audioausgabe , für
Eingabemodule und für die
Bildschirmwartung.Die Aufgabe
der Tonausgabe ist recht einfach: Sie empfängt eine Reihe von Frequenzen und Dauern und ändert einfach regelmäßig die Timer-Einstellungen, um Rechteckimpulse einer bestimmten Frequenz zu erzeugen.
Die Wartung von
Wassermodulen ist ebenfalls recht einfach. Von den interessanten Punkten wird das Modul automatisch erkannt: Zuerst messen wir mit dem ADC die Spannung, wenn sie im Bereich von 25% bis 75% der Versorgungsspannung liegt, wird ein analoger Joystick eingesetzt, andernfalls Tasten oder ein Encoder. Wenn es sich nicht um einen Joystick handelt, überprüfen Sie die vierte Zeile des E / A-Moduls: Wenn es sich auf einem hohen Pegel befindet, sind dies Tasten (
alle Tasten werden zur Stromversorgung hochgezogen und, wenn die Tasten gedrückt werden, zum Boden geschlossen ). Wenn es niedrig ist, handelt es sich um einen Encoder (eine
kleine Taste wird „hochgezogen“) auf den Boden und wenn gedrückt, schließt sich die Stromversorgung ).
Die Bildschirmwartungsaufgabe ist die interessanteste Aufgabe. Der Bildschirm ist zunächst 320 x 240 x 16 Bit groß, sodass Sie 153600 Byte für den Framebuffer benötigen . Das ist nicht nur viel, es ist einfach riesig - in diesem Mikrocontroller sind nur 192 KB RAM vorhanden, und in Mikrocontrollern ist es möglicherweise einfacher, überhaupt nicht die richtige Größe zu haben. Wie soll ich sein? Die Antwort ist einfach: Zeichnen Sie den Bildschirm in Teilen! Aber Sie können etwas auf verschiedene Arten zeichnen ...Die Lösung, die ich für diese Aufgabe angewendet habe, ist wie alle genial. Es hat einen Puffer auf zwei Bildschirmzeilen. Wir zeichnen alles, was in einer Zeile stehen soll, senden es über SPI im DMA-Modus an den Bildschirm und können zu diesem Zeitpunkt eine weitere Zeile vorbereiten.Woher weiß die Aufgabe, was in der Linie sein soll und wie sie zu zeichnen ist? Aber sie weiß es nicht!Aber sie hat eine Liste von Objekten, die wissen, wie man sich selbst zeichnet. Jedes dieser Objekte wird von der VisObject- Klasse geerbt .Die Bildschirmwartungsaufgabe für jede Linie durchläuft die Liste der Objekte und ruft die Funktion DrawInBufW () auf. Dabei wird ein Zeiger auf den Puffer, die Anzahl der Punkte, die zu zeichnende Linie und die Startposition übergeben ( bis die Idee verwendet wurde, den Bildschirmsteuerungsmodus zum Aktualisieren des Fensters zu verwenden ). Tatsächlich zeichnet sich jedes Objekt über die bereits gezeichneten Objekte und es ist einfach, die Objekte in der gewünschten Reihenfolge anzuordnen, indem Sie sie einfach an der gewünschten Position in der Liste platzieren.Darüber hinaus erleichtert dieser Ansatz die Integration der Verarbeitung aktiver Objekte. Nach dem Empfang der Koordinaten vom Touchscreen-Controller kann die Bildschirmwartungsaufgabe das Arbeitsblatt von Ende an auf der Suche nach dem aktiven Objekt durchlaufen, das in die Koordinaten des Drückens fällt. Wird ein solches Objekt gefunden, wird die virtuelle Funktion Action () für das angegebene Objekt aufgerufen.Im Moment gibt es Objekte für Linien, Grundelemente ( Linie, Quadrat, Kreis ), Bilder und Kachelkarten ( zum Erstellen von Spielen ).Auch in DevCore betritt einen anderen Code für einige Elemente der Benutzeroberfläche ( wie zum Beispiel ein Menü ), die Schnittstelle für den I2C - Treiber, I2C - Treiber und Bibliotheken für das Arbeiten mit Sensor BME280 und EEPROM 24S256, aber es ist nicht so interessant, und doch will ich nicht beschreiben - und es stellte sich heraus , ziemlich groß .Der vollständige Code ist ohne Registrierung und SMS auf GitHub verfügbar : https://github.com/nickshl/devboyPS Anscheinend geht das Unternehmen zu Epic Fail. In der ersten Woche nur drei Bäcker, darunter ein Dollar aus einer Art " Innovationsfonds"", $ 180 von einer Person, die wahrscheinlich aus einem Artikel über Habré ( Danke, Andrey! ) Von diesem Projekt erfahren hat. Und der Rest von meinem Kollegen aus einem benachbarten Würfel.Kein Geld zu sammeln ist kein Problem. Das Problem ist das mangelnde Interesse an dem Projekt ...