SPI AXI Sensor

Gast #3485485
Lesenswert?

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

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

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

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

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

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

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

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;
 }
}
#3489706
Lesenswert?

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

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

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

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;
}
Angehängte Dateien:
Gast #3490505
Lesenswert?

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

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

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

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.
Angehängte Dateien:
Persönliche Seite #3507854
Lesenswert?

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

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