D:\Xilinx\SDK\2019.1\data\embeddedsw\XilinxProcessorIPLib\drivers\spi_v4_4\examples
中
xspi_winbond_flash_quad_example.c文件,作为移植的参考。
这个例子中,
定义了一系列功能函数,它们利用BSP提供的操作函数,完成功能级的封装。
int SpiFlashWriteEnable(XSpi *SpiPtr);
int SpiFlashWrite(XSpi *SpiPtr, u32 Addr, u32 ByteCount, u8 WriteCmd);
int SpiFlashRead(XSpi *SpiPtr, u32 Addr, u32 ByteCount, u8 ReadCmd);
int SpiFlashBulkErase(XSpi *SpiPtr);
int SpiFlashSectorErase(XSpi *SpiPtr, u32 Addr);
int SpiFlashGetStatus(XSpi *SpiPtr);
int SpiFlashQuadEnable(XSpi *SpiPtr);
int SpiFlashEnableHPM(XSpi *SpiPtr);
static int SpiFlashWaitForFlashReady(void);
void SpiHandler(void *CallBackRef, u32 StatusEvent, unsigned int ByteCount);
static int SetupInterruptSystem(XSpi *SpiPtr);
在SOD风格下,定义了static的结构体,
static XIntc InterruptController;
static XSpi Spi;
volatile static int TransferInProgress;
static int ErrorCount;
static u8 ReadBuffer[PAGE_SIZE + READ_WRITE_EXTRA_BYTES + 4];
static u8 WriteBuffer[PAGE_SIZE + READ_WRITE_EXTRA_BYTES];
这些static变量,是我们封装时要关注的变量。
在C++环境下,既可以封装为class,也可以封装为struct,为了尽量多的保持SOD风格,这里封装成struct。
struct SpiFlashDev
{
XSpi spi;
int TransferInProgress;
int ErrorCount;
u8 ReadBuffer[PAGE_SIZE + READ_WRITE_EXTRA_BYTES + 4];
u8 WriteBuffer[PAGE_SIZE + READ_WRITE_EXTRA_BYTES];
};
并为它设计相应的功能级函数。对应于example中的功能函数。
int spi_flash_init(struct SpiFlashDev* dev, int dev_id);
int spi_flash_start(struct SpiFlashDev* dev);
void SpiHandler(void *CallBackRef, u32 StatusEvent, unsigned int ByteCount);
int spi_flash_get_status(struct SpiFlashDev* dev);
int spi_flash_wait_for_flash_ready(struct SpiFlashDev* dev);
int spi_flash_write_enable(struct SpiFlashDev* dev);
int spi_flash_sector_erase(struct SpiFlashDev* dev, u32 addr);
int spi_flash_read_page(struct SpiFlashDev* dev, u32 addr);
int spi_flash_write_page(struct SpiFlashDev* dev, u32 addr);
来看看main函数,
main函数里,首先对xspi进行初始化,然后启动,然后执行了各种读写操作,完成测试。
所以,我们可以根据初始化序列,来封装所需要的spi_flash_init函数,
根据启动代码,来封装所需要的spi_flash_start函数。
int spi_flash_init(struct SpiFlashDev* dev, int dev_id)
{
int ret;
XSpi_Config *ConfigPtr;
ConfigPtr = XSpi_LookupConfig(dev_id);
if (ConfigPtr == NULL) {
return -1;
}
ret = XSpi_CfgInitialize(&dev->spi, ConfigPtr, ConfigPtr->BaseAddress);
if (ret != XST_SUCCESS) {
return -1;
}
/*
* Setup the handler for the SPI that will be called from the interrupt
* context when an SPI status occurs, specify a pointer to the SPI
* driver instance as the callback reference so the handler is able to
* access the instance data.
*/
XSpi_SetStatusHandler(&dev->spi, dev, (XSpi_StatusHandler)SpiHandler);
/*
* 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.
*/
ret = XSpi_SetOptions(&dev->spi, XSP_MASTER_OPTION | XSP_MANUAL_SSELECT_OPTION);
if(ret != XST_SUCCESS) {
return -1;
}
/*
* Select the quad flash device on the SPI bus, so that it can be
* read and written using the SPI bus.
*/
ret = XSpi_SetSlaveSelect(&dev->spi, 1);
if(ret != XST_SUCCESS) {
return -1;
}
return 0;
}
int spi_flash_start(struct SpiFlashDev* dev)
{
XSpi_Start(&dev->spi);
return 0;
}
执行流程和main一致,区别在于,main中操作的对象是static的变量,而在封装函数中,替换成参数传入的对象。
在main中调用的函数SetupInterruptSystem,这里并未调用,因为这是对XINTC进行配置的函数,属于XINTC的初始化,此时并不执行,而是放在整板级别统一执行。加入如下的代码,并稍加修改即可。
/*
* Connect a device driver handler that will be called when an interrupt
* for the device occurs, the device driver handler performs the
* specific interrupt processing for the device
*/
Status = XIntc_Connect(&InterruptController,
SPI_INTR_ID,
(XInterruptHandler)XSpi_InterruptHandler,
(void *)SpiPtr);
if(Status != XST_SUCCESS) {
return XST_FAILURE;
}
其中用到的spiHandler函数,只需要对example中的函数稍加改动,
void SpiHandler(void *CallBackRef, u32 StatusEvent, unsigned int ByteCount)
{
struct SpiFlashDev* dev = (struct SpiFlashDev*)CallBackRef;
/*
* Indicate the transfer on the SPI bus is no longer in progress
* regardless of the status event.
*/
dev->TransferInProgress = 0;
/*
* If the event was not transfer done, then track it as an error.
*/
if (StatusEvent != XST_SPI_TRANSFER_DONE) {
dev->ErrorCount++;
}
}
至此,initialize函数,start函数,callback函数已经移植了。
然后是
int spi_flash_write_enable(struct SpiFlashDev* dev);
这个函数里,由于使用了SpiFlashWaitForFlashReady函数,所以,先移植这个函数。
而它里面又使用了SpiFlashGetStatus函数,所以,还要先移植这个函数
int spi_flash_get_status(struct SpiFlashDev* dev)
{
int ret;
/*
* Prepare the Write Buffer.
*/
dev->WriteBuffer[0] = COMMAND_STATUSREG_READ;
/*
* Initiate the Transfer.
*/
dev->TransferInProgress = TRUE;
ret = XSpi_Transfer(&dev->spi, dev->WriteBuffer, dev->ReadBuffer, STATUS_READ_BYTES);
if(ret != XST_SUCCESS) {
return -1;
}
/*
* Wait till the Transfer is complete and check if there are any errors
* in the transaction..
*/
while(dev->TransferInProgress);
if(dev->ErrorCount != 0) {
dev->ErrorCount = 0;
return -1;
}
return 0;
}
可以看出,区别只是在于变量引用上的不同。
再来移植SpiFlashWaitForFlashReady函数。
int spi_flash_wait_for_flash_ready(struct SpiFlashDev* dev)
{
int ret;
u8 StatusReg;
while(1) {
/*
* Get the Status Register.
*/
ret = spi_flash_get_status(dev);
if(ret < 0) {
return -1;
}
/*
* Check if the flash is ready to accept the next command.
* If so break.
*/
StatusReg = dev->ReadBuffer[1];
if((StatusReg & FLASH_SR_IS_READY_MASK) == 0) {
break;
}
}
return 0;
}
可以看出,区别只是在于变量引用上的不同,以及调用的API的不同。
为了保持模块内聚,这里使用的是刚封装的spi_flash_get_status函数。
int spi_flash_write_enable(struct SpiFlashDev* dev)
{
int ret;
/*
* Wait while the Flash is busy.
*/
ret = spi_flash_wait_for_flash_ready(dev);
if(ret < 0) {
return -1;
}
/*
* Prepare the WriteBuffer.
*/
dev->WriteBuffer[0] = COMMAND_WRITE_ENABLE;
/*
* Initiate the Transfer.
*/
dev->TransferInProgress = TRUE;
ret = XSpi_Transfer(&dev->spi, dev->WriteBuffer, NULL, WRITE_ENABLE_BYTES);
if(ret != XST_SUCCESS) {
return -1;
}
/*
* Wait till the Transfer is complete and check if there are any errors
* in the transaction..
*/
while(dev->TransferInProgress);
if(dev->ErrorCount != 0) {
dev->ErrorCount = 0;
return -1;
}
return 0;
}
可以看出,区别只是在于变量引用上的不同,以及调用的API的不同。
为了保持模块内聚,这里使用的是刚封装的spi_flash_wait_for_flash_ready函数。
回到main,继续看,SpiFlashSectorErase函数,
int spi_flash_sector_erase(struct SpiFlashDev* dev, u32 addr)
{
int ret;
/*
* Wait while the Flash is busy.
*/
ret = spi_flash_wait_for_flash_ready(dev);
if(ret < 0) {
return -1;
}
/*
* Prepare the WriteBuffer.
*/
dev->WriteBuffer[0] = COMMAND_SECTOR_ERASE;
dev->WriteBuffer[1] = (u8) (addr >> 16);
dev->WriteBuffer[2] = (u8) (addr >> 8);
dev->WriteBuffer[3] = (u8) (addr);
/*
* Initiate the Transfer.
*/
dev->TransferInProgress = TRUE;
ret = XSpi_Transfer(&dev->spi, dev->WriteBuffer, NULL, SECTOR_ERASE_BYTES);
if(ret != XST_SUCCESS) {
return -1;
}
/*
* Wait till the Transfer is complete and check if there are any errors
* in the transaction..
*/
while(dev->TransferInProgress);
if(dev->ErrorCount != 0) {
dev->ErrorCount = 0;
return -1;
}
return 0;
}
可以看出,区别只是在于变量引用上的不同,以及调用的API的不同。
为了保持模块内聚,这里使用的是刚封装的spi_flash_wait_for_flash_ready函数。
回到main,继续看,SpiFlashWrite函数,
int spi_flash_write_page(struct SpiFlashDev* dev, u32 addr)
{
int ret;
/*
* Wait while the Flash is busy.
*/
ret = spi_flash_wait_for_flash_ready(dev);
if(ret < 0) {
return -1;
}
/*
* Prepare the WriteBuffer.
*/
dev->WriteBuffer[0] = COMMAND_PAGE_PROGRAM;
dev->WriteBuffer[1] = (u8) (addr >> 16);
dev->WriteBuffer[2] = (u8) (addr >> 8);
dev->WriteBuffer[3] = (u8) addr;
/*
* Initiate the Transfer.
*/
dev->TransferInProgress = TRUE;
ret = XSpi_Transfer(&dev->spi, dev->WriteBuffer, NULL, (PAGE_SIZE + READ_WRITE_EXTRA_BYTES));
if(ret != XST_SUCCESS) {
return -1;
}
/*
* Wait till the Transfer is complete and check if there are any errors
* in the transaction.
*/
while(dev->TransferInProgress);
if(dev->ErrorCount != 0) {
dev->ErrorCount = 0;
return -1;
}
return 0;
}
可以看出,区别只是在于变量引用上的不同,以及调用的API的不同。
为了保持模块内聚,这里使用的是刚封装的spi_flash_wait_for_flash_ready函数。
另外,由于只需要按页写入,不需要变长写入,所以省去了与变长相关的代码。
回到main,继续看,SpiFlashRead
int spi_flash_read_page(struct SpiFlashDev* dev, u32 addr)
{
int ret;
/*
* Wait while the Flash is busy.
*/
ret = spi_flash_wait_for_flash_ready(dev);
if(ret < 0) {
return -1;
}
/*
* Prepare the WriteBuffer.
*/
dev->WriteBuffer[0] = COMMAND_RANDOM_READ;
dev->WriteBuffer[1] = (u8) (addr >> 16);
dev->WriteBuffer[2] = (u8) (addr >> 8);
dev->WriteBuffer[3] = (u8) addr;
/*
* Initiate the Transfer.
*/
dev->TransferInProgress = TRUE;
ret = XSpi_Transfer(&dev->spi, dev->WriteBuffer, dev->ReadBuffer, (PAGE_SIZE + READ_WRITE_EXTRA_BYTES));
if(ret != XST_SUCCESS) {
return -1;
}
/*
* Wait till the Transfer is complete and check if there are any errors
* in the transaction.
*/
while(dev->TransferInProgress);
if(dev->ErrorCount != 0) {
dev->ErrorCount = 0;
return -1;
}
return 0;
}
可以看出,区别只是在于变量引用上的不同,以及调用的API的不同。
为了保持模块内聚,这里使用的是刚封装的spi_flash_wait_for_flash_ready函数。
另外,由于只需要按页读出,不需要变长读出,所以省去了与变长相关的代码。