printf in Verwendung mit eclipse+gcc für msp430

Gast #425402
Lesenswert?

Hallo Leute,
ich habe folgendes Problem mit Eclipse und dem gcc-Compiler. Ich möchte 
gerne printf benutzen um Text und Zahlen über die serielle Schnittstelle 
meines MSP430 ausgeben.
Leider bekomme ich nicht eindeutige Fehlermeldungen:

msp430-gcc -mmcu=msp430x149 -otest  ./test.o
/cygdrive/c/Programme/mspgcc/bin/../lib/gcc-lib/msp430/3.2.3/../../../.. 
/msp430/lib/msp2/libc.a(printf.o):  In function `printf':
/f/prog/msp430/sf/packaging/build/msp430-libc/src/stdlib/printf.c:39: 
undefined reference to `putchar'
make: *** [test] Error 1

Da ich bis jetzt immer mit einem 8051 gearbeitet habe, ist mir die 
Eclipse Umgebung neu.
Kann es sein das es printf beim gcc nicht gibt? In der stdio.h taucht 
aber ein Eintrag auf, den ich aber nicht verstehe:

int __attribute__((format (printf, 2, 3))) uprintf(int (*func)(int c
),const char *fmt, ...);
int __attribute__((format (printf, 3, 4))) snprintf (char *buf, size_t 
size, const char *fmt, ...);
int __attribute__((format (printf, 2, 3))) sprintf (char *buf, const 
char *fmt, ...);
int __attribute__((format (printf, 1, 2))) printf(const char *string, 
...);
int vuprintf(int (*func)(int c), const char *fmt0, va_list ap);
int vsnprintf(char *dest, size_t maxlen, const char *string, va_list 
ap);
int vsprintf(char *dest, const char *string, va_list ap);
int vprintf(const char *string, va_list ap);


Über jede Hilfe bin ich sehr dankbar.
Persönliche Seite #425405
Lesenswert?

Die Fehlermeldung, auf die es ankommt, ist die hier:

In function `printf':
undefined reference to `putchar'


Das bedeutet, daß die von printf benötigte Funktion "putchar" nicht 
existiert.

Die musst Du zur Verfügung stellen.

printf etc. ist dem Compiler sehr wohl bekannt, nur müssen die Zeichen 
ja auch irgendwohin geschickt werden - und dafür ist die 
putchar-Funktion zuständig. Schreibe eine, die die übergebenen Zeichen 
auf die serielle Schnittstelle ausgibt (die musst Du natürlich vorher 
noch irgendwie initialisieren), und die Linkerfehlermeldung verschwindet 
... und printf funktioniert.
Gast #425410
Lesenswert?

Hallo Rufus,
danke für die schnelle Antwort!
Ich dachte das putchar schon implementiert ist, da in der stdio.h schon 
folgendes steht:

int puts(const char *s);
int putchar(int c);

liege ich da falsch?
Danke.
Gast #425542
Lesenswert?

Okay, ich schiebe in putchar einfach ein Zeichen in den TXBUF.
Ich bekomme aber nur Bruchstücke von meiner Zeichenkette, die ich per 
printf an die serielle Schnittstelle schicke!
Woran liegt das?
#425544
Lesenswert?

> Okay, ich schiebe in putchar einfach ein Zeichen in den TXBUF

Wenn du das wirklich machst, dann überläufst du den TXBUF.
Deine Funktion sollte vielleicht warten, bis dir die Hardware
signalisiert, dass sie bereit ist ein neues Zeichen anzunehmen.

Deine Funktion funktionierte anscheinend doch nicht so supi
(Konnte mir das nicht verkneifen :-)
Gast #425561
Lesenswert?

Okay, ich frage jetzt das Statusbit ab welches meldet das der TX-Puffer 
leer ist.

int putchar(int c)
{
  while(!(UTXIFG0));
  TXBUF0 = c;
  return 0;
}

Klappt aber immernoch nicht! Es kommen nur Bruchstücke der Zeichenkette 
im Hyperterm an.
Hab ich noch 'nen Denkfehler?
#425716
Lesenswert?

Wieso liest du nicht mal die C-Demos von TI? Da steht doch ganz klar 
drin, wie man die UART im Polling betreibt:
Müsste bei dir dann heißen:

int putchar(int c)
{
  while (!(IFG1 & UTXIFG0));                // USART0 TX buffer ready?
  TXBUF0 = (unsigned char)c;
  return 0;
}

Polling ist allerdings ziemlich schlechte Programmierweise, lieber einen 
Buffer anlegen, das erste Zeichen direkt schicken und alle weiteren per 
TX-Interrupt abholen lassen.

Du kommst aus der PC-Programmier-Ecke, oder? Bei µC linkt man 
normalerweise nicht einfach mal so nen riesen Brocken von lib wie die 
stdio dazu. Da ist ja gleich massenhaft an Flash und RAM weg....das kann 
man selber auch viel kürzer schreiben, wenn man nicht alle Funktionen 
braucht.
Gast #425732
Lesenswert?

