AVR ATMEGA328PB mit UART.h stürzt ab

Gast #7303395
Lesenswert?

Hallo, ich beschäftige mich seit ein paar Wochen mit Mikrocontroller Programmierung und verwende dazu einen ATMEGA328PB welcher auf einem Board über UART mit dem Rechner kommuniziert. (Eigentlich sind es insg. 10 Mikrocontroller aber für das beschriebene Problem sollte nur der Master Controller relevant sein)

Im eigentlichen Skript geht es darum einen Datensatz mit Positionswerten zu generieren, aber ich bin auf einen Fehler gestoßen welcher den Mikrokontroller abstürzen lässt (zumindest springt er in die Main zurück).

Der Fehler ist auch mit dem unten aufgeführten Minimalbeispiel vorführbar, daher muss ich scheinbar irgendwas fundamentales missverstehen das nichts mit der Wertgenerierung an sich zu tun hat.

Im aktuellen Zustand gibt das Skript des mikrokontrollers beim Start die Standardmeldung "Master ready" über UART aus und ich erhalte die Ausgabe über hTerm am Rechner. Dann geht das Skript in eine Warteschleife in der es auf einen beliebigen Input über UART wartet. Sobald ich irgendein Zeichen sende müsste die generate_ramp Funktion durchlaufen und mit der Ausgabe "Exit function" abschließen. Das tut sie auch, allerdings nur für ramp_freq >= 2.0 Für ramp_freq <= 1.0 stürzt das Skript ab und der Kontroller startet neu, was sich dadurch äußert, dass wieder die Standardmeldung "Master ready" ausgegeben wird. Der "tolerierbare Bereich" rutscht tiefer wenn ich die globale Variable DATA_FREQ auf 256 setze, dann gehen also auch Werte zwischen 1.0 und 2.0 aber nicht kleiner 1.0.

Ich habe also versucht manuell Werte für seq_Length vorzugeben und dabei festgestellt:

  • Werte <= 452 funktionieren problemlos
  • Werte >= 453 führen zu fehlerhafter UART Ausgabe aber es sind korrekte Zeichen dabei
  • Werte zwischen 456 und 506 führen zu einer Endlosschleife der UART Ausgabe)
  • Werte >= 507 führen zum altbekannten Neustart

Gebe ich den Wert von seq_Length direkt ohne Variable vor so funktioniert das Skript problemlos auch für Werte weit über 512.

Ich hoffe ich habe alles beschrieben was hilfreich sein kann und dass irgendwer besser versteht was hier vor sich geht. Für hilfreiche Kommentare wäre ich sehr dankbar.

1
#include <stdlib.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include <util/delay.h>
5
#include <time.h>
6
#include <stdbool.h>
7
#include <stdint.h>
8
#include "uart.h"
9
#include "linsin16.h"
10

11
/* define CPU frequency in Hz in Makefile */
12
#ifndef F_CPU
13
#error "F_CPU undefined, please define CPU frequency in Hz in Makefile"
14
#endif
15

16
/* Define UART buad rate here */
17
#define UART_BAUD_RATE      200000  //115200    
18

19
#define RESET  PC4
20
#define RESET_SLAVES      {(PORTC |= (1 << RESET)); (DDRC |= (1 << RESET)); _delay_ms(100); (PORTC &= ~(1 << RESET)); _delay_ms(100);}
21

22
#define T_TRIGGER_512      37499
23
#define T_TRIGGER_256      9374
24
#define DATA_FREQ_512      (19200000/(T_TRIGGER+1))
25
#define DATA_FREQ_256      (2400000/(T_TRIGGER+1))
26

27
#define T_TRIGGER      T_TRIGGER_512
28
#define DATA_FREQ      DATA_FREQ_512
29

30
/***********************************************
31
    Functions
32
***********************************************/
33
struct Pos_Array { uint8_t   data[4];};
34

35
void generate_ramp(float ramp_freq){
36

37
  int seq_Length    = (int)((float)DATA_FREQ/ramp_freq);
38
  //int seq_Length  >= 507;    // Klappt nicht
39
  //int seq_Length  >= 453;    // Klappt aber nicht richtig
40
  //int seq_Length  = 452;    // Klappt
41
  struct Pos_Array   ramp_pos_arr[seq_Length];
42
  
43
  for(int i=0;i<seq_Length;i++){
44
      ramp_pos_arr[i].data[0] = 0x00;    
45
  }
46

47
  uart_puts("Exit function");
48
  uart_puts("\r\n");
49
  return;
50
}
51

