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
charbuffer[64];
12
13
uint16_tgetSeed(void)
14
{
15
uint16_tseed=0;
16
uint16_t*p=(uint16_t*)(RAMEND+1);
17
externuint16_t__heap_start;
18
19
while(p>=&__heap_start+1)
20
seed^=*(--p);
21
22
returnseed;
23
}
24
25
intmain(void)
26
{
27
uart_init();
28
srand(getSeed());
29
30
sprintf(buffer,"Hallo Welt, Random %d\r\n",rand()%256);
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.
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 ?
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.
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
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
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.
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
> 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?
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.
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.
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.
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.
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.
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.
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
voiduart_init(void);
13
voiduart_putc(charc);
14
voiduart_puts(char*s);
15
16
charbuffer[64];
17
18
unsignedshortget_seed()
19
{
20
unsignedshortseed=0;
21
unsignedshort*p=(unsignedshort*)(RAMEND+1);
22
externunsignedshort__heap_start;
23
24
while(p>=&__heap_start+1)
25
seed^=*(--p);
26
27
returnseed;
28
}
29
30
intmain(void)
31
{
32
uart_init();
33
srand(get_seed());
34
35
sprintf(buffer,"Hallo Welt, Random %d\r\n",rand()%256);
>> 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.