前面已经解读了GPIO以及同步FIFO操作,下面我们看一个SPI读写的例子,它是主程序命令从SPI中读写一些数据。
SPI传输子程序看一下: 页地址,字节计数,缓冲区,读写标志
因为只能一页一页的读或写,故读写总是从页地址开始的
/* SPI read / writefor programmer application. */
CyU3PReturnStatus_t
CyFxSpiTransfer (
uint16_t pageAddress, //页地址
uint16_t byteCount, //字节计数
uint8_t *buffer, //缓冲区
CyBool_t isRead) //读写标志
{
CyU3PDmaBuffer_t buf_p; //DMA buffer
uint8_t location[4];
uint32_t byteAddress = 0;
uint16_t pageCount = (byteCount /glSpiPageSize);
CyU3PReturnStatus_t status =CY_U3P_SUCCESS;
if (byteCount == 0)
{
return CY_U3P_SUCCESS;
}
if ((byteCount % glSpiPageSize) != 0)
{
pageCount ++; ///如果除不尽,则按多一页来读写
}
buf_p.buffer = buffer; //地址重载
buf_p.status = 0;
byteAddress = pageAddress * glSpiPageSize; //页地址*尺寸=实际地址
CyU3PDebugPrint (2, "SPI access -addr: 0x%x, size: 0x%x, pages: 0x%x.\r\n",
byteAddress, byteCount, pageCount);
while (pageCount != 0)
{
//高字节
location[1] = (byteAddress >> 16)& 0xFF; /* MS byte */
location[2] = (byteAddress >> 8)& 0xFF;
//低字节
location[3] = byteAddress &0xFF; /* LS byte */
if (isRead)
{
location[0] = 0x03; /* Read command. *///读命令
buf_p.size = glSpiPageSize;
buf_p.count = glSpiPageSize;
status = CyFxSpiWaitForStatus ();
if (status != CY_U3P_SUCCESS)
return status;
CyU3PSpiSetSsnLine (CyFalse);
status = CyU3PSpiTransmitWords(location, 4);
if (status != CY_U3P_SUCCESS)
{
CyU3PDebugPrint (2, "SPIREAD command failed\r\n");
CyU3PSpiSetSsnLine (CyTrue);
return status;
}
CyU3PSpiSetBlockXfer (0,glSpiPageSize); //设置传输尺寸
/// 这个子程序是允许DMA。两个参数一个是TX,一个是RX的个数
status =CyU3PDmaChannelSetupRecvBuffer (&glSpiRxHandle,
&buf_p);
if (status != CY_U3P_SUCCESS)
{
CyU3PSpiSetSsnLine (CyTrue);
return status;
}
status =CyU3PDmaChannelWaitForCompletion (&glSpiRxHandle,
CY_FX_USB_SPI_TIMEOUT);
if (status != CY_U3P_SUCCESS)
{
CyU3PSpiSetSsnLine (CyTrue);
return status;
}
CyU3PSpiSetSsnLine (CyTrue);
CyU3PSpiDisableBlockXfer (CyFalse,CyTrue);
}
else /* Write */
{
location[0] = 0x02; /* Writecommand */
buf_p.size = glSpiPageSize;
buf_p.count = glSpiPageSize;
status = CyFxSpiWaitForStatus ();
if (status != CY_U3P_SUCCESS)
return status;
CyU3PSpiSetSsnLine (CyFalse);
status = CyU3PSpiTransmitWords(location, 4);
if (status != CY_U3P_SUCCESS)
{
CyU3PDebugPrint (2, "SPIWRITE command failed\r\n");
CyU3PSpiSetSsnLine (CyTrue);
return status;
}
CyU3PSpiSetBlockXfer(glSpiPageSize, 0);
status =CyU3PDmaChannelSetupSendBuffer (&glSpiTxHandle,
&buf_p);
if (status != CY_U3P_SUCCESS)
{
CyU3PSpiSetSsnLine (CyTrue);
return status;
}
status =CyU3PDmaChannelWaitForCompletion(&glSpiTxHandle,
CY_FX_USB_SPI_TIMEOUT);
if (status != CY_U3P_SUCCESS)
{
CyU3PSpiSetSsnLine (CyTrue);
return status;
}
CyU3PSpiSetSsnLine (CyTrue);
CyU3PSpiDisableBlockXfer (CyTrue,CyFalse);
}
/* Update the parameters */
byteAddress += glSpiPageSize;
buf_p.buffer += glSpiPageSize;
pageCount --;
CyU3PThreadSleep (10);
}
return CY_U3P_SUCCESS;
}
在USB的SETUP中回调中( CyFxUSBSetupCB ),有两个参数,一个是setupdat0,一个是setupdat1.
这两个参数是类,VENDOR调用时的回调函数。
如果是请求ID号,则直接往EP0中写入一个字符串。
如果是请求FLASH写,则从EP0中得到相应的数组。后写到SPI中。
如果是请求读,则从SPI中读出指定长度的数,再送到EP0中去。
如果是请求擦除或点名。则如果点名,就送状态过去,如果是擦除,就送一个ACK包给USB即可。
那么就要了解一下类/VENDOR请求的格式是什么即可。