Wednesday, April 16, 2014
Is the data stable while clock arrives ?
Will this cause setup time issues ? But the click period is huge.. so I can't really make out.
Monday, April 14, 2014
Saturday, April 12, 2014
Problem : Understanding why the SPI transfered bits cant be always seen on the DSO ?
Q: What is the clock of the SPI transfer that is taking place?
Ans: The busySignal in the write byte can give what is the clk time for the SPI transfer.
Obs1: So when the DSO reads M 10ms it gives tiny spikes...
obs2: When I zoom in , ie. 250us, and i set it to normal mode - I keep clicking at a high rate on the "transfer data" button- I get the values.
So it does get transfered ...
Ans: The busySignal in the write byte can give what is the clk time for the SPI transfer.
Obs1: So when the DSO reads M 10ms it gives tiny spikes...
obs2: When I zoom in , ie. 250us, and i set it to normal mode - I keep clicking at a high rate on the "transfer data" button- I get the values.
So it does get transfered ...
Friday, April 11, 2014
BASICS: Concept of glEP0buff
One thing you have to understand is that,
In vendor requests - we send Setup Packets to chose the application direction.
Setup packets have wValue and wIndex bits free if you want to receive some immediate data.
wLength is the length of data dumped onto the endpoint in the EP0 buffers from the computer to the host or vice-versa. If you want to pick this data up or put data on the buffer you do something like this:
CyU3PUsbSendEP0Data(wLength,glEp0Buffer, NULL);
CyU3PUsbGetEP0Data(wLength,glEp0Buffer, NULL);
Questions:
1.So does this transaction has to happen to complete a loop of communication protocol of some sort?
2. Will the pin up and down function actually need / or why would it actually need the fake EP0 buffer transfer.
In vendor requests - we send Setup Packets to chose the application direction.
Setup packets have wValue and wIndex bits free if you want to receive some immediate data.
wLength is the length of data dumped onto the endpoint in the EP0 buffers from the computer to the host or vice-versa. If you want to pick this data up or put data on the buffer you do something like this:
CyU3PUsbSendEP0Data(wLength,glEp0Buffer, NULL);
CyU3PUsbGetEP0Data(wLength,glEp0Buffer, NULL);
Questions:
1.So does this transaction has to happen to complete a loop of communication protocol of some sort?
2. Will the pin up and down function actually need / or why would it actually need the fake EP0 buffer transfer.
Thursday, April 10, 2014
ERROR: Vender Requests Code Error 997 :/
Added this :
gpioConfig.outValue = CyFalse;
gpioConfig.driveLowEn = CyTrue;
gpioConfig.driveHighEn = CyTrue;
gpioConfig.inputEn = CyFalse;
gpioConfig.intrMode = CY_U3P_GPIO_NO_INTR;
apiRetStatus = CyU3PGpioSetSimpleConfig(45, &gpioConfig);
Reason:
1.For vendor requests in control panel must be selected control endpoint, req. type. "vendor", target "device", req. code field must be filled with vendor request code.2.The error code 997 refers I/O pending for the overlapped to http://msdn.microsoft.com/en-us/library/windows/desktop/ms681388(v=vs.85).aspx. PSoC3 has a full-speed USB. You're most probably sending a big transfer and clicking transfer again before the previous one completes.
In control panel error 997 is usually visible if is selected direction "out", is clicked transfer data button and is sent to FX3, but firmware does not read data from endpoint (using CyU3PUsbGetEP0Data; for zero length packets most likely should be called CyU3PUsbAckSetup). Or if is selected direction "in", clicked transfer data button, but firmware does not send data to endpoint (using CyU3PUsbSendEP0Data).
Tested using USB 2.0 and with above mentioned commands errors 997 are not displayed.
Regarding error 69 (decimal), I think that it means timeout.
Regards,
3.
Backup Code: SPI-GPIO original firmware code.
/*
## Cypress USB 3.0 Platform source file (cyfxusbspigpiomode.c)
## ===========================
##
## Copyright Cypress Semiconductor Corporation, 2011-2012,
## All Rights Reserved
## UNPUBLISHED, LICENSED SOFTWARE.
##
## CONFIDENTIAL AND PROPRIETARY INFORMATION
## WHICH IS THE PROPERTY OF CYPRESS.
##
## Use of this file is governed
## by the license agreement included in the file
##
## <install>/license/license.txt
##
## where <install> is the Cypress software
## installation root directory path.
##
## ===========================
*/
/* This application is used read / write to SPI flash devices from USB.
The FX3 accesses by using a set of GPIO lines configured as Clock, Slave
select, MISO and MOSI lines.
The firmware enumerates as a custom device communicating with the
cyUsb3.sys driver and provides a set of vendor commands that can be
used to access the attached SPI flash device.
*/
#include "cyu3system.h"
#include "cyu3os.h"
#include "cyu3dma.h"
#include "cyu3error.h"
#include "cyu3usb.h"
#include "cyu3gpio.h"
#include "cyu3uart.h"
#include "cyu3utils.h"
#include "cyfxusbspigpiomode.h"
#include "gpio_regs.h"
CyU3PThread appThread; /* Application thread object. */
CyBool_t glIsApplnActive = CyFalse; /* Application status. */
/* Firmware ID variable that may be used to verify SPI firmware. */
const uint8_t glFirmwareID[32] __attribute__ ((aligned (32))) = { 'F', 'X', '3', ' ', 'S', 'P', 'I', '\0' };
uint8_t glEp0Buffer[4096] __attribute__ ((aligned (32)));
uint16_t glSpiPageSize = 0x100; /* SPI Page size to be used for transfers. */
// Not needed as of yet
CyU3PReturnStatus_t
CyFxDebugInit (
void)
{
CyU3PUartConfig_t uartConfig;
CyU3PReturnStatus_t status = CY_U3P_SUCCESS;
/* Initialize and configure the UART for logging. */
status = CyU3PUartInit ();
if (status != CY_U3P_SUCCESS)
{
return status;
}
CyU3PMemSet ((uint8_t *)&uartConfig, 0, sizeof (uartConfig));
uartConfig.baudRate = CY_U3P_UART_BAUDRATE_115200;
uartConfig.stopBit = CY_U3P_UART_ONE_STOP_BIT;
uartConfig.parity = CY_U3P_UART_NO_PARITY;
uartConfig.txEnable = CyTrue;
uartConfig.rxEnable = CyFalse;
uartConfig.flowCtrl = CyFalse;
uartConfig.isDma = CyTrue;
status = CyU3PUartSetConfig (&uartConfig, NULL);
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* Set the dma for an inifinity transfer */
status = CyU3PUartTxSetBlockXfer (0xFFFFFFFF);
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* Start the debug module for printing log messages. */
status = CyU3PDebugInit (CY_U3P_LPP_SOCKET_UART_CONS, 8);
return status;
}
/* This function intializes the GPIO module. GPIO Ids 53-56 are used for communicating
with the SPI slave device. */
CyU3PReturnStatus_t
CyFxGpioInit (void)
{
CyU3PGpioClock_t gpioClock;
CyU3PGpioSimpleConfig_t gpioConfig;
CyU3PReturnStatus_t apiRetStatus = CY_U3P_SUCCESS;
/* Initialize the GPIO module. */
{
/* Error Handling */
CyU3PDebugPrint (4, "CyU3PGpioInit failed, error code = %d\n", apiRetStatus);
CyFxAppErrorHandler(apiRetStatus);
}
/* Configure GPIO 53 as output(SPI_CLOCK). */
{
/* Error handling */
CyU3PDebugPrint (4, "CyU3PGpioSetSimpleConfig for GPIO Id %d failed, error code = %d\n",
FX3_SPI_CLK, apiRetStatus);
CyFxAppErrorHandler(apiRetStatus);
}
/* Configure GPIO 54 as output(SPI_SSN) */
{
/* Error handling */
CyU3PDebugPrint (4, "CyU3PGpioSetSimpleConfig for GPIO Id %d failed, error code = %d\n",
FX3_SPI_SS, apiRetStatus);
CyFxAppErrorHandler(apiRetStatus);
}
/* Configure GPIO 55 as input(MISO) */
{
/* Error handling */
CyU3PDebugPrint (4, "CyU3PGpioSetSimpleConfig for GPIO Id %d failed, error code = %d\n",
FX3_SPI_MISO, apiRetStatus);
CyFxAppErrorHandler(apiRetStatus);
}
/* Configure GPIO 56 as output(MOSI) */
{
/* Error handling */
CyU3PDebugPrint (4, "CyU3PGpioSetSimpleConfig for GPIO Id %d failed, error code = %d\n",
FX3_SPI_MOSI, apiRetStatus);
CyFxAppErrorHandler(apiRetStatus);
}
return apiRetStatus;
}
/* This function pulls up/down the SPI Clock line. */
CyU3PReturnStatus_t
CyFxSpiSetClockValue (
CyBool_t isHigh
/* Cyfalse: Pull down the Clock line,
CyTrue: Pull up the Clock line */
)
/* This function pulls up/down the slave select line. */
CyU3PReturnStatus_t
CyFxSpiSetSsnLine (
CyBool_t isHigh /* Cyfalse: Pull down the SSN line,
CyTrue: Pull up the SSN line */
)
{
/* This function transmits the byte to the SPI slave device one bit a time.
Most Significant Bit is transmitted first.
*/
CyU3PReturnStatus_t
CyFxSpiWriteByte (
uint8_t data)
{
/* This function receives the byte from the SPI slave device one bit at a time.
Most Significant Bit is received first.
*/
CyU3PReturnStatus_t
CyFxSpiReadByte (
uint8_t *data)
{
uint8_t i = 0;
CyBool_t temp = CyFalse;
#ifdef FX3_USE_GPIO_REGS
uvint32_t *regPtrClock;
regPtrClock = &GPIO->lpp_gpio_simple[FX3_SPI_CLK];
#endif
*data = 0;
for (i = 0; i < 8; i++)
{
#ifndef FX3_USE_GPIO_REGS
CyFxSpiSetClockValue (CyTrue);
CyU3PGpioGetValue (FX3_SPI_MISO, &temp);
*data |= (temp << (7 - i));
CyU3PBusyWait (1);
CyFxSpiSetClockValue (CyFalse);
CyU3PBusyWait (1);
#else
*regPtrClock|=CYFX_GPIO_HIGH;
temp = (GPIO->lpp_gpio_simple[FX3_SPI_MISO] & CY_U3P_LPP_GPIO_IN_VALUE)>>1;
*data |= (temp << (7 - i));
CyU3PBusyWait (1);
*regPtrClock&=~CYFX_GPIO_HIGH;
CyU3PBusyWait (1);
#endif
}
return CY_U3P_SUCCESS;
}
/* This function is used to transmit data to the SPI slave device. The function internally
calls the CyFxSpiWriteByte function to write to the slave device.
*/
CyU3PReturnStatus_t
CyFxSpiTransmitWords (
uint8_t *data,
uint32_t byteCount)
{
uint32_t i = 0;
CyU3PReturnStatus_t status = CY_U3P_SUCCESS;
if ((!byteCount) || (!data))
{
return CY_U3P_ERROR_BAD_ARGUMENT;
}
for (i = 0; i < byteCount; i++)
{
status = CyFxSpiWriteByte (data[i]);
if (status != CY_U3P_SUCCESS)
{
break;
}
}
return status;
}
/* This function is used receive data from the SPI slave device. The function internally
calls the CyFxSpiReadByte function to read data from the slave device.
*/
CyU3PReturnStatus_t
CyFxSpiReceiveWords (
uint8_t *data,
uint32_t byteCount)
{
uint32_t i = 0;
CyU3PReturnStatus_t status = CY_U3P_SUCCESS;
if ((!byteCount) || (!data))
{
return CY_U3P_ERROR_BAD_ARGUMENT;
}
for (i = 0; i < byteCount; i++)
{
status = CyFxSpiReadByte (&data[i]);
if (status != CY_U3P_SUCCESS)
{
break;
}
}
return status;
}
/* Wait for the status response from the SPI flash. */
CyU3PReturnStatus_t
CyFxSpiWaitForStatus (
void)
{
uint8_t buf[2], rd_buf[2];
CyU3PReturnStatus_t status = CY_U3P_SUCCESS;
/* Wait for status response from SPI flash device. */
do
{
buf[0] = 0x06; /* Write enable command. */
CyFxSpiSetSsnLine (CyFalse);
status = CyFxSpiTransmitWords (buf, 1);
CyFxSpiSetSsnLine (CyTrue);
if (status != CY_U3P_SUCCESS)
{
CyU3PDebugPrint (2, "SPI WR_ENABLE command failed\n\r");
return status;
}
buf[0] = 0x05; /* Read status command */
CyFxSpiSetSsnLine (CyFalse);
status = CyFxSpiTransmitWords (buf, 1);
if (status != CY_U3P_SUCCESS)
{
CyU3PDebugPrint (2, "SPI READ_STATUS command failed\n\r");
CyFxSpiSetSsnLine (CyTrue);
return status;
}
status = CyFxSpiReceiveWords (rd_buf, 2);
CyFxSpiSetSsnLine (CyTrue);
if(status != CY_U3P_SUCCESS)
{
CyU3PDebugPrint (2, "SPI status read failed\n\r");
return status;
}
} while ((rd_buf[0] & 1)|| (!(rd_buf[0] & 0x2)));
return CY_U3P_SUCCESS;
}
/* SPI read / write for programmer application. */
CyU3PReturnStatus_t
CyFxSpiTransfer (
uint16_t pageAddress,
uint16_t byteCount,
uint8_t *buffer,
CyBool_t isRead)
{
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 ++;
}
byteAddress = pageAddress * glSpiPageSize;
CyU3PDebugPrint (2, "SPI access - addr: 0x%x, size: 0x%x, pages: 0x%x.\r\n",
byteAddress, byteCount, pageCount);
while (pageCount != 0)
{
// split the into 8 bit elements so u can pass in the predefined functions...
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. */
status = CyFxSpiWaitForStatus ();
if (status != CY_U3P_SUCCESS)
return status;
CyFxSpiSetSsnLine (CyFalse);
status = CyFxSpiTransmitWords (location, 4);
if (status != CY_U3P_SUCCESS)
{
CyU3PDebugPrint (2, "SPI READ command failed\r\n");
CyFxSpiSetSsnLine (CyTrue);
return status;
}
status = CyFxSpiReceiveWords (buffer, glSpiPageSize);
if (status != CY_U3P_SUCCESS)
{
CyFxSpiSetSsnLine (CyTrue);
return status;
}
CyFxSpiSetSsnLine (CyTrue);
}
else /* Write */
{
location[0] = 0x02; /* Write command */
status = CyFxSpiWaitForStatus ();
if (status != CY_U3P_SUCCESS)
return status;
CyFxSpiSetSsnLine (CyFalse);
status = CyFxSpiTransmitWords (location, 4);
if (status != CY_U3P_SUCCESS)
{
CyU3PDebugPrint (2, "SPI WRITE command failed\r\n");
CyFxSpiSetSsnLine (CyTrue);
return status;
}
status = CyFxSpiTransmitWords (buffer, glSpiPageSize);
if (status != CY_U3P_SUCCESS)
{
CyFxSpiSetSsnLine (CyTrue);
return status;
}
CyFxSpiSetSsnLine (CyTrue);
}
/* Update the parameters */
byteAddress += glSpiPageSize;
buffer += glSpiPageSize;
pageCount --;
CyU3PThreadSleep (10);
}
return CY_U3P_SUCCESS;
}
/* Function to erase SPI flash sectors. */
static CyU3PReturnStatus_t
CyFxSpiEraseSector (
CyBool_t isErase,
uint8_t sector,
uint8_t *wip)
{
uint32_t temp = 0;
uint8_t location[4], rdBuf[2];
CyU3PReturnStatus_t status = CY_U3P_SUCCESS;
if ((!isErase) && (wip == NULL))
{
return CY_U3P_ERROR_BAD_ARGUMENT;
}
location[0] = 0x06; /* Write enable. */
CyFxSpiSetSsnLine (CyFalse);
status = CyFxSpiTransmitWords (location, 1);
CyFxSpiSetSsnLine (CyTrue);
if (status != CY_U3P_SUCCESS)
return status;
if (isErase)
{
location[0] = 0xD8; /* Sector erase. */
temp = sector * 0x10000;
location[1] = (temp >> 16) & 0xFF;
location[2] = (temp >> 8) & 0xFF;
location[3] = temp & 0xFF;
CyFxSpiSetSsnLine (CyFalse);
status = CyFxSpiTransmitWords (location, 4);
CyFxSpiSetSsnLine (CyTrue);
}
else
{
location[0] = 0x05; /* Read status */
CyFxSpiSetSsnLine (CyFalse);
status = CyFxSpiTransmitWords (location, 1);
if (status != CY_U3P_SUCCESS)
{
CyFxSpiSetSsnLine (CyTrue);
return status;
}
status = CyFxSpiReceiveWords (rdBuf, 2);
CyFxSpiSetSsnLine (CyTrue);
*wip = rdBuf[0] & 0x1;
}
return status;
}
CyBool_t
CyFxUSBSetupCB (
uint32_t setupdat0,
uint32_t setupdat1)
{
/* Fast enumeration is used. Only requests addressed to the interface, class,
* vendor and unknown control requests are received by this function. */
/* Decode the fields from the setup request. */
if (bType == CY_U3P_USB_STANDARD_RQT)
{
/* Handle SET_FEATURE(FUNCTION_SUSPEND) and CLEAR_FEATURE(FUNCTION_SUSPEND)
* requests here. It should be allowed to pass if the device is in configured
* state and failed otherwise. */
if ((bTarget == CY_U3P_USB_TARGET_INTF) && ((bRequest == CY_U3P_USB_SC_SET_FEATURE)
|| (bRequest == CY_U3P_USB_SC_CLEAR_FEATURE)) && (wValue == 0))
{
if (glIsApplnActive)
CyU3PUsbAckSetup ();
else
CyU3PUsbStall (0, CyTrue, CyFalse);
isHandled = CyTrue;
}
}
/* Handle supported vendor requests. */
if (bType == CY_U3P_USB_VENDOR_RQT)
{
isHandled = CyTrue;
switch (bRequest)
{
case CY_FX_RQT_ID_CHECK:
CyU3PUsbSendEP0Data (8, (uint8_t *)glFirmwareID);
break;
case CY_FX_RQT_SPI_FLASH_WRITE:
status = CyU3PUsbGetEP0Data (wLength, glEp0Buffer, NULL);
if (status == CY_U3P_SUCCESS)
{
status = CyFxSpiTransfer (wIndex, wLength,
glEp0Buffer, CyFalse);
}
break;
case CY_FX_RQT_SPI_FLASH_READ:
CyU3PMemSet (glEp0Buffer, 0, sizeof (glEp0Buffer));
status = CyFxSpiTransfer (wIndex, wLength,
glEp0Buffer, CyTrue);
if (status == CY_U3P_SUCCESS)
{
status = CyU3PUsbSendEP0Data (wLength, glEp0Buffer);
}
break;
case CY_FX_RQT_SPI_FLASH_ERASE_POLL:
status = CyFxSpiEraseSector ((wValue) ? CyTrue : CyFalse,
(wIndex & 0xFF), glEp0Buffer);
if (status == CY_U3P_SUCCESS)
{
CyFxSpiWaitForStatus ();
if (wValue == 0)
{
status = CyU3PUsbSendEP0Data (wLength, glEp0Buffer);
}
else
{
CyU3PUsbAckSetup ();
}
}
break;
default:
/* This is unknown request. */
isHandled = CyFalse;
break;
}
/* If there was any error, return not handled so that the library will
* stall the request. Alternatively EP0 can be stalled here and return
* CyTrue. */
if (status != CY_U3P_SUCCESS)
{
isHandled = CyFalse;
}
}
return isHandled;
}
/* This is the callback function to handle the USB events. */
void
CyFxUSBEventCB (
CyU3PUsbEventType_t evtype, /* Event type */
uint16_t evdata /* Event data */
)
{
switch (evtype)
{
case CY_U3P_USB_EVENT_SETCONF:
glIsApplnActive = CyTrue;
break;
case CY_U3P_USB_EVENT_RESET:
case CY_U3P_USB_EVENT_DISCONNECT:
glIsApplnActive = CyFalse;
break;
default:
break;
}
}
/* Callback function to handle LPM requests from the USB 3.0 host. This function is invoked by the API
whenever a state change from U0 -> U1 or U0 -> U2 happens. If we return CyTrue from this function, the
FX3 device is retained in the low power state. If we return CyFalse, the FX3 device immediately tries
to trigger an exit back to U0.
This application does not have any state in which we should not allow U1/U2 transitions; and therefore
the function always return CyTrue.
*/
CyBool_t
CyFxApplnLPMRqtCB (
CyU3PUsbLinkPowerMode link_mode)
{
return CyTrue;
}
/* Initialize all interfaces for the application. */
CyU3PReturnStatus_t
CyFxUsbSpiGpioInit (
uint16_t pageSize)
{
CyU3PReturnStatus_t status = CY_U3P_SUCCESS;
glSpiPageSize = pageSize;
/* Initialize the GPIO Pins for the SPI interface. */
status = CyFxGpioInit ();
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* Start the USB functionality. */
status = CyU3PUsbStart();
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* The fast enumeration is the easiest way to setup a USB connection,
* where all enumeration phase is handled by the library. Only the
* class / vendor requests need to be handled by the application. */
CyU3PUsbRegisterSetupCallback(CyFxUSBSetupCB, CyTrue);
/* Setup the callback to handle the USB events. */
CyU3PUsbRegisterEventCallback(CyFxUSBEventCB);
/* Register a callback to handle LPM requests from the USB 3.0 host. */
CyU3PUsbRegisterLPMRequestCallback(CyFxApplnLPMRqtCB);
/* Set the USB Enumeration descriptors */
/* Super speed device descriptor. */
status = CyU3PUsbSetDesc(CY_U3P_USB_SET_SS_DEVICE_DESCR, NULL, (uint8_t *)CyFxUSB30DeviceDscr);
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* High speed device descriptor. */
status = CyU3PUsbSetDesc(CY_U3P_USB_SET_HS_DEVICE_DESCR, NULL, (uint8_t *)CyFxUSB20DeviceDscr);
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* BOS descriptor */
status = CyU3PUsbSetDesc(CY_U3P_USB_SET_SS_BOS_DESCR, NULL, (uint8_t *)CyFxUSBBOSDscr);
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* Device qualifier descriptor */
status = CyU3PUsbSetDesc(CY_U3P_USB_SET_DEVQUAL_DESCR, NULL, (uint8_t *)CyFxUSBDeviceQualDscr);
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* Super speed configuration descriptor */
status = CyU3PUsbSetDesc(CY_U3P_USB_SET_SS_CONFIG_DESCR, NULL, (uint8_t *)CyFxUSBSSConfigDscr);
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* High speed configuration descriptor */
status = CyU3PUsbSetDesc(CY_U3P_USB_SET_HS_CONFIG_DESCR, NULL, (uint8_t *)CyFxUSBHSConfigDscr);
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* Full speed configuration descriptor */
status = CyU3PUsbSetDesc(CY_U3P_USB_SET_FS_CONFIG_DESCR, NULL, (uint8_t *)CyFxUSBFSConfigDscr);
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* String descriptor 0 */
status = CyU3PUsbSetDesc(CY_U3P_USB_SET_STRING_DESCR, 0, (uint8_t *)CyFxUSBStringLangIDDscr);
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* String descriptor 1 */
status = CyU3PUsbSetDesc(CY_U3P_USB_SET_STRING_DESCR, 1, (uint8_t *)CyFxUSBManufactureDscr);
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* String descriptor 2 */
status = CyU3PUsbSetDesc(CY_U3P_USB_SET_STRING_DESCR, 2, (uint8_t *)CyFxUSBProductDscr);
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* Connect the USB Pins with super speed operation enabled. */
status = CyU3PConnectState(CyTrue, CyTrue);
return status;
}
/*
* Entry function for the application thread. This function performs
* the initialization of the Debug, GPIO and USB modules and then
* executes in a loop printing out heartbeat messages through the UART.
*/
void
AppThread_Entry (
uint32_t input)
{
uint8_t count = 0;
CyU3PReturnStatus_t status = CY_U3P_SUCCESS;
/* Initialize the debug interface. */
status = CyFxDebugInit ();
if (status != CY_U3P_SUCCESS)
{
goto handle_error;
}
/* Initialize the application. */
status = CyFxUsbSpiGpioInit (0x100);
if (status != CY_U3P_SUCCESS)
{
goto handle_error;
}
for (;;)
{
CyU3PDebugPrint (4, "%x: Device initialized. Firmware ID: %x %x %x %x %x %x %x %x\r\n",
count++, glFirmwareID[3], glFirmwareID[2], glFirmwareID[1], glFirmwareID[0],
glFirmwareID[7], glFirmwareID[6], glFirmwareID[5], glFirmwareID[4]);
CyU3PThreadSleep (1000);
}
handle_error:
CyU3PDebugPrint (4, "%x: Application failed to initialize. Error code: %d.\n", status);
while (1);
}
/* Application define function which creates the application threads. */
void
CyFxApplicationDefine (
void)
{
void *ptr = NULL;
uint32_t retThrdCreate = CY_U3P_SUCCESS;
/* Allocate the memory for the threads and create threads */
ptr = CyU3PMemAlloc (APPTHREAD_STACK);
retThrdCreate = CyU3PThreadCreate (&appThread, /* Thread structure. */
"21:AppThread", /* Thread ID and name. */
AppThread_Entry, /* Thread entry function. */
0, /* Thread input parameter. */
ptr, /* Pointer to the allocated thread stack. */
APPTHREAD_STACK, /* Allocated thread stack size. */
APPTHREAD_PRIORITY, /* Thread priority. */
APPTHREAD_PRIORITY, /* Thread pre-emption threshold: No preemption. */
CYU3P_NO_TIME_SLICE, /* No time slice. Thread will run until task is
completed or until the higher priority
thread gets active. */
CYU3P_AUTO_START /* Start the thread immediately. */
);
/* Check the return code */
if (retThrdCreate != 0)
{
/* Thread creation failed with the error code retThrdCreate */
/* Add custom recovery or debug actions here */
/* Application cannot continue. Loop indefinitely */
while(1);
}
}
/*
* Main function
*/
int
main (void)
{
CyU3PIoMatrixConfig_t io_cfg;
CyU3PReturnStatus_t status = CY_U3P_SUCCESS;
/* Initialize the device */
status = CyU3PDeviceInit (NULL);
if (status != CY_U3P_SUCCESS)
{
goto handle_fatal_error;
}
/* Initialize the caches. Enable both Instruction and Data Caches. */
status = CyU3PDeviceCacheControl (CyTrue, CyTrue, CyTrue);
if (status != CY_U3P_SUCCESS)
{
goto handle_fatal_error;
}
/* Configure the IO matrix for the device. On the FX3 DVK board, the COM port
* is connected to the IO(46:49) in 16-bit GPIF mode. GPIO Ids 53-56 are used
* to control the SPI slave device.
* */
CyU3PMemSet ((uint8_t *)&io_cfg, 0, sizeof(io_cfg));
io_cfg.isDQ32Bit = CyFalse;
io_cfg.s0Mode = CY_U3P_SPORT_INACTIVE;
io_cfg.s1Mode = CY_U3P_SPORT_INACTIVE;
io_cfg.useUart = CyTrue;
io_cfg.useI2C = CyFalse;
io_cfg.useI2S = CyFalse;
io_cfg.useSpi = CyFalse;
io_cfg.lppMode = CY_U3P_IO_MATRIX_LPP_DEFAULT;
/* 53-56 GPIOs are enabled. */
io_cfg.gpioSimpleEn[0] = 0;
io_cfg.gpioSimpleEn[1] = 0x01E00000;
io_cfg.gpioComplexEn[0] = 0;
io_cfg.gpioComplexEn[1] = 0;
{
goto handle_fatal_error;
}
/* This is a non returnable call for initializing the RTOS kernel */
CyU3PKernelEntry ();
/* Dummy return to make the compiler happy */
return 0;
handle_fatal_error:
/* Cannot recover from this error. */
while (1);
}
/* [ ] */
## Cypress USB 3.0 Platform source file (cyfxusbspigpiomode.c)
## ===========================
##
## Copyright Cypress Semiconductor Corporation, 2011-2012,
## All Rights Reserved
## UNPUBLISHED, LICENSED SOFTWARE.
##
## CONFIDENTIAL AND PROPRIETARY INFORMATION
## WHICH IS THE PROPERTY OF CYPRESS.
##
## Use of this file is governed
## by the license agreement included in the file
##
## <install>/license/license.txt
##
## where <install> is the Cypress software
## installation root directory path.
##
## ===========================
*/
/* This application is used read / write to SPI flash devices from USB.
The FX3 accesses by using a set of GPIO lines configured as Clock, Slave
select, MISO and MOSI lines.
The firmware enumerates as a custom device communicating with the
cyUsb3.sys driver and provides a set of vendor commands that can be
used to access the attached SPI flash device.
*/
#include "cyu3system.h"
#include "cyu3os.h"
#include "cyu3dma.h"
#include "cyu3error.h"
#include "cyu3usb.h"
#include "cyu3gpio.h"
#include "cyu3uart.h"
#include "cyu3utils.h"
#include "cyfxusbspigpiomode.h"
#include "gpio_regs.h"
CyU3PThread appThread; /* Application thread object. */
CyBool_t glIsApplnActive = CyFalse; /* Application status. */
/* Firmware ID variable that may be used to verify SPI firmware. */
const uint8_t glFirmwareID[32] __attribute__ ((aligned (32))) = { 'F', 'X', '3', ' ', 'S', 'P', 'I', '\0' };
uint8_t glEp0Buffer[4096] __attribute__ ((aligned (32)));
uint16_t glSpiPageSize = 0x100; /* SPI Page size to be used for transfers. */
// Not needed as of yet
/* Application error handler. *//* Initialize the debug module with UART. */
void
CyFxAppErrorHandler ( CyU3PReturnStatus_t apiRetStatus /* API return status */ ){ /* Application failed with the error code apiRetStatus */ /* Add custom debug or recovery actions here */ /* Loop indefinitely */ for (;;) { /* Thread sleep : 100 ms */ CyU3PThreadSleep (100); }}
CyU3PReturnStatus_t
CyFxDebugInit (
void)
{
CyU3PUartConfig_t uartConfig;
CyU3PReturnStatus_t status = CY_U3P_SUCCESS;
/* Initialize and configure the UART for logging. */
status = CyU3PUartInit ();
if (status != CY_U3P_SUCCESS)
{
return status;
}
CyU3PMemSet ((uint8_t *)&uartConfig, 0, sizeof (uartConfig));
uartConfig.baudRate = CY_U3P_UART_BAUDRATE_115200;
uartConfig.stopBit = CY_U3P_UART_ONE_STOP_BIT;
uartConfig.parity = CY_U3P_UART_NO_PARITY;
uartConfig.txEnable = CyTrue;
uartConfig.rxEnable = CyFalse;
uartConfig.flowCtrl = CyFalse;
uartConfig.isDma = CyTrue;
status = CyU3PUartSetConfig (&uartConfig, NULL);
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* Set the dma for an inifinity transfer */
status = CyU3PUartTxSetBlockXfer (0xFFFFFFFF);
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* Start the debug module for printing log messages. */
status = CyU3PDebugInit (CY_U3P_LPP_SOCKET_UART_CONS, 8);
return status;
}
/* This function intializes the GPIO module. GPIO Ids 53-56 are used for communicating
with the SPI slave device. */
CyU3PReturnStatus_t
CyFxGpioInit (void)
{
CyU3PGpioClock_t gpioClock;
CyU3PGpioSimpleConfig_t gpioConfig;
CyU3PReturnStatus_t apiRetStatus = CY_U3P_SUCCESS;
/* Initialize the GPIO module. */
gpioClock.fastClkDiv = 2;if (apiRetStatus != 0)
gpioClock.slowClkDiv = 0;
gpioClock.simpleDiv = CY_U3P_GPIO_SIMPLE_DIV_BY_2;
gpioClock.clkSrc = CY_U3P_SYS_CLK;
gpioClock.halfDiv = 0;
apiRetStatus = CyU3PGpioInit(&gpioClock, NULL);
{
/* Error Handling */
CyU3PDebugPrint (4, "CyU3PGpioInit failed, error code = %d\n", apiRetStatus);
CyFxAppErrorHandler(apiRetStatus);
}
/* Configure GPIO 53 as output(SPI_CLOCK). */
gpioConfig.outValue = CyFalse;if (apiRetStatus != CY_U3P_SUCCESS)
gpioConfig.inputEn = CyFalse;
gpioConfig.driveLowEn = CyTrue;
gpioConfig.driveHighEn = CyTrue;
gpioConfig.intrMode = CY_U3P_GPIO_NO_INTR;
apiRetStatus = CyU3PGpioSetSimpleConfig(FX3_SPI_CLK, &gpioConfig);
{
/* Error handling */
CyU3PDebugPrint (4, "CyU3PGpioSetSimpleConfig for GPIO Id %d failed, error code = %d\n",
FX3_SPI_CLK, apiRetStatus);
CyFxAppErrorHandler(apiRetStatus);
}
/* Configure GPIO 54 as output(SPI_SSN) */
gpioConfig.outValue = CyTrue;if (apiRetStatus != CY_U3P_SUCCESS)
gpioConfig.inputEn = CyFalse;
gpioConfig.driveLowEn = CyTrue;
gpioConfig.driveHighEn = CyTrue;
gpioConfig.intrMode = CY_U3P_GPIO_NO_INTR;
apiRetStatus = CyU3PGpioSetSimpleConfig(FX3_SPI_SS, &gpioConfig);
{
/* Error handling */
CyU3PDebugPrint (4, "CyU3PGpioSetSimpleConfig for GPIO Id %d failed, error code = %d\n",
FX3_SPI_SS, apiRetStatus);
CyFxAppErrorHandler(apiRetStatus);
}
/* Configure GPIO 55 as input(MISO) */
gpioConfig.outValue = CyFalse;if (apiRetStatus != CY_U3P_SUCCESS)
gpioConfig.inputEn = CyTrue;
gpioConfig.driveLowEn = CyFalse;
gpioConfig.driveHighEn = CyFalse;
gpioConfig.intrMode = CY_U3P_GPIO_NO_INTR;
apiRetStatus = CyU3PGpioSetSimpleConfig(FX3_SPI_MISO, &gpioConfig);
{
/* Error handling */
CyU3PDebugPrint (4, "CyU3PGpioSetSimpleConfig for GPIO Id %d failed, error code = %d\n",
FX3_SPI_MISO, apiRetStatus);
CyFxAppErrorHandler(apiRetStatus);
}
/* Configure GPIO 56 as output(MOSI) */
gpioConfig.outValue = CyFalse;if (apiRetStatus != CY_U3P_SUCCESS)
gpioConfig.inputEn = CyFalse;
gpioConfig.driveLowEn = CyTrue;
gpioConfig.driveHighEn = CyTrue;
gpioConfig.intrMode = CY_U3P_GPIO_NO_INTR;
apiRetStatus = CyU3PGpioSetSimpleConfig(FX3_SPI_MOSI, &gpioConfig);
{
/* Error handling */
CyU3PDebugPrint (4, "CyU3PGpioSetSimpleConfig for GPIO Id %d failed, error code = %d\n",
FX3_SPI_MOSI, apiRetStatus);
CyFxAppErrorHandler(apiRetStatus);
}
return apiRetStatus;
}
/* This function pulls up/down the SPI Clock line. */
CyU3PReturnStatus_t
CyFxSpiSetClockValue (
CyBool_t isHigh
/* Cyfalse: Pull down the Clock line,
CyTrue: Pull up the Clock line */
)
{
CyU3PReturnStatus_t status;
status = CyU3PGpioSetValue (FX3_SPI_CLK, isHigh);
return status;
}
/* This function pulls up/down the slave select line. */
CyU3PReturnStatus_t
CyFxSpiSetSsnLine (
CyBool_t isHigh /* Cyfalse: Pull down the SSN line,
CyTrue: Pull up the SSN line */
)
{
#ifndef FX3_USE_GPIO_REGS
status = CyU3PGpioSetValue (FX3_SPI_SS, isHigh);
return status;
#else
regPtrSS = &GPIO->lpp_gpio_simple[FX3_SPI_SS];
if(isHigh)
{
*regPtrSS |=CYFX_GPIO_HIGH;
}
else
{
*regPtrSS&=~CYFX_GPIO_HIGH;
}
return CY_U3P_SUCCESS;
#endif
CyU3PReturnStatus_t status;}
uvint32_t *regPtrSS;
/* This function transmits the byte to the SPI slave device one bit a time.
Most Significant Bit is transmitted first.
*/
CyU3PReturnStatus_t
CyFxSpiWriteByte (
uint8_t data)
{
uint8_t i = 0;}
#ifdef FX3_USE_GPIO_REGS
CyBool_t value;
uvint32_t *regPtrMOSI, *regPtrClock;
regPtrMOSI = &GPIO->lpp_gpio_simple[FX3_SPI_MOSI];
regPtrClock = &GPIO->lpp_gpio_simple[FX3_SPI_CLK];
#endif
for (i = 0; i < 8; i++)
{
#ifndef FX3_USE_GPIO_REGS
/* Most significant bit is transferred first. */
CyU3PGpioSetValue (FX3_SPI_MOSI, ((data >> (7 - i)) & 0x01));
CyFxSpiSetClockValue (CyTrue);
CyU3PBusyWait (1);
CyFxSpiSetClockValue (CyFalse);
CyU3PBusyWait (1);
#else
/* Most significant bit is transferred first. */
value =((data >> (7 - i)) & 0x01);
if(value)
{
*regPtrMOSI |= CYFX_GPIO_HIGH;
}
else
{
*regPtrMOSI &=~CYFX_GPIO_HIGH;
}
*regPtrClock|=CYFX_GPIO_HIGH; CyU3PBusyWait (1);
*regPtrClock&=~CYFX_GPIO_HIGH;
CyU3PBusyWait (1);
#endif
}
return CY_U3P_SUCCESS;
/* This function receives the byte from the SPI slave device one bit at a time.
Most Significant Bit is received first.
*/
CyU3PReturnStatus_t
CyFxSpiReadByte (
uint8_t *data)
{
uint8_t i = 0;
CyBool_t temp = CyFalse;
#ifdef FX3_USE_GPIO_REGS
uvint32_t *regPtrClock;
regPtrClock = &GPIO->lpp_gpio_simple[FX3_SPI_CLK];
#endif
*data = 0;
for (i = 0; i < 8; i++)
{
#ifndef FX3_USE_GPIO_REGS
CyFxSpiSetClockValue (CyTrue);
CyU3PGpioGetValue (FX3_SPI_MISO, &temp);
*data |= (temp << (7 - i));
CyU3PBusyWait (1);
CyFxSpiSetClockValue (CyFalse);
CyU3PBusyWait (1);
#else
*regPtrClock|=CYFX_GPIO_HIGH;
temp = (GPIO->lpp_gpio_simple[FX3_SPI_MISO] & CY_U3P_LPP_GPIO_IN_VALUE)>>1;
*data |= (temp << (7 - i));
CyU3PBusyWait (1);
*regPtrClock&=~CYFX_GPIO_HIGH;
CyU3PBusyWait (1);
#endif
}
return CY_U3P_SUCCESS;
}
/* This function is used to transmit data to the SPI slave device. The function internally
calls the CyFxSpiWriteByte function to write to the slave device.
*/
CyU3PReturnStatus_t
CyFxSpiTransmitWords (
uint8_t *data,
uint32_t byteCount)
{
uint32_t i = 0;
CyU3PReturnStatus_t status = CY_U3P_SUCCESS;
if ((!byteCount) || (!data))
{
return CY_U3P_ERROR_BAD_ARGUMENT;
}
for (i = 0; i < byteCount; i++)
{
status = CyFxSpiWriteByte (data[i]);
if (status != CY_U3P_SUCCESS)
{
break;
}
}
return status;
}
/* This function is used receive data from the SPI slave device. The function internally
calls the CyFxSpiReadByte function to read data from the slave device.
*/
CyU3PReturnStatus_t
CyFxSpiReceiveWords (
uint8_t *data,
uint32_t byteCount)
{
uint32_t i = 0;
CyU3PReturnStatus_t status = CY_U3P_SUCCESS;
if ((!byteCount) || (!data))
{
return CY_U3P_ERROR_BAD_ARGUMENT;
}
for (i = 0; i < byteCount; i++)
{
status = CyFxSpiReadByte (&data[i]);
if (status != CY_U3P_SUCCESS)
{
break;
}
}
return status;
}
/* Wait for the status response from the SPI flash. */
CyU3PReturnStatus_t
CyFxSpiWaitForStatus (
void)
{
uint8_t buf[2], rd_buf[2];
CyU3PReturnStatus_t status = CY_U3P_SUCCESS;
/* Wait for status response from SPI flash device. */
do
{
buf[0] = 0x06; /* Write enable command. */
CyFxSpiSetSsnLine (CyFalse);
status = CyFxSpiTransmitWords (buf, 1);
CyFxSpiSetSsnLine (CyTrue);
if (status != CY_U3P_SUCCESS)
{
CyU3PDebugPrint (2, "SPI WR_ENABLE command failed\n\r");
return status;
}
buf[0] = 0x05; /* Read status command */
CyFxSpiSetSsnLine (CyFalse);
status = CyFxSpiTransmitWords (buf, 1);
if (status != CY_U3P_SUCCESS)
{
CyU3PDebugPrint (2, "SPI READ_STATUS command failed\n\r");
CyFxSpiSetSsnLine (CyTrue);
return status;
}
status = CyFxSpiReceiveWords (rd_buf, 2);
CyFxSpiSetSsnLine (CyTrue);
if(status != CY_U3P_SUCCESS)
{
CyU3PDebugPrint (2, "SPI status read failed\n\r");
return status;
}
} while ((rd_buf[0] & 1)|| (!(rd_buf[0] & 0x2)));
return CY_U3P_SUCCESS;
}
/* SPI read / write for programmer application. */
CyU3PReturnStatus_t
CyFxSpiTransfer (
uint16_t pageAddress,
uint16_t byteCount,
uint8_t *buffer,
CyBool_t isRead)
{
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 ++;
}
byteAddress = pageAddress * glSpiPageSize;
CyU3PDebugPrint (2, "SPI access - addr: 0x%x, size: 0x%x, pages: 0x%x.\r\n",
byteAddress, byteCount, pageCount);
while (pageCount != 0)
{
// split the into 8 bit elements so u can pass in the predefined functions...
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. */
status = CyFxSpiWaitForStatus ();
if (status != CY_U3P_SUCCESS)
return status;
CyFxSpiSetSsnLine (CyFalse);
status = CyFxSpiTransmitWords (location, 4);
if (status != CY_U3P_SUCCESS)
{
CyU3PDebugPrint (2, "SPI READ command failed\r\n");
CyFxSpiSetSsnLine (CyTrue);
return status;
}
status = CyFxSpiReceiveWords (buffer, glSpiPageSize);
if (status != CY_U3P_SUCCESS)
{
CyFxSpiSetSsnLine (CyTrue);
return status;
}
CyFxSpiSetSsnLine (CyTrue);
}
else /* Write */
{
location[0] = 0x02; /* Write command */
status = CyFxSpiWaitForStatus ();
if (status != CY_U3P_SUCCESS)
return status;
CyFxSpiSetSsnLine (CyFalse);
status = CyFxSpiTransmitWords (location, 4);
if (status != CY_U3P_SUCCESS)
{
CyU3PDebugPrint (2, "SPI WRITE command failed\r\n");
CyFxSpiSetSsnLine (CyTrue);
return status;
}
status = CyFxSpiTransmitWords (buffer, glSpiPageSize);
if (status != CY_U3P_SUCCESS)
{
CyFxSpiSetSsnLine (CyTrue);
return status;
}
CyFxSpiSetSsnLine (CyTrue);
}
/* Update the parameters */
byteAddress += glSpiPageSize;
buffer += glSpiPageSize;
pageCount --;
CyU3PThreadSleep (10);
}
return CY_U3P_SUCCESS;
}
/* Function to erase SPI flash sectors. */
static CyU3PReturnStatus_t
CyFxSpiEraseSector (
CyBool_t isErase,
uint8_t sector,
uint8_t *wip)
{
uint32_t temp = 0;
uint8_t location[4], rdBuf[2];
CyU3PReturnStatus_t status = CY_U3P_SUCCESS;
if ((!isErase) && (wip == NULL))
{
return CY_U3P_ERROR_BAD_ARGUMENT;
}
location[0] = 0x06; /* Write enable. */
CyFxSpiSetSsnLine (CyFalse);
status = CyFxSpiTransmitWords (location, 1);
CyFxSpiSetSsnLine (CyTrue);
if (status != CY_U3P_SUCCESS)
return status;
if (isErase)
{
location[0] = 0xD8; /* Sector erase. */
temp = sector * 0x10000;
location[1] = (temp >> 16) & 0xFF;
location[2] = (temp >> 8) & 0xFF;
location[3] = temp & 0xFF;
CyFxSpiSetSsnLine (CyFalse);
status = CyFxSpiTransmitWords (location, 4);
CyFxSpiSetSsnLine (CyTrue);
}
else
{
location[0] = 0x05; /* Read status */
CyFxSpiSetSsnLine (CyFalse);
status = CyFxSpiTransmitWords (location, 1);
if (status != CY_U3P_SUCCESS)
{
CyFxSpiSetSsnLine (CyTrue);
return status;
}
status = CyFxSpiReceiveWords (rdBuf, 2);
CyFxSpiSetSsnLine (CyTrue);
*wip = rdBuf[0] & 0x1;
}
return status;
}
CyBool_t
CyFxUSBSetupCB (
uint32_t setupdat0,
uint32_t setupdat1)
{
/* Fast enumeration is used. Only requests addressed to the interface, class,
* vendor and unknown control requests are received by this function. */
uint8_t bRequest, bReqType;
uint8_t bType, bTarget;
uint16_t wValue, wIndex, wLength;
CyBool_t isHandled = CyFalse;
CyU3PReturnStatus_t status = CY_U3P_SUCCESS;
/* Decode the fields from the setup request. */
bReqType = (setupdat0 & CY_U3P_USB_REQUEST_TYPE_MASK);
bType = (bReqType & CY_U3P_USB_TYPE_MASK);
bTarget = (bReqType & CY_U3P_USB_TARGET_MASK);
bRequest = ((setupdat0 & CY_U3P_USB_REQUEST_MASK) >> CY_U3P_USB_REQUEST_POS);
wValue = ((setupdat0 & CY_U3P_USB_VALUE_MASK) >> CY_U3P_USB_VALUE_POS);
wIndex = ((setupdat1 & CY_U3P_USB_INDEX_MASK) >> CY_U3P_USB_INDEX_POS);
wLength = ((setupdat1 & CY_U3P_USB_LENGTH_MASK) >> CY_U3P_USB_LENGTH_POS);
if (bType == CY_U3P_USB_STANDARD_RQT)
{
/* Handle SET_FEATURE(FUNCTION_SUSPEND) and CLEAR_FEATURE(FUNCTION_SUSPEND)
* requests here. It should be allowed to pass if the device is in configured
* state and failed otherwise. */
if ((bTarget == CY_U3P_USB_TARGET_INTF) && ((bRequest == CY_U3P_USB_SC_SET_FEATURE)
|| (bRequest == CY_U3P_USB_SC_CLEAR_FEATURE)) && (wValue == 0))
{
if (glIsApplnActive)
CyU3PUsbAckSetup ();
else
CyU3PUsbStall (0, CyTrue, CyFalse);
isHandled = CyTrue;
}
}
/* Handle supported vendor requests. */
if (bType == CY_U3P_USB_VENDOR_RQT)
{
isHandled = CyTrue;
switch (bRequest)
{
case CY_FX_RQT_ID_CHECK:
CyU3PUsbSendEP0Data (8, (uint8_t *)glFirmwareID);
break;
case CY_FX_RQT_SPI_FLASH_WRITE:
status = CyU3PUsbGetEP0Data (wLength, glEp0Buffer, NULL);
if (status == CY_U3P_SUCCESS)
{
status = CyFxSpiTransfer (wIndex, wLength,
glEp0Buffer, CyFalse);
}
break;
case CY_FX_RQT_SPI_FLASH_READ:
CyU3PMemSet (glEp0Buffer, 0, sizeof (glEp0Buffer));
status = CyFxSpiTransfer (wIndex, wLength,
glEp0Buffer, CyTrue);
if (status == CY_U3P_SUCCESS)
{
status = CyU3PUsbSendEP0Data (wLength, glEp0Buffer);
}
break;
case CY_FX_RQT_SPI_FLASH_ERASE_POLL:
status = CyFxSpiEraseSector ((wValue) ? CyTrue : CyFalse,
(wIndex & 0xFF), glEp0Buffer);
if (status == CY_U3P_SUCCESS)
{
CyFxSpiWaitForStatus ();
if (wValue == 0)
{
status = CyU3PUsbSendEP0Data (wLength, glEp0Buffer);
}
else
{
CyU3PUsbAckSetup ();
}
}
break;
default:
/* This is unknown request. */
isHandled = CyFalse;
break;
}
/* If there was any error, return not handled so that the library will
* stall the request. Alternatively EP0 can be stalled here and return
* CyTrue. */
if (status != CY_U3P_SUCCESS)
{
isHandled = CyFalse;
}
}
return isHandled;
}
/* This is the callback function to handle the USB events. */
void
CyFxUSBEventCB (
CyU3PUsbEventType_t evtype, /* Event type */
uint16_t evdata /* Event data */
)
{
switch (evtype)
{
case CY_U3P_USB_EVENT_SETCONF:
glIsApplnActive = CyTrue;
break;
case CY_U3P_USB_EVENT_RESET:
case CY_U3P_USB_EVENT_DISCONNECT:
glIsApplnActive = CyFalse;
break;
default:
break;
}
}
/* Callback function to handle LPM requests from the USB 3.0 host. This function is invoked by the API
whenever a state change from U0 -> U1 or U0 -> U2 happens. If we return CyTrue from this function, the
FX3 device is retained in the low power state. If we return CyFalse, the FX3 device immediately tries
to trigger an exit back to U0.
This application does not have any state in which we should not allow U1/U2 transitions; and therefore
the function always return CyTrue.
*/
CyBool_t
CyFxApplnLPMRqtCB (
CyU3PUsbLinkPowerMode link_mode)
{
return CyTrue;
}
/* Initialize all interfaces for the application. */
CyU3PReturnStatus_t
CyFxUsbSpiGpioInit (
uint16_t pageSize)
{
CyU3PReturnStatus_t status = CY_U3P_SUCCESS;
glSpiPageSize = pageSize;
/* Initialize the GPIO Pins for the SPI interface. */
status = CyFxGpioInit ();
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* Start the USB functionality. */
status = CyU3PUsbStart();
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* The fast enumeration is the easiest way to setup a USB connection,
* where all enumeration phase is handled by the library. Only the
* class / vendor requests need to be handled by the application. */
CyU3PUsbRegisterSetupCallback(CyFxUSBSetupCB, CyTrue);
/* Setup the callback to handle the USB events. */
CyU3PUsbRegisterEventCallback(CyFxUSBEventCB);
/* Register a callback to handle LPM requests from the USB 3.0 host. */
CyU3PUsbRegisterLPMRequestCallback(CyFxApplnLPMRqtCB);
/* Set the USB Enumeration descriptors */
/* Super speed device descriptor. */
status = CyU3PUsbSetDesc(CY_U3P_USB_SET_SS_DEVICE_DESCR, NULL, (uint8_t *)CyFxUSB30DeviceDscr);
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* High speed device descriptor. */
status = CyU3PUsbSetDesc(CY_U3P_USB_SET_HS_DEVICE_DESCR, NULL, (uint8_t *)CyFxUSB20DeviceDscr);
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* BOS descriptor */
status = CyU3PUsbSetDesc(CY_U3P_USB_SET_SS_BOS_DESCR, NULL, (uint8_t *)CyFxUSBBOSDscr);
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* Device qualifier descriptor */
status = CyU3PUsbSetDesc(CY_U3P_USB_SET_DEVQUAL_DESCR, NULL, (uint8_t *)CyFxUSBDeviceQualDscr);
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* Super speed configuration descriptor */
status = CyU3PUsbSetDesc(CY_U3P_USB_SET_SS_CONFIG_DESCR, NULL, (uint8_t *)CyFxUSBSSConfigDscr);
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* High speed configuration descriptor */
status = CyU3PUsbSetDesc(CY_U3P_USB_SET_HS_CONFIG_DESCR, NULL, (uint8_t *)CyFxUSBHSConfigDscr);
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* Full speed configuration descriptor */
status = CyU3PUsbSetDesc(CY_U3P_USB_SET_FS_CONFIG_DESCR, NULL, (uint8_t *)CyFxUSBFSConfigDscr);
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* String descriptor 0 */
status = CyU3PUsbSetDesc(CY_U3P_USB_SET_STRING_DESCR, 0, (uint8_t *)CyFxUSBStringLangIDDscr);
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* String descriptor 1 */
status = CyU3PUsbSetDesc(CY_U3P_USB_SET_STRING_DESCR, 1, (uint8_t *)CyFxUSBManufactureDscr);
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* String descriptor 2 */
status = CyU3PUsbSetDesc(CY_U3P_USB_SET_STRING_DESCR, 2, (uint8_t *)CyFxUSBProductDscr);
if (status != CY_U3P_SUCCESS)
{
return status;
}
/* Connect the USB Pins with super speed operation enabled. */
status = CyU3PConnectState(CyTrue, CyTrue);
return status;
}
/*
* Entry function for the application thread. This function performs
* the initialization of the Debug, GPIO and USB modules and then
* executes in a loop printing out heartbeat messages through the UART.
*/
void
AppThread_Entry (
uint32_t input)
{
uint8_t count = 0;
CyU3PReturnStatus_t status = CY_U3P_SUCCESS;
/* Initialize the debug interface. */
status = CyFxDebugInit ();
if (status != CY_U3P_SUCCESS)
{
goto handle_error;
}
/* Initialize the application. */
status = CyFxUsbSpiGpioInit (0x100);
if (status != CY_U3P_SUCCESS)
{
goto handle_error;
}
for (;;)
{
CyU3PDebugPrint (4, "%x: Device initialized. Firmware ID: %x %x %x %x %x %x %x %x\r\n",
count++, glFirmwareID[3], glFirmwareID[2], glFirmwareID[1], glFirmwareID[0],
glFirmwareID[7], glFirmwareID[6], glFirmwareID[5], glFirmwareID[4]);
CyU3PThreadSleep (1000);
}
handle_error:
CyU3PDebugPrint (4, "%x: Application failed to initialize. Error code: %d.\n", status);
while (1);
}
/* Application define function which creates the application threads. */
void
CyFxApplicationDefine (
void)
{
void *ptr = NULL;
uint32_t retThrdCreate = CY_U3P_SUCCESS;
/* Allocate the memory for the threads and create threads */
ptr = CyU3PMemAlloc (APPTHREAD_STACK);
retThrdCreate = CyU3PThreadCreate (&appThread, /* Thread structure. */
"21:AppThread", /* Thread ID and name. */
AppThread_Entry, /* Thread entry function. */
0, /* Thread input parameter. */
ptr, /* Pointer to the allocated thread stack. */
APPTHREAD_STACK, /* Allocated thread stack size. */
APPTHREAD_PRIORITY, /* Thread priority. */
APPTHREAD_PRIORITY, /* Thread pre-emption threshold: No preemption. */
CYU3P_NO_TIME_SLICE, /* No time slice. Thread will run until task is
completed or until the higher priority
thread gets active. */
CYU3P_AUTO_START /* Start the thread immediately. */
);
/* Check the return code */
if (retThrdCreate != 0)
{
/* Thread creation failed with the error code retThrdCreate */
/* Add custom recovery or debug actions here */
/* Application cannot continue. Loop indefinitely */
while(1);
}
}
/*
* Main function
*/
int
main (void)
{
CyU3PIoMatrixConfig_t io_cfg;
CyU3PReturnStatus_t status = CY_U3P_SUCCESS;
/* Initialize the device */
status = CyU3PDeviceInit (NULL);
if (status != CY_U3P_SUCCESS)
{
goto handle_fatal_error;
}
/* Initialize the caches. Enable both Instruction and Data Caches. */
status = CyU3PDeviceCacheControl (CyTrue, CyTrue, CyTrue);
if (status != CY_U3P_SUCCESS)
{
goto handle_fatal_error;
}
/* Configure the IO matrix for the device. On the FX3 DVK board, the COM port
* is connected to the IO(46:49) in 16-bit GPIF mode. GPIO Ids 53-56 are used
* to control the SPI slave device.
* */
CyU3PMemSet ((uint8_t *)&io_cfg, 0, sizeof(io_cfg));
io_cfg.isDQ32Bit = CyFalse;
io_cfg.s0Mode = CY_U3P_SPORT_INACTIVE;
io_cfg.s1Mode = CY_U3P_SPORT_INACTIVE;
io_cfg.useUart = CyTrue;
io_cfg.useI2C = CyFalse;
io_cfg.useI2S = CyFalse;
io_cfg.useSpi = CyFalse;
io_cfg.lppMode = CY_U3P_IO_MATRIX_LPP_DEFAULT;
/* 53-56 GPIOs are enabled. */
io_cfg.gpioSimpleEn[0] = 0;
io_cfg.gpioSimpleEn[1] = 0x01E00000;
io_cfg.gpioComplexEn[0] = 0;
io_cfg.gpioComplexEn[1] = 0;
status = CyU3PDeviceConfigureIOMatrix (&io_cfg);if (status != CY_U3P_SUCCESS)
{
goto handle_fatal_error;
}
/* This is a non returnable call for initializing the RTOS kernel */
CyU3PKernelEntry ();
/* Dummy return to make the compiler happy */
return 0;
handle_fatal_error:
/* Cannot recover from this error. */
while (1);
}
/* [ ] */
Wednesday, April 9, 2014
Discovery: CyU3PUsbGetEP0Data and CyU3PUsbSendEP0Data Mystery??
How the Vendor/Class Request is handled in the FX3 ? |
The API CyU3PUsbRegisterSetupCallback() will register a callback function which will handle vendor/class/standard requests. If the fastEnum bit in the function parameter is set then the device hardware itself handles the standard request, we only need to handle the class/vendor requests. |
Discovery: End Point 0...
One of the blogs on Cypress.. (wasnt answered, but gives a good insight):
I am used to dealing with microcontrollers where the USB data is put into an array that can be accessed at the byte level. So you call a doUSB() function, you get a 64byte packet of data from the host, process, and send back a 64byte packet. Or receive a byte array all the time and then send out byte arrays all the time by just checking if the endpoint is clear to do so or not.
So looking at the FX3 sample code is daunting. I can make the GPIO sample wiggle a PWM pin and so it works.
But now I just want to be able to pass the information out of the USB module into a peripheral and into another chip like an FPGA to do some light work and pass it pack through the peripheral and back into the USB module. Like a FIFO in for USB data from the host to the device and a FIFO out for USB data from the device to the host.
Since there are impossibly tiny Samtech and Tyco connectors on the dev board to access the Slave FIFO, I am forced to use the SPI header. I read that it can go 33MHz which is fine for initial testing. I am hoping I can move to the slave FIFO once I get an actual board spun with an FPGA and the FX3 on it. But for now it will be 2 dev kits wired together with some jumper wire.
So back to the firmware, I am looking at the USBSpiRegMode example (although I still dont understand the difference between RegMode and DMA mode) because it seems like a good base to go from USB to SPI. I don't know if I know what I am looking at.
I see uint8_t glEp0Buffer[4096]; which appears to be Endpoint 0's byte array buffer. Is that correct? It also looks like the USB mode is not a Write-then-Read architecture but an architecture that splits the write and reads from the endpoint into separate entitites so that you could write forever without reading or visa versa read forever without writing. Correct?It would appear that CyU3PUsbGetEP0Data() is the magic USB goo that checks the USB endpoint from the host to the FX3 and when there is data it will return the data in the buffer, correct?
So this bit of code...
status = CyU3PUsbGetEP0Data (length, glEp0Buffer, NULL);...gets "length" bytes from EndPoint 0 (EP0) and puts them into glEp0Buffer, with returned_data's index-0 at glEp0Buffer's index-0? Is this a blocking call until data is received or does it fail the status if there is nothing to read?Then to transfer on the Spi peripheral it uses this bit of code immediately afterwards correct?
if (status == CY_U3P_SUCCESS) { status = CyFxSpiTransfer (index, length, glEp0Buffer, CyFalse); } break;It would also appear that to send data over USB, you would call CyU3PUsbSendEP0Data(length, buffer pointer) correct?
So would it stand to reason that I could simple stay in a loop that called CyU3PUsbGetEP0Data() and get a byte stream back that I could then pass into CyFxSpiTransfer() for the Host->FPGA communication? Then pass that returned SPI byte array into CyU3PUsbSendEP0Data() for the FPGA->Host communication?
Any help would be appreciated.
Subscribe to:
Posts (Atom)