Forum: Mikrocontroller und Digitale Elektronik ATmega328P Funktionsadresse in Register speichern und aufrufen


von Matthias (ahamatta)


Lesenswert?

Hallo, ich bins...

Ich brauche für die Solaranlage eine Steuerung mit CAN und RS485.

Kann mir bitte einer sagen, was da nicht stimmt? Ich habe schon die 
ganze Nacht gesucht. Leider sind da in dem Quelltext von dem TCB_t und 
ListItem_t so viele #ifdef dass ich nicht weiß, wie ich aus einem 
StackType_t * ein TCB_t bekomme.
1
typedef uint16_t StackType_t;
2
typedef void(*TaskFunction_t)(void*);
3
//#define portFLAGS_INT_ENABLED    ( ( StackType_t ) 0x00 )
4
#define portFLAGS_INT_ENABLED    ( ( StackType_t ) 0x80 )
5
#define PRIVILEGED_DATA
6
7
typedef void TCB_t;
8
extern volatile TCB_t * volatile pxCurrentTCB;
9
PRIVILEGED_DATA volatile TCB_t * volatile pxCurrentTCB = NULL;
10
11
/*
12
 * See header file for description.
13
 */
14
StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
15
                                     TaskFunction_t pxCode,
16
                                     void * pvParameters )
17
{
18
uint16_t usAddress;
19
20
    /* Simulate how the stack would look after a call to vPortYield() generated by
21
     * the compiler. */
22
23
    /* The start of the task code will be popped off the stack last, so place
24
     * it on first. */
25
    usAddress = ( uint16_t ) pxCode;
26
    *pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff );
27
    pxTopOfStack--;
28
29
    usAddress >>= 8;
30
    *pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff );
31
    pxTopOfStack--;
32
33
#if defined(__AVR_3_BYTE_PC__)
34
35
    /* The AVR ATmega2560/ATmega2561 have 256KBytes of program memory and a 17-bit
36
     * program counter. When a code address is stored on the stack, it takes 3 bytes
37
     * instead of 2 for the other ATmega* chips.
38
     *
39
     * Store 0 as the top byte since we force all task routines to the bottom 128K
40
     * of flash. We do this by using the .lowtext label in the linker script.
41
     *
42
     * In order to do this properly, we would need to get a full 3-byte pointer to
43
     * pxCode. That requires a change to GCC. Not likely to happen any time soon.
44
     */
45
    *pxTopOfStack = 0;
46
    pxTopOfStack--;
47
#endif
48
49
    /* Next simulate the stack as if after a call to portSAVE_CONTEXT().
50
     * portSAVE_CONTEXT places the flags on the stack immediately after r0
51
     * to ensure the interrupts get disabled as soon as possible, and so ensuring
52
     *  the stack use is minimal should a context switch interrupt occur. */
53
    *pxTopOfStack = ( StackType_t ) 0x00; /* R0 */
54
    pxTopOfStack--;
55
    *pxTopOfStack = portFLAGS_INT_ENABLED;
56
    pxTopOfStack--;
57
58
#if defined(__AVR_3_BYTE_PC__)
59
60
    /* If we have an ATmega256x, we are also saving the EIND register.
61
     * We should default to 0.
62
     */
63
    *pxTopOfStack = ( StackType_t ) 0x00;    /* EIND */
64
    pxTopOfStack--;
65
#endif
66
67
#if defined(__AVR_HAVE_RAMPZ__)
68
69
    /* We are saving the RAMPZ register.
70
     * We should default to 0.
71
     */
72
    *pxTopOfStack = ( StackType_t ) 0x00;    /* RAMPZ */
73
    pxTopOfStack--;
74
#endif
75
76
    /* Now the remaining registers. The compiler expects R1 to be 0. */
77
    *pxTopOfStack = ( StackType_t ) 0x00;    /* R1 */
78
79
    /* Leave R2 - R23 untouched */
80
    pxTopOfStack -= 23;
81
82
    /* Place the parameter on the stack in the expected location. */
83
    usAddress = ( uint16_t ) pvParameters;
84
    *pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff );
85
    pxTopOfStack--;
86
87
    usAddress >>= 8;
88
    *pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff );
89
90
    /* Leave register R26 - R31 untouched */
91
    pxTopOfStack -= 7;
92
93
    return pxTopOfStack;
94
}
95
96
97
#define portRESTORE_CONTEXT()                                                           \
98
        __asm__ __volatile__ (  "lds    r26, pxCurrentTCB                       \n\t"   \
99
                                "lds    r27, pxCurrentTCB + 1                   \n\t"   \
100
                                "ld     r28, x+                                 \n\t"   \
101
                                "out    __SP_L__, r28                           \n\t"   \
102
                                "ld     r29, x+                                 \n\t"   \
103
                                "out    __SP_H__, r29                           \n\t"   \
104
                                "pop    r31                                     \n\t"   \
105
                                "pop    r30                                     \n\t"   \
106
                                "pop    r29                                     \n\t"   \
107
                                "pop    r28                                     \n\t"   \
108
                                "pop    r27                                     \n\t"   \
109
                                "pop    r26                                     \n\t"   \
110
                                "pop    r25                                     \n\t"   \
111
                                "pop    r24                                     \n\t"   \
112
                                "pop    r23                                     \n\t"   \
113
                                "pop    r22                                     \n\t"   \
114
                                "pop    r21                                     \n\t"   \
115
                                "pop    r20                                     \n\t"   \
116
                                "pop    r19                                     \n\t"   \
117
                                "pop    r18                                     \n\t"   \
118
                                "pop    r17                                     \n\t"   \
119
                                "pop    r16                                     \n\t"   \
120
                                "pop    r15                                     \n\t"   \
121
                                "pop    r14                                     \n\t"   \
122
                                "pop    r13                                     \n\t"   \
123
                                "pop    r12                                     \n\t"   \
124
                                "pop    r11                                     \n\t"   \
125
                                "pop    r10                                     \n\t"   \
126
                                "pop    r9                                      \n\t"   \
127
                                "pop    r8                                      \n\t"   \
128
                                "pop    r7                                      \n\t"   \
129
                                "pop    r6                                      \n\t"   \
130
                                "pop    r5                                      \n\t"   \
131
                                "pop    r4                                      \n\t"   \
132
                                "pop    r3                                      \n\t"   \
133
                                "pop    r2                                      \n\t"   \
134
                                "pop    __zero_reg__                            \n\t"   \
135
                                "pop    __tmp_reg__                             \n\t"   \
136
                                "out    __SREG__, __tmp_reg__                   \n\t"   \
137
                                "pop    __tmp_reg__                             \n\t"   \
138
                             );
139
140
void callback(void *args){
141
  digitalWrite(LED_BUILTIN, HIGH);
142
  while(1);
143
}
144
145
void setup() {
146
147
  //extern int __heap_start,*__brkval;
148
  Serial.begin(115200); // open the serial port at 9600 bps:
149
  while(!Serial){}
150
151
  pinMode(LED_BUILTIN, OUTPUT);
152
153
pxCurrentTCB = pxPortInitialiseStack(0x4F5,callback,0);
154
155
156
  portRESTORE_CONTEXT();
157
  asm volatile ( "ret" );
158
159
}

von Falk B. (falk)


Lesenswert?

Matthias schrieb:
> Hallo, ich bins...
>
> Ich brauche für die Solaranlage eine Steuerung mit CAN und RS485.
>
> Kann mir bitte einer sagen, was da nicht stimmt?

Du hast die Netiquette nicht beachtet, längere Quelltexte gehören in 
den Anhang.

> Ich habe schon die
> ganze Nacht gesucht. Leider sind da in dem Quelltext von dem TCB_t und
> ListItem_t so viele #ifdef dass ich nicht weiß, wie ich aus einem
> StackType_t * ein TCB_t bekomme.

Ich auch nicht. Aber für bissel CAN und Solaranlage scheint das hier 
eine verdammt aufgeblähte Lösung zu sein.

von Matthias (ahamatta)


Lesenswert?

Ja, mei, wie es halt immer ausartet...

Ich glaube, nach
1
portSAVE_CONTEXT();
2
portRESTORE_CONTEXT();

ist das Programm richtig weitergelaufen.
1
#define portSAVE_CONTEXT()                                                              \
2
        __asm__ __volatile__ (  "push   __tmp_reg__                             \n\t"   \
3
                                "in     __tmp_reg__, __SREG__                   \n\t"   \
4
                                "cli                                            \n\t"   \
5
                                "push   __tmp_reg__                             \n\t"   \
6
                                "push   __zero_reg__                            \n\t"   \
7
                                "clr    __zero_reg__                            \n\t"   \
8
                                "push   r2                                      \n\t"   \
9
                                "push   r3                                      \n\t"   \
10
                                "push   r4                                      \n\t"   \
11
                                "push   r5                                      \n\t"   \
12
                                "push   r6                                      \n\t"   \
13
                                "push   r7                                      \n\t"   \
14
                                "push   r8                                      \n\t"   \
15
                                "push   r9                                      \n\t"   \
16
                                "push   r10                                     \n\t"   \
17
                                "push   r11                                     \n\t"   \
18
                                "push   r12                                     \n\t"   \
19
                                "push   r13                                     \n\t"   \
20
                                "push   r14                                     \n\t"   \
21
                                "push   r15                                     \n\t"   \
22
                                "push   r16                                     \n\t"   \
23
                                "push   r17                                     \n\t"   \
24
                                "push   r18                                     \n\t"   \
25
                                "push   r19                                     \n\t"   \
26
                                "push   r20                                     \n\t"   \
27
                                "push   r21                                     \n\t"   \
28
                                "push   r22                                     \n\t"   \
29
                                "push   r23                                     \n\t"   \
30
                                "push   r24                                     \n\t"   \
31
                                "push   r25                                     \n\t"   \
32
                                "push   r26                                     \n\t"   \
33
                                "push   r27                                     \n\t"   \
34
                                "push   r28                                     \n\t"   \
35
                                "push   r29                                     \n\t"   \
36
                                "push   r30                                     \n\t"   \
37
                                "push   r31                                     \n\t"   \
38
                                "lds    r26, pxCurrentTCB                       \n\t"   \
39
                                "lds    r27, pxCurrentTCB + 1                   \n\t"   \
40
                                "in     __tmp_reg__, __SP_L__                   \n\t"   \
41
                                "st     x+, __tmp_reg__                         \n\t"   \
42
                                "in     __tmp_reg__, __SP_H__                   \n\t"   \
43
                                "st     x+, __tmp_reg__                         \n\t"   \
44
                             );

Speichert denn die portSAVE_CONTEXT() mehr als nur die 32 Register?

Der Stack muss wegen dem uint16_t[] wahrscheinlich auf einer geraden 
Adresse liegen? Also eher so?
1
pxPortInitialiseStack(0x4F0,callback,0);

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Matthias schrieb:
> Ich brauche für die Solaranlage eine Steuerung mit CAN und RS485.

Soll das ein präemptives Multitasking System werden?
Das ist sicherlich etwas überzogen für Solar, RS485 und CAN

Das geht bestimmt auch Kooperativ!

Und wenn doch, warum nicht FreeRTOS, da weiß man dass es funktioniert.

von Matthias (ahamatta)


Lesenswert?

Der Wechselrichter läuft seit einem Jahr ohne Fehler. Problem ist der 
Batteriespeicher, da kommen ständig Fehlermeldungen wegen der Temperatur 
und Spannung.
Ich hab da an dem BMS schon einen Monat rumgestellt und es dann 
aufgegeben. Da braucht es je nach Temperatur und Jahreszeit 
unterschiedliche MinSOC, MaxSOC und Ladestrom, was das BMS und WR nicht 
kann.

Also Stromverbrauch-/Einspeisemesswerte lesen (RS485), BMS lesen (CAN), 
Batterie-WR schreiben (Batterieladezustand CAN) (Ladeleistung RS485).

Ohne Multitasking wird es arg kompliziert, wenn da irgendwas hängen 
bleibt.

