Forum: Mikrocontroller und Digitale Elektronik UART auf ATmega644P


von Alram L. (alram)


Lesenswert?

Hallo,

Eine Info gleich vorab: Ich bin erfahrener Programmierer (Java und etwas 
C) aber Einsteiger im Bereich Mikrocontrollerprogrammierung.
Für ein kleines Projekt im Heimbereich hab ich mir das Pollin AVR-Net-IO 
Board zugelegt. Die ersten Programmierungen mit dem Board (Firmware von 
Ulrich Radig) liefen eigentlich recht erfolgreich. Webserver, UART etc. 
hab ich schon viel umgesetzt.
Nach kurzer Zeit hab ich dann auch festgestellt, dass ein zweiter UART 
nicht schlecht wäre. Daher habe ich den ATmega32 gegen einen ATmega644P 
getauscht. Da auch recht viel mit UART gearbeitet wird, habe ich auch 
gleich den Quarz von 16MHz auf 18,432 MHz gewechselt. Ansonsten ist das 
Board aber unverändert geblieben.

Nun zu meinem Problem, wo ich euch um etwas Hilfe bitte: Ich verwende 
beide UARTS mit einem MAX232. Irgendwann nach dem Umstieg auf den 
ATmega664P habe ich festgestellt, dass der Controller unregelmäßig 
resetet oder in er Loop wilde Zeichen auf der Konsole ausgibt. Eine Zeit 
lang dachte ich einfach nur an Programmierfehler, letztendlich konnte 
ich aber keine mehr ausmachen. Daher hab ich versucht das Problem 
einzugrenzen und habe schrittweise alles an Code entfernt. Übrig 
geblieben ist nur folgende main.c:
1
#include <avr/interrupt.h>
2
#include "config.h"
3
4
void usart_write_char(const char c)
5
{
6
  while( (UCSRA & (1<<UDRE)) == 0);
7
  UDR = c;
8
}
9
10
ISR (USART_RXC_vect)
11
{
12
  puffer = UDR;
13
}
14
15
void printit(void)
16
{
17
  if (puffer != 0)
18
  {
19
    usart_write_char(puffer);
20
    puffer = 0;
21
  }
22
}
23
24
int main(void)
25
{  
26
  // UART initialisieren:
27
  uint16_t baud = F_CPU / (BAUDRATE * 16L) - 1;
28
  UBRRH = (uint8_t) (baud >> 8);
29
  UBRRL = (uint8_t) baud;
30
  UCSRB = (1 << TXEN | 0 << RXEN | 0 << RXCIE);
31
32
  char bootmsg[] = "****** System Ready *******\n\r";  
33
  for(int i=0; i<29; i++)
34
    usart_write_char(bootmsg[i]);
35
  // Buffer init:
36
  puffer = 0;
37
  sei();
38
  while(1)
39
  {
40
    printit();
41
  }
42
}

die config.h sieht auch nicht recht spektakulär aus:
1
  #define _CONFIG_H_  
2
  
3
  //Taktfrequenz
4
    // #define F_CPU 16000000UL
5
  #define F_CPU 18432000UL
6
  
7
  #define BAUDRATE 9600
8
  
9
  // UART Inputpuffer
10
  volatile char puffer;
11
12
  #if defined (__AVR_ATmega644__) || defined (__AVR_ATmega644P__)
13
    #define UCSRA UCSR0A
14
    #define UCSRB UCSR0B
15
    #define UBRRL UBRR0L
16
    #define UBRRH UBRR0H
17
    #define TXEN TXEN0
18
    #define RXEN RXEN0
19
    #define RXCIE RXCIE0
20
    #define UDR UDR0
21
    #define UDRE UDRE0
22
    #define USART_RXC_vect USART0_RX_vect
23
  #endif

Mein Problem ist nun: Der UART0 hängt über den MAX232 vom Board an einem 
USB2Serial Adapter am PC. Am PC habe ich Putty auf den entsprechenden 
Com Port göffnet. Sofort nach dem programmieren erhalte ich 
Erwartungsgemäß die Meldung "System Ready" im Putty.

