CS4344 I2S Transmitter

OP #5312212
Lesenswert?

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!
Angehängte Dateien:
OP #5312894
Lesenswert?

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.
Moderator (Firma: Titel) Persönliche Seite #5312978
Lesenswert?

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?
Gast #5312992
Lesenswert?

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?
OP #5313034
Lesenswert?

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.
Angehängte Dateien:
Gast #5313064
Lesenswert?

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.
OP #5313103
Lesenswert?

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)?
Angehängte Dateien:
Gast #5313213
Lesenswert?

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.
#5313618
Lesenswert?

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.
#5313740
Lesenswert?

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
OP #5313843
Lesenswert?

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 :)
#5313945
Lesenswert?

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?
OP #5314242
Lesenswert?

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.
OP #5314662
Lesenswert?

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?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren