SPI Read Problem

I am trying to get my SPI working but I got into several problems.

Here is the functions I am using to get the revision number of my SPI peripheral.

// Structure used in SPI registration
static NASpiDeviceConfigType SPI_CP2120 [] =
{
{
1, /Serial Port, 0 based/
NULL, /Callback function to select the SEEPROM Chip/
NULL, /Callback function to deselect the SEEPROM Chip/
NA_SPI_MODE0, /SPI mode, only mode 0 is supported in NS7520/
NA_SPI_MSB, /most significant bit first/
100000, /speed/
40, /deselect time/
“NWC_CP2120”/unique name for this device/
},
};

void TestSPI (void)
{
NaStatus ccode;
char Revision[2];

ccode = NASpiRegisterDevice(&SPI_CP2120[0]);
if (ccode != NASTATUS_SUCCESS)
{
	printf("NASpiRegisterDevice() failed 0x%X

", (unsigned int)ccode);
}
else
{
//Get version from chip
GetCP2120Revision(Revision);

	//Deregister the SPI Port		
	NASpiDeregisterDevice(SPI_CP2120[0].name);

	if (ccode != NASTATUS_SUCCESS)
	{
		printf("NASpiDeregisterDevice() failed 0x%X!

", (unsigned int)ccode);
}
else
{
printf("NASpiDeregisterDevice() success!

");
}
}

return;

}

//Command template is out:[command][don’t care]
// in: [Rev Byte 1] [Rev Byte 2]
void GetCP2120Revision (char* Revision)
{
NaStatus Status;
char Buffer[128];
char Response[128];

memset(Buffer, 0xFF, 128);
memset(Response, 0xFF, 128);

Buffer[0] = 0x40;

    //use bufferlength of 4 to include 2 bytes out and 2 bytes in    from what I have read on the forum
Status = NASpiReadWrite(SPI_CP2120[0].name, Buffer, Response, 4);

if(NA_IS_SUCCESS(Status))
{
	Revision[0] = Response[0];
	Revision[1] = Response[1];
	printf("SPI Success

");
}
}

With this code I am using getting the error NASTATUS_SPI_MASTER_INVALID_BUFFER.

Anyone has any idea why this is happening? Am I wrong to assume that if my buffer has a length of 128 bytes that it should be 32-bits aligned?

Regards

Hi,

The buffers need to be on a 32 Byte boundary for SPI. I believe this is required for the DMA to operate correctly.

I remember having some problems trying to get this alignment simply and developed the following routine to allocate SPI buffers.

It is a bit inefficient but ios seems to work OK for me.

/*********************************************************************
Definitions of SPI buffer structures used to transfer data
*********************************************************************/
struct str_spi_buffers {
unsigned char *rd_algn_ptr;
unsigned char *wr_algn_ptr;
};

/*****************************************************************************

SPI_AllocBuffers:

Description:
This routine is used to allocate buffers to be used by the SPI ReadWrite
routine. The routine first allocates a str_spi_buffers structure and then
fills this structure with pointers to the equal sized read and write buffers
that are correctly aligned on a 32 byte boundary

  Parameters
    size			Required buffer size
    
  Returns
    Pointer to allocated structue		(NOTE: use SPI_FreeBuffers to free this)
			NULL	error allocating buffers

*****************************************************************************/
struct str_spi_buffers * SPI_AllocBuffers(int size)
{
UINT status;
int rqd_size;
unsigned int temp;
struct str_spi_buffers *ptr = NULL;
const char *ERR_FMT = "ERR:[%08ld] SPI_InitModule: %s() failed with status %d.
";

/* Determine the total size required */
rqd_size = ((size + BYTE_ALIGN - 1) * 2) + sizeof(struct str_spi_buffers);

/* Allocate memory for both structure and buffers */
status = tx_byte_allocate(&GBL_SPI_pool, (VOID *)&ptr, rqd_size, TX_NO_WAIT);
if (status != TX_SUCCESS) {
	printf(ERR_FMT, tx_time_get(), "tx_byte_allocate", status);
	return(NULL);
}

/* Determine aligned pointer for rd buffer */
temp = (unsigned int)ptr + sizeof(struct str_spi_buffers);
if (temp % BYTE_ALIGN) {
	temp += BYTE_ALIGN - (temp % BYTE_ALIGN);
}
ptr->rd_algn_ptr = (unsigned char *)temp;

/* Determine aligned pointer for wr buffer */
temp += size;
if (temp % BYTE_ALIGN) {
	temp += BYTE_ALIGN - (temp % BYTE_ALIGN);
}
ptr->wr_algn_ptr = (unsigned char *)temp;

return (ptr);

}

/*****************************************************************************

SPI_FreeBuffers:

Description:
This routine is used to free buffers that were provided by SPI_AllocBuffers

  Parameters
    spi_buffers			Pointer to the allocated bufferrs
    
  Returns
    status      SPI_OK (0)             	= Success
                SPI_ERR_MEMORY					= Failed to release memory

*****************************************************************************/
int SPI_FreeBuffers(struct str_spi_buffers *spi_buffers)
{
UINT status;
const char *ERR_FMT = "ERR:[%08ld] SPI_FreeBuffers: %s() failed with status %d.
";

/* Allocate memory for controlling structure */
status = tx_byte_release((VOID *)spi_buffers);
if (status != TX_SUCCESS) {
	printf(ERR_FMT, tx_time_get(), "tx_byte_release", status);
	return(SPI_ERR_MEMORY);
}

return(SPI_ERR_OK);

}

Thank you very much for your routines concerning the allocation of thebuffers.

I have used it and now I am getting a different error NASTATUS_SPI_MASTER_DMA_FAILED . I have noticed that the length passed in NASpiReadWrite() is confusing also, what should I put as length, the TX length or the TX + RX length ? Maybe that may cause my problem…

If this is not working with a good length in parameter I will recheck every signal on the module to make sure everything is ok.

Hi,

The length passed to NASpiReadWrite() is used for both the Tx Length and the Rx length. Effectively the data from the Tx buffer is clocked out and the data in the Rx buffer is clocked in using the same clock, atr the same time. The way to interpret this does depend a bit on the exact way the peripheral works. If youare ony reading then you can ignore the data in the Tx buffer, but it still must be there to provide data even though it is ignored. Similarly when writing data will be read into the Rx buffer so that must be there also.

The Initialisation I use to set up the GPIO is:
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ConfigureGPIO:

Description:
This routine is used to configure the GPIO pins that will be used for
the SPI interface. It uses the pin definitions from spi.h and is
caled by the main Module Initialisation routine.

Parameters
None

Return
None

static void ConfigureGPIO(void)
{
	#if (PROCESSOR == ns9210 || PROCESSOR == ns9215)
	    NAconfigureGPIOpin(APP_SPI_MASTER_GPIO_CS, NA_GPIO_FUNC4_STATE, 0);      
	    NAconfigureGPIOpin(APP_SPI_MASTER_GPIO_CLK, NA_GPIO_FUNC4_STATE, 0);
	    NAconfigureGPIOpin(APP_SPI_MASTER_GPIO_RXD, NA_GPIO_FUNC4_STATE, 0);
	    NAconfigureGPIOpin(APP_SPI_MASTER_GPIO_TXD, NA_GPIO_FUNC4_STATE, 0);
	
	#elif (PROCESSOR == ns9360 || PROCESSOR == ns7520)
	    NAconfigureGPIOpin(APP_SPI_MASTER_GPIO_CS, NA_GPIO_OUTPUT_STATE, 1);  /*enable*/
	    NAsetGPIOpin (APP_SPI_MASTER_GPIO_CS, 1);
	
	    NAconfigureGPIOpin(APP_SPI_MASTER_GPIO_CLK, NA_GPIO_OUTPUT_STATE, 0);  /*clk*/
	    NAsetGPIOpin (APP_SPI_MASTER_GPIO_CLK, 0);
	
	    NAconfigureGPIOpin(APP_SPI_MASTER_GPIO_CS, NA_GPIO_FUNC0_STATE, 0);  
	    NAconfigureGPIOpin(APP_SPI_MASTER_GPIO_CLK, NA_GPIO_FUNC0_STATE, 0); 
	#else
		#error "set up the GPIO pins here.
Then, comment this line out to build your platform."
	#endif
}



Then the device registration is done by:
/***************************************************************************** 

   SPI_OpenModule:
   
   Description: 
      This routine is used to initialise the SPI module. 
			The required GPIO signals asr set up and a device description is added
			to the NetOS driver table

			NOTE: This currently supports a master interface optimised for CML C-BUS

      Parameters
        None
        
      Returns
        status      SPI_OK (0)             	= Success
                    SPI_ERR_MEMORY					= Failed to generate memory pool
                    SPI_ERR_REGISTER				= Failed to register device 
           
*****************************************************************************/ 
int SPI_OpenModule(void)
{
	UINT status;
	NaStatus reg_stat;
	const char *ERR_FMT = "ERR:[%08ld] SPI_InitModule: %s() failed with status %d.
";
	
	/* Configure the hardware signal we will use */
	ConfigureGPIO();
	
	/* Create the memory pool to be used for SPI buffers */
	status = CreateBufferPool();
	if (status) {
		return(SPI_ERR_MEMORY);
	}

  reg_stat = NASpiRegisterDevice(&GBL_CMX_Device);
  if (NA_IS_ERROR(reg_stat))
  {
		printf(ERR_FMT, tx_time_get(), "NASpiRegisterDevice", reg_stat);
		return(SPI_ERR_REGISTER);
  }
	
	return (SPI_ERR_OK);
}



And the actual transfer is:

/***************************************************************************** 

   SPI_ReadWrite:
   
   Description: 
      This routine is used to transfer data on the SPI bus. It should passed a 
      buffer structure that was allocated by SPI_AllocBuffers, and with data to 
      be written set up at the wr_algn_ptr. The routine reads and writes at the 
      same time. When the routine returns read data will be at the rd_align_ptr 
      location.
      
      Parameters
      	device		Name of device for data transfer (SPI_CMX7143)
      	buffs			pointer to structure containing read and write buffers
        length		Number of bytes to be transferred
        
      Returns
        Pointer to allocated structue		(NOTE: use SPI_FreeBuffers to free this)
				NULL	error allocating buffers
           
*****************************************************************************/ 
int SPI_ReadWrite(char * device, struct str_spi_buffers *buffs, int length)
{
	NaStatus status;
	const char *ERR_FMT = "ERR:[%08ld] SPI_ReadWrite: %s() failed with status %d.
";
	char *wr_ptr = (char *)(buffs->wr_algn_ptr);
	char *rd_ptr = (char *)(buffs->rd_algn_ptr);

	ShowBuff("SPT", wr_ptr, length);
	status = NASpiReadWrite(device, wr_ptr, rd_ptr, length);
	ShowBuff("SPR", rd_ptr, length);
  if (NA_IS_ERROR(status))
  {
		printf(ERR_FMT, tx_time_get(), "NASpiReadWrite", status);
		return(SPI_ERR_REGISTER);
  }

	return (SPI_ERR_OK);
}

The actual GPIO pins used are defined by

/*********************************************************************
   Definition of the Port and GPIO Signals to be used
*********************************************************************/
#define PORTA 0
#define PORTB 1
#define PORTC 2
#define PORTD 3

#if (PROCESSOR == ns9215)
    #define APP_SPI_MASTER_PORT         PORTA
    #define APP_SPI_SLAVE_PORT          PORTA
    #define APP_SPI_MASTER_GPIO_CS      0
    #define APP_SPI_MASTER_GPIO_CLK     5
    #define APP_SPI_MASTER_GPIO_RXD     3
    #define APP_SPI_MASTER_GPIO_TXD     7
    #define APP_SPI_SLAVE_GPIO_CS       0
    #define APP_SPI_SLAVE_GPIO_CLK      5
    #define APP_SPI_SLAVE_GPIO_RXD      3
    #define APP_SPI_SLAVE_GPIO_TXD      7
#elif (PROCESSOR == ns9210)
    #define APP_SPI_SLAVE_PORT          PORTA
    #define APP_SPI_MASTER_PORT         PORTA
    #define APP_SPI_MASTER_GPIO_CS      0
    #define APP_SPI_MASTER_GPIO_CLK     5
    #define APP_SPI_MASTER_GPIO_RXD     3
    #define APP_SPI_MASTER_GPIO_TXD     7
    #define APP_SPI_SLAVE_GPIO_CS       0
    #define APP_SPI_SLAVE_GPIO_CLK      5
    #define APP_SPI_SLAVE_GPIO_RXD      3
    #define APP_SPI_SLAVE_GPIO_TXD      7
#elif (PROCESSOR == ns9360)
    #define APP_SPI_MASTER_PORT         PORTB
    #define APP_SPI_SLAVE_PORT          PORTB
    #if (APP_SPI_MASTER_PORT == PORTB)
        #define APP_SPI_MASTER_GPIO_CS  7
        #define APP_SPI_MASTER_GPIO_CLK 6
    #elif (APP_SPI_MASTER_PORT == PORTC)
        #define APP_SPI_MASTER_GPIO_CS  23
        #define APP_SPI_MASTER_GPIO_CLK 22
    #elif (APP_SPI_MASTER_PORT == PORTD)
        #define APP_SPI_MASTER_GPIO_CS  27
        #define APP_SPI_MASTER_GPIO_CLK 26
    #endif
    #if (APP_SPI_SLAVE_PORT == PORTB)
        #define APP_SPI_SLAVE_GPIO_CS   7
        #define APP_SPI_SLAVE_GPIO_CLK  6
    #elif (APP_SPI_SLAVE_PORT == PORTC)
        #define APP_SPI_SLAVE_GPIO_CS   23
        #define APP_SPI_SLAVE_GPIO_CLK  22
    #elif (APP_SPI_SLAVE_PORT == PORTD)
        #define APP_SPI_SLAVE_GPIO_CS   27
        #define APP_SPI_SLAVE_GPIO_CLK  26
    #endif
#elif (PROCESSOR == ns7520)
    #define APP_SPI_MASTER_PORT         PORTB
    #define APP_SPI_MASTER_GPIO_CS      0
    #define APP_SPI_MASTER_GPIO_CLK     4
#else
#error "SPI support not available on this processor or platform."
#endif

I have only used this with a ConnectCore9P_9215 to communicate with a SPI compatiable device and it works very well apart from being rather slow.

Hope this helps

Thank you very much rdeabill it helped out a lot. I am not able to send correctly over the SPI bus now but I have found out that my SPI device chip requires a mode 3 which is not available for the NS7520. I was wondering if some code is now available for the NS7520 in mode 1. Currently, we only have mode 0. If mode 1 was available I could try to inverse the clock with hardware and use mode 1 and see if it works.

Regards,