Die Schnipsel sind vom FreeRTOS 
(https://github.com/feilipu/Arduino_FreeRTOS_Library/blob/master/src/port.c), 
aber wenn ich das aufspiele ist der Speicher voll.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Matthias schrieb:
> Die Schnipsel sind vom FreeRTOS
> (https://github.com/feilipu/Arduino_FreeRTOS_Library/blob/master/src/port.c),
> aber wenn ich das aufspiele ist der Speicher voll.

Und jetzt baust du dein eigenes FreeRTOS um Speicher zu sparen?
Ich kann dir dabei nicht helfen, werde es aber wohlwollend verfolgen.

von Michi S. (mista_s)


Lesenswert?

Matthias schrieb:
> Also Stromverbrauch-/Einspeisemesswerte lesen (RS485),
> BMS lesen (CAN),
> Batterie-WR schreiben (Batterieladezustand CAN)
> (Ladeleistung RS485).
>
> Ohne Multitasking wird es arg kompliziert,

Also zwei Messwert(sätz)e lesen und anschließend beide ans 
BMS-Schreiben? Was ist da so arg kompliziert ohne Multitasking?
Wie oft muß das überhaupt passieren, 1/s oder 1/µs?

> wenn da irgendwas hängen bleibt.

Meinst Du beim Lesen? Timeout abwarten? k.A. was die sinnvollste Aktion 
ist, wenn Dir ein Eingabewert fehlt, aber dagegen hilft Dir auch 
Multitasking nichts, im Gegenteil läufst Du eher Gefahr, nichts 
mitzubekommen wenn einer der Lese-Tasks dauerhaft hängt und keine 
Updates liefert.

von Rolf (rolf22)


Lesenswert?

Matthias schrieb:
> Ohne Multitasking wird es arg kompliziert, wenn da irgendwas hängen
> bleibt.

Mit MT bleibt es vielleicht noch öfter hängen, wenn man da kein Profi 
ist.

Ich weiß allerdings nicht genau, wo das Problem liegt.
Was soll wo hängen und warum?

Läuft doch alles mit einem Mess-/Aktionstakt > 10 Sekunden, oder?
Wenn eine CAN- oder RS-485-Funktion hängt, kann man das mit einem 
Watchdog-Timer abfangen. Danach kann man dann eine Ersatzfunktion 
aufrufen (z. B. das Interface zurücksetzen) und die Aktion beim nächsten 
Durchlauf erneut versuchen. Bei einer Dauerstörung der Hardware hilft 
dir MT auch nicht.

von Oliver S. (oliverso)


Lesenswert?

Arduino F. schrieb:
> Und jetzt baust du dein eigenes FreeRTOS um Speicher zu sparen?

Augenscheinlich kopiert er irgendwelche Softwarefragmente aus dem Netz 
zusammen, mit der Hoffnung auf ein funktionierendes Ergebnis.

Oliver

von Veit D. (devil-elec)


Lesenswert?

Hallo,

also wenn ich TCB_t und ATmega328P lese, dann sagt mir meine innere 
Stimme das was nicht zusammenpasst oder zusammengewürfelt wurde. TCB_t 
ist ein struct Datentyp der neueren Controller Serien. Ein ATmega328P 
hat keine Timer des Typs TCB (oder TCA, TCD) oder dergleichen.

: Bearbeitet durch User
von Rolf (rolf22)


Lesenswert?

Michi S. schrieb:
> Meinst Du beim Lesen? Timeout abwarten? k.A. was die sinnvollste Aktion
> ist, wenn Dir ein Eingabewert fehlt

Soi, wie ich die Beschreibung lese, nimmt man dann einfach den 
vorherigen Einlesewert. Es sind doch alles sich nur langsam verändernde 
Größen.

von Oliver S. (oliverso)


Lesenswert?

Veit D. schrieb:
> TCB_t
> ist ein struct Datentyp der neueren Controller Serien. Ein ATmega328P
> hat keine Timer des Typs TCB (oder TCA, TCD) oder dergleichen.

Der hat vor allem kein CAN…

@TO
Der hat auch keinen 3-Byte-PC. Vielleicht hilft das ja weiter. Wobei die 
Antwort auf die Frage vermutlich „gar nicht“ lautet, und ansonsten RTFM 
des unbekannten RTOS.

Oliver

: Bearbeitet durch User
von Matthias (ahamatta)


Lesenswert?

Okay, ich versuche mich durch die Instruction Set der CPU zu wühlen 
(https://ww1.microchip.com/downloads/en/devicedoc/atmel-0856-avr-instruction-set-manual.pdf).

Wäre ja eine Schande, wenn es nicht klappt, die paar Register aus dem 
SRAM zu laden und speichern...

Ist _SREG_ ein Teil von R0-R31? Muss ich die I/O Register beim 
Taskwechsel auch speichern?

https://i.stack.imgur.com/NWBNO.png

von Maxim B. (max182)


Lesenswert?

Matthias schrieb:
> Kann mir bitte einer sagen, was da nicht stimmt?

Ich kann sagen. Es stimmt nichts.

Hast du Datasheet für von dir gewählte Mega gelesen?

Matthias schrieb:
> Ist SREG ein Teil von R0-R31? Muss ich die I/O Register beim
> Taskwechsel auch speichern?

wahrscheinlich doch nicht gelesen. Sonst käme diese Frage nicht.

: Bearbeitet durch User
von Steve van de Grens (roehrmond)


Lesenswert?

Matthias schrieb:
> Ist SREG ein Teil von R0-R31?

Nein

> Muss ich die I/O Register beim Taskwechsel auch speichern?

Das ist unmöglich.

von Maxim B. (max182)


Lesenswert?

Matthias schrieb:
> Wäre ja eine Schande, wenn es nicht klappt

Um einen Elefanten im Ganzen zu essen, muss man ihn Stück für Stück 
essen.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Veit D. schrieb:
> also wenn ich TCB_t und ATmega328P lese, dann sagt mir meine innere
> Stimme das was nicht zusammenpasst oder zusammengewürfelt wurde.

TCB soll wohl TaskControlBlock heißen.
Hat also nix mit Timern zu tun.
oder nur um 12 Ecken.

Matthias schrieb:
> Wäre ja eine Schande, wenn es nicht klappt, die paar Register aus dem
> SRAM zu laden und speichern...

Was willst du erreichen?
Was willst du "wirklich" erreichen?

Und ja, dass du gerade am Ende einer Sackgasse angekommen bist, und vor 
einer Wand stehst, hat hier (fast) jeder begriffen.

Die Frage ist daher, wo isser falsch abgebogen um da zu landen.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Matthias schrieb:

> Ohne Multitasking wird es arg kompliziert, wenn da irgendwas hängen
> bleibt.

Kann man deutlich einfacher kooperativ gestalten. Das Rad "neu" in eckig 
zu erfinden, weil man mal zum Bäcker fahren will, ist Unsinn.

>
> Die Schnipsel sind vom FreeRTOS
> (https://github.com/feilipu/Arduino_FreeRTOS_Library/blob/master/src/port.c),
> aber wenn ich das aufspiele ist der Speicher voll.

Es gibt mehr als genug "Arduinos" mit tonnenweise Speicher, ESP32, 
RPpico etc. Und für das bissel Klim Bim allemal.

von Falk B. (falk)


Lesenswert?

Matthias schrieb:
> Okay, ich versuche mich durch die Instruction Set der CPU zu wühlen
> 
(https://ww1.microchip.com/downloads/en/devicedoc/atmel-0856-avr-instruction-set-manual.pdf).

UM ein bisselö auf dem CAN Bus Daten zu verschicken, schnon klar . . .

> Wäre ja eine Schande, wenn es nicht klappt, die paar Register aus dem
> SRAM zu laden und speichern...
>
> Ist SREG ein Teil von R0-R31?

Nö, das SREG liegt im IO-Bereich. Klingt komisch, ist aber so.

> Muss ich die I/O Register beim
> Taskwechsel auch speichern?

Nö.

von Maxim B. (max182)


Lesenswert?

Wenn man noch nicht weiß, was SREG ist, dann ist es für RTOS noch zu 
früh.

von Falk B. (falk)


Lesenswert?

Maxim B. schrieb:
> Wenn man noch nicht weiß, was SREG ist, dann ist es für RTOS noch zu
> früh.

In der Tat. Vor allem klingt es hier nach Tunnelblick und Voodoo, so als 
ob ein präemtives Multitasking alle Probleme löst.

von Veit D. (devil-elec)


Lesenswert?

Arduino F. schrieb:
> Veit D. schrieb:
>> also wenn ich TCB_t und ATmega328P lese, dann sagt mir meine innere
>> Stimme das was nicht zusammenpasst oder zusammengewürfelt wurde.
>
> TCB soll wohl TaskControlBlock heißen.
> Hat also nix mit Timern zu tun.
> oder nur um 12 Ecken.

Aha.  ;-)

von Veit D. (devil-elec)


Lesenswert?

Veit D. schrieb:
> Arduino F. schrieb:
>> Veit D. schrieb:
>>> also wenn ich TCB_t und ATmega328P lese, dann sagt mir meine innere
>>> Stimme das was nicht zusammenpasst oder zusammengewürfelt wurde.
>>
>> TCB soll wohl TaskControlBlock heißen.
>> Hat also nix mit Timern zu tun.
>> oder nur um 12 Ecken.
>
> Aha.  ;-)

Das könnte zwar wieder eine Abseitsdiskussion werden. Nur wenn ich so 
rund um die Lib lese wurde diese auch für die neueren Controller 
angepasst. Wenn TCB_t für was anderes steht, aber für die neuen 
Controller in deren Headerfile für die Timer schon existiert, dieser 
Name TCB_t, dann muss das doch früher oder später knallen. Vielleicht 
knallt das jetzt ausgerechnet beim TO?

Wenn ich der TO wäre, ich würde erstmal die Beispiele der Lib versuchen 
zu kompilieren. Das soll ja alles auch auf einem ATmega328P 
funktionieren, also muss das eigentlich laufen. Danach kann man immer 
noch daran rumfummeln, wenn man weiß was man tut.

von Matthias (ahamatta)


Lesenswert?

Steve van de Grens schrieb:
> Matthias schrieb:
>> Ist SREG ein Teil von R0-R31?
>
> Nein
>
>> Muss ich die I/O Register beim Taskwechsel auch speichern?
>
> Das ist unmöglich.

Danke für die Hilfe! Also relevant sind SREG und R0-R31.

Hier (https://gcc.gnu.org/wiki/avr-gcc) wird beschrieben, was 
_tmp_reg_ = R0 und _zero_reg_ = R1 ist.

_SP_L__ und __SP_H_ sind wahrscheinlich je ein Byte vom SP. Wobei ich 
mir jetzt nicht sicher bin ob es _SP_L_, _SP_H__ oder __SP_H_, 
_SP_L_ ist.
1
union{
2
  uint8_t  SP[2]{__SP_L__, __SP_H__};
3
  uint16_t SP;
4
  void     *SP;
5
}

Das Funktionsargument wird scheinbar in R24, R25 übergeben.

von Matthias (ahamatta)


Lesenswert?

Das ist der TCB_t...
1
struct xLIST_ITEM
2
{
3
?  listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE        /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
4
?  configLIST_VOLATILE TickType_t xItemValue;      /*< The value being listed.  In most cases this is used to sort the list in descending order. */
5
2  struct xLIST_ITEM * configLIST_VOLATILE pxNext;    /*< Pointer to the next ListItem_t in the list. */
6
2  struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;  /*< Pointer to the previous ListItem_t in the list. */
7
2  void * pvOwner;                    /*< Pointer to the object (normally a TCB) that contains the list item.  There is therefore a two way link between the object containing the list item and the list item itself. */
8
2  void * configLIST_VOLATILE pvContainer;        /*< Pointer to the list in which this list item is placed (if any). */
9
?  listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE        /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
10
};
11
typedef struct xLIST_ITEM ListItem_t;
12
13
typedef struct tskTaskControlBlock
14
{
15
2  volatile StackType_t  *pxTopOfStack;  /*< Points to the location of the last item placed on the tasks stack.  THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */
16
17
  #if ( portUSING_MPU_WRAPPERS == 1 )
18
?    xMPU_SETTINGS  xMPUSettings;    /*< The MPU settings are defined as part of the port layer.  THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */
19
?    BaseType_t    xUsingStaticallyAllocatedStack; /* Set to pdTRUE if the stack is a statically allocated array, and pdFALSE if the stack is dynamically allocated. */
20
  #endif
21
22
8  ListItem_t      xGenericListItem;  /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
23
8  ListItem_t      xEventListItem;    /*< Used to reference a task from an event list. */
24
?  UBaseType_t      uxPriority;      /*< The priority of the task.  0 is the lowest priority. */
25
2  StackType_t      *pxStack;      /*< Points to the start of the stack. */
26
  char        pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created.  Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
27
} TCB_t;
28
#endif

: Bearbeitet durch User
von Harald K. (kirnbichler)


Lesenswert?

Statt unlesbare Fragmente zu posten, könntest Du vielleicht einfach nur 
verlinken, wo Du das Zeug herhast.

von Rolf (rolf22)


Lesenswert?

Matthias schrieb:
> Muss ich die I/O Register beim Taskwechsel auch speichern?

Schon das Lesen kann den Zustand des zugehörigen Peripheriegeräts 
ungewollt verändern. Und das Zurückschreiben gespeicherter Inhalte ist 
noch schlimmer.
Und das auch noch in unterschiedlichen Tasks? ουαί κι αλίμονό μου!

Das steht in keinem Datenbuch ausdrücklich drin, weil es für jeden Profi 
absolut selbstverständlich ist.

von Falk B. (falk)


Lesenswert?

Rolf schrieb:
> Das steht in keinem Datenbuch ausdrücklich drin,

Aber sicher, man muss nur des sinnerfassenden Lesens mächtig sein. Bei 
ALLEN IO-Registern steht, ob und wie ein Schreib- oder Lesezugriff eine 
Reaktion bewirkt.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Harald K. schrieb:
> Statt unlesbare Fragmente zu posten, könntest Du vielleicht einfach nur
> verlinken, wo Du das Zeug herhast.

Hatta doch.

Matthias schrieb:
> Die Schnipsel sind vom FreeRTOS
> (https://github.com/feilipu/Arduino_FreeRTOS_Library/blob/master/src/port.c),
> aber wenn ich das aufspiele ist der Speicher voll.

von Matthias (ahamatta)


Lesenswert?

Scheinbar muss man doch Daten aus den I/O Register sichern und laden...

"The AVR Stack Pointer is implemented as two 8-bit registers in the I/O 
space."

https://developerhelp.microchip.com/xwiki/bin/view/products/mcu-mpu/8-bit-avr/structure/stack/

Das (https://www.mikrocontroller.net/articles/AVR-Tutorial:_Stack) ist 
auch super als Lektüre!

Wird eine lange Nacht :)

: Bearbeitet durch User
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Matthias schrieb:
> Wird eine lange Nacht :)

Da kann ich dir gerne einen Tipp geben:
> Wer in die falsche Richtung läuft,
> braucht sich nicht zu beeilen.

von Matthias (ahamatta)


Lesenswert?

Ich hab mir jetzt Microchip Studio runtergeladen und schon paar Fehler 
gefunden.

Im Simulator geht das leichter...

Glaube der Stack ist uint8_t und dann stimmt glaube ich noch die 
pxCurrentTCB Variable nicht.

Ist gleich fertig :)

PS Geht's schon wieder los mit der Fingermotorik...

: Bearbeitet durch User
von Matthias (ahamatta)


Lesenswert?

Glaube ich habe es mehr oder weniger. Muss noch bissi testen und 
schauen, wie man das mit dem Speicher macht, wenn man keine MMU hat.

Was noch wichtig ist, während man an SP rumfummelt, muss man die 
Interrupt abschalten.
1
ZRTOS__INTERRUPTS_DISABLE();
2
portSAVE_CONTEXT(tmp);
3
portRESTORE_CONTEXT(tmp);
4
//asm volatile ( "ret" );
5
ZRTOS__INTERRUPTS_ENABLE();

Beitrag #7663315 wurde vom Autor gelöscht.
von Oliver S. (oliverso)


Lesenswert?

Matthias schrieb:
> Glaube ich habe es mehr oder weniger.

Ja, wenn man nur wüsste, was eigentlich. Denn aktuell ist das klassische 
xy-Problem. Du bastelst an Lösungen, die mit deinem Problem gar nichts 
zu tun haben.

Oliver

von Steve van de Grens (roehrmond)


Lesenswert?

Matthias,

ich habe den Eindruck, dass du deine Fähigkeiten extrem überschätzt. Du 
willst ein RTOS Betriebssystem neu erfinden, ohne den Prozessor zu 
kennen. Was du vor hast ist machbar, aber das wird nach meiner 
Einschätzung einige Monate dauern.

100% sicher ist, dass du damit den Fokus auf die Problemursache 
verlierst. Du verzettelst dich mit einem komplexen Balkon, der dein 
Problem nicht löst, sondern höchstwahrscheinlich noch schwieriger 
begreifbar macht. Man soll ja junge Leute nicht demotivieren, doch es 
tut mir in der Seele weh, zu sehen, wie du mit Anlauf vor die Wand 
läufst.

Auf dem kleinen Mikrocontroller wird ein aktive Multitasking so viel RAM 
und CPU Leistung verschlucken, dass du damit nicht glücklich wirst - 
falls du es überhaupt schaffst.

Einen kooperativen Lösungsansatz ohne Register-Zauber habe ich dort 
beschrieben:
http://stefanfrings.de/multithreading_arduino/index.html

Aber: Finde erst mal die Fehlerursache in deinem Programm! Nur wenn man 
seine eigenen Fehler erkannt und verstanden hat, kann man es danach 
besser machen.

: Bearbeitet durch User
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Steve van de Grens schrieb:
> Einen besseren Lösungsansatz
Ihm ist nicht an kooperation interessiert.

Steve van de Grens schrieb:
> wie du mit Anlauf vor die Wand läufst
Ich sehe auch keinerlei Bestreben, nach rechts oder links zu schauen, ob 
der Maurer irgendwo ein Loch gelassen hat.

Wie auch immer...
Ich bin gespannt wie sein Multitasking (optimiertes FreeRTOS) ausschaut, 
wenn es denn fertig ist.

von Wastl (hartundweichware)


Lesenswert?

Steve van de Grens schrieb:
> ich habe den Eindruck, dass du deine Fähigkeiten extrem überschätzt.

Wenn er es bis hierher nicht verstanden hat dann darf man ihm
Beratungsresistenz attestieren.

Leider ist der Thread gestern, am Freitag, entstanden. Was auch
kein gutes Zeichen ist. Allein CAN und Multitasking in Einem
auf dem ATmega328P lässt mich schon ganz schwindelig werden.

: Bearbeitet durch User
von Steve van de Grens (roehrmond)


Lesenswert?

Was der Matthias vielleicht noch nicht auf sich zu kommen sieht:

Wenn mehrere Threads auf gemeinsame Resourcen zugreifen (z.B. ein 
Display oder der CAN Bus), dann muss man irgendwie dafür sorgen, dass 
das in einer geordneten Reihenfolge passiert (Semaphoren). Das läuft oft 
auf gepufferte Ein/Ausgabe hinaus, für die er aber nicht genug RAM haben 
wird, da das ja schon von Registern und Stack der Threads "aufgefressen" 
wurde.

von Rolf (rolf22)


Lesenswert?

Falk B. schrieb:
> Rolf schrieb:
>> Das steht in keinem Datenbuch ausdrücklich drin,
>
> Aber sicher, man muss nur des sinnerfassenden Lesens mächtig sein. Bei
> ALLEN IO-Registern steht, ob und wie ein Schreib- oder Lesezugriff eine
> Reaktion bewirkt.

Dann lies mal richtig. Was habe ich denn gesagt und was nicht?
Und worauf bezog sich das?

Die **allgemeine** Aussage, dass man bei I/O-Registern nicht einfach 
blind lesen und schreiben darf, da es – im Gegensatz zu "normalen" 
Speicherregistern –  gar keine Speicher, sondern nur Adressen zum 
Übermitteln von Befehlen und Stati an/von Peripheriegeräten sind, die 
steht eben nicht **ausdrücklich** drin.

von Peter D. (peda)


Lesenswert?

Matthias schrieb:
> Ich brauche für die Solaranlage eine Steuerung mit CAN und RS485.

Sowas ähnliches habe ich auch im Einsatz. Auf CAN und UART fahre ich das 
gleiche Stringprotokoll. Der CAN-Interrupt teilt die Nachrichten in 
8-Byte Pakete auf bzw. liest sie ein.
RS485 und CAN lesen einfach in getrennte Puffer. Und sobald das 
Endezeichen erkannt wird, geht beides in den gemeinsamen Parser, der es 
dann ausführt und die Antwort in den CAN- bzw. UART-Puffer bastelt.
Nirgends kann was hängen bleiben und Multitasking ist erst recht völlig 
unnötig.
Sämtliche Parameter (ADC, I2C usw.) werden im Hintergrund permanent 
eingelesen. Der Parser muß also nirgends warten, sondern schickt gleich 
die Antworten.
Als Schmankerl gibt es noch eine Autosend-Funktion. Der Master schickt 
dazu den Parameternamen und das gewünschte Intervall. Dann muß er nicht 
jedes mal erneut anfragen, sondern bekommt zyklisch alles geschickt.

Was Deine Registerrettungsorgie mit der Fragestellung zu tun hat, ist 
mir jedoch ein völliges Rätsel.
Das ist nur unnütze Verschwendung von RAM, Code und CPU-Zeit.

Matthias schrieb:
> Ohne Multitasking wird es arg kompliziert, wenn da irgendwas hängen
> bleibt.

Multitasking hilft aber nicht gegen Programmfehler. Im Gegenteil, es 
macht die Funktionen nur unnötig kompliziert und damit Fehler 
wahrscheinlicher.
Wenn man die Abläufe sauber strukturiert, kann auch nichts 
"hängenbleiben".

von Maxim B. (max182)


Lesenswert?

Matthias schrieb:
> Ich hab mir jetzt Microchip Studio runtergeladen und schon paar Fehler
> gefunden.

Das stimmt. Besonders in Simulatoren kann man in Microchip Studio viele 
Fehler finden.

Ich sehe dein Problem aber woanders: du willst Inline Assembler 
benutzen, ohne AVR einigermaßen kennenzulernen.

An deiner Stelle würde ich zuerst ein paar Projekte mit C und mit 
Assembler machen, dann etwas mit Inline Assembler Schritt zu Schritt, 
und erst danach mit RTOS experimentieren. Nur so wirst du verstehen, was 
du machst.

von Matthias (ahamatta)


Lesenswert?

Frage, was passiert mit den Registern und Stack im Interrupt?

Kann ich da im Interrupt einfach einen Task starten oder Taskwechsel 
machen?

Wahrscheinlich muss ich ganz am Anfang vom Interrupt die Register und 
Stack des alten Task speichern?

Gibt es da ein Muster irgendwo? Ist dafür das naked Funktionsattribut, 
oder muss das in ASM sein?

von Matthias (ahamatta)


Lesenswert?

Scheint so. Ich habe es zwar noch nicht ganz verstanden, aber hier steht 
es.

https://www.freertos.org/implementation/a00022.html

Ist denn die TIMER2_COMPA_vect bzw. alle Funktionen, definiert mit ISR() 
ohne Prolog und Epilog?
1
ISR(TIMER2_COMPA_vect){
2
}

: Bearbeitet durch User
von Maxim B. (max182)


Lesenswert?

Matthias schrieb:
> Frage, was passiert mit den Registern und Stack im Interrupt?

Schreibe ein Programm, laß es kompilieren und öffne Disassembler. Oder 
*.lss - File.

von Matthias (ahamatta)


Lesenswert?

Maxim B. schrieb:
> Matthias schrieb:
>> Frage, was passiert mit den Registern und Stack im Interrupt?
>
> Schreibe ein Programm, laß es kompilieren und öffne Disassembler. Oder
> *.lss - File.

Ja, danke, ich kämpfe mich schon durch!

ISR(TIMER2_COMPA_vect) ist per default nicht naked...

Verdammte kleine Mistdinger, ist doch alles komplizierter als gedacht.

von Ob S. (Firma: 1984now) (observer)


Lesenswert?

Matthias schrieb:

> Frage, was passiert mit den Registern und Stack im Interrupt?

Beim AVR8? So gut wie nix. Der PC wird auf den Stack gesichert und das 
I-Flag in SREG gelöscht. Für alles andere ist man selbst (oder der 
Compiler) verantwortlich.

> Kann ich da im Interrupt einfach einen Task starten oder Taskwechsel
> machen?

Üblicherweise nicht. Üblicherweise ist so ein Multitasking-OS 
sinnvollerweise so konstruiert, dass die Devicetreiber (und der 
Task-Scheduler) das einzige sind, was überhaupt Interrupthandler 
implementiert.

Und die Devicetreiber ihrerseits füttern oder entleeren üblicherweise 
nur Queues im RAM. Maximal können sie noch dafür sorgen, dass der Task, 
der auf ein entsprechendes Ereignis wartet, in der Prioritätsliste nach 
oben wandert.

Fazit: ein Riesenhaufen Verwaltungs-Overhead, den niemand benötigt, der 
wirklich programmieren kann...

Klar, man kann auch mit einem RTOS was zum Laufen bringen, aber das 
Ergebnis wird massiv suboptimal sein. Nunja: solange die 
Rechenzeit-Resourcen dafür reichen, dass es halt den Anforderungen der 
Anwendung genügt, ist das egal. Aber wehe, es kommt was dazu...

Dann ist das Bein genauso dicke, als hätte man den Kram "klassisch" 
implementiert, also ohne RTOS. Der Unterschied ist halt nur: das wird 
bei einem RTOS-Ansatz bei gegebener Hardware viel früher passieren. 
Dafür sorgt eben der Overhead des RTOS...

von Matthias (ahamatta)


Lesenswert?

Ob S. schrieb:
> Matthias schrieb:
>
>> Frage, was passiert mit den Registern und Stack im Interrupt?
>
> Beim AVR8? So gut wie nix. Der PC wird auf den Stack gesichert und das
> I-Flag in SREG gelöscht. Für alles andere ist man selbst (oder der
> Compiler) verantwortlich.

Bei mir hat der Compiler zumindest einen Teil der Register auf dem Stack 
gesichert und vor reti wieder geladen.
ISR() vollzieht also sowas wie einen Taskwechsel, wenn es nicht mit 
__attribute__((naked)) ist.


> Fazit: ein Riesenhaufen Verwaltungs-Overhead, den niemand benötigt, der
> wirklich programmieren kann...
>
> Klar, man kann auch mit einem RTOS was zum Laufen bringen, aber das
> Ergebnis wird massiv suboptimal sein. Nunja: solange die
> Rechenzeit-Resourcen dafür reichen, dass es halt den Anforderungen der
> Anwendung genügt, ist das egal. Aber wehe, es kommt was dazu...
>
> Dann ist das Bein genauso dicke, als hätte man den Kram "klassisch"
> implementiert, also ohne RTOS. Der Unterschied ist halt nur: das wird
> bei einem RTOS-Ansatz bei gegebener Hardware viel früher passieren.
> Dafür sorgt eben der Overhead des RTOS...

Ja, mal schauen. Wenn es mir am Ende nicht gefällt, kann ich es immer 
noch mit einem while(1){switch} neu machen.

von Matthias (ahamatta)


Lesenswert?

Btw. was hat der SRAM-Bus von dem Teil eigentlich für eine Leistung? 
Läuft der auch mit 16 MHz?

von Maxim B. (max182)


Lesenswert?

Matthias schrieb:
> ISR(TIMER2_COMPA_vect) ist per default nicht naked...

Und gut so. Naked brauchst du selten. Z.B. dort wo SREG in ISR nicht 
geändert wird. Oder muß du per Hand SREG und alle benutzten Register in 
Stack legen. Aber Compiler selbst macht das noch besser. Nur vergiß 
nicht, Optimieren auf -Os zu stellen. Dummerweise macht Microchip Studio 
für neue Projekte -Og.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Matthias schrieb:
> Verdammte kleine Mistdinger, ist doch alles komplizierter als gedacht.

Aber nur, wenn man es sich absichtlich kompliziert machen will.
Die Mehrheit läßt einfach den Compiler sich um alles kümmern und pfuscht 
ihm nicht mit Assembler ins Handwerk.
Was stört Dich denn an der Mainloop mit Interrupts Methode?

Hast Du überhaupt schonmal irgend was programmiert oder ist das Dein 
Einsteigerprojekt?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Matthias schrieb:
> Ist dafür das naked Funktionsattribut,
> oder muss das in ASM sein?

Ist eh kaum ein Unterschied, weil GCC in naked Funktionen offiziell nur 
Inline Asm unterstützt.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Ein RTOS zu verwenden macht übrigens auf anderen Controllern deutlich 
mehr Sinn, wie z.B. Cortex-M. Die sind im Gegensatz zu den AVR extra 
dafür konzipiert und können den Kontextwechsel fast automatisch und sehr 
effizient. Außerdem haben die Support für Atomics, Speicherschutz (MPU) 
und Privilegierung/Separierung von OS und Anwendung, 
Interrupt-Prioritäten usw. Rein zufällig gibt es dafür auch schon 
fertige RTOS wie eben FreeRTOS.

von Stored B. (Firma: drx) (umbrecht)


Lesenswert?

Maxim B. schrieb:
> Nur vergiß
> nicht, Optimieren auf -Os zu stellen. Dummerweise macht Microchip Studio
> für neue Projekte -Og.

Für seinen Fall wäre -Og besser:

-Os: Diese Option optimiert den Code für die Größe des resultierenden 
ausführbaren Programms. Der Compiler versucht, den Code so zu 
optimieren, dass er weniger Speicherplatz benötigt, auch wenn dies 
möglicherweise auf Kosten der Ausführungsgeschwindigkeit geht. Das ist 
besonders nützlich für eingebettete Systeme oder Programme, bei denen 
die Größe des Binärdatei eine Rolle spielt.

-Og: Diese Option steht für "Optimize for Debugging". Im Gegensatz zu 
anderen Optimierungsstufen versucht "-Og" nicht, den Code stark zu 
optimieren. Stattdessen optimiert es den Code auf eine Weise, die das 
Debuggen erleichtert. Das bedeutet, dass der generierte Code lesbarer 
bleibt und das Debuggen einfacher ist, da Variablenwerte leichter 
nachvollziehbar sind. Diese Option ist besonders nützlich während der 
Entwicklungsphase, wenn die Hauptpriorität das Debuggen und die 
Fehlersuche sind.

von Matthias (ahamatta)


Lesenswert?

Ja, erst sauber programmieren und dann -Os.

Schon klar, dass das danach außer mir auch noch einer lesen will.

Tut mir leid, es zieht sich etwas...

Ich packe das dann auf GitHub wenn ich fertig bin.

Vllt. will ja einer in den Sommerferien eine ATmega2560 Portierung 
machen?

von Maxim B. (max182)


Lesenswert?

Stored B. schrieb:
> Der Compiler versucht, den Code so zu
> optimieren, dass er weniger Speicherplatz benötigt, auch wenn dies
> möglicherweise auf Kosten der Ausführungsgeschwindigkeit geht.

Meine Erfahrung: mit -Os gewinnt man beides, auch 
Ausführungsgeschwindigkeit. Noch interessanter: manche Sachen, die mit 
-Os gut funktionieren, werden mit -Og Fehler bringen. Ein Beispiel:
1
ISR(TIMER1_COMPA_vect,ISR_NAKED){ /* Timer/Counter1 Compare Match A */
2
  PORTB |= 1<<2;
3
  reti(); 
4
}
Mit -Os bekommen wir:
1
SBI 0x05,2
2
RETI
Das wird funktionieren.

Mit -Og bekommen wir:
1
IN R24,0x05
2
ORI R24,0x04 
3
OUT 0x05,R24
4
RETI
Scheinbar wird das auch funktionieren, nur langsamer. In Wirklichkeit 
aber werden hier SREG und R24 in ISR geändert, das führt zu groben 
Programmfehler.

: Bearbeitet durch User
von Matthias (ahamatta)


Lesenswert?

Was mit errno oder C++?

Gibt es da irgendwelche Variablen die beim Taskwechsel getauscht werden 
müssen?

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Matthias schrieb:
> Was mit errno oder C++?

Mit C++ ist alles ok!
Zumindest war es das, als ich es zum letzten Mal gesehen habe.
Welche Probleme hättest du gerne?

von Matthias (ahamatta)


Lesenswert?

Naja, tendenziell machen alle globalen Variablen ohne Mutex Probleme.

Und da man zum Beispiel kein "new Serial", oder "Serial val()" sondern 
"Serial.begin()" schreibt, wird es sicher irgendwo Kauderwelsch geben...

Nutzen die in den Bibliotheken pthread?

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Matthias schrieb:
> Nutzen die in den Bibliotheken pthread?

KA, es gibt gefühlte 20 Tausend Arduino Libs.
Sicherlich nutzen einige davon die ProtoThreads, davon musst du 
ausgehen.
Und seit die Coroutinen in C++ Einzug gehalten haben, wird das Konzept 
wohl in Zukunft häufiger zu finden sein.

Matthias schrieb:
> irgendwo Kauderwelsch
Alles klar!
Keine Fragen mehr.
Alles klar!

von Steve van de Grens (roehrmond)


Lesenswert?


: Bearbeitet durch User
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Steve van de Grens schrieb:
> ...

Ok!
POSIX Threads findet man unter Linux(und anderen Unix artigen).
Damit ist Arduino und sein Framework wohl aus dem Rennen.


Also muss ich meine Antwort wohl konkretisieren.
POSIX Threads: Eher Nein!
Proto Threads: Durchaus!

von Stored B. (Firma: drx) (umbrecht)


Lesenswert?

Arduino F. schrieb:
> POSIX Threads findet man unter Linux(und anderen Unix artigen).

Nutze ich seit Jahren auch auf Windows.
Cross-Platform-fähig.

Scheinbar sind in der avr-libc auch Fragmente von POSIX zu finden

von Matthias (ahamatta)


Angehängte Dateien:

Lesenswert?

Nur so als Vorschlag, vllt. braucht das ja sonst noch einer??

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Matthias schrieb:
> braucht das ja sonst noch einer??

Busy-Wait, naja, ich glaub das kommt man noch so gerade selber drauf. 
Die lock Funktion sollte den Thread schlafen legen und sofort zu anderen 
Threads wechseln. Inkl. Priority Boosting des aktuell den Mutex 
besitzenden Threads. Und rekursiv funktioniert es auch nicht.

von Steve van de Grens (roehrmond)


Lesenswert?

In 15 Jahren gibt die Version 1.0.0 von Matthias OS. Mal sehen, ob dann 
überhaupt noch jemand mit AVR bastelt.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Steve van de Grens schrieb:
> Mal sehen, ob dann überhaupt noch jemand mit AVR bastelt.

Vielleicht gibt's ja dann Multicore-AVR, dann muss das OS das können 😋

von Matthias (ahamatta)


Lesenswert?

Nur mal angenommen, eine Bibliothek würde die posix pthread einbauen.

Was hätte man denn dann verloren?

Ein Zustandsautomat definiert das einfach auf nichts und der wo es 
braucht, implementiert das je nach eigenen Vorstellungen.

Wenn man da die einzelnen speziellen Funktionen der unzähligen RTOS mit 
# ifdef einbauen will ist man ja verloren...

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Matthias schrieb:
> Was hätte man denn dann verloren?

Du müsstest halt genau dieses API implementieren damit die pthread 
Funktionen was aufrufen können. Aber warum POSIX Threads und nicht 
Standard C bzw. C++ threading?

Matthias schrieb:
> Wenn man da die einzelnen speziellen Funktionen der unzähligen RTOS mit
> # ifdef einbauen will ist man ja verloren...

Genau so macht man es aber, Stichwort OSAL (OS abstraction layer).

von Steve van de Grens (roehrmond)


Lesenswert?

Matthias schrieb:
> Was hätte man denn dann verloren?

RAM,
CPU Takte

> Ein Zustandsautomat definiert das einfach auf nichts und der wo es
> braucht, implementiert das je nach eigenen Vorstellungen.

Du meinst wohl ein Makro. Ganz so einfach ist es in der Praxis nicht. 
Multi-Threading ist nicht nur ein Balkon den man wahlweise weg lassen 
kann. Das ganze Programm muss strukturell darauf ausgelegt sein  und das 
bekommt man nicht zum Nulltarif.

: Bearbeitet durch User
von Matthias (ahamatta)


Lesenswert?

Ich hätte da eine Frage, jetzt wird es bissi wild und ich verliere so 
bissl die Kontrolle...

Kann der Compiler irgendwie den Stackpointer überwachen? Also 
automatisch Code einfügen, der irgendwas macht, wenn der SP < x ist?

von Oliver S. (oliverso)


Lesenswert?

Nun ja, gcc ist Open Source, der Quellcode ist verfügbar. Das schaffst 
du…

Oliver

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Matthias schrieb:
> Also automatisch Code einfügen, der irgendwas macht, wenn der SP < x
> ist?

Tja, die MPU vom Cortex-M kann das ohne Geschwindigkeitsverlust 
(allerdings erst wenn auch wirklich ein Zugriff erfolgt).

von Matthias (ahamatta)


Lesenswert?

Das mir zu schwer. Noch dazu bin ich schon relativ durchgenudelt und 
brauche bis mindestens Herbst eine Pause...

von Matthias (ahamatta)


Lesenswert?


von Matthias (ahamatta)


Lesenswert?


von Falk B. (falk)


Lesenswert?

Johann L. schrieb:
>> Ist dafür das naked Funktionsattribut,
>> oder muss das in ASM sein?
>
> Ist eh kaum ein Unterschied, weil GCC in naked Funktionen offiziell nur
> Inline Asm unterstützt.

Na dann kann man das aber auch gleich bleiben lassen und die ISR normal 
als separate Assemblerfunktion schreiben. 100x einfacher und lesbarer!

von Peter D. (peda)


Lesenswert?

Matthias schrieb:
> Das mir zu schwer.

Das wäre dann doch der ideale Zeitpunkt, das ganze RTOS selber bauen 
Gedöns grundsätzlich fallen zu lassen. Und vor allem, wenn man keinerlei 
Ahnung davon hat.
Nur wegen der 2 Schnittstellen muß man noch lange nicht mit Kanonen auf 
Spatzen schießen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Soweit ich weiß werden Coroutinen in avr-g++ nicht unterstützt, gleiches 
gilt für Atomics.

In der AVR LibC gibt es einige Funktionen, die nicht reentrant sind.

Und die gezeigten Inline Asm Schnipsel funktionieren vielleicht mit viel 
Gluck, stellen aber keinen validen Code dar (inkorrekter Code darf 
funktionieren, muss aber nicht).

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Johann L. schrieb:
> Soweit ich weiß werden Coroutinen in avr-g++ nicht unterstützt,
Sind nicht im Lieferumfang.

Aber hier durchaus vorhanden:
https://github.com/modm-io/avr-libstdcpp

-> bisher nicht getestet

Mein (AVR) Arduino beschwert sich zumindest nicht über ein
1
#include <coroutine>

: Bearbeitet durch User
von Ob S. (Firma: 1984now) (observer)


Lesenswert?

Peter D. schrieb:

> Das wäre dann doch der ideale Zeitpunkt, das ganze RTOS selber bauen
> Gedöns grundsätzlich fallen zu lassen. Und vor allem, wenn man keinerlei
> Ahnung davon hat.

Ganz genau. Wenn ein RTOS irgendeinen Sinn ergeben soll, dann doch 
allenfalls, wenn man es nicht erst noch selber basteln muss.

Wenn man das nämlich kann, hat man auch keinerlei Probleme damit, eine 
Anwendung ganz klassisch ohne RTOS umzusetzen.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Ob S. schrieb:
> Wenn man das nämlich kann, hat man auch keinerlei Probleme damit, eine
> Anwendung ganz klassisch ohne RTOS umzusetzen.

Oft ist man auf externe proprietäre Bibliotheken/Frameworks angewiesen, 
welche synchron implementiert sind. Wenn man dann noch andere Dinge 
parallel laufen lassen möchte, braucht man ein RTOS. Das allerdings 
kompatibel zu solchen Bibliotheken zu machen könnte interessant werden.

von Ob S. (Firma: 1984now) (observer)


Lesenswert?

Niklas G. schrieb:

> Oft ist man auf externe proprietäre Bibliotheken/Frameworks angewiesen,
> welche synchron implementiert sind.

Ist mir noch nie passiert. Hast du Beispiele?

> Wenn man dann noch andere Dinge
> parallel laufen lassen möchte, braucht man ein RTOS.

Selbst dann nicht wirklich. Kommt allerdings auch ein wenig darauf an, 
was genau da parallel laufen muss. Wenn das dann eine zweiter synchroner 
zusammengeklauter Scheiß ist, dann könnte es tatsächlich eng werden...

Also: weniger klauen, mehr selber programmieren und gut isses.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Ob S. schrieb:
> Hast du Beispiele?

Proprietär: TouchGFX, die ST USB-PD Library

OpenSource: Die STM32WL55 RF und LoRa Middleware, der ATWILC-Treiber, 
FatFs, die I²C-Libraries für die alten STM32, überhaupt alle möglichen 
Libraries für (I²C-)Sensoren und Peripherie-ICs

Es gibt bestimmt noch viele mehr für exotische Protokolle z.B. in der 
Industrie. Die APIs der ESP32 sind größtenteils synchron, aber dort 
benutzt man ja sowieso FreeRTOS.

Die OpenSource-Libraries kann man prinzipiell umbauen, aber der Aufwand 
ist oft nicht gerechtfertigt. Wenn man nur ein Framework dieser Art hat 
kann man sich herauslavieren indem man den Rest asynchron macht, aber 
sobald es mehr als eins ist braucht man ein RTOS. Ich habe das Gefühl, 
dass die ganze Embedded-Industrie das Komponentenparadigma nicht 
verstanden hat - die Annahme ist immer, man nutzt exakt 1 Framework an 
welchem man das ganze Projekt ausrichtet und sonst nichts.

Ob S. schrieb:
> Also: weniger klauen, mehr selber programmieren und gut isses.

Und wer bezahlt das? Mal eben so ein 100kLoC-Framework nachbauen kann 
sich nicht jedes Unternehmen leisten.

von Oliver S. (oliverso)


Lesenswert?

Arduino F. schrieb:
> Johann L. schrieb:
>> Soweit ich weiß werden Coroutinen in avr-g++ nicht unterstützt,
> Sind nicht im Lieferumfang.
>
> Aber hier durchaus vorhanden:
> https://github.com/modm-io/avr-libstdcpp
>
> -> bisher nicht getestet
>
> Mein (AVR) Arduino beschwert sich zumindest nicht über ein1#include
> <coroutine>

Jetzt musst du nur noch die AVR-gcc toolchain mit multithreading enabled 
bauen, und schon wird es auch funktionieren. Die dafür benötigten 
„Kleinigkeiten“ werden dich ja nicht groß überfordern…

Oliver

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ich seh jetzt nicht wie man Threads vernünftig unterstützen kann ohne 
entsprechenden OS Support. RTEMS+Newlib Support für AVR wurden vor X 
Jahren fallen gelassen. Und pthreads gibt's auch keine.

von Steve van de Grens (roehrmond)


Lesenswert?

Johann L. schrieb:
> Ich seh jetzt nicht wie man Threads vernünftig unterstützen kann ohne
> entsprechenden OS Support.

Mit endlichen Automaten. Zu old-scool?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Steve van de Grens schrieb:
> Johann L. schrieb:
>> Ich seh jetzt nicht wie man Threads vernünftig unterstützen kann ohne
>> entsprechenden OS Support.
>
> Mit endlichen Automaten. Zu old-scool?

Es geht um Unterstützung im Compiler.

von Steve van de Grens (roehrmond)


Lesenswert?

Johann L. schrieb:
> Es geht um Unterstützung im Compiler.

Ach so, ich habe den Zusammenhang nicht erkannt.

von Peter D. (peda)


Lesenswert?

Johann L. schrieb:
> Es geht um Unterstützung im Compiler.

Meine Erfahrung ist, es funktioniert am zuverlässigsten, wenn man dem 
Compiler nicht ins Handwerk pfuscht. Die Compilerbauer verstehen schon 
ihr Handwerk.

Ich hab mal in einem früheren Projekt naked Interrupts mit Assembler 
benutzt, um dem AVR eine 2. Priorität beizubringen. Rückblickend würde 
ich das aber nicht als Masterpiece ansehen.

von Matthias (ahamatta)


Lesenswert?

Peter D. schrieb:
> Johann L. schrieb:
>> Es geht um Unterstützung im Compiler.
>
> Meine Erfahrung ist, es funktioniert am zuverlässigsten, wenn man dem
> Compiler nicht ins Handwerk pfuscht. Die Compilerbauer verstehen schon
> ihr Handwerk.

Das Problem ist, man programmiert halt und rechnet den Speicherbedarf 
aus und dann wächst der Stack doch plötzlich da rein, wo er nicht hin 
soll und das Teil stürzt unkontrolliert ab.

Wenn man jetzt bissl Luft lässt, so dass man nicht vor jedem 
Stackzugriff prüfen muss, könnte man optional schon Rechenzeit gegen 
Sicherheit tauschen und bei einem Überlauf den laufenden Thread beenden.

Klar kann man auch den Code manuell vor dem Compilerdurchgang mit 
Stacküberlauftests durchziehen, aber...

von Peter D. (peda)


Lesenswert?

Matthias schrieb:
> Klar kann man auch den Code manuell vor dem Compilerdurchgang mit
> Stacküberlauftests durchziehen, aber...

Ich habe in meinen Programmen 2 kleine Prüffunktionen implementiert, die 
man per Kommando aufrufen kann. Einmal wird der freie Bereich zwischen 
Daten und Stackpointer mit 0x77 gefüllt und getestet, wieviel davon seit 
dem letzten Aufruf übrig ist.
Die andere Funktion zählt die maximalen Timerticks (1ms) zwischen 2 
Durchgängen der Mainloop. Beim ersten Aufruf kriegt man die Dauer aller 
Initialisierungen angezeigt.
Damit läßt sich bequem die maximale Auslastung während der Laufzeit 
ermitteln.

Weiterhin wird noch der letzte Resetgrund ausgegeben. Ist dieser seit 
dem letzen Start der Applikation 0x00, dann ab zurück zum Debuggen. Denn 
dann ist ja ein wilder Pointer in den Resetvektor gelaufen, d.h. dieses 
Programm darf nicht ausgeliefert werden.

Beitrag #7665901 wurde vom Autor gelöscht.
von Joachim B. (jar)


Lesenswert?

Peter D. schrieb:
> Ich habe in meinen Programmen 2 kleine Prüffunktionen implementiert, die
> man per Kommando aufrufen kann. Einmal wird der freie Bereich zwischen
> Daten und Stackpointer mit 0x77 gefüllt und getestet, wieviel davon seit
> dem letzten Aufruf übrig ist.
> Die andere Funktion zählt die maximalen Timerticks (1ms) zwischen 2
> Durchgängen der Mainloop. Beim ersten Aufruf kriegt man die Dauer aller
> Initialisierungen angezeigt.
> Damit läßt sich bequem die maximale Auslastung während der Laufzeit
> ermitteln.

und wie schaffst du es alle anfallenden Bedingungen zu testen?
Wie erkennst du zerpflückte nicht zusammenhängende Speicherbereiche?

Ich denke an PET2001 da gab es die garbadge collection, der Müll mußte 
ab und an rausgetragen werden.
Ich denke an AtariST TOS 1.0 wo nach 128 malloc/free Aufrufe gebombt 
wurde, also Absturz, was mit TOS 1.4 nur auf 1024 malloc/free Aufrufe 
erweitert wurde aber das Problem nur verschob.

Ich dachte auch mal man könnte auf kleinere AVR sowas machen, aber der 
Code wurde immer aufgeblähter und passte dann nicht mehr ins flash.

Meine Erfahrungen, bekannte viel genutzte Variablen nicht dynamisch 
zuzuweisen sondern schon vorher zu reservieren, verringert zwar den 
freien SRAM aber es kommen zur Laufzeit keine Überraschungen.

Speicher ist wie Hubraum, durch nichts zu ersetzen. Die kleinen Motoren 
mit Turbo aufzublasen schaffen auch mehr Probleme als sie lösen, Golf 
mit 1,4L und Turbo fällt mir da ein oder die Ford EcoBoost mit in Öl 
laufenden Zahnriemen.

: Bearbeitet durch User
von Matthias (ahamatta)


Lesenswert?

Peter D. schrieb:
> Matthias schrieb:
>> Klar kann man auch den Code manuell vor dem Compilerdurchgang mit
>> Stacküberlauftests durchziehen, aber...
>
> Ich habe in meinen Programmen 2 kleine Prüffunktionen implementiert, die
> man per Kommando aufrufen kann. Einmal wird der freie Bereich zwischen
> Daten und Stackpointer mit 0x77 gefüllt und getestet, wieviel davon seit
> dem letzten Aufruf übrig ist.
> Die andere Funktion zählt die maximalen Timerticks (1ms) zwischen 2
> Durchgängen der Mainloop. Beim ersten Aufruf kriegt man die Dauer aller
> Initialisierungen angezeigt.
> Damit läßt sich bequem die maximale Auslastung während der Laufzeit
> ermitteln.
>
> Weiterhin wird noch der letzte Resetgrund ausgegeben. Ist dieser seit
> dem letzen Start der Applikation 0x00, dann ab zurück zum Debuggen. Denn
> dann ist ja ein wilder Pointer in den Resetvektor gelaufen, d.h. dieses
> Programm darf nicht ausgeliefert werden.

Hm, eine dritte ISR die den SP überwacht, das eine sehr gute Idee!!

Baue das heute Abend ein, nachdem ich die ganzen Fehler behoben habe, 
die ich gestern Abend nach zwei Bier reingeschusselt hab...

Btw. ich musste leider wegen einem Namenskonflikt mit dem Repository 
umziehen und das Teil in AgileRTOS umbenennen 
(https://github.com/ykat-UG-haftungsbeschrankt/agilertos).

von Matthias (ahamatta)


Lesenswert?

Darf man irgendwann aufgeben? Ich glaube ich bin schon zu alt...

von Steve van de Grens (roehrmond)


Lesenswert?

Matthias schrieb:
> Darf man irgendwann aufgeben?

Dazu wurde dir schon geraten, als du deinen ersten Beitrag zum Thema 
geschrieben hattest.

von Klaus S. (kseege)


Lesenswert?

Matthias schrieb:
> Ich glaube ich bin schon zu alt...
>
Aus meine Sicht eher zu jung. Ein mittelprächtig anspruchsvolles 
Programm mit aufwendigen Mitteln lösen zu wollen, spricht eher für 
mangelnde Weitsicht. Ich kann nur Falk beipflichten:
Falk B. schrieb:
> Aber für bissel CAN und Solaranlage scheint das hier
> eine verdammt aufgeblähte Lösung zu sein.

Es wäre aus meiner Sicht angebracht, zwei Schritte zurückzutreten, das 
Projekt neu aufzusetzen und sich zunächst mal um die einfacheren 
Varianten des Multitasking zu kümmern.

Just my 2 cents
Klaus (der soundsovielte)

von Gerhard H. (hauptmann)


Lesenswert?

Klaus S. schrieb:
> Multitasking

realisiert man am sinnvollsten und minimal Overhead produzierend mit 
einem regelmäßigen Timerinterrupt, der ganz einfach alle regelmäßig zu 
erledigenden Sachen aufruft.

von J. S. (jojos)


Lesenswert?

Was dann eher ein Multitasking für Arme ist weil alles im 
Interruptkontext mit vielen Einschränkungen abläuft.

von Gerhard H. (hauptmann)


Lesenswert?

J. S. schrieb:
> weil alles im Interruptkontext mit vielen Einschränkungen abläuft.

Richtig designt nicht.
Jedes waschechte Multitasking kostet auf dem AVR mehr Ressourcen.

von J. S. (jojos)


Lesenswert?

Das kostet auf jedem μC mehr Ressourcen, nur das die beim AVR dafür sehr 
knapp sind…

von Gerhard H. (hauptmann)


Lesenswert?

J. S. schrieb:
> Das kostet auf jedem μC mehr Ressourcen,

Nicht unbedingt.
Nämlich dann nicht wenn Task/Kontext-Wechsel von der Hardware 
unterstützt werden.

von Steve van de Grens (roehrmond)


Lesenswert?

Gerhard H. schrieb:
> Nämlich dann nicht wenn Task/Kontext-Wechsel von der Hardware
> unterstützt werden.

Denkst du dabei an den Z80?

von Gerhard H. (hauptmann)


Lesenswert?

Steve van de Grens schrieb:
> Denkst du dabei an den Z80?

Nein. Eingeschränkt aber z.B. an den Z380 :)

Z80 hab ich mal interruptgesteuertes Quasi-Multitasking realisiert.

von Steve van de Grens (roehrmond)


Lesenswert?

Gerhard H. schrieb:
> Eingeschränkt aber z.B. an den Z380

Oh wie cool, der hat ja noch mehr Registersätze! Ich dachte, der Z80 sei 
der einzige Prozesser dieser Art.

von Bauform B. (bauformb)


Lesenswert?

Steve van de Grens schrieb:
> Gerhard H. schrieb:
>> Eingeschränkt aber z.B. an den Z380
>
> Oh wie cool, der hat ja noch mehr Registersätze! Ich dachte, der Z80 sei
> der einzige Prozesser dieser Art.

Heute wäre die Werbung für den TMS9900 "Bis zu 2047 Registersätze!"
Wirklich schade, dass diese Architektur aus der Mode gekommen ist. Mit 
1MByte On Chip RAM und 0 Wait States würde das gut funktionieren.

https://en.wikipedia.org/wiki/TMS9900

von J. S. (jojos)


Lesenswert?

Die Register die beim Taskwechsel gerettet werden müssen sind ja nur das 
eine. Man gönnt jedem Task ja seinen eigenen Stack. Wenn man da sparsam 
ist dann kann es in langen Debug Sessions enden, oder man ist großzügig, 
muss dann aber auch genug RAM haben.
Genug Gründe um für preemptives MT Cortex-M einzusetzen.

von Gerhard H. (hauptmann)


Lesenswert?

Matthias schrieb:
> Hm, eine dritte ISR die den SP überwacht, das eine sehr gute Idee!!

Dazwischen kann aber auch sehr viel passieren...
Das testweise Markieren des Zwischenraums Daten<>Stack a'la Peter D. ist 
sicher die bessere Idee. Diese Markierung performance- gesittet d.h. 
stückweise zu kontrollieren wäre für besagte periodische ISR m.M. eine 
sinnvollere Aufgabe.
Im allgemeinen aber sollten fehlgeleitete SRAM Zugriffe und Stackfehler- 
und damit der nötige Einsatz von Kontroll- Instrumenten die absolute 
Ausnahme darstellen. Kann gut sein daß man da mit Assembler besser am 
Puls der Hardware hört und dran ist :)

Peter D. schrieb:
> Die andere Funktion zählt die maximalen Timerticks (1ms) zwischen 2
> Durchgängen der Mainloop.

Ich hab dafür (so verfügbar) einen Hardware TC-Counter mit vollem Speed 
= maximaler Zeitauflösung laufen. Der kann dann nicht nur zu 
verschiedenen Zeitpunkten in der Main abgefragt werden sondern auch in 
Interrupts, um die Zeiten der Abarbeitung derselben zu kontrollieren.

: Bearbeitet durch User
von Matthias (ahamatta)


Lesenswert?

Falk B. schrieb:
> Matthias schrieb:
>> Hallo, ich bins...
>>
>> Ich brauche für die Solaranlage eine Steuerung mit CAN und RS485.
>>
>> Kann mir bitte einer sagen, was da nicht stimmt?
>
> Du hast die Netiquette nicht beachtet, längere Quelltexte gehören in
> den Anhang.
>
>> Ich habe schon die
>> ganze Nacht gesucht. Leider sind da in dem Quelltext von dem TCB_t und
>> ListItem_t so viele #ifdef dass ich nicht weiß, wie ich aus einem
>> StackType_t * ein TCB_t bekomme.
>
> Ich auch nicht. Aber für bissel CAN und Solaranlage scheint das hier
> eine verdammt aufgeblähte Lösung zu sein.

Hab dem Teil noch paar Eventhandler für Arme spendiert...

https://ykat-ug-haftungsbeschrankt.github.io/agilertos/index.html#autotoc_md2

Die Tasks (statisch und vheap) laufen noch nicht richtig und der mutex 
auf dem vheap fehlt. Weiß nicht, ob ich das heute und morgen noch 
schaffe.

Danach steht erst mal was anderes an...

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.