Forum: Mikrocontroller und Digitale Elektronik Linux Uart AVR


von Stephan (Gast)


Lesenswert?

Hallo,

vieleicht hat jemand von Euch eine Lösung

ich habe ein kleines embedded Linuxboard, welches mit einem
ATMega8 "via Uart "sprechen" soll.

also mit einem Taster sollen "Befehle" zum Linuxboard geschickt werden
das Linuxboard "antwortet" dann.

der Test ATmega8 - Windows PC war erfolgreich
also ich kann mit einem Taster am AVR einen "Befehl" also eine 
Zeichenkette zum
Hyperterminal senden und vom Hyperterminal wieder zum AVR.

######################################################################## 
########
mit dem Linuxboard kann ich auch Zeichen zum AVR senden :

Eingabe z.B:
echo "Hallo AVR" > /dev/ttyS0

die Zeichenkette "Hallo AVR" kommt auch beim ATmega8 an
######################################################################## 
########

mein Problem:
das Linuxboard kann nichts empfangen.

gesendet wird vom AVR :

 uart_puts_P("Hallo Linux\n\0");


die Schnittstelle hängt sich scheinbar auf.
Fehlermeldung : keine

das Linux Skript (Auszug) zum empfangen :

stty 384000 </dev/ttyS0

cat /dev/ttyS0 | while read line; do
    if [ "$line" == "Test" ] ; then
  echo Hallo
  echo Hallo >/dev/ttyS1
    fi
done

#############
mit dem Programm Minicom geht gar nichts
#########################################
also Windows geht Linux nicht
habe ich irgendetwas vergessen ?

die alten Beiträge im Forum brachten noch keine Lösung

Danke Stephan

von Stephan (Gast)


Lesenswert?

gemeint war

das Linux Skript (Auszug) zum empfangen :

stty 384000 </dev/ttyS0

cat /dev/ttyS0 | while read line; do
    if [ "$line" == "Hallo Linux" ] ; then
  echo Hallo
  echo Hallo >/dev/ttyS1
    fi
done

von Whitespace (Gast)


Lesenswert?

stty 384000 </dev/ttyS0
sollte wohl eher
stty 38400 </dev/ttyS0
heißen.

Ich verwende minicom öfters, das geht nicht schlecht.
Allerdings ist es auf Modem-Kommunikation ausgelegt, sodass man zuerst 
die Modem-Steuerzeichen 'entfernen' und auch sonst einiges einstellen 
muss.

von Stephan (Gast)


Lesenswert?

ärger

gemeint war

das Linux Skript (Auszug) zum empfangen :

stty 38400 </dev/ttyS0

cat /dev/ttyS0 | while read line; do
    if [ "$line" == "Hallo Linux" ] ; then
  echo Hallo
      fi
done

also das Linuxboard empfängt nichts
die Schnittstelle hängt sich auf

aber unter /Procs/interrupt kann man "sehen" das ein
serial Interrupt ausgelöst wurde.

von Sven K. (svenk)


Lesenswert?

Was gibt es für einen Grund so zu schicken

uart_puts_P("Hallo Linux\n\0");

und nicht so

uart_puts_P("Hallo Linux\n");

oder uart_puts_P("Hallo Linux\n\r"); ?

Gruß Sven

von Watz (Gast)


Lesenswert?

Moeglicherweise wird auch ein Ctrl-Z am Ende erwartet.

von Rainer S. (heckenpenner)


Lesenswert?

ich hatte mal Probleme wenn ich nicht alles hinter cat /dev/ttySx in 
eine Klammer gesetzt hatte.
Funktioniert den nur cat /dev/ttyS1 ohne Auswertung überhaupt bei dir?




1
#!/bin/bash
2
3
stty 115200 -echo crtscts igncr < /dev/ttyS1 
4
5
cat /dev/ttyS1 | {
6
while [ 1 ]
7
do 
8
  read zeile
9
  echo $zeile
10
    case $zeile in
11
    "12324")
