cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Highlighted
Adventurer
Adventurer
582 Views
Registered: ‎09-11-2018

XSpi_Transfer stuck on XSP_INTR_TX_EMPTY_MASK - in Polled mode

(I had this post in this thread here earlier, but I had already accepted the solution to its original question, so I'm moving the new question to this new thread
https://forums.xilinx.com/t5/Processor-System-Design/QSPI-flash-on-MicroBlaze-correct-driver-code/m-p/1034274/highlight/false#M49525
)

I have some configuration problem, apparently.

I have taken the Winbond SPI flash driver code example (IRQ based), and also looked at another example for polled mode - because I don't have/want an interrupt for this SPI channel, and tried to change my setup such that I am using polled mode, no interrupt.

Yet, when I am trying to use this SPI, then I am seeing something strange:
The first call to XSpi_Transfer() does return - when I read the status register of the connected flash IC. The result seems wrong, but that could have a lot of causes.
When I later call  XSpi_Transfer() again to send a sector erase command to the flash, XSpi_Transfer() hangs...
And now with debugging enabled for the BSP, I see it hangs here:

do {
	StatusReg = XSpi_IntrGetStatus(InstancePtr);
} while ((StatusReg & XSP_INTR_TX_EMPTY_MASK) == 0);


So it seems it is expecting to be something happening with regards to an interrupt. Althouth this loop is in the code branch which a comment describes as: "Polled mode of operation", and the branch above that, it's called "Interrupt Mode of operation".
Why is it querying interrupt related flags there (at least that's what their names and comments above the defines suggest)?
If I am just misunderstanding this and it has not (necessarily) something to do with interrupt:

What could cause the TX register not becoming empty / how could I investigate that?

Here is my modified winbond flash example init code, with the intent to make it polling mode:

static int read_status()
{
WriteBuffer[0] = COMMAND_STATUSREG_READ;
int ret = transfer(WriteBuffer, ReadBuffer, STATUS_READ_BYTES);
return ret==XST_SUCCESS ? ReadBuffer[1] : -1;
}


int XspiFlash_Init()
{ ConfigPtr = XSpi_LookupConfig(SPI_DEVICE_ID); if (ConfigPtr == NULL) { return XST_DEVICE_NOT_FOUND; } if ( XST_SUCCESS != XSpi_CfgInitialize(&m_xspi, ConfigPtr, ConfigPtr->BaseAddress) || XST_SUCCESS != XSpi_SetOptions(&m_xspi, XSP_MASTER_OPTION | XSP_MANUAL_SSELECT_OPTION) || XST_SUCCESS != XSpi_SetSlaveSelect(&m_xspi, SPI_SELECT) ) { return XST_FAILURE; } XSpi_Start(&m_xspi); /* * Disable Global interrupt to use polled mode operation */ XSpi_IntrGlobalDisable(&m_xspi); const int stat = read_status(); // *** NOTE *** This calls XSpi_Transfer, which returns, a value of 0xff (wrong, but anyway)
if (stat < 0)
return XST_FAILURE;

if (!(stat & quadEnableBit)) // let's only write this NON-VOLATILE bit if need be, to not unnecessarily reduce the lifetime.
{ // [removed for brevity] code to set flash to quad mode - get's never called, as 0xff always has the QE bit set...
} return XST_SUCCESS; }

After that init code, XSpi_Transfer is called once more - to send a command for Sector Erase to the flash, and it hangs on that, waiting for the TX empty, like described above.

Tags (3)
3 Replies
Highlighted
Adventurer
Adventurer
523 Views
Registered: ‎09-11-2018

Ok folks, I have no idea why it does not work in polled mode.

I configured things for interrupt mode, and it seems to just work. So although it seems kinda unnecessary to use an interrupt in my scenario, since it doesn take away from anything else that might need one, I won't bother investigating this further.

 

0 Kudos
Highlighted
Adventurer
Adventurer
298 Views
Registered: ‎11-13-2018

Hi @sktpin,

I'm experiencing the same problem. I was wondering how you were able to add interrupt mode into your design. I need to connect the ip2intc_irpt pin from the AXI SPI IP to an AXI interrupt controller, right? Then in my application would I use the SetupInterruptSystem() function to create the interrupt?

Thanks in advance for your help.

Brad

0 Kudos
Highlighted
Adventurer
Adventurer
239 Views
Registered: ‎09-11-2018

I don't have the Vivado project ready to look at that part and I didn't do the FPGA design, but most certainly there would have to be a connection from the SPI stuff to the µBlaze for it to see the interrupt.

We might be using different Xilinx SDKs, I can't find "SetupInterruptSystem" in any source file of that project.

What I have is this, roughly:

#include "xparameters.h"	/* XPAR parameters */
#include "xspi.h"		/* SPI device driver */
#include "xintc.h"		/* Interrupt controller devive driver */
#include "xil_exception.h"

#define INTC_DEVICE_ID		XPAR_INTC_0_DEVICE_ID

static XIntc m_intcInstance;  /* Instance of the Interrupt controller device */

static int init()
{
	if (XST_SUCCESS != XIntc_Initialize(&m_intcInstance, INTC_DEVICE_ID))
		return XST_FAILURE;

	/*
	 * Enable the interrupt for the Spi device.
	 */
	XIntc_Enable( &m_intcInstance, id );
	if (XST_SUCCESS != XIntc_Connect( &m_intcInstance, id, (XInterruptHandler)handler, callBackRef ))
		return XST_FAILURE;
		
	if (XST_SUCCESS != XIntc_Start(&m_intcInstance, XIN_REAL_MODE))
		return XST_FAILURE;


	/*
	 * Initialize the exception table.
	 */
	Xil_ExceptionInit();

	/*
	 * Register the interrupt controller handler with the exception table.
	 */
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
				(Xil_ExceptionHandler)XIntc_InterruptHandler,
				&m_intcInstance);

	/*
	 * Enable non-critical exceptions.
	 */
	Xil_ExceptionEnable();

	return XST_SUCCESS;		
}


"Roughly" meaning, I copy+pasted together things in the sequence they would happen, to make it simpler vs. the actual code - so some ad-hoc editing mistakes (incl. some of the return value checking) might have crept in there - don't necessarily take this verbatim.

If the SDK you're using does not have this, it might not be of much help, but might be a reference for someone else stumbling on this