microblaze spi core problem

T

Tobias Baumann

Guest
Hello

I'm using Xilinx EDK 11.5 with xps_spi core version 2.01b. Core is
correctly integrated in my SDK, I can see the signals on my DSO.
Everything seems to be allright. But I've got a little software problem.

In SDK I transfer my data with the function "XSpi_Transfer(&mySPI,
outBuffer, inBuffer, 2)" (see above). It works exactly one time and I
get XST_SCCUSS back. But if I call XSpi_Transfer again, I get
XST_DEVICE_BUSY back.

My program do the following steps:

1.) initalize SPI (function "XSpi_Initialize")
2.) set options (function "XSpi_SetOptions")
3.) select slave (function "XSpi_SetSlaveSelect")
4.) start SPI (function "XSpi_Start")
5.) transfer data (function "XSpi_Transfer")

Every function return XST_SUCCESS, but not Xspi_transfer when I call it
the second time.

So my question? Is there any bug in the core or have I forgot something?
I hope someone can help me. I tried to google, found a similar problem,
but no solution.

Thanks a lot,

Tobias

C-Code:

#include <stdio.h>
#include "platform.h"
#include "xbasic_types.h"
#include "xstatus.h"
#include "xparameters.h"
#include "xspi.h"

void SPIini(void);
void pause(void);

XSpi mySPI;

int main()
{
init_platform();

print("SPI Test\n\r");
pause();

Xuint8 inBuffer[4] = {0x00, 0x00, 0x00, 0x00};
Xuint8 outBuffer[4] = {0x00, 0xAA, 0xFF, 0xAA};

XStatus status = XST_SUCCESS;

SPIini();

for(Xuint8 i=0; i<100; i++) {

/* initialization */

status = XSpi_Transfer(&mySPI, outBuffer, inBuffer, 2);

switch(status)
{
case XST_SUCCESS: print("Status: Erfolgreich gesendet."); break;
case XST_DEVICE_IS_STOPPED: print("Status: Device stopped\n\r"); break;
case XST_DEVICE_BUSY: print("Status: Device busy\n\r"); break;
case XST_SPI_NO_SLAVE: print("Status: Device no slave\n\r"); break;
}

pause();
}

cleanup_platform();

return 0;
}

void SPIini(void)
{
XStatus status = XST_SUCCESS;

status = XSpi_Initialize(&mySPI, XPAR_TEST_SPI_DEVICE_ID);

switch(status)
{
case XST_SUCCESS: print("Status: Erfolgreich initialisiert\n\r"); break;
case XST_DEVICE_IS_STARTED: print("Status: Device is started\n\r"); break;
case XST_DEVICE_NOT_FOUND: print("Status: Device not found\n\r"); break;
}

Xuint32 options = XSP_MASTER_OPTION;
status = XSpi_SetOptions(&mySPI, options);

switch(status)
{
case XST_SUCCESS: print("Status: Erfolgreich option gesetzt\n\r"); break;
case XST_DEVICE_BUSY: print("Status: Device busy\n\r"); break;
case XST_SPI_SLAVE_ONLY: print("Status: Slave only\n\r"); break;
}

XSpi_SetSlaveSelect(&mySPI, 1);
XSpi_Start(&mySPI);
}

void pause(void)
{
for(int i=0; i<CPU_FREQ; i++);
}
 
Tobias Baumann <ttobsen@hotmail.com> writes:

Hello

I'm using Xilinx EDK 11.5 with xps_spi core version 2.01b. Core is
correctly integrated in my SDK, I can see the signals on my
DSO. Everything seems to be allright. But I've got a little software
problem.

In SDK I transfer my data with the function "XSpi_Transfer(&mySPI,
outBuffer, inBuffer, 2)" (see above). It works exactly one time and I
get XST_SCCUSS back. But if I call XSpi_Transfer again, I get
XST_DEVICE_BUSY back.
Maybe it is actually busy? There's a FIFO in the SPI controller, so
the XSpi_Transfer call can return before the hardware has finished
sending. Try checking the status flags before calling XSpi_Transfer
again.

If that's not the case, here's some other thoughts (without looking
deeply into your code, sorry!):

Have you provided your own XAssert handler function to report when
assertions fail - the Xilinx drivers are liberally sprinkled with
them, but the default action is just to hang. If you look at the call
stack in the debugger, you can see what's going on, but I prefer to
have it pushed out over stdout as well...

I have this in main():
XAssertSetCallback((XAssertCallback)myassert);

and this function elsewhere.

/* override the Xilinx xassert stub to report errors */
void myassert(char * file, int line)
{
xil_printf("XASSERT: %s: line %d\r\n", file, line);
}

This may give some clues.

Also:

Have you enabled interrupts? If so, is the driver expecting
interrupts? As I recall, the 2.00.a driver didn't work in
non-interrupt mode (it re-enabled the SPI interrupts at the end of a
transmit, irrespective of the interrupt status on entry :) but I think
that was fixed in 2.00.b

Have you provided a StatusHandler function for the spi driver? I seem
to recall doing this helped me debug a similar problem.

On the up side - you at least have all the source to the driver, so
you can single step everything through :)

void pause(void)
{
for(int i=0; i<CPU_FREQ; i++);
}
This is not the world's greatest pause function! The compiler will
just optimise the loop away (although probably not the function call
itself).

You need a timer in your system that you can watch to see elapsed
time.

Cheers,
Martin

--
martin.j.thompson@trw.com
TRW Conekt - Consultancy in Engineering, Knowledge and Technology
http://www.conekt.co.uk/capabilities/39-electronic-hardware
 
I have successfully used the SPI peripheral with a SPI Flash. The
only difference that I can see is a call to disable the interrupts
since I use the peripheral in polled mode:
XSpi_mIntrGlobalDisable(&mySpi);

Here's my instantiation from my MHS. I turned on the FIFOs and have
an SCK Ratio of 16 (this is from EDK 10):

BEGIN xps_spi
PARAMETER INSTANCE = SPI_FLASH
PARAMETER C_FIFO_EXIST = 1
PARAMETER C_SCK_RATIO = 16
PARAMETER HW_VER = 2.01.b
PARAMETER C_BASEADDR = 0x83400000
PARAMETER C_HIGHADDR = 0x8340ffff
BUS_INTERFACE SPLB = mb_plb
PORT SPISEL = net_vcc
PORT SCK = fpga_0_SPI_FLASH_SCK_pin
PORT MISO = fpga_0_SPI_FLASH_MISO_pin
PORT MOSI = fpga_0_SPI_FLASH_MOSI_pin
PORT SS = fpga_0_SPI_FLASH_SS_pin
END

Here's the complete example if you are interested:
www.em.avnet.com/spartan3a-evl --> > MicroBlaze Serial Flash Test

Bryan

On Dec 15, 10:05 am, Tobias Baumann <ttob...@hotmail.com> wrote:
Hello

I'm using Xilinx EDK 11.5 with xps_spi core version 2.01b. Core is
correctly integrated in my SDK, I can see the signals on my DSO.
Everything seems to be allright. But I've got a little software problem.

In SDK I transfer my data with the function "XSpi_Transfer(&mySPI,
outBuffer, inBuffer, 2)" (see above). It works exactly one time and I
get XST_SCCUSS back. But if I call XSpi_Transfer again, I get
XST_DEVICE_BUSY back.

My program do the following steps:

1.) initalize SPI (function "XSpi_Initialize")
2.) set options (function "XSpi_SetOptions")
3.) select slave (function "XSpi_SetSlaveSelect")
4.) start SPI (function "XSpi_Start")
5.) transfer data (function "XSpi_Transfer")

Every function return XST_SUCCESS, but not Xspi_transfer when I call it
the second time.

So my question? Is there any bug in the core or have I forgot something?
I hope someone can help me. I tried to google, found a similar problem,
but no solution.

Thanks a lot,

Tobias

C-Code:

#include <stdio.h
#include "platform.h"
#include "xbasic_types.h"
#include "xstatus.h"
#include "xparameters.h"
#include "xspi.h"

void SPIini(void);
void pause(void);

XSpi mySPI;

int main()
{
     init_platform();

        print("SPI Test\n\r");
        pause();

        Xuint8 inBuffer[4] = {0x00, 0x00, 0x00, 0x00};
        Xuint8 outBuffer[4] = {0x00, 0xAA, 0xFF, 0xAA};

        XStatus status = XST_SUCCESS;

        SPIini();

        for(Xuint8 i=0; i<100; i++) {

                /* initialization */

                status = XSpi_Transfer(&mySPI, outBuffer, inBuffer, 2);

                switch(status)
                {
                        case XST_SUCCESS: print("Status: Erfolgreich gesendet."); break;
                        case XST_DEVICE_IS_STOPPED: print("Status: Device stopped\n\r"); break;
                        case XST_DEVICE_BUSY: print("Status: Device busy\n\r"); break;
                        case XST_SPI_NO_SLAVE: print("Status: Device no slave\n\r"); break;
                }

                pause();
        }

     cleanup_platform();

     return 0;

}

void SPIini(void)
{
        XStatus status = XST_SUCCESS;

        status = XSpi_Initialize(&mySPI, XPAR_TEST_SPI_DEVICE_ID);

        switch(status)
        {
                case XST_SUCCESS: print("Status: Erfolgreich initialisiert\n\r"); break;
                case XST_DEVICE_IS_STARTED: print("Status: Device is started\n\r"); break;
                case XST_DEVICE_NOT_FOUND: print("Status: Device not found\n\r"); break;
        }

        Xuint32 options = XSP_MASTER_OPTION;
        status = XSpi_SetOptions(&mySPI, options);

        switch(status)
        {
                case XST_SUCCESS: print("Status: Erfolgreich option gesetzt\n\r"); break;
                case XST_DEVICE_BUSY: print("Status: Device busy\n\r"); break;
                case XST_SPI_SLAVE_ONLY: print("Status: Slave only\n\r"); break;
        }

        XSpi_SetSlaveSelect(&mySPI, 1);
        XSpi_Start(&mySPI);

}

void pause(void)
{
        for(int i=0; i<CPU_FREQ; i++);

}
 
Hi Martin and Bryan

You both were right. I had to disable the interrupts with
Xspi_mIntrGlobalDisable(&mySpi) and now it works fine. Thanks a lot to you!

But unfortunately I have a new problem. I want to stream data to a W-LAN
module, so I need a high throughput to max out my performance. The SPI
core is very slow, so I can't use the high performance of my W-LAN
module. (I get a throughput of 30kB/s, this is much to slow).

Has someone an idea how to increase the throughput of my system? A fine
solution would be, sending data directly from rams and/or registers via
SPI to my module. Maybe DMA is the right keyword, but I'm not sure,
because I'm a total beginner of programming microblaze and IP cores.

Maybe someone has a hint in which direction I have to search, for
finding a solution.

Thanks a lot!

Tobias
 
Some improvement can be made by decreasing the SCK Ratio, but you're
still dealing with the PLB. If this is Spartan-6 or Virtex-6, you
could look at switching to AXI. You could also look at a designing
your own simple SPI peripheral and connect to MicroBlaze via FSL.

Bryan

On Dec 21, 10:02 am, Tobias Baumann <ttob...@hotmail.com> wrote:
Hi Martin and Bryan

You both were right. I had to disable the interrupts with
Xspi_mIntrGlobalDisable(&mySpi) and now it works fine. Thanks a lot to you!

But unfortunately I have a new problem. I want to stream data to a W-LAN
module, so I need a high throughput to max out my performance. The SPI
core is very slow, so I can't use the high performance of my W-LAN
module. (I get a throughput of 30kB/s, this is much to slow).

Has someone an idea how to increase the throughput of my system? A fine
solution would be, sending data directly from rams and/or registers via
SPI to my module. Maybe DMA is the right keyword, but I'm not sure,
because I'm a total beginner of programming microblaze and IP cores.

Maybe someone has a hint in which direction I have to search, for
finding a solution.

Thanks a lot!

Tobias
 
Am 22.12.2010 17:34, schrieb Bryan:
Some improvement can be made by decreasing the SCK Ratio, but you're
still dealing with the PLB. If this is Spartan-6 or Virtex-6, you
could look at switching to AXI. You could also look at a designing
your own simple SPI peripheral and connect to MicroBlaze via FSL.
I'm working with a Spartan 3A-DSP.

After optimizing the settings of the SPI-Core I get a much higher
throughput (maybe 500kB/s to 1MB/s, I still have to measure it).

I thought that I have to make my own SPI peripheral to optimize my
problem, but I hoped that there is a finshed solution.

Thanks a lot.

Tobias
 

Welcome to EDABoard.com

Sponsor

Back
Top