Forum: Mikrocontroller und Digitale Elektronik FreeRTOS vListInsert() hängt


von Daniel R. (jackyryan)


Lesenswert?

Hallo,

wir benutzen FreeRTOS v8.2.0 auf einem Cortex M4 (NXP LPC4078) und ich 
bekomme in letzter Zeit immer öfter einen Programmabsturz in list.c, in 
der Funktion vListInsert() bei der for-Schleife mit den darüber 
beschriebenen 4 Fehlerursachen. Suche schon seit Tagen danach im 
FreeRTOS-Forum und Google, aber habe leider noch keine Lösung. Wäre 
super, wenn mir jemand einen Tipp geben könnte, was es ist.

Im konkreten Fall läuft das Programm und FreeRTOS tadellos und bei einer 
bestimmten Aktion wird ein Task per xTaskCreate() erzeugt, der auch 
gleich startet und per xTaskNotifyWait() auf eine Antwort wartet. Das 
funktioniert an vielen anderen Stellen problemlos. In dieser Funktion 
sind in der Mitte die beiden Aufrufe taskEXIT_CRITICAL(); und 
taskENTER_CRITICAL(); bei denen das Programm nicht mehr weiterzugehen 
scheint und danach an besagter Stelle hängt. Ist im Debugger nicht ganz 
einfach nachuvollziehen, wenn man Step-over macht, kommt man nicht 
weiter (auch ein späterer Breakpoint wird nicht mehr aufgerufen). Wenn 
man aber mit Step-into durchläuft, klappt es meist doch. Da darf man 
nicht zuviel auf den Debugger geben (LPCXpresso mit LPC-Link 2).

configASSERT() ist definiert und half mir schon ein paar mal.

Jetzt zu den 4 Möglichkeiten laut FreeRTOS:

1) Stack overflow - see 
http://www.freertos.org/Stacks-and-stack-overflow-checking.html

#define configCHECK_FOR_STACK_OVERFLOW 1 ist gesetzt, aber 
vApplicationStackOverflowHook wird nie aufgerufen bzw. dort hängt er 
nicht. Auch die Überprüfung per vTaskList() vor dem xTaskNotifyWait() - 
Aufruf der laufenden Tasks sieht ganz i.O. aus:
1
File Transfer task  R   2   268 19
2
AnyBus              R   0   150 3
3
IDLE                R   0   93  12
4
Tmr Svc             B   3   186 13
5
NFC Tag             B   0   262 6
6
console             B   7   264 11
7
LED Control         B   2   195 1
8
Event task          B   2   178 15
9
ADC Control         B   2   218 7
10
ext. ADC            B   2   90  5
11
Eeprom Control      B   2   207 8
12
abccCmdHandler      B   4   583 10
13
LSB Driver          S   0   175 2
"File Transfer task" ist der aktive Task, aus dem der vListInsert() - 
crash
 auftritt

2) Incorrect interrupt priority assignment, especially on Cortex-M parts 
where numerically high priority values denote low actual interrupt 
priorities, which can seem counter intuitive.  See 
http://www.freertos.org/RTOS-Cortex-M3-M4.html and the definition of 
configMAX_SYSCALL_INTERRUPT_PRIORITY on 
http://www.freertos.org/a00110.html

Habe mir beide Webseiten angesehen, aber es ist ehrlich gesagt ziemlich 
komplex. Die dort erwähnten #defines habe ich in FreeRTOSConfig.h wie 
folgt gesetzt:
1
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY         0x3f
2
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY    5
3
#define configPRIO_BITS       __NVIC_PRIO_BITS   // steht auf 5
Für configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY habe ich schon Werte 
von 0-15 ausprobiert, macht kein Unterschied.
Da es so aussieht, dass der Crash in taskEXIT_CRITICAL() passiert würde 
ich dennoch vermuten, dass es am ehesten mit den Interrupts 
zusammenhängt?

3) Calling an API function from within a critical section or when the 
scheduler is suspended, or calling an API function that does not end in 
"FromISR" from an interrupt.

Wie erwähnt scheint es in xTaskNotifyWait() aufzutreten, in der Mitte 
bei taskEXIT_CRITICAL();. Die Funktion ist original und nicht verändert.

4) Using a queue or semaphore before it has been initialised or before 
the scheduler has been started (are interrupts firing before 
vTaskStartScheduler() has been called?).

Da das Programm davor einwandfrei läuft, alle Tasks erstellt wurden und 
auch vTaskStartScheduler() am Anfang aufgerufen wurde, sollte es damit 
nicht zusammenhängen?


Da das Projekt drängt und ich nicht wirklich weiterkomme wegen dem 
Hängenbleiben, würde ich mich sehr freuen, wenn mir jemand einen guten 
Tipp hat. Falls noch irgendwelche Infos fehlen, liefere ich diese gerne 
nach.

Danke schonmal!

Gruß,
Daniel

von fsdf (Gast)


Lesenswert?

Kannst du bitte mal die Stellen hier als Code einfügen, wo er wartet?

von Daniel R. (jackyryan)


Lesenswert?

