
Dieser Artikel befasst sich mit Signalen, die die einfachsten Mechanismen für die Interaktion zwischen Aufgaben in Nucleus SE darstellen. Sie bieten eine kostengünstige Möglichkeit, einfache Nachrichten zwischen Aufgaben zu übertragen.
Frühere Artikel in der Reihe:
Artikel Nr. 15. Speicherpartitionen: Dienste und DatenstrukturenArtikel # 14. Speicherbereiche: Einführung und GrundversorgungArtikel Nr. 13. Aufgabendatenstrukturen und nicht unterstützte API-AufrufeArtikel 12. Dienstleistungen für die Arbeit mit AufgabenArtikel 11. Aufgaben: Konfiguration und Einführung in die APIArtikel 10. Scheduler: Erweiterte Funktionen und KontexterhaltungArtikel 9. Scheduler: ImplementierungArtikel 8. Nucleus SE: Internes Design und BereitstellungArtikel 7. Nucleus SE: EinführungArtikel 6. Andere RTOS-DiensteArtikel 5. Aufgabeninteraktion und SynchronisationArtikel 4. Aufgaben, Kontextwechsel und InterruptsArtikel 3. Aufgaben und PlanungArtikel 2. RTOS: Struktur und Echtzeitmodus
Artikel 1. RTOS: Einführung.
Signale verwenden
Signale unterscheiden sich von allen anderen Arten von Kernelobjekten darin, dass sie nicht autonom sind: Signale sind Aufgaben zugeordnet und können ohne sie nicht existieren. Wenn die Anwendung für die Verwendung von Signalen konfiguriert ist, verfügt jede Task über einen Satz von acht Signalflags.
Jede Aufgabe kann Signale für eine andere Aufgabe setzen. Signale können nur vom Eigentümer des Signals gelesen werden. Während des Lesens werden die Signale zurückgesetzt. Aufgaben können keine Signale von anderen Aufgaben lesen oder zurücksetzen.
Nucleus RTOS verfügt über ein Tool, mit dem Aufgaben Funktionen zuweisen können, die ausgeführt werden, wenn eine andere Aufgabe ein oder mehrere Signalflags setzt. Dies erinnert etwas an eine Interrupt-Verarbeitungsroutine. Diese Funktion wird in Nucleus SE nicht unterstützt. Hier sollten Aufgaben explizit Signalflags anfordern.
Signaleinrichtung
Wie bei den meisten Nucleus SE-Objekten wird die
Signaloptimierung durch die Direktiven
#define in
nuse_config.h bestimmt . Der Hauptparameter ist
NUSE_SIGNAL_SUPPORT , der die Funktionsunterstützung aktiviert (für alle Aufgaben in der Anwendung). Die Frage nach der Anzahl der Signale lohnt sich nicht: Für jede Aufgabe werden 8 Flags vergeben.
Das Einstellen dieses Freigabeparameters dient als Hauptsignalaktivator. Dies liefert eine genau definierte Datenstruktur mit einer geeigneten Größe. Darüber hinaus aktiviert diese Option die API-Einstellungen.
API-Aufrufe aktivieren
Jede API-Funktion (Dienstprogrammaufruf) in Nucleus SE wird durch die Direktive
#define in
nuse_config.h aktiviert. Zu den Signalen gehören:
NUSE_SIGNALS_SEND NUSE_SIGNALS_RECEIVE
Standardmäßig sind sie auf
FALSE gesetzt , wodurch jeder Serviceabruf deaktiviert und verhindert wird, dass der Code, der sie implementiert, aktiviert wird. Um die Signale in der Anwendung zu konfigurieren, müssen Sie die erforderlichen API-Aufrufe auswählen und die entsprechenden Anweisungen auf
TRUE setzen .
Das Folgende ist ein Auszug aus der Standarddatei
nuse_config.h :
#define NUSE_SIGNAL_SUPPORT FALSE #define NUSE_SIGNALS_SEND FALSE #define NUSE_SIGNALS_RECEIVE FALSE
Eine aktivierte API-Funktion mit deaktivierter Signalisierungsunterstützung führt zu einem Kompilierungsfehler. Wenn Ihr Code einen API-Aufruf verwendet, der nicht aktiviert wurde, tritt ein Layoutfehler auf, da der Implementierungscode nicht in der Anwendung enthalten war. Natürlich ist die Aufnahme von zwei API-Funktionen etwas unnötig, da es keinen Sinn macht, die Signalunterstützung zu aktivieren, wenn diese APIs fehlen. Aus Gründen der Kompatibilität mit anderen Nucleus SE-Funktionen wurden Aktivatoren hinzugefügt.
Rufsignale
Nucleus RTOS unterstützt vier signalbezogene Overhead-Anrufe mit folgenden Funktionen:
- Senden von Signalen an eine bestimmte Aufgabe. Nucleus SE ist in der Funktion NUSE_Signals_Send () implementiert.
- Empfang von Signalen. Nucleus SE ist in der Funktion NUSE_Signals_Receive () implementiert.
- Registrierung des Signalhandlers. Nicht in Nucleus SE implementiert.
- Ein- / Ausschalt- (Steuer-) Signale. Nicht in Nucleus SE implementiert.
Die Implementierung jeder dieser Herausforderungen wird nachstehend ausführlich erörtert.
Signalisierungs- und Empfangsdienste
Die grundlegenden Operationen, die an einer Reihe von Aufgabensignalen ausgeführt werden können, sind das Senden von Daten (kann von jeder Aufgabe ausgeführt werden) und das Lesen von Daten (daher kann das Löschen der Daten nur von der Eigentümeraufgabe ausgeführt werden). Nucleus RTOS und Nucleus SE bieten zwei grundlegende API-Aufrufe für diese Operationen, die nachfolgend beschrieben werden.
Da Signale Bits sind, werden sie am besten als Binärzahlen dargestellt. Da Standard C die Darstellung von
Binärkonstanten (nur oktal und hexadezimal) in der
Vergangenheit nicht unterstützt hat, verfügt Nucleus SE über eine nützliche Header-Datei
nuse_binary.h , die
# define- Zeichen wie
b01010101 für alle 256 8-Bit-Werte enthält. Das Folgende ist ein Auszug aus der Datei
nuse_binary.h :
#define b00000000 ((U8) 0x00) #define b00000001 ((U8) 0x01) #define b00000010 ((U8) 0x02) #define b00000011 ((U8) 0x03) #define b00000100 ((U8) 0x04) #define b00000101 ((U8) 0x05)
Signale senden
Jede Aufgabe kann Signale an jede andere Aufgabe in der Anwendung senden. Beim Senden von Signalen werden ein oder mehrere Signalflags gesetzt. Dies ist eine ODER-Verknüpfung, die zuvor gesetzte Flags nicht beeinflusst.
Rufen Sie an, um Signale an Nucleus RTOS zu sendenPrototyp eines Serviceabrufs:
STATUS NU_Send_Signals (Task NU_TASK *, UNSIGNED-Signale);Parameter:
Task - Zeiger auf die Task-Steuereinheit, zu der die gesetzten Signalflags gehören;
Signale - Der Wert der gesetzten Signalflags.
Rückgabewert:
NU_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NU_INVALID_TASK - ungültiger Zeiger auf die Aufgabe;
Rufen Sie an, um Signale an Nucleus SE zu sendenDieser API-Aufruf unterstützt die Kernfunktionalität der Nucleus RTOS-API.
Prototyp eines Serviceabrufs:
STATUS_NUSE_Signals_Send (NUSE_TASK-Task, U8-Signale);Parameter:
Task - Index (ID) der Task, zu der die gesetzten Signalflags gehören;
Signale - Der Wert der gesetzten Signalflags.
Rückgabewert:
NUSE_SUCCESS - Der Serviceabruf wurde erfolgreich abgeschlossen.
NUSE_INVALID_TASK - ungültiger Aufgabenindex.
Implementierung der Signalübertragung in Nucleus SEUnten finden Sie den vollständigen Code für die Funktion NUSE_Signals_Send ():
STATUS NUSE_Signals_Send(NUSE_TASK task, U8 signals) { #if NUSE_API_PARAMETER_CHECKING if (task >= NUSE_TASK_NUMBER) { return NUSE_INVALID_TASK; } #endif NUSE_CS_Enter(); NUSE_Task_Signal_Flags[task] |= signals; NUSE_CS_Exit(); return NUSE_SUCCESS; }
Der Code ist sehr einfach. Nach jeder Überprüfung der Parameter durchlaufen die Signalwerte die ODER-Verknüpfung der Signalflags der angegebenen Aufgabe. Das Sperren von Aufgaben wirkt sich nicht auf Signale aus.
Signale empfangen
Eine Task kann nur einen eigenen Satz von Signalflags lesen. Während des Lesens werden die Flag-Werte zurückgesetzt.
Aufruf zum Empfangen von Signalen in Nucleus RTOSPrototyp eines Serviceabrufs:
UNSIGNED NU_Receive_Signals (VOID);Parameter: keine.
Rückgabewert:
Signalflagwerte.
Rufen Sie an, um Signale in Nucleus SE zu empfangenDieser API-Aufruf unterstützt die Kernfunktionalität der Nucleus RTOS-API.
Prototyp eines Serviceabrufs:
U8 NUSE_Signals_Receive (void);Parameter: keine.
Rückgabewert:
Signalflagwerte.
Implementierung des Nucleus SE-SignalempfangsDas Folgende ist der vollständige Code für die Funktion
NUSE_Signals_Receive () :
U8 NUSE_Signals_Receive(void) { U8 signals; NUSE_CS_Enter(); Signals = NUSE_Task_Signal_Flags[NUSE_Task_Active]; NUSE_Task_Signal_Flags[NUSE_Task_Active] = 0; NUSE_CS_Exit(); return signals; }
Der Code ist sehr einfach. Der Wert der Flags wird kopiert, der Anfangswert wird zurückgesetzt und die Kopie wird von der API-Funktion zurückgegeben. Das Sperren von Aufgaben wirkt sich nicht auf Signale aus.
Datenstrukturen
Da Signale keine unabhängigen Objekte sind, hängt die Verwendung des Speichers von den Aufgaben ab, zu denen sie gehören. Nachfolgend finden Sie einige Informationen zum vollständigen Verständnis. Signale verwenden eine Datenstruktur (im RAM), die wie andere Nucleus SE-Objekte eine Tabelle ist, deren Abmessungen der Anzahl der Aufgaben in der Anwendung entsprechen. Diese Datenstruktur wird nur verwendet, wenn die Signalunterstützung aktiviert ist.
Ich empfehle dringend, dass Anwendungscode nicht direkt auf diese Datenstruktur zugreift, sondern die verfügbaren API-Funktionen verwendet. Dies vermeidet Inkompatibilität mit zukünftigen Versionen von Nucleus SE, unerwünschte Nebenwirkungen und vereinfacht auch die Portierung der Anwendung auf Nucleus RTOS. Die Datenstruktur wird nachstehend ausführlich erläutert, um das Verständnis der Prinzipien für Serviceabrufe und Debugging zu vereinfachen.
Die Struktur der im RAM abgelegten Daten
Datenstruktur:
NUSE_Task_Signal_Flags [] - Ein Array vom Typ U8 mit einem Eintrag für jede konfigurierte Aufgabe. In diesem Array werden Signalflags gespeichert.
Diese Datenstruktur wird von der Funktion
NUSE_Init_Task () beim Laden von Nucleus SE auf
Null initialisiert.
Struktur der im ROM abgelegten Daten
Signalen fehlen Datenstrukturen im ROM.
Speichermengen zum Speichern von Signaldaten
Wie bei allen Nucleus SE-Kernobjekten ist die für Signale erforderliche Speichermenge vorhersehbar.
Die Datenmenge im ROM für alle Signale in der Anwendung beträgt 0.
Die Speichermenge zum Speichern von Daten im RAM (in Byte) für alle Signale in der Anwendung entspricht der Anzahl der konfigurierten Aufgaben (
NUSE_TASK_NUMBER ). Tatsächlich gehören diese Daten jedoch zu den Aufgaben und werden im vorherigen Artikel über die Aufgaben beschrieben.
Nicht realisierte API-Aufrufe
Zwei Nucleus RTOS API-Signalisierungsaufrufe sind in Nucleus SE nicht implementiert:
Signalhandler-Registrierung
Dieser API-Aufruf richtet die Signalverarbeitungsprozedur (Funktion) für die aktuelle Aufgabe ein. Nucleus SE benötigt dies nicht, da Signalhandler nicht unterstützt werden.
Prototyp eines Serviceabrufs:
STATUS NU_Register_Signal_Handler (VOID (* signal_handler) (UNSIGNED));Parameter:
signal_handler - eine Funktion, die beim Empfang von Signalen aufgerufen werden sollte
Rückgabewert:
NU_SUCCESS - Der Anruf wurde erfolgreich abgeschlossen.
NU_INVALID_POINTER - Nullzeiger auf den Signalhandler (
NULL )
Steuerung (Aktivierung / Deaktivierung) von Signalen
Dieser Dienst aktiviert und / oder deaktiviert Signale für die aktuelle Aufgabe. Für jede Aufgabe stehen 32 Signale zur Verfügung. Jedes Signal wird in
signal_enable_mask durch ein Bit
dargestellt . Durch Hinzufügen eines Bits zu
signal_enable_mask wird das entsprechende Signal
aktiviert , und durch Löschen eines Bits wird es deaktiviert.
Prototyp eines Serviceabrufs:
UNSIGNED NU_Control_Signals (UNSIGNED enable_signal_mask);Parameter:
enable_signal_mask - Bitmuster, das die richtigen Signale darstellt.
Rückgabewert:
Maske zum Aktivieren / Deaktivieren des vorherigen Signals.
Nucleus RTOS-kompatibel
Bei der Entwicklung von Nucleus SE war es mein Ziel, die Codeebene mit Nucleus RTOS kompatibel zu halten. Signale sind keine Ausnahme und werden aus Entwicklersicht ähnlich wie in Nucleus RTOS implementiert. Es gibt einige Inkompatibilitäten, die ich für gültig hielt, da der endgültige Code viel einfacher zu verstehen ist und den Speicher effizienter nutzen kann. Andernfalls können Nucleus RTOS-API-Aufrufe fast direkt an Nucleus SE-Aufrufe übertragen werden.
Signalhandler
In Nucleus SE sind Signalhandler nicht implementiert, um die Gesamtstruktur zu vereinfachen.
Signalverfügbarkeit und -menge
In Nucleus RTOS können Tasks 32 Signalflags haben. In Nucleus SE habe ich beschlossen, die Anzahl auf acht zu reduzieren, da dies für einfachere Anwendungen ausreicht und RAM-Ressourcen spart. Bei Bedarf können die Signale vollständig ausgeschaltet werden.
Nicht realisierte API-Aufrufe
Nucleus RTOS unterstützt vier Signalisierungsdienstanrufe. Von diesen wurden zwei nicht in Nucleus SE implementiert. Ihre Beschreibung finden Sie oben im Abschnitt „Nicht realisierte API-Aufrufe“.
Über den Autor: Colin Walls ist seit über dreißig Jahren in der Elektronikindustrie tätig und widmet sich die meiste Zeit der Firmware. Heute ist er Firmware-Ingenieur bei Mentor Embedded (einer Abteilung von Mentor Graphics). Colin Walls spricht häufig auf Konferenzen und Seminaren, Autor zahlreicher technischer Artikel und zweier Bücher über Firmware. Lebt in Großbritannien.
Colins professioneller
Blog , E-Mail: colin_walls@mentor.com.