Aber: Sobald ich in der Putty Sitzung ein paar Zeichen eingebe resetet 
der Controller. Wenn ich auf einer beliebigen Taste drauf bleibe, 
resetet er alle paar Sekunden. Und das unabhängig davon, ob diese Code 
Zeile
1
UCSRB = (1 << TXEN | 0 << RXEN | 0 << RXCIE);
oder so
1
UCSRB = (1 << TXEN | 1 << RXEN | 1 << RXCIE);
aussieht. Bei zweiterer werden die Empfangenen Zeichen korrekt wieder 
ausgegeben (Echo); Aber der Controller resetiert trotzdem.

Setze ich anstatt dem ATmega644P den originalen ATmega32 ein, 
funktioniert es einwandfrei. Ohne Probleme. Getestet bei beiden 
Prozessoren mit 16MHz und 18,324 MHz Quarz. Habs auch mit 3 
verschiedenen USB2RS232 Convertern probiert.

Jetzt meine Frage an euch: Hab ich hier einen defekten ATmega644P oder 
ist der UART an diesem anders zu programmieren als am ATmega32? Diese 
Fehler hat mich nun schon ziemlich viel Zeit gekostet und jetzt bin ich 
am Ende meiner Weisheit.
Meine Hausaufgaben (Google, Datenblatt, Tutorial, ...) habe ich alle 
schon mehrfach gesichtet. Finde aber nichts brauchbares mehr.
Kann das mit den Fuses zusammenhängen? Alles betreffend der Taktung kann 
ja eher ausgeschlossen werden - die Ausgabe auf dem UART funktioniert 
tadellos. Der UART1 weist dieses Verhalten nicht auf. Nur der UART0 
macht hier Probleme.

Wenn ich obige main wie folgt umbaue (den Inhalt der printit in die 
main-loop direkt eintragen):
1
#include <avr/interrupt.h>
2
#include "config.h"
3
4
void usart_write_char(const char c)
5
{
6
  while( (UCSRA & (1<<UDRE)) == 0);
7
  UDR = c;
8
}
9
10
ISR (USART_RXC_vect)
11
{
12
  puffer = UDR;
13
}
14
15
int main(void)
16
{  
17
  // UART initialisieren:
18
  uint16_t baud = F_CPU / (BAUDRATE * 16L) - 1;
19
  UBRRH = (uint8_t) (baud >> 8);
20
  UBRRL = (uint8_t) baud;
21
  UCSRB = (1 << TXEN | 1 << RXEN | 1 << RXCIE);
22
23
  char bootmsg[] = "****** System Ready *******\n\r";  
24
  for(int i=0; i<29; i++)
25
    usart_write_char(bootmsg[i]);
26
  // Buffer init:
27
  puffer = 0;
28
  sei();
29
  while(1)
30
  {
31
    if (puffer != 0)
32
    {
33
      usart_write_char(puffer);
34
      puffer = 0;
35
    }
36
    }
37
}
dann funktioniert es auch am ATmega644P. Allerdings, sobald ein 
Funktionsaufruf in der main-loop enthalten ist (das kann auch eine 
andere, leere Funktion sein), ist die Sache vorbei soabld Zeichen am 
UART0 eintrudeln. Sieht so aus, als verwürfelt dann irgendetwas den 
Stack ...

Danke im Voraus für eure Hilfe & Tips!

vG Alram

von holger (Gast)


Lesenswert?

Übersetz du das Programm auch für einen ATMEGA644P oder
brutzelst du da die HEX Datei vom ATMEGA32 rein? Das geht nicht.

von Alram L. (alram)


Lesenswert?

natürlich wird das Projekt auch für den jeweiligen Controller übersetzt.

von holger (Gast)


Lesenswert?

>natürlich wird das Projekt auch für den jeweiligen Controller übersetzt.

Und im Programmierdialog hast du auch die entsprechende
HEX Datei ausgewählt?

von sebastan (Gast)


Lesenswert?

Irgend ein elektrisches Problem? (Pull Up am Reset-Pin vergessen, und 
weil der UART0 da näher dran liegt kommt die Störung da an, aber nicht 
wenn du was mit dem UART1 machst, ... oder so ...)

von holger (Gast)


Lesenswert?

>natürlich wird das Projekt auch für den jeweiligen Controller übersetzt.