Wenn ich den Debugger stoppe, steht er hier bei der for-Schleife in 
vListInsert():
1
else
2
  {
3
    /* *** NOTE ***********************************************************
4
    If you find your application is crashing here then likely causes are
5
    listed below.  In addition see http://www.freertos.org/FAQHelp.html for
6
    more tips, and ensure configASSERT() is defined!
7
    http://www.freertos.org/a00110.html#configASSERT
8
9
      1) Stack overflow -
10
         see http://www.freertos.org/Stacks-and-stack-overflow-checking.html
11
      2) Incorrect interrupt priority assignment, especially on Cortex-M
12
         parts where numerically high priority values denote low actual
13
         interrupt priorities, which can seem counter intuitive.  See
14
         http://www.freertos.org/RTOS-Cortex-M3-M4.html and the definition
15
         of configMAX_SYSCALL_INTERRUPT_PRIORITY on
16
         http://www.freertos.org/a00110.html
17
      3) Calling an API function from within a critical section or when
18
         the scheduler is suspended, or calling an API function that does
19
         not end in "FromISR" from an interrupt.
20
      4) Using a queue or semaphore before it has been initialised or
21
         before the scheduler has been started (are interrupts firing
22
         before vTaskStartScheduler() has been called?).
23
    **********************************************************************/
24
25
    for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 The mini list structure is used as the list end to save RAM.  This is checked and valid. */
26
    {
27
      /* There is nothing to do here, just iterating to the wanted
28
      insertion position. */
29
    }
30
  }


