UART arbeitet bei Codeänderung nicht mehr, ATmega16

#2166304
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?
#2166341
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.
#2166358
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.
#2166364
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?
Persönliche Seite #2166367
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
#2166371
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
}
Persönliche Seite #2166375
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
#2166392
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?
#2166408
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.
#2166416
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren