Hallo zusammen, ich habe meinen alten I2S-Transmitter mal neu geschrieben und ihn mit ein paar Handshake-Signalen versehen. Für das Auslesen der Daten aus einem ROM und der Ansteuerung des Transmitters habe ich mir zudem einen State-Machine drumherum gebaut (diese möchte ich später noch erweitern um auch Daten in einen Speicher reinschreiben zu können). In der Simulation sieht alles soweit stimmig aus (soweit ich das beurteilen kann - siehe Screenshot), aber wenn ich die Schaltung auf mein FPGA übertrage erhalte ich nur Rauschen und keinen Sinuston. Wo habe ich einen Fehler in der Schaltung? Vielen Dank für die Hilfe!
Daniel K. schrieb: > aber wenn ich die Schaltung auf mein FPGA übertrage ... sollte man bei solchen Problemen ein Oszi bzw. LA anschliessen und schauen, ob die Simulation was mit der Realität zu tu hat.
Daniel K. schrieb: > Wo habe ich einen Fehler in der Schaltung? Keine Ahnung, aber ROM- und übertragene Daten scheinen nicht zueinander zu passen und ausserdem ist ein ROM-Word nur 16 Bit breit - bist Du sicher, dass Du dem Codec einen Sinus zufütterst?
Hallo, ein Oszi habe ich bereits dran gehalten. Es kommt kein "vernünftiges" Signal raus. Es sind Spuren eines Sinus, aber komplett durcheinander. Die ROM-Daten und die zu übertragenen Daten sind etwas versetzt, das stimmt schon. Die ROM-Daten werden einen Übertragungszyklus später gesendet als diese ausgelesen werden (z. B. das Wort an Adresse 1 wird erst gelesen und dann übertragen, wenn das Wort von Adresse 2 gelesen wird). Das ist bewusst so gemacht und sollte dem CS4344 auch egal sein (oder?). Die Worte sind 16-Bit breit, aber sie stellen nur einen Kanal dar. Daher sende ich die Daten 2x in einem Paket. Einmal Links und einmal Rechts.
Daniel K. schrieb: > ein Oszi habe ich bereits dran gehalten. Es kommt kein "vernünftiges" > Signal raus. Es sind Spuren eines Sinus, aber komplett durcheinander. Ich würde mal mit weniger komplexen signalen anfangen: 1. Rechteck(e) 2. Sägezahn/Dreieck 3. komplexere Signale aus dem ROM > Für das Auslesen der Daten aus einem ROM und der Ansteuerung des > Transmitters habe ich mir zudem einen State-Machine drumherum gebaut Es ist ein wenig mühsam, sich die VHDL-Files aus den ganzen Verzeichnissen zusammenzuklauben. Könntest du einfach mal die paar relevanten Dateien als *.VHD hier anhängen?
Der erste Takt auf I2S_DATA nach einem Flankenwechsel auf I2S_LRCK hat mal Daten und mal nicht (0/1). Laut Datenblatt des CS4344 hat dieser aber I2S Standard und der erste Takt enthält keine Nutzdaten. Kann da dein Fehler sein?
Hallo, Nils N. schrieb: > Der erste Takt auf I2S_DATA nach einem Flankenwechsel auf I2S_LRCK hat > mal Daten und mal nicht (0/1). > > Laut Datenblatt des CS4344 hat dieser aber I2S Standard und der erste > Takt enthält keine Nutzdaten. > > Kann da dein Fehler sein? ich habe mich bei der I2S-Spezifikation hieran https://www.sparkfun.com/datasheets/BreakoutBoards/I2SBUS.pdf orientiert. Dort steht, dass der erste Takt nach einem Wechsel von WS (also hier LRCLK) von Low nach High, bzw. von High nach Low, das LSB des Datenwortes n - 1 überträgt. Das MSB des Datenwortes n wird erst beim zweiten Takt des Flankenwechsels von LRCLK übertragen. Ich habe meinen Sender nach diesem PDF aufgebaut und dann "nur" noch die spezifischen Komponenten für den CS4344 hinzugefügt (wie z. B. MCLK). Lothar M. schrieb: > Daniel K. schrieb: >> ein Oszi habe ich bereits dran gehalten. Es kommt kein "vernünftiges" >> Signal raus. Es sind Spuren eines Sinus, aber komplett durcheinander. > Ich würde mal mit weniger komplexen signalen anfangen: > 1. Rechteck(e) > 2. Sägezahn/Dreieck > 3. komplexere Signale aus dem ROM > >> Für das Auslesen der Daten aus einem ROM und der Ansteuerung des >> Transmitters habe ich mir zudem einen State-Machine drumherum gebaut > Es ist ein wenig mühsam, sich die VHDL-Files aus den ganzen > Verzeichnissen zusammenzuklauben. Könntest du einfach mal die paar > relevanten Dateien als *.VHD hier anhängen? sry, ich dachte ein komplettes Projekt wäre einfacher :). Anbei die einzelnen VHDL-Files und die Testbench. Einzig die ClockingWizard IP kann ich nicht hochladen. Die muss dann ggf. in den Files ausgetauscht werden.
Daniel K. schrieb: > Dort steht, dass der erste Takt nach einem Wechsel von WS > (also hier LRCLK) von Low nach High, bzw. von High nach Low, das LSB des > Datenwortes n - 1 überträgt. Dort steht: "The WS line changes one clock period before the MSB is transmitted." Bei dir sehe ich aber das MSB scheinbar schon direkt nach dem Flankenwechsel. Zusätzlich will der CS4344 das MSB zuerst haben. Beides will also zurst einen takt Pause und dann das MSB, also komplett gegensätzlich zu deiner Meinung. Oder? Bzw. du kannst nicht das LSB in dieser taktwartezeit schicken oder? Diese Pause iat ja dazu gedacht, die Nutzdaten auszuwerten. Der CS4345 hat diese Taktpause nicht.
Nils N. schrieb: > Daniel K. schrieb: >> Dort steht, dass der erste Takt nach einem Wechsel von WS >> (also hier LRCLK) von Low nach High, bzw. von High nach Low, das LSB des >> Datenwortes n - 1 überträgt. > > Dort steht: "The WS line changes one clock period before the MSB is > transmitted." > > Bei dir sehe ich aber das MSB scheinbar schon direkt nach dem > Flankenwechsel. > > Zusätzlich will der CS4344 das MSB zuerst haben. Beides will also zurst > einen takt Pause und dann das MSB, also komplett gegensätzlich zu deiner > Meinung. Oder? > > Bzw. du kannst nicht das LSB in dieser taktwartezeit schicken oder? > Diese Pause iat ja dazu gedacht, die Nutzdaten auszuwerten. Der CS4345 > hat diese Taktpause nicht. Hallo, anbei noch mal das ein besserer Screenshot der Simulation (für das Datenwort 0x0805). Das Wort hat die Bitfolge 0000 1000 0000 0101 WS geht bei CounterDelay2 = 30 runter und ist somit bei dem LSB des Datenwortes, welches zuvor gesendet wurde, auf Low. Dann beginnt das eigentliche Datenwort. Bit 15 - 12 sind 0, Bit 11 ist 1, Bit 10 - 3 sind 0, 2 ist 1, 1 ist 0 und 0 ist 1. Während das Bit 0 aber 1 ist, ist WS bereits auf 1 gesprungen (das ganze dann noch mal, weil ich das selbe Datenwort für beide Kanäle sende). Das ist doch das gewünschte Verhalten, wie es in der Spezifikation beschrieben ist. Oder sehe ich das gerade falsch (ggf. habe ich was falsch interpretiert...will das nicht ausschließen)?
:
Bearbeitet durch User
Du schickst also das LSB während des ersten Taktes eines neuen Frames? Ich bin nicht soo I2S geläufig - ist das denn erlaubt? Aber wenn schon, dann müsste das LSB doch einfach abgeschnitten werden.
Hallo, laut dieser Spezifikation https://www.sparkfun.com/datasheets/BreakoutBoards/I2SBUS.pdf soll das wohl so sein (siehe Bild) :).
:
Bearbeitet durch User
Daniel K. schrieb: > laut dieser Spezifikation > > https://www.sparkfun.com/datasheets/BreakoutBoards/I2SBUS.pdf > > soll das wohl so sein (siehe Bild) :). Welches Verhältnis MCLK/SCLK/LRCLK verwendest Du? Laut Datenblatt hängt die Zahl der zu übertragenen Bits beim I2S-Format vom Verhältnis MCLK/LRCLK ab (gilt analog auch bei externer SCLK): I²S, 16-Bit data and INT SCLK = 32 Fs if MCLK/LRCK = 1024, 512, 256, 128, or 64 I²S, Up to 24-Bit data and INT SCLK = 48 Fs if MCLK/LRCK = 768, 384, 192, or 96 I²S, Up to 24-Bit data and INT SCLK = 72 Fs if MCLK/LRCK = 1152 Alternativ gibt es ein left- oder right-justified Format, da fallen LRCLK-Flanke und MSB zusammen.
Aus I2S_Top.vhd: >(...) > StateChange : process(Clock, Reset, CurrentState) > variable NextState : STATES; > begin > if(Reset = '1') then > NextState := ResetState; > (...) Du verwendest einen asyncronen Reset, ist der einsyncronisiert? Siehe dazu auch: Beitrag "Re: Detailfrage Reset" und sehe ich das Richtig: hier wird ein geteilter Clock verwendet? aus "I2S-Transmitter.vhd" > -- Generate the I2S clock > I2S_Clock_Divider : ClockDivider generic map (Prescaler => >(MCLK_PRESCALER / (2 * DATA_WIDTH_PER_CHANNEL))) > port map ( Clock_In => Clock, > Reset => Reset, > Clock_Out => *Clock_Int* > ); >(...) >Load_data : process(Clock_Int, Reset, Strobe, Data) > begin > if(Reset = '1') then > DataBuffer <= (others => '0'); > elsif(falling_edge(Clock_Int)) then Und in I2S_Top.vhd wird der eingangs Takt der Clockdividers verwendet? > -- State network > StateChange : process(Clock, Reset, CurrentState) > variable NextState : STATES; > begin > if(Reset = '1') then > NextState := ResetState; > elsif(rising_Edge(Clock)) then ist das so beabsichtigt und ok? nun dazu auch: https://www.mikrocontroller.net/articles/Taktung_FPGA/CPLD
Burkhard K. schrieb: > Daniel K. schrieb: >> laut dieser Spezifikation >> >> https://www.sparkfun.com/datasheets/BreakoutBoards/I2SBUS.pdf >> >> soll das wohl so sein (siehe Bild) :). > > Welches Verhältnis MCLK/SCLK/LRCLK verwendest Du? Laut Datenblatt hängt > die Zahl der zu übertragenen Bits beim I2S-Format vom Verhältnis > MCLK/LRCLK ab (gilt analog auch bei externer SCLK): > > I²S, 16-Bit data and INT SCLK = 32 Fs if MCLK/LRCK = 1024, 512, 256, > 128, or 64 > I²S, Up to 24-Bit data and INT SCLK = 48 Fs if MCLK/LRCK = 768, 384, > 192, or 96 > I²S, Up to 24-Bit data and INT SCLK = 72 Fs if MCLK/LRCK = 1152 > > Alternativ gibt es ein left- oder right-justified Format, da fallen > LRCLK-Flanke und MSB zusammen. Hallo, danke für die Antworten. Ich werde es morgen mal ausprobieren und berichten. Bernhard K. schrieb: > Aus I2S_Top.vhd: >>(...) >> StateChange : process(Clock, Reset, CurrentState) >> variable NextState : STATES; >> begin >> if(Reset = '1') then >> NextState := ResetState; >> (...) > Du verwendest einen asyncronen Reset, ist der einsyncronisiert? > Siehe dazu auch: > Beitrag "Re: Detailfrage Reset" > > und sehe ich das Richtig: hier wird ein geteilter Clock verwendet? > > aus "I2S-Transmitter.vhd" >> -- Generate the I2S clock >> I2S_Clock_Divider : ClockDivider generic map (Prescaler => >(MCLK_PRESCALER / > (2 * DATA_WIDTH_PER_CHANNEL))) >> port map ( Clock_In => Clock, >> Reset => Reset, >> Clock_Out => *Clock_Int* >> ); >>(...) >>Load_data : process(Clock_Int, Reset, Strobe, Data) >> begin >> if(Reset = '1') then >> DataBuffer <= (others => '0'); >> elsif(falling_edge(Clock_Int)) then > > Und in I2S_Top.vhd wird der eingangs Takt der Clockdividers verwendet? >> -- State network >> StateChange : process(Clock, Reset, CurrentState) >> variable NextState : STATES; >> begin >> if(Reset = '1') then >> NextState := ResetState; >> elsif(rising_Edge(Clock)) then > ist das so beabsichtigt und ok? nun dazu auch: > https://www.mikrocontroller.net/articles/Taktung_FPGA/CPLD Danke für die Links. Der Reset ist nicht einsynchronisiert. Vielmehr wende ich hier Wissen aus dem Studium an, was VHDL angeht und dort wurde uns eingetrichtert den Reset IMMER asynchron einzubauen (interessanterweise auch auf Xilinx FPGAs). Ich werde den entsprechenden Thread mal an meinen Prof weiterleiten :) Mit dem Takt hast du Recht. Auch dazu lese ich mir den entsprechenden Artikel mal durch. Vielen Dank für die Hinweise :)
Daniel K. schrieb: > dort wurde uns eingetrichtert den Reset IMMER asynchron einzubauen Du kannst zwar den Reset asynchron aktivieren, musst ihn aber auf jeden Fall synchron wegnehmen. Dazu den fast zehnjährigen Beitrag "Re: Reset für mehrere Komponenten"
Lothar M. schrieb: > Du kannst zwar den Reset asynchron aktivieren, musst ihn aber auf jeden > Fall synchron wegnehmen. Wenn man sich den MCLK-Takt per DCM/MMCM/PLL etc. erzeugt, kann das negierte "locked"-Signal auch als synchronisierter Reset dienen, zumindest bei Xilinx scheint "locked" immer synchron gesetzt zu werden. Laut Simulation dauert es bei 100 MHz Systemtakt ca. 7.5 us, bis "locked" aktiv wird (Könnte von der generierten Frequenz abhängen). Bernhard K. schrieb: > ist das so beabsichtigt und ok? nun dazu auch: > https://www.mikrocontroller.net/articles/Taktung_FPGA/CPLD Spricht eigentlich etwas dagegen, eine "Derived Clock" mit einem passenden Puffer-Primitiv (z.B.: BUFG, BUFGMUX) zu einer "guten" Taktquelle zu adeln?
Hallo, Burkhard K. schrieb: > Lothar M. schrieb: >> Du kannst zwar den Reset asynchron aktivieren, musst ihn aber auf jeden >> Fall synchron wegnehmen. > > Wenn man sich den MCLK-Takt per DCM/MMCM/PLL etc. erzeugt, kann das > negierte "locked"-Signal auch als synchronisierter Reset dienen, > zumindest bei Xilinx scheint "locked" immer synchron gesetzt zu werden. > Laut Simulation dauert es bei 100 MHz Systemtakt ca. 7.5 us, bis > "locked" aktiv wird (Könnte von der generierten Frequenz abhängen). > also kann ich das Locked des ClockingWizards verwende habe ich meinen synchronen Reset? In den VHDL Vorlesungen wurde der Reset auch immer mit dem Locked verknüpft (wahrscheinlich sogar aus dem Grund). Meinen Clockteiler werde ich die Tage dann mal umbauen.
Daniel K. schrieb: > also kann ich das Locked des ClockingWizards verwende habe ich meinen > synchronen Reset? Ich würde es noch einsynchronisieren, der Aufwand ist minimal. Wenn man 'locked' nicht beachtet, kann Dir ggf. das hier passieren: Beitrag "Spartan 6, dem DCM-Ausgang auf die Finger geschaut" Duke
Hallo, also zusammengefasst sollte ich dann grundsätzlich so etwas hier für den Reset verwenden (frei Hand geschrieben, daher ggf. Syntaxfehler). Das Locked kommt ggf. weg, je nachdem ob ich nen DCM benutze oder nicht.
1 | arch ... |
2 | signal Reset_Int : STD_LOGIC := '0'; |
3 | signal Locked : STD_LOGIC := '0'; -- Reset Signal für die restliche Schaltung |
4 | begin
|
5 | |
6 | process(Clock, Reset) |
7 | begin
|
8 | if(rising_edge(Clock)) then |
9 | Reset_Int <= Locked and Reset; |
10 | end if; |
11 | end process; |
12 | end arch ... |
Dazu dann noch mal eine kleine Offtopicfrage... Kann man sich das Routing bzw. die FFs etc., die für eine Schaltung genutzt werden, genau anschauen? Ich habe im Vivado noch nicht so ganz durchschaut wie und ob man sich das visualisieren kann. Bisher habe ich nur gesehen, dass die benutzten CLBs angezeigt werden können, nicht aber die Routingressourcen. Ich würde mir nämlich gerne mal den Unterschied (rein Schaltungstechnisch) zwischen einem Synchronen und einem Asynchronen Reset anschauen. Hat da vielleicht jemand eine Anleitung oder Beschreibung zu?
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.