Guten Tag! AVR hat USART. Ich lese aber überall nur, wie man USART asynchron verwendet. Für mich wäre es aber interessant, USART synchron zu betreiben, da schnellere Datenübertragung möglich wird und auch braucht dann Slave nicht unbedingt mit Quarz getaktet zu sein. Die Frage nun: wie kann man am besten mehrere AVR miteinander verbinden? Master wird inner nur einer. Und so etwa von 10 bis 20 Slave. Wie kann man aber viele Slave adressieren? Mit Hilfe von 74HC138 für jeden separate Takt erzeugen oder kann man das besser machen? Mein Ziel ist, innerhalb von 1-2 ms 512-Block zu schicken. Ich nehme an, für I2C ist das schon zu viel? SPI kommt leider nur schwer in Frage, da ich MK auf der Platte programmieren möchte. So kann ich SPI nur mit zusätzlichen Schalter zusammenführen, das sieht nicht schön aus. Vielen Dank im voraus für Erklärung!
@Maxim B. (max182) >Die Frage nun: wie kann man am besten mehrere AVR miteinander verbinden? >Master wird inner nur einer. Und so etwa von 10 bis 20 Slave. Ganz schöne viele. >Wie kann >man aber viele Slave adressieren? Bei SPI braucht man für jeden Slave ein chip select Signal. >Mit Hilfe von 74HC138 für jeden >separate Takt erzeugen Sicher nicht, eher das chip select erzeugen. > oder kann man das besser machen? Mein Ziel ist, >innerhalb von 1-2 ms 512-Block zu schicken. 512 was? Äpfel, Birnen oder gar Melonen? Bits oder Bytes? >Ich nehme an, für I2C ist das schon zu viel? Rechnung? 512 Bytes/MS = 512kB/s ~ 4Mbit/s Das kann I2C nicht mehr, da braucht man SPI. >SPI kommt leider nur schwer in Frage, da ich MK auf der Platte >programmieren möchte. MK? Makulatur? >So kann ich SPI nur mit zusätzlichen Schalter >zusammenführen, das sieht nicht schön aus. Wie meinen? SPI kann man problemlos nutzen, auch wenn man die AVRs per ISP programmieren will. Dazu braucht es keine Schalter, "nur" Knoff Hoff. https://www.mikrocontroller.net/articles/AVR_In_System_Programmer#ISP-Pins_am_AVR_auch_f.C3.BCr_andere_Zwecke_nutzen Warum willst du 10-20 Mikrocontroller vernetzen?
Maxim B. schrieb: > SPI kommt leider nur schwer in Frage, da ich MK auf der Platte > programmieren möchte. So kann ich SPI nur mit zusätzlichen Schalter > zusammenführen, das sieht nicht schön aus. Dann hast du SPI nicht verstanden...
Maxim B. schrieb: > Für mich wäre es aber interessant, USART synchron zu > betreiben, da schnellere Datenübertragung möglich wird und auch braucht > dann Slave nicht unbedingt mit Quarz getaktet zu sein Das ist wohl beides ein Irrtum, dafür wird die Sache wesentlich komplizierter - es hat schon seinen Grund, warum synchrone Protokolle nahezu ausgestorben sind. Für ein Byte werden zwar nur 8 bit statt 10 gebruacht, aber ein wesentlicher Unterschied ist das ja nicht, und ausserdem kommt vor dem Datenblock noch eine Einleitung aus mehreren Bytes dazu. Und der Takt muss ABSOLUT synchron sein, also wird er mitübertragen oder aus den Daten regeneriert, die Anfordungen sind wesentlich höher als bei asynchron, ein Quarztakt genügt dafür nicht. Maxim B. schrieb: > Wie kann > man aber viele Slave adressieren? Genauso wie asynchron: indem man sich ein eigenes Protokoll schreibt und einen Bus verwendet anstatt eine Direktverbindung. Nicht zuletzt ist es eine erhebliche Einschränkung, wenn man nur Controller mit synchronen Modi verwenden kann. Georg Georg
Falk B. schrieb: > SPI kann man problemlos nutzen, auch wenn man die AVRs per > ISP programmieren will. Dazu braucht es keine Schalter, "nur" Knoff Das kann ich mir schlecht vorstellen. Wenn auf der Platte z.B. 8 AVR stehen und SCK, MISO und MOSI zusammen geschaltet sind, wie unterscheide ich, welche Kontroller gerade programmiert wird? Beim Programmieren gibt es ja kein SS! Einziges, was in Kopf kommt: bei jedem AVR zusätzlich noch ein Dip-Schalter einlöten und somit diese Linien beim Programmieren voneinander trennen. Schön ist das aber nicht.
:
Bearbeitet durch User
Maxim B. schrieb: > Wenn auf der Platte z.B. 8 AVR > stehen und SCK, MISO und MOSI zusammen geschaltet sind ...ist das Ganze bereits "broken by Design"
georg schrieb: > Nicht zuletzt ist es eine erhebliche Einschränkung, wenn man nur > Controller mit synchronen Modi verwenden kann. Ich möchte ATMEGA644PA und ATMEGA1284P verwenden. Die haben zwei USART, beide haben XCK-Pin.
Falk B. schrieb: > Warum willst du 10-20 Mikrocontroller vernetzen? Weil ich mit STM32 noch nicht vertraut bin. Ich möchte Möglichkeit haben, die Fehler mit Simulator zu überprüfen. Geschwindigkeit von AVR reicht nur, wenn die Aufgabe auf mehrere geteilt wird. Grob gesagt, ich muß jede 20 us 800 Befehle ausführen können. Dazu muß noch genug Zeit übrig bleiben, mindestens 50% frei. Sonst kann AVR nichts mehr, nicht einmal Befehle empfangen. > Wie meinen? SPI kann man problemlos nutzen, auch wenn man die AVRs per > ISP programmieren will. Dazu braucht es keine Schalter, "nur" Knoff > Hoff. > https://www.mikrocontroller.net/articles/AVR_In_Sy... Dort ist leider nur beschrieben, wie man AVR mit anderen IC verwenden kann. Dort steht aber nicht, wie man per SPI mehrere AVR verbinden kann und sie dabei noch programmieren. Die werden einander stören. Das kann nur bei AVR funktionieren, wo SPI und ISP verschiedene Pins haben, so wie bei ATMEGA128.
:
Bearbeitet durch User
Maxim B. schrieb: > Die haben zwei USART, > beide haben XCK-Pin. Das ändert doch an der Aussage garnichts. Aber wenn du unbedingt deinen Kopf durchsetzen und synchron senden/empfangen willst, studiere Protokolle wie SDLC oder HDLC, sowas brauchst du. Meiner Erinnerung nach hat Datev das verwendet, vor der Internetzeit. Georg
@Maxim B. (max182) >Grob gesagt, ich muß jede 20 us 800 Befehle ausführen können. Dazu muß >noch genug Zeit übrig bleiben, mindestens 50% frei. Sonst kann AVR >nichts mehr, nicht einmal Befehle empfangen. Das ist nicht wirklich, wonach ich gefragt habe. Was willst du INSGESAMT machen? Soviele uC klingt mal wieder nach LED-Ansteuerung etc.
Ich möchte eine Orgel mit 8 gleichzeitig klingenden Stimmen (für Pedal reicht zwei) bauen. Ich habe eine Ahlborn aus 70-n, ich muß dort sowieso etwas ändern. ich überlege: wenn sowieso Umbau notwendig, dann mache ich vielleicht ganze Klangerzeugung neu. In Moment favorisiere ich folgende Aufbau: Alle Tastaturen MIDIfizieren (das erleichtert spätere Nachbesserungen). Ein Zentralblock mit ATmega1284. Der bekommt MIDI-Befehle, sucht freie Kanal und falls vorhanden, schaltet den Ton ein. So etwas habe ich schon im 2000 mit AT89C-Serie gemacht. Nun aber möchte ich Klangerzeugung nach Wellentabellen-Prinzip. Dabei scheint es mir von Vorteil, wenn nur zentrale CPU die ganzen Formen gespeichert hat und sie nach Bedarf an die Kanal-Erzeuger schickt. Nach meinen Berechnungen kann ATMEGA844PA mit F_CPU=20MHz zwei Töne bedienen, mehr nicht. Dabei verzichte ich auf digitale Modulation: Amplitude wird mit Hilfe vom PWM und Vref bei DAC MCP4922 erzeugt. Auch 2 Einheiten pro Chip, so paßt das gut zusammen. Um Ton zu schalten, sollte zuerst Formtabelle übertragen werden, 480 16bit-Worte (es reicht eigentlich, wenn das nur beim Umschalten von Register gemacht wird, nicht bei jedem Tastendruck. Aber sowieso: so schnell wie nur technisch möglich). SPI ist schon sowieso mit DAC beschäftigt, ich brauche andere Interface. Schema für 2 Töne so ungefähr wie auf dem Bild. Noch zuletzt: ich bin ein Musiker. Ich weiß, was ich brauche. Ich weiß nur noch nicht genau, wie ich das mache.
:
Bearbeitet durch User
@Maxim B. (max182) >Ich möchte eine Orgel mit 8 gleichzeitig klingenden Stimmen (für Pedal >reicht zwei) bauen. Dafür braucht man keine 20 AVRs. Bestenfalls 2. >So etwas habe ich schon im 2000 mit AT89C-Serie gemacht. Nun aber möchte >ich klangerzeugung nach Wellentabellen-Prinzip. Gute Idee. >Nach meinen Berechnungen kann ATMEGA844PA mit F_CPU=20MHz zwei Töne >bedienen, mehr nicht. Andere schaffen 6 und mehr. http://elm-chan.org/works/mxb/report.html >SPI ist schon sowieso mit DAC beschäftigt, ich brauche andere Interface. Nö, bessere Konzepte.
Für mich ist eine gute Polyphonie am wichtigsten. Es ist nicht zulässig, wenn bei mehreren Stimmen immer "schmutziger" wird, wie normalerweise bei Keyboards. Deshalb möchte ich Töne maximal voneinander trennen. Wie man hier noch 8 Töne schafft, verstehe ich schlecht. Als Beispiel: DDS-Funktion:
1 | while(1){ |
2 | |
3 | |
4 | if( FLAGG & (1<<F_PULS) ){ |
5 | |
6 | unsigned int phase_index = 0; |
7 | unsigned int a = 0; |
8 | static __uint24 freq_zaehler_a = 0; |
9 | static __uint24 freq_zaehler_b = 0; |
10 | static unsigned int form_puffer_a = MCP4921_KANA | MCP4921_GA | MCP4921_SHDN | 0x0400; |
11 | static unsigned int form_puffer_b = MCP4921_KANB | MCP4921_GA | MCP4921_SHDN | 0x0400; |
12 | |
13 | FLAGG &= ~(1<<F_PULS); |
14 | |
15 | /*** Kanal A ***/
|
16 | |
17 | // Per SPI an DAC MSB senden
|
18 | |
19 | PORT_CS0 &= ~(1<<CS0); |
20 | SPDR = (unsigned char)(form_puffer_a >> 8); |
21 | |
22 | // DDS Phase berechnen
|
23 | freq_zaehler_a += tonfrequenz_a; |
24 | if(freq_zaehler_a >= 0xf00000) freq_zaehler_a -= 0xf00000; |
25 | |
26 | // Per SPI an DAC LSB senden
|
27 | while(!(SPSR & (1<<SPIF))); |
28 | SPDR = (unsigned char)form_puffer_a; |
29 | |
30 | // Adresse fuer Formtabelle berechnen
|
31 | phase_index = (unsigned int)(freq_zaehler_a >> 16); |
32 | a = (unsigned int)freq_zaehler_a; |
33 | phase_index = (phase_index << 1); |
34 | if(a & 0x8000) phase_index |= 0x0001; |
35 | |
36 | // Signalform aus der Tabelle holen
|
37 | form_puffer_a = (unsigned int)(tonform[phase_index] + 2048) | MCP4921_KANA | MCP4921_GA | MCP4921_SHDN; |
38 | |
39 | while(!(SPSR & (1<<SPIF))); |
40 | PORT_CS0 |= (1<<CS0); |
41 | |
42 | |
43 | /*** Kanal B ***/
|
44 | |
45 | // Per SPI an DAC MSB senden
|
46 | |
47 | PORT_CS0 &= ~(1<<CS0); |
48 | SPDR = (unsigned char)(form_puffer_b >> 8); |
49 | |
50 | // DDS Phase berechnen
|
51 | freq_zaehler_b += tonfrequenz_b; |
52 | if(freq_zaehler_b >= 0xf00000) freq_zaehler_b -= 0xf00000; |
53 | |
54 | // Per SPI an DAC LSB senden
|
55 | while(!(SPSR & (1<<SPIF))); |
56 | SPDR = (unsigned char)form_puffer_b; |
57 | |
58 | // Adresse fuer Formtabelle berechnen
|
59 | phase_index = (unsigned int)(freq_zaehler_b >> 16); |
60 | a = (unsigned int)freq_zaehler_b; |
61 | phase_index = (phase_index << 1); |
62 | if(a & 0x8000) phase_index |= 0x0001; |
63 | |
64 | // Signalform aus der Tabelle holen
|
65 | form_puffer_b = (unsigned int)(tonform[phase_index] + 2048) | MCP4921_KANB | MCP4921_GA | MCP4921_SHDN; |
66 | |
67 | while(!(SPSR & (1<<SPIF))); |
68 | PORT_CS0 |= (1<<CS0); |
69 | |
70 | }
|
71 | }
|
Schon jetzt ist das so gemacht, daß während SPI beschäftigt ist, weiter gerechnet wird. Was kann man hier noch optimieren? Interrupt:
1 | ISR(TIMER0_COMPA_vect, ISR_NAKED){ // Timer 0 interrupt. |
2 | |
3 | MCP4921_LDAC_PORT &= ~(1<<MCP4921_LDAC); // Impuls LDAC |
4 | FLAGG |= (1<<F_PULS); // Flag fuer Puls einsetzen |
5 | MCP4921_LDAC_PORT |= (1<<MCP4921_LDAC); |
6 | |
7 | reti(); // da ISR_NAKED |
8 | }
|
So ist schneller, als ohne ISR_NAKED ISR von Timer ist hier nur provisorisch, am Ende muß natürlich ISR von INT0 kommen, aber Prinzip ist gleich. Fd wird von AD9833 erzeugt (um 50, notfalls 40 kHz), so kann feine Abstimmung der Tonhöhe gemacht werden. Schieben von Tabellenindex habe ich schon optimiert: sieht etwas komisch aus, kommt aber viel schneller, als gewöhnliche
1 | phase_index = (unsigned int)(freq_zaehler_b >> 15); |
Was noch? Das ganze braucht etwa 179 Cycle. Es muß noch etwas anderes erledigt werden, CPU darf nicht 100% nur das machen... Für Tabellen möchte ich einfach etwas von meinen Orgeln aufnehmen und so anpassen, daß bei beliebigen gleichzeitig geschalteten Register +2047 und -2048 nicht überschritten werden. Klar: hier fehlt noch Klangfarben-Anpassung nach Tonhöhe. Aber bei so einem einfachen Instrument kann man nicht alles haben. Es wird sowieso besser als jetzt. Es wäre schön, wenn auch repetierende Register gelingen. Dafür sehe ich nur eine Möglichkeit: Formtabelle während des Spiels aufladen und zwischen zwei umschalten. Aber das sollte schneller passieren, als eine wahrnehmbare Verzögerung. Eine pneumatische Jehmlich möchte ich nicht :)
:
Bearbeitet durch User
Noch ein bisschen kalkuliert: bei I2C 400 kHz, wenn folgende Schema benutzt wird:IC-Adresse - Befehl (- Daten), zuerst Daten nach Rx-Puffer, dann Schaltbefehl: Formtabelle aus Puffer aufladen, ~500 us Ton ausschalten ~= 60 us Tonfrequenz, Amplitude -> Puffer und Schaltbefehl: 270 us Data -> Rx_Puffer[960] ~= 28,9 ms für 960 bytes, das ist eindeutig zu viel.
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.