Forum: Mikrocontroller und Digitale Elektronik LIN synchronisation


von Amir B. (sticky)


Lesenswert?

Hallo an alle.

Ich habe ein LIN-Slavemodul gebaut auf dem ein ATMega168 und ein ATA6662 
(LIN-Transceiver) sitzt. Nutze auserdem AVRStudio mit gcc

Ich will mein LIN-Slavemodul auf eine LIN-Header-Nachricht des Masters 
synchronisieren.

Dazu habe ich folgendes Datenblatt gefunden.
http://www.atmel.com/dyn/resources/prod_documents/doc7653.pdf

ich versteh nur leider nicht wie ich es anwenden muss.

Kann mir jemand bei der Synchronisation meines Slaves helfen?

Ich danke im voraus.

von Harald (Gast)


Lesenswert?

>Ich will mein LIN-Slavemodul auf eine LIN-Header-Nachricht des Masters
>synchronisieren.

Die Application Note bezieht sich - nach kurzer Sichtung - mehr auf das 
Autobauding, d.h. Abgleich der Slave-Baudrate auf den Master. 
Insbesondere erforderlich bei Eisatz von RC-Oszillatoren.

Du meinst wahrscheinlich mehr die grundsätzliche Synchronisation auf die 
LIN-Nachricht, oder?

von Harald (Gast)


Lesenswert?

Falls Du die grundsätzliche Synchronisation meinst, geht das wie folgt:

- Im Receive-Interrupt als erstes prüfen, ob ein Framing-Error vorliegt 
(Verdacht auf Break)

- Prüfen, ob das empfangene Byte = 0 ist.

- Ich prüfe zusätzlich zu diesem Zeitpunkt noch, ob der Portpin RXD an 
dieser Stelle ebenfalls noch '0' ist. Nur empfehlenswert bei 
Interrupt-basierender Verarbeitung.

- Empfangs-State-Machine an dieser Stelle auf jeden Fall zurücksetzen, 
ein Break hat immer Vorrang.

- Nächstes Byte sollte ein 0x55 sein (An dieser Stelle kann man einige 
Prozessoren auf das Autobauding mittels 0x55 Character vorbereiten, z.B. 
PIC)

- Als nächstes Byte die ID empfangen. Parität prüfen und feststellen, ob 
ID für einen selbst bestimmt ist.

- Je nach geplanter Frame Datenrichtung nun 1..8 Datenbytes senden oder 
empfangen.

- Checksumme empfangen und prüfen oder Checksumme berechnen und senden.

- Fertig.


Die Prüfung mittels Framing Error mag einigen Usern nicht genügen, sie 
hätte theoretisch noch einige Unzulänglichkeiten. In der Praxis machen 
das aber viele Implementationen so. Ich auch.

von Amir B. (sticky)


Lesenswert?

Harald wrote:


> Du meinst wahrscheinlich mehr die grundsätzliche Synchronisation auf die
> LIN-Nachricht, oder?

ja!

mein code
1
ISR (USART_RX_vect) {    //Die Interupt Service Routine wird ausgeführt wenn ein zeichen empfangen wird
2
              //(LIN KOMMUNIKATION STARTET HIER)
3
  uint16_t TMPchecksum = 0;
4
  uint8_t checksum;
5
  uint8_t ID;
6
7
    Receive_Byte();
8
//(LIN KOMMUNIKATION STARTET HIER)
9
  if (FE0==1){        //Ein Frame Error wird durch ein Sync-Break hervorgerufen
10
    Receive_Byte();      
11
    if (SyncFeld==0x55){
12
13
      PID = Receive_Byte();
14
      //ID = PID
15
      
16
17
      if (ID ==0 && Slave_Address==0){        
18
        
19
        for (uint8_t i=0; i<=6; i++){
20
          Send_Byte(Daten[i]);              //gesammelte Daten senden
21
          TMPchecksum= TMPchecksum + Daten[i];  //Checksumme berechnen (CARRY-BIT fehlt noch)!!!
22
        }
23
24
        
25
        TMPchecksum = TMPchecksum+PID;        //Enhanced Checksumme!
26
        
27
        //Low-Byte der checksumme + High-Byte der checksumme
28
        checksum  = (uint8_t) ((TMPchecksum & 0x00FF) + (TMPchecksum >> 8));
29
        
30
        checksum= ~checksum;        //Checksumme invertieren
31
        Send_Byte(checksum);        //anschließend die Checksumme senden
32
      }
33
34
      if (ID == 1 && Slave_Address==0){    
35
        Set_Relais(0,1);          //Relais1 einschalten
36
      }
37
38
      if (ID == 2 && Slave_Address==0){    
39
        Set_Relais(1,0);          //Relais2 einschalten
40
      }
41
42
      if (ID == 3 && Slave_Address==0){    
43
        Set_Relais(1,1);          //Relais1 und 2 einschlaten
44
      }
45
46
      if (ID == 4 && Slave_Address==0){    
47
        SW_Reset();              //Reset auslösen
48
      }
49
    }
50
  }
51
52
}//ISR

