PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Mal wieder ein UART Problem



Coop
20.11.2010, 22:49
Hallo,

versuche mir zur Zeit eine sichere UART-Verbindung aufzubauen.
Die Grundlagen dazu, habe ich mir mit eigen geschriebenen Quellcode erarbeitet, was auch beim Senden von Einzelzeichen ganz gut funktioniert hatte.
Nun wollte ich mir die Herangehensweise mittels Buffer anhand des von Peter Fleury bereitgestellten UART-Quellcodes erarbeiten. Dazu habe ich versucht, diesen Code an den Prozessor (ATMega16) anzupassen, den ich benutzen will und alles andere an QC wegzulassen (den, den ich nicht benötige).
Leider klappt nicht alles so, wie ichs mir erhofte - den Fehler habe ich leider nicht finden können.
Das Programm funktioniert quasi bis zur while(1) Schleife - das heißt, die Ausgaben werden ordentlich an ein Terminalprogramm übergeben.
Allerdings werden keine Zeichen, die im Terminalprogramm eingegeben werden, "geechot".
Vielleicht habe ich schon zu lange drauf geschaut - ich hoffe mir kann jemand zur Lösung verhelfen.

Hier der genutzte Quellcode (ohne uart.h, da daran nix geändert wurde):




/*
* Notes:
* Based on Atmel Application Notes AVR306 and the library of Peter Fleury
*/

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <stdint.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include "uart.h"

/*
* constants and makros
*/
#define F_CPU 8000000UL

/* 9600 baud */
#define UART_BAUD_RATE 9600


//size of RX/TX buffers
#define UART_RX_BUFFER_MASK (UART_RX_BUFFER_SIZE-1)
#define UART_TX_BUFFER_MASK (UART_RX_BUFFER_SIZE-1)

/*ATmega with one USART*/
#define ATMEGA_USART
#define UART0_RECEIVE_INTERRUPT USART_RXC_vect
#define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect
#define UART0_STATUS UCSRA
#define UART0_CONTROL UCSRB
#define UART0_DATA UDR
#define UART0_UDRIE UDRIE //USART Data Register Empty Interrupt Enable

/*
* modul global variables
*/
static volatile unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE];
static volatile unsigned char UART_RxBuf[UART_RX_BUFFER_SIZE];
static volatile unsigned char UART_TxHead;
static volatile unsigned char UART_TxTail;
static volatile unsigned char UART_RxHead;
static volatile unsigned char UART_RxTail;
static volatile unsigned char UART_LastRxError;

ISR(UART0_RECEIVE_INTERRUPT)
/************************************************** ************************************************** ****/
// Function: UART Receive Complete Int
// 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;

lastRxError = (usr & ( (1<<FE) | 1<<DOR) );

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

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

ISR(UART0_TRANSMIT_INTERRUPT)
/************************************************** ************************************************** ****/
// Function: UART Data Register Empty Int
// Purpose : called, when the UART is ready to transmit the next byte
/************************************************** ************************************************** ****/
{
unsigned char tmptail;

if(UART_TxHead != UART_TxTail)
{
/*calculate and store new buffer index*/
tmptail = (UART_TxTail +1) & UART_TX_BUFFER_MASK;
UART_TxTail = tmptail;
/*get one Byte from buffer and write it to UART*/
UART0_DATA = UART_TxBuf[tmptail]; //start transmission
}
else
{
/*tx buffer empty, disable UDRE interrupt*/
UART0_CONTROL &= ~(1<<UART0_UDRIE);
}
}

void uart_init(unsigned int baudrate)
/************************************************** ************************************************** ****/
// Function: uart_init()
// Purpose : initialize UART and set baudrate
// Input : baudrate using macro UART_BAUD_SELECT
// Returns : none
/************************************************** ************************************************** ****/
{
/*first definition of buffer indicies*/
UART_TxHead = 0;
UART_RxTail = 0;
UART_RxHead = 0;
UART_TxTail = 0;

/*set baudrate*/
if(baudrate & 0x8000)
{
UART0_STATUS = (1<<U2X); //Enable 2x speed
baudrate &= ~0x8000;
}
UBRRH = (unsigned char)(baudrate>>8);
UBRRL = (unsigned char)(baudrate);

/*Enable UART receiver, transmitter and receive complete interrupt*/
UART0_CONTROL = (1<<RXCIE) | (1<<RXEN) | (1<<TXEN);//

/*Set frame format: asynchronous, 8databits, no parity, 1Stopbit*/
#ifdef URSEL
UCSRC = (1<<URSEL) | (3<<UCSZ0);
#else
UCSRC = (3<<UCSZ0);
#endif

// Flush Receive-Buffer (entfernen evtl. vorhandener ungültiger Werte)
do
{
UART0_DATA;
}
while (UART0_STATUS & (1 << RXC));
}

unsigned int uart_getc(void)
/************************************************** ************************************************** ****/
// Function: uart_getc()
// Purpose : returns byte from ringbuffer
// Input : none
// Returns : lower byte: received byte from ringbuffer / higher byte: last receive error
/************************************************** ************************************************** ****/
{
unsigned char tmptail;
unsigned char data;

if(UART_RxHead == UART_RxTail)
{
return UART_NO_DATA; //no data available
}

/*calculate and store buffer index*/
tmptail = (UART_RxTail + 1) & UART_RX_BUFFER_MASK;
UART_RxTail = tmptail;

/*get data from receive buffer*/
data = UART_RxBuf[tmptail];

return (UART_LastRxError<<8) + data;
}

void uart_putc(unsigned char data)
/************************************************** ************************************************** ****/
// Function: uart_putc()
// Purpose : write byte to ringbuffer for transmitting via UART
// Input : byte to be transmitted
// Returns : none
/************************************************** ************************************************** ****/
{
unsigned char tmphead;

tmphead = (UART_TxHead + 1) & UART_TX_BUFFER_MASK;

while(tmphead == UART_TxTail); //wait for free space in puffer

UART_TxBuf[tmphead] = data;
UART_TxHead = tmphead;

/*enable UDRE interrupt*/
UART0_CONTROL |= (1<<UART0_UDRIE);
}

void uart_puts(const char *s)
/************************************************** ************************************************** ****/
// Function: uart_puts()
// Purpose : transmit string to UART
// Input : string to be transmitted
// Returns : none
/************************************************** ************************************************** ****/
{
while(*s)
{
uart_putc(*s++);
}
}

void uart_puts_p(const char *progmem_s)
/************************************************** ************************************************** ****/
// Function: uart_puts_p()
// Purpose : transmit string from program memory to UART
// Input : programm memory string to be transmitted
// Returns : none
/************************************************** ************************************************** ****/
{
register char c;

while( (c = pgm_read_byte(progmem_s++)) )
{
uart_putc(c);
}
}


int main(void)
{
unsigned int c=0;
char buffer[7];
int num=134;
DDRB=0xFF; //for debugging


/*
* Initialize UART library, pass baudrate and AVR cpu clock
* with the macro
* UART_BAUD_SELECT() (normal speed mode )
* or
* UART_BAUD_SELECT_DOUBLE_SPEED() ( double speed mode)
*/
uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );

/*
* now enable interrupt, since UART library is interrupt controlled
*/
sei();

/*
* Transmit string to UART
* The string is buffered by the uart library in a circular buffer
* and one character at a time is transmitted to the UART using interrupts.
* uart_puts() blocks if it can not write the whole string to the circular
* buffer
*/
uart_puts("String stored in SRAM\n");

/*
* Transmit string from program memory to UART
*/
uart_puts_P("String stored in FLASH\n");


/*
* Use standard avr-libc functions to convert numbers into string
* before transmitting via UART
*/
itoa( num, buffer, 10); // convert interger into string (decimal format)
uart_puts(buffer); // and transmit string to UART
PORTB=0x55;

