Forum: Compiler & IDEs FreeRTOS Task in C++ erzeugen


von Manuel S. (Firma: S+S) (msimmerl)


Lesenswert?

Hallo zusammen,

hat hier jemand vielleicht Erfahrung mit der Erstellung von Tasks in 
C++?

Leider bekomme ich das selbst nicht auf die Reihe...

Hier mal mein Code:

ioCtrl.cpp
1
/* INCLUDE FILES **************************************************************/
2
3
/* IMPORT */
4
#include "common.h"
5
//#include "TaskWrapper.h"
6
/* FreeRTOS */
7
8
#if defined(__cplusplus)
9
extern "C" {     /* Make sure we have C-declarations in C++ programs */
10
#endif
11
12
#include "FreeRTOS.h"
13
#include "task.h"
14
#include "queue.h"
15
#include "timers.h"
16
17
#include "ioCtrl.h"
18
19
#if defined(__cplusplus)
20
}     /* Make sure we have C-declarations in C++ programs */
21
#endif
22
23
/* EXPORT */
24
25
26
27
void ioCtrl::task(void)
28
{
29
  vErrorMessage( "Task is starting!", 0, RADIX_NO_VALUE, 0 );
30
  portTickType xLastWakeTime;
31
    xLastWakeTime = xTaskGetTickCount();
32
33
    for(;;) {    
34
        //debug_printf("TestTask[%d]\n", this->xtest);
35
    vErrorMessage( "Task is running!", 0, RADIX_NO_VALUE, 0 );
36
      //Delay für 1000ms
37
      vTaskDelayUntil(&xLastWakeTime, ( 1000 / portTICK_RATE_MS ) );
38
    }
39
}
40
41
int ioCtrl::start(void)
42
{
43
  xTaskCreate(&taskwrapper, (const signed char*)"Task", 240, ((void *) 0), (unsigned long)1, (unsigned long)0);
44
    
45
  //xTaskGenericCreate(doTask, (const signed char*)"Task", 240, NULL, (unsigned long)1,  (unsigned long)0, (void *) 0, (const xMemoryRegion*) 0);
46
  
47
  /*if( xTaskGenericCreate(&taskrun, (const signed char*)"Task", 240, ((void *) 0), (unsigned long)1, (unsigned long)0, (unsigned long *)0, (xMemoryRegion *)0) != pdPASS)
48
    vErrorMessage( "Insufficient heap memory available to create ControlTask!", 0, RADIX_NO_VALUE, 0 );
49
  else
50
    vErrorMessage( "Task created successful!", 0, RADIX_NO_VALUE, 0 );*/
51
}


ioCtrl.h
1
#ifndef _IOCTRL_H
2
#define _IOCTRL_H
3
4
5
/// Refresh intervall in ms for ioCtrl.
6
#define SYSCNF_IOCTRL_UPDATE_INTERVAL       25
7
#define _CONTROL_QUEUE_LENGTH        10
8
#define _CONTROL_TASK_STACK_SIZE      192
9
/* Application task priorities */
10
#define CONTROL_TASK_PRIORITY               4
11
12
#if defined(__cplusplus)
13
extern "C" {     /* Make sure we have C-declarations in C++ programs */
14
#endif
15
16
class ioCtrl
17
{
18
19
private:
20
21
public:
22
  /// constructor
23
    ioCtrl() {}
24
    /// destructor
25
    ~ioCtrl() {}
26
  
27
  
28
    void task(void);
29
    int start(void);
30
};
31
32
extern "C" void taskwrapper(void* parm) {
33
    (static_cast<ioCtrl*>(parm))->task();
34
}
35
36
#if defined(__cplusplus)
37
}     /* Make sure we have C-declarations in C++ programs */
38
#endif
39
40
#endif /*_IOCTRL_H*/

Bei dem extern "C" Aufruf bekomme ich folgende Fehlermeldung:
multiple definition of 'taskwrapper'

Der Task will einfach nicht starten...

Mfg
msimmerl

von Karl H. (kbuchegg)


Lesenswert?

Manuel Simmerl schrieb:


> extern "C" void taskwrapper(void* parm) {
>     (static_cast<ioCtrl*>(parm))->task();
> }


extern "C" inline void taskwrapper(void* parm) {
     (static_cast<ioCtrl*>(parm))->task();
}

