Forum: Mikrocontroller und Digitale Elektronik UART arbeitet bei Codeänderung nicht mehr, ATmega16


von Albert .. (albert-k)


Lesenswert?

Hallo zusammen
Ich habe derzeit ein komisches Verhalten beim ATmega16. Folgende 
Konfiguration:
- ATmega16 @4MHz internen Oszillator
- Kommunikation über RS232 @ 19200Baud

Nun zu meinem Problem:
Ich versuche derzeit die FAT32 Lib von hier zu verwenden:
http://www.mikrocontroller.net/articles/AVR_FAT32
Es tritt jetzt jedoch ein Fehlverhalten des Controllers auf das ich 
nicht nachvollziehen kann.

Wenn ich folgenden Code verwende
1
int main(void){
2
  u8Flag = 0;
3
  //Datei die auf SD Karte angelegt werden soll
4
  unsigned char file_name [] = "test.txt";
5
  //String der in die Datei geschrieben werden soll
6
  unsigned char str [] = "Hallo Datei!";
7
8
  unsigned long int seek;
9
10
  _delay_ms(200);  //dummy delay
11
  gvUsartConfig(&tdsUsartConfig);
12
  MAKRO_USART_ENABLE_CHANNELS(USART_TX);
13
14
  timer0_init();
15
  vPortInit();
16
17
  gvUsartPutStringPolling("Startup\n");
18
  gvUsartPutCharPolling(TERM_CARRIAGE_RETURN);
19
20
  if( FALSE == mmc_init() ){
21
      gvUsartPutStringPolling("No SD Card!\n");
22
      //gvUsartPutCharPolling(TERM_CARRIAGE_RETURN);
23
      return 1;
24
    }
25
        /*
26
          Ab hier alles gleich
27
        */
Hier einmal kurz die Funktionen für das senden:
1
void gvUsartPutCharPolling(const uint8_t u8Char){
2
  while(!(UCSRA & (1<<UDRE)));  //wait until transmission possible
3
  UDR = u8Char;          //write char into transmit buffer
4
}
1
void gvUsartPutStringPolling(const char* u8String){
2
  while(*u8String != '\0'){
3
    gvUsartPutCharPolling((uint8_t)*u8String);
4
    u8String++;
5
  }
6
}
Wenn ich keine SD-Karte anschließe habe ich das gewünschte Verhalten=> 
Das Programm startet immer wieder neu da mmc_init einen Fehler 
zurückliefert.

Nun aber zu meinem seltsammen verhalten:
Wenn ich die Codezeile
1
gvUsartPutCharPolling(TERM_CARRIAGE_RETURN);
herausnehme wird gar nichts mehr über RS232 herausgesendet, nicht einmal 
irgendwelcher Unsinn.
Dieser Fehler tritt auch bei noch minimalistischeren Code auf (Nur 
initialisierung und dann senden). Manchmal nimmt er alles an, dann beim 
hinzufügen eines weiteren sendebefehls geht wieder gar nichts usw.

Ich kann mir nicht erklären woher dieser Fehler nun kommt. Das einzige 
das ich mir erklären kann ist das der Controller in irgendeinen Reset 
wegen eines Fehler reinspringt. Leider habe ich keinen Debugger um der 
Vermutung nachzugehen.
Hatte mal jmd. ein ähnliches Problem und hat eine Lösung gefunden?

von Peter D. (pdiener) Benutzerseite


Lesenswert?

Der interne Oszillator ist zu ungenau. Ohne Kalibrierung ist er 
ungeeignet zum Takten einer UART. Die Kalibrierung sollte der Controller 
regelmäßig selbst gegen eine Taktreferenz vornehmen. Die Alternative ist 
das Verwenden eines Quarzes.

Grüße,

Peter

von A.N. (Gast)


Lesenswert?

Salut ..

 gvUsartConfig(&tdsUsartConfig);
 MAKRO_USART_ENABLE_CHANNELS(USART_TX);

ist vielleicht schuld? Dummerweise hat meine Glaskugel gerade just in
dem Moment die Batterien leer gehabt ^^

von Albert .. (albert-k)


Lesenswert?

Peter Diener schrieb:
> Der interne Oszillator ist zu ungenau. Ohne Kalibrierung ist er
> ungeeignet zum Takten einer UART. Die Kalibrierung sollte der Controller
> regelmäßig selbst gegen eine Taktreferenz vornehmen. Die Alternative ist
> das Verwenden eines Quarzes.
Die Übertragung funktioniert aber einwandfrei, wenn ich das Carriage 
Return drinnen lasse kann ich Stundenlang senden ohne Probleme. Aber 
sobald diese Codezeile herausgenommen wird geht gar nichts mehr.

A.N. schrieb:
> gvUsartConfig(&tdsUsartConfig);
>  MAKRO_USART_ENABLE_CHANNELS(USART_TX);
>
> ist vielleicht schuld? Dummerweise hat meine Glaskugel gerade just in
> dem Moment die Batterien leer gehabt ^^
Das kann ich mir nicht denken, denn dann dürfte es ja nie funktionieren. 
Es funktioniert aber solange ich ein Carriage return versende. Sobald 
keines mehr versendet wird gibt es Probleme.

Als weiterer Hinweis:
Die Funktionen zur Intialisierung und aktivieren des Uart funktionieren 
in anderen programmen auf anderen ATmegas einwandfrei. Nur dieser ATmega 
macht derzeit Probleme.

von Peter D. (pdiener) Benutzerseite


Lesenswert?

Bei Timingfehlern an einer UART sind Fehlerbilder wie dieses nicht 
ungewöhnich. Meine Meinung ist unverändert, dass es mit großer 
Wahrscheinlichkeit am Oszillator liegt.

Grüße,

Peter

von Albert .. (albert-k)


Lesenswert?

Ich habe den Controller nun auf externen Quarz umgestellt. Das 
Fehlerbild ist Haargenau das gleiche.

von Stefan E. (sternst)


Lesenswert?

Albert ... schrieb:
> Wenn ich keine SD-Karte anschließe habe ich das gewünschte Verhalten=>
> Das Programm startet immer wieder neu da mmc_init einen Fehler
> zurückliefert.

Welche Toolchain verwendest du? Bei avr-gcc/AVRLibc wäre ein Neustart 
bei return aus main ein Fehlverhalten.

Dein Controller hat bloß 1k RAM. Eine FAT32-Lib zusammen mit der 
Tatsache, dass du dir über RAM-Verbrauch wohl keine allzu großen 
Gedanken machst (wenn ich die ganzen Strings im RAM sehe), ich schätze 
dir wird einfach das RAM ausgegangen sein. Und wenn der Stack in die 
Variablen läuft, gibt das dann alle möglichen Effekte.

von Albert .. (albert-k)


Lesenswert?

Stefan Ernst schrieb:
> Dein Controller hat bloß 1k RAM. Eine FAT32-Lib zusammen mit der
> Tatsache, dass du dir über RAM-Verbrauch wohl keine allzu großen
> Gedanken machst (wenn ich die ganzen Strings im RAM sehe), ich schätze
> dir wird einfach das RAM ausgegangen sein. Und wenn der Stack in die
> Variablen läuft, gibt das dann alle möglichen Effekte.
Der RAM-Verbrauch liegt bei 703 Bytes (68.7%). Da glaube ich nicht das 
es zu einem Stack-Überlauf kommt. Oder doch?

von Peter D. (pdiener) Benutzerseite


Lesenswert?

Es kommt darauf an, was alles dynamisch allokiert wird.

Ich finde es trotzdem komisch, dass beim Senden eines \n nach
gvUsartPutStringPolling("Startup\n");
das "Startup" nicht mehr angezeigt wird. Das deutet auf einen 
Timingfehler hin, den der PC ab einer bestimmten Anzahl kontinuiertlich 
übertragenen Zeichen erkennen kann und den ganzen Puffer verwirft.

Mich würde mal die Implementierung der UART Initialisierung 
interessieren.

Grüße,

Peter

von Albert .. (albert-k)


Lesenswert?

Hier die Uart initialisierung:
1
//-----------------------------------------------------------------------
2
//  USART Configuration struct inside Flash
3
//-----------------------------------------------------------------------
4
typedef struct {
5
  uint8_t u8Baudrate;  //use preprocessor calculated UBRR_VAL
6
  uint8_t u8Mode;
7
  uint8_t u8Parity;
8
  uint8_t u8StopBits;
9
  uint8_t u8BitSize;
10
  uint8_t u8ClockPolarity;
11
}const tdsUSART_CONFIG;
12
13
void gvUsartConfig(const tdsUSART_CONFIG* ptdsUsartConfig){
14
15
  PGM_P pgm_pData     = (PGM_P)ptdsUsartConfig;
16
  uint8_t u8BitSize    = pgm_read_word(&(ptdsUsartConfig->u8BitSize));
17
  uint8_t u8ClockPolarity  = pgm_read_word(&(ptdsUsartConfig->u8ClockPolarity));
18
19
  //Pin Configuration
20
  DDRD |= (1<<PD1);  //set Tx Pin PIND.1 to output
21
  DDRD &= ~(1<<PD0);  //set Rx Pin PIND.0 to Input
22
  PORTD |= (1<<PD0);  //set Pullup
23
24
  //Configure Baudrate
25
  UBRRH = pgm_read_word(pgm_pData) >> 8;  //set higher baudrate value first
26
  UBRRL = pgm_read_word(pgm_pData) & 0xFF;  //set second baudrate value
27
  pgm_pData++;
28
29
  //set Mode
30
  UCSRC |= (1<<URSEL) | (pgm_read_word(pgm_pData)<<6);
31
  pgm_pData++;
32
33
  //set parity
34
  UCSRC |= (pgm_read_word(pgm_pData)<<4) | (1<<URSEL);
35
  pgm_pData++;
36
37
  //set Stop bits
38
  UCSRC |= (1<<URSEL) | (pgm_read_word(pgm_pData)<<3);
39
  pgm_pData++;
40
41
  //Configure number of bits. Check if UCSZ2 bit must be set
42
  if(u8BitSize & 0x04){
43
    UCSRB |= (1<<UCSZ2);
44
  }
45
  //set Bitsize
46
  UCSRC |= (1<<URSEL) | ((u8BitSize & 0x03)<<1);
47
48
  //set clock polarity
49
  UCSRC |= u8ClockPolarity;
50
}

von Peter D. (pdiener) Benutzerseite


Lesenswert?

>uint8_t u8Baudrate

>PGM_P pgm_pData     = (PGM_P)ptdsUsartConfig;

>UBRRH = pgm_read_word(pgm_pData) >> 8;  //set higher baudrate value first
>UBRRL = pgm_read_word(pgm_pData) & 0xFF;  //set second baudrate value
>pgm_pData++;

pgm_pData wird als Pointer auf das erste Element in dem Struct 
initialisiert, das ist u8Baudrate. Das Ziel ist also ist 8 Bit groß. 
Dann wird versucht, ein 16 Bit breites Wort an dieser Stelle zu lesen. 
Und danach der Pointer um 1 Byte hochgestellt. Das passt doch alles 
nicht zusammen.

Grüße,

Peter

von Stefan E. (sternst)


Lesenswert?

Da wird einfach alles per pgm_read_word gelesen, obwohl alles nur 
uint8_t ist.

Die ganze Vorgehensweise, die einzelnen Elemente der Struct über einen 
fortlaufenden Pointer zu lesen, ist äußerst fragwürdig. Und zudem auch 
völlig überflüssig, und auch noch komplizierter und unübersichtlicher, 
als der normale Weg.

PS: Und was ist eigentlich mit der Frage nach der Toolchain und den 
Neustarts?

von Albert .. (albert-k)


Lesenswert?

Peter Diener schrieb:
> pgm_pData wird als Pointer auf das erste Element in dem Struct
> initialisiert, das ist u8Baudrate. Das Ziel ist also ist 8 Bit groß.
> Dann wird versucht, ein 16 Bit breites Wort an dieser Stelle zu lesen.
> Und danach der Pointer um 1 Byte hochgestellt. Das passt doch alles
> nicht zusammen.

Da hast du natürlich recht, habe nun Baudrate auf 16 Bit geändert und 
die Initialisierung angepasst.
Mich wundert es nur das es bei anderen Projekten geklappt hatte.

von Peter D. (pdiener) Benutzerseite


Lesenswert?

Und genau das führt dazu, dass in UBRR nicht das steht, was dort 
hingehört, sondern etwas anderes, das sich zum Teil auch aus u8Mode 
zusammensetzt.

Daher kommt der Timingfehler, die UART läuft also mit der falschen 
Baudrate. Auch die anderen vorgenommenen Konfigurationen sind von diesem 
Grundlegenden Fehler betroffen.

Grüße,

Peter

von Albert .. (albert-k)


Lesenswert?

Stefan Ernst schrieb:
> PS: Und was ist eigentlich mit der Frage nach der Toolchain und den
> Neustarts?
Als Toolchain verwende ich Eclipse+WinAVR. Das mit dem return hatte ich 
aus dem Beispiel zur FAT32 Lib herausgenommen und nicht weiter 
hinterfragt.

von Stefan E. (sternst)


Lesenswert?

1
UCSRC |= (1<<URSEL) | (pgm_read_word(pgm_pData)<<6);
2
...
3
  UCSRC |= (pgm_read_word(pgm_pData)<<4) | (1<<URSEL);
Und auch das ist Unsinn. Du kannst bei UCSRC nicht mit "|=" arbeiten, 
weil dabei der Inhalt aus UBRRH genommen und verodert wird.

Sorry, aber die ganze Funktion ist ziemlicher Murks.

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.