- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic to the Top
- Bookmark
- Subscribe
- Printer Friendly Page
XPS SPI Core and SD Card
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
08-25-2011 06:12 AM
Hi,
my objective is to write data to a sd card via Microblaze and its SPI Core.
Is it possible to handle the individual sd init ?
Are there any examples ? The only i found was the SP605 Example - CF Card.
Solved! Go to Solution.
Re: XPS SPI Core and SD Card
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
08-25-2011 09:59 PM
Hi,
Its really easy to communicate to a SD card in SPI module using the XPS-SPI Core.
On the SD Card the following pin mapping is used:
Pin 1 -> SPI SS
Pin 2 -> SPI MOSI
Pin 5 -> SPI CLK
Pin 7 -> SPI MISO
There is a difference between SD cards using SD V1.0, SD V2.0 and the SHDC specifications. You should get a copy of the spec from google. It is also important that if you want to have the SD card used in SPI mode then you'll need to keep pin 1 low during POR (from memory). Otherwise the card will operate in SD-1bit mode.
As for the code to init the card and read/write sectors... you should use google. There are lots of projects on the web for this.
Cheers
Lachlan.
Re: XPS SPI Core and SD Card
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
08-25-2011 11:30 PM
Hi lockiegrogan,
thanks for reply !
I read the the specification v. 3.0 and im familiar with the sdc init routine. I also found a initialization flow like this :
http://elm-chan.org/docs/mmc/sdinit.png
What i mainly wanted to know is how the spi-core muste be set/ intialized to communicate with an sd-card.
The datasheet from the LogiCore IP XPS SPI v2.02a only gives information about the registers but not about the functions
included via xspi.h and xspil.h.
Its essential that the SPI Core and furthermore the xspi.h functions supports multibyte transfer because one SD "Command" exists of 6 Bytes.
Greets
Christian
Re: XPS SPI Core and SD Card
[ Edited ]- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
08-26-2011 12:22 AM - edited 08-26-2011 01:02 AM
In other words :)
I would init the SPI Core like this (Only first CMD Send):
This Code is from the example of the SP605 Board -> Write/Read to a STM Flash
#include "xparameters.h" /* EDK generated parameters */
#include "xspi.h" /* SPI device driver */
#include "mb_interface.h" /* Microblaze interface */
/*
* The following constants map to the XPAR parameters created in the
* xparameters.h file. They are defined here such that a user can easily
* change all the needed parameters in one place.
*/
#define SPI_DEVICE_ID XPAR_SPI_0_DEVICE_ID
/*
* The following constant defines the slave select signal that is used to
* to select the Flash device on the SPI bus, this signal is typically
* connected to the chip select of the device.
*/
#define STM_SPI_SELECT 0x01 // 0x01 for Port 1 CS ?
/*
* The instances to support the device drivers are global such that they
* are initialized to zero each time the program runs. They could be local
* but should at least be static so they are zeroed.
*/
static XSpi Spi;
/*
* Initialize the SPI driver so that it's ready to use,
* specify the device ID that is generated in xparameters.h.
*/
Status = XSpi_Initialize(&Spi, SPI_DEVICE_ID);
if(Status != XST_SUCCESS) {\
xil_printf("Failure INIT\r\n");
return XST_FAILURE;
}
/*
* Set the SPI device as a master and in manual slave select mode such
* that the slave select signal does not toggle for every byte of a
* transfer, this must be done before the slave select is set.
*/
Status = XSpi_SetOptions(&Spi, XSP_MASTER_OPTION |
XSP_MANUAL_SSELECT_OPTION);
if(Status != XST_SUCCESS) {
xil_printf("Failure Options\r\n");
return XST_FAILURE;
}
/*
* Select the device on the SPI bus, so that it can be
* read and written using the SPI bus.
*/
Status = XSpi_SetSlaveSelect(&Spi, STM_SPI_SELECT);
if(Status != XST_SUCCESS) {
xil_printf("Failure Slave Select\r\n");
return XST_FAILURE;
}
/*
* Start the SPI driver so that the device are enabled.
*/
XSpi_Start(&Spi);
// ****************** SD INIT ***********************
/*
* Prepare the WriteBuffer.
*/
WriteBuffer[BYTE1] = CMD 0;
WriteBuffer[BYTE2] = Argument Byte 1/4;
WriteBuffer[BYTE3] = Argument Byte 2/4;
WriteBuffer[BYTE4] = Argument Byte 3/4;
WriteBuffer[BYTE5] = Argument Byte 4/4;
WriteBuffer[BYTE6] = CRC BYTE
/*
* Initiate the Transfer.
*/
TransferInProgress = TRUE;
Status = XSpi_Transfer(SpiPtr, WriteBuffer, NULL,6);
if(Status != XST_SUCCESS) {
xil_printf("Error in transfer\r\n");
return XST_FAILURE;
}
Re: XPS SPI Core and SD Card
[ Edited ]- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
08-27-2011 03:40 AM - edited 08-27-2011 03:43 AM
I used the xps spi core in the first version of a product supporting sdhc cards. I made a local copy of the ip and added the ability to support two clocks, one at 400khz and one at 25mhz as per spec. I used a spare bit in the register to control the clock speed cos as u know you'll need to start at 400k, query the card and change freq later on.
As for the code, if you manually control the slave select pin then you can do multibyte. What I have never done is used the xilinx drivers, I have always written directly to the registers using XIo_... Commands. It took a few hrs of extra coding, but well worth it. If you want any speed when reading and writing blocks from the card then you can consume another bit in the control register and rather than readin 8bits, read 32bits at a time. This way you make the most of the bus transfer to your micro blaze. In my tests if you don't have the software overhead of setting and clearing the slave select pin on each transfer and use full bus width transfers from the card you will be able to stream video from the card....
Cheers
Lachlan
Re: XPS SPI Core and SD Card
[ Edited ]- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
08-28-2011 11:49 PM - edited 08-29-2011 12:21 AM
Hi lockiegrogan,
were do you find those Xlo.. commands ? As far as i know, the 400khz initialization speed is only for mmc cards and not for sd cards.
Anyway, are there any code examples you found ? I dont feel certain with those initialization:
several commands for sd init
-> one command : 6 bytes
-> send one byte per SPI then the others and so on...
-> send one byte :
static void spi_write_byte(XSpi *SpiPtr,uint8_t byte)
{
XSpi_Transfer(SpiPtr, byte, NULL,1);
}
?
greets
Re: XPS SPI Core and SD Card
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
08-29-2011 12:59 AM
Perhaps i can send with selecting manual slave select mode the whole cmd (and receive the response) like this? :
/*
* Prepare the WriteBuffer.
*/
WriteBuffer[BYTE1] = CMD;
WriteBuffer[BYTE2] = Argument[1]; //Argument[31..24]
WriteBuffer[BYTE3] = Argument[2]; //Argument[23..16]
WriteBuffer[BYTE4] = Argument[3]; //Argument[15..8]
WriteBuffer[BYTE5] = Argument[4]; //Argument[7..0]
WriteBuffer[BYTE6] = CRC;
XSpi_Transfer(SpiPtr, WriteBuffer, Response,6);
The Bytecount is equal to the written bytes?
Greets
Re: XPS SPI Core and SD Card
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
08-29-2011 02:58 PM
Hi,
Here is how I would write one byte out the SPI using XIo_Out32...
u8SDSPI_SendByte(Xuint8 u8OutGoing)
{
Xuint32 u32Return;
Xuint32 u32Read;
//Set the SSO bit (force chipselect)
u32_SDLowLevel_ControlRegister |= C_SDCON_CONTROL_REG_SLAVE_SELECT_MASK;
XIo_Out32((C_SDCON_CONTROLLER_BASE_ADDRESS) +SDCON_SDCON_SLAVE_WRITE_CONTROL, u32_SDLowLevel_ControlRegister);
//load our byte
//This will also force a start of the write and read
XIo_Out32((C_SDCON_CONTROLLER_BASE_ADDRESS) +SDCON_SDCON_SLAVE_WRITE_DATA, (Xuint32)u8OutGoing);
//wait until done
u32Read = XIo_In32((C_SDCON_CONTROLLER_BASE_ADDRESS) +SDCON_SDCON_SLAVE_READ_STATUS);
while((u32Read & C_SDCON_STATUS_REG_BUSY_MASK) == C_SDCON_STATUS_REG_BUSY_MASK)
{
u32Read = XIo_In32((C_SDCON_CONTROLLER_BASE_ADDRESS) +SDCON_SDCON_SLAVE_READ_STATUS);
}
//read the returned data
u32Return = XIo_In32((C_SDCON_CONTROLLER_BASE_ADDRESS) +SDCON_SDCON_SLAVE_READ_DATA);
//write to the control register and disable the chip select
u32_SDLowLevel_ControlRegister &= C_SDCON_CONTROL_REG_SLAVE_SELECT_MASK_CLEAR; XIo_Out32((C_SDCON_CONTROLLER_BASE_ADDRESS) +SDCON_SDCON_SLAVE_WRITE_CONTROL, u32_SDLowLevel_ControlRegister);
return (Xuint8)u32Return;
}
You can just as easily send that byte without using the chip select.
And when you want to send a command, call the IssueCommand function:
void vSDSPI_IssueCommand(Xuint8 u8Command, Xuint16 u16ParameterX, Xuint16 u16ParameterY)
{
Xuint8 u8Return;
Xuint8 u8CRC;
//send 8 clocks
u8Return = u8SDCON_SPI_SendByte(0xFF);
//send the command
u8Return = u8SDSPI_SendByte(0x40 | u8Command);
//send the MSB of ParamX
u8Return = u8SDSPI_SendByte((Xuint8) (u16ParameterX >> 8));
//send the LSB of ParamX
u8Return = u8SDSPI_SendByte((Xuint8) (u16ParameterX));
//send the MSB of ParamY
u8Return = u8SDSPI_SendByte((Xuint8) (u16ParameterY >> 8));
//send the LSB of ParamY
u8Return = u8SDSPI_SendByte((Xuint8) (u16ParameterY));
#if C_LOCALDEF__SDCON__CRC_SOFTWARE == 1
u8CRC = 0x00;
u8CRC = u8SDNPI_CRC__7Bit_Add(u8CRC, 0x40 | u8Command);
u8CRC = u8SDNPI_CRC__7Bit_Add(u8CRC, (Xuint8) (u16ParameterX >> 8));
u8CRC = u8SDNPI_CRC__7Bit_Add(u8CRC, (Xuint8) (u16ParameterX));
u8CRC = u8SDNPI_CRC__7Bit_Add(u8CRC, (Xuint8) (u16ParameterY >> 8));
u8CRC = u8SDNPI_CRC__7Bit_Add(u8CRC, (Xuint8) (u16ParameterY));
u8CRC = u8SDNPI_CRC__7Bit_Finalise(u8CRC);
u8CRC <<= 1;
//always add the 0x01 as this is the stop bit.
u8CRC |= 0x01;
#endif //C_LOCALDEF__SDCON__CRC_SOFTWARE ==1
#if C_LOCALDEF__SDCON__CRC_DISABLE == 1
//send the checksum
switch(u8Command)
{
case C_SDCARDCOMMAND__SEND_IF_COND__CMD8:
//when sending the IF cond (CMD8) iwe must always send
//the correct CRC
u8Return = u8SDSPI_SendByte(0x87);
break;
case C_SDCARDCOMMAND__GO_IDLE__CMD0:
//CMD0 = 0x95 CRC
u8Return = u8SDSPI_SendByte(0x95);
break;
default:
//for all other commands, CRC is ignored in SPI mode.
u8Return = u8SDSPI_SendByte(0xFF);
break;
}
#elif C_LOCALDEF__SDCON__CRC_SOFTWARE == 1
u8Return = u8SDSPI_SendByte(u8CRC);
#else
#error
#endif
//send some more clocks to eat the empty command slot.
//u8Return = u8SDSPI_SendByte(0xFF);
}
Does that help a bit?
Lachlan.
Re: XPS SPI Core and SD Card
[ Edited ]- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
08-29-2011 11:26 PM - edited 08-29-2011 11:44 PM
Hi Lachlan,
yes this helps me alot.
Am i right that those Xio_.. Commands are lower lvl Drivers from the Xilinx Library ?
Or were do you find them ?
Ive got a Problem with the Bustimings e.g with the 8x Clock delay after a CS High -> Low switch.
So im very interested in your solution.
My works like this :
int sd_send_cmd(uint8_t cmd, uint32_t arg,XSpi *SpiPtr)
{
uint8_t n;
int Dummy;
/*
* Prepare the WriteBuffer.
*/
WriteBuffer[BYTE1] = (0x40 | cmd); // Command
WriteBuffer[BYTE2] = ( (uint8_t)(arg >> 24) ); // Argument[31..24]
WriteBuffer[BYTE3] = ( (uint8_t)(arg >> 16) ); // Argument[23..16]
WriteBuffer[BYTE4] = ( (uint8_t)(arg >> 8) ) ; // Argument[15..8]
WriteBuffer[BYTE5] = ( (uint8_t)arg ); // Argument[7..0]
n = 0x01; // Dummy CRC + Stop
if (cmd == CMD0) n = 0x95; // Valid CRC for CMD0(0)
if (cmd == CMD8) n = 0x87; // Valid CRC for CMD8(0x1AA)
WriteBuffer[BYTE6] = n;
XSpi_Transfer(SpiPtr, WriteBuffer, ReadBuffer,6);
return Dummy;
}
But yours seems more elegant :)
Perhaps you can send me your Makro definition ? Easier to understand ;)
Re: XPS SPI Core and SD Card
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
08-30-2011 04:37 PM
Check XIo.h This file has the prototypes for the XIo_In / Out calls.
Again with your code, you are still using the xilinx drivers. It will be very hard to ensure accurate and efficient timing without lower level control over your hardware. You really need explicit control over the chip select line.
Cheers.
Lachlan