Davor war er in einer Funktion und kam bis xTaskNotifyWait:
1
static bool File_create(uint16_t * instance)
2
{
3
  char strTaskList[500];
4
  fileTask = xTaskGetCurrentTaskHandle();
5
6
  *instance = 0; // in case of error, return zero
7
8
  LogMessage(LOG_FILE_MESSAGE, MSG_FORMATTED, "Creating file system interface object ...");
9
10
  ABP_MsgType* psMsg = ABCC_GetCmdMsgBuffer();
11
  ABCC_SetMsgHeader(psMsg, ABP_OBJ_NUM_FSI, 0x00, 0, ABP_CMD_CREATE, 0, ABCC_GetNewSourceId());
12
  ABCC_MsgType sMsg;
13
  sMsg.psMsg = psMsg;
14
  ABCC_SetLowAddrOct(sMsg.psMsg16->sHeader.iCmdExt0CmdExt1, 0x00); /* CmdExt0: reserved */
15
  ABCC_SetHighAddrOct(sMsg.psMsg16->sHeader.iCmdExt0CmdExt1, 0x01); /* CmdExt1: reserved  */
16
17
  // hier kommt "Response instance" und "Successfully created file interface instance" Debug messages
18
  ABCC_ErrorCodeType err = ABCC_SendCmdMsg(psMsg, HandleResponseCreate /*ABCC_CbfReceiveMsg*/);
19
20
  if (err != ABCC_EC_NO_ERROR)
21
  {
22
    LogMessage( LOG_FILE_ERROR,
23
                MSG_FORMATTED,
24
                "Error creating file interface instance, code = %u",
25
                err );
26
    return false;
27
  }
28
29
  vTaskList(strTaskList);
30
  DEBUGOUT("\r\n%s\r\n", strTaskList);
31
32
  // response handler will be called from anybus task
33
  uint32_t result;
34
  xTaskNotifyWait(0x00, ULONG_MAX, &result, portMAX_DELAY); /* Block indefinitely until notified. */

Dort drin läuft er dann bis taskEXIT_CRITICAL();, danach ist es für mich 
unklar. (xTaskNotifyWait hat ziemlich viele Zeilen für den Beitrag hier)
Selbstverständlich kann ich vTaskList(strTaskList); mit dem 400 Byte 
array wieder rausnehmen ohne Änderung des Problems.

von Ruediger A. (Gast)


Lesenswert?

das ist zu fast 99%iger Sicherheit ein Problem mit falsch konfigurierten 
Interrupts. Sieh Dir mal im NVIC Block die Prioritäten der 
Interruptsources an und im SCB die der ersten 16 Systeminterrupts.

Ist alles kein Hexenwerk und in meinem Buch recht ausführich 
beschrieben. Der SysTick Interrupt muss die niedrigste Priorität haben, 
und der Service Interrupt des OS auch. Kein Interrupt, der über 
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY liegt, darf OS Services 
aufrufen.

von Daniel R. (jackyryan)


Lesenswert?

Das ist der NVIC->IP Block aus dem Speicher ausgelesen (linke 
hex-Werte):
1
00 WDT_IRQn   
2
00 TIMER0_IRQn
3
00 TIMER1_IRQn
4
00 TIMER2_IRQn
5
00 TIMER3_IRQn
6
08 UART0_IRQn 
7
00 UART1_IRQn
8
00 UART2_IRQn
9
00 UART3_IRQn
10
00 PWM1_IRQn 
11
00 I2C0_IRQn 
12
00 I2C1_IRQn     
13
00 I2C2_IRQn     
14
00 Reserved0_IRQn
15
00 SSP0_IRQn     
16
00 SSP1_IRQn       
17
00 PLL0_IRQn       
18
00 RTC_IRQn        
19
00 EINT0_IRQn      
20
00 EINT1_IRQn      
21
00 EINT2_IRQn      
22
00 EINT3_IRQn      
23
28 ADC_IRQn        
24
00 BOD_IRQn        
25
00 USB_IRQn        
26
28 CAN_IRQn        
27
28 DMA_IRQn        
28
00 I2S_IRQn        
29
00 ETHERNET_IRQn   
30
00 SDC_IRQn        
31
00 MCPWM_IRQn      
32
00 QEI_IRQn        
33
00 PLL1_IRQn       
34
00 USBActivity_IRQn
35
00 CANActivity_IRQn
36
00 UART4_IRQn      
37
00 SSP2_IRQn       
38
00 LCD_IRQn        
39
00 GPIO_IRQn       
40
00 PWM0_IRQn       
41
00 EEPROM_IRQn

Das ist die Funktion zum Setzen der Priorität:
1
__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
2
{
3
  if(IRQn < 0) {
4
    SCB->SHP[((uint32_t)(IRQn) & 0xF)-4] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* set Priority for Cortex-M  System Interrupts */
5
  else {
6
    NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff);    }        /* set Priority for device specific Interrupts  */
7
}

D.h. ADC_IRQn, CAN_IRQn und DMA_IRQn stehen auf 5 und UART0_IRQn auf 1.

Und das der SCB->SHP - Block:
1
00 MemoryManagement_IRQn
2
00 BusFault_IRQn
3
00 UsageFault_IRQn
4
00
5
00
6
00
7
00 
8
00 SVCall_IRQn
9
00 DebugMonitor_IRQn
10
00 
11
F8 PendSV_IRQn
12
F8 SysTick_IRQn

Das ist das enum mit den Interrupts aus cmsis_40xx.h:
1
typedef enum {
2
  /* -------------------------  Cortex-M4 Processor Exceptions Numbers  ----------------------------- */
3
  Reset_IRQn                    = -15,    /*!< 1 Reset Vector, invoked on Power up and warm reset */
4
  NonMaskableInt_IRQn           = -14,    /*!< 2 Non maskable Interrupt, cannot be stopped or preempted */
5
  HardFault_IRQn                = -13,    /*!< 3 Hard Fault, all classes of Fault */
6
  MemoryManagement_IRQn         = -12,    /*!< 4 Memory Management, MPU mismatch, including Access Violation and No Match */
7
  BusFault_IRQn                 = -11,    /*!< 5 Bus Fault, Pre-Fetch-, Memory Access Fault, other address/memory related Fault */
8
  UsageFault_IRQn               = -10,    /*!< 6 Usage Fault, i.e. Undef Instruction, Illegal State Transition  */
9
  SVCall_IRQn                   = -5,      /*!< 11 System Service Call via SVC instruction   */
10
  DebugMonitor_IRQn             = -4,      /*!< 12 CDebug Monitor   */
11
  PendSV_IRQn                   = -2,      /*!< 14 Pendable request for system service */
12
  SysTick_IRQn                  = -1,      /*!< 15 System Tick Interrupt */
13
14
  /* ---------------------------  LPC40xx Specific Interrupt Numbers  ------------------------------- */
15
  WDT_IRQn                      = 0,      /*!< Watchdog Timer Interrupt                         */
16
  TIMER0_IRQn                   = 1,      /*!< Timer0 Interrupt                                 */
17
  TIMER1_IRQn                   = 2,      /*!< Timer1 Interrupt                                 */
18
  TIMER2_IRQn                   = 3,      /*!< Timer2 Interrupt                                 */
19
  TIMER3_IRQn                   = 4,      /*!< Timer3 Interrupt                                 */
20
  UART0_IRQn                    = 5,      /*!< UART0 Interrupt                                  */
21
  UART_IRQn                     = UART0_IRQn,  /*!< Alias for UART0 Interrupt                        */
22
  UART1_IRQn                    = 6,      /*!< UART1 Interrupt                                  */
23
  UART2_IRQn                    = 7,      /*!< UART2 Interrupt                                  */
24
  UART3_IRQn                    = 8,      /*!< UART3 Interrupt                                  */
25
  PWM1_IRQn                     = 9,      /*!< PWM1 Interrupt                                   */
26
  I2C0_IRQn                     = 10,      /*!< I2C0 Interrupt                                   */
27
  I2C_IRQn                      = I2C0_IRQn,  /*!< Alias for I2C0 Interrupt                         */
28
  I2C1_IRQn                     = 11,      /*!< I2C1 Interrupt                                   */
29
  I2C2_IRQn                     = 12,      /*!< I2C2 Interrupt                                   */
30
  Reserved0_IRQn                = 13,      /*!< Reserved                                         */
31
  SSP0_IRQn                     = 14,      /*!< SSP0 Interrupt                                   */
32
  SSP_IRQn                      = SSP0_IRQn,  /*!< Alias for SSP0 Interrupt                         */
33
  SSP1_IRQn                     = 15,      /*!< SSP1 Interrupt                                   */
34
  PLL0_IRQn                     = 16,      /*!< PLL0 Lock (Main PLL) Interrupt                   */
35
  RTC_IRQn                      = 17,      /*!< Real Time Clock Interrupt                        */
36
  EINT0_IRQn                    = 18,      /*!< External Interrupt 0 Interrupt                   */
37
  EINT1_IRQn                    = 19,      /*!< External Interrupt 1 Interrupt                   */
38
  EINT2_IRQn                    = 20,      /*!< External Interrupt 2 Interrupt                   */
39
  EINT3_IRQn                    = 21,      /*!< External Interrupt 3 Interrupt                   */
40
  ADC_IRQn                      = 22,      /*!< A/D Converter Interrupt                          */
41
  BOD_IRQn                      = 23,      /*!< Brown-Out Detect Interrupt                       */
42
  USB_IRQn                      = 24,      /*!< USB Interrupt                                    */
43
  CAN_IRQn                      = 25,      /*!< CAN Interrupt                                    */
44
  DMA_IRQn                      = 26,      /*!< General Purpose DMA Interrupt                    */
45
  I2S_IRQn                      = 27,      /*!< I2S Interrupt                                    */
46
  ETHERNET_IRQn                 = 28,      /*!< Ethernet Interrupt                               */
47
  SDC_IRQn                      = 29,      /*!< SD/MMC card I/F Interrupt                        */
48
  MCPWM_IRQn                    = 30,      /*!< Motor Control PWM Interrupt                      */
49
  QEI_IRQn                      = 31,      /*!< Quadrature Encoder Interface Interrupt           */
50
  PLL1_IRQn                     = 32,      /*!< PLL1 Lock (USB PLL) Interrupt                    */
51
  USBActivity_IRQn              = 33,      /*!< USB Activity interrupt                           */
52
  CANActivity_IRQn              = 34,      /*!< CAN Activity interrupt                           */
53
  UART4_IRQn                    = 35,      /*!< UART4 Interrupt                                  */
54
  SSP2_IRQn                     = 36,      /*!< SSP2 Interrupt                                   */
55
  LCD_IRQn                      = 37,      /*!< LCD Interrupt                                    */
56
  GPIO_IRQn                     = 38,      /*!< GPIO Interrupt                                   */
57
  PWM0_IRQn                     = 39,      /*!< PWM0 Interrupt                                   */
58
  EEPROM_IRQn                   = 40,      /*!< EEPROM Interrupt                               */
59
} LPC40XX_IRQn_Type;

Wenn ich es richtig interpretiert habe, dann steht SysTick_IRQn auf 
niedrigster Priorität:
1
 NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Systick Interrupt */
Für SVCall_IRQn gibt es gar keinen Aufruf, d.h. steht noch auf 0?
Was könnte nun der Fehler sein? Auch wenn es kein Hexenwerk ist, 
überblicke ich das noch nicht ganz.

Bin sehr dankbar für weitere Tipps :-)

von Ruediger A. (Firma: keine) (rac)


Lesenswert?

Könnte ein bug im LPC Cortex port sein, der mit der 8.2.3. gefixt wurde 
(per PM mit Richard Barry). Es geht da um einen fehlerhaften Gebrauch 
der __NVIC_PRIO_BITS. Mach mal einen Vergleich der beiden Codebasen.

: Bearbeitet durch User
von Ruediger A. (Firma: keine) (rac)


Lesenswert?

P.S: Die 0xf8 der OS Interrupts sieht mir auf den ersten Blick nicht ok 
aus, was dafür sprechen würde, dass die prio bits nicht richtig 
berechnet werden. Ist aber nur ein Schuss ins Blaue (bin auf dem 
Sprung).

von Daniel R. (jackyryan)


Lesenswert?

Okay, dann könnte ich aber gleich auf FreeRTOS v10 aktualisieren?
Oder meinst Du vergleichen und herausfinden was der Bugfix war und nur 
das eine übernehmen (wäre wesentlich weniger Arbeit)?

Die 0xF8 kommen halt aus der Übergabeparameter-Formel "1 um 5 nach links 
shiften = 0010 0000 und 1 abziehen macht 0001 1111.
In NVIC_SetPriority() wird das dann um (8-5) nach links geschiftet, so 
dass alle Bits "oben" anfangen, also 1111 1000, daher die 0xF8. 
Berechnung also korrekt. Da alle Bits auf 1 stehen, müsste es doch die 
niedrigste Priorität sein, oder was wäre da falsch?

von gdfgsdgsg (Gast)


Lesenswert?

ich hatte anfangs das problem das __NVIC_PRIO_BITS  zwar in der cmsis 
definiert wurde .. aber die IDE ( eclipse ) das an einigen stellen auch 
in der FreeRTOSConfig.h ignoriert hat.

bei mir steht da:
1
#ifdef __NVIC_PRIO_BITS
2
 /* __NVIC_PRIO_BITS will be specified when CMSIS is being used. */
3
 #define configPRIO_BITS                     __NVIC_PRIO_BITS
4
#else
5
 #define configPRIO_BITS                     4
6
#endif

demnach nur 4 bits bei Cortex M... ist der LPC hier anders mit 5bits ?

mein M7 :
1
#define __NVIC_PRIO_BITS          4       /*!< CM7 uses 4 Bits for the Priority Levels       */

von Ruediger A. (Firma: keine) (rac)


Lesenswert?

Der Cortex schreibt ein Minimum von 8 Prio levels vor, d.h. 3 der 8 bits 
müssen minimal signifikant sein. Was in den restlichen 5 bits passiert 
ist maufacturer dependent; manche pods unterstützen bis zu 256 levels 
(brauchen also alle 8 bits), manche ignorieren die ungebrauchten bits, 
und manche definieren Subprioritäten o.ä. in den bits.

Wenn ich es richtig in Erinnerung habe, sind die priority levels im NVIC 
und dem SCB konsistent, d.h. wenn im NVIC die Prioritäten mit x8 (~1) 
und x28 (~5) codiert sind, dann wäre 0xf8 die (unzulässige) höchste 
Priorität.

Was gdfgsdgsg schreibt, klingt sehr nach dem Problem, das ich mit R. 
Barry mal am Wickel hatte.

@Daniel: Du kannst ja spasseshalber mal versuchen, direkt am Anfang 
deiner ersten Task die Priorität von SysTick und PendSV explizit auf 0x8 
festzunageln und sehen, ob das am Problem etwas ändert. Dann weisst Du 
zumindestens, ob wir den richtigen Baum hoch bellen...

Re Upgrade: Grundsätzlich ist es nicht falsch, immer mit der aktuellen 
Version einer Middleware zu arbeiten. Erfahrungsgemäss kann aber der 
Portieraufwand ziemlich nervig werden, vor Allem wenn Dritthersteller 
ihre custom ports bereit stellen, die dann mit neueren Revisionen wieder 
nicht kompatibel sind. You figure.

: Bearbeitet durch User
von Daniel R. (jackyryan)


Angehängte Dateien:

Lesenswert?

@gdfgsdgsg: Im Handbuch (s. NVIC1.png im Anhang) lese ich, dass es 32 
Interrupt Prioritäten gibt, mit 4 Bits (1111) komme ich nur auf 16 
Möglichkeiten, d.h. muss dann __NVIC_PRIO_BITS auf 5 stehen?
Hab es trotzdem mal auf 4 geändert, aber hilft leider nicht.
Außerdem steht im User-Manual UM10562, dass es 5 Bits sind (s. 
NVIC2/3.png)

@Rüdiger A.: Die 0x8 habe ich für beide gesetzt per
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY      0x01
in FreeRTOSConfig.h. Im Anhang SHP_mit_0x8.png sieht man, dass es 
gesetzt ist. Leider bekomme ich jetzt einen HardFault_Handler - Fehler 
während einer SPI-Initialisierungs-Kommunikation. Das Programm kommt gar 
nicht mehr in den Idle-Zustand (ob das jetzt "besser" oder "schlechter" 
mit vListInsert geworden ist kann ich noch nicht sagen).
Erst ab 0x05 läuft der Idle Mode wieder, aber das Problem mit 
vListInsert besteht trotzdem noch.

Warum soll eigentlich 0xF8 unzulässig sein? Das wäre doch Priorität 
0x1F, d.h. die erlaubte Prio 31?

Gibt es noch Dinge, die ich ausprobieren könnte?

von Ruediger A. (Firma: keine) (rac)


Lesenswert?

Daniel R. schrieb:
> @gdfgsdgsg: Im Handbuch (s. NVIC1.png im Anhang) lese ich, dass es 32
> Interrupt Prioritäten gibt, mit 4 Bits (1111) komme ich nur auf 16
> Möglichkeiten, d.h. muss dann __NVIC_PRIO_BITS auf 5 stehen?
> Hab es trotzdem mal auf 4 geändert, aber hilft leider nicht.
> Außerdem steht im User-Manual UM10562, dass es 5 Bits sind (s.
> NVIC2/3.png)
>
2^5 sind 32. Der Cortex ist so gestaltet, dass die signifikanten Bits 
immer in den MSB der Prioritätenbytes codiert sind. Das ist bewusst so, 
damit unabhängig von der Belegung der nicht genutzten Bits höhere Werte 
immer auch höhere Prioritäten sind. Deswegen codieren beim LPC die 
obereren 5 bits die Priorität, und deswegen werden die Prioritäten um 5 
bits nach links geshiftet. Die 4 ist eine FreeRTOS Default, die haben 
beim LPC folglich nichts zu suchen.

> @Rüdiger A.: Die 0x8 habe ich für beide gesetzt per
> #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY      0x01
> in FreeRTOSConfig.h. Im Anhang SHP_mit_0x8.png sieht man, dass es
> gesetzt ist.

Das ist vermutlich der falsche Weg. Mach es umgekehrt so, dass Du am 
Ende des kernel launches die beiden Prioritäten explizit umbiegst (Test 
code). Ich habe momentan keine Kapazitäten, um die Seiteneffekte deiner 
Strategie zu analyisieren, aber ich denke, dass der 
configLIBRARY_LOWEST_INTERRUPT_PRIORITY etwas Anderes macht als Du 
denkst (such mal danach).

> Leider bekomme ich jetzt einen HardFault_Handler - Fehler
> während einer SPI-Initialisierungs-Kommunikation. Das Programm kommt gar
> nicht mehr in den Idle-Zustand (ob das jetzt "besser" oder "schlechter"
> mit vListInsert geworden ist kann ich noch nicht sagen).
> Erst ab 0x05 läuft der Idle Mode wieder, aber das Problem mit
> vListInsert besteht trotzdem noch.
>
> Warum soll eigentlich 0xF8 unzulässig sein? Das wäre doch Priorität
> 0x1F, d.h. die erlaubte Prio 31?
>

Ja, aber SysTick und PendSV müssen die niedrigste Priorität haben. Warum 
steht in meinem Buch. 31 wäre die höchste.

Hier ist ansonsten auch eine hilfreiche Quelle: 
https://www.freertos.org/RTOS-Cortex-M3-M4.html


> Gibt es noch Dinge, die ich ausprobieren könnte?

Der sicherste Weg besteht darin, eine funktionierende Codebasis zu 
nehmen und Stück für Stück zu portieren. Ist eure Hardware selbst 
gestrickt oder basierend auf einem Eval Board? Bei zweiterem gibt es 
bestimmt Codebeispiele für FreeRTOS im Ökosystem des Boardherstellers.

Ansonsten habe ich funktionierende Beispiele (allerdings für Andere 
Cortex Derivate) hier: https://www.springer.com/de/book/9783658148492, 
runterscrollen, Zusatzmaterial. Mit Chance laufen die Kapitel 3 
Beispiele aus der Büchse heraus auf deinem Controller (die OS Beispiele 
benutzen nur den reinen Cortex Kern, keine Board Peripherie ausser 
vielleicht ein paar LEDs), dann kannst Du dir die Registerinhalte ja mal 
genauer ansehen.

: Bearbeitet durch User
von Daniel R. (jackyryan)


Lesenswert?

Im Handbuch steht doch, dass 31 die niedrigste Priorität hat 
(NVIC3.png), wie kommst Du dann darauf, dass das die höchste sein soll?

Ich hab den Code durchsucht, configLIBRARY_LOWEST_INTERRUPT_PRIORITY 
wird soweit ich sehen kann nur für die beiden Interrupts PendSV_IRQn und 
SysTick_IRQn verwendet.

In einem der ersten Tasks mit Prio 0 habe ich die beiden Zeilen 
eingebaut:
1
NVIC_SetPriority(PendSV_IRQn, 1);
2
NVIC_SetPriority(SysTick_IRQn, 1);
Dann passiert genau das gleiche wie mit 
configLIBRARY_LOWEST_INTERRUPT_PRIORITY, es tritt ein HardFault während 
der Initialisierung auf.
Was genau soll das denn bringen, weil laut FreeRTOS sollen beide doch 
die niedrigste Prio haben (schreibst Du auch, aber dagegen meinst Du 
anscheinend dass "0" die niedrigste ist)?

Dein STM32-Beispiel aus Kapitel 3 habe ich mir angesehen, aber unser 
System ist einfach viel zu komplex um das mal schnell zu testen. Ich 
möchte nicht von vorne anfangen. Die Entwicklung  geht schon etwa 2 
Jahre und FreeRTOS funktioniert an sich tadellos. Erst jetzt durch meine 
Änderungen der letzten Wochen tritt dieser Fehler auf (ich kann nicht 
sagen, was an meinen Änderungen kritisch sein sollte... und auch nicht 
ab wann genau es auftrat, vielleicht gab es das früher auch schon, wenn 
man einige Debug-#defines zugeschaltet hätte).
Ich habe ehrlich gesagt keine Lust mehrere 100 git-Commits durchzugehen 
und zu prüfen, wo es instabiler läuft. Lieber wäre mir, dem Fehler auf 
die Schliche zu kommen, zumal ja diese 4 Fehlermöglichkeiten extra 
aufgelistet werden.
Ich könnte mir mit gewissem Aufwand vorstellen auf v10 zu aktualisieren, 
aber das Projekt drängt. Ein gezieltes eingrenzen der Ursache fände ich 
am besten. Na... gibt es noch ein paar Ideen?
Vielleicht kaufen wir auch Dein Buch. Finde es echt super hier an den 
Autor rangekommen zu sein :-)

von Ruediger A. (Firma: keine) (rac)


Lesenswert?

Daniel R. schrieb:
> Im Handbuch steht doch, dass 31 die niedrigste Priorität hat
> (NVIC3.png), wie kommst Du dann darauf, dass das die höchste sein soll?
>
> Ich hab den Code durchsucht, configLIBRARY_LOWEST_INTERRUPT_PRIORITY
> wird soweit ich sehen kann nur für die beiden Interrupts PendSV_IRQn und
> SysTick_IRQn verwendet.
>

