Forum: Projekte & Code AVR-GCC: UART mit FIFO


von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Anbei mal ne UART-Routine für AVRs mit FIFO fürs Senden und Empfangen.


Funktion:

Die FIFO arbeitet mit Ein- und Ausgabeindex. Gegenüber Pointern ergibt 
sich dadurch kürzerer und schnellerer Code.
In der Regel reichen max 258 Byte Empfangspuffer (HW-Puffer + SW-Puffer) 
aus.
Sind beide Indexe gleich, dann ist nichts im Puffer. Die Eingabefunktion 
(Receiveinterrupt) schreibt was in den Puffer und erhöht ihren Index. 
Die Ausgaberoutine holt das Byte ab und erhöht ihren Index gleichfalls. 
Sind beide Indexe gleich, ist der FIFO wieder leer.
Da die Indexe nur bis zum FIFO-Limit wachsen dürfen, macht das Erhöhen 
das Macro ROLLOVER. Es erhöht den Wert und setzt ihn wieder auf Null, 
wenn er das Maximum erreicht.

Die Funktion ugetchar0() liefert ein Byte aus dem FIFO zurück. Aber ist 
nichts im FIFO, dann wartet sie, bis was empfangen wurde. Wenn in dieser 
Zeit aber andere Tasks auszuführen sind, ist es daher sinnvoll, erstmal 
ukbhit0() aufzurufen, ob überhaupt was im FIFO ist.

Analog gibt es beim Senden die Funktion utx0_ready() zum Prüfen, ob der 
FIFO noch Platz hat. Damit kann man statt warten, bis ein Byte gesendet 
wurde, was anderes machen.

Ein Empfangspufferüberlauf wird nicht abgetestet. Wer will, kann ihn 
hinzufügen. In der Regel sichert man sich mit einem Protokoll gegen 
falsche Daten bei Überlauf, z.B. CRC-Test.


Fallgrube 1:

Ich war es leid, ständig mit Fehlermeldungen bombardiert zu werden, wenn 
ich mal nen anderen AVR verwende.
Der Hauptteil der Arbeit bestand daher darin, das Namens-Chaos bei den 
AVRs in geordnete Bahnen zu lenken.
In der uart0.h sind daher ne ganze Menge Macros drinne, die die 
verschiedenen Namen umdefinieren, damit ein Code alle AVRs erschlägt.

Die Funktionsnamen enden alle auf die Ziffer 0.
Wenn man einen AVR mit 2..4 UARTs benutzt, kann man den Code einfach für 
die anderen UARTs kopieren und die 0 durch 1..3 ersetzen.


Fallgrube 2:

Da hier Interrupts mit main-Funktionen kommunizieren, müßten die Indexe 
als volatile definiert werden, damit sie der AVR-GCC nicht wegoptimiert.
Dies würde aber in den Interrupts besonders weh tun, da es mehr Code 
bedeutet.
Daher werden nur die Zugriffe in den main-Funktionen als volatile 
gecastet (per Macro in meiner mydefs.h).


Fallgrube 3:

Die Kommunikation Interrupts mit Funktionen birgt die Gefahr, daß ein 
Interrupt genau innerhalb eine Funktion zuschlägt und damit falsche 
Werte liest oder setzt.
Die in meinem Code gewählte Reihenfolge der Instruktionen ist 
interruptfest, d.h. nirgends müssen atomare Zugriffe unter 
Interruptsperre gemacht werden.
Will jemand was an dem Code ändern, muß er das berücksichtigen.
Außerdem muß man mit Interruptsperre arbeiten, wenn man die Indexe auf 
16Bit erweitern will oder Pointer statt Indexe verwenden will.
16Bit Zugriffe sind ja auf nem 8Bitter nicht interruptfest.


Peter

von Simon K. (simon) Benutzerseite


Lesenswert?

Peter Dannegger wrote:
> Anbei mal ne UART-Routine für AVRs mit FIFO fürs Senden und Empfangen.
>
>
> Funktion:
>
> Die FIFO arbeitet mit Ein- und Ausgabeindex. Gegenüber Pointern ergibt
> sich dadurch kürzerer und schnellerer Code.

