Forum: Mikrocontroller und Digitale Elektronik Immer Ärger mit s(n)printf


von Hermann E. (hermann_e)


Lesenswert?

Erst 'mal "Guten Tag" an alle die wie ich den Brückentag nutzen !

Leider hat mir die freie Zeit die ich heute habe nicht viel gebracht 
weil ich mal wieder mit dem leidigen s(n)printf rumschlage.

Wenn ich im AVR Studio 5.1 folgendes einfache Programm durchsimuliere:


//---------------------------------------------
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>

#define F_CPU       14745600UL
#define UART_BAUD_RATE     9600UL

#define N1_PRESCALER  1024
#if N1_PRESCALER == 1024
#define TIMER1_TOP  (F_CPU/(N1_PRESCALER))-1
#endif

uint8_t volatile FktNr = 0;

//=================== 16Bit timer Timebase ================
void  Init_16Bit_Timebase(void)
{

  TCCR1A = (1<<WGM10) | (1<<WGM11); // Fast PWM, TOP = OCR1A, No OC1A/B 
pin toggled
    TCCR1B = (1<<WGM13) | (1<<WGM12); //to finish settings above

  OCR1A = TIMER1_TOP;
    TIMSK1 |= (1<<TOIE1);         //  Overflow Interrupt Enable

  if(N1_PRESCALER == 1024)
  {
    TCCR1B |= (1<<CS12)|(1<<CS10); // Start Timer with prescaler 1024
  }
  return;
}

//-----------------------------------------------

ISR(TIMER1_OVF_vect) // occurs at first "Top"
{
  char SendBuffer[32];
  static uint32_t TimeInSecs = 0;

  PORTB ^= (1<<PB2);
  TimeInSecs++;

//   snprintf(SendBuffer,31,"R_%d_0_0_#",(int)TimeInSecs);
   sprintf(SendBuffer,"R_%d_0_0_#",(int)TimeInSecs);
   uart_puts(SendBuffer);

}
//==========================================


int  main(void)
{

// =========== Start Timer ===============
  Init_16Bit_Timebase();
//=======================================
  sei();
  DDRB |= (1<<PB2);  // Define Pin B1 as output
  DDRB |= (1<<PB3);  // Define Pin B1 as output

  for(;;)
  {
//    PORTB ^= (1<<PB3);
   } //for

} // main


PS: der Aufruf: "uart_puts(SendBuffer);"
benutzt die von Peter Fleury geschriebene (Standard-) Uart Funktionen
die ich der Einfachheit halber hier nicht mit eingefügt habe

//********************************************************************** 
***


geschehen merkwürdige Dinge: Das Programm resetted ständig, die 
Unterroutine Init_16Bit_Timebase() wird ständig auf's Neue ausgeführt 
obwohl weder ein Watchdog noch das entsprechende Fuse-Bit gesetzt ist.

Richtig interessant wird's im Disassembly wo er in einen File mit dem 
Weg:
"D:\usr\local\avr32studio\hudson\workspace\avr8-gnu-toolchain\src\avr-li 
bc\libc\stdio\vfprintf.c  " springen will. Ich vermute mal das Mr Hudson 
(siehe Path) für Atmel arbeitet aber nicht für mich, jedenfalls 
entspricht der Weg nicht einer existierenden Adresse.

Vermutlich hat's was mit den Compiler bzw. Linker Settings zu tun:

Hier die definierten Settings:

Compiler:
-x c -funsigned-char -funsigned-bitfields -O1 -fpack-struct 
-fshort-enums -g2 -Wall -c -std=gnu99 -MD -MP -MF "$(@:%.o=%.d)" 
-MT"$(@:%.o=%.d)"  -mmcu=($DEVICE)

Linker:
-Wl,-Map="$(OutputFileName).map" -Wl,-lm -Wl,-lprintf_flt -Wl,-lm 
-Wl,-u,vfprintf  -mmcu=($DEVICE) ($MEMORY_SETTINGS)

Last not least: Alles funktioniert wie erwartet wenn ich entweder die 
"s(n)printf" oder die uart_puts(SendBuffer) auskommentiere.

Zugegebenermaßen ziemlich viel auf einmal aber jetzt wurschtle ich schon 
seit Tagen an dem Problem 'rum und habe langsam die Faxen dicke ...

Wäre wirklich prima wenn mir jemand dazu eine Idee hätte !

Danke:  Hermann

von Karl H. (kbuchegg)


Lesenswert?

> Wäre wirklich prima wenn mir jemand dazu eine Idee hätte !

In einer ISR auszugeben ist meistens eine schlechte Idee.
Ganz besonders schlecht ist die Idee allerdings, wenn die 
Ausgabefunktionen darauf angewiesen sind, dass sie per Interrupt ihre 
zwischengespeicherten Daten ausgeben können. Das ist speziell dann ganz 
besonders unangenehm, wenn die uart_puts Funktion die Daten nicht in den 
Buffer stellen kann, weil der Buffer voll ist und darauf wartet, dass 
endlich ein paar Zeichen aus dem Buffer per UART auf die Reise geschickt 
werden. Was aber nie passiert, da in einer ISR die Interrupts gesperrt 
sind.

Fazit: Man macht keine Ausgaben in einer ISR. Ausgaben kommen in die 
Hauptschleife und die ISR signalsiert mit einem Flag der Hauptschleife, 
die Ausgabe vorzunehmen.

von Hermann E. (hermann_e)


Lesenswert?

Danke Karl Heinz,

musste erst 'mal den Familiensegen retten ("du verbringst die ganze Zeit 
hinter deiner blöden Kiste ..."), daher die späte Rückmeldung.

