Ich verweise auf den Beitrag Beitrag "Xilinx Spartan6 SPI ADC". Da dieser älter als sechs Monate ist, eröffne ich an dieser Stelle einen neuen Beitrag. Ich habe wie in dem Beitrag in einem FPGA einen MicroBlaze implementiert. Dieser ist über den AXI-Bus mit dem AXI SPI Core verbunden. Zum Initialisieren rufe ich SPI_Initialize() auf. Es wird bei mir "SPI_Initialize ... XST_SUCCESS" zurückgegeben. Klinkt schonmal gut. int SPI_Initialize(uint32_t Device_ID) { int Status = 0x00; uint8_t Option = 0x00; SPI_Config = XSpi_LookupConfig(Device_ID); if (SPI_Config == NULL){ print("SPI_Initialize ... XST_DEVICE_NOT_FOUND\n\r"); return XST_DEVICE_NOT_FOUND;} Status = XSpi_CfgInitialize(&SPI_Instance, SPI_Config, SPI_Config->BaseAddress); /*XSP_MASTER_OPTION 0x1 XSP_CLK_ACTIVE_LOW_OPTION 0x2 XSP_CLK_PHASE_1_OPTION 0x4 XSP_LOOPBACK_OPTION 0x8 XSP_MANUAL_SSELECT_OPTION 0x10 */ Option = XSP_MASTER_OPTION | XSP_CLK_PHASE_1_OPTION |XSP_MANUAL_SSELECT_OPTION; XSpi_SetOptions(&SPI_Instance, Option); if (Status != XST_SUCCESS){ print("SPI_Initialize ... XST_FAILURE\n\r"); return XST_FAILURE;} else{ print("SPI_Initialize ... XST_SUCCESS\n\r"); return XST_SUCCESS;} } Ich muss dazu sagen, dass am FPGA ein Sensor angeschloßen ist, den ich über SPI auslesen möchte. -> SPI wird als Master konfiguriert. Nun meine bisherige Lese-Funktion aufbauend auf dem oben genannten Beitrag und den Dokumentationen zur xspi.h Datei. uint32_t SPI_Read(uint32_t Address) { int Status = 0; uint8_t ReadBuffer[1] = {0x00}; uint16_t WriteBuffer[1] = {0x147}; /*Instruction Format*/ XSpi_SetSlaveSelect(&SPI_Instance, 1); XSpi_Start(&SPI_Instance); XSpi_IntrGlobalDisable(&SPI_Instance); Status = XSpi_Transfer(&SPI_Instance, &WriteBuffer[0], &ReadBuffer[0], 1); switch(Status){ case XST_SUCCESS:print("XST_SUCCESS\n\r");break; case XST_DEVICE_IS_STOPPED:print("XST_DEVICE_IS_STOPPED\n\r");break; case XST_DEVICE_BUSY:print("XST_DEVICE_BUSY\n\r");break; case XST_SPI_NO_SLAVE: print("XST_SPI_NO_SLAVE\n\r");break; } xil_printf("Register-Wert: %x\n\r",ReadBuffer); return XST_SUCCESS; } Hier wird erneut ein Register-Wert ausgegeben. Allerding "Null", statt dem Default-Wert. 1. Frage: Fällt generell etwas auf, was an den beiden Funktionen falsch läuft? 2. Frage: Ich möchte lediglich pro Funktionsaufruf "einmal" einen registerwert lesen. Wieso muss ich ein Array an die Funktion XSpi_Transfer() übergeben) 3. Frage: Mein Instruction Format (welches den Lesevorgang einleitet: Lesebit, Adresse etc.) ist 15 Bit lang, die WriteBuffer darf lediglich vom Typ u8 sein. Gibt es einen Ausweg? Vielen Dank
Ich sehe gerade, die Formatierung ist missglückt. Entschuldigung dafür. Ich habe mir die Signale EN, SCK, MISO, MOSI aufs Oszilloskop gelegt. Ich sehe jedoch keine Signale. Nicht einmal das CLK Signal. Trotz positiver Rückmeldung bei der Initialisierung und Read-Funktion. Hat wer Vorschläge?
Anbei ein Ausschnitt aus der Simulation. (Simulationsumgebung funktioniert (habe es zuvor einmal mit der Ausgabe eines Characters versucht) Der zugehörige C-Code: main.c ------------------------------------------------------- #include <stdio.h> #include "platform.h" #include "parameters.h" #include "spi.h" void print(char *str); int main() { init_platform(); SPI_Initialize(SPI_DEVICE_ID); while(1) { test(); }; return 0; } spi.c --------------------------------------------------------- #include "spi.h" #include "xspi.h" #include "parameters.h" #include "stdint.h" XSpi_Config *SPI_Config; static XSpi SPI_Instance; int SPI_Initialize(uint32_t Device_ID) { XSpi_LookupConfig(Device_ID); XSpi_CfgInitialize(&SPI_Instance, SPI_Config,SPI_Config->BaseAddress); Option = XSP_MASTER_OPTION | XSP_CLK_PHASE_1_OPTION| XSP_MANUAL_SSELECT_OPTION; XSpi_SetOptions(&SPI_Instance, Option); // Control Register (SPICR) #define SPI_CR_LOOP 0x01 #define SPI_CR_SPE 0x02 #define SPI_CR_MASTER 0x03 #define SPI_CPOL 0x04 #define SPI_CPHA 0x05 #define SPI_CR_TX_FIFO_RESET 0x06 #define SPI_CR_RX_FIFO_RESET 0x07 #define SPI_CR MANUAL_SLAVE_SELECT 0x08 #define SPI_CR MASTER_TRANSACTION_INHIBIT 0x09 uint32_t spicr_reg = SPI_CR_SPE | SPI_CR_MASTER | SPI_CPOL |SPI_CPHA; XSpi_WriteReg(SPI_Base_ADDRESS, 0x60, spicr_reg ); } void test(void) { int8_t out[4]; int8_t in[4]; out[0] = 0x9F; out[1] = 0xFF; out[2] = 0xFF; out[3] = 0xFF; in[0] = 0x00; in[1] = 0x00; in[2] = 0x00; in[3] = 0x00; XSpi_Start(&SPI_Instance); XSpi_SetSlaveSelect(&SPI_Instance, 1); XSpi_Transfer(&SPI_Instance, out, in, 4); } Sieht jemand den Fehler?
Diese Zeile kommt mir etwas komsich vor: uint32_t spicr_reg = SPI_CR_SPE | SPI_CR_MASTER | SPI_CPOL |SPI_CPHA; wahrscheinlich braucht es da noch ein paar shift operationen oder du musst die Defines anders definiern.
Du definierst einen Pointer auf eine Config-Struktur: XSpi_Config *SPI_Config; Der wird aber nirgendwo initialisiert, und es wird auch keine entsprechende Struktur instanziiert.
Ok, ich seh gerade dass die XSpi_CfgInitialize() die Struktur füllt. Anlegen muss Du sie aber trotzdem. Also meiner Meinung nach müsste das so aussehen.
1 | XSpi_Config *SPI_Config; |
2 | static XSpi SPI_Instance; |
3 | |
4 | int SPI_Initialize(uint32_t Device_ID) |
5 | {
|
6 | XSpi_LookupConfig(Device_ID); |
7 | XSpi_CfgInitialize(&SPI_Instance, SPI_Config, SPI_Base_ADDRESS); |
8 | |
9 | |
10 | ...
|
Sorry, ich meinte so:
1 | static XSpi_Config SPI_Config; |
2 | static XSpi SPI_Instance; |
3 | |
4 | int SPI_Initialize(uint32_t Device_ID) |
5 | {
|
6 | XSpi_LookupConfig(Device_ID); |
7 | XSpi_CfgInitialize(&SPI_Instance, &SPI_Config, SPI_Base_ADDRESS); |
8 | |
9 | |
10 | ...
|
Beispiel: #define SPI_CR_LOOP 0x01 #define SPI_CR_SPE 0x02 #define SPI_CR_MASTER 0x03 #define SPI_CPOL 0x04 Ich möchte Bit SPI_CR_LOOP und Bit SPI_CR_MASTER auf High setzen. Alter Registerinhalt ist beispielsweise 0b1001 => spicr_reg |= SPI_CR_LOOP | SPI_CPOL; => 0b1001 |= 0b0001 | 0b0100; => spicr_reg = 0b1101 Somit müsste die Zeile nun stimmen. Meine Änderung: uint32_t spicr_reg = XSpi_ReadReg(SPI_Base_ADDRESS, 0x60); spicr_reg |= ((1 << SPI_CR_SPE) | (1 << SPI_CR_MASTER)| (1 << SPI_CPOL) | (1 << SPI_CPHA)); XSpi_WriteReg(SPI_Base_ADDRESS, 0x60, spicr_reg ); Die ISim-Diagramme sehen jedoch unverändert aus. Zu anderen Anmerkung: static XSpi_Config SPI_Config; static XSpi SPI_Instance; habe ich doch geschrieben (siehe oben). Ich habe lediglich einmal das "static" vergessen. Laut Beispiel muss es: static XSpi_Config *SPI_Config; static XSpi SPI_Instance; lauten. (mit Stern). Ansonsten gibt es Fehlermeldungen.
Dir ist aber schon der Unterschied zischen SPI_Config und *SPI_Config klar? Wo wird denn in Deinem Beispiel die Struktur angelegt?
Im xspi.h file dachte ich. Siehe hierzu http://www.cs.indiana.edu/hmg/le/project-home/xilinx/ise_13.2/ISE_DS/EDK/sw/XilinxProcessorIPLib/drivers/spi_v3_01_a/doc/html/api/xspi_8h.html Dort ist die Struktur definiert. Der Rückgabewert von XSpi_CfgInitialize() und XSpi_LookupConfig() ist auch "XST_SUCCESS".
Ein Beispiel, welches ich zuvor angesprochen habe. Hier wird es ebenfalls mit Sternchen in der main() aufgeführt. http://www.cs.indiana.edu/hmg/le/project-home/xilinx/ise_13.2/ISE_DS/EDK/sw/XilinxProcessorIPLib/drivers/spi_v3_01_a/examples/xspi_stm_flash_example.c
Und da wird dem Pointer auch was zugewiesen: ConfigPtr = XSpi_LookupConfig(SPI_DEVICE_ID); Du rufst die Funktion auf, ohne den Rückgabewert zu verwenden und Dein Pointer bleibt uninitialisiert.
Das ist jetzt mein abgeänderter Code. Habe es eingearbeitet. Ich habe somit den Rückgabewert aufgerufen, richtig? Ich sehe jedoch immernoch das selbe Bild. :( #include "spi.h" #include "xspi.h" #include "parameters.h" #include "stdint.h" static XSpi_Config *SPI_Config; static XSpi SPI_Instance; int SPI_Initialize(uint32_t Device_ID) { int Status = 0x00; uint8_t Option = 0x00; SPI_Config=XSpi_LookupConfig(Device_ID); if (SPI_Config == NULL) { //print("SPI_Initialize ... XST_DEVICE_NOT_FOUND\n\r"); return XST_DEVICE_NOT_FOUND; } Status = XSpi_CfgInitialize(&SPI_Instance, SPI_Config, SPI_Config->BaseAddress); Option = XSP_MASTER_OPTION | XSP_CLK_PHASE_1_OPTION | XSP_MANUAL_SSELECT_OPTION; XSpi_SetOptions(&SPI_Instance, Option); #define PI_CR_LOOP 0x01 #define PI_CR_SPE 0x02 #define PI_CR_MASTER 0x03 #define PI_CPOL 0x04 #define SPI_CPHA 0x05 #define SPI_CR_TX_FIFO_RESET 0x06 #define SPI_CR_RX_FIFO_RESET 0x07 #define SPI_CR MANUAL_SLAVE_SELECT 0x08 #define SPI_CR MASTER_TRANSACTION_INHIBIT 0x09 uint32_t spicr_reg = XSpi_ReadReg(SPI_Base_ADDRESS, 0x60); spicr_reg |= ((1 << SPI_CR_SPE) | (1 << SPI_CR_MASTER) | (1 << SPI_CPOL) | (1 << SPI_CPHA)); XSpi_WriteReg(SPI_Base_ADDRESS, 0x60, spicr_reg ); if (Status != XST_SUCCESS) { //print("SPI_Initialize ... XST_FAILURE\n\r"); return XST_FAILURE; } else { //print("SPI_Initialize ... XST_SUCCESS\n\r"); return XST_SUCCESS; } }
Ich habe jetzt einmal genau folgenden Code übernommen: Beitrag "Xilinx Spartan6 SPI ADC". In diesem Beitrag hat derjenige jedenfalls irgendein Signal am SPI_CLK, SPI_ENB etc. Ich bin ratlos. Wenn ich noch weitere Einstellungen hochladen soll, damit eine Analyse des Problems einfacher wird, sagt bescheid. Vielen Dank euch.
Schau Dir doch mal in der Simulation gezielt den SPI-Core an, ob da überhaupt Registerzugriffe stattfinden und ob in den Registern das steht was Du denkst. Es muss ja nicht an der Software liegen, das Prozessor-System an sich kann auch Fehler haben. XPS vergisst auch gern mal Signale zu verbinden, ich musste da schon oft manuell ran.
User schrieb: > anbei das mhs-File. Da kann ich jetzt nicht auffälliges entdecken. Allerdings ist mir aufgefallen, dass Deine #defines für die Flags alle um 1 zu groß sind. Das hier: #define PI_CR_SPE 0x02 ... spicr_reg |= ((1 << SPI_CR_SPE) ... setzt z.B. das Master-Flag.
Anbei die gezielte Analyse. Wieso sind die Registereinträge nur 5 Bit lang? Im Datenblatt zum IP-Core steht 32 Bit. Das ist nun nur der Teil, wo zum Test #include <stdio.h> #include "platform.h" #include "parameters.h" #include "spi.h" #include "xspi.h" static XSpi InstancePtr; int main() { init_platform(); XSpi_Initialize(&InstancePtr, SPI_DEVICE_ID); return 0; } simuliert wird. Ich wollte den Registerinhalt einmal mit den Default-Werten vergleichen. Hat wer eine Idee?
Anbei einmal der Registerinhalt vom Register "SPICR" für folgendes File: #include <stdio.h> #include "platform.h" #include "parameters.h" #include "spi.h" #include "xspi.h" static XSpi InstancePtr; static XSpi_Config *SPI_Config; int main() { init_platform(); XSpi_Initialize(&InstancePtr, SPI_DEVICE_ID); SPI_Config = XSpi_LookupConfig(SPI_DEVICE_ID); XSpi_CfgInitialize(&InstancePtr, SPI_Config, SPI_Config->BaseAddress); uint32_t Option = XSP_MASTER_OPTION | XSP_CLK_PHASE_1_OPTION| XSP_CLK_ACTIVE_LOW_OPTION| XSP_MANUAL_SSELECT_OPTION; XSpi_SetOptions(&InstancePtr, Option); XSpi_Enable(&InstancePtr); return 0; } In der Simulation sieht das doch schonmal korrekt aus, was sagt ihr?
Mir ist noch aufgefallen, dass "mst_trans_inhibit" nach einer Zeit wieder von High auf Low wechselt. (-> deaktivieren der Master Transaktion) Und "sr2_spisel_slave" sieht irgendwie nicht korrekt aus.
Das letzte Foto erst einmal. Sorry. Das ist der komplette Abschnitt diesesmal: Initialisieren und Senden. Man sieht, dass der TX-Speicher einmal voll ist und auch wieder geleert wird. Trotzdem keine Reaktion an SPI_CLK, SPI_ENB etc. #include <stdio.h> #include "platform.h" #include "parameters.h" #include "spi.h" #include "xspi.h" void print(char *str); static XSpi InstancePtr; static XSpi_Config *SPI_Config; int main() { init_platform(); uint8_t in[4] = {0xf0, 0x0f, 0xf0, 0x1f}; uint8_t out[4] = {0x0f, 0x0f0, 0x10, 0x03}; XSpi_Initialize(&InstancePtr, SPI_DEVICE_ID); SPI_Config = XSpi_LookupConfig(SPI_DEVICE_ID); XSpi_CfgInitialize(&InstancePtr, SPI_Config, SPI_Config->BaseAddress); uint32_t Option = XSP_MASTER_OPTION | XSP_CLK_PHASE_1_OPTION |XSP_CLK_ACTIVE_LOW_OPTION |XSP_MANUAL_SSELECT_OPTION; XSpi_SetOptions(&InstancePtr, Option); XSpi_SetSlaveSelect(&InstancePtr, 0); XSpi_Enable(&InstancePtr); XSpi_Start(&InstancePtr); XSpi_Transfer(&InstancePtr, out, in, 4); return 0; }
Also sr_2_spisel_slave habe ich mit Setzen des Eingangs SPI_SEL auf '1' gesetzt, bzw. zum Test auf '0'.
Ich sehe nun die Sendedaten, CLK und ENB an den Signalen: spi_enb_o spi_clk_o spi_di_o Ich sehe sie eine Ebene höher nicht mehr. Also bei SPI_ENB, SPI_CLK, SPI_Do. Nun dachte ich, dass ich es umändern muss (siehe Foto). Dann erscheint folgende Fehlermeldung: ERROR:EDK:4068 - INSTANCE: axi_spi_0, PORT: MISO_I - THREE_STATE port, MISO, in use. Multiple drivers found on TRI_I port, MISO_I - Z:\EDK_Projekt\system.mhs line 163 ERROR:EDK:4074 - INSTANCE: axi_spi_0, PORT: SCK, CONNECTOR: axi_spi_0_SCK - No driver found - Z:\EDK_Projekt\system.mhs line 156 ERROR:EDK:4074 - INSTANCE: axi_spi_0, PORT: MISO, CONNECTOR: axi_spi_0_MISO - No driver found - Z:\EDK_Projekt\system.mhs line 157 ERROR:EDK:4074 - INSTANCE: axi_spi_0, PORT: MOSI, CONNECTOR: axi_spi_0_MOSI - No driver found - Z:\EDK_Projekt\system.mhs line 158 ERROR:EDK:4074 - INSTANCE: axi_spi_0, PORT: SS, CONNECTOR: axi_spi_0_SS - No driver found - Z:\EDK_Projekt\system.mhs line 159 Also scheint es wohl ein Problem mit der Schnittstelle nach Außen zu sein.
Ich lese aufmerksam mit, weil ich an einem ähnlichen Problem laboriere. Scheiss AXI-Mist.
Ok. Der Bus ist nicht schuld ;). Hast du einen Vorschlag für Abhilfe ? Bzw wie Ich weiter vorgehen kann dem Fehler auf die Spur zu kommen ? Danke euch
Ich vermute mal, da wird noch irgendeine Einstellung falsch sein. Bist Du sicher, dass der Core nicht im loopback-mode ist?
CLK-Signal liegt nun am Pin an. Hatte SlaveSelect nicht auf null. MISO, MOSI, EN liegen jedoch noch nicht an. Vorschläge?
Hat irgendwer die Möglichkeit es bei sich einmal zu simulieren. Finde den Fehler nicht. Habe versucht alle Einstellungen anzuhängen. Ratlos.
Wenn ich in Abbildung 1.gif axi_spi_o_sck_pin usw. auf die direction IO statt O stelle funktioniert es. Die Signale liegen nun am Pin an. Kann mir das einer erklären? SCK ist doch definitiv ein Ausgang, wenn der SPI ein Master ist.
User schrieb: > SCK ist doch definitiv ein Ausgang, wenn der SPI > ein Master ist. Korrekt, wenn er denn ein Master ist. Kenne mich mit AXI nicht aus, denke aber das du den Master/Slave Modus auch dynamisch zur Laufzeit umstellen kannst, ergo: sollte schon beim Design der SCK Pin bidirektional konfiguriert worden sein.
Danke. Das Thema mit dem Tri-State-Ausgängen habe ich mir durchgelesen. Deren Einstellung in EDK bzw. SDK noch nicht ganz verstanden wie es scheint. Anbei der aktuelle ISim-Verlauf. Das Signal SS kommt immernoch nicht bis ans obere Layer. Irgendwie wird immer wieder der hochohmige Z-Zustand eingenommen. Außerdem dachte ich, dass das SS_Signal (entspricht ja Enable) automatisch beim Start eines Transfers auf Low gezogen wird und nach dem Transfer wieder auf High gesetzt wird. Scheinbar muss ich das manuel mit XSpi_Enable() bzw. XSpi_Disable() machen. Ein weiterer Punkt: Scheinbar ist es egal, ob ich SPISEL auf Low oder High lege, wenn ich das Device als Master vorgesehen habe, richtig? Ich möchte die Übertragung gemäß Datenblatt (Figure 14 auf Seite 20) aufbauen. -> http://www.xilinx.com/support/documentation/ip_documentation/axi_spi/v1_02_a/axi_spi_ds742.pdf
Ein weiteres Problem: Möchte ich z.B. 24 Bit senden, dann muss ich schreiben: uint8_t Byte_1 = 0x01; uint8_t Byte_2 = 0x03; uint8_t Byte_3 = 0x02; uint8_t in[1] = {0x00,0x00,0x00}; uint8_t out[1] = {Byte_1, Byte_2, Byte_3}; XSpi_Initialize(&InstancePtr, SPI_DEVICE_ID); ConfigPtr = XSpi_LookupConfig(SPI_DEVICE_ID); XSpi_CfgInitialize(&InstancePtr, ConfigPtr,ConfigPtr->BaseAddress); uint32_t Option = XSP_MASTER_OPTION |XSP_CLK_ACTIVE_LOW_OPTION |XSP_MANUAL_SSELECT_OPTION; XSpi_SetOptions(&InstancePtr, Option); XSpi_SetSlaveSelect(&InstancePtr, 0); XSpi_Start(&InstancePtr); XSpi_Enable(&InstancePtr); XSpi_Transfer(&InstancePtr, out, in, 3); cleanup_platform(); return 0; Dann sehe ich zwischen den Bytes immer undefinierte kurze Zustände.
Hat einer eine Idee, wo die Zustande (rot dargestellt) nach Byte 1, Byte 2 u.s.w. herkommen? Bzw. wie man diese beseitigt? Kommt ja oft vor, dass man per SPI ein Befehl bit 2 Byte senden muss.
User schrieb: > Hat einer eine Idee, wo die Zustande (rot dargestellt) nach Byte 1, Byte Das ist das 8 Bit Reg. das muss im Zyklus neu geladen werden.+ Der Teiler-Takt für den SPI Clock muss aus dem Master-Takt eingesyncht werden. Da ist eben Pause ...bis es weiter geht. ############################################################# Transaction Width: Selects 8, 16 or 32-bit transactions. Each SPI transaction incorporates the selected number of bits. In dual and quad SPI modes, the transaction width is restricted to 8 bits. Seite 90 Transaction Width Link: http://www.xilinx.com/support/documentation/ip_documentation/axi_quad_spi/v3_1/pg153-axi-quad-spi.pdf Gruss Holger. Hier muss man auch warten,bis die MCU das SPI shiften erledigt hat. static unsigned char spiByte(unsigned char val) { USISR = (1<<USIOIF); // Clear Counter Overflow Interrupt Flag (by writing 1 to the USIOIF bit) USIDR = val; // Set data byte to send do { } while ((USISR & (1<<USIOIF)) == 0); // Check for OIF set which will happen after 16 cycles. //I.e. 8 bits since the clock toggles twice per bit. return ( USIDR); // Return data value } Mcu-isMaster SPI_S0# SPI Slave select out_put
:
Bearbeitet durch User
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.