Forum: FPGA, VHDL & Co. DE0_Nano ADXL345 SPI


von zander (Gast)



Lesenswert?

Hallo Zusammen,

ich versuche schon seit geraumer Zeit per QSYS den NIOSII auf meinem 
DE0Nano lauffähig zu bekomen, um den ADXL345 per SPI auszulesen.
Die Beispielprogramme auf der beiligenden CD des DE0Nano funktionieren, 
allerdings mit "älteren" Versionen der QSYS Module.
Wenn ich versuche diese mit den von "Quartus II 13.0" standardmäßig 
installierten Modulen aufzubauen/nachzubilden (und die gleichen 
Bibliotheken in C verwende) funktioniert leider gar nichts...
Kann mir jemand weiterhelfen, wo evtl schon meine grundlegenden Fehler 
in beiligenden Dateien sind?
Ich bin absoluter Anfänger was FPGAs / VHDL betrifft!

Grundlegende Frage:
Reicht mir das "SPI (3 WIRE SERIAL)" Modul in QSYS aus um als 
NIOSII-Master auf den ADXL345 zuzugreifen oder benötige ich noch die 
"SPI SLAVE TO AVALON MASTER BRIDGE"?
Wie gesagt, absoluter newbie :)

Gruß
zander

von Sigi (Gast)


Lesenswert?

Ganz Unten sind die Ports MISO und MOSI gleichnamig,
müssen aber verschieden sein!
Ist CS_N low während der SPI-Kommunikation?

von zander (Gast)


Lesenswert?

