FX3: UART - receive data with DMA into CPU's buffer causes CY_U3P_ERROR_NOT_STARTED

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
MaksymDevX
Level 1
Level 1
5 replies posted First reply posted First question asked

Good day everyone!

I have FX3 CYUSB3011 and I'm trying to make UART working in DMA mode to receive and process data from UART.

The problem is that sometimes received packets just dropped and CyU3PDmaChannelGetBuffer returns CY_U3P_ERROR_NOT_STARTED. And if I decrease sleep ticks issue repeats more often.

Interesting thing is that I could not find any examples of the code for the same purpose. I've tried to make it work with DMA or UART callbacks but it did not work. "Software polling" of DMA buffer is the only way that worked somehow at least.

My code below:

 

 

 

void UartReceiveTask(void * arg)
{
	CyU3PDmaBuffer_t ConsoleInDmaBuffer;
	CyU3PReturnStatus_t Status;

	while(1)
	{
		Status = CyU3PDmaChannelSetWrapUp(&glUARTtoCPU_Handle);
		if(Status == CY_U3P_SUCCESS)
		{
			Status = CyU3PDmaChannelGetBuffer(&glUARTtoCPU_Handle, &ConsoleInDmaBuffer, CYU3P_WAIT_FOREVER);
			if(Status == CY_U3P_SUCCESS)
			{
				if(ConsoleInDmaBuffer.count > 0)
				{
					protPushSequence(fifo, ConsoleInDmaBuffer.buffer,ConsoleInDmaBuffer.count);
				}

				Status = CyU3PDmaChannelDiscardBuffer(&glUARTtoCPU_Handle);
				if(Status != CY_U3P_SUCCESS)
				{
					CyU3PDmaChannelReset (&glUARTtoCPU_Handle);
					CyU3PDmaChannelSetXfer (&glUARTtoCPU_Handle, 0);
				}
			}
			else
			{
				CyU3PDmaChannelReset (&glUARTtoCPU_Handle);
				CyU3PDmaChannelSetXfer (&glUARTtoCPU_Handle, 0);
			}
		}
		else
		{
			CyU3PDmaChannelReset (&glUARTtoCPU_Handle);
			CyU3PDmaChannelSetXfer (&glUARTtoCPU_Handle, 0);
		}

		CyU3PThreadSleep(10);
	}
}

 

 

 

Initialization: 

 

 

CyU3PReturnStatus_t InitializeUart(void)
{
    CyU3PReturnStatus_t Status = CY_U3P_SUCCESS;

    Status = CyU3PUartInit();										// Start the UART driver
    CheckStatus("CyU3PUartInit", Status);							// This will not display since we're not connected yet

    CyU3PMemSet ((uint8_t *)&glUartConfig, 0, sizeof (glUartConfig));
    glUartConfig.baudRate = CY_U3P_UART_BAUDRATE_38400;
    glUartConfig.stopBit  = CY_U3P_UART_ONE_STOP_BIT;
    glUartConfig.parity   = CY_U3P_UART_NO_PARITY;
    glUartConfig.txEnable = CyTrue;
    glUartConfig.rxEnable = CyTrue;
    glUartConfig.flowCtrl = CyFalse;
    glUartConfig.isDma    = CyTrue;
	Status = CyU3PUartSetConfig(&glUartConfig, UartCallback);	// Configure the UART hardware
    CheckStatus("CyU3PUartSetConfig", Status);

    CyU3PDmaChannelConfig_t dmaConfig;
	CyU3PMemSet((uint8_t *)&dmaConfig, 0, sizeof(dmaConfig));
	dmaConfig.size  		= 1024;
	dmaConfig.count 		= 4;
	dmaConfig.prodSckId		= CY_U3P_CPU_SOCKET_PROD;
	dmaConfig.consSckId 	= CY_U3P_LPP_SOCKET_UART_CONS;
	Status = CyU3PDmaChannelCreate(&glCPUtoUART_Handle, CY_U3P_DMA_TYPE_MANUAL_OUT, &dmaConfig);
    CheckStatus("CreateDebugTxDmaChannel", Status);

	dmaConfig.prodSckId		= CY_U3P_LPP_SOCKET_UART_PROD;
	dmaConfig.consSckId 	= CY_U3P_CPU_SOCKET_CONS;
	Status = CyU3PDmaChannelCreate(&glUARTtoCPU_Handle, CY_U3P_DMA_TYPE_MANUAL_IN, &dmaConfig);
    CheckStatus("CreateDebugRxDmaChannel", Status);


    Status = CyU3PUartTxSetBlockXfer(0xFFFFFFFF);
    CheckStatus("CyU3PUartTxSetBlockXfer", Status);
    Status = CyU3PUartRxSetBlockXfer(1);
    CheckStatus("CyU3PUartRxSetBlockXfer", Status);

	Status = CyU3PDmaChannelSetXfer(&glUARTtoCPU_Handle, 0);
    CheckStatus("ChannelSetXfer", Status);
	Status = CyU3PDmaChannelSetXfer(&glCPUtoUART_Handle, 0);
    CheckStatus("ChannelSetXfer", Status);

	if (Status == CY_U3P_SUCCESS) glUartTxEnabled = CyTrue;
    CheckStatus("ConsoleOutEnabled", Status);						// First console display message

    return Status;
}

 

 

 

