Forum: Mikrocontroller und Digitale Elektronik Verstehe den Reset vom Atmega328P nicht


von Stefan S. (sschultewolter)


Lesenswert?

Hallo,

ich habe gerade ein Problem, dass ich nicht versteh, wieso mein 
Atmega328P (Sparkfun Pro Mini) Probleme bei dem UART hat.

er springt nicht in die while Schleife sondern zuvor neu. F_CPU wurde in 
Projekteigenschaften auf 16000000UL gesetzt.

1
// main.c
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
5
#include <util/delay.h>
6
7
#include <stdio.h>
8
9
#include "uart.h"
10
11
char buffer[64];
12
13
uint16_t getSeed(void)
14
{
15
  uint16_t seed = 0;
16
  uint16_t *p = (uint16_t*) (RAMEND+1);
17
  extern uint16_t __heap_start;
18
  
19
  while(p >= &__heap_start + 1)
20
  seed ^= *(--p);
21
  
22
  return seed;
23
}
24
25
int main(void)
26
{
27
  uart_init();
28
  srand(getSeed());
29
  
30
  sprintf(buffer, "Hallo Welt, Random %d\r\n", rand()%256);
31
  uart_puts(buffer);
32
  DDRB |= 1<<5;
33
  
34
  while (1)
35
  {
36
    _delay_ms(500);
37
    PORTB ^= 1<<5;
38
    sprintf(buffer, "Neues Random %d\r\n", rand()%256);
39
    uart_puts(buffer);
40
  }
41
}

1
//uart.c
2
extern void uart_init(void)
3
{
4
  UBRR0 = UBRR_VALUE;
5
  
6
  #if USE_2X
7
  UCSR0A |= (1 << U2X0);
8
  #else
9
  UCSR0A &= ~(1 << U2X0);
10
  #endif
11
  
12
  // UART Tx, Rx Interrupt, Rx einschalten
13
  UCSR0B |= (1 << TXEN0) | (1 << RXEN0);
14
  // Asynchron 8N1
15
  UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
16
}
17
18
extern void uart_putc(char c)
19
{
20
  while(!(UCSR0A & (1 << UDRE0))) ;
21
  UDR0 = c;
22
}
23
24
extern void uart_puts(char *s)
25
{
26
  while(*s)
27
  {
28
    uart_putc(*s);
29
    s++;
30
  }
31
}

1
//uart.h
2
#ifndef UART_H_
3
#define UART_H_
4
5
#define BAUD        250000
6
7
#include <avr/io.h>
8
#include <util/setbaud.h>
9
10
extern void uart_init(void);
11
12
extern void uart_putc(char c);
13
extern void uart_puts(char *s);
14
15
#endif /* UART_H_ */

Als Ausgabe auf dem Terminal (Putty) erfolgt nur
1
Hallo Welt, Random 241
2
Hallo Welt, Random 252
3
Hallo Welt, Random 241
4
Hallo Welt, Random 252
5
Hallo Welt, Random 241
6
Hallo Welt, Random 252
7
Hallo Welt, Random 241
8
Hallo Welt, Random 252
9
[...]

von Karl H. (kbuchegg)


Lesenswert?

Watchdog per Fuse abgeschaltet?

von Stefan S. (sschultewolter)


Lesenswert?

Entferne ich das delay, geht es genau 12x
1
  while (1)
2
  {
3
    static uint16_t ct = 0;
4
    //_delay_ms(500);
5
    PORTB ^= 1<<5;
6
    sprintf(buffer, "%4d : Neues Random %d\r\n", ct++, rand()%256);
7
    uart_puts(buffer);
8
  }
Ehe es zum Reset kommt.

von Stefan S. (sschultewolter)


Lesenswert?

Hallo Karl-Heinz,

bewusst habe ich an den Fuses nichts geändert. Habe testweise WDTON 
gesetzt und wieder gelöscht. Keine Auswirkung.
1
BODLEVEL = 2V7
2
RSTDISBL = [ ]
3
DWEN = [ ]
4
SPIEN = [X]
5
WDTON = [ ]
6
EESAVE = [X]
7
BOOTSZ = 1024W_3C00
8
BOOTRST = [X]
9
CKDIV8 = [ ]
10
CKOUT = [ ]
11
SUT_CKSEL = EXTXOSC_8MHZ_XX_16KCK_14CK_65MS
12
13
EXTENDED = 0xFD (valid)
14
HIGH = 0xD2 (valid)
15
LOW = 0xFF (valid)

Programmiert wird der Controller über einen Atmel ICE mit ISP Interface.

Habe das ganze nur noch auf ein Blink-Testsketch heruntergebrochen. Hier 
kommt es zum gleichen Fehler. Irgendwas scheint mit dem Controller nicht 
zu stimmen. Doof, der ist bereits auf Platine gelötet, werde aber gleich 
mal einen weiteren besorgen udn testen.

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Stefan S. schrieb:
> Habe das ganze nur noch auf ein Blink-Testsketch heruntergebrochen. Hier
> kommt es zum gleichen Fehler. Irgendwas scheint mit dem Controller nicht
> zu stimmen. Doof, der ist bereits auf Platine gelötet, werde aber gleich
> mal einen weiteren besorgen udn testen.

 Und ohne LED-Blinkerei ?
1
  DDRB |= 1<<5;
2
  
3
  PORTB ^= 1<<5;

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Stefan S. schrieb:
> BOOTSZ = 1024W_3C00
> BOOTRST = [X]

Wenn dein Mega keinen Bootloader ab Adresse 0x3C00 hat, sollte BOOTRST 
nicht gesetzt sein.
Da du über ISP programmierst, ist das auch für weitere Experimente kein 
Problem.

von Dieter F. (Gast)


Lesenswert?

Sparkfun Pro Mini unterstützt den sog. Auto-Reset - kannte ich auch noch 
nicht.

The auto reset feature from arduino boards enables the PC to reset the 
board by toggling the DTR line of the serial connection.

https://cdn.sparkfun.com/assets/0/7/5/5/1/51eec304ce395f104c000000.png

von Joachim (Gast)


Lesenswert?

Dieter F. schrieb:
> Sparkfun Pro Mini unterstützt den sog. Auto-Reset - kannte ich auch noch
> nicht.

Der TE programmiert den uC aber ganz normal per ISP, nicht über den 
Arduino Bootloader. Daher dürfte an der seriellen Schnittstelle des 
Bords nichts angeschlossen sein. Außerdem wäre weiterhin fraglich, warum 
der PC dann das Bord regelmäßig in den Reset ziehen sollte.

Das kann also nicht der Fehler sein.

Gruß Joachim

von Joachim (Gast)


Lesenswert?

Argh.... Überlesen, dass er den UART nutzt. Vergesst meine Einwände.
Dann muss allerdings DTR wenigstens angeschlossen sein. Sollten nur 
RX/TX/GND angeschlossen sein, kann es auch nicht die Ursache sein.

@Stefan

Wie kommuniziert dein Bord per USART mit wem? Kann der Reset per DTR das 
Problem sein?

Gruß Joachim

von Karl H. (kbuchegg)


Lesenswert?

Joachim schrieb:

> Wie kommuniziert dein Bord per USART mit wem? Kann der Reset per DTR das
> Problem sein?

Das lässt sich ja leicht feststellen.
Einfach alle Verbindungen zum PC kappen, inklusive Brenner falls 
vorhanden, und wenn dann das Board aufhört mit dem ständigen Reseten, 
dann wars wohl irgendeine dieser Verbindungen.

von Dieter F. (Gast)


Lesenswert?

Joachim schrieb:
> Der TE programmiert den uC aber ganz normal per ISP, nicht über den
> Arduino Bootloader. Daher dürfte an der seriellen Schnittstelle des
> Bords nichts angeschlossen sein. Außerdem wäre weiterhin fraglich, warum
> der PC dann das Bord regelmäßig in den Reset ziehen sollte.

Es geht nicht um die Programmierung sondern um die serielle 
Kommunikation. Diese funktioniert nur selten ohne serielle Schnittstelle 
:-)

Wenn der TO das passende FTDI-Modul angeschlossen hat (wovon ich 
ausgehe), dann wird die Leitung scheinbar vom Terminal-Programm auf den 
angeschlossenen (Annahme) PC getoggelt - nämlich bei DTR nach dem 
Empfang der ersten Datenladung -> und Reset

von Kirsch (Gast)


Lesenswert?

In Putty mal die Flusssteuerung auf None setzen.

Standard ist aber XON/XOFF, da muss der TE sie schon manuell auf DSR/DTR 
gesetzt haben.

von Stefan F. (Gast)


Lesenswert?

> Es geht nicht um die Programmierung sondern um die
> serielle Kommunikation.

Das sehe ich anders. An den Ausgaben sehen wir, dass der Controller 
scheinbar unerwartet Resetted. Und das könnte durchaus eine andere 
Ursache haben, als die direkten (gewollten) Zugriffe aus den seriellen 
port.

Ich würde mal den Aufruf von getSeed() durch eine konstante Zahl 
ersetzen, um zu sehen, ob dort etwas faul ist.

Als nächstes würde ich prüfen, was passiert, wenn du die Ausgaben via 
uart_puts(buffer); verdoppelst und das Delau auskommentierst. Kommt der 
Reset dann nach 6 Wiederholungen (=12 Ausgaben) oder nach immer noch 
nach 12 Widerholungen (=24 Ausgaben) vor?

von Stefan F. (Gast)


Lesenswert?

Wie schreibst du eigentlich "extern void"?

von Dieter F. (Gast)


Lesenswert?

Stefan U. schrieb:
> Das sehe ich anders.

Ich meinte die Programmierung mit dem ISP ...

Aber: Respekt!

Hast Du das (wie ich gerade) auch ausprobiert

Stefan U. schrieb:
> Ich würde mal den Aufruf von getSeed() durch eine konstante Zahl
> ersetzen, um zu sehen, ob dort etwas faul ist.

oder Kraft Wissens erkannt?

Wenn man das weglässt "resettet" er nicht mehr ...

Ich habe die "extern" weggelassen und alles in ein File gesteckt - mein 
AVR-Studio hat sich hat mit dem Original kräftig rumgemeckert.

von Stefan F. (Gast)


Lesenswert?

extern benutze ich nur für Variablen, die sich in einer andere 
Quelltextdatei befinden. Aber das mache ich nur sehr selten, 
normalerwesie kapsele ich den Zugriff durch getter und setter.

Beispiel (main.c):
1
extern int counter;
2
3
void main() 
4
{
5
  counter++;
6
}

(wasauchimmer.c):
1
int counter;

Ich schätze, du hast den Compiler oder den Linker nicht richtig 
verwendet. Denn ich sehe keinen Grund, warum du "extern" benötigst. Die 
Header Datei macht die Funktionen für den UART bekannt und du hast sie 
ja auch eingebunden.

Schau Dir mal meine Kopiervorlage an, vor allem das Makefile: 
http://stefanfrings.de/avr_hello_world/index.html
Das passt ganz gut zu deiner konkreten Anwendung.

Ich habe dir den Tip mit der seed Funktion gegeben, weil ich nicht 
nachvollziehen kann, was genau diese Funktion eigentlich machen soll. 
Darin befindet sich Pointer-Arithmetik der übelsten Art. Genau wegen 
solchen Konstrukten hassen manche Entwickler die Sprache C.

RAMEND+1 finde ich ganz besonders merkwürdig. Auf den ersten Blick 
greifst du damit aufs Nirvana zu.

Und __heap_start+1 finde ich auch seltsam. Warum sollte man an der 
Speicherverwaltung des Systems vorbei auf den Heap zugreifen? Ich würde 
sowas nur tun, wenn absolut kein anderer Weg daran vorbei führt.

Tu Dir selbst einen Gefallen und nutze Pointer ausschließlich dazu, um 
auf die eigenen Variablen zuzugreifen. Auf Pointer-Arithmetik sollte man 
weitgehend verzichten, denn damit brockt man sich leicht Fehler ein, die 
man selbst nicht versteht.

von Georg G. (df2au)


Lesenswert?

Stefan U. schrieb:
> RAMEND+1 finde ich ganz besonders merkwürdig. Auf den ersten Blick
> greifst du damit aufs Nirvana zu.

Der zweite Blick zeigt dann, dass er mit Predecrement zufasst, also 
durchaus ins reale Leben. Und da er nur lesend zufasst, würde auch ein 
Griff ins Nirvana nicht tödlich enden.


> Und __heap_start+1 finde ich auch seltsam. Warum sollte man an der
> Speicherverwaltung des Systems vorbei auf den Heap zugreifen? Ich würde
> sowas nur tun, wenn absolut kein anderer Weg daran vorbei führt.

Er möchte eine Pseudo Zufallszahl haben und nutzt dazu den Inhalt des 
RAM. Ob das sinnvoll und zufällig genug ist, sei dahin gestellt, legitim 
ist es.


> Tu Dir selbst einen Gefallen und nutze Pointer ausschließlich dazu, um
> auf die eigenen Variablen zuzugreifen. Auf Pointer-Arithmetik sollte man
> weitgehend verzichten, denn damit brockt man sich leicht Fehler ein, die
> man selbst nicht versteht.

Der Absatz ist voll daneben. Es spricht absolut nichts gegen Pointer 
Arithmetik. Man muss nur wissen, was man tut. Das gilt aber auch in 
allen anderen Lebenslagen.

Die seed() Funktion sieh erst einmal sauber aus. Was da genau zum 
Absturz führt, muss noch erforscht werden. Mir fehlt momentan leider die 
Zeit dazu.

von Dieter F. (Gast)


Lesenswert?


von Georg G. (df2au)


Lesenswert?

Dieter F. schrieb:
> Da kommt es scheinbar her:

Das macht die Funktion nicht besser :-)
Nach einem Kaltstart ist das RAM 0x00 oder 0xff, abhängig von der 
Technologie und dem Chip Layout. Wirklich zufällige Inhalte habe ich 
noch bei keinem Typ gefunden.

