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?
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.
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.
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.
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?
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;
}
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.
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
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