Please help. Best regards

0 Likes
1 Solution
Rashi_Vatsa
Moderator
Moderator
Moderator
5 likes given 500 solutions authored 1000 replies posted

Hello,

CY_U3P_ERROR_NOT_STARTED error is returned by CyU3PDmaChannelGetBuffer when DMA channel is not in one of the following state -  CY_U3P_DMA_ACTIVE or CY_U3P_DMA_IN_COMPLETION

Please let me know why is  CyU3PUartRxSetBlockXfer is set with rxsize as 1. The UART RX will stop receiving the data once the the rxsize is received. You would need to call CyU3PUartRxSetBlockXfer again to receive data or set the rxsize to infinite/indefinite as done for txSize in CyU3PUartTxSetBlockXfer.

Regards,
Rashi

View solution in original post

0 Likes
11 Replies
Rashi_Vatsa
Moderator
Moderator
Moderator
5 likes given 500 solutions authored 1000 replies posted

Hello,

CY_U3P_ERROR_NOT_STARTED error is returned by CyU3PDmaChannelGetBuffer when DMA channel is not in one of the following state -  CY_U3P_DMA_ACTIVE or CY_U3P_DMA_IN_COMPLETION

Please let me know why is  CyU3PUartRxSetBlockXfer is set with rxsize as 1. The UART RX will stop receiving the data once the the rxsize is received. You would need to call CyU3PUartRxSetBlockXfer again to receive data or set the rxsize to infinite/indefinite as done for txSize in CyU3PUartTxSetBlockXfer.

Regards,
Rashi
0 Likes

Hello,

I need to receive data byte-by-byte because of undefined packet length. Anyway, changing CyU3PUartRxSetBlockXfer to 0xFFFFFFFF doesn't make any difference as well.

Best Regards,

Maks

0 Likes
Rashi_Vatsa
Moderator
Moderator
Moderator
5 likes given 500 solutions authored 1000 replies posted

Hello,

Can you please share your firmware with us? This will help us to know the flow of the application.

Regards,
Rashi
0 Likes

Hi. Firmware is attached but customer asked to password protect it and send it in private message. Thank you for understanding

0 Likes
Rashi_Vatsa
Moderator
Moderator
Moderator
5 likes given 500 solutions authored 1000 replies posted

Hello,

From the firmware, I noticed that UartReceiveTask is a thread entry function. 

You can try the following to synchronize the data received by UART

