STM32 MUTEX Semaphore

OP #3112419
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.
OP #3112477
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.
OP #3112503
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);
#3112541
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.
#3112579
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.
Gast #3113241
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 ...
#3113269
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);
  }
#3113278
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren