Forum: Mikrocontroller und Digitale Elektronik LIN-Break Signal mit TI CC2640 erzeugen


von Maximilian H. (wolkenschaufler)


Lesenswert?

Hallo,

ich versuche einen LIN-Treiber auf Basis eines TI CC2640 zu entwickeln.

Der uC kann den benötigten Frame-Break in einer Längen von <13 Bit 
erzeugen. Allerdings verstehe ich die Treiberdokumentation von TI noch 
nicht so ganz.

Das entsprechende Register kann man mit der Funktion UARTBreakCtl 
setzen.

In der Dokumentation steht aber folgende Anmerkung dabei:

> For proper transmission of a break command, the break must be asserted for > at 
least two complete frames.

Quelle: 
http://software-dl.ti.com/dsps/dsps_public_sw/sdo_sb/targetcontent/tirtos/2_18_00_03/exports/tirtos_full_2_18_00_03/products/cc26xxware_2_23_03_17162/doc/driverlib/group__uart__api.html#ga0cb85e7658795a9656fc1065f025b1e5

Kann mir jemand vielleicht einen Tipp geben wie das zu verstehen ist?

Warum reicht es nicht, dass Bit zu setzen, 13 Bits zu warten und dann 
wieder umschalten?

Danke und viele Grüße

Maximilian

von Clemens L. (c_l)


Lesenswert?

Wenn du mit dem Break die Übertragung eines anderen Bytes unterbrichst, 
dann sieht der Empfänger erstmal nur ein ungültiges Byte, und kann erst 
danach den Beginn des Breaks erkennen.

Bei einem korrekt arbeitenden LIN-System wird der Break nicht zur 
Unterbrechung von anderen Daten benutzt, sonder nur, um die 
Baudratenerkennung in den Empfängern auszulösen. Es genügt also die in 
der LIN-Spezifikation festgelegte Länge, 13 Bits.

von Rudolph R. (rudolph)


Lesenswert?

Hmm, okay UARTBreakCtl() ist eine Funktion aus dem UART-Treiber.
Ganz toll, kommt man an die Register von dem Controller nicht ran?

Setze lieber die Baud-Rate runter und sende ein einzelnes Null-Byte für 
den Break.

von Maximilian H. (wolkenschaufler)


Lesenswert?

Hallo,

Danke für eure Rückmeldungen.

Clemens L. schrieb:
> Es genügt also die in der LIN-Spezifikation festgelegte Länge, 13 Bits.

Wobei es ja heißt, man muss mindestens 13 Bits zum aufwecken der Slaves 
einen Break senden. Wenn es also zwei Frames sind, ist es auch nicht 
weiter tragisch.

Bist du dir mit der Baudratenerkennung sicher? Dachte die ist sowieso im 
LDF festgelegt?

Rudolph R. schrieb:
> Ganz toll, kommt man an die Register von dem Controller nicht ran?

Doch, die Fkt macht nichts anderes. Siehe Zeile 700 hier:
http://software-dl.ti.com/dsps/dsps_public_sw/sdo_sb/targetcontent/tirtos/2_18_00_03/exports/tirtos_full_2_18_00_03/products/cc26xxware_2_23_03_17162/doc/driverlib/uart_8h_source.html#l00700

HWREG() ist ein Makro zum ansprechen vom Register.

Aber ich verstehe eben nicht, was mit der Anmerkung gemeint sein soll. 
Wenn ich da Bit setze ist der Bus doch sowieso auf low??

Rudolph R. schrieb:
> Setze lieber die Baud-Rate runter und sende ein einzelnes Null-Byte für
> den Break.

Daran hatte ich auch schon gedacht, würde jedoch lieber den 
"offiziellen" Weg gehen. Sollte das nicht klappen, mache ich es über die 
Baudrate.

von Rudolph (Gast)


Lesenswert?

Maximilian H. schrieb:
> Daran hatte ich auch schon gedacht, würde jedoch lieber den
> "offiziellen" Weg gehen.

Nun ja, da steht nichts von LIN, das ist ein UART-Treiber, mehr nicht. 
Meinen die mit Break überhaupt das gleiche?