Der ATMEGA644P kennt aber kein UDR. UDR0 und UDR1 kennt er.
Ich frag mich auch wo puffer deklariert ist.

Ich denke es wird Zeit für vollständigen Code.
Irgendwas was man mal durch den Compiler jagen kann.

von sebastan (Gast)


Lesenswert?

> Der ATMEGA644P kennt aber kein UDR.
Guck mal in den Config Header. Ist schon im ersten Post.

von holger (Gast)


Lesenswert?

>> Der ATMEGA644P kennt aber kein UDR.
>Guck mal in den Config Header. Ist schon im ersten Post.

Verdammt;) Danke, übersehen.

von Alram L. (alram)


Lesenswert?

Hi,

elektrische Probleme hab ich eigentlich ausgeschlossen, da ja der 
ATmega32 im  gleichen im Sockel des Boards bestens funktioniert ... der 
uart0 ist auch zur gänze auf der platine des boards. der uart1 ist mit 
kabeln auf einem externen steckbrett angeschlossen und der funktioniert 
ja bestens.

der UART0 des 664P funktioniert ja auch, bis man eben bspw. den code der 
main loop in eine funktion auslagert. (siehe printit)

vG Alram

von Alram L. (alram)


Lesenswert?

holger schrieb:
> ammierdialog hast du auch die entsprechende
> HEX Datei ausg

ich stelle im projekt (atmel studio) das device um und drücke F5. wenn 
ich da den falschen device hab, meldet er mir das ziemlich schnell.
ich hab ja bereits den kompletten webserver und telnetserver erfolgreich 
am laufen gehabt. ich denke, das hätte wohl nicht funktioniert, wenn ich 
das falsche binary in den atmega644p geschossen hätte. ;)

leider hab ich keinen zweiten 644p zum testen da.

von Kaj (Gast)


Lesenswert?

Alram Lechner schrieb:
> der UART0 des 664P funktioniert ja auch, bis man eben bspw. den code der
> main loop in eine funktion auslagert. (siehe printit)

Alram Lechner schrieb:
> void printit(void)
> {
>   if (puffer != 0)
>   {
>     usart_write_char(puffer);
>     puffer = 0;
>   }
> }

Wo ist puffer definiert? Nicht in der funktion und wird auch nicht 
übergeben... glaubst du das das eine gute idee ist? nur mal so am 
rande...

Grüße

von sebastan (Gast)


Lesenswert?

> Wo ist puffer definiert?
Auch im Config header. Nicht schön, sollte aber tun.


Nächste Idee: Hast du schonmal versucht, einen Breakpoint auf den R 
Reset-Vektor zu setzen? Keine Ahnung, ob das was bringt, oder ob da 
schon alle Information verloren ist.

von sebastian (Gast)


Lesenswert?

Jetzt fang ich schon an zu stottern... Das R ist natürlich zu viel.

von Alram L. (alram)


Lesenswert?

Kaj schrieb:
> Wo ist puffer definiert? Nicht in der funktion und wird auch nicht

in der config.h

> übergeben... glaubst du das das eine gute idee ist? nur mal so am
> rande...

ich möchte hier nicht um den Sinn des gezeigten Problems disktuieren! 
den Code habe ich geschrieben, um mit möglichst wenig Zeilen, 
übersichtlich mein Problem darzustellen. Weil funktionieren müsste es ja 
so, oder? (OK: theoretisch können Zeichen verloren gehen - aber das ist 
ja nicht mein Problem)

Den Fehler hab ich festgestellt, während ich mittels UDP Paketen Befehle 
an den NetIo gesendet und damit am UART0 Befehle ausgelöst habe; Dort 
hängt dann mein Receiver dran, der Antworten sendet. Und immer bei 
Empfang einer Antwort, resetierte sich der Controler. Auf dem Weg das 
Problem einzugrenzen, bin ich bei den obigen Code-Zeilen gelandet.

vG Alram

von Alram L. (alram)


Lesenswert?

sebastan schrieb:
> Hast du schonmal versucht, einen Breakpoint auf den R
> Reset-Vektor zu setzen?

hab nur den AVRISP mkII - da ist nix mit debuggen, oder?

von sebastian (Gast)


Lesenswert?