kann ich erst beantworten, wenn ich mal wieder an einem Cortex System 
arbeite und mir das im echten Leben ansehen kann...

>
> Dein STM32-Beispiel aus Kapitel 3 habe ich mir angesehen, aber unser
> System ist einfach viel zu komplex um das mal schnell zu testen. Ich
> möchte nicht von vorne anfangen. Die Entwicklung  geht schon etwa 2
> Jahre und FreeRTOS funktioniert an sich tadellos. Erst jetzt durch meine
> Änderungen der letzten Wochen tritt dieser Fehler auf (ich kann nicht
> sagen, was an meinen Änderungen kritisch sein sollte... und auch nicht
> ab wann genau es auftrat, vielleicht gab es das früher auch schon, wenn
> man einige Debug-#defines zugeschaltet hätte).

ok, kann es sein, dass Du in einem ISR mit höherer Priorität als 
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY versuchst einen 
Systemaufruf (Semaphore signalisieren o.ä.) vornimmst?

In jedem Fall wäre meine Strategie, deine Änderungen Stück für Stück 
zurückzunehmen, bis das Problem nicht mehr auftritt, dann hast Du es 
genau genug lokalisiert.


Und: Ein Stacküberlauf wird nicht 100% verlässlich über den 
Signaturmechanismus erkannt, wie folgendes Beispiel zeigt:

void AFunctionThatOverwritesTheStack(...)
{
    unsigned long a_TrashVal;
    unsigned char a_SomeArray[100];
    ....
    a_TrashVal = 0x55555555;
}

wenn bei Eintritt in diese Funktion noch 50 bytes stack übrig sind und 
auf a_SomeArray nur partiell zugegriffen wird (das Array wird ja nur 
reserviert, nicht notwendigerweise überschrieben), dann ist der 
Schreibzugriff auf a_TrashVal weit jenseits des Stacks, aber der Context 
Switcher erkennt nichts böses (weil die Stacksignatur noch intakt ist). 
Es kann also trotzdem ein Stack Overflow sein.

von Daniel R. (jackyryan)


Lesenswert?

Ich bin sämtliche Interrupts durchgegangen, alle werden mit der 
Priorität configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY oder höher 
initialisiert. Habe zur Sicherheit +2 angehängt, aber das ändert nichts.

Änderungen Stück für Stück zurücknehmen ist nicht so einfach, weil 
zuletzt eine ganze Programmbibliothek aktualisiert und mit Änderungen 
eines anderen Branches gemergt wurde. Habe mir damals aber alles Stück 
für Stück mit Beyond Compare angeschaut. Es geht ja auch alles, bis dass 
er halt irgendwann (es muss nicht unbedingt bei erwähntem xTaskNotify() 
auftreten) wieder bei vListInsert steht. Habe schon versucht die 
Parameter der for-Schleife auszuwerten, aber ist sehr kompliziert. Auch 
im Debugger aus vListInsert rauspsringen brachte mir keine Erkenntnisse 
(...).

Hab nun nochmal mit dem Heap und den Task-Stack-Größen rumgespielt. Wenn 
der Heap zu klein und in einem Task zuviel Stack angefordert wird, dann 
kommt es bei einem xTaskCreate bei prvAllocateTCBAndStack zu einem 
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY.
Angenommen es tritt ein Stack-Overflow auf und 
vApplicationStackOverflowHook zeigt es mir warum auch immer nicht an, 
dann sollte das Problem doch mit einer größeren configTOTAL_HEAP_SIZE 
beseitigt werden, solange es ausreichend vergrößert wird?
Auch wenn ich configTOTAL_HEAP_SIZE maximal vergrößere auf 44kb, wodurch 
der 64kb RAM komplett voll ist, bleibt das Problem 1:1 bestehen.

Mal sehen, ob ich morgen noch Ideen habe, was neue Erkenntnisse bringt, 
ansonsten bin ich dankbar für jeden Tipp :-)

: Bearbeitet durch User
von Ruediger A. (Firma: keine) (rac)


Lesenswert?

Daniel R. schrieb:
> Ich bin sämtliche Interrupts durchgegangen, alle werden mit der
> Priorität configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY oder höher
> initialisiert. Habe zur Sicherheit +2 angehängt, aber das ändert nichts.
>

Hallo Daniel,

also da die Info, dass das FreeRTOS seit 2 Jahren stabil lief, erst 
später kam, würde ich Alles was Interrupts, Prioritäten etc. angeht 
erstmal genau so lassen wie es war.

>
> Hab nun nochmal mit dem Heap und den Task-Stack-Größen rumgespielt. Wenn
> der Heap zu klein und in einem Task zuviel Stack angefordert wird, dann
> kommt es bei einem xTaskCreate bei prvAllocateTCBAndStack zu einem
> errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY.

Ja, genau so denkt man es sich ja auch... ;-)

> Angenommen es tritt ein Stack-Overflow auf und
> vApplicationStackOverflowHook zeigt es mir warum auch immer nicht an,
> dann sollte das Problem doch mit einer größeren configTOTAL_HEAP_SIZE
> beseitigt werden, solange es ausreichend vergrößert wird?