von Clemens L. (c_l)


Lesenswert?

Maximilian H. schrieb:
> Bist du dir mit der Baudratenerkennung sicher? Dachte die ist sowieso im
> LDF festgelegt?

LIN ist für billige Slaves ohne Quarz-Oszillator ausgelegt; wenn der 
UART mit 9600 baud ± 20 % läuft, dann würde man ohne das Sync-Feld 
nichts empfangen können.

von Soul E. (Gast)


Lesenswert?

Rudolph schrieb:

> Nun ja, da steht nichts von LIN, das ist ein UART-Treiber, mehr nicht.

Wenn für LIN-Master nur ein UART zur Verfügung steht, gibt es zwei 
Möglichkeiten: für den Sync Break den Pin auf GPIO Output Low 
umschalten, oder temporär die Baudrate runtersetzen.


> Meinen die mit Break überhaupt das gleiche?

Vermutlich nicht. Im Zusammenhang mit UART meint Break einen bewusst 
generierten Frame Error, um die gegnerische Übertragung zu stoppen. Die 
genaue Länge ist egal, Hauptsache das Stopbit ist low (was in einem 
normalen UART-Frame unzulässig ist).

Bei LIN bedeutet Sync Break quasi das Startbit der kompletten Botschaft. 
Ein LIN-Frame beginnt mit einer überlangen Low-Periode, gefolgt von 
einem Rechtecksignal mit der halben Bitrate. Letzteres kann man durch 
Senden von 0x55 (oder war es 0xAA?) simulieren, ersteres halt nur durch 
Tricksen.



Bei einem LIN Slave reicht es, auf ein Byte mit Frame Error gefolgt von 
einem weiteren mit dem Inhalt 0x55 (0xAA?) zu warten. Zum Bestehen des 
Conformance Test muss die Länge des Sync Break bewertet werden, in der 
Praxis ist das aber egal.

von Clemens L. (c_l)


Lesenswert?

soul e. schrieb:
> Wenn für LIN-Master nur ein UART zur Verfügung steht, gibt es zwei
> Möglichkeiten: für den Sync Break den Pin auf GPIO Output Low
> umschalten, oder temporär die Baudrate runtersetzen.

Dritte Möglichkeit: dem UART sagen, er soll einen Break senden. Ich 
kenne keinen, bei dem das nicht möglich wäre (auch wenn es im 
einfachsten Fall das Äquivalent eines GPIOs ist, wie hier).

>> Meinen die mit Break überhaupt das gleiche?
>
> Vermutlich nicht.

In beiden Fällen ist es ein überlanger Space-Zustand.

> Zum Bestehen des Conformance Test muss die Länge des Sync Break bewertet
> werden, in der Praxis ist das aber egal.

Wie schon erwähnt: in der Praxis wissen viele Slaves nicht, wie schnell 
(relativ zum Master) sie sind.

von Maximilian H. (wolkenschaufler)


Lesenswert?

Das Sync-Byte nach dem break ist 0x55. Ich dachte eigentlich, das ist 
zur Synchronisierung zwischen Slave und Master da. Der Break ist doch 
nur zum Aufwecken da oder?

soul e. schrieb:
> Die genaue Länge ist egal,

Kann ich bestätigen. Habe die Kommunikation schon mal mit einem Arduino 
und der Software UART aufgebaut. Dort hatte ich einen Fehler in der 
Zeitberechnung und obwohl der Break viel zu lang war, hat der Slave 
geantwortet.

Clemens L. schrieb:
> Dritte Möglichkeit: dem UART sagen, er soll einen Break senden. Ich
> kenne keinen, bei dem das nicht möglich wäre

Genau das will ich doch, versteh aber nicht ganz wie das zu 
Bewerkstelligen ist. Siehe Eröffnungspost von mir.

Gruß Maximilian

von Clemens L. (c_l)


Lesenswert?

Maximilian H. schrieb:
> Clemens L. schrieb:
>> dem UART sagen, er soll einen Break senden.
>
> Genau das will ich doch, versteh aber nicht ganz wie das zu
> Bewerkstelligen ist.

Bit setzen, mindestens 13 Bit-Times warten, Bit löschen.

von Maximilian H. (wolkenschaufler)


Lesenswert?

Clemens L. schrieb:
> Bit setzen, mindestens 13 Bit-Times warten, Bit löschen.

Genau das funktioniert eben nicht. Auch nicht wie in dem Note vom 
Treiber geschrieben, zwei Bytes zu senden.

Oder mache ich da was grundsätzlich falsch? Bei unten genanntem Code 
hängt der uC bei UART_write.
1
 
2
while (1) {
3
    HWREG(UART0_BASE + UART_O_LCRH) =
4
    (true ?
5
    (HWREG(UART0_BASE + UART_O_LCRH) | UART_LCRH_BRK) :
6
    (HWREG(UART0_BASE + UART_O_LCRH) & ~(UART_LCRH_BRK)));
7
8
 
9
    GPIO_write(Board_GPIO_LED1, Board_GPIO_LED_ON);
10
    UART_write(uart, &Break, 1);
11
    UART_write(uart, &Break, 1);
12
    HWREG(UART0_BASE + UART_O_LCRH) =
13
    (false ?
14
    (HWREG(UART0_BASE + UART_O_LCRH) | UART_LCRH_BRK) :
15
    (HWREG(UART0_BASE + UART_O_LCRH) & ~(UART_LCRH_BRK)));
16
17
 
18
    Task_sleep(1000 * (1000 / Clock_tickPeriod));
19
    GPIO_write(Board_GPIO_LED1, Board_GPIO_LED_OFF);
20
 }

von Clemens L. (c_l)


Lesenswert?

Maximilian H. schrieb:
> Genau das funktioniert eben nicht.

Vielen Dank für die ausführliche Fehlerbeschreibung. (Du hast 
wahrscheinlich kein Oszilloskop oder LA?)

Zeig doch mal, wie du 13 Bit-Times lang wartest.

> Auch nicht wie in dem Note vom Treiber geschrieben, zwei Bytes zu senden.

Er verlangt nicht von dir, zwei Bytes zu senden, sondern so lange zu 
warten, wie zwei Frames brauchen würden.

Und wartet UART_write() auch wirklich, bis das Byte komplett gesendet 
wurde? Gibt es da nicht etwa einen Sendepuffer?

von Maximilian H. (wolkenschaufler)


Lesenswert?

Clemens L. schrieb:
> Vielen Dank für die ausführliche Fehlerbeschreibung. (Du hast
> wahrscheinlich kein Oszilloskop oder LA?)

Oszi habe ich und hab damit auch auf den UART geschaut. Leider ein 
altes, also keine LA. Hab mir mal zwar einen mit nem Arduino gebaut, 
funktioniert aber nicht so recht weil der Speicher kaum ausreicht.

Wenn ich das Bit über die JTAG-Schnittstelle manuell setze geht der Bus 
auf Null.

Auch das setzen im Code funktioniert -> Der UART TX Pin geht auf Null.

Alles andere funktioniert dann irgendwie nicht mehr... Deswegen habe ich 
mir auch die LEDs mit
1
    GPIO_write(Board_GPIO_LED1, Board_GPIO_LED_ON);
ein und wieder ausschalten lassen. Die LED bleibt an, deswegen vermute 
ich, bleibt der uC "dazwischen" hängen.

Warten habe ich schon versucht mit:
1
    Task_sleep( 760 / Clock_tickPeriod);

Ich hab auch mal im TI-Forum gefragt, aber da weiß bisher auch nicht so 
genau, wie die note beim Treiber zu verstehen ist.

Clemens L. schrieb:
> Und wartet UART_write() auch wirklich, bis das Byte komplett gesendet
> wurde? Gibt es da nicht etwa einen Sendepuffer?

Weiß ich nicht - schau ich mir mal an.

Clemens L. schrieb:
> Er verlangt nicht von dir, zwei Bytes zu senden, sondern so lange zu
> warten, wie zwei Frames brauchen würden.

