Forum: Mikrocontroller und Digitale Elektronik timing problem bei arv-uart


von Patrick L. (drgonzo)


Lesenswert?

guten tag!

da ich hier neu bin, erstmal hallo an alle :)

so, nun zu meinem keinen problem:
ich steuere einen midi controller über den eingebauten UART vom AVR an, 
nun
ist es aber so, dass ich ein gewisses timing-problem habe!
die noten werden írgendwie unregelmäßig wiedergegeben...
zum berechnen des tempos (BPM) verwende ich den 16bit timer, der auch
recht gut arbeitet.
ich vermute das problem liegt an folgender codestelle:

void uart_putc(unsigned char c)
{
    while (!(UCSRA & (1<<UDRE)))
    {
    }

    UDR = c;
}

es scheint das " while (!(UCSRA & (1<<UDRE))) {} " sehr unregelmäsig in 
der ausführungszeit ist und somit für musikalische zwecke nicht zu 
gerauchen ist!

meine frage nun:

- wer hatte ähnliche probleme?
- gibt es einen schnelleren und sauberen weg serielle daten zu senden?

besten dank im vorraus!
mfg
drgonzo

von Johannes M. (johnny-m)


Lesenswert?

> - gibt es einen schnelleren und sauberen weg serielle daten zu senden?
Schneller nicht direkt. Das hängt nun mal von Deinen Settings ab. Aber 
Warteschleifen sind in zeitkritischen Anwendungen immer Mist, weil der 
µC z.B. in diesem Fall nichts anderes tun kann, während er wartet, bis 
das UDR leer ist. Ich kenne zwar den restlichen Code nicht und habe auch 
keine Ahnung von der Anwendung an sich, aber ich halte es für möglich, 
dass eine Verwendung des UDRE-Interrupt das Problem beheben könnte.

von Patrick L. (drgonzo)


Angehängte Dateien:

Lesenswert?

die warte-schleife ist nicht das problem. aber vielleicht bringts was, 
wenn ich den quelltext mit schicke, vielleicht ist es ja nur ein 
anfängerfehler!

zum quelltext: sequence.c ist das hauptprogramm.

von Florian D. (code-wiz)


Lesenswert?

_msg und _nc als volatile definieren.

von Patrick L. (drgonzo)


Lesenswert?

@ Florian Demski

danke für den hinweis!

das problem besteht aber dennoch...
der zeitabstand zwischen den einzelnen bytes, die gesendet werde ist 
einfach
unregelmäßig und sehr hoch...vielleicht versuche ich das mal über einen 
software uart....

von Falk (Gast)


Lesenswert?

@ Patrick Lindenberg (drgonzo)

>das problem besteht aber dennoch...
>der zeitabstand zwischen den einzelnen bytes, die gesendet werde ist
>einfach
>unregelmäßig und sehr hoch...

Wie hast du das gemessen? Mit dem Oszi?

>vielleicht versuche ich das mal über einen
>software uart....

Das is der flasche Weg. Der Hardware-UART ist WESENTLICH besser und auch 
genauer!

Hmm, habmal nen Blick auf deinen Code geworfen. Das ist aber schon ein 
wenig heiss, was du da gestrickt hast!

Du willst ja mit dem Timer einen gleichmässigen Takt erzeugen. Dein Code 
ist da aber nicht ganz korrekt. Du darfst nicht den Timer auf Null 
setzen, sondern du musst dem Compare-Wert um den berechneten Wert 
erhöhen!

OCR1A += 27700;

Das macht bei 16 MHz Takt und Vorteiler 64 ein Zeit von 110,8ms, oder 
9,02 Hz. Ist das so gewünscht?Ausserdem solltest du auf JEDEN Fall nur 
die Interrupts aktivieren, die auch benutzt werden. Du schaltest aber 
auch den Input Capture ein, hast dafür aber keine ISR. Da kann die CPU 
mal fix hängen bleiben! Also nur OCIE1A einschalten.

  TIMSK  = 0b00010000;

Der Rest ist erstmal soweit OK. Das mit volatile für _nc und _msg muss 
beibehalten werden.

MFG
Falk

P.S. Ich hoffe du hast ein 16 MHz Quarz bzw. Quarzoszillator im Einsatz.

von Michael U. (Gast)


Lesenswert?

Hallo,

ohne bis jetzt in Dein Programm geschaut zu haben:

void uart_putc(unsigned char c)
{
    while (!(UCSRA & (1<<UDRE)))
    {
    }

    UDR = c;
}

Die Funktion schickt die Daten sofort, wenn das Register leer ist.
Wenn also da unerwartete Pausen passieren, dann hat Dein Hauptprogramm 
eben noch keine Daten parat und uart_putc noch garnicht aufgerufen.

uart_enable(16000000, 19200);
Midi war doch irgendwas mit 31250 Baud, wenn ich nicht irre?

Gruß aus Berlin
Michael

von Willi W. (williwacker)


Lesenswert?

Hast Du denn einen Quartz ?

Wenn Du den internen Takt nimmt, der kommt aus einem RC-Glied, der ist 
SEHR temperaturabhängig und das hören dann auch Nicht-Karajans

von Patrick L. (drgonzo)


Angehängte Dateien:

Lesenswert?

so, nun erstmal ein großes dankeschön an alle :)

aber...ich habe alles probiert und beachtet...jedoch ohne erfolg.. :(

der quartz ist genau 16mhz (pollin-board)

es scheint immernoch so, dass zwichen note off und note on (also das 
senden
der midi kommados an die soundkarte) , die ja sequenziell passiert, eine 
unregelmäßigkeit herrscht. hier mal als beispiel einen auszug aus den 
MIDI rekorder am  rechner als anhang.

mit freundlicher ratlosigkeit
...

von Falk (Gast)


Lesenswert?

@ Patrick Lindenberg (drgonzo)

>aber...ich habe alles probiert und beachtet...jedoch ohne erfolg.. :(

Wirklich? Schick mal deinen aktuellen Sourcecode.

>der quartz ist genau 16mhz (pollin-board)

Passt.

>es scheint immernoch so, dass zwichen note off und note on (also das
>senden
>der midi kommados an die soundkarte) , die ja sequenziell passiert, eine
>unregelmäßigkeit herrscht. hier mal als beispiel einen auszug aus den

Die Frage ist, wird das bei MIDI überhaupt to gemacht? Rein vom Programm 
her sollten die Daten sehr gleichmässig geschickt werden. Ist die 
Baudrate OK?

Uups, ich sehe gerade. In deiner (arg auskommentierten) Funktion 
uart_enable(16000000, 19200); wird die Baudrate auf 16.000.000  16  
(32+1) = 30303,03 Baud gesetzt. Das ist ein Fehler von 3% Das ist 
zuviel! Du musst den Teiler auf 31! setzen (was effektiv ein Teiler von 
32 bedeutet), dann passt es mit 0% Fehler! Wenn du die Fuktion normal 
benutzt hättest, wäre das nicht passiert.

>MIDI rekorder am  rechner als anhang.

Was soll man auf dem Bild sehen?

MFG
Falk

von Patrick L. (drgonzo)


Lesenswert?

@Falk

danke erstmal.

so, die uart_enable ist nur zu testzwecken auskommentiert, hab alles 
manuell
errechnet. war die formel nicht: F_CPU / ( (BAUD*16) - 1) ? da komme ich
auf 32...komisch.
selbst mit 31 als teiler erkennt man keine merkliche verbesserung. 
leider.

auf dem bild sieht man deutlich den versatz zwischen noteoff und noteon, 
der
sehr unregelmäßig ist, normalerweise sollten die noten bündig sein, 
deswegen das bild als anhang.

so, werde heute abend mal einen software-uart schreiben...nur so zum 
testen.
als anhang der aktuelle source.

mfg
lindenberg

von Patrick L. (drgonzo)


Angehängte Dateien:

Lesenswert?

oha, der anhang...

von Falk (Gast)


Lesenswert?

Die Formel für die Baudrate lautet

Man beachte die Klammern.

Den Rest schau ich mir mal an.

MfG
Falk

P.S. So einen Soft-Uart programmiert man nicht mal so nebenbei. Aber 
wenns Spass macht . . . ;-)

von Falk (Gast)


Angehängte Dateien:

Lesenswert?

@  Patrick Lindenberg

Ich hab mir deinen Code mal ansgeschaut. Soweit war alles in Ordnung, 
wenn gleich die Form etwas zu wünschen übrig lässt.  ;-) Ich hab das 
Ganze mal auf nem MEGA32 umgesetzt und in realer Hardware getestet (auf 
dem Oszi den RS232 Ausgang angeschaut). Das Programm funktioniert 1A. 
Das Problem muss also woanders liegen. Was du jetzt prüfen solltest

- ist dein MIDI-Programm auf dem PC in Ordnung?
- kommt das Programm mit so schnellen Anschlägen klar? Was passiert bei 
niedrigeren BPMs?
- ist deine MIDI Sequenz in Ordnung? Sind die Codes der MIDI Kommandos 
OK?

MfG
Falk

P.S. Ich hab den Code ein wenig bereinigt, hier ein paar kleine 
Anmerkungen.

- es ist meist günstiger anstatt char/int etc. die Typen mit exakt 
definierter Länge zu benutzen die in stdint definiert sind, also 
uint8_t, uint16_t etc.

- die Funktion _delay_ms() ist ein Macro, das mit Fliesskommazahlen 
arbeitet. Das sollte man auf keinen Fall mit variablen Argumenten 
benutzen, sonst werden Fliesskommaoperationen eingebaut die massig 
Speicher kosten (~3kB) und die Verzögerungszeiten massiv erhöhen. Siehe 
hd44780.c Ausserdem muss die Codeoptimierung eingeschaltet sein.

- bei der UART Initialisierung sollte man auch mit dem define F_CPU 
arbeiten

von Patrick L. (drgonzo)


Lesenswert?

@ falk

danke erstmal für deine intesive hilfe!
ich bitte um nachsicht was meinen C code betrifft, ich habe jahrelang
pascal programmiert und bin neu bei C!

irgendwie habe ich das gefühl, dass das problem bei meinem midi nach usb 
adapter ist. ich werde nächste woche einen versuch starten mit einem 
nativen
midi-kabel und nochmal bescheid geben, ob sich was ändert.

bis dahin...

von Michael U. (Gast)


Lesenswert?

Hallo,

@Patrick Lindenberg: nur interessahalber, bin kein Musikus, hatte nur 
mit Midi und Computer öfter zu schaffen...
Midi an USB geht? Sind da nicht durch USB prinzipiell die Latenzzeiten 
untragbar? Welche Trick habe die Hersteller da benutzt?

Gruß aus Berlin
Michael

von Der Hubert (Gast)


Lesenswert?

>> ich habe jahrelang pascal programmiert und bin neu bei C!

Auch ein Pascal Programmierer sollte sich gewisse Codestrukturen 
angewöhnen .... ;):D

Hat ja nix mit der Sprache zu tun, wenn Du im Quelltext "rumsaust".

von Patrick L. (drgonzo)


Angehängte Dateien:

Lesenswert?

guten tag die herrschaften!

nun nochmal in großes danke (besonders an den herrn falk) für die nette 
unterstützung!!!

ich habe mittlerweile das problem gelöst, es liegt tatsächlich am 
midi-programm, das wohl ein timing problem hat. naja...

so und nun zum neuen problem:

ich möchte ein paar analoge drehregler "midifizieren" und versuche diese 
am
adc-port PA0-7 auszulesen. klappt prima, aber nur einmal nach dem reset 
des controllers. nun ist meine frage was mache ich falsch??? bit's im 
register
nich richtig gesetzt? ISR verkehrt?

wie immer besten dank im vorraus!
(quelltext im anhang)

ps. @falk:
die formel für den richtigen timer ist (F_CPU/PRESCALE)/(4*bpm/60)
da: 135bpm sind 135 virtel-noten / min, da ich aber mich 16'tel arbeite
noch mal 4.

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.