> hab nur den AVRISP mkII - da ist nix mit debuggen, oder?
Stimmt. Außer du kannst den Fehler im Simulator reproduzieren. Kann dir 
aber nicht sagen, wie man UART-Input simuliert.

von holger (Gast)


Angehängte Dateien:

Lesenswert?

Probier mal die HEX Datei im Anhang.

von holger (Gast)


Angehängte Dateien:

Lesenswert?

>Probier mal die HEX Datei im Anhang.

Und jetzt die.

von Alram L. (alram)


Lesenswert?

holger schrieb:
> Probier mal die HEX Datei im Anhang.

da kommt "Test" beim UART0 raus.
kein tastaturecho;
aber auch kein reset; auch wenn ich länger auf einer taste bleibe ...

wie sieht der source dazu aus?

von Alram L. (alram)


Lesenswert?

holger schrieb:
>>Probier mal die HEX Datei im Anhang.
>
> Und jetzt die.

die gibt "****** System Ready *******" aus und resetiert regelmäßig, 
solange ich auf einer taste bleibe ...

von Volker (Gast)


Lesenswert?

Wie ist denn das Low-Byte Fuse gesetzt?

von holger (Gast)


Angehängte Dateien:

Lesenswert?

>> Probier mal die HEX Datei im Anhang.
>
>da kommt "Test" beim UART0 raus.
>kein tastaturecho;

Son Mist da fehlte ein sei()

So, nochmal wenn du magst.

Bei mir schmiert das so nicht ab.

von holger (Gast)


Angehängte Dateien:

Lesenswert?

Und nochmal dein Programm, das schmiert bei mir auch nicht ab.
Allerdings hab ich das auch nur mit 16MHz laufen lassen.

von holger (Gast)


Lesenswert?

Und wenn man sich deine erste Version aus deinem Post
genauer ansieht hätte eine Eingabe gar nicht funktionieren
dürfen.

  UCSRB = (1 << TXEN | 0 << RXEN | 0 << RXCIE);

RXEN aus, RXCIE aus. Eingabe nicht möglich.

von Alram L. (alram)


Lesenswert?

holger schrieb:
> Und nochmal dein Programm, das schmiert bei mir auch nicht ab.
> Allerdings hab ich das auch nur mit 16MHz laufen lassen.
guten morgen,

das scheint zu funktionieren.  es kommt die "****** System Ready 
*******" meldung und alle eingaben kommen als echo zurück. ohne reset.

das schaffe ich nur, wenn die mainloop so aussieht:
1
while(1)
2
{
3
  if (puffer != 0)
4
  {
5
    usart_write_char(puffer);
6
    puffer = 0;
7
  }
8
}

sobald ich den inhalt in die printit() funktion auslagere, resetet er. 
wie sieht dein code zu dem hex aus?

danke nochmals für deine bemühungen!

vG Alram

von Alram L. (alram)


Lesenswert?

holger schrieb:
> Und wenn man sich deine erste Version aus deinem Post
> genauer ansieht hätte eine Eingabe gar nicht funktionieren
> dürfen.
>
>   UCSRB = (1 << TXEN | 0 << RXEN | 0 << RXCIE);
>
> RXEN aus, RXCIE aus. Eingabe nicht möglich.

korrekt. das echo der zeichen hat auch nicht funktioniert. resetieren 
tut der controller aber schon.

daher hab ich im ersten post auch explizit auf diese zeile hingewiesen.

vG Alram

von Alram L. (alram)


Lesenswert?

Volker schrieb:
> Wie ist denn das Low-Byte Fuse gesetzt?

sorry - hab ich erst jetzt gelesen:

low: 0xFF
high: 0xDF
extended: 0xFF

kann es mit den fuses zusammenhängen?

von Ernst O. (ernstj)


Lesenswert?

Hallo Leute, ich habe erst vor drei Wochen angefangen, mich mit C zu 
befassen. Meine Wortmeldung hier ist daher vielleicht verfrüht, vorlaut 
sein will ich auch nicht.

Mir ist aufgefallen, dass in der config.h folgender Passus steht:

Alram Lechner schrieb:
> #if defined (_AVR_ATmega644_) || defined (_AVR_ATmega644P_)
>     #define UCSRA UCSR0A
>     #define UCSRB UCSR0B
>     #define UBRRL UBRR0L... usw.

