Weltweiter kostenloser Versand ab 120 € Bestellwert – Zahlung mit PayPal und Stripe – Hergestellt in Finnland

Ruuvi Firmware – Teil 8: Echtzeituhr

Ruuvi Firmware Serie Teil 8 Intro-Bild

In diesem Teil des Tutorials fügen wir Unterstützung für die Echtzeituhr (RTC) auf dem nRF52832 hinzu. Der finale Code dieses Blogbeitrags kann auf Ruuvi GitHub im ruuviblog-Branch, Tag 3.8.0-alpha, heruntergeladen werden.

Bitte folge Teil 1 der Serie für Details zum Klonen des Repositories und Kompilieren des Codes. Die finale Hex-Datei dieses Tutorials kann vom Ruuvi Jenkins heruntergeladen werden.

ruuvi-firmware.c Architektur 3.8.0

Echtzeituhr

Die RTC wird verwendet, um die verstrichene Zeit außerhalb des Programmzustands zu verfolgen. Vorerst begnügen wir uns damit, Millisekunden seit dem Programmstart zu zählen und unsere Sensordatenproben mit Zeitstempeln zu versehen. Später könnten wir einen Mechanismus hinzufügen, um die interne Uhr des nRF52832 mit einer extern vorgegebenen Zeit zu synchronisieren, wie z. B. der Unix-Epoche.

RTC-Schnittstelle

Da die Konfiguration von Dingen wie Skalierung, Auflösung oder Abtastrate für die RTC nicht wirklich sinnvoll ist, verwenden wir die Sensor-Schnittstelle nicht für das RTC-Peripheral. Wir definieren nur die Funktionen init, uninit und millis für die RTC und fügen einen Funktionszeiger zur Zeitstempelfunktion in unserer Sensor-Schnittstelle hinzu.

ruuvi_interface_rtc.h
ruuvi_interface_rtc.h

RTC-Treiber

Der interne Zähler des nRF52 hat nur 24 Bit, aber glücklicherweise haben wir ein Overflow-Event, das verwendet werden kann, um die Zeitpunkte zu verfolgen, an denen der interne Zähler übergelaufen ist.

Bisher hat unser Sleep-Modus alle Takte ausgeschaltet, und die einzige Möglichkeit zum Aufwachen war über einen externen Interrupt, wie z. B. einen Tastendruck. Das bedeutet jedoch, dass die Zeit für unser Gerät während des Schlafens nicht existiert. Wir können den Niederfrequenztakt (LFCLK) starten, wenn wir die RTC initialisieren, und den LFCLK während des Schlafens aktiv halten, um die Zeit über die Schlafphasen hinweg zu verfolgen.

Da das vom Bluetooth-Stack verwendete Nordic Softdevice den Niederfrequenzquarz aktiv hält, entstehen für den LFCLK im fertigen Programm keine „zusätzlichen“ Energiekosten. Das SDK bietet praktische Anforderungs– und Freigabe-Funktionen für den LFCLK, die verfolgen, ob der LFCLK gestoppt werden kann, falls es mehrere Benutzer für den Taktgeber gibt, sodass unser RTC-Treiber den LFCLK anfordern und freigeben kann, ohne sich um den Zustand anderer Treiber kümmern zu müssen.

Da wir 64 Bit als Zählerbreite verwenden, brauchen wir den Prescaler der RTC nicht wirklich. Wir erhöhen die Ticks mit 32,768 kHz des LFCLK, was uns etwa 512 Sekunden zwischen den Hardware-Zählerüberläufen und 17.850 Jahre bis zum Überlauf unseres Software-Zählers gibt. Wir könnten auch eine Sub-Millisekunden-Auflösung für die Zeitstempel erhalten, aber vorerst ist das nicht notwendig.

Integration der RTC

Wir fügen die Zeitstempelfunktion zu unserer RTCSchnittstelle hinzu und passen unsere Treiber an, um diese aufzurufen, anstatt den Zeitstempel der Proben einfach als ungültig zu markieren. Um Abhängigkeiten zwischen den Sensor-Schnittstellen und der RTC selbst zu vermeiden, fügen wir die Zeitstempelfunktion als Funktionszeiger zur Sensor-Schnittstelle hinzu und setzen den Funktionszeiger bei der RTC-Initialisierung auf die Schnittstelle.