Wieso ergibt sich denn kürzerer und schnellerer Code mit Index statt 
Pointern? Bei Pointern muss nur dereferenziert werden (ld mit der 
Adresse im X,Y,Z register). Bei Indizes muss noch gerechnet werden..

Oder liege ich da falsch?

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Simon K. wrote:

> Wieso ergibt sich denn kürzerer und schnellerer Code mit Index statt
> Pointern? Bei Pointern muss nur dereferenziert werden (ld mit der
> Adresse im X,Y,Z register). Bei Indizes muss noch gerechnet werden..

Aber bei Pointern muß jede Operation 16-bittig gemacht werden (Laden, 
Rückschreiben, Test auf Gleichheit, Test auf Endwert, Setzen auf 
Startwert).
Dagegen sind die beiden zusätzlichen 8-Bit Additionen beim Indexzugriff 
nur pillepalle.

Ich hab mal nur die Empfangsroutine auf Pointer umgestellt und schon 
stieg der UART Code von 322 auf 378 Byte.
Anbei der Code.


Peter

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Wäre es nicht besser, UART und FIFO zu entflechten? Damit wäre FIFO 
unabhängig vom UART verwendbar. In meinen Anwendungen benutze ich auch 
FIFOs, teilweise mehrere in einer Anwendung. Wenn der Code dann immer 
wiederholt werden muss, spart man ja nix, und Klarheit gewinnt man auch 
nicht...

von Peter D. (peda)


Lesenswert?

Georg johann Lay wrote:
> Wäre es nicht besser, UART und FIFO zu entflechten? Damit wäre FIFO
> unabhängig vom UART verwendbar.

Der FIFO ist speziell für die UART ausgelegt, z.B. die Enable/Disable 
Interupt Befehle, um den HW-Puffer mit zu benutzen.
Auch würde ein Warten in den Funktionen einen Deadlock bedeuten, wenn 
der FIFO nicht mit Interrupts verwendet wird.


> In meinen Anwendungen benutze ich auch
> FIFOs, teilweise mehrere in einer Anwendung.

Kannst Du dafür mal Beispiele nennen?
Ich brauche nen FIFO ausschließlich in der UART, da nur dort die Bytes 
einzeln reinkommen bzw. Zeit zum Senden brauchen.


> Wenn der Code dann immer
> wiederholt werden muss, spart man ja nix, und Klarheit gewinnt man auch
> nicht...

Man könnte dafür Macros schreiben, das spart aber nix, da der Code für 
jeden FIFO separat existieren muß. Die FIFOs sollen sich ja nicht 
gegenseitig stören.

Man könnte ein Array aus n FIFOs definieren und den FIFO per Argument 
auswählen.
Damit wird der Code aber nur größer und langsamer, da dann nie direkt 
auf die FIFO-Indexe zugefriffen werden kann sondern die erst umständlich 
indirekt ausgelesen werden müssen.


Peter

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter Dannegger wrote:
> Georg johann Lay wrote:
>> In meinen Anwendungen benutze ich auch
>> FIFOs, teilweise mehrere in einer Anwendung.
>
> Kannst Du dafür mal Beispiele nennen?
> Ich brauche nen FIFO ausschließlich in der UART, da nur dort die Bytes
> einzeln reinkommen bzw. Zeit zum Senden brauchen.

Zwei FIFOs brauchts in der genannten Anwendung für den UART, eine 
weitere brauch ich für Timer1. Timer1 muss einerseite per Auftrag ne 
HW-PWM erzeugen können, aber auch eine Zeitmessung (Kapazitätsmessung an 
einer LED zur Helligkeitsmessung) via InCapture. (Die beiden 
Verwendungen schliessen sich aus, erlauben aber kleiner Verzögerungen in 
der Ausführung. Das InCapt muss mit einer Soft-PWM synchronisiert 
werden, da die LED auch während der Helligkeitsmessung leuchten soll).

Insgesamt verwende ich 4 FIFOs (2*ISR-UART (IN+OUT), 1*Timer1-Service, 
1*HW-PWM-Muster).

Da ich meine Anwendungen sämtlich nicht-blockierend schreibe, gibt es in 
der main-Schleife keine Warte- oder Poll-Schleifen. Es wäre also nicht 
möglich, auf die OFF-Phase der Soft-PWM zu warten, um eine Messung 
einzufügen.

Die Anwendung ist zugegeben recht speziell, ich will aber net jedesmal 
FIFO neu coden und verwende auch anderswo, wo es nur eine FIFO braucht, 
den allgemeinen Code. Ich nehem dort ein paar Ticks mehr an 
Ausführungszeit in kauf.

Peter Dannegger wrote:
> Fallgrube 2:
>
> Da hier Interrupts mit main-Funktionen kommunizieren, müßten die Indexe
> als volatile definiert werden, damit sie der AVR-GCC nicht wegoptimiert.
> Dies würde aber in den Interrupts besonders weh tun, da es mehr Code
> bedeutet.
> Daher werden nur die Zugriffe in den main-Funktionen als volatile
> gecastet (per Macro in meiner mydefs.h).

Ja, volatile in einer ISR ist nicht toll. Eine Alternative zum 
volatile-Cast ist eine Barrier... nicht unbedingt hübscher, aber eben 
eine weitere Möglichkeit.
1
__asm volatile ("":::"memory");
Das sagt gcc, dass sich der Inhalt des Speichers möglicherweise geändert 
hat, und entsprechende REG-Inhalte nicht mehr verwendbar sind. Eine 
Barrier am Anfang der main-Loop erspart mir volatile und Casterei. Da 
ich wie gasagt keine Poll-Schleifen verwende, reicht diese eine Barrier, 
egal wieviele Werte in einer ISR manipuliert werden.

von Peter D. (peda)


Lesenswert?

Georg johann Lay wrote:

> Zwei FIFOs brauchts in der genannten Anwendung für den UART, eine
> weitere brauch ich für Timer1. Timer1 muss einerseite per Auftrag ne
> HW-PWM erzeugen können, aber auch eine Zeitmessung (Kapazitätsmessung an
> einer LED zur Helligkeitsmessung) via InCapture.

Ich habe eine ähnliche Anwendung, Temperaturregelung mittels STM160 am 
ICP, und Heiztransistor am OC1B (OC1A geht ja nicht zusammen mit ICP).

Allerdings verwende ich da keinerlei FIFO.
Der ICP-Interrupt macht die Puls/Periodenmessung und wenn der Regler den 
Wert nicht ausliest, wird er einfach mit der neuen Messung 
überschrieben.
Ein FIFO wäre da nur hinderlich, ich will ja den möglichst aktuellsten 
Meßwert und nicht irgendwelche uralten, sonst spinnt die Regelung.
Ich verwende sehr gerne diesen Overwrite Modus zur Parameterübergabe, 
dann brauche ich mich nicht um nen Pufferüberlauf zu kümmern.


Man könnte natürlich universelle Macros zum Erzeugen einer FIFO 
schreiben aber ich wollte das Beispiel nicht zu kompliziert machen.
Man hätte dann ganz schön rumbasteln müssen, um die Unterschiede 
zwischen dem Empfangs- und dem Sende-FIFO irgendwie zu lösen. Das wäre 
dann erheblich auf Kosten der Lesbarkeit gegangen.

Insbesondere in Zusammenhang mit Interrupts versuche ich den Code 
einfach zu halten, da dabei schnell Fehler passieren können.
Wenn man also den Interruptcode kurz hält, kann man gut sehen, was er 
bewirken könnte, wenn er an jeder Stelle des Main zuschlägt.
Mit irgendwelchen großen Macros oder Unterfunktionen darin, geht diese 
Übersicht verloren. Da hilft dann nur noch rohe Gewalt (cli/sei an jeder 
möglichen Stelle).


> Ja, volatile in einer ISR ist nicht toll. Eine Alternative zum
> volatile-Cast ist eine Barrier... nicht unbedingt hübscher, aber eben
> eine weitere Möglichkeit.
>
1
> __asm volatile ("":::"memory");
2
>

Kannte ich bisher noch nicht.
Dürfte aber das Kind mit dem Bade ausschütten, d.h. sämtliche Variablen 
betreffen, nicht nur die von Interrupts geänderten.
Da ist das Casten also zielgenauer.