das ist was ich soweit habe. doch muss ich nicht dafür sorgen, dass sich 
der slave synchronisiert? oder reicht es das ich einen Quarz nutze ?

von Harald (Gast)


Lesenswert?

Wenn Du einen Quarz nutzt, sehe ich bei festgelegter Baudrate (nicht 
Norm-konform) für Synchronisation keinen Bedarf. Sonst müsste sich ja 
jede beliebige UART-Schnittstelle auf geeignete Art und Weise 
synchronisieren. Im großen Stückzahl-Bereich tut man sicherlich alles 
dafür, um auf einen Quarz verzichten zu können. Ganz nebenbei sollte ein 
RC-Oszillator auch weniger Ausfallrisiko haben (Quarzbruch etc.). Für 
ein privates Projekt oder Kleinserie indes völlig unerheblich.

von Harald (Gast)


Lesenswert?

Sichte gerade deien Code. Du solltest nicht ernsthaft im Interrupt auf 
neue Bytes warten, das frisst ja deine ganze Rechenzwit auf. Viel besser 
baust Du eine State-Machine auf, stark vereinfacht dargestellt:


if (FramingError) state = 1;

switch (state)
{
case 0 : break; // Standby, nichts zu tun

case 1 : Empfangsbyte==0x55  --> nein= state=0, ja=state++

case 2 : Empfangsbyte==ID ?  --> nein=state=0, ja=state++

case 3 : Bytes in Schleife empfangen/senden

case 4 : Checksumme senden bzw. prüfen --> Gültig=state++ / 
ungültig=state=0

case 5 : Frame an Applikation übergeben, state=0

}

von Amir B. (sticky)


Lesenswert?

Is es notwendig es in einer statemashine zu machen? Denn ich sammel mit 
meinem Modul Daten mit den ADC und wandle diese um. Das tue ich solange 
bis ich ein Anfrage vom Master erhalte die gesammelten Daten an ihn 
(Master) zu senden.

gibt es eine bessere Möglischkeit?

von Harald (Gast)


Lesenswert?

Wie gesagt, ich würde den Code auf State-Machine umstellen. Die meisten 
UART sind ja double-buffered, d.h. ein nachfolgend empfangenes Byte 
schlägt im nächsten Durchlauf auf. In deinem Code gibst Du aber dem 
Break nicht die höchste Priorität. Wenn sich der Master den Abbruch des 
Frames überlegt (ist - glaube ich - in der Norm vorgesehen) würde dein 
Code das nicht berücksichtigen bzw. durcheinander kommen.

von Amir B. (sticky)


Lesenswert?

steht denn im Empfangsregister das Syncbreak solange bis ich es mittels 
receiveByte() abrufe? Erhalte ich beim 2. Aufruf von receiveByte() dann 
das Sync-Field?

tut mir leid die fragen mögen sehr trivial und dumm erscheinen.
1
uint8_t Receive_Byte(){
2
  DDRC = (1 << DDC3);       //rote LED einschalten (receive)
3
    while (!(UCSR0A & (1<<RXC0)))  // warten bis Zeichen verfuegbar
4
        ;
5
    return UDR0;          // Zeichen aus UDR an Aufrufer zurueckgeben
6
  DDRC = (0 << DDC3);       //rote LED ausschalten (receive)
7
}

von Harald (Gast)


Lesenswert?

Ich bin jetzt beim AVR nicht so im Thema. Bei einigen Prozessoren muss 
man nach einem Framing Error erstmal alle Fehler zurücksetzen, bevor es 
weiter geht. In diesem Fall würde es so nicht funktionieren. Baue deine 
Interrupt-Routine so auf, dass immer nur ein Byte verarbeitet wird. Dann 
veranlasst Du alles notwendige und bereitest den Interrupt auf den 
Empfang des nächsten Bytes vor.

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.