12
        kaffeine -f /mnt/windows/d/Filme/liste.kaffeine&
13
        ;;      
14
    "12303")
15
        dcop kaffeine KaffeineIface fullscreen 
16
        ;;
17
    "12301")
18
        dcop kaffeine KaffeineIface mute 
19
        ;;
20
     esac
21
done
22
}

von butrus (Gast)


Lesenswert?

Braucht der linux nicht den CTS signal?
Oder: stty -F /dev/ttyS0 -crtscts  ?

von Rainer S. (heckenpenner)


Lesenswert?

ich glaube mein Beispiel verwendet Hardware RTS/CTS

von Stephan (Gast)


Lesenswert?

Hallo
vielen Dank für die Unterstützung

ich habe die Skriptbefehle hier gefunden:

Beitrag "Linux steuern über LCD u. Tasten ???"


ich muss gestehen das ich die Zeile :

cat /dev/ttyS0 | while read line; do

nicht verstehe

cat
while schleife
do schleife
??

#####
-crtscts ??

Stephan

von Stephan (Gast)


Lesenswert?

Hallo
um meinen Fehler ertwas einzugrenzen.

was erwartet Linux den am Zeilenende ?

ich bin davon ausgegangen das ein \n reicht
nachdem das nicht funktionierte habe ich noch
für den AVR ein \0 hinzugefügt. daher \n\0

watz(gast)schrieb :
Moeglicherweise wird auch ein Ctrl-Z am Ende erwartet.

ist da ein \Z mit gemeint ??

zu :
 Autor:  Rainer Stamm (heckenpenner)
mit deinem Code ging es leider auch nicht

Gruß
Stephan

von Zwatz (Gast)


Lesenswert?

Ein Ctrl-Z ist ein EOF, End of file. Was auch immer das fuer ein Zeichen 
ist. Ist im ASCII standard definiert.

von Stefan E. (sternst)


Lesenswert?

Das Kommando read erwartet ein '\n' als Zeilenende. Wenn du gerne 
etwas anderes hättest, kannst du das per -d einstellen.

Teste doch erstmal, ob du überhaupt über die serielle Schnittstelle was 
bekommst, mache also nur "cat /dev/ttyS0" ohne zusätzlichen 
Schnickschnack. Ist ttyS0 überhaupt die richtige Schnittstelle? Teste 
auch die anderen, wenn es mehrere gibt.

von Roland P. (pram)


Lesenswert?

1
uart_puts_P("Hallo Linux\n");
ist falsch. Entweder:
1
uart_puts("Hallo Linux\n");
oder bessere Lösung (verbraucht weniger Ram, da Konstante im Flash)
1
uart_puts_P(PSTR("Hallo Linux\n"));

(Weitere Infos stehen irgendwo im Tutorial zu Konstanten im Flash)

2. Fehlerquelle:
Sind die Fuses richtig gesetzt? Falls du da noch nix dran geändert hast, 
stehen die noch auf internen RC-Oszillator. -> Baudrate stimmt nicht.

Gruß
Roland

von Stephan (Gast)


Lesenswert?

Hallo

zu:
 Roland Praml

schrieb:
a)
uart_puts_P("Hallo Linux\n");
ist falsch    (warum ?)

b)
uart_puts("Hallo Linux\n");
wäre richtig
#####################

bei mir funktionieren a) und b)
allerdings nur unter Windows
dh: Fuse müssten auch richtig sein.

das Linuxboard kann auch senden aber nicht empfangen

ich weiss nicht wo ich noch ansetzen soll


Gruß
Stephan

von Sven K. (svenk)


Lesenswert?

Schreibe doch einfach mal ein Linux Programm, welches Dir
Zeichen für Zeichen mit printf ausgibt, nachdem
Du die serielle Schnittstelle Deiner Wahl geöffnet hast.

Wenn es mit ("Hallo Linux\n") unter Windows funktioniert,
tut das auch unter Linux.

Welche Baudrate hast Du eigentlich eingestellt ?
Das hast Du in den Antworten noch nicht geschrieben...

Wahrscheinlich arbeitest Du nicht mit 9600baud oder ?

Gruß Sven

von Roland P. (pram)


Lesenswert?

> Schreibe doch einfach mal ein Linux Programm, welches Dir
> Zeichen für Zeichen mit printf ausgibt, nachdem
> Du die serielle Schnittstelle Deiner Wahl geöffnet hast.

Oder nimm ein Terminalprogramm. Ich nehm unter Linux für so schnelle 
checks gern minicom (und unter Windows Hyperterminal)
Handshake am Besten auf Off stehen (sonst musst du dich um die RTS/CTS 
Leitungen auch noch kümmern)


> uart_puts_P("Hallo Linux\n");
> ist falsch    (warum ?)

alle *_P Funktionen erwarten eine Konstante aus dem Flash. Zum Ablegen 
von solchen Konstanten kann man das PSTR-Makro verwenden. Um das ganze 
GENAU verstehen zu können, muss man leider etwas tiefer in die Materie 
greifen. Der AVR hat halt 2 verschiedene Speicherbereiche RAM/FLASH

> b)
> uart_puts("Hallo Linux\n");

Beispiel zu b:
Beim Programmstart wird der String "Hallo Linux\n" an eine 
RAM-Speicheradresse kopiert, z.B. 0x30

Der Befehl: uart_puts("Hallo Linux\n"); bedeutet nun, dass alles ab 
RAM-Adresse 0x30 bis zum Stringende-Zeichen (0x00) über die UART 
gesendet wird.

Der _P-Befehl bedeutet, das alles ab FLASH(!)-Adresse 0x30 (bis 0x00) 
über die UART gesendet wird. Der Parameter gibt aber eine RAM(!)-Adresse 
an.
Es wird das gesendet was an 0x30 im Flash steht, dies kann zufällig der 
gewünschte String sein, meist sinds aber Sonderzeichen (und der String 
kommt evtl später) so dass Windows mit dem "Müll" der vor dem String 
kommt, zwar klarkommt, linux aber nicht.

auch wenn
 uart_puts_P("Hallo Linux\n");
zu funktionieren scheint, es ist DEFINITV falsch so.

hier sind noch ein paar Erläuterungen
Beitrag "sprintf_P & PSTR"
Gruß
Roland

von Stephan (Gast)


Lesenswert?

Hallo

Tag 2

Hallo Roland Praml
vielen Dank für deinen letzten Betrag.
ich schau mir das Tutorial nochmal an.

ich habe den "Fehler" gefunden :

nach Hinweis von Stefan Ernst (sternst)
wurde das Skript auf :
cat < /dev/ttyS0
reduziert

nach Aufruf dieses Skriptes ändert sich die Baudrate automatisch
auf den Standardwert von 115200.
Meine Baudrate war aber auf 38400 eingestellt.

Frage wie kann ich die automatisch Änderung der Baudrate verhindern ?

ich bin jetzt ein ganzes Stück weiter

Stephan

von yalu (Gast)


Lesenswert?

> ich habe den "Fehler" gefunden :

Heißt das, dass das "Hallo Linux\n" jetzt tatsächlich vom
Linux-Rechner empfangen wird?

> nach Aufruf dieses Skriptes ändert sich die Baudrate automatisch auf
> den Standardwert von 115200.

Wie meinst du das? Du stellst die richtige Baudrate mit

  stty 384000 </dev/ttyS0

nach deinen Wünschen ein, und später steht sie plötzlich auf 115200?
Möglicherweise läuft noch ein anderer Prozess auf dem Rechner, der die
Baudrate regelmäßig auf einen anderen Wert setzt und mitunter die
ankommenen Daten selber frisst, z.B. ein {,a,m,min}getty o.ä.

Lass dir mal mit

  ps auxw