Hallo Christian!
Ich komme eher aus der Elektronik-Ecke und brauche das printf "nur" zum 
debuggen.
Leider funktioniert die Funktion so wie Du sie gepostet hast auch nicht!
Wie würde ich das denn mit Interrupts lösen?
#425820
Lesenswert?

Wenn das nicht klappt, muss es am printf() liegen. Diese Funktion 
schickt einfach jedes Zeichen, wenn der Buffer frei ist. Da geht nix 
verloren.

Mit INT? Naja, du musst erst alle Zeichen in einen Buffer einsortieren, 
dann das erste schicken, und bei jedem TX-Interrupt ein weiteres, bis 
alle ist.

Das ganze kann man natürlich auch mit einem Ringpuffer machen, aber das 
is bissl aufwendiger.
Gast #425986
Lesenswert?

Das komische ist, wenn ich die selbst geschriebene 
putchar-Funktion(siehe 3 Threads weiter oben) allein teste, also zum 
Beispiel: putchar('X'); dann kommt das X nicht auf dem Hyperterminal an!
Das ist doch sehr komisch oder!?
Hat da noch jemand eine Idee dazu?
Gast #426124
Lesenswert?

Ja, ich benutze einen 8MHz Quarz und das Kabel ist in Ordnung!
Wenn ich mir nämlich ein char-array fest definiere und dieses per 
Tastatureingabe und mit Hilfe von Interrupts ausgebe funktioniert es 
einwandfrei.
Ich habe als Referenz das "echo"-Programm von www.mathar.com genommen 
und auf eclipse+gcc angepasst.
Und wie gesagt, das läuft super mit 115200 BAUD!

Ich bin am verzweifeln! :-(
Gast #426536
Lesenswert?

Also irgendwie funktioniert die Abfrage: while(!(IFG1 & UTXIFG0)); 
nicht!
Die while-Schleife wird nie verlassen. Warum nicht?
Kennt sich nicht irgendjemand damit aus?
Das ist doch eine ganz normale Schleife mit Abfrage!
Der Compiler macht auch keine Fehler.
Gibts da bei eclipse irgendwelche Besonderheiten?

Hiermal meine Initialisierung der UART:

void initUART(void)
{
  P3SEL = 0x30;           // P3.4 und P3.5 als USART0 TXD/RXD
  ME1 |= UTXE0 + URXE0;   // TX- und RX-modul erst mal anschalten
  UCTL0 |= CHAR;          // 8 data bits, 1 stop bit, no parity
  UTCTL0 |= SSEL0;        // ACLK als UCLK festlegen
   UBR00 = 0x45;           // 115200 baud aus 8MHz erzeugen
    UBR10 = 0x00;
    UMCTL0 = 0xAA;
    UCTL0 &= ~SWRST;        // USART freigeben
    IE1 |= URXIE0 +UTXIE0;  // TX- und RX-interrupts anschalten
    IFG1 &= ~UTXIFG0;       // interrupt-flag loeschen
}
Gast #426581
Lesenswert?

Hmmm, zwei Anmerkungen:

ACLK als Taktquelle stimmt wirklich?

Wenn der TX Interrupt aktiv ist, wird das UTXIFG0-Flag automatisch (Ack)
beim Einsprung in die ISR gelöscht - dein Polling kann niemals ein
gesetztes Flag sehen...
Schau mal ins User Manual (SLAU49E.pdf), Seite 277.

Ahoi, Martin
#426596
Lesenswert?

Mit UTCTL0 |= SSEL1; hast du deinen 8Mhz Clock als Takt. Dann klappts 
auch mit den 115,2KBaud. Ist im C-Demo von TI falsch.

Und wie Martin schon sagte, Polling und Interrupt zusammen wird nicht 
klappen. Nur, wenn du das erste Zeichen sendest, nach dem ersten, wird 
die ISR angesprungen und das Flag gelöscht.
#426630
Lesenswert?

Aus dem ACLK bekommst du doch aber keine 115.200 raus. Da musst du schon 
vorher den XT2-Oszillator zuschalten und den SMCLK auf die 8MHz vom 
Quarz legen. Oder den DCO mit dem ACLK füttern, eine passende Frequenz 
einstellen und daraus die Baudrate generieren.

Schau dir mal das C-Demo fet140_uart01_0115k_2.c an.
Gast #426674
Lesenswert?

Mein ACLK läuft auf 8MHz von XT1, damit speise ich den 
Baudratengenerator der mit 115200 BAUD läuft! Warum sollte das nicht 
gehen???

Kann mir jemand sagen, wie ich ohne Interrupts zu benutzen, abfragen 
kann ob der Sende-Puffer schon frei ist?

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