mikrocontroller.net

Forum: Compiler & IDEs avr-libc timme.h __system_time


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von sep (Gast)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich stehe gerade vor einem Problem, und habe erst einmal keine andere 
Möglichkeit gefunden als die AVR-LibC dafür ein wenig zu modifizieren. 
Ich wollte nun einmal abklopfen, ob es vielleicht noch andere 
Möglichkeiten gibt, oder ob man das schöner machen könnte...

Also, ausschlaggebend ist folgendes Problem.
Ich nutze FreeRTOS auf einem ATMega und habe nun kleine Treiber 
geschrieben. Zuerst für I²C (Interrupt-getrieben), anschließend für eine 
RTC (RV3029). Dann dachte ich mir, seit der AVR-LibC v2.0.0 ist eine 
Time-Lib mit an Board. Diese würde ich gerne nutzen. Nur um das Rad 
nicht neu zu erfinden.

Auf FreeRTOS nutze ich einen Kernel-Task. Dieser initialisiert mit die 
Hardware und anschließend werden aus einer Tabelle im Flash die weiteren 
Tasks erstellt. Das klappt alles bisher ganz gut. Bei ca. 13kB ROM und 
1,2kB RAM habe ich 4 Tasks zu laufen, und ein paar Treiber so wie ich 
sie brauche. Wenn nix zu tun ist, dann nutze ich den Tickless Idle von 
FreeRTOS.

So, nun wollte ich halt die time.h aus der AVR-LibC nutzen und das 
klappt auch erst einmal ganz gut. Bis ich nun auf folgendes Problem 
stieß.

Kommt der Controller aus dem Sleep, so sende ich noch aus der Funktion 
vApplicationSleep an den Kernel Task ein KERN_CLOCK_SYNC. Das wird dann 
anschließend auch aufgerufen.

Also fragt der Kernel-Task die RTC ab um die system_time wieder zu 
synchronisieren. Das Abfragen geht via I²C (Interrupt getrieben) und ich 
gebe Rechenzeit ab, sobald der I²C-Treiber auf die ISR warten muss. Also 
kommt ein anderer Task an die Reihe und rechnet was. Fragt dieser nun 
via time( NULL ) die Zeit ab, so ist diese falsch!
    switch( action ) {
        case KERN_CLK_SYNC: {
            struct tm time;
            ioctl( rtcFile, RTC_RD_TIME, &time ); // <-- Hier wird Rechenzeit abgegeben
            time.tm_isdst = 0;
            set_system_time( mk_gmtime( &time ) );
        } break;
        default: break;
    }

So... Mein erster naiver Ansatz war gewesen, dass ich den Scheduler 
vorübergehend abschalte mit vTaskSuspendAll... Jedoch verwende ich im 
I²C Treiber ein xQueueReceive mit einer Wartezeit, was dort nicht 
zulässig ist. (Also wenn der Scheduler deaktiviert ist. Wohin soll auch 
abgegeben werden.. :D) Also scheidet diese Möglichkeit aus...

Dann war ich am überlegen... Und bei dem Symbol __system_time aus der 
time.h handelt es sich um eine shared ressource. Diese muss also 
geschützt werden. Jedoch habe ich dazu nur die Möglichkeit, wenn ich die 
AVR-LibC ändere... :/

Und das habe ich nun getan. Ich habe die Funktionen welche auf 
__system_time zugreifen nun als weak definiert. So habe ich die 
Möglichkeit die __system_time per Semaphore vor konkurrierenden 
Zugriffen zu schützen. Wenn man sich den angehangenen Patch anschaut 
würde mein Code dann ähnlich wie in dem nächsten Bsp ausschauen:
void set_system_time( time_t t ) {
    extern volatile time_t __system_time;
    // xSemaphoreTake
    sys_atomic() {
        __system_time = t;
    }
    // xSemaphoreGive
}

time_t time( time_t *tm ) {
    time_t ret;
    // xSemaphoreTake
    extern time_t __time_libc( time_t * );
    ret = __time_libc( tm );
    // xSemaphoreGive
    return ret;
}

Was haltet ihr davon? Hier gab es doch auch welche die an der avr-libc 
mit entwickelt haben... ...
Ich würde mich dort über Rückmeldungen freuen, weil ich mir darüber 
lange den Kopf zerbrochen habe und irgendwie keine andere Möglichkeit 
gesehen habe.

Danke und Viele Grüße
Sep

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
sep schrieb:
> Also fragt der Kernel-Task die RTC ab um die system_time wieder zu
> synchronisieren. Das Abfragen geht via I²C (Interrupt getrieben) und ich
> gebe Rechenzeit ab, sobald der I²C-Treiber auf die ISR warten muss.

Das halte ich für nicht günstig. Ich würde an dieser Stelle wohl lieber 
warten, bis die aktuelle Zeit verfügbar ist.

> So... Mein erster naiver Ansatz war gewesen, dass ich den Scheduler
> vorübergehend abschalte mit vTaskSuspendAll... Jedoch verwende ich im
> I²C Treiber ein xQueueReceive mit einer Wartezeit, was dort nicht
> zulässig ist.

Hmm, hmm, verstehe.

> Und das habe ich nun getan. Ich habe die Funktionen welche auf
> __system_time zugreifen nun als weak definiert. So habe ich die
> Möglichkeit die __system_time per Semaphore vor konkurrierenden
> Zugriffen zu schützen.

Naja, eigentlich kannst du den entsprechenden Teil auch gleich neu 
schreiben. Diese Sachen sind doch völlig unabhängig vom Rest der 
time-Bibliothek. Du kannst also komplett deine eigene Idee von 
system_time und time() implementieren und dennoch den Rest aus der 
avr-libc benutzen.

Die time-Bibliothek ist m.E. ausreichend gut modularisiert, als dass da 
aus der libc.a nur die Dinge gelinkt werden, die du nicht schon selbst 
definiert hast – ganz und gar bereits ohne "weak".

Du kannst mich natürlich gern korrigieren, falls das nicht der Fall sein 
sollte. Das ist jetzt nur mein Eindruck nach dem ersten Blick auf den 
Sourcecode.

: Bearbeitet durch Moderator
von sep (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Jörg W. schrieb:
> sep schrieb:
>> Also fragt der Kernel-Task die RTC ab um die system_time wieder zu
>> synchronisieren. Das Abfragen geht via I²C (Interrupt getrieben) und ich
>> gebe Rechenzeit ab, sobald der I²C-Treiber auf die ISR warten muss.
>
> Das halte ich für nicht günstig. Ich würde an dieser Stelle wohl lieber
> warten, bis die aktuelle Zeit verfügbar ist.

Das ist ja die Frage, wie soll die aktuelle Zeit verfügbar gemacht 
werden. Der Kernel Task hat an sich die höchste Priorität im System.Das 
der I²C-Treiber zwar für den Task blockiert, aber die Rechenzeit abgibt, 
wenn er die Message sendet ist ja so gewollt. Man könnte das System 
komplett blockieren. Das wäre aber, so denke ich ziemlich ungünstig. 
Weil nicht jeder Task ist auf eine Uhrzeit angewiesen...

Jörg W. schrieb:
>> So... Mein erster naiver Ansatz war gewesen, dass ich den Scheduler
>> vorübergehend abschalte mit vTaskSuspendAll... Jedoch verwende ich im
>> I²C Treiber ein xQueueReceive mit einer Wartezeit, was dort nicht
>> zulässig ist.
>
> Hmm, hmm, verstehe.

Eine andere Möglichkeit wäre es die "User-Tasks" zu blockieren... Wobei 
dort aber auch kein unterschied besteht zu dem ersten Ansatz. Denn in 
der Zeit wo der Controller sendet und empfängt, können andere Tasks 
arbeiten, welche nicht auf time.h angewiesen sind.

Jörg W. schrieb:
>> Und das habe ich nun getan. Ich habe die Funktionen welche auf
>> __system_time zugreifen nun als weak definiert. So habe ich die
>> Möglichkeit die __system_time per Semaphore vor konkurrierenden
>> Zugriffen zu schützen.
>
> Naja, eigentlich kannst du den entsprechenden Teil auch gleich neu
> schreiben. Diese Sachen sind doch völlig unabhängig vom Rest der
> time-Bibliothek. Du kannst also komplett deine eigene Idee von
> system_time und time() implementieren und dennoch den Rest aus der
> avr-libc benutzen.
>
> Die time-Bibliothek ist m.E. ausreichend gut modularisiert, als dass da
> aus der libc.a nur die Dinge gelinkt werden, die du nicht schon selbst
> definiert hast – ganz und gar bereits ohne "weak".
>
> Du kannst mich natürlich gern korrigieren, falls das nicht der Fall sein
> sollte. Das ist jetzt nur mein Eindruck nach dem ersten Blick auf den
> Sourcecode.

Da hätte ich doch die Frage, wie sollte das aussehen. Zur Zeit habe ich 
die LibC auf meinem System installiert (Gentoo). AVR-GCC nutzt die 
system installierte. Natürlich kann ich die LibC projektspezifisch aus 
dem SRC kompilieren. Ich würde aber gerne eine Möglichkeit haben eine 
einzelne zu nutzen.

Oder wie ist das gemeint dass ich mir die Module anpassen kann?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
sep schrieb:
> Oder wie ist das gemeint dass ich mir die Module anpassen kann?

Dass du dir das für dich Relevante in dein Projektverzeichnis kopieren 
kannst, oder die entsprechenden Funktionen gleich bei dir neu schreibst.

Dank der Modularisierung der Bibliothek werden dann die durch die 
Bibliothek definierten Funktionen (und Daten) einfach nicht von dort 
geladen, denn du hast sie ja schon innerhalb deines Projekts verfügbar.

Dafür braucht man gar kein "weak", das ist ganz normale 
Bibliotheks-Funktionalität: der Linker zieht eine Bibliothek nur zur 
Auflösung undefinierter Symbole heran, und dann auch nur modulweise – 
nicht etwa die Bibliothek im Ganzen.

von sep (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Jörg W. schrieb:
> Dafür braucht man gar kein "weak", das ist ganz normale
> Bibliotheks-Funktionalität: der Linker zieht eine Bibliothek nur zur
> Auflösung undefinierter Symbole heran, und dann auch nur modulweise –
> nicht etwa die Bibliothek im Ganzen.

Verdammt. Und ich dachte genau dafür gäbe es das weak... ...
Hm. Man lernt nie aus. Ich denke ich werde das morgen einmal probieren. 
Danke für den Hinweis. ;)

von sep (Gast)


Bewertung
0 lesenswert
nicht lesenswert
So, hab das noch einmal probiert und das funktioniert. Danke. Ich bin 
immer davon ausgegangen, das ich die Funktionen nicht "überschreiben" 
kann und das dafür extra das weak da ist, Danke dafür! ^^

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.