Äh, nein, Du musst ja explizit bei jedem xTaskCreate() die Stackgrösse 
angeben, also solange Du einer Task nicht explizit mehr Stack gönnst, 
bringt ja allein das vergrössern des Heaps nicht, oder sehe ich da etwas 
falsch?...

> Auch wenn ich configTOTAL_HEAP_SIZE maximal vergrößere auf 44kb, wodurch
> der 64kb RAM komplett voll ist, bleibt das Problem 1:1 bestehen.
>

Welchen Memory Allocator benutzt Du? Bist Du vielleicht in die fehlende 
thread safety Falle getappt 
(https://www.freertos.org/a00111.html#heap_3)?

> Mal sehen, ob ich morgen noch Ideen habe, was neue Erkenntnisse bringt,
> ansonsten bin ich dankbar für jeden Tipp :-)

von Daniel R. (jackyryan)


Lesenswert?

Okay, kann sein dass bei xTaskCreate() die usStackDepth absolut und 
nicht minimal angegeben wird. Habe diese schon für sämtliche Tasks 
vergrößert und mit vTaskList() kontrolliert, normalerweise sollte es 
groß genug sein.

Beim Speichermanagment nutzen wir heap_4.c. Die anderen heap-c-Dateien 
werden im Build-Prozess exkludiert.
Ist das dann auch Thread-Safe?

von Daniel R. (jackyryan)


Lesenswert?

Ich bin alle Interrupts durchgegangen und habe tatsächlich 2 aktive 
gefunden, die mit Prio 0 liefen, also höhere Prio als 
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY. Leider wurde es mit "5" 
nicht besser, vermutlich auch weil beide Interrupts (I2C und GPIO) keine 
FreeRTOS-Api-Funktionen aufrufen.
Desweiteren hab ich nochmal bei sämtlichen xTaskCreate-Aufrufen 
usStackDepth vergrößert, bringt aber auch nichts (configTOTAL_HEAP_SIZE 
steht wie schonmal erwähnt auf 40kb). Sollten die folgenden 
HighWatermarks aus vTaskList nicht groß genug sein, d.h. weit genug von 
0 weg?
1
File Transfer task   R  2  396  17
2
AnyBus               R  0  284  3
3
IDLE                 R  0  221  12
4
NFC Tag              B  0  260  6
5
abccCmdHandler       B  4  583  10
6
console              B  7  264  11
7
LED Control          B  2  195  1
8
Event task           B  2  182  15
9
ADC Control          B  2  216  7
10
ext. ADC             B  2  350  5
11
Eeprom Control       B  2  207  8
12
Tmr Svc              B  3  186  13
13
LSB Driver           S  0  303  2

von Ruediger A. (Firma: keine) (rac)


Lesenswert?

Hallo Daniel,

das lezte, was ich ohne genauer in den Code zu sehen als mögliche 
Fehlerquelle noch ins Feld werfen würde wäre eine Mutexvariable, die 
eigentlich rekursiv sein müsste aber es nicht ist. Das ist ein typischer 
Fehler in heap3.c, wo malloc_lock() und malloc_unlock() mit einer nicht 
rekursiven mutex implementiert werden (in low Memory conditions rufen 
die C Runtime libs malloc_lock() rekursiv auf). In heap4.c sollte das 
erstmal kein Thema sein, aber vielleicht hast Du eine andere Stelle, wo 
ein Mutex nicht rekursiv definiert ist aber sein müsste. Da Du den hang 
immer an derselbesn Stelle hast, sieht das wie ein mögliches 
Fehlerszenario aus.

Wenn Ihr gar nicht weiter kommt, kannst Du mir eine PM schreiben.

: Bearbeitet durch User
von Daniel R. (jackyryan)


Lesenswert?

So, wir haben das Problem gelöst!
Es lag daran, dass ein anderer Stack in unserer Bibliothek an vielen 
Stellen global alle Interrupts aus- und wieder eingeschaltet hat, da 
dort "kritische" - Bereich definiert wurden, die in der Abarbeitung 
nicht durch Interrupts unterbrochen werden dürfen.
In solch einer critical section wurde ein xQueueSend für den UART-Task 
verwendet, der unter Umständen voll war und es dann gewartet wurde. 
Leider lief aber in dem Moment das ganze FreeRTOS mit dem UART-Task, der 
mit xQueueReceive die Queue wieder geleert hätte, nicht mehr weiter, 
weil der SysTick-Interrupt durch das globale Ausschalten der Interrupts 
nicht mehr lief. Das war dann somit die Endlosschleife, wo es nicht mehr 
weiterging, eine Deadlock sozusagen.
Die Lösung könnte nun sein, mit xSemaphoreTake und Give zu arbeiten um 
kritische Bereiche nicht zu unterbrechen und gleichzeitg das Sperren 
aller Interrupts zu umgehen, damit der UART-Task die Queue weiterhin 
abarbeitet.
Danke für die ganzen Tipps!

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.