von Karl H. (kbuchegg)


Lesenswert?

Georg G. schrieb:
> Dieter F. schrieb:
>> Da kommt es scheinbar her:
>
> Das macht die Funktion nicht besser :-)
> Nach einem Kaltstart ist das RAM 0x00 oder 0xff, abhängig von der
> Technologie und dem Chip Layout. Wirklich zufällige Inhalte habe ich
> noch bei keinem Typ gefunden.

Alles richtig.
Da aber ein AVR keinen Memory Manager hat und auch keinen Busfault 
auslösen kann, kann er von jeder beliebigen Adresse lesen, wie er lustig 
ist. Abschmieren wird dadurch nichts.

von Stefan F. (Gast)


Lesenswert?

Und warum läuft das Programm stabil, seit er diese Funktion nicht mehr 
verwendet? Es wäre ja schon interessant, diese Frage zu klären.

von Georg G. (df2au)


Lesenswert?

Stefan U. schrieb:
> Es wäre ja schon interessant, diese Frage zu klären.

Bestimmt. "Man" muss nur die Zeit zur Fehlersuche haben. So kurz vor 
Jahresende ist das immer etwas kritisch.

von Dieter F. (Gast)


Lesenswert?

Stefan U. schrieb:
> Und warum läuft das Programm stabil, seit er diese Funktion nicht mehr
> verwendet?

Woher weißt Du das? Er hüllt sich in Schweigen - das ist lediglich meine 
Erfahrung mit der angepassten Version (ohne extern ...).

Beim ersten compilieren meckert er (nur eine Warnung) die fehlende 
Deklaration von srand() an, weil <...stdlib.h> nicht eingebunden ist - 
die habe ich reingepackt und es funktioniert.

Die "seed"-Routine ist halt ziemlich funktionslos, weil

Georg G. schrieb:
> Nach einem Kaltstart ist das RAM 0x00 oder 0xff,

tatsächlich lauter 0x00-en drin stehen. Hier die absturzfreie Version 
(ich habe die "Original-seed"-Routine aus dem Link genommen):
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
#include <stdio.h>
5
#include <stdlib.h>
6
7
#define BAUD        250000
8
9
#include <util/setbaud.h>
10
11
12
void uart_init(void);
13
void uart_putc(char c);
14
void uart_puts(char *s);
15
16
char buffer[64];
17
18
unsigned short get_seed()
19
{
20
  unsigned short seed = 0;
21
  unsigned short *p = (unsigned short*) (RAMEND+1);
22
  extern unsigned short __heap_start;
23
  
24
  while (p >= &__heap_start + 1)
25
  seed ^= * (--p);
26
  
27
  return seed;
28
}
29
30
int main(void)
31
{
32
  uart_init();
33
  srand(get_seed());
34
  
35
  sprintf(buffer, "Hallo Welt, Random %d\r\n", rand()%256);
36
  uart_puts(buffer);
37
  DDRB |= 1<<5;
38
  
39
  while (1)
40
  {
41
    _delay_ms(100);
42
    PORTB ^= 1<<5;
43
    sprintf(buffer, "Neues Random %d\r\n", rand()%256);
44
    uart_puts(buffer);
45
  }
46
}
47
48
void uart_init(void)
49
{
50
  UBRR0 = UBRR_VALUE;
51
  
52
  #if USE_2X
53
  UCSR0A |= (1 << U2X0);
54
  #else
55
  UCSR0A &= ~(1 << U2X0);
56
  #endif
57
  
58
  // UART Tx, Rx Interrupt, Rx einschalten
59
  UCSR0B |= (1 << TXEN0) | (1 << RXEN0);
60
  // Asynchron 8N1
61
  UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
62
}
63
64
void uart_putc(char c)
65
{
66
  while(!(UCSR0A & (1 << UDRE0))) ;
67
  UDR0 = c;
68
}
69
70
void uart_puts(char *s)
71
{
72
  while(*s)
73
  {
74
    uart_putc(*s);
75
    s++;
76
  }
77
}

von Stefan F. (Gast)


Lesenswert?

>> Und warum läuft das Programm stabil, seit er diese Funktion nicht mehr
>> verwendet?

> Woher weißt Du das? Er hüllt sich in Schweigen

Das hatte ich deiner Antwort entnommen:

>> Ich würde mal den Aufruf von getSeed() durch eine konstante Zahl
>> ersetzen, um zu sehen, ob dort etwas faul ist.

> Wenn man das weglässt "resettet" er nicht mehr ...

Jedenfalls war das nur so ein Bauchgefühl von mir. Die Funktion kam mir 
komisch vor, deswegen hatte ich sie auf dem Kieker.

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.