PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : UART, Sprungtabelle und Systemabstürze...



PCMan
17.12.2008, 21:10
Hallo Leute,
mal wieder komme ich nicht weiter und möchte nun mal die Experten an die harte Nuss lassen.

Ich möchte meinen AVR mit dem PC kommunizieren lassen. Dazu verwende ich das Terminalprogram puTTY.
Ich möchte, dass mein AVR empfangene Befehle erkennt und ausführt.

Im Großen und Ganzen realisiere ich das mit P.Fleuries UART-Library.
Dort habe ich aber in der uart.c einige Modifikationen vorgenommen.

Zunächst etwas Code:



volatile struct {
... jede Menge zeugs...

uint8_t command_ptr;
char command[255];
} system;


// Die Kommandostruktur
char p_unknown[] PROGMEM = "Unbekannter Befehl: ";
typedef struct
{
void (*func)(uint8_t); // Zeiger auf die auszuführende Funktion
//uint8_t arg; // das Argument, das mitübergeben wird
uint8_t arg;
char text[255]; // Text, maximal TEXT_LEN Zeichen lang
} command_t;

//Sprungtabelle: welche Funktion mit welchem Parameter bei welchem eingegangenem Befehl?

const command_t commands[] PROGMEM =
{
{ execute, 1, "ping" },
{ execute, 2, "help" }
};

...

//zunächst alles beim alten...
SIGNAL(UART0_RECEIVE_INTERRUPT)
/************************************************** ***********************
Function: UART Receive Complete interrupt
Purpose: called when the UART has received a character
************************************************** ************************/
{
unsigned char tmphead;
unsigned char data;
unsigned char usr;
unsigned char lastRxError;


/* read UART status register and UART data register */
usr = UART0_STATUS;
data = UART0_DATA;

/* */
#if defined( AT90_UART )
lastRxError = (usr & (_BV(FE)|_BV(DOR)) );
#elif defined( ATMEGA_USART )
lastRxError = (usr & (_BV(FE)|_BV(DOR)) );
#elif defined( ATMEGA_USART0 )
lastRxError = (usr & (_BV(FE0)|_BV(DOR0)) );
#elif defined ( ATMEGA_UART )
lastRxError = (usr & (_BV(FE)|_BV(DOR)) );
#endif

/* calculate buffer index */
tmphead = ( UART_RxHead + 1) & UART_RX_BUFFER_MASK;

if ( tmphead == UART_RxTail ) {
/* error: receive buffer overflow */
lastRxError = UART_BUFFER_OVERFLOW >> 8;
}else{
/* store new index */
UART_RxHead = tmphead;
/* store received data in buffer */
UART_RxBuf[tmphead] = data;
}
UART_LastRxError = lastRxError;

//AB HIER MODIFIZIERT
uint8_t c = uart_getc(); //es wurde Zeichen empfangen, dann hole es ab!

if (!(c & UART_NO_DATA) && !( c & UART_FRAME_ERROR ) && !( c & UART_OVERRUN_ERROR ) && !( c & UART_BUFFER_OVERFLOW )&& c != 0) //es wurde ein Zeichen empfangen und kein Fehler o.Ä.
{
uart_putc(c); //zeichen ausgeben

if (c == 13) //es wurde Enter-Taste im puTTY gedrückt.
{
uart_puts("\n\r"); //neue Zeile in puTTY
system.command[system.command_ptr]='\0';
system.command_ptr = 0;
lcd_clrscr();
lcd_puts((char*)system.command);
const command_t * cmd = commands;
uint8_t i;
for (i=0; i < sizeof(commands) / sizeof(command_t); i++)
{
// Ist das der gesuchte String?
if (strcmp_P ((char*)system.command, cmd->text))
{
// Nein, dann weitersuchen
cmd++;
continue;
}
else
{
// Ja
uint8_t (*func)(uint8_t), arg;

// Dann Funktionszeiger und Argument besorgen,
func = (uint8_t(*)(uint8_t)) pgm_read_word (& cmd->func);
arg = (uint8_t) pgm_read_word (& cmd->arg);
// Funktion ausführen und deren Wert zurückliefern
func (arg);
break;
}
}
if (i==2) //es wurden alle Befehle abgegrast, aber der richtige war nicht dabei
{
uart_puts_P("Unbekannter Befehl: "); //<- HIER ENTSTEHT DER FEHLER
uart_puts((char*)system.command);
uart_puts("\n\r#");
}
}
else
{
system.command[system.command_ptr] = c;
system.command_ptr++;
}

}

}


Es kommen keine Warnings nach dem Kompilieren.
Wenn ich nun folgendes in putty eingebe:
"ping": ich erhalte wie erwartet antwort
"ping.": Meldung dass Befehl nicht gefunden wurde
"ping.." (oder irgendetwas anderes was mehr als 7 Zeichen hat führt zum Absturz des Programmes. Ich weiß aber, dass die Codezeilen ausgeführt werden, aber ich weiß nicht, warum nix über den UART rausgesendet wird.

Ich hoffe ihr habt ein paar Ideen,
Grüße Simon

P.S.: ATMega32, 12MHz

sternst
17.12.2008, 22:53
Dein Problem ist, dass du uart_puts im Receive-Interrupt aufrufst.
Wenn der Puffer nämlich voll ist, wartet die Funktion, bis wieder Platz im Puffer ist. Es wird aber kein Platz frei, wenn nichts gesendet wird, und das wird es nicht, so lange der Receive-Interrupt noch bearbeitet wird. Wenn du also mehr Zeichen versuchst zu senden, als der Sendepuffer groß ist, hast du einen schönen Dead-Lock.

Es ist überhaupt eine reichlich schlechte Idee, das ganze Geraffel in den Receive-Interrupt zu stopfen.

PCMan
17.12.2008, 23:10
Hi sternst,
ich würde ja gerne einen anderen Weg gehen als das alles in die interrupt routine zu stopfen. Aber wie soll ich erkennen, wann den ein befehl ankam? Ich meine alles in der main-Endlosschleife dauernd abzutasten ist doch verbrauchte Leistung, oder?
Bin natürlich offen für Vorschläge.
Grüße Simon

sternst
17.12.2008, 23:27
Ich meine alles in der main-Endlosschleife dauernd abzutasten ist doch verbrauchte Leistung, oder?

Was machst du denn aktuell in der main-Endlosschleife anderes, als Leistung zu verbraten?

SprinterSB
18.12.2008, 10:31
1) die ISR-Routinen würde ich unverändert lassen.
2) Sooo lange dauert eine Auswertung in main() auch nicht, wenn man's richtig anstellt ;-)
3) Falls die Zeichen zu flott ankommen, kann man sie über ne FIFO puffern, ein Beispiel dazu ist im wiki.

Ob ein kompletter Befehl angekommen ist, kannst du erkennen, indem jeder Befehl zB mit einem Zeichen wie # endet oder jeder Befehl ne bestimmte länge hat.

Ich würd allerdings ne 'inkrementelle' Erkennung vorschlagen, d.h. es gibt keine eigene Schleife für die Erkennung uneterhalb von main, sondern wenn ein neues Zeichen ankommt geht die Erkennung um dieses 1 Zeichen weiter.

Dazu muss man sich den Status der Erkennung merken (wieviel Zeichen sind schon da, etc.). Dein main()-Schleife muss dazu nicht-blockierend aufgebaut sein, also ohne wait() und so üblen Kram.

PCMan
18.12.2008, 12:11
hallo ihr beiden,
alles klar, dann werd' ich mal umstrukturieren. Jetzt versteh ich wenigstens auch, wo der Fehler lag.
Habt vielen Dank,
Simon