alle Prozesse anzeigen und sieh nach, ob einer davon "ttyS0" in seiner
Parameterliste stehen hat. Ist dies nicht der Fall, kannst du die
ausgegebene Prozessliste hier posten. Vielleicht erkennt jemand darin
den Störenfried.

von Simon K. (simon) Benutzerseite


Lesenswert?

Roland Praml wrote:
>  uart_puts_P("Hallo Linux\n");
> zu funktionieren scheint, es ist DEFINITV falsch so.

Das stimmt nicht. uart_puts_P könnte aus der Fleury Lib sein, da ist es 
sogar gewollt das so zu schreiben.

http://homepage.hispeed.ch/peterfleury/group__pfleury__uart.html#ga18

von Stephan (Gast)


Lesenswert?

Hallo,

hier einige mit dem gleichen Problem

Beitrag "OT Uart unter Linux?"
http://www.linuxforen.de/forums/archive/index.php/t-163036.html
http://www.wer-weiss-was.de/theme26/article1672370.html
und
und

!!!
Alle die mit 115200 Baud arbeiten, haben dieses Problem nicht !!
115200 ist die Standardeinstellung von  meiner NSLU2 / unslung
!!!
ich habe nur einen 16 MHz Quarz also 38400 eingestellt, wg Atmega8
#################################################################
mit dem Linuxbefehl:

stty -a -F /dev/ttyS0 > vorher.txt  --> 38400 Baud
Nach dem Aufruf von   cat < /dev/ttyS0
stty -a -F /dev/ttyS0 > vorher.txt --> 115000 Baud

hab ich mir die Einstellungen von der Schnittstelle in eine Datei
schreiben lassen.

Simon hat recht mit Fleury Lib !

Das Terminalprogramm Minicom funktioniert jetzt auch, ich hatte es
nach dem Aufruf von cat.. mit 38400 gestartet, da war die Bautrate
aber schon auf 115000.
###################################################
Kurze Info:
das Ding holt "meldet" meine Emails und die meiner Frau
kontrolliert den FTP Server auf Eingänge
hat das aktuelle Datum,
holt regelmässig Bilder von einer Webcam wg. Urlaub / Regen
funktioniert alles wunderbar, braucht 2 Watt und läuft 24/7
jetzt wird mir das zuviel und ich benötige ein Tastengesteuertes Menü.

Gruß
Stephan
bin seit Juni dabei, von 0 Kenntnissen bis jetzt.

von Stefan E. (sternst)


Lesenswert?

Und was ist mit dem möglichen getty-Prozess?
Mache doch mal das schon vorgeschlagene "ps axw" und poste das Ergebnis 
hier.

von Stephan (Gast)


Lesenswert?

Hallo,

da hatte ich wohl etwas nicht bedacht :

wie Eingangs erwähnt "embedded Linuxboard" ohne Tastatur und Bildschirm

den Zugang zur Verwaltung etc. mach ich übers Netzwerk via Putty SSH

die Standardbaudrate ist 115200, Teile des Linux Betriebssystems liegen
im Flash andere auf einem USB Stick (no HDD).

wenn ich die serielle Schnittstelle des Boards mit dem PC über einen 
Pegelwandler mit dem Board verbinde, kann ich den Bootvorgang mit einem 
Windows Terminalprogramm (115200 Baud) beobachten.

Mein Ziel war, es "Meldungen" vom Linuxboard an den ATmega via Uart zu 
senden
- was auch klappt und über am AVR angeschlossene Taster "Befehle" zum 
Linuxboard zu schicken -was nicht klappte.

denn :
sobald ich nur 1 Zeichen sende, "fordert"  mich das Board promtlos auf, 
mich über die serielle Schnittstelle einzuloggen.
Diese "Aufforderung" kommt immer mit der Baudrate von 115200. daher 
wahrscheinlich auch die Baudratenänderung.

wenn ich nun im Windows Terminalprogramm eingebe:
Login
Benutzer
Passwort
bin ich drin.

das war aber nicht Sinn der Sache

als Anhang noch die gewünschte "Datei"

der Rechner soll machen was ich will, sonst gcc !!

mit freundlichen Grüßen
Stephan

von Stephan (Gast)


Angehängte Dateien:

Lesenswert?

ups

von Sven K. (svenk)


Lesenswert?

Tja, jetzt weißt Du, das der Kernel sich die Konsole auf die
serielle Schnittstelle holt, auf der Du eigene Dinge programmieren 
willst.

Jetzt hast Du im einfachsten Fall 3 Möglichkeiten:

1. Du hast noch eine weitere serielle Schnittstelle.
   Du benutzt diese für die AVR Kommunikation.

2. Du hast ein USB-Host Interface an Deinem Board und
   kannst einen USB <-> RS232 seriell Wandler anschliessen
   und damit auf den AVR gehen.

3. Du weisst ganz genau was Du tust und schaltest die Notfall
   Konsole auf Deiner seriellen Schnittstelle von oben ab
   und kannst diese ganz normal nutzen, ohne das Dir der Kernel
   dazwischen funkt.
   Damit kommst Du aber nur noch per ssh auf das Linux Board.
   Also Vorsicht.

Gruß Sven

von Sven K. (svenk)


Lesenswert?

Was ist das genau für ein Linux Board ?
Mit Intel Chip IXP425 konnte ich ja erkennen,
aber welches Board genau ?

Gruß Sven

von yalu (Gast)


Lesenswert?

Sven K. schrieb:
> 1. Du hast noch eine weitere serielle Schnittstelle.
>    Du benutzt diese für die AVR Kommunikation.

Ja, in deinen Skripten tauchen sowohl ttyS0 als auch ttyS1 auf. Heißt
das, dass der Rechner eine zweite serielle Schnittstelle hat? Dann
kannst du ja einfach diese anstelle von ttyS0 verwenden.

Sonst:

> sobald ich nur 1 Zeichen sende, "fordert"  mich das Board promtlos
> auf, mich über die serielle Schnittstelle einzuloggen.

Ja, genau das macht das getty-Programm. Also musst du diesem getty
irgendwie den Garaus machen, damit die Schnittstelle frei wird.

> als Anhang noch die gewünschte "Datei"

Hmm, da ist kein getty dabei und auch nichts, was wie ein getty-Ersatz
aussieht. Vielleicht hat es sich aber auch nur getarnt. Warst du, als
du das 'ps axw' eingegeben hast, über SSH oder über das
Terminalprogramm eingeloggt? Falls letzteres der Fall ist, hat getty
bei der Eingabe des ersten Zeichens login geexect und damit den Namen
"login" angenommen. Auf Desktop-Linux-Systemen forkt login nach
erfolgreicher Passworteingabe die Shell, so dass man jetzt zwei
Prozesse "login" und "-<Name der Shell>" sehen kann. Da auf deinem
Embedded-Rechner aber auch kein "login"-Prozess zu sehen ist, ist
wahrscheinlich die platzsparendere TinyLogin-Suite installiert, die
die Shell nicht forkt, sondern exect. Damit ensteht kein neuer
Prozess, stattdessen ändert der laufende Prozess erneut seinen Namen.

Sind die bisherigen vagen Vermutungen alle richtig, ist der Prozess
590 mit dem Namen "-sh" der ursprüngliche getty-Prozess, der seither
zweimal seinen Namen geändert hat. Wenn du dir die Prozessliste über
SSH ausgeben lässt, während niemand über die serielle Schnittstelle
eingeloggt ist (und auch nicht versucht, sich einzuloggen), solltest
du den getty-Prozess mit seinem ursprünglichen Namen sehen können.

Getty wird üblicherweise von init gestartet. Wann und wie, steht in
/etc/inittab. Schau mal nach, ob diese Datei eine Zeile mit

  ...:respawn:/sbin/getty 115200 ttyS0 ...

(oder so ähnlich) enthält. Um den Start von getty zu verhindern, musst
du diese Zeile löschen oder mit einem '#' am Anfang auskommentieren.
Ich hoffe, dass der USB-Stick so gemountet ist, dass man die Datei
problemlos ändern kann. Wenn nicht, muss man nach einer anderen
Möglichkeit suchen.

Falls auf dem Linux-System kein Texteditor installiert ist, kannst du
die Datei auch auf den PC übertragen und dort die Änderung vornehmen.

VORSICHT: Wenn du an der inittab-Datei etwas verhaust, bootet das
System möglicherweise nicht mehr. Da die dann fällige Reparatur der
Daten nicht ganz einfach ist, wäre es sinnvoll, vor Beginn der
Experimente eine Sicherheitskopie der Inhalte des Sticks zu machen.

Wenn du die Änderung in inittab gemacht hast, sollte beim nächsten
Reboot getty nicht mehr gestartet werden, d.h. die serielle
Schnittstelle ist jetzt (fast) frei. Fast deswegen, weil sie
wahrscheinlich auch als Konsole zur Ausgabe von Kernelmeldungen
genutzt wird. Ich gehe aber davon aus, dass der Kernel nach erfolgtem
Bootvorgang die Klappe hält. Stören den angeschlossenen Controller die
Bootmeldungen, muss dem Kernel per Parameter mitgeteilt werden, dass
er ttyS0 nicht als Konsole benutzen soll. Wie die Kernel-Parameter
geändert werden können, hängt allerdings vom verwendeten Bootloader
ab.

Bevor du dauerhafte Änderungen an inittab machst, kannst du getty
probehalber temporär außer Gefecht setzen. Das Abbrechen des Prozesses
bringt allerdings nichts, da auf Grund des respawn-Flags in inittab
(s.o.) sofort ein neuer gestartet wird. Du kannst ihn aber mit

  kill -SIGSTOP <pid>

anhalten. Dabei ist <pid> die von ps angezeigte Prozess-ID. Falls
gewünscht, kann der Prozess mit

  kill -SIGCONT <pid>

wieder fortgesetzt werden. Aber wie gesagt, das ist keine Dauerlösung.

von Stefan E. (sternst)


Lesenswert?

Wenn über die inittab ein getty gestartet wird, würde ich den Eintrag 
aber nicht auskommentieren oder löschen, sondern von respawn auf 
once ändern. So hat man nach einem Reboot weiterhin die Möglichkeit, 
sich über die serielle Schnittstelle einzuloggen (zumindest einmal), und 
man kann den getty problemlos vor dem Start der eigenen Sachen killen.

von Roland P. (pram)


Lesenswert?

Simon K. wrote:
> Roland Praml wrote:
>>  uart_puts_P("Hallo Linux\n");
>> zu funktionieren scheint, es ist DEFINITV falsch so.
>
> Das stimmt nicht. uart_puts_P könnte aus der Fleury Lib sein, da ist es
> sogar gewollt das so zu schreiben.
>
> http://homepage.hispeed.ch/peterfleury/group__pfleury__uart.html#ga18

stimmt, hier ist "uart_puts_P(...)" (großes P) ein Makro das 
"uart_puts_p(PSTR(...))" (kleines p) ausführt und hier ist dann auch das 
von mir erwähnte PSTR drin.

übrigens mit
lsof -n | grep tty
sieht man schnell, welche Prozesse ein tty geöffnet haben

Gruß
Roland

von Peter Tanzerl (Gast)


Lesenswert?

Ich möchte gern mit den AVR32 im Linuxsystem eine UART Bridge bauen d.h 
z.B. das alles was auf ttys0 ankommt direkt auf ttys1 weitergeleitet 
wird und umgekehrt. Das ist mit Kanonen auf spatzen geschossen das ist 
mir schon klar :-) ... macht es sinn an dieser Stelle ein Perl skript 
oder richtigen c-code zu schreiben ??? Hat jemand ein Codeschnipsel für 
mich ???

Danke Peter

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.