Forum: Mikrocontroller und Digitale Elektronik AVR ATMega324PA USART Daten empfangen via Interrupt


von Julian B. (zitrone18)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

wie der Betreff schon sagt, habe ich einen ATMega324PA und möchte beide 
USART's mit Interrupts verwenden. Ich habe das Ganze mal in einem 
minimalen Programm komprimiert, erstmal nur für eine Schnittstelle.
Die Sende-/ und Empfangsdaten sollen in einem Ringspeicher abgelegt 
werden. Wichtiger sind mir die Empfangsdaten an dieser Stelle. Die 
Senderoutine kann ich zur Not auch ohne ISR basteln.

Im Anhang findet ihr meinen aktuellen Code.
In der Main prüfe ich, ob sich der Schreib-/ und Lesepointer 
unterscheiden und möchte daraufhin ein Byte aus dem Speicher laden und 
an den PC zurückschicken.

Das Delay am Ende ist aktuell auskommentiert. So funktioniert es nicht!
Wenn ich das Delay einkommentieren dann funktioniert die Kommunikation.
Kleiner als 2ms darf ich den Delay aber auch nicht machen und bei vielen 
Daten überholt der Schreib-/ den Lesepointer.
Warum braucht der Knecht diese Auszeit?
Er Antwortet mir ohne den Delay nichtmal auf einzelne Bytes...


Der Prozessor läuft mit einem 14,7456 Mhz Quarz bei 115200 Baud.
Die Fuse-Bits stehen auf High = 0xD9 und Low = 0xFF.

Ich hoffe ich habe alle wichtigen Infos gegeben.

Gruß,
Zitrone

von jojo (Gast)


Lesenswert?

Hi, ich habe auf nem Atmega16 mal ne kommunikation mit Sendefifo und 
Interrupt gabastelt, und habe aber nicht den UDRE (Uart Data register 
empty)interrupt benutzt, sondern den TXC (transmition complete).

Ich glaube mich zu erinnern, dass ich ähnliche Probleme hatte, wenn der
Tx-Interrupt kam, bevor die Daten komplett gesendet wurden.

Versuchs doch mal damit.

vg. Norbert

von jojo (Gast)


Lesenswert?

Nachtrag:

Für Tx-complete musst Du allerdings immer das Erste Byte manuell senden, 
wenn der Sendebuffer zuvor leer war.

Die folgenden folgende Queue kann dann vom Interrupt geleert werden.
1
static uint8   UartTxActiv;
2
3
void UartInit(UartBdr_t bdr)
4
{
5
#if (UART_PRINT_BY_QUEUE)
6
   /* initialise TX Queue*/
7
   FifoInit(&UartTxFifo, UartTxBuffer, sizeof(UartTxBuffer));
8
#endif
9
10
   uint16 baud = __LPM_word(&UartBdrTab[bdr]);       /* read BdrTab from Progmem */
11
12
   UBRRH = (uint8)(baud >>8);
13
   UBRRL = (uint8)(baud);
14
15
   UCSRA  = (1<<U2X);                                /* Baudrate divisor =8 */
16
17
   UCSRB  = (1<<RXEN) | (1<<TXEN);                   /* Enable RX und TX */
18
19
#if (UART_PRINT_BY_QUEUE)
20
   UCSRB  |= (1<<TXCIE);                             /* Enable Tx Interrupt*/
21
#endif
22
23
   /*       async      par even   StopBits 2  Databits 8 */
24
   UCSRC = (1<<URSEL)| (0<<UPM0)| (0<<USBS) | (3<<UCSZ0);
25
}
26
/*******************************************************************************
27
**                                                                            **
28
** FUNC-NAME     : UartTx                                                     **
29
**                                                                            **
30
** DESCRIPTION   Routine writes a byte to the Uart TxFifo buffer              **
31
**               If no transmittion is activ, it copies the byte from the     **
32
**               buffer to the TxRegister and starts the transmition.         **
33
**               If the buffer is full, it waits until there is some          **
34
**               space left.                                                  **
35
**                                                                            **
36
** PARAMETER     : uint8 data_b:    byte to transmit                          **
37
**                                                                            **
38
** RETURN        : -                                                          **
39
**                                                                            **
40
*******************************************************************************/
41
void UartTx(uint8 data_b)
42
{
43
#if (UART_PRINT_BY_QUEUE)
44
   // Hier wird bei vollem Fifo bis zum Erfolg versucht zu schreiben
45
   while(!FifoWriteByte(&UartTxFifo, data_b));
46
   /* Wenn aktuell keine Uebertragung mehr aktiv ist, dann muss das erste Byte
47
      von Hand uaf das UDR Register geschrieben werden*/
48
   if(UartTxActiv ==0)
49
   {
50
      if( FifoReadByte(&UartTxFifo,&data_b) )
51
      {
52
         UDR = data_b;
53
         UartTxActiv =1;
54
      }
55
   }
56
#else
57
   while( !(UCSRA & (1<<UDRE)) );
58
   UDR = data_b;
59
#endif
60
}
61
62
63
/*******************************************************************************
64
**                                                                            **
65
** FUNC-NAME     : Interrupt 'USART_TXC_vect'                                 **
66
**                                                                            **
67
** DESCRIPTION   : Uart Transmition Complete Service Routine:                 **
68
**                 Routine occures each time a Uart Transmition has completed **
69
**                 It copies the next byte to transmit from TxFifo buffer to  **
70
**                 the uart transmit register - until Fifo is empty.          **
71
**                                                                            **
72
** PARAMETER     : -                                                          **
73
**                                                                            **
74
** RETURN        : -                                                          **
75
**                                                                            **
76
*******************************************************************************/
77
ISR(USART_TXC_vect)
78
{
79
#if (UART_PRINT_BY_QUEUE)
80
   uint8 data;
81
   // Byte aus dem Fifo lesen
82
   if( FifoReadByte(&UartTxFifo,&data) )
83
   {
84
      // Daten vorhanden ->Byte Uart Data Register schreiben
85
      UDR = data;
86
   }
87
   else
88
   {
89
      // Keine Daten mehr vorhanden-> Uebertragung auf inaktiv setzen
90
      UartTxActiv = 0;
91
   }
92
#endif
93
}

