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
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
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 | }
|
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.
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.
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
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 |
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.
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.
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.
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.
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ß
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!
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.