- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
I am using the GPIF to interface with a NAND chip. The protocol is to send a command byte, then 5 address bytes, then a page of data (2048 bytes), then 2nd command byte to initiate NAND programming. The GPIF state machine gets data bytes from USB socket thread 3, and command/address bytes from CPU socket thread2. I need to keep CPU sending command/addr bytes as fast as GPIF consumes them. In state machine, I am using the DMA_WM_TH2 to send a CPU_INTR when thread2 data falls below the watermark. I am not sure what watermarl level is best to use. The CPU interrupt routine is to set up the command and address bytes in the manual DMA CPU to GPIF channel buffer, and to use the CyU3PDmaChannelCommitBuffer() to send a set of data in multiple of 7 to thread 2. Please note that the DMA between CPU and GPIF is a Manual Out DMA. The buffer size is 2048 or 512 , buffer count is 2.
Using a digital oscilloscope, I see that data on thread 2 are incorrect. It seems the data in buffer are overwritten. If I change the DMA_WM_TH2 to DMA_RDY_TH2 to trigger a CPU_INTR, the data on thread 2 are correct, but throughput is slower because state machine has to wait for thread 2 data to be filled. I like to keep thread2 buffer not reaching empty to maximum throughput in state machine.
Is there a way for CPU to write data to GPIF socket thread 2 repeatedly without losing any data? The data size is multiple of 7.
How can CPU tell that the GPIF socket thread 2 is almost full, and cannot accept any more data from CPU?
When GPIF socket thread 2 is not empty, does writing new data to its buffer overwrite the existing data?
How can I avoid that?
Is there other API beside CyU3PDmaChannelCommitBuffer() for sending data to consumer socket from CPU?
Thanks
Phil
Below are the code snippets.
/* Create a DMA MANUAL channel for CPU2P transfer. */
//dmaCfgCPU.size = 2048;
dmaCfgCPU.size = 64*8;
dmaCfgCPU.count = 2; //must be greater than 1 to write buffer continuously
dmaCfgCPU.prodSckId = CY_U3P_CPU_SOCKET_PROD; //CPU Socket for producer
dmaCfgCPU.consSckId = CY_U3P_PIB_SOCKET_2; //P port socket 2 for consumer
dmaCfgCPU.dmaMode = CY_U3P_DMA_MODE_BYTE;
/* Enabling the callback for produce event. */
dmaCfgCPU.notification = 0;
dmaCfgCPU.cb = NULL;
dmaCfgCPU.prodHeader = 0;
dmaCfgCPU.prodFooter = 0;
dmaCfgCPU.consHeader = 0;
dmaCfgCPU.prodAvailCount = 0;
**********************************************************************
/* This will create a ManualOut DMA channel that will carry data from the CPU to the GPIF.
FX3 CPU will be involved in the data transfer */
apiRetStatus = CyU3PDmaChannelCreate (&glChHandleCPUtoP,
CY_U3P_DMA_TYPE_MANUAL_OUT, &dmaCfgCPU);
if (apiRetStatus != CY_U3P_SUCCESS)
{
CyU3PDebugPrint (CY_FX_DEBUG_PRIORITY, "CyU3PDmaChannelCreate failed, Error code = %d\n", apiRetStatus);
CyFxAppErrorHandler(apiRetStatus);
}
//set watermark, true when count falls below the mark.
//Watermark must be at least 12, and addrSetCount is 64 in interrupt routine
apiRetStatus = CyU3PGpifSocketConfigure(2, CY_U3P_PIB_SOCKET_2, 12, CyFalse, 1);
if (apiRetStatus != CY_U3P_SUCCESS)
{
CyU3PDebugPrint (CY_FX_DEBUG_PRIORITY, "CyU3PGpifSocketConfigure Failed, Error code = %d\n", apiRetStatus);
CyFxAppErrorHandler(apiRetStatus);
}
/* Set DMA channel transfer size. */
apiRetStatus = CyU3PDmaChannelSetXfer (&glChHandleCPUtoP, 0);
if (apiRetStatus != CY_U3P_SUCCESS)
{
CyU3PDebugPrint (CY_FX_DEBUG_PRIORITY, "CyU3PDmaChannelSetXfer Failed, Error code = %d\n", apiRetStatus);
CyFxAppErrorHandler(apiRetStatus);
}
/* Update the status flag. */
glIsApplnActive = CyTrue;
/* Start the GPIF state machine which will read and write data to/from SRAM whenever requested */
//apiRetStatus = CyU3PGpifSMStart (START,ALPHA_START);
apiRetStatus = CyU3PGpifSMStart (START_PROG,ALPHA_START); //phil
**********************************************************************************
// CPU Interrupt routine to set up data in buffer and send to GPIF consumer socket
void GpifCallBack(CyU3PGpifEventType Event, uint8_t State)
{
int addrSetCount = 64; //send # of set of NAND addr bytes
//must set Control Counter to 15 to prevent additional interrupt issued in GPIF state machine
CyU3PGpifInitCtrlCounter(0, 15, CyFalse, CyTrue, 1 ); //phil,
int i = 0;
for(i=0; i< 1; i++)
{
CyU3PGpioSetValue (LED_GPIO, CyFalse); /* Turn LED-OFF */
CyU3PGpioSetValue (LED_GPIO, CyTrue); /* Turn LED-ON */
}
CyU3PGpioSetValue (LED_GPIO, CyFalse); /* Turn LED-OFF */
uint8_t cmd1 = 0x0;
uint8_t cmd2 = 0x0;
CyU3PDmaChannelGetBuffer(&glChHandleCPUtoP, &gUserBuffer, 0); //get the DMA buffer so content can be modified
int offset = 0;
for(i=0; i<addrSetCount; i++)
{
offset = i*7;
gUserBuffer.buffer[3 + offset] = (gNANDPageBlock>> 0) & 0xFF; //3rd NAND Addr byte
if(gNANDplane == 0)
{
gUserBuffer.buffer[3 + offset] = gUserBuffer.buffer[3 + offset] & 0xFFFFFFBF; //set plane# bit 6 to 0
gNANDplane = 1;
cmd1 = 0x80;
cmd2 = 0x11;
}
else
{
gUserBuffer.buffer[3 + offset] = gUserBuffer.buffer[3 + offset] | 0x40; //set plane# bit 6 to 1
gNANDplane = 0;
cmd1 = 0x81;
cmd2 = 0xAA;
}
gUserBuffer.buffer[0 + offset] = cmd1;
gUserBuffer.buffer[1 + offset] = (gNANDAddr>> 0) & 0xFF; //1st NAND Addr byte
gUserBuffer.buffer[2 + offset] = (gNANDAddr>> 😎 & 0xFF; //2nd NAND Addr byte
//gUserBuffer.buffer[3 + offset] = (gNANDPageBlock>> 0) & 0xFF; //3rd NAND Addr byte
gUserBuffer.buffer[4 + offset] = (gNANDPageBlock>> 😎 & 0xFF; //4th NAND Addr byte
gUserBuffer.buffer[5 + offset] = (gNANDPageBlock>> 16) & 0xFF; //5th NAND Addr byte
gUserBuffer.buffer[6 + offset] = cmd2;
if(gNANDplane == 0)
{
//increment page addr only if next plane is 0
if((gNANDPageBlock & 0x3F) == 0x3F)
gNANDPageBlock += 0x41; //skip over the plane bit (bit 6)
else
gNANDPageBlock += 0x01; //Cypress S34ML04G2, each block has 64 pages
}
}
//do I need to use CyU3PDmaChannelSetupSendBuffer()?
//CyU3PDmaChannelSetupSendBuffer(&glChHandleCPUtoP, &gUserBuffer); //setup buffer for DMA chan to send to GPIFCyU3PDmaChannelCommitBuffer(&glChHandleCPUtoP, i*7, 0); //commit to send data to GPIF
CyU3PGpioSetValue (LED_GPIO, CyTrue); /* Turn LED-ON */
}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Phil,
In general, the flag assigned to consumer p-port shows empty/not-empty, so that external processor can decide whether it can read. Similarly, producer sockets are assigned full/not-full flag, so that external processor can decide whether it can write.
As we know that there is latency in flag gets asserted as mentioned in section 7 in AN65974, the partial flag helps to know the status of the buffer before it is filled or emptied as per water mark value.
It is not clear how you are handling the data flow between NAND and FX3.
Let us know how the flow of data is handling between NAND and GPIF?
How the data is provided to CPU Producer?
Attach the GPIF Project and FX3 project for further debugging?
Regards,
Srdr