@ Sigi:
Danke für die Rückmeldung.
Das mit MISO/MOSI hab ich versucht so zu lösen, da der adxl345 per 
3-wire-spi an den DE0Nano angebunden ist...
siehe hierzu das Datenblatt S.23 
([[http://www.altera.com/literature/ug/DE0_Nano_User_Manual_v1.9.pdf]]).
Irgenwie muss ich wohl deklarieren, dass ich nur die "I2C_SDAT" Leitung 
zur Kommunikation habe, aber wie?

CS_N ist active low während der Kommunikation. Zuvor muss er jedoch HIGH 
sein, um die clock polarity und clock phase(?) einzustellen. Zumindest 
verstehe ich das Datenblatt so auf S. 14 
([[http://www.analog.com/static/imported-files/data_sheets/ADXL345.pdf]]).
Ich meine irgendwo gelesen zu haben, dass das SPI-Modul (wenn nur ein 
Slave vorhanden ist) diesen automatisch anwählt, daher bin ich davon 
ausgegangen, dass das automatisch funktioniert.

von Sigi (Gast)


Lesenswert?

Ich habe mal kurz in die Schematics geschaut:
Dein DE0-Nano hat beim adxl345 SDO leider auf
3.3V hochgezogen, d.h. es ist leider nur
I2C möglich (sofern sich über mehrere Versionen
von DE0_Nano I2C/SPI nicht ändert).

SPI kann also nicht funktionieren. Lösch also
in deinem QSYS-Design da SPI und füge ein I2C-Modul
ein.

Und!: statt der Instantiierung
1
comp_inst : COMP
2
port map
3
(
4
  clk,
5
  sig0,
6
  sig1,
7
  ..
8
)

schreib besser/übersichtlicher/weniger fehleranfällig
1
comp_inst : COMP
2
port map
3
(
4
  clk  => clk,
5
  sig0 => sig0,
6
  sig1 => sig1,
7
  ..
8
)

von zander (Gast)


Lesenswert?

Ich habe mir mal den I2C-Core 
[[http://www.alterawiki.com/wiki/I2C_%28OpenCores%29]] runtergeladen und 
in QSYS eingebunden. Werde das morgen testen. Allerdings verwundert mich 
doch, dass im Datenblatt zum DE0Nano steht, dass der adxl345 per SPI (3 
wire) angesteuert werden kann. Und auf der CD ist auch ein 
Beispielprogramm, worin in QSYS mit dem SPI-3-Wire Modul gearbeitet 
wird...

Das mit der Instantiierung werde ich mir so angewöhnen!

von zander (Gast)


Lesenswert?

Der I2C-Core hat funktioniert. Siehe:
[[Beitrag "Projektdokumentation DE0_Nano ADXL345 per I2C auslesen"]]

Gruß
zander

von zander (Gast)


Angehängte Dateien:

Lesenswert?

Nachdem der I2C funktioniert hat, habe ich mich nochmal dem SPI 
gewidmet.
Mit dem "SPI (3 WIRE SERIAL)" scheint der SPI auch zu funktionieren! 
Wenn ich das DATA_FORMAT-Register (Adresse 0x31 - siehe obigen Link zum 
ADXL345) mit 0x4B (Bit6 - SPI; Bit3 - FULL_RES; BIT1/0 - RANGE) 
beschreibe und danach z.B. die Device ID aus Register 0x00 (0x80 = 
Read-Befehl + 0x00) lesen möchte bekomme ich das angehängte Signal 
zurück. Das Signal selbst stimmt (11100101 - 0xE5), nur leider die Pegel 
nicht.
Ich vermute dass das irgendwie mit Pull up/down Widerständen 
zusammenhängt...
Meine Versuche den Ausgang als Input/Output zu deklarieren brachten 
leider keine Veränderung. Ausschließen würde ich, dass der ADXL einen 
Defekt hat, da der I2C immer noch tadellos funktioniert.

Hat jemand eine "schnelle" Idee woran das liegen könnte?

Möchte vermeiden den ganzen Code zu posten. Wenn es jemand auf seinem 
Board testen möchte, dann lade ich ihn allerdings gerne hoch.

Gruß
zander

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Was man da sieht ist die klassische Buskollision: es sind 2 Ausgänge 
aktiv am Bus. Einer treibt das Signal, der andere statisch 0.

von zander (Gast)


Lesenswert?

Das meinte ich ja mit der "Pull up/down"-Geschichte.
Aber wie "inaktiviere" ich den FPGA während der ADXL das Signal treibt?

Datenblatt zur SPI (ab Seite 107):
[[www.altera.com/literature/ug/ug_embedded_ip.pdf]]

Zum Lesen/Senden steht der Befehl "alt_avalon_spi_command" zur 
Verfügung, aber ich sehe nicht, wie ich darin den Master aktiv/inaktiv 
schalte...

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

zander schrieb:
> Aber wie "inaktiviere" ich den FPGA während der ADXL das Signal treibt?
Ein Portpin wird so hochohmig geschaltet:
1
   -- ausgeben bzw. hochohmig schalten
2
   portpin <= 'Z' when direction=input else dataout;
3
   
4
   -- einlesen
5
   datain  <= portpin;

von zander (Gast)


Angehängte Dateien:

Lesenswert?

Ich mal wieder...

Leider hat sich das Problem noch nicht geklärt, es sind eher mehr Fragen 
und Unklarheiten aufgekommen. :-(
Ich habe versucht meinen portpin (I2C_SDAT) tristate-fähig zu bekommen. 
Allerdings scheitere ich an der Initialisierung gemäß dem Beispiel von 
Herrn Miller:

> Ein Portpin wird so hochohmig geschaltet:
>
>   -- ausgeben bzw. hochohmig schalten
>   portpin <= 'Z' when direction=input else dataout;
>
>   -- einlesen
>   datain  <= portpin;

Irgendwie müsste ich zuerst meinen portpin als bidirectionalen Pin 
definieren, damit die Struktur dem Bild im Anhang entspricht (Quelle: 
http://www.altera.com/literature/ug/ug_avalon_tc.pdf S. 13). Dann hätte 
ich auch die Signale für direction(≙data_outen im Bild) und 
datain(≙data_in im Bild).
Ein Beispiel für einen Tristate-Output in VHDL-Code habe ich auch hier 
gefunden:
http://www.altera.com/support/examples/vhdl/v_prebus.html

Folgende Probleme:
1. Wie sind die Signale direction und datain zu deuten? Es sind ja keine 
physischen Ausgänge sondern eine Art interne "Richtungsschalter". Wird 
da nicht mein Pin-Planer meckern, weil ich die Signale keinem Ausgang 
zuweise?

2. Wie weiß mein C-Programm (NIOSII), dass es ein Signal direction gibt, 
über welches ich den Eingang am FPGA hochohmig setzen kann?
Dieses Zusammenspiel bzw. der Wissenstransfer vom VHDL-Code zum C-Code 
ist mir völlig unklar.
I2C_SDAT wird ja dann im VHDL-Code auf '1', '0' oder 'Z' gesetzt. Für 
mein Verständnis müsste ich im VHDL-Code abfragen, wann der FPGA im 
C-Code bei der SPI-Kommunikation in den Lese-Modus geht!? Wie gesagt, 
das ist mir völlig unklar.

3. Muss das Qsys Modell mit "Tri-State" Modulen erweitert werden?
- Generic Tri-State Controller
- Tri-State Conduit Bridge
- Tri-State Conduit Bridge Translator
- Tri-State Conduit Pin Sharer
(beschrieben in obiger Quelle)


Es wäre sehr nett, wenn mich jemand dazu aufschlauen könnte.
Ich hab noch mein aktuelles vhdl-file im Anhang, vielleicht liegt ja 
auch noch mehr im Argen...


Gruß
zander

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

zander schrieb:
> Folgende Probleme:
> 1. Wie sind die Signale direction und datain zu deuten? Es sind ja keine
> physischen Ausgänge sondern eine Art interne "Richtungsschalter". Wird
> da nicht mein Pin-Planer meckern, weil ich die Signale keinem Ausgang
> zuweise?
Nein, denn diese Signale beeinflussen ja einen Pin.

> 2. Wie weiß mein C-Programm (NIOSII), dass es ein Signal direction gibt,
> über welches ich den Eingang am FPGA hochohmig setzen kann?
Das Programm interessiert sich nicht dafür. Sondern es gibt dem I2C 
Modul Sendedaten und einen Startbefehl. Die Richtungsumschaltung und die 
Verwaltung der Pins werden dann vom Sendemodul durchgeführt. So, wie es 
in jedem uC eben auch geht...

zander schrieb:
> um den ADXL345 per SPI auszulesen.
Der hat doch getrennte SDI und SDO (aka. MOSI und MISO), warum also 
überhaupt eine Richtungsumschaltung?
Mir ist auch nicht klar, warum "dein" SPI-Modul da überhaupt kollidieren 
kann, denn beim SPI sind die Richtungen alle glasklar definiert, und 
bestenfalls, wenn 2 Slaves gleichzeitig selektiert werden, kann es zu 
Kollisionen auf der MISO-Leitung kommen...

Und ich verstehe nicht, warum du da irgendwelche I2C-Leitungen an den 
SPI anklemmst:
1
    spi_external_MISO       => I2C_SDAT,
2
    spi_external_MOSI       => I2C_SDAT,
3
    spi_external_SCLK       => I2C_SCLK,

von zander (Gast)


Angehängte Dateien:

Lesenswert?

Das DE0Nano-Board unterstützt nur eine 3-wire-SPI, siehe Bild im Anhang 
(Quelle: 
ftp://ftp.altera.com/up/pub/Altera_Material/12.1/Boards/DE0-Nano/DE0_Nan 
o_User_Manual.pdf  S.22). Daher habe ich nur eine Datenleitung zur 
Verfügung.
Ich verwende die vom Hersteller vorgegebenen Signalnamen, daher die 
I2C-Namen für die SPI-Verbindung. Etwas unglücklich, gebe ich zu...

Ich verwende zudem das Qsys Modul zur 3-wire-SPI über welches ich dann 
im C-Programm des NIOSII sende und empfange.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Als kleiner Denkanstoss das hier:
1
    spi_external_MISO       => DataIn,
2
    spi_external_MOSI       => DataOut,
3
    spi_external_SCLK       => I2C_SCLK,
4
    spi_external_SS_n       => G_SENSOR_CS_N
5
6
   -- die übertragenen Bits mitzählen
7
   process begin
8
      wait until rising_edge(clk_clk);
9
      if G_SENSOR_CS_N='1' then
10
        cnt <= 0;
11
        dir = '0';        -- Out
12
      end if;
13
      if I2C_SCLK='1' and I2C_SCLK_old='0' then -- SPI-Takte erkennen
14
        if  cnt<8 then    -- nach 8 Takten:
15
          cnt <= cnt+1;
16
        else              -- Datenrichtung umschalten
17
          dir = '1';      -- In
18
        end if;
19
      end if;
20
   end process;
21
  
22
   DataIn <= I2C_SDAT;
23
   I2C_SDAT <= DataOut when dir='0' else 'Z';

von zander (Gast)



Lesenswert?

So Prüfungen erst mal rum, jetzt konnte ich mich wieder dem Thema 
widmen...

Lothar, deinen Vorschlag habe ich so nicht 1:1 umgesetzt, aber als 
Grundlage verwendet. Ich habe die C-Bibliotheksfunktion des "3-wire-spi" 
(int alt_avalon_spi_command(...)) als separate Unterfunktion angelegt 
und an der Stelle im Programmcode, an welcher GELESEN wird einen freien 
Port im C-Programm auf HIGH gesetzt (in meinen Fall GPIO_0(31)), welchen 
ich im VHDL-Programm wie von dir vorgeschlagen überwache.

Hier der Code:
1
  spi_hardware_umschalter: process(GPIO_0(31))
2
  
3
  begin
4
    -- als Ausgang definieren
5
    if (GPIO_0(31) = '1') then
6
      direction <= '1';  -- Input
7
      
8
    -- auf HIGH Impedanz / Datenrichtung umschalten
9
    else 
10
      direction <= '0';  -- Output
11
12
    end if;
13
    
14
  end process spi_hardware_umschalter;
15
  
16
  Data_In <= I2C_SDAT;
17
  I2C_SDAT <= Data_Out when direction='0' else 'Z';

Und HURA!!! :-) es funktioniert endlich, wie man den Bildern entnehmen 
kann.

Info zu den Bildern:
Kanal gelb - Takt
Kanal grün - Chip-Select
Kanal blau - Datenkanal
Kanal pink - Zustand von GPIO_0(31), meinem "Umschalter".

Jetzt verstehe ich auch warum der Master in Richtung des Slave selbst 
beim Lesen etwas "schreiben" muss -> damit der Takt aufrechterhalten 
wird! Hatte mich im Programm gewundert warum beim Lesen 1byte lang 0er 
geschrieben werden, aber jetzt ist das auch klar!
Was ich abschließend nur nicht durchdringe ist, warum der Datenkanal 
(blau) einmal nach dem Lesen der DeviceID auf HIGH bleibt, während er 
beim Lesen des Registers wieder auf Low geht... Aber das betrifft ja 
glücklicherweise nicht das Schreiben und Lesen auf dem SPI.

Somit ist das Thema für mich beendet und ich danke allen Beteiligten 
vielmals für die Unterstützung!

zander

von Duke Scarring (Gast)


Lesenswert?

zander schrieb:
> Was ich abschließend nur nicht durchdringe ist, warum der Datenkanal
> (blau) einmal nach dem Lesen der DeviceID auf HIGH bleibt, während er
> beim Lesen des Registers wieder auf Low geht
Villeicht, weil ganz zum Schluss nochmal das erste Bit ausgegeben wird?

Duke

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.