- Try checking CY_U3P_LPP_UART_RX_DONE event in the UartCallback. As CyU3PUartRxSetBlockXfer is set to 1, CY_U3P_LPP_UART_RX_DONE is expected to be triggered when 1 byte is received by UART RX.

- Once the CY_U3P_LPP_UART_RX_DONE is triggered, call the UartReceiveTask 

Regards,
Rashi
0 Likes

Hi,

Unfortunately, it didn't help. CyU3PDmaChannelGetBuffer still throws CY_U3P_ERROR_NOT_STARTED in case I run UartReceiveTask's code after UART callback. If I run it inside of callback then no error thrown but packets still loosed.

Thanks

0 Likes

Hello,

For the case when is called CyU3PDmaChannelGetBuffer inside callback, how do you confirm that the packets are lost.

Please let me know how much data is being sent to FX3 over UART and how so you check missing packets. Also let me know where do you call CyU3PUartRxSetBlockXfer API gain after receiving 1 byte of data in the new implementation

Regards,
Rashi
0 Likes

Hi,

It is detected by external PC software that communicates to FX3 and other chips via UART. FX3 acts like a bridge. Data size is variable: from 13 up to 990 bytes. I've tried to call CyU3PUartRxSetBlockXfer  before CyU3PDmaChannelSetWrapUp, before and after CyU3PDmaChannelGetBuffer - no positive results. 

By the way, in original code DMA state is CY_U3P_DMA_ERROR when CyU3PDmaChannelGetBuffer  throws an error.

Regards

0 Likes

Hello,

FX3 acts like a bridge. Data size is variable: from 13 up to 990 bytes

>> In that case, could please set CyU3PUartRxSetBlockXfer to 0xFFFFFFFF.

The CyU3PDmaChannelSetWrapUp should be called in synchronization with the data sent to FX3 over UART. The ThreadSleep API or the delay should be set such that DMA socket is wrapped up after a particular interval of time.

Once the CyU3PDmaChannelSetWrapUp is called a CY_U3P_DMA_CB_PROD_EVENT will triggered in the DMA callback. Please note that DMA callback and CY_U3P_DMA_CB_PROD_EVENT event need to be registered while creating the MANUAL IN DMA channel.

On receiving CY_U3P_DMA_CB_PROD_EVENT, the CyU3PDmaChannelGetBuffer API should be called to get the buffer.

Please refer to UsbUart example of the FX3 SDK with similar implementation

Regards,
Rashi
0 Likes

Hello,

It doesn't work that way either. Still loosing packets

void UartCallback(CyU3PDmaChannel *handle, CyU3PDmaCbType_t type, CyU3PDmaCBInput_t *input)
{
	CyU3PDmaBuffer_t ConsoleInDmaBuffer;
	CyU3PReturnStatus_t Status;
	if(type == CY_U3P_DMA_CB_PROD_EVENT)
	{
		Status = CyU3PDmaChannelGetBuffer(&glUARTtoCPU_Handle, &ConsoleInDmaBuffer, CYU3P_WAIT_FOREVER);
		if(Status == CY_U3P_SUCCESS)
		{
			if(ConsoleInDmaBuffer.count > 0)
			{
				protPushSequence(fifo,ConsoleInDmaBuffer.buffer,ConsoleInDmaBuffer.count);
			}

			Status = CyU3PDmaChannelDiscardBuffer(&glUARTtoCPU_Handle);
			if(Status != CY_U3P_SUCCESS)
			{
				CyU3PDmaChannelReset (&glUARTtoCPU_Handle);
				CyU3PDmaChannelSetXfer (&glUARTtoCPU_Handle, 0);
			}
		}
		else
		{
			CyU3PDmaChannelReset (&glUARTtoCPU_Handle);
			CyU3PDmaChannelSetXfer (&glUARTtoCPU_Handle, 0);
		}
	}
}
CyU3PReturnStatus_t InitializeUart(void)
{
    CyU3PReturnStatus_t Status = CY_U3P_SUCCESS;

    Status = CyU3PUartInit();										// Start the UART driver
    CheckStatus("CyU3PUartInit", Status);							// This will not display since we're not connected yet

    CyU3PMemSet ((uint8_t *)&glUartConfig, 0, sizeof (glUartConfig));
    glUartConfig.baudRate = CY_U3P_UART_BAUDRATE_38400;
    glUartConfig.stopBit  = CY_U3P_UART_ONE_STOP_BIT;
    glUartConfig.parity   = CY_U3P_UART_NO_PARITY;
    glUartConfig.txEnable = CyTrue;
    glUartConfig.rxEnable = CyTrue;
    glUartConfig.flowCtrl = CyFalse;
    glUartConfig.isDma    = CyTrue;
	Status = CyU3PUartSetConfig(&glUartConfig, NULL);	// Configure the UART hardware
    CheckStatus("CyU3PUartSetConfig", Status);

    CyU3PDmaChannelConfig_t dmaConfig;
	CyU3PMemSet((uint8_t *)&dmaConfig, 0, sizeof(dmaConfig));
	dmaConfig.size  		= 1024;
	dmaConfig.count 		= 4;
	dmaConfig.prodSckId		= CY_U3P_CPU_SOCKET_PROD;
	dmaConfig.consSckId 	= CY_U3P_LPP_SOCKET_UART_CONS;
	Status = CyU3PDmaChannelCreate(&glCPUtoUART_Handle, CY_U3P_DMA_TYPE_MANUAL_OUT, &dmaConfig);
    CheckStatus("CreateDebugTxDmaChannel", Status);

	dmaConfig.prodSckId		= CY_U3P_LPP_SOCKET_UART_PROD;
	dmaConfig.consSckId 	= CY_U3P_CPU_SOCKET_CONS;
	dmaConfig.notification  = CY_U3P_DMA_CB_PROD_EVENT;
	dmaConfig.cb  			= UartCallback;
	Status = CyU3PDmaChannelCreate(&glUARTtoCPU_Handle, CY_U3P_DMA_TYPE_MANUAL_IN, &dmaConfig);
    CheckStatus("CreateDebugRxDmaChannel", Status);


    Status = CyU3PUartTxSetBlockXfer(0xFFFFFFFF);
    CheckStatus("CyU3PUartTxSetBlockXfer", Status);
    Status = CyU3PUartRxSetBlockXfer(0xFFFFFFFF);
    CheckStatus("CyU3PUartRxSetBlockXfer", Status);

	Status = CyU3PDmaChannelSetXfer(&glUARTtoCPU_Handle, 0);
    CheckStatus("ChannelSetXfer", Status);
	Status = CyU3PDmaChannelSetXfer(&glCPUtoUART_Handle, 0);
    CheckStatus("ChannelSetXfer", Status);

	if (Status == CY_U3P_SUCCESS) glUartTxEnabled = CyTrue;
    CheckStatus("ConsoleOutEnabled", Status);						// First console display message

    return Status;
}

 

void UartReceiveTask(void * arg)
{
	CyU3PReturnStatus_t Status;

	while(1)
	{
		Status = CyU3PDmaChannelSetWrapUp(&glUARTtoCPU_Handle);
		if(Status == CY_U3P_SUCCESS)
		{
		}
		else
		{
			CyU3PDmaChannelReset (&glUARTtoCPU_Handle);
			CyU3PDmaChannelSetXfer (&glUARTtoCPU_Handle, 0);
		}

		CyU3PThreadSleep(1);
	}
}

 Thanks

0 Likes

Hello,

Could you please let me know how much data is sent to FX3 and how is the data received by FX3 so that I can understand the problem better. Or else could you send 10-12 bytes of incrementing data to FX3 and let me know how much is received by FX3

Please let me know if protPushSequence API is a custom API and what is the functionality.

Also, let me know if any of the API fails at any point of time when the data is being received 

Regards,
Rashi
0 Likes