52

53
int main(void)
54
{
55
  uint16_t   c;
56

57
  RESET_SLAVES; // Sets reset signal for other controllers
58
  
59
  uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );           // Initialize UART library, pass baudrate and AVR cpu clock with the macro 
60
  
61
  sei();                                  // Enable interrupt, since UART library is interrupt controlled
62
  
63
  uart_puts("Master ready");
64
  uart_puts("\r\n");
65

66
  for(;;){
67
    do{  
68
      c   = uart_getc();
69
      if ( c & UART_NO_DATA ){/* no data available from UART*/}
70
      else{
71
        generate_test( 1.0);
72
      }
73
    }while (!( c & UART_NO_DATA ));
74
  }
75
  uart_puts("Exit Main");
76
  uart_puts("\r\n");
77
}
Gast #7303432
Lesenswert?

Achso ja klar, danke schonmal für die Antwort. ich benutze die "UART Lib." vom Peter Flury (http://homepage.hispeed.ch/peterfleury/avr-software.html)

Bezüglich der Speichergröße wären das dann etwa 1.8kB für die ramp_pos_arr Variable womit also unter 0.2kB übrig bleiben für den Rest des Skripts (das könnte in der Tat zu wenig sein)

Warum aber funktioniert das Skript dann vollkommen in Ordnung, wenn ich die Sequenz Länge direkt eingebe also so z.B. würden ja über 2kB belegt werden

1
  struct Pos_Array   ramp_pos_arr[512];
2
  for(int i=0;i<512;i++){
3
      ramp_pos_arr[i].data[0] = 0x01;
4
                        ramp_pos_arr[i].data[1] = 0x01;
5
                        ramp_pos_arr[i].data[2] = 0x01;
6
                        ramp_pos_arr[i].data[3] = 0x01;
7
  }
Gast #7304007
Lesenswert?

Hi, danke für den Hinweis.

An sich macht das ja Sinn, aber ganz ist der Groschen bei mir noch nicht gefallen.

Meine Variante aus dem zweiten Post entspricht doch der Initialisierung eines Feldes mit fixer Größe, was bedeutet, dass die Größe zum Zeitpunkt der Übersetzung festgelegt wird. Beim Übersetzen und Laden bemerkt der AVR Dude das ja schonmal nicht, aber wie weißt der Mikrokontroller während der Laufzeit 512*4 Feldern einen Byte Wert zu und gibt im Nachhinein noch völlig korrekt die UART Ausgabe aus, ohne etwas zu bemerken ??

Moderator Persönliche Seite #7304021
Lesenswert?

AVRDUDE weiß davon rein gar nichts, weil es sich um den SRAM ja nicht kümmert. Der Linker könnte es bemerken, allerdings sind die AVR-Linkerscripte relativ generisch gehalten und nur grob in MCU-Klassen eingeteilt. Daher benennen sie immer den maximal möglichen Speicher einer jeden MCU-Klasse. (Ansonsten müsste man mehrere Dutzend Linkerscripte pflegen und die Binutils wären für jeden neuen AVR extra anzupassen.)

Du solltest dir einfach angewöhnen, am Ende des Compilierens noch ein "avr-size" auf das generierte ELF-File loszulassen.

Gast #7304025
Lesenswert?

Slav schrieb:

struct Pos_Array ramp_pos_arr[seq_Length];

Das was ich zu bemängeln habe mag für die eine oder andere Prozessor-Architektur nicht zutreffen, diese Einschränkung also vorab. Vielleicht ist es auch Compiler-abhängig?

Aber es ist kein guter Stil innerhalb einer Funktion ein so grosses Array anzulegen. Manche Applikationen (allgemein) könnten dazu tendieren den Stack zu überlasten, zum Über- laufen zu bringen. Was dann passiert kann sich jeder aus- malen: es kracht. Ich hab es erlebt, aber das muss hier nicht so sein.

my 2ct, YMMV

Moderator Persönliche Seite #7304031
Lesenswert?

beo bachta schrieb:

Aber es ist kein guter Stil innerhalb einer Funktion ein so grosses Array anzulegen.

Für so einen kleinen Controller ist es generell kein guter Stil, so ein großes Array anzulegen – egal ob auf dem Stack oder im Heap oder statisch. ;-)

Aber das sollte Slav ja jetzt verstanden haben. Bei einer MCU muss man sich um die Menge seiner Daten vor der Programmierung schon mal Gedanken machen.

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