Das inline ist wichtig. Denn sonst erzeugst du in jedem Cpp-File, 
welches dieses Header File includiert eine neue Funktion taskwrapper und 
es setzt einen ....
> Bei dem extern "C" Aufruf bekomme ich folgende Fehlermeldung:
> multiple definition of 'taskwrapper'



Edit:
Oder aber du ziehst die Funktion überhaupt in ioCtl.cpp hinein. Es gibt 
ja so wie es aussieht, sowieso keinen Grund, warum die im Header File 
sein sollte. Ist wahrscheinlich sowieso die bessere Lösung.

von Manuel S. (Firma: S+S) (msimmerl)


Lesenswert?

Super, danke für deine schnell Antwort.
Der Fehler ist weg.

Nur leider läuft der Task immer noch nicht...

Siehst du vielleicht einen weiteren Fehler im Code?

Viele Grüße
msimmerl

von Hans (Gast)


Lesenswert?

Du übergibt 0 in dein trampolin... ((void *) this) als parameter sollte 
reichen

von Manuel S. (Firma: S+S) (msimmerl)


Lesenswert?

Hab es jetzt folgendermaßen abgeändert:

xTaskCreate(&taskwrapper, (const signed char*)"Task", 240, ((void *) 
this), (unsigned long)4, (unsigned long)0);

Läuft leider immer noch nicht.

Mfg
msimmerl

von Karl H. (kbuchegg)


Lesenswert?

Hast du denn schon mal eine der mitgelieferten Demos probiert, studiert 
und ein wenig abgeändert?


In der Demo-Übersicht seh ich zum Beispiel, dass man
  vTaskStartScheduler();
aufrufen muss - erst dann laufen die Tasks.
Machst du das?

http://www.freertos.org/a00102.html

von Manuel S. (Firma: S+S) (msimmerl)


Lesenswert?

Ja das mache ich in der main.
Ich habe auch andere Tasks am laufen, jedoch nicht in einer Klasse
und die laufen ohne Probleme.

von Karl H. (kbuchegg)


Lesenswert?

Mich macht zum Beispiel stutzig, dass du eine 0 für den Pointer zum 
TaskHandle übergibst. Die Doku erwähnt nicht, dass dies zulässig ist.

Auch solltest du dir angewöhnen, ReturnCodes der Funktion aufzufangen 
und auszuwerten. xTaskCreate liefert einen Code, ob die Funktion 
geklappt hat oder nicht.

Und deine letzten beiden Parameter im Aufruf sind mir da ehrlich gesagt 
etwas zuviel gecastet. Das sollte eigentlich nicht notwendig sein.

Die Funktionssignatur
http://www.freertos.org/a00125.html
lautet
1
portBASE_TYPE xTaskCreate( 
2
                            pdTASK_CODE pvTaskCode, 
3
                            const portCHAR * const pcName, 
4
                            unsigned portSHORT usStackDepth, 
5
                            void *pvParameters, 
6
                            unsigned portBASE_TYPE uxPriority, 
7
                            xTaskHandle *pvCreatedTask 
8
                          );

da jetzt einfach eine 1 bzw eine 0 zu casten, ist meiner Meinung nach 
etwas gewagt. Und wie gesagt: ob die 0 überhaupt zulässig ist .....

von Manuel S. (Firma: S+S) (msimmerl)


Lesenswert?

So habs jetzt nochmals angepasst:
1
/* INCLUDE FILES **************************************************************/
2
3
/* IMPORT */
4
#include "common.h"
5
/* FreeRTOS */
6
7
#if defined(__cplusplus)
8
extern "C" {     /* Make sure we have C-declarations in C++ programs */
9
#endif
10
11
#include "FreeRTOS.h"
12
#include "task.h"
13
#include "queue.h"
14
#include "timers.h"
15
16
#include "ioCtrl.h"
17
#if defined(__cplusplus)
18
}     /* Make sure we have C-declarations in C++ programs */
19
#endif
20
21
/* EXPORT */
22
23
xTaskHandle xHandle;
24
25
extern "C" void taskwrapper(void* parm) {
26
    (static_cast<ioCtrl*>(parm))->task();
27
}
28
29
void ioCtrl::task(void)
30
{
31
  vErrorMessage( "Task is starting!", 0, RADIX_NO_VALUE, 0 );
32
  portTickType xLastWakeTime;
33
    xLastWakeTime = xTaskGetTickCount();
34
35
    for(;;) 
36
        {    
37
    vErrorMessage( "Task is running!", 0, RADIX_NO_VALUE, 0 );
38
      //Delay für 1000ms
39
      vTaskDelayUntil(&xLastWakeTime, ( 1000 / portTICK_RATE_MS ) );
40
    }
41
}
42
43
int ioCtrl::start(void)
44
{
45
  vErrorMessage( "Create task!", 0, RADIX_NO_VALUE, 0 );
46
  xTaskCreate(&taskwrapper, (const signed char*)"Task", 240, NULL, CONTROL_TASK_PRIORITY, &xHandle);
47
}

Nur leider nach wie vor ohne Erfolg...

Habe den Rückgabewert überprüft von xTaskCreate. Der besagt, dass der 
Task erfolgreich angelegt wurde.

von Karl H. (kbuchegg)


Lesenswert?

Manuel Simmerl schrieb:

>   xTaskCreate(&taskwrapper, (const signed char*)"Task", 240, NULL,
> CONTROL_TASK_PRIORITY, &xHandle);


Wieso NULL?


Dieses Argument hier

 xTaskCreate(&taskwrapper, (const signed char*)"Task", 240, NULL,
                                                            ****

das ist das, welches die Funktion taskwrapper hier

extern "C" void taskwrapper(void* parm) {

                                 *******

wieder bekommt!
Wie willst du denn einen NULL Pointer vernünftig

    (static_cast<ioCtrl*>(parm))->task();

auf einen ioCtrl Pointer umcasten um damit dann die Memberfunktion 
dieses Objektes aufzurufen?

(Hast du eigentlich schon mal probiert, ob diese Verteiler-Funktion 
überhaupt aufgerufen wird?)

Aber abgesehen davon: Ich hab kein FreeRTOS da und auch keine Hardware 
auf der ich das probieren könnte. D.h. ich muss mich da jetzt sowieso 
verabschieden.

von Manuel S. (Firma: S+S) (msimmerl)


Lesenswert?

Erstmal vielen Dank für eure Hilfe.

Ich hätte schon versucht ob die Verteilerfunktion aufgerufen wird. 
Leider wird der Wrapper nie aufgerufen.

Das mit NULL als Parameterübergabe beim Task erstellen müsste eigentlich 
funktionieren. Zumindest wird das in der Doku, bei den Beispielen, auch 
so gemacht.

Irgendwas muss noch am dem Wrapper falsch sein denke ich...

von Rolf M. (rmagnus)


Lesenswert?

Manuel Simmerl schrieb:
> Das mit NULL als Parameterübergabe beim Task erstellen müsste eigentlich
> funktionieren.

Nein. Du dereferenzierst einen Nullzeiger. Wie Karl Heinz schon 
geschrieben hat, wird das, was du da an xTaskCreate übergibst, als 
Parameter an taskwrapper übergeben. Das heißt, param ist in taskwrapper 
NULL und das dereferenzierst du dann hier:
1
 (static_cast<ioCtrl*>(parm))->task();

> Zumindest wird das in der Doku, bei den Beispielen, auch so gemacht.

Wird da der Zeiger denn nacher auch benutzt, so wie bei dir?
Oder warum sollte das
1
extern "C" void taskwrapper(void* parm) {
2
                                  ^^^^

auf dein Objekt zeigen? Magie?

von Manuel S. (Firma: S+S) (msimmerl)


Lesenswert?

Nein der Parameter wird später nicht benutzt.
Deshalb wird beim Task erstellen auch NULL übergeben.

von Manuel S. (Firma: S+S) (msimmerl)


Lesenswert?

Jetzt noch ein anderer Ansatz.
Den wrapper brauch ich ja nur wenn ich auf eine Methode der Klasse 
verweisen möchte.

Jetzt mal für einen Versuch kann ich ja auch auf eine andere Methode 
verweisen.

void test(void *parm)
{
  vErrorMessage( "Task is starting!", 0, RADIX_NO_VALUE, 0 );
  portTickType xLastWakeTime;
    xLastWakeTime = xTaskGetTickCount();

    for(;;) {
    vErrorMessage( "Task is running!", 0, RADIX_NO_VALUE, 0 );
              //Delay für 1000ms
              vTaskDelayUntil(&xLastWakeTime, ( 1000 / portTICK_RATE_MS 
) );
        }
}


Nur komischerweise funktioniert nicht mal das....

von Karl H. (kbuchegg)


Lesenswert?

Manuel Simmerl schrieb:
> Jetzt noch ein anderer Ansatz.
> Den wrapper brauch ich ja nur wenn ich auf eine Methode der Klasse
> verweisen möchte.

Genau.
Weil du irgendwie die Kurve von der C Welt in die Welt der Objekte 
kratzen musst. Und das geht halt nur dann, wenn man irgendeinen Verweis 
auf ein Objekt hat.

> Jetzt mal für einen Versuch kann ich ja auch auf eine andere Methode
> verweisen.

Weise Entscheidung.
Genau so macht man das: Wenn nichts geht - abspecken, vereinfachen - bis 
man zum Kern des Problems vorstösst.

> Nur komischerweise funktioniert nicht mal das....

Womit wir wieder bei den Demos wären, die ja laut deiner Aussage 
funktionieren.
Also: Was ist bei den Demos anders?
Das können durchaus auch irgendwelche Compiler-Einstellungen sein!

von Manuel S. (Firma: S+S) (msimmerl)


Lesenswert?

Was mir noch aufgefallen ist, dass ich lauter Warnungen bekomme:

Phase Linker starting
c:\renesas\hew\tools\kpit\gnurx-elf\v12.03\rx-elf\rx-elf\lib\libc.a(lib_ 
a-closer.o):  In function `_close_r':
closer.c:(.text._close_r+0x10): warning: _close is not implemented and 
will always fail
c:\renesas\hew\tools\kpit\gnurx-elf\v12.03\rx-elf\rx-elf\lib\libc.a(lib_ 
a-fstatr.o):  In function `_fstat_r':
fstatr.c:(.text._fstat_r+0x12): warning: _fstat is not implemented and 
will always fail
c:\renesas\hew\tools\kpit\gnurx-elf\v12.03\rx-elf\rx-elf\lib\libc.a(lib_ 
a-signalr.o):  In function `_getpid_r':
signalr.c:(.text._getpid_r+0x1): warning: _getpid is not implemented and 
will always fail
c:\renesas\hew\tools\kpit\gnurx-elf\v12.03\rx-elf\rx-elf\lib\libc.a(lib_ 
a-isattyr.o):  In function `_isatty_r':
isattyr.c:(.text._isatty_r+0x10): warning: _isatty is not implemented 
and will always fail
c:\renesas\hew\tools\kpit\gnurx-elf\v12.03\rx-elf\rx-elf\lib\libc.a(lib_ 
a-signalr.o):  In function `_kill_r':
signalr.c:(.text._kill_r+0x12): warning: _kill is not implemented and 
will always fail
c:\renesas\hew\tools\kpit\gnurx-elf\v12.03\rx-elf\rx-elf\lib\libc.a(lib_ 
a-lseekr.o):  In function `_lseek_r':
lseekr.c:(.text._lseek_r+0x14): warning: _lseek is not implemented and 
will always fail
c:\renesas\hew\tools\kpit\gnurx-elf\v12.03\rx-elf\rx-elf\lib\libc.a(lib_ 
a-readr.o):  In function `_read_r':
readr.c:(.text._read_r+0x14): warning: _read is not implemented and will 
always fail
c:\renesas\hew\tools\kpit\gnurx-elf\v12.03\rx-elf\rx-elf\lib\libstdc++.a 
(pure.o):  In function `__cxa_pure_virtual':
pure.cc:(.text.__cxa_pure_virtual+0xc): warning: _write is not 
implemented and will always fail


kann damit vielleicht jemand etwas anfangen?

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

Wieder mal ein klassischer Fall von: am Symptom 'rumgedoktort ;-)
Karl Heinz ist sicherlich davon ausgegangen, dass Du solche fatalen 
Fehlermeldungen ganz sicher nicht (mehr) bekommst!

Eine Lösung habe ich da jetzt auch nicht zu, aber evtl. hilft die 
Compiler, oder genauer: die libc-Doku dabei, diese Fehler zu beheben. 
Dir fehlen die gesamten "reentrant functions", wie das bei der newlib in 
der Regel auch der Fall ist. Aber evtl. hilft da auch irgend ein 
Schalter, der die Verwendung abschaltet. Der newlib-Port für WinARM ist 
lange her...

Viel Erfolg!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.