Hallo, sorry für den bereits zweiten Code-Beitrag heute:
Ich versuche gerade das erste mal UART-Kommunikation zwischen PC und
AtMega644 umzusetzen. Einzelne Bytes senden und empfangen hat bereits
geklappt - Hardware und UART-Konfiguration sollte soweit also stimmen.
Nun Habe ich versucht einen Sende-Puffer einzurichten. Das Ziel:
Es sollen immer 3 Byte in den Puffer geschrieben und nacheinander
gesendet werden, während die nächsten drei Bytes in Vorbereitung sind.
Das ganze soll Interrupt-Gesteuert und ohne Polling passieren.
Für den Code habe ich mir auch schon
http://www.mikrocontroller.net/articles/Interrupt zu Gemüte geführt und
mich auch grob daran orientiert, wollte das ganze aber noch
spartanischer auf mich zugeschnitten einmal selber umsetzen.
Nur: Der Code läuft (natürlich) nicht, mal wieder die Frage warum.
Die Funktionalität sollte eigentlich einfach sein:
Ich habe einen default 3-Wort-block "data" (1. Byte 0xFF, 2. Byte 0xAA,
3. Byte 0xBB), der mit einem counter stück für stück gesendet wird -
unter Verwendung des UDRE (USART Data register empty= Flag-Interrupts.
Immer wenn ein Byte raus ist wird der Interrupt neu aufgerufen und das
nächste Byte verschickt, bis der counter >2 ist - dann wird der counter
auf 0 gesetzt und der UDRIE ausgeschaltet.
Wo habe ich einen fehler gemacht? Es scheint so, als ob die
ISR(USART0_UDRE_vect) Routine nicht aufgerufen wird (mal wieder
LED-Blink-Test)..
Hi,
UART Interrupt freigegeben? Hab das Datenblatt gerade nicht aber TIMSK
koennte das richtige register sein. Dort steht auch ob der Interrupt
ueberhaupt beim Senden geht, ich hab ihn bisher nur fuer RX verwendet.
//hufnala
>transmit_string(&uart_tx_flag...
Warum dieser Umweg mit der Adresse vom flag? Übergebe doch einfach das
Byte?! Deine Variante erzeugt sogar noch mehr Code und längere Laufzeit,
wenngleich das hier nicht wichtig ist.
Ich würde das Rad auch nicht neuerfinden. Saubere Implementationen für
Ringbuffer findest du in der Softwaresammlung.
Gruß Jonas
/* Enable receiver and transmitter, Set Interrupts: RXCIE - RX-Complete, TCVIE - TX-Complete */
11
UCSR0B=(1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);
12
/* Set frame format: 8data, 2stop bit */
13
UCSR0C=(1<<USBS0)|(3<<UCSZ00);
14
15
}
Jonas Biensack schrieb:> Warum dieser Umweg mit der Adresse vom flag? Übergebe doch einfach das> Byte?!
ich bin nicht sicher ob ich dich richtig verstehe aber:
Ich übergebe die adresse vom flag (und nicht das flag) nur, weil die
methode in einem anderen file steht und die variable dort nicht
deklariert ist.
Das mit flag und buffer habe ich eigentlich von der idee her (wenn ichs
denn richtig gemacht habe) von
http://www.mikrocontroller.net/articles/Interrupt abgeguckt...
Die transmit funktion enabled ja im wesentlichen nur den UDRE-Interrupt,
damit so lange vom buffer in das UDR0 register geschaufelt wird, bis der
buffer leer ist.
Ich würde mich aber nicht wundern wenn es klügere implementierungen gibt
als meine, ich bin da ja anfänger. nur trotzdem sollte der code ja
laufen, wenn auch nicht zeitoptimal meinetwegen...?
Alex v. L. schrieb:> ich bin nicht sicher ob ich dich richtig verstehe aber:> Ich übergebe die adresse vom flag (und nicht das flag) nur, weil die> methode in einem anderen file steht und die variable dort nicht> deklariert ist.
Wen kümmerts?
Die Funktion kriegt ja bei
1
voidfoo(inti)
2
{
3
printf("%d",i);
4
}
5
6
intmain()
7
{
8
intj=7;
9
10
foo(j);
11
}
ja sowieso nie zu sehen, dass der Aufruf von foo mit j gemacht wurde.
Der Funktion wird der Wert 7 übergeben, der vom Aufrufer aus j geholt
wird, an die Funktion übergeben wird, und den die Funktion sich für sich
selbst in i ablegt.
Die Funktion muss nicht wissen, dass es in main ein j gibt und das von
dort der Wert für ihren Aufruf herstammt.
> Die transmit funktion enabled ja im wesentlichen nur den UDRE-Interrupt,> damit so lange vom buffer in das UDR0 register geschaufelt wird, bis der> buffer leer ist.
Das müsste man jetzt genauer analysieren.
Grundsätzlich ist die Versteifung auf die 3-er Sequenzen schon mal
etwas, was man anzweifeln kann. Bringt eigentlich nichts. D.h. man würde
einen Buffer Mechanismus schreiben, der erst mal mit einzelnen Bytes
umgehen kann. Das du als Aufrufer dann jeweils gleich immer 3 Aufrufe
machst um Bytes einzustellen, ja das ist dein Bier als Aufrufer. Aber es
ist nichts, was den Buffermechanismus jetzt groß kümmern müsste.
Es gibt derartige IMplentierungen. Zb ist in der UART Lib vom P.Fleury
eine ethalten. Vielleicht möchtest du ja die mal studieren wie die
arbeitet, ehe du dich dann selber daran versuchst?
Hi,
>ja ist freigegeben,>in der UART_Init(); die nicht im code drin ist oben: void UART_Init()
.
.
> /* Enable receiver and transmitter, Set Interrupts: RXCIE - RX->Complete,
TCVIE - TX-Complete */
> UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);> /* Set frame format: 8data, 2stop bit */> UCSR0C = (1<<USBS0)|(3<<UCSZ00);
Das sehe ich aber anders, oder kann ich nicht lesen?
RXCIE ist nicht UDRIE
Bit 7 – RXCIEn: RX Complete Interrupt Enable
Bit 5 – UDRIEn: USART Data Register Empty Interrupt Enable
Bit 7 6 5 4 3 2 1 0
RXCIEn TXCIEn UDRIEn RXENn TXENn UCSZn2 RXB8n TXB8n UCSRnB
viel Erfolg, Uwe
Alex v. L. schrieb:
Da ist auch noch ein Bock
> void transmit_string(volatile uint8_t *uart_tx_flag, char> *uart_tx_buffer[], char data[3])> {
...
> uart_tx_flag = 0; // Delete "Sent-Flag"
Ich denke ehrlich gesagt nicht, dass derartige Mechanismen momentan
schon etwas für dich sind.
Soalnge du derart eklatante Schwächen in grundlegenden C Dingen hast,
solltest du ehrlich gesagt besser ein C-Buch durcharbeiten und die
Übungen da drinnen machen (auf dem PC), als dich mit weiterführenden
Konzepten auf einem AVR beschäftigen. Da klafft ein scheinentorgrosses
Wissensloch, das erst gestopft werden sollte.
Und ja. Das Argument muss ein Pointer sein. Wenn sich auch deine
Begründung dafür ein wenig hahnebüchern liest.
Eine ganz kurze generelle Frage, die mich beim datenblattlesen und coden
gerade noch einmal stutzig gemacht hat:
Das UDR-Register besteht aus eigentlich zwei 8-Bit registern - einem
Empfangs- und einem Senderegister - oder nur EINEM 8 Bit register?
Ich lese ja aus UDR wenn ich einen RXC-Interrupt bekomme und schreibe
wenn mir der UDRE-Interrupt zeigt, dass das register leer ist - aber
doch wohl nicht beide male auf das selbe register?
Wenn es zwei sind - wieso haben sie dann nur einen namen? -
unterscheidet der µC durch die Lese/schreibaktion dann auf welches
zugegriffen wird, dient das ganze also der simplifizierung?
Im Datenblatt des Atmega644 auf s.165 wird im USART-Block Diagramm ja
UDR(Transmit) und UDR(Receive) unterschieden.
Wenn es ein und das selbe ist: wie wird dann verindert, dass beim senden
und empfangen gleichzeitig das selbe register beschrieben wird?
Alex v. L. schrieb:> Das UDR-Register besteht aus eigentlich zwei 8-Bit registern - einem> Empfangs- und einem Senderegister - oder nur EINEM 8 Bit register?
Genau
> Ich lese ja aus UDR wenn ich einen RXC-Interrupt bekomme und schreibe> wenn mir der UDRE-Interrupt zeigt, dass das register leer ist - aber> doch wohl nicht beide male auf das selbe register?
Nö. Wozu auch.
Aber es ist völlig klar, dass beim Schreiben das eine Register gemeint
ist und beim Lesen das andere. Also kann man die beiden Register an eine
gemeinsame Speicheradresse legen und durch die Art des Zugriffs
(Schreiben oder Lesen) entscheiden, welches von beiden gemeint ist.
>> Wenn es zwei sind - wieso haben sie dann nur einen namen?
Weil das Adressen einspart und der "Preis" dafür akzeptabel ist. Man
verliert die Möglichkeit aus dem Sende-UDR auslesen zu können, was
eigentlich gesendet wird. Das interessiert aber sowieso keinen, denn das
Programm hat ja den Wert selber reingeschrieben. Der muss aber von
irgendwoher gekommen sein und daher weiß man auch was man
reingeschrieben hat ohne im Schreibe-UDR nachsehen zu müssen.
Auf der anderen Seite macht es keinen Sinn, etwas in den Lese-UDR
einschreiben zu wollen. Aus diesem UDR kommt das raus, was die UART
empfangen hat. Wozu soll ich da was reinschreiben?
>Das mit flag und buffer habe ich eigentlich von der idee her (wenn ichs>denn richtig gemacht habe) von>http://www.mikrocontroller.net/articles/Interrupt abgeguckt...>Die transmit funktion enabled ja im wesentlichen nur den UDRE-Interrupt,>damit so lange vom buffer in das UDR0 register geschaufelt wird, bis der>buffer leer ist.
Doch wird dort nirgends ein einzelnes Byte über einen Pointer als
Parameter übergeben, das macht auf 8-Bit Systemen einfach keinen Sinn
weil
>Deine Variante erzeugt sogar noch mehr Code und längere Laufzeit,>wenngleich das hier nicht wichtig ist.
Jonas Biensack schrieb:> Parameter übergeben, das macht auf 8-Bit Systemen einfach keinen Sinn> weil>>Deine Variante erzeugt sogar noch mehr Code und längere Laufzeit,>>wenngleich das hier nicht wichtig ist.
Es würde dann Sinn machen, wenn man hier
if(&uart_tx_flag==1)// check whether last string has been sent completely
4
{
5
for(inti=0;i<3;i++)
6
{
7
uart_tx_buffer[i]=data[i];// Copy String into send buffer
8
}
9
uart_tx_flag=0;// Delete "Sent-Flag"
den Kapitalen Fehler beseitigen würde.
Auf der anderen Seite liegt da noch ein Konzeptfehler drüber.
Dieses uart_tx_flag hat im Grunde genommen in main() überhaupt nichts
verloren, sondern gehört zu den UART Routinen wodurch sich die ganze
Notwendigkeit es zu übergeben, sofort in Luft auflösen würde.
Hier fehlt es einfach unter anderem an grundlegenden Fertigkeiten bzw.
Übung und Erfahrung, wie man sich Module baut, speziell wenn die in ein
eigenes C-File ausgelagert werden. Gepaart mit einigen C-Schwächen ist
das dann eben eine brisante Mischung.
Alex v. L. schrieb:> Nun Habe ich versucht einen Sende-Puffer einzurichten. Das Ziel:> Es sollen immer 3 Byte in den Puffer geschrieben und nacheinander> gesendet werden, während die nächsten drei Bytes in Vorbereitung sind.> Das ganze soll Interrupt-Gesteuert und ohne Polling passieren.
Das hört sich umständlich an. Nimm lieber einen kleinen Ringpuffer/FIFO,
das ist die Standardlösung, und braucht neben dem Buffer nur zwei
Indizes für Producer und Consumer.
So ein Puffer ist beim Empfangen aber wichtiger, denn da gibt der Sender
das Timing vor; wenn der ohne Pause ein Byte nach dem anderen sendet,
musst du hinterher kommen. Wenn du selbst sendest, ist das Timing
unkritisch.
>Das hört sich umständlich an. Nimm lieber einen kleinen Ringpuffer/FIFO,>das ist die Standardlösung, und braucht neben dem Buffer nur zwei>Indizes für Producer und Consumer.
sag ich doch:
>>Ich würde das Rad auch nicht neuerfinden. Saubere Implementationen für>>Ringbuffer findest du in der Softwaresammlung.>Auf der anderen Seite liegt da noch ein Konzeptfehler drüber.>Dieses uart_tx_flag hat im Grunde genommen in main() überhaupt nichts>verloren, sondern gehört zu den UART Routinen wodurch sich die ganze>Notwendigkeit es zu übergeben, sofort in Luft auflösen würde.
Eben.
>Hier fehlt es einfach unter anderem an grundlegenden Fertigkeiten bzw.>Übung und Erfahrung, wie man sich Module baut. Gepaart mit einigen>C-Schwächen ist das dann eben eine brisante Mischung.
100 % ack
Gruß Jonas
Die Ringbuffer-Implementierungen haben schon einige Tricks, die die
Performance massiv steigern, auf die kommst DU nie. Also wenn man keine
Ahnung hat lieber mal über den leeren Tellerrand schauen.
Gruß Jonas
Also ich habe mir eure Kommentare zu Herzen genommen und seit heute
morgen mal eine Ringpufferlösung programmiert. die funktioniert auch
grundsätzlich, nur bin ich jetzt am Macken ausbessern - wenn ich nämlich
den unten eingefügten code zur kontrolle durchlaufen lasse, kommt am
Terminal die dezimal-zahlenreihe (ACHTUNG, LANG):
0
0
1
2
3
4
5
6
7
8
9
10
11
12
13
0
16
17
18
19
20
21
22
23
24
25
26
27
28
29
0
0
32
33
34
35
36
37
38
39
40
41
42
43
44
45
0
0
48
49
50
51
52
53
54
55
56
57
58
59
60
61
0
0
64
65
66
67
68
69
70
71
72
73
74
75
76
77
0
0
80
81
82
83
84
85
86
87
88
89
90
91
92
93
0
0
96
97
98
99
an. Man sieht: Da sind Nullen wo keine hingehören! ;-) Für tips bin ich
außerordentlich dankbar, auch wie man die hier nun gepostete
-->bisherige Lösung noch weiter verbessern kann:
1
/*.............RINGPUFFER.............*/
2
structcirc_buffer{
3
uint8_tdata[buffer_size];
4
uint8_tread_ptr;// points to last input data
5
uint8_twrite_ptr;// always points to empty field
6
uint8_tfillcount;
7
};
8
9
voidbuffer_init(structcirc_buffer*buf)// Initialization of circular buffer values
10
{
11
buf->fillcount=0;
12
buf->read_ptr=buffer_size;
13
buf->write_ptr=0;
14
}
15
16
voidbuffer_write(structcirc_buffer*buf,uint8_tbyte)// Write byte into buffer, increment fillcounter and write pointer
17
{
18
buf->data[buf->write_ptr]=byte;
19
buf->fillcount++;
20
21
if(buf->write_ptr>=buffer_size)
22
buf->write_ptr=0;
23
else
24
buf->write_ptr=buf->write_ptr+1;
25
}
26
27
uint8_tbuffer_read(structcirc_buffer*buf)// Read byte out of buffer, decrement fillcounter, increment read ptr
Das sieht finde ich schon einigermaßen viel übersichtlicher aus.
In der testschleife nutze ich nur den TX-Buffer und lese keine bytes.
Grundsätzlich ist es aber so gedacht, dass Interrupt-Gesteuert UDR
gelesen und beschrieben wird (aus und in die zwei Ringpuffer) und in der
main diese puffer bearbeitet. Sinnvoll?
Jonas Biensack schrieb:> Also wenn man keine> Ahnung hat lieber mal über den leeren Tellerrand schauen.
Ich bin nicht sicher, was du mir damit sagen willst - ganz so leer ist
der teller gar nicht - nur die Seite vom Gemüse (C-Programmierung) ist
bisher eben beschränkt und muss noch gefüllt werden. Zum Füllen aber bin
ich ja HIER! ;)
Karl Heinz schrieb:> Ich denke ehrlich gesagt nicht, dass derartige Mechanismen momentan> schon etwas für dich sind.> Soalnge du derart eklatante Schwächen in grundlegenden C Dingen hast,> solltest du ehrlich gesagt besser ein C-Buch durcharbeiten und die> Übungen da drinnen machen (auf dem PC), als dich mit weiterführenden> Konzepten auf einem AVR beschäftigen.
Dem würde ich an der Stelle mal klar widersprechen und zwar:
Ich habe schon C/C++ Bücher durchgearbeitet, nur ist das schon ganz
schön her. Die µC Programmierung ist für mich bisher immer Mittel zum
Zweck gewesen - und auch hier wieder. Ich muss mich dann allerdings
jedes mal wieder neu reinfummeln - und mache auch immer erstmal wieder
ähnliche Fehler bis ich mich wieder eingearbeitet habe.
Das UART-Kommunikationsmodul brauche ich eigentlich nur um eine ganz
andere Hardware zu unterstützen, damit ich die damit gemessenen Signale
auf den PC bekomme.
Ich finde es eigentlich eher spannend mir verschiedene grundlagen durch
größere Projekte anzueignen, auch wenn der weg umso steiniger ist (durch
mehr flüchtigkeits und dummheitsfehler), sonst fehlt mir die Motivation.
Gerade bin ich sehr motiviert! ;-)
Alex v. L. schrieb:> void buffer_init (struct circ_buffer *buf) // Initialization of> circular buffer values> {> buf->fillcount=0;> buf->read_ptr=buffer_size;> buf->write_ptr=0;> }
read_ptr und write_ptr sollten beide mit 0 initialisiert werden, sonst
haut das nicht hin. fillcount ist unnötig.
Alex v. L. schrieb:> if (buf->write_ptr>= buffer_size)> buf->write_ptr = 0;> else> buf->write_ptr = buf->write_ptr + 1;
buf->write_ptr = (buf->write_ptr + 1) % buffer_size;
ist kürzer und klarer.
Keine Ahnung was da konkret nicht klappt, hab nur mal kurz
drübergeschaut und das ist mir aufgefallen.
greg schrieb:> read_ptr und write_ptr sollten beide mit 0 initialisiert werden, sonst> haut das nicht hin.
ok, gemacht. kommt allerdings das selbe raus am terminal wie vorher
greg schrieb:> fillcount ist unnötig.
Ja ich weiß, auf der mikrocontroller.net-FiFo Seite ists auch ohne
gemacht. Ich habs drin weil mein Kleingeist das besser versteht ;-)
Danke für deine Anmerkungen!
Eine Sache noch: immer erst die Daten lesen/schreiben, und danach erst
read_ptr/write_ptr/fillcount aktualisieren. Sonst hast du eine race
condition! Wenn der Interrupt in einem ungünstigen Augenblick feuert,
dann hat dein Ringbuffer sonst einen inkonsistenten Zustand. Das ist
insgesamt recht tricky.
Einfachere Lösung: Interrupts kurzzeitig deaktivieren.
>Eine Sache noch: immer erst die Daten lesen/schreiben, und danach erst>read_ptr/write_ptr/fillcount aktualisieren. Sonst hast du eine race>condition! Wenn der Interrupt in einem ungünstigen Augenblick feuert,>dann hat dein Ringbuffer sonst einen inkonsistenten Zustand. Das ist>insgesamt recht tricky.>Einfachere Lösung: Interrupts kurzzeitig deaktivieren.
Um wieder nur einen Teil der ganzen Wahrheit preiszugeben.
Also wenn es wirklich nur darum geht, den Algorithmus der
Implemtierungen zu verstehen, verstehe ich deine Mühe. Aber ganz ehrlich
das ist doch unwichtig.
Ich meine, ein Ringbuffer ist doch meist ein nur kleiner Teil einer viel
größeren Anwendung. Oder in welchem Rahmen findet das alles statt?
Viele Grüße
P.S. Unterschätzt nicht dein Wissen! :D
Alex v. L. schrieb:> Dem würde ich an der Stelle mal klar widersprechen und zwar:> Ich habe schon C/C++ Bücher durchgearbeitet, nur ist das schon ganz> schön her.
red nicht um den heissen Brei rum.
Wer bei Argumentübergabe an Funktion bzw. deren Weiterverwendung in der
Funktion Schwächen hat, hat ganz einfach ein Basis-Problem.
Da diskutiere ich nicht drüber.
>red nicht um den heissen Brei rum.>Wer bei Argumentübergabe an Funktion bzw. deren Weiterverwendung in der>Funktion Schwächen hat, hat ganz einfach ein Basis-Problem.>Da diskutiere ich nicht drüber.
Jetzt wird'r böss.
Auch noch'm Karl-Heinz sein Middag versauen und kein C-können. Oh oh,
ich seh schwarz :D
Nur Spass, schönes Wochenende euch!
AFK Jonas
greg schrieb:> Eine Sache noch: immer erst die Daten lesen/schreiben, und danach erst> read_ptr/write_ptr/fillcount aktualisieren. Sonst hast du eine race> condition! Wenn der Interrupt in einem ungünstigen Augenblick feuert,> dann hat dein Ringbuffer sonst einen inkonsistenten Zustand. Das ist> insgesamt recht tricky.
Danke, umgesetzt.
Jonas Biensack schrieb:> Oder in welchem Rahmen findet das alles statt?
Der Rahmen: Ein eigenes kleines ADC Board. Darauf: Ein Atmega644, ein
LTC2468 16 Bit ADC und ein AMB2300 Bluetoothmodul.
Ziel: (beliebige) Analogdaten samplen und an den PC per bluetooth
senden.
Board steht, software eben noch nicht. da gibts drei schritte
1. UART einarbeiten (grade dran)
2. SPI einarbeiten (ADC, folgt)
3. ADC-Werte über UART-Schnittstelle ans Bluetoothmodul.
Karl Heinz schrieb:> Da diskutiere ich nicht drüber.
In ordnung. Ich werde mir meine Basisprobleme trotzdem an größeren
zielen austreiben! Bislang hat das ganz gut funktioniert..
Frust-Tolerant bin ich ;-)
P.S. Die Fehler habe ich durchaus noch entdeckt.
>Der Rahmen: Ein eigenes kleines ADC Board. Darauf: Ein Atmega644, ein>LTC2468 16 Bit ADC und ein AMB2300 Bluetoothmodul.
Mit Rahmen meinte ich eher deinen "persönlichen Rahmen", Vorkenntnisse
und Ausbildung etc. Sonst hätte ich vermutlich eher Board oder
Evaluationsboard oder so geschrieben.
Wie sieht's damit aus?
Also für die Uni, oder für dich, dein Kumpel, oder Karl-Heinz ;)?
Man "Etwas jemandem aus der Nase ziehen" ist bei dir schon fast
übertrieben. :D
Gruß Jonas
Sorry ich scheine nur deine Fragen nie richtig zu deuten! :D
Eine Mischung. Das Gesamtprojekt nennt sich Masterarbeit, das was ich
grade mache ist aber im Prinzip ein eigenes oben drauf (was mir auch
evaluieren helfen soll) ;-)
Fehlt noch was?
Jonas Biensack schrieb:> Sag doch einfach du bist fast "Elektroingenieur" und kannst keinen MC> dazubringen ein Signal in einen Buffer zu schreiben?
war das jetzt ironie? ;)
Sagen wir so mit Augenzwinkern. Du musst, wenn du ein guter Ingenieur
werden willst, verstehen, dass nur Erfahrung hilft so cool zu bleiben
das man alle Probleme überblicken kann. Im Umkehrschluss verfängst du
dich ohne Erfahrung in allen möglichen nur erdenklichen Problemen. Oder
um es mal anders zu formulieren, ein fleißiger Bastler bringt das Ding
an einem Tag zum laufen, ohne jemals eine Uni betretten zu haben. Um
also das massive Fachwissen was die Uni mit sich bringt zu nutzen, musst
du tun. Du braucht Interesse, das ist viel wichtiger, such dir eigene
Projekte. Nur dass Zeug für die Uni reicht nicht, das willst du auch gar
nicht. geb gas man.
Gruß Jonas
Jonas Biensack schrieb:> Nur dass Zeug für die Uni reicht nicht, das willst du auch gar> nicht. geb gas man.
Haha danke, ganz meine Einstellung. Womit wir wieder bei dem Grund
meiner Anwesenheit und dem Forenbeitrag sind :D
>Haha danke, ganz meine Einstellung. Womit wir wieder bei dem Grund>meiner Anwesenheit und dem Forenbeitrag sind :D
Ok digga. Dann ziehen wir das jetzt durch. Ich helf dir.
Anforderung nochmal genau, bitte jetzt mit den neuen Erkenntnissen:
-Samplen...
-Ringbuffer...
...
Gruß jonas
>Es sollen immer 3 Byte in den Puffer geschrieben und nacheinander>gesendet werden, während die nächsten drei Bytes in Vorbereitung sind.>Das ganze soll Interrupt-Gesteuert und ohne Polling passieren.
DAs ganze macht nur Sinn wenn die berechnung der 3 bytes fast unendlich
dauert, was wird da berechnet der Bauchumfang von cyblords ma?
gruß Jonas
;)
Also der µC wird zum schluss
- einzelne (wenige ~16) Konfigurationsbytes vom PC verarbeiten müssen,
der empfangspuffer ist also unkritisch. Das wird eine einfache
Switch-Case geschichte, die z.B. den Kanal des ADC wählt. unkritisch.
- Mit vorgegebenem Takt (über Timer, kenne ich auch - unkritisch) den
ADC wert eines kanals des LTC2468 abrufen über SPI (kenne ich noch nicht
- wird kritisch ;-) und direkt in den Sendepuffer des UART kanals
packen. Der ADC hat 16 bit werte, davor soll ein Byte konfigdaten (kanal
etc). Also: Pro Messung drei Bytes.
Tatsächlich ist die UART geschichte für mich soweit vollständig geklärt
und umgesetzt, sobald der Puffer einwandfrei funktioniert. Und der
knarzt gerade nur noch an einer Stelle, die mit den write/read pointern
zu tun haben muss. Wenn du mir ein schafes auge für den Debug leihen
willst freue ich mich natürlich sehr. Der aktuelle Code auf dem PC
(kommt unten nochmal) inkrementiert eine zahl und steckt sie in den
puffer, damit ich sehe ob alles richtig klappt. Tut es noch nicht - und
zwar immer bei den Sprüngen auf den Anfang des Puffers zurück - dann
kommt eine Null. Mit einer Ausnahme: Dem ersten Durchlauf, der klappt.
Konkreter auszug:
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
0
18
19
20
21
22
23
24
25
0
27
28
29
30
31
32
33
34
0
...
Der Puffer ist jetzt unter Berücksichtigung der meisten Rückmeldungen so
aufgebaut:
1
structcirc_buffer{
2
uint8_tdata[buffer_size];
3
uint8_tread_ptr;// points to last input data
4
uint8_twrite_ptr;// always points to empty field
5
uint8_tfillcount;
6
};
7
8
#include"circbuf.h"
9
10
voidbuffer_init(structcirc_buffer*buf)// Initialization of circular buffer values
11
{
12
buf->fillcount=0;
13
buf->read_ptr=0;
14
buf->write_ptr=0;
15
}
16
17
voidbuffer_write(structcirc_buffer*buf,uint8_tbyte)// Write byte into buffer, increment fillcounter and write pointer
18
{
19
buf->data[buf->write_ptr]=byte;
20
21
buf->fillcount++;
22
if(buf->write_ptr>=buffer_size)
23
buf->write_ptr=0;
24
else
25
buf->write_ptr=buf->write_ptr+1;
26
}
27
28
uint8_tbuffer_read(structcirc_buffer*buf)// Read byte out of buffer, decrement fillcounter, increment read ptr
29
{
30
uint8_treturnval=0;
31
32
if(buf->fillcount>0)
33
{
34
returnval=buf->data[buf->read_ptr];
35
36
if(buf->read_ptr>=buffer_size)
37
{
38
buf->read_ptr=0;
39
}
40
else
41
buf->read_ptr=buf->read_ptr+1;
42
43
buf->fillcount--;
44
returnreturnval;
45
}
46
elsereturn0;
47
}
48
49
boolbuffer_full(structcirc_buffer*buf)
50
{
51
if(buf->fillcount==buffer_size)
52
returntrue;
53
elsereturnfalse;
54
}
55
56
boolbuffer_empty(structcirc_buffer*buf)
57
{
58
if(buf->fillcount==0)
59
returntrue;
60
elsereturnfalse;
61
}
wie gesagt - und wie ganz oben im codebeispiel: In der main passiert im
wesentlichen
1
if(number<100)
2
{
3
buffer_write(&uart_tx_buffer,number);
4
number++;
5
_delay_ms(100);
6
}
Wenn das läuft bin ich schon ziemlich glücklich, der rest ist
fleißarbeit.
Offen ist nur noch die Anmerkung von greg mit den race-conditions:
Ich habe jetzt lesen/schreiben immer vor den
dekrementierungen/inkrementierungen gemacht aber
greg schrieb:> Einfachere Lösung: Interrupts kurzzeitig deaktivieren.
die interrupts noch laufen...
greg schrieb:
> Einfachere Lösung: Interrupts kurzzeitig deaktivieren.
die interrupts noch laufen...
Um erst mal den Ball wieder zurück zu spielen, du weisst wie man
Interrupts global aktiviert und deaktiviert?
Davon sehe ich gerade nichts?
Oder hast du den Hazard gelöst?
Gruß Jonas
ja weiß ich, ist aber ja noch nicht umgesetzt.
ich kann gerne mal ein sei() und cli() einbauen aber ich dachte erstmal
nicht dass das am ringpufferverhalten in diesem fall was ändert - aber
vll ist das ja tatsächlich eine periodische race condition?.. mal
probieren
>ich kann gerne mal ein sei() und cli() einbauen aber ich dachte erstmal>nicht dass das am ringpufferverhalten in diesem fall was ändert - aber>vll ist das ja tatsächlich eine periodische race condition?.. mal>probieren
Das sind keine Endzeit-Phänomäne, sondern sowas bringt Raketen zum
Absturz. Da kann Morphy noch weiter schlafen und da hast Ärger damit.
Siehst du doch gerade :) So geil...
Gruß Jonas
ja, wars leider nicht.
habe am anfang der buffer_read und _write funktionen global
ausgeschaltet und am ende wieder ein. Das so zu lassen ist aber wegen
den race-c empfehlenswert?
und nein - hazard ist damit noch nicht gelöst. ;)
Alex sorry, bin erstmal afk from keyboard. Mein wauwau muss raus. BIn
heute abend wieder one, dann helf ich dir weiter gerne - aber du bist ja
der .Ing. :D
Gruß Jonas