Forum: Compiler & IDEs printf bei armgcc


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Tilo (Gast)


Lesenswert?

Hallo

Ich will printf verwenden, um per Uart Daten auszugeben.

Die Datenausgabe mit meiner eigenen Funktion UartWrite() funktioniert 
problemlos.

Leider hat mir google verschiedenste Lösungen angeboten, die alle nicht 
taten.

Ich habe in meinem Hauptprogramm die Funktion int __putchar(int ch) 
definiert. Sie wird allerdings von printf nicht aufgerufen.

Ich habe auch int putchar(int ch) versucht, dann erhalte ich folgende 
Fehlermeldung, die ich gar nicht verstehe:

main.c:9: error: expected identifier or '(' before '--' token
make: *** [main.o] Error 1

Ich habe bisher mit printf etc. noch nicht gearbeitet und stehe ein 
wenig auf dem Schlauch.

Wer weiß, wo mein Fehler liegt bzw. wo ich Hilfe finden könnte?

Vielen Dank,

Tilo

von Teplotaxl X. (t3plot4x1)


Lesenswert?

Da ich bedauerlicherweise nicht über eine Glaskugel verfüge, kann ich 
dir auch nicht weiterhelfen. Zeig doch bitte mal den ganzen Code her.

von Tilo (Gast)


Lesenswert?

1
#include "ADuC7020.h"
2
#include "uart.h"
3
#include <stdlib.h>
4
#include <stdio.h>
5
6
void IRQ_Function(void);      // IRQ Funktion
7
8
int __putchar(int ch) {
9
  return UartPutChar(ch);
10
}
11
12
int main (void)  {
13
  IRQ = IRQ_Function; // Weise IRQ Funkion zu
14
  UartInit(115200); // Initialisiere Uart mit 115200Baud
15
16
  while (1) {
17
    printf("Hallo printf test.");
18
  }
19
}
20
21
void IRQ_Function (void) {
22
  if (IRQSTA & UART_BIT) { // Uart
23
    UartIrq(); // Zeichen wurde empfangen
24
  }
25
}

Das ist der vollständige Code. Durch den Aufruf von UartPutChar() kann 
direkt ein Zeichen gesendet werden.

von Martin T. (mthomas) (Moderator) Benutzerseite


Lesenswert?

Üblicherweise werden die stdio-Funktionen der newlib, die in den meisten 
Packeten mit arm-elf/eabi-gcc die libc ist, per sogen. syscalls mit der 
Hardware verbunden. Vgl. newlib Dokumentation, Implementierungsbeispiel 
z.B. newlib-lpc.

von Tilo (Gast)


Angehängte Dateien:

Lesenswert?

Danke für den Hinweis!

Ich habe mir die newlib-lpc angeschaut. Für jemanden, der die newlib 
noch nie verwendet hat, ist das erst einmal ein ganz schöner Brocken. 
Ich habe auch einiges an Dokumentation gefunden, nur die geht meist 
davon aus, dass man schon weiß, wo man hin will.

Ich habe mal die newlib-lpc angehängt. Ich habe mich am Beispiel test3.c 
orientiert.
1
  /**** Device table.  List of device drivers for newlib.  ****/
2
const struct device_table_entry *device_table[] = {
3
  &com1,  /* stdin  */
4
  &com1,  /* stdout */
5
  &com1,  /* stderr */
6
  0 };  /* end of list */

Es wird ein Array (Array aus Pointern) *device_table mit 4 Einträgen vom 
Typ device_table_entry erzeugt. "com1" ist in der uart0_int.c definiert. 
Dort sind die einzelnen Funktionen hinterlegt. device_table_entry ist in 
dev_cntrl.h hinterlegt. Soweit habe ich auch verstanden, wie die 
einzelnen Codeteile zusammenhängen.

Ein paar Dinge sind mir aber noch unklar:

1. Wo klinkt sich die newlib ein? Erwartet newlib, dass es ein Array mit 
dem Namen *device_table gibt?

2. Der Eintrag in die Tabelle für den uart sieht in uart0_int.c so aus:
1
/************************** com1_int ************************************/
2
/*  Device table entry used to add this device.        */
3
const struct device_table_entry com1_int = {
4
  "com1",        /*  Device name.    */
5
  uart0_open,        /*  Open method.    */
6
  uart0_close,      /*  Close method.    */
7
  uart0_read,      /*  Read method.    */
8
  uart0_write,      /*  Write method.    */
9
  uart0_ioctl,      /*  Ioctl method.    */
10
  0 };        /*  No per-instance data.  */
1
static _ssize_t uart0_write (
2
    struct _reent *r,      /*  Re-entrancy structure, used to make  */
3
        /* thread safe.        */
4
    int file,       /*  File handle.  Used to distinguish  */
5
        /* multiple instances.      */
6
    const void *ptr,    /*  Pointer to data to write.    */
7
    size_t len,      /*  Amount of data to write.    */
8
    SUB_DEVICE_INFO *info)  /*  Per instance information, only one  */
9
            /* instance so not used.    */
10
{
11
[...]

In den Kommentaren zu dieser Funktion ist als Datentyp immer von "Byte" 
die Rede. Wo ist das festgelegt? Könnte als Datentyp nicht auch short 
oder long von der newlib verwendet werden?


3. In diesem Beispiel wird stdin, stdout und stderr auf "com1" gelegt. 
Gehen wir davon aus, ich will zusätzlich ein Device per SPI ansprechen:
1
  /**** Device table.  List of device drivers for newlib.  ****/
2
const struct device_table_entry *device_table[] = {
3
  &com1,  /* stdin  */
4
  &com1,  /* stdout */
5
  &com1,  /* stderr */
6
        &spi1,
7
  0 };  /* end of list */

Wie kann die Ausgabe von newlib von stdout auf spi1 umgebogen werden?

Vielen Dank,

Tilo

von mthomas (Gast)


Lesenswert?

zu 1: Die Implementierung der syscalls in newlib-lpc "erwart" ein Array 
um zum hander die passenden Funktionen zu suchen. newlib-lpc (oder 
libsysbase von devkitpro) bietet wahrscheinlich schon ein paar mehr 
Möglichkeiten als benötigt. Man kann write etc. auch einfacher 
implementierung v.a. wenn man nur stdio/printf nur dazu verwenden will 
ein paar Ausgaben auf einen uart umzuleiten. Vgl. z.B. den Code zu 
"uVision+Codesourcery" von keil.com oder ein paar meiner Bespiele auf 
www.siwawi.arubi.uni-kl.de/avr_projects/arm_projects

zu 2: verstehe die Frage wahrscheinlich nicht wirklich. Die syscalls 
fuer stdio-support sind dazu gedacht, einen Bytestream 
auszugeben/einzulesen.

zu 3: ja, "umbiegen" von stdout auf SPI (oder was auch immer) 
funktioniert im Prinzip - habe das aber nie selbst ausprobiert. 
Interface der Hardwarefunktionen fuer SPI-Ausgabe analog dem für UART 
implementieren und Adressen in einer device_table_entry structure 
eintragen.

von Tilo (Gast)


Lesenswert?

zu 1:
Ich hab schon funktionierende Funktioenen. Wie geschrieben, ich würde es 
jetzt gerne mal mit schon vorhandenen Libraries versuchen

zu 2:
OK, das wollte ich wissen. Hätte ja sein können, dass z.B. ein 
Short-Stream zugelassen ist.

Nochmals Danke für deine Hilfe!

Tilo

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.