von Karl H. (kbuchegg)


Lesenswert?

Und wieder mal: VOLATILE !

FAQ: Was hat es mit volatile auf sich


1
  while(1)
2
  {
3
    if(!(ptrRecWrite == ptrRecRead))
4
    {
5
      input = uart0_getc();
6
      uart0_putc(input);
7
    }
8
    //_delay_ms(2);          //Wenn drin gehts. Wenn nicht dann nicht!
9
  }

ist der _delay nicht drinnen, hat der Compiler genug Register frei um 
sich die Werte für ptrRecWrite bzw. ptrRecRead in CPU-Registern halten 
zu können. Da passiert einfach zu wenig in der Hauptschleife, als das er 
die Werte jedesmal aus dem Speicher nachladen müsste.

von Karl H. (kbuchegg)


Lesenswert?

Julian B. schrieb:

> Kleiner als 2ms darf ich den Delay aber auch nicht machen und bei vielen
> Daten überholt der Schreib-/ den Lesepointer.

Könnte ein Hinweis auf einen weiteren Fehler sein, auch wenn ich beim 
Drüberscrollen nichts mehr gesehen habe.
Aber ergänze mal das fehlende volatile an den Pointer Variablen. Und 
dann sieht man weiter.

von Julian B. (zitrone18)


Lesenswert?

Hallo zusammen,

danke für die Antworten.

@ Norbert:
Das habe ich im Vorfeld auch schon ausprobiert. Habe es gerade aber 
nochmal gemacht. Allerdings ohne Erfolg die Daten (0xAA, 0xBB, 0xCC) 
werden korrekt ausgegeben aber Daten annehmen will der Knecht nicht. 
Schade.

@ Karl Heinz:
Entschuldige bitte, dass ich die Version ohne volatile hochgeladen habe. 
Volatile ist mir bekannt und benutze ich auch da wo es sinnvoll ist. Ich 
habe die Variablen jetzt wie folgt Deklariert:
1
 //VARS
2
#define TRANSBUF_SIZE  150
3
uint8_t transBuffer[TRANSBUF_SIZE];    // Sendebuffer
4
volatile uint8_t* ptrTransStart;          // Startadresse
5
volatile uint8_t* ptrTransEnd;          // Letzte Adresse + 1
6
volatile uint8_t* ptrTransWrite;          // aktuelle Schreibadresse
7
volatile uint8_t* ptrTransRead;          // aktuelle Leseadresse
8
9
#define RECBUF_SIZE  150
10
uint8_t recBuffer[RECBUF_SIZE];      // Empfangsbuffer
11
volatile uint8_t* ptrRecStart;      // Startadresse
12
volatile uint8_t* ptrRecEnd;        // Letzte Adresse + 1
13
volatile uint8_t* ptrRecWrite;          // aktuelle Schreibadresse
14
volatile uint8_t* ptrRecRead;          // aktuelle Leseadresse
15
uint16_t countData;

Leider auch ohne Erfolg. Das habe ich im Vorfeld auch schon mehrfach 
ausprobiert mal mit mal ohne usw..... volatile sollte an dieser Stelle 
natürlich verwendet werden.

Leider besteht das Problem mit den empfangenen Daten weiterhin. Ich 
verstehe nur leider nicht warum...

: Wiederhergestellt durch User
von Karl H. (kbuchegg)


Lesenswert?

Julian B. schrieb:

> Leider auch ohne Erfolg.

Logisch. Ist ja auch falsch geschrieben
1
uint8_t* volatile ptrTransStart;
2
...


Der Pointer Wert selber ist volatile. Nicht das worauf er zeigt.
D.h. eigentlich ist das auch volatile. Also
1
volatile uint8_t* volatile ptrTransStart;
2
...


Diese Modifier wirken immer von rechts nach links. Es sei denn, der 
Modifier steht schon ganz links, dann wirkt er auf das Teil rechts von 
ihm

1
uint8_t* volatile ptr;
Das Volatile bezieht sich auf den Pointer, denn der * steht links von 
ihm
1
     ptr
2
    +------+           +---+
3
    |  o-------------->|   |
4
    +------+           +---+
5
       ^
6
       | das hier ist volatile

1
uint8_t volatile * ptr;
Das volatile bezieht sich auf den uint8_t, denn der steht links von ihm. 
Der Pointerwert selber ist nicht volatile, wohl aber das worauf er 
zeigt.
1
     ptr
2
    +------+           +---+
3
    |  o-------------->|   |
4
    +------+           +---+
5
                         ^
6
                         | das hier ist volatile
1
volatile uint8_t * ptr;
selber Fall. das volatile bezieht sich auf den uint8_t, weil das 
volatile schon ganz links steht.


Du vergleichst die Pointer Werte (und nicht das worauf die Pointer 
zeigen). Ergo müssen die Pointer Werte volatile sein. Mit
1
volatile uint8_t * ptr;
sind sie es aber nicht.


Und zu guter letzt
1
volatile uint8_t * volatile ptr;
1
     ptr
2
    +------+           +---+
3
    |  o-------------->|   |
4
    +------+           +---+
5
       ^                 ^
6
       |                 | das hier ist volatile
7
       |
8
       | und das hier ist auch volatile

von jojo (Gast)


Lesenswert?

noch ne möglichkeit dem volatile zu entgehen (für teste obs daran 
liegt).

Ein nicht optimierter Code braucht in der Regel kein volatile d.h. wenn 
Du das Ding mit -O0 übersetzt und es läuft und be -O2 läufts nicht mehr, 
dann kanst Du davon ausgehen, irgendwo ein fehlendes volatile zu haben.

von Julian B. (zitrone18)


Lesenswert?

Hier der aktuelle Stand:

Volatile hat in keiner Form was gebracht (Habe alle ausprobiert) Bei den 
Version
1
volatile uint8_t * volatile ptr;
 schickt der Prozessor mir permanent 0x00.....

Die Optimierung habe ich mal ausgeschaltet. Bringt aber auch nichts, 
außer dass die Anfangswerte 0xAA,0xBB und 0xCC nicht mehr ausgegeben 
werden...

Ich werde mir da noch einige Gedanken zu machen.

von Karl H. (kbuchegg)


Lesenswert?

Julian B. schrieb:
> Hier der aktuelle Stand:
>
> Volatile hat in keiner Form was gebracht

Gut.
Nichts desto trotz gehört es da rein.

Sagt ja keiner, dass das das einzige Problem im Code ist.

von Svenska (Gast)


Lesenswert?

Ich würde statt Pointern übrigens mit Indizes rechnen.
Dann laufen die beiden Pointer von 0..BUFSIZE-1, was bei Zweierpotenzen 
ziemlich einfach zu berechnen ist. Auf die Daten greifst du dann mit 
buf[read_idx] zu.

von Julian B. (zitrone18)


Lesenswert?

Hey Svenska,

die Idee mit den Indizes hatte ich kurz vor Feierabend dann auch. Ist 
denke ich auch verständlicher als die Spielerei mit den Pointern...

Ich werde das morgen mal ausprobieren. Ich danke euch erstmal und werde 
berichten :)

Gruß

von Julian B. (zitrone18)


Angehängte Dateien:

Lesenswert?

Tag zusammen,

habe den Fehler gefunden... Er lag nicht an der Software.
Ich habe einen Kurzschluss auf meinem Board gehabt.
Zwischen RX und TX...

Den Fehler habe ich gefunden nachdem ich auf Indizes umgestiegen bin.
Im Anhang der Code mit Indizes...

Danke für eure Hilfe!

von Julian B. (zitrone18)


Angehängte Dateien:

Lesenswert?

Und hier noch die Version mit Pointern...(s. Anhang)

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.