Peter

von Rudi (Gast)


Lesenswert?

Hallo Peter,
Vorerst einmal Danke für das geniale Prog.
Benutze WinAVR-20081205 mit AVR-Studio.
Folgendes Problem. Das Program läuft einwandfrei wenn ich die 
Optimierung abschalte, sobald ich aber mit -Os optimiere werden mir die 
volatile gecasteten Variablen wegoptimiert...
Vielleich wer eine Ahnung warum das so ist?
Ich hab jetzt die "Interrupt" Variablen fix als volatile deklariert. 
Dann funktioniert es auch mit der Optimierung.
Was ich nicht verstehe, warum soll der Code bei fixer volatile 
Deklaration größer werden als bei gecastetem volatile?

Dank
lg
Rudi

von gast (Gast)


Lesenswert?

Frage, muss man hier nicht die Interrupts sperren?
1
void uputchar0( u8 c )
2
{
3
  u8 i = tx_in;
4
5
  ROLLOVER( i, TX0_SIZE );
6
7
==>   UTX0_IEN = 0;                         // disable TX interrupt ???
8
                                        // wieso braucht man das hier nicht?
9
10
  tx_buff[tx_in] = c;
11
  while( i == vu8(tx_out));    // until at least one byte free
12
          // tx_out modified by interrupt !
13
  tx_in = i;
14
  UTX0_IEN = 1;                         // enable TX interrupt
15
}

von Peter D. (peda)


Lesenswert?

gast wrote:
> Frage, muss man hier nicht die Interrupts sperren?

Nein, weil erst hier der Interrupt den neuen Index bekommt und damit das 
neue Zeichen senden kann:
1
  tx_in = i;
Und das ist eine atomare Instruktion, da 8-bittig.

Außerdem würde die Sperre an der von Dir vorgeschlagenen Stelle einen 
Deadlock bedeuten, da dann der Interrupt nie den Puffer freigeben kann.


Peter

P.S.:
Da der FIFO prinzipiell immer ein Byte freilassen muß, darf man das neue 
Byte schon vorher reinschreiben.

von gast (Gast)


Lesenswert?

Wenn nicht 8-bittig müsste man das aber machen oder? Wieso Deadlock 
verstehe ich nicht sorry.

von Stefan E. (sternst)


Lesenswert?

gast wrote:
> Wieso Deadlock verstehe ich nicht sorry.

Weil bei vollem Puffer in der while-Schleife gewartet wird, bis wieder 
Platz ist. Aber wie soll Platz frei werden, wenn zu diesem Zeitpunkt der 
TX-Interrupt ausgeschaltet ist?

von Gerd E. (robberknight)


Angehängte Dateien:

Lesenswert?

Hallo,

vielen Dank für den Code, damit hatte ich ratzfatz die serielle 
Schnittstelle angebunden.

Ich hab etwas in dieser Art versucht (naja, in Realität nicht ganz so 
schlimm):
1
...
2
uputs0("Ich schreibe einen Roman und der ist laaaaaaaang...");
3
...

Der Compiler hat dann beim Optimieren das uputchar0 genommen und in die 
Schleife vom uputs0 mit reingepackt (hab ich im Assembler gesehen) - 
soweit Ok. Jetzt hat er aber in dieser Schleife das tx_in in einem 
Register gespeichert. Da das nicht volatile deklariert ist, war das 
vollkommen legal. Nachteil ist allerdings, daß dann dieser Code im 
uputchar0 nur noch das Register verändert:
1
tx_in = i;

Dann kommt der Interrupt:
1
ISR( USART0_UDRE_vect )
2
{
3
  if( tx_in == tx_out ){    // nothing to sent
4
    UTX0_IEN = 0;      // disable TX interrupt
5
    return;
6
  }
7
...

und schaltet sich wieder ab - er kann von den neuen Daten nix 
mitbekommen, denn er weiß ja nix von dem Register. Irgendwann ist dann 
der Puffer voll und das while im uputchar0 wird zur Endlosschleife.

Der Fix sieht so aus, daß man den Schreibzugriff auf das tx_in im 
uputchar0 volatile machen muss:
1
...
2
  vu8(tx_in) = i
3
...

Das gilt genauso für den Schreibzugriff (ROLLOVER) auf rx_out im 
ugetchar0.

Außerdem verbraucht mein "Roman" aus dem Beispiel oben wertvolles SRAM. 
Ich hab daher noch eine kleine Funktion gebaut, die den Text direkt aus 
dem Flash liest:
1
uputs0_pgm_P("Ich schreibe einen Roman und der ist laaaaaaaang...");

Durch ein Makro wird der Text automatisch in den Flash gelegt. Wenn man 
die Daten schon im Flash hat gehts so:
1
unsigned char longtext[] PROGMEM = "dies ist ein langer Text";
2
3
void printtext(void)
4
{
5
    uputs0_pgm((PGM_P)longtext);
6
}

Beide Änderungen hab ich in einen Patch gepackt und diesem Beitrag 
angehängt.

von Stephan M. (muphin)


Lesenswert?

Vielen vielen dank für den Code! Das erleichtert einem das Programmieren 
einer UART ja wesentlich!

Was ich bisher nicht ganz verstehe is das Stückchen hier im uart Header:
usable: RX0_SIZE + 2 (4 .. 258)

Die Begrenzung auf 256 is klar, aber wieso dann das "+2"?

von Rene B. (themason) Benutzerseite


Lesenswert?

@peter

ich habe mal generell eine frage zum thema FIFO und atomare operationen.
ich habe meine fifos bisher immer so gestaltet das ich neben dem 
schreib/lese-index noch einen differenzindex benutze. dieser dient als 
generelle abfrage dafür ob ich zeichen in meinem puffer habe oder nicht 
(um mir die abfrage schreib-leseindex ist gleich zu sparen). wenn dieser 
als byte ausgeführt wird müsste es ja dennoch möglich sein im 
hauptprogramm atomare zugriffe zu gewährleisten, oder ?

beispiel :

volatile char rptr = 0; // read pointer
volatile char wptr = 0; // write pointer
volatile char diff = 0; // diff pointer
volatile char data [100];


isr (irgendwas)
{
  if (diff < 100)
  {
    diff++;
    wptr++;
    if (wptr > 100) { wptr = 0; } // rollover
    data [wptr] = int_data_register;
  }
}

char fifo_read (void)
{
  if (diff > 0)
  {
    diff --;
    rptr ++;
    if (rptr > 100) { rptr = 0; } // rollover
    return data [rptr];
  }
  return 0;
}

meine frage ist nun : kann es zu kollisionen kommen dadurch das ich 2 
indexe (schreib/differenzindex bzw lese/differenzindex) verwende, oder 
ist lediglich die gewährleistung des atomaren zugriffs auf den 
differenzindex (dadurch das ich eben die ausführung der schreib/lese 
funktionen des FIFOs an die diff-variable koppele) entscheidend ?

von Stefan E. (sternst)


Lesenswert?

Rene Böllhoff schrieb:

> wenn dieser
> als byte ausgeführt wird müsste es ja dennoch möglich sein im
> hauptprogramm atomare zugriffe zu gewährleisten, oder ?

Wieso "dennoch"? Eher "deswegen". Aber nur weil es nur eine 
8-Bit-Variable ist, ist nicht jeder Zugriff automatisch atomar.

>   if (diff > 0)
Das ist ein atomarer Zugriff auf diff (weil nur gelesen wird).

>     diff --;
Dieser ist nicht atomar, und daher problematisch.
Das ist ein Read-Modify-Write-Zugriff. Was wenn zwischen Read und Write 
dein "irgendwas"-Interrupt auftritt?

von Peter D. (peda)


Lesenswert?

Stephan M. schrieb:
> Was ich bisher nicht ganz verstehe is das Stückchen hier im uart Header:
> usable: RX0_SIZE + 2 (4 .. 258)

Der FIFO darf sich nicht einholen, daher Size - 1.
Die UART hat noch einen Empfangspuffer für 3 Byte, also: Size - 1 + 3
Der Sendepuffer ist aber nur 2 Byte, also: Size - 1 + 2


Peter

von Rene B. (themason) Benutzerseite


Lesenswert?

>>     diff --;
>Dieser ist nicht atomar, und daher problematisch.
>Das ist ein Read-Modify-Write-Zugriff. Was wenn zwischen Read und Write
>dein "irgendwas"-Interrupt auftritt?

ok. soweit klar. aber dann müsste bei peters code das makro ROLLOVER in 
der "ugetchar0" ja ebenfalls problematisch sein, da das "++x" im 
ROLLOVER-Makro ja ebenfalls kein atomarer zugriff ist oder vertue ich 
mich da ?!
ich habe mir mit meiner 3-index-lösung eine interrupt-sperre eingebaut, 
aber es ist natürlich unschön jedesmal den interrupt zu sperren.
da mal eine frage (auch auf die gefahr hin das ich nun ge/erschlagen 
werde) :

wenn ich den interrupt global sperre (mit cli) in der funktion dann ein 
interrupt auftritt, und ich den interrupt wieder freigebe, geht mir 
dieser dann verloren oder wird unmittelbar nach freigabe des interrupts 
dieser ausgeführt ?

von Stefan E. (sternst)


Lesenswert?

Rene Böllhoff schrieb:

> ok. soweit klar. aber dann müsste bei peters code das makro ROLLOVER in
> der "ugetchar0" ja ebenfalls problematisch sein, da das "++x" im
> ROLLOVER-Makro ja ebenfalls kein atomarer zugriff ist oder vertue ich
> mich da ?!

Welche negativen Folgen soll der nicht-atomare Zugriff denn dort haben? 
rx_out wird im Interrupt ja nicht verändert (nur gelesen).

von Peter D. (peda)


Lesenswert?

Rene Böllhoff schrieb:
> ok. soweit klar. aber dann müsste bei peters code das makro ROLLOVER in
> der "ugetchar0" ja ebenfalls problematisch sein

Nö, der Interrupt liest zwar den Ausgabeindex, aber er schreibt ihn 
nicht.
Daher kann die Mainfunktion diesen gefahrlos ändern.

Dein "diff" wird jedoch in Main und Interrupt geschrieben.

Deine zusätzliche Variable ist nur dann einen Tick schneller, wenn der 
FIFO leer ist.
Aber sie benötigt deutlich mehr Code.


Peter

von Gerd E. (robberknight)


Lesenswert?

> Die UART hat noch einen Empfangspuffer für 3 Byte, also: Size - 1 + 3
> Der Sendepuffer ist aber nur 2 Byte, also: Size - 1 + 2

Woher hast Du das mit der Größe des Empfangs-/Sendepuffers im UART? Ich 
hab wie blöd im Datenblatt vom meinem atmega168 genau nach dieser Größe 
gesucht und nix gefunden.

von Stefan E. (sternst)


Lesenswert?

Rene Böllhoff schrieb:

> wenn ich den interrupt global sperre (mit cli) in der funktion dann ein
> interrupt auftritt, und ich den interrupt wieder freigebe, geht mir
> dieser dann verloren oder wird unmittelbar nach freigabe des interrupts
> dieser ausgeführt ?

Letzteres.

von Stefan E. (sternst)


Lesenswert?

Gerd E. schrieb:

> Woher hast Du das mit der Größe des Empfangs-/Sendepuffers im UART? Ich
> hab wie blöd im Datenblatt vom meinem atmega168 genau nach dieser Größe
> gesucht und nix gefunden.

Steht normalerweise bei der UDR-Beschreibung.
1
The receive buffer consists of a two level FIFO.
Dazu kommt dann noch das Input-Shift-Register, also 3 Bytes effektiv.

von Rene B. (themason) Benutzerseite


Lesenswert?

>Nö, der Interrupt liest zwar den Ausgabeindex, aber er schreibt ihn
>nicht.

>Dein "diff" wird jedoch in Main und Interrupt geschrieben.

ah ok. da lag der knoten in meinen hirnwindungen. verstanden.
aber mit einer interruptsperre sollte das problem ja dann umschifft 
sein.
ich fand die diff-geschichte recht angenehm da man am diff direkt sehen 
kann wieviel noch im puffer steht, ohne den pufferstand aus dem schreib 
und lese index berechnen zu müssen.

von Gabriel B. (gabriel)


Angehängte Dateien:

Lesenswert?

Hallo Forum,

mich macht folgender Sachverhalt seit 3 Tagen wahnsinnig! Ich habe das 
obige Projekt für meinen UART verwendet (Benutze einen Atmega644 20PU 
mit 14,7456MHz).

Folgendes: Wenn ich das Projekt auf meinen Atmega flashe, sendet dieser 
stetig "A4". Er sendet kein "Hallo Welt" usw. Ich verstehe einfach 
meinen Fehler nicht.

Das Projekt ist soweit unverändert (Dank Peter`s Vorarbeit), trotzdem 
hänge ich dieses nochmal an.

Vielen Dank im voraus
Gabriel

PS.: Wenn ich den Reset-Button drücke, bekomme ich Hex "90 00".

von Tim H. (rettungstim)


Lesenswert?

Hallo zusammen,

ich wollte den Code unverändert Testen mit AVR Studio 4.19.

Ich bekomme aber folgende Fehler:

undefined reference to `init_uart0'
undefined reference to `uputs0_'
undefined reference to `uputs0_'
undefined reference to `ukbhit0'
undefined reference to `ugetchar0'
undefined reference to `uputchar0'
undefined reference to `utx0_ready'
undefined reference to `ukbhit0'
undefined reference to `ukbhit0'
undefined reference to `uputchar0'
undefined reference to `uputchar0'
undefined reference to `uputchar0'
undefined reference to `ugetchar0'
undefined reference to `uputchar0'
undefined reference to `ukbhit0'
collect2.exe: error: ld returned 1 exit status

Kann mir da jemand Helfen wo ich suchen muss?

Grüße
Tim

von Tim H. (rettungstim)


Lesenswert?

Ich habe in einem anderem Thema gelesen, das man auch Groß- und 
Kleinschreibung achten soll.

das war dann auch der Fehler. :-)

von Moritz N. (mox-mox)


Lesenswert?

Hi,
erstmal vielen Dank für die Bibliothek. Ich hab sie vor einem halben 
Jahr in einem Projekt eingesetzt, und sie hat wunderbar funktioniert.
Als ich sie heute jedoch in einem anderen Projekt mit einem AT90PWM3B 
benutzen wollte, habe ich ein Problem festgestellt:
In der Headerdatei steht
1
usart0.h:
2
...
3
#ifndef  UDR0
4
#define  UDR0  UDR
5
#endif
6
...
was ja eigentlich dafür sorgt, dass das richtige Register verwendet 
wird. In der Headerdatei für den AT90PWM3B 
(/usr/avr/include/avr/io90pwm3b.h) steht jedoch:
1
#define UDR _SFR_MEM8(0xC6)
2
#define UDR0 0
3
#define UDR1 1
4
#define UDR2 2
5
#define UDR3 3
6
#define UDR4 4
7
#define UDR5 5
8
#define UDR6 6
9
#define UDR7 7
Somit kann die Auswahl nicht mehr richtig funktionieren.

Als Lösung würde ich vorschlagen, den Namen zu ändern und ihn dann in 
einem konditionalen Define ersetzen zu lassen:
1
usart0.h:
2
...
3
#if (!defined UDR0 | UDR0 == 0)
4
//#ifndef  UDR0
5
#define  UDR0_  UDR
6
#else
7
#define UDR0_ UDR0
8
#endif
9
...
In der Quelldatei müssten dann noch die beiden Vorkommen von UDR0 zu 
UDR0_ geändert werden.

Ich hoffe, dass das jemandem hilft. Vielleicht mag Peter den Vorschlag 
ja sogar übernehmen?
viele Grüße,
mox

von Lirezh (Gast)


Lesenswert?

Aww und ich suche ewig nach dem bug.
volatile in meinen fifos hinzugefügt und schon spielt mein AVR nicht 
mehr verrückt.

von Josef (Gast)


Lesenswert?

Hallo,

darf man die UART-Routine in einem Projekt verwenden, welches unter der 
LGPL veroeffentlicht werden soll?

Viele Gruesse
Josef

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.