/*
* Transmit single character to UART
*/
uart_putc('>');
while(!(c = uart_getc()));
uart_putc( (unsigned char)c );
while(1)
{
c = uart_getc();
if ( c & UART_NO_DATA )
{PORTB=~0x55;//for debugging
}
else
{
if ( c & UART_FRAME_ERROR )
{
/* Framing Error detected, i.e no stop bit detected */
uart_puts_P("UART Frame Error: ");
}
if ( c & UART_OVERRUN_ERROR )
{
uart_puts_P("UART Overrun Error: ");
}
if ( c & UART_BUFFER_OVERFLOW )
{
uart_puts_P("Buffer overflow error: ");
}
/*
* send received character back
*/
uart_putc( (unsigned char)c );
}
}

}



Also, hoffe es schaut sich jemand an und schaffts auch noch den fehlenden Hinweis zu geben.

Danke...

@Edit Tippfehler in ISR_RXC UART_TxHead = tmphead;<-->UART_RxHead = tmphead;

Coop
27.11.2010, 23:29
Hallo,

wollte das Problem nochmal aktualisieren.
In einem anderen Forum hat dankenswerterweise jemand einen Tippfehler gefunden, habe es oben editiert.
Leider funktioniert es trotzdem immer noch nicht.
Ich nutze das Programm "HTerm" - dort kann man eine Serie von Zeichen eingeben - erst bei der Betätigung von Enter wird der gesamte String verschickt. Und genau da liegt das Problem.
Echo von einzelnen Zeichen funktioniert gut. Bei mehreren werden nur die ersten drei und das letzte Zeichen richtig dargestellt.
Folgende Beispiele (Transmit -- Receive)
1--1
12--12
123--123
1234--1234
12345--1235
123456--1236
1234567--1237
12345678--1238
usw.

Weiß nicht woran es liegt, vielleicht auch am Terminalprogramm, wäre super wenn es mal jemand probieren könnte und seine Ergebnisse beschreibt.
So langsam verzweifle ich daran....

Hubert.G
28.11.2010, 10:34
Wenn einzelne Zeichen funktionieren, mehrere aber nicht mehr, dann deutet das auf eine abweichenede Frequenz hin.
Arbeitest du mit dem internen Oszillator oder einem Quarz.
Wenn Quarz, wie ist der angeschalten.

Jaecko
28.11.2010, 14:40
Wie gross ist denn UART_RX_BUFFER_SIZE?
Die Frequenzabweichung wird bei einem neuen Zeichen "zurückgesetzt", da das Startbit als Synchronisation arbeitet.

Jaecko
28.11.2010, 14:41
Wie gross ist denn UART_RX_BUFFER_SIZE?
Die Frequenzabweichung wird bei einem neuen Zeichen "zurückgesetzt", da das Startbit als Synchronisation dient. Sieht eher nach einem überlaufenden Puffer irgendwo aus.

Coop
28.11.2010, 17:41
Hallo,
danke erstmal für eure Bereitschaft helfen zu wollen.
Da es keine extra Hardware gibt, nutze ich das STK500 als Plattform.
Darauf arbeitet ein ATMega16 mit externem 8MHz-Quarz. Die Fuse des Taktes ist auf "Ext. Crystal/Resonator High Freq.; Start-up time 16K CK+64ms" gesetzt.
Ich denke eigentlich auch, dass durch jedes Start/Stopbit bei jedem Byte eine Synchronisation im Asynchronmodus angestoßen wird.

Die Größe des Buffers wird in der von Peter Fleury mitgelieferten Headerdatei eingestellt. Ich habe diese sowohl für den RX als auch für den TX Buffer auf 128 eingestellt.
{
#define UART_RX_BUFFER_SIZE 128
#define UART_TX_BUFFER_SIZE 128}

berecke
02.12.2010, 19:30
Kann man bei STK500 nicht den internen Board-Takt über das AVRStudio variieren? Vielleicht der Takt dort verstellt?!

berecke
02.12.2010, 19:31
Kann man beim STK500 nicht den internen Board-Takt über das AVRStudio variieren? Vielleicht der Takt dort verstellt?!