Ich weiß nicht, ich finde das kommt darauf an, wie man asserted 
übersetzt... Aber ich bin nicht so der Englisch Profi ;-)

von Rudolph R. (rudolph)


Lesenswert?

Maximilian H. schrieb:
> Das Sync-Byte nach dem break ist 0x55. Ich dachte eigentlich, das ist
> zur Synchronisierung zwischen Slave und Master da.

Ist es ja auch, der Slave kann die Bit-Zeiten messen und bei Bedarf die 
Baudrate anpassen.
Da ich LIN-Slaves nicht in größeren Stückzahlen baue spare ich mir das 
und hänge da lieber einen Quarz oder Resonator an den Controller.

> Der Break ist doch nur zum Aufwecken da oder?

Nein, um den Start des Frames zu markieren.
Geweckt wird über den Transceiver mit dessen Inibit-Ausgang indem die 
Spannungs-Versorgung eingeschaltet wird.
Wenn ein LIN-Slave ordentlich schläft ist der Controller aus.

Um das Break als solches erkennen zu können dürfte der Controller 
bestenfalls ein wenig schlummern.

von Frank K. (fchk)


Lesenswert?

Maximilian H. schrieb:

> Oszi habe ich und hab damit auch auf den UART geschaut. Leider ein
> altes, also keine LA. Hab mir mal zwar einen mit nem Arduino gebaut,
> funktioniert aber nicht so recht weil der Speicher kaum ausreicht.

Dann sei nich tdumm und hol dir so ein kleines USB-Teilchen wie das 
hier:

ebay #181767474651

Das langt für einfache UART/SPI/I2C Geschichten vollkommen und erspart 
Dir Stunden und Tage fruchtlosen Suchens.

> Ich weiß nicht, ich finde das kommt darauf an, wie man asserted
> übersetzt... Aber ich bin nicht so der Englisch Profi ;-)

Dann werde es. Im Beruf wirst Du es brauchen.

fchk

PS: Hast Du überhaupt die LIN-Primärspezifikationen vorliegen?
Wenn nicht: Google nach
1
"LIN specification package" filetype:pdf
und bediene dich.

von Maximilian H. (wolkenschaufler)


Lesenswert?

Frank K. schrieb:
> Dann sei nich tdumm und hol dir so ein kleines USB-Teilchen wie das
> hier:
>
> ebay #181767474651

Hab ich gemacht.

Frank K. schrieb:
> Dann werde es. Im Beruf wirst Du es brauchen.

Bei dem was ich beruflich vorhabe nicht ;-) Aber natürlich hast du 
recht, hab ich auch festgestellt in meinen 4 Jahren im Job. Ich bin mir 
dennoch nicht ganz sicher, was mit dem asserted gemeint ist.

Den Break will er dennoch ums verrecken nicht senden... Egal ob ich 
jetzt zwei Bytes warte oder versuche, zwei Bytes zu senden.

Mach ich da etwas grundsätzlich falsch?
1
    while(UARTBusy(UART0_BASE)); // wait until UART is available
2
3
    UARTIntDisable(UART0_BASE, UART_INT_TX); //Disable tx Interrupt
4
    UARTBreakCtl(UART0_BASE, true);     //set Break
5
    Task_sleep(1050 / Clock_tickPeriod); //assert two frame times
6
7
    while(UARTBusy(UART0_BASE)); //wait until UART is available
8
9
    UARTBreakCtl(UART0_BASE, false);        //unset Break
10
    UARTIntEnable(UART0_BASE, UART_INT_TX); //enable UART Interrupt

von Maximilian H. (wolkenschaufler)


Lesenswert?

Hallo,

da ich das mit dem Break einfach nicht hinbekommen habe, habe ich es 
jetzt mittels Baudratenumschaltung gelöst.

Sende ich ein Nullbyte mit 13000 Baud so akzeptiert der Slave die 
Präambel und antwortet.

Das einzige was ich jetzt nicht genau unter Kontrolle habe ist der 
Inter-Byte Space zwischen Break und Sync.

Gruß

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.