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!
1 | switch( action ) {
|
2 | case KERN_CLK_SYNC: {
|
3 | struct tm time;
|
4 | ioctl( rtcFile, RTC_RD_TIME, &time ); // <-- Hier wird Rechenzeit abgegeben
|
5 | time.tm_isdst = 0;
|
6 | set_system_time( mk_gmtime( &time ) );
|
7 | } break;
|
8 | default: break;
|
9 | }
|
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:
1 | void set_system_time( time_t t ) {
|
2 | extern volatile time_t __system_time;
|
3 | // xSemaphoreTake
|
4 | sys_atomic() {
|
5 | __system_time = t;
|
6 | }
|
7 | // xSemaphoreGive
|
8 | }
|
9 |
|
10 | time_t time( time_t *tm ) {
|
11 | time_t ret;
|
12 | // xSemaphoreTake
|
13 | extern time_t __time_libc( time_t * );
|
14 | ret = __time_libc( tm );
|
15 | // xSemaphoreGive
|
16 | return ret;
|
17 | }
|
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