Forum: Mikrocontroller und Digitale Elektronik STM32 MUTEX Semaphore


von Ma B. (drumstick)


Lesenswert?

Hallo,

Ich arbeite mit dem STM32F107VCT6 und dem uVision von Keil.

Ich habe 2 uPs die per CAN-Bus miteinander kommunizieren. Jetzt möchte 
ich zyklisch einen Request von A nach B senden und wenn B antwortet, 
zeige ich auf dem Display von "Verbindung OK" an. Sendet B nichts 
zurück, steht auf dem Display "Keine Verbindung".

Wie mache ich das: Ich setze eine Variable auf false und sende den 
Request. Sendet B eine Antwort, wird die Variable auf true gesetzt. 
Jetzt habe ich eine Flackern auf dem Display zwischen "Verbindung OK" 
und "Keine Verbindung". Jetzt wollte ich dies mit einem MUTEX lösen und 
habe mir das Beispiel auf der KEIL Webside angeschaut und gleich 
aufgebaut. Jetzt empfängt A gar nichts mehr, weil wahrscheinlich der CAN 
Controller verstopft wird!?
1
//                                                                      
2
//================  request_CAN_Connection =======                      
3
//                                                                      
4
void request_CAN_Connection(void)
5
{
6
  if(os_mut_wait (&mutex1, 0xFFFE) != OS_R_TMO)
7
  {
8
    rqstConnection();
9
  }
10
  os_mut_release (&mutex1);
11
}
12
13
14
//                                                                      
15
//================  reset_CAN_Connection =======                        
16
//                                                                      
17
void reset_CAN_Connection(void)
18
{
19
  if(os_mut_wait (&mutex1, 0xFFFE) != OS_R_TMO)
20
  {
21
    set_Connect_Stat(false);
22
    request_CAN_Connection();
23
  }
24
  os_mut_release (&mutex1);
25
}
26
27
28
/******************************************************************************/
29
/*   CAN handler task  'task_CAN'Prio: 50  main CAN dispatcher                */
30
/******************************************************************************/
31
32
__task void task_CAN(void)  
33
{
34
  tsk_CAN_dispatch(TSK_ACTION_INIT);
35
  os_dly_wait (100);      // delay clock ticks (x 1ms)
36
37
  while(true)
38
  {
39
    tsk_CAN_dispatch(TSK_ACTION_RUN);
40
    {
41
42
       static U32 os_time_lastpoll    = 0;
43
       U32 os_time_current            = os_time_get();
44
45
       if((os_time_current - os_time_lastpoll) > 1000)
46
       {
47
        rqstOpTm();
48
        os_time_lastpoll = os_time_current;
49
       }
50
    }
51
  }
52
}
53
54
55
/******************************************************************************/
56
/*   Debuggger  task  'task_mutex1'Prio:                                      */
57
/******************************************************************************/
58
59
__task void task_mutex1(void)  
60
{
61
  os_itv_set(10);
62
  while(true)
63
  {
64
    os_itv_wait();
65
    request_CAN_Connection();
66
  }
67
}
68
69
70
/******************************************************************************/
71
/*   Debuggger  task  'task_mutex2'Prio:                                      */
72
/******************************************************************************/
73
74
__task void task_mutex2(void)  
75
{
76
  os_itv_set(10);
77
  os_mut_init (&mutex1);
78
  while(true)
79
  {
80
    os_itv_wait();
81
    reset_CAN_Connection();
82
  }
83
}

Link zu den Erklärungen
http://www.keil.com/support/man/docs/rlarm/rlarm_os_mut_wait.htm


Weiss jemand Rat oder sieht jemand einen Fehler?
Vielen Dank und Gruss!
M.B.

von Ma B. (drumstick)


Lesenswert?

Nachtrag:

Anderst Formuliert: Ich möchte eine sporadische Verbindungskontrolle 
durchführen.

Ich habe meinen Code gegenüber dem Beispiel abgeändert und auf den 
Rückgabewert des os_mut_wait geprüft.

Ich habe beobachtet kurz nach dem Einschalten funktionierts, aber 
plötzlich empfängt A nichts mehr.

A ist meine Testeinheit und B ist das eigentliche 
Produkt(EC-Motorensteuerung).

Ich habe für die MUTEX Funktionen extra unabhängige Task aufgesetzt, 
damit der CAN-Task verschont bleibt. Aber trotzdem verstopft irgendwie 
der CAN-Bus!?


Danke und Gruss!

M.B.

von Debugger (Gast)


Lesenswert?

Deadlock ...

von Ma B. (drumstick)


Lesenswert?

hier noch die Prio der Tasks:
1
  otid_bkgnd       = os_tsk_self();
2
  otid_GUI         = os_tsk_create_user (tsk_GUI, 100,&StkTsk, sizeof(StkTsk));
3
  otid_CAN         = os_tsk_create (task_CAN, 60);
4
  otid_functions   = os_tsk_create (task_functions, 50);
5
  otid_mutex2      = os_tsk_create (task_mutex2, 75);
6
  otid_mutex1      = os_tsk_create (task_mutex1, 70);

von Ma B. (drumstick)


Lesenswert?

Deadlock ...

JA aber das wait wird doch wieder released, dann sind die Tasks wieder 
frei...

von (prx) A. K. (prx)


Lesenswert?

Es gibt RTOS-Kernels, in denen eine Task eine bereits besitzende Mutex 
erneut anfordern darf, ohne dass eine Blockade auftritt (interner 
Zähler). Und solche, bei denen das nicht zulässig ist, sondern direkt in 
den Deadlock führt. Zu welcher Gattung dieses gehört weiss ich nicht.

Hier: reset_CAN_connection holt sich die Mutex und ruft in diesem 
Zustand request_CAN_connection auf - das sich aber auch erst die Mutex 
holt. Sinn ergibt das wenig, weil direkt rqstConnection aufgerufen 
werden könnte.

von Ma B. (drumstick)


Lesenswert?

Vielen Dank...

Dann ist aber das Example von Keil eher unbrauchbar...

von (prx) A. K. (prx)


Lesenswert?

Wie ich schon schrieb: Ich kenne Keil nicht, das war eine eher 
allgemeine Aussage zu RTOS-Kernels. Das Beispiel - habs jetzt erst 
gelesen - legt allerdings nahe, dass es bei Keil zulässig ist.

von Ma B. (drumstick)


Lesenswert?

Danke!

Ich denke, das Example ist eben sehr allgemein. Ich muss noch paar 
Überlegungen investieren.

Der reset darf nur erfolgen wenn der request den Mutex freigegeben hat.

von (prx) A. K. (prx)


Lesenswert?

Anderes Thema: Es ist nicht sonderlich sauber, in einer Task eine 
Semaphore zu initialisieren, die in einer konkurrierenden Task ebenfalls 
verwendet wird. Das mag hier zwar aufgrund der Reihenfolge und der Prios 
kein Problem sein, es bleibt aber unsauber und fehlerträchtig.

Task-übergreifende Resourcen sollten initialisiert werden, bevor diese 
Tasks in Verlegenheit kommen könnten, sich drum zu streiten. Also hier 
sinnvollerweise bevor die Tasks überhaupt existieren.

Ja, das steht so ebenfalls im Keil Beispiel, aber das machts auch nicht 
besser.

von Ma B. (drumstick)


Lesenswert?

gehe mit dir einig! Danke für den Hinweis!

von ASM (Gast)


Lesenswert?

A. K. schrieb:
> Hier: reset_CAN_connection holt sich die Mutex und ruft in diesem
> Zustand request_CAN_connection auf - das sich aber auch erst die Mutex
> holt. Sinn ergibt das wenig, weil direkt rqstConnection aufgerufen
> werden könnte.

rqstConnection wird in diesem Fall nie aufgerufen da os_mut_wait in den 
Timeout läuft. Ich verstehe nicht wie bei einem fehlgeschlagenen 
os_mut_wait direkt os_mut_release aufgerufen werden kann ohne in 
Probleme zu laufen, ist alles etwas verwirrend ohne sich die 
API-Referenz angeschaut zu haben ...

von (prx) A. K. (prx)


Lesenswert?

Quellcode vom ARTX: 
http://read.pudn.com/downloads92/sourcecode/embed/359226/Kernel/AR_Mutex.c__.htm

Wenn eine Task die Mutex bereits besitzt, dann wird in os_mut_wait nicht 
blockiert, sondern inkrementiert. os_mut_release gibt passend dazu erst 
beim letzten Aufruf wieder frei. Das ist also sauber und entspricht dem 
Beispiel in der Referenz (siehe Link im 1. Beitrag).

Wenn os_mut_release auf eine nicht im Besitz befindliche Mutex 
aufgerufen wird, geschieht nichts. Besser wäre natürlich trotzdem
  if(os_mut_wait (&mutex1, 0xFFFE) != OS_R_TMO)
    {
      rqstConnection();
      os_mut_release (&mutex1);
  }

von (prx) A. K. (prx)


Lesenswert?

NB: os_mut_wait ist etwas unschön konzipiert. Im erfolgreichen Fall gibt 
es zwei verschiedene Return-Codes (mit/ohne Wait), im Fehlerfall aber 
nur einen, und der betrifft einen speziellen Fall (Timeout) und heisst 
auch entsprechend.

Folglich wird natürlich wie oben auf den speziellen Fehler getestet, 
nicht auf den Erfolg. So ist es per Design quasi unmöglich, diesem API 
irgendwann einen weiteren speziellen Error-Return hinzu zu fügen, ohne 
haufenweise existierenden Code zu schrotten.

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.