Ich hätte da anstatt des "#if defined" ein "#ifndef" erwartet, um 
Doppeldeklarationen zu vermeiden, die angeblich zu unverstehbaren 
Effekten führen sollen.

von Karl H. (kbuchegg)


Lesenswert?

ernst oellers schrieb:

> Alram Lechner schrieb:
>> #if defined (_AVR_ATmega644_) || defined (_AVR_ATmega644P_)
>>     #define UCSRA UCSR0A
>>     #define UCSRB UCSR0B
>>     #define UBRRL UBRR0L... usw.
>
> Ich hätte da anstatt des "#if defined" ein "#ifndef" erwartet, um
> Doppeldeklarationen zu vermeiden, die angeblich zu unverstehbaren
> Effekten führen sollen.

Das passt schon. Diese Makros werden dem Compiler auf der Command Line 
übergeben und spezifizieren welcher µC-Typ benutzt wird.

> die angeblich zu unverstehbaren
> Effekten führen sollen.

na ja. so unverstehbar ist das jetzt nicht gerade.
Es geht einfach nur darum, dass Atmel, der Himmerl weiß warum, es nicht 
schafft eine einheitliche Nomenklatur für die UART Register quer über 
alle AVR hinzukriegen. Also wird das hier nachgeholt. Die Korrektur ist 
für die beiden Typen 644 und 644P identisch. Mehr steht da nicht.

: Bearbeitet durch User
von holger (Gast)


Angehängte Dateien:

Lesenswert?

So, da bin ich nochmal.

Ich hab dein erstes Beispiel ohne RX Interrupt probiert.
Da gibt es keinen Reset. Dann den Rx mit Interrupt aktiviert.
Kein Reset. Ich hab die Flosse so lange auf der X Taste gelassen
bis das Terminalfenster voll war.

Im Anhang mal die Hex für mit Rx Interrupt.

von Alram L. (alram)


Angehängte Dateien:

Lesenswert?

holger schrieb:
> So, da bin ich nochmal.
>
> Ich hab dein erstes Beispiel ohne RX Interrupt probiert.
> Da gibt es keinen Reset. Dann den Rx mit Interrupt aktiviert.
> Kein Reset. Ich hab die Flosse so lange auf der X Taste gelassen
> bis das Terminalfenster voll war.
>
> Im Anhang mal die Hex für mit Rx Interrupt.

Hallo Holger,

danke für deine Bemühungen - ich weiss das sehr zu schätzen. Ich hab nun 
dein letztes Images geflasht und im Putty einfach nur die x Taste 
gedrückt (und gedrückt gehalten). Das Ergebnis ist im Anhang ...

 :((

also ich denke, ich hab da einen defekten ATmega644P.

Bin gerade dabei einen ATmega1284P (leider im TQFP package) auf eine 
prototyping Platine zu löten und dann testweise mit dem AVR Net IO zu 
verbinden ... mal sehen, ob ich so endlich einmal 2 UARTS gleichzeitig 
zum laufen bekomme.

von Volker (Gast)


Lesenswert?

alram schrieb:
> low: 0xFF

CKSEL3..0 steht also auf low power crystal oscillator?
Würde ich mal auf full swing crystal oscillator setzen.

von holger (Gast)


Lesenswert?

>also ich denke, ich hab da einen defekten ATmega644P.

So schnell geht ein ATMega nicht kaputt.
Das könnte z.B. auch an deiner Spannungsversorgung liegen.

von Alram L. (alram)


Lesenswert?

Volker schrieb:
> alram schrieb:
>> low: 0xFF
>
> CKSEL3..0 steht also auf low power crystal oscillator?
> Würde ich mal auf full swing crystal oscillator setzen.

low steht nun auf 0xF7.

und was ist nun? >> es funktioniert. danke Volker!

wieder einmal wurde bewiesen: immer wenn man glaubt das ding sei defekt, 
sitzt das problem vor dem PC. peinlich

danke an alle, die mitgeholfen haben.

vG Alram

von Ratloser (Gast)


Lesenswert?

Hallo , hast du dein bootloader hexfile noch vom 644P ?

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.