Jetzt können wir endlich auch Debouncing-Unterstützung zu unserem Button-Code hinzufügen: Wir versehen den Tastendruck mit einem Zeitstempel und ignorieren das Event, wenn nicht genug Zeit seit dem letzten registrierten Druck vergangen ist.

task_button.c – keine Doppelklicks mehr
task_button.c – keine Doppelklicks mehr

Schließlich beheben wir den UINT64-Druckfehler bei ARMGCC, indem wir einfach die höheren 32 Bit des Zeitstempels weglassen. Das gibt uns immer noch fast 50 Tage, bevor unser Zeitstempel überläuft.

Testen

Im vorherigen Teil haben wir begonnen, Unit-Tests zu erstellen, die prüfen, ob jede Sensor-Schnittstelle bei Initialisierung und Deinitialisierung das richtige Verhalten zeigt. Erweitern wir den Test und fügen Tests für das Abrufen und Setzen von Skalierung, Abtastrate und Auflösung hinzu. Da alle Funktionen dieselbe Signatur haben, können wir dieselben Tests für jede der Funktionen verwenden.

Diesmal findet unser neuer Test ein Problem im vorherigen Test. Da der Initialisierungstest die Sensorstruktur vor der ersten Initialisierung nicht auf Null setzt, ist unser Initialisierungstest zufrieden zu sehen, dass ein Funktionszeiger nicht NULL ist, wenn alte Werte im Speicher verbleiben, auf den unsere Struktur zeigt. Wenn wir tatsächlich versuchen, die Funktion aufzurufen, stürzt das Programm ab, da der Funktionszeiger nicht auf eine gültige Adresse zeigt. Beheben wir sowohl den Test als auch den Fehler und machen weiter.

Debug-Terminal
Wieder einmal finden unsere Tests Fehler

Zeit, zurückzugehen und die Treiber etwas aufzuräumen. Zuerst sehen wir, dass wir Probleme mit den Zeilen 187, 193 und 223 unseres ADC-Selbsttests hatten.

Unser Fehler liegt in der NULL-Prüfung
Unser Fehler liegt in der NULL-Prüfung
Die Fehlerquelle liegt in den Skalierungsfunktionen
Die Fehlerquelle liegt in den Skalierungsfunktionen

Es scheint, dass unser ADC keine ordnungsgemäße NULL-Zeiger-Prüfung im Skalierungs-Setter und -Getter hat. Beheben wir das.

NULL-Prüfungen hinzugefügt
NULL-Prüfungen hinzugefügt

Jetzt führen wir die Tests erneut aus:

Der ADC-Test besteht jetzt
Der ADC-Test besteht jetzt

Nach der Behebung bestehen wir 11 von 16 Tests, gegenüber vorher 9 von 16. Die restlichen Fehler werden auf ähnliche Weise aufgespürt und behoben.

Gefundene Probleme
Die von den Tests gefundenen Probleme sind jetzt behoben und die Zeitstempel sehen gut aus

Stromverbrauch

Da der LFCLK ständig läuft, können wir nach Aktivierung der RTC einen gewissen Anstieg des Stromverbrauchs erwarten. Schauen wir uns an, wie es aussieht.

Stromverbrauch im Leerlauf
Stromverbrauch im Leerlauf

Unser aktueller Verbrauch liegt jetzt bei 6,4 μA im Leerlauf, 1,4 μA mehr als die 5,0 μA in unserem vorherigen Beitrag.

Fazit

In diesem Tutorial haben wir RTC-Unterstützung und Zeitstempel zu unseren Sensorauslesungen hinzugefügt. Jetzt haben wir alles, was wir brauchen, um das Ruuvi-Datenformat 3 zu implementieren. Im nächsten Beitrag werden wir beginnen, die Daten vom RuuviTag zu übertragen.

Bleib dran und folge @ojousima und @ruuvicom auf Twitter für #FirmwareFriday-Beiträge!