Natürlich hast du recht: ISR's nicht überladen ! Leider hat ein Flag 
(wie von dir empfohlen) das Problem nicht gelöst, Die ISR setzt jetzt 
das Flag und der UART wird jetzt in der "for(;;)"- Schleife aufgerufen 
(und das Flag zurückgesetzt) aber mit dem gleichen Ergebniss. Hab's auch 
nochmals unter dem AVR Studio4 compiliert (und simuliert) ebenfalls mit 
der gleichen Konsequenz.
Zum Mäusemelken ! Hermann

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Hallo Hermann, hast du mal probiert, auf sprintf() ganz zu verzichten?
1
sprintf(SendBuffer,"R_%d_0_0_#",(int)TimeInSecs);
lässt sich ohne größere Verrenkungen auch zu Fuß erledigen.

von Hermann E. (hermann_e)


Lesenswert?

Grüss dich Markus,

wahrscheinlich nicht, ich habe das Programm nur auf's Minimum reduziert 
um das Problem klarzumachen. snprintf wird im eigentlichen Programm 
leider ständig gebraucht.
Langsam habe ich das Gefühl das irgendetwas mit dem Uart-Teil nicht 
stimmt.
Die Library von Fleury nutzt noch die alte "Signal" Syntax die heute 
nicht mehr verwendet werden soll (zugunsten von USART0_TX_vect und 
Konsorten).
Ich habe daher die ISR Headers umgeschrieben ins "Neue" Format, dies hat 
auch bislang gut funktioniert.
Witzigerweise ist auch da ein Fehler im AVR5.1 Studio, für zB 
"USART0_RX_vect" wie im Datenblatt angegeben will er die ISR mit 
"USART0__RX_vect" (2 Underscores vor __RX) für den Atmega234p (in 
"iom324.h" so definiert) sonst sagt er "kenn' ich nich'" !

Ich habe jetzt die Programmabfolge soweit auseinandergedröselt das ich 
sehe wo's hapert: Ganz am Ende vom uart_putc(unsigned char date) (in 
Fleurys Program) sagt mir der Dissembler noch:

000000FB  CALL 0x0000016B    Call subroutine
000000FD  JMP 0x00000A18    Jump
--- No source file 
--------------------------------------------------------
000000FF  JMP 0x00000000    Jump

und springt dann ins Nirwana bzw auf den Anfang. Scheint das die ISR 
Einsprungsadresse für "USART0_RX_vect" irgendwie nicht stimmt, er kommt 
da nämlich nie an (wahrscheinlich mit obig genanntem Problem 
zusammenhängend).

Die Aussage "No source File" weis ich nicht so recht zu interpretieren.

Ich Kompiliers mal mit 'ner anderen CPU um zu sehen ob was mit den Atmel 
Dateien für den Atmega324p nicht stimmt.

-> schon gemacht: Gleiches Problem für den Atmega644

Grüsse:  Hermann

von Hermann E. (hermann_e)


Lesenswert?

wollte sagen:

Scheint das die ISR Einsprungsadresse für "USART0_TX_vect" irgendwie 
nicht stimmt

und nicht: Scheint das die ISR Einsprungsadresse für "USART0_RX_vect" 
irgendwie nicht stimmt...

von Hermann E. (hermann_e)


Lesenswert?

Für alle dies interessiert,

das Problem scheint wirklich in der ATmega324p Bibliothek zu liegen.
Wie schon in einem anderen Thread bemerkt kennt AVR_Studio5.1 den 
Atmega324p nicht (man kann ihn zwar aussuchen aber hinterher jammert der 
Compiler das er die Datei "iom324p.h" nicht findet. Nachdem ich mein 
Programm bis aufs Letzte reduziert habe und dies immer noch aus dem 
Resetten nicht mehr rauskam hab' ich's nochmals als ATmega644 compiliert 
und siehe da: alles funzt und er springt (endlich) auch nicht mehr auf 
den Anfang sondern in die "USART0_TX_vect" ISR !

Also Achtung, die ATmega324 Dateien scheinen fehlerhaft im Studio5.1 !!
Zur Lösung werde ich eben einen ATmega644 einschrauben, was solls, 
lieber 2€ mehr ausgeben als sich zu Tode ärgern.

Hermann

von Hermann E. (hermann_e)


Lesenswert?

Auch auf die Gefahr hin mich nur mit mir selbst zu unterhalten denke ich 
dass ich der Community schuldig bin das Ende der Geschichte zu erzählen:

Nach weiterem Rumfummeln scheint die Lage jetzt klar:

Die UART Datei von Peter Fleury  nutzt noch die alte "SIG_xxx" Syntax in 
den ISR-Routinen. Das Neue AVR Studio 5.1 weiss damit nicht viel 
anzufangen. Da ich wie beschrieben diese Software für mich selbst schon 
in die neue Syntax (wie zb: "USART0_UDRE_vect") umgeschrieben hatte, 
glaubte ich davor geschützt zu sein.

Jetzt kommt das eigentlich Heimtückische:

Für den Atmega324p sind die beiden Vektoren "USART0_RX_vect" und 
"USART0_UDRE_vect" in meinen Augen falsch geschrieben, man muß sie 
nämlich
wie "USART0_RX_vect" und "USART0__UDRE_vect" angeben (doppelter 
Underscore nach dem "USART"). Der AVR ist also in eine nicht vorhandene 
ISR gesprungen
(USART0_UDRE_vect) und hat daraufhin resetted.
Letztlich hat mich mich die geniale "ISR(BADISR_vect){...}" - die nur 
empfehlen kann- auf die Idee gebracht.

Also nochmals: Achtung mit der Fleurischen UART Datei in Kombination mit
AVR Studio5.1

Hermann

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.