Cypress EZ-USB FX3 DMA模式下的串口通讯

Posted lxk0825

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Cypress EZ-USB FX3 DMA模式下的串口通讯相关的知识,希望对你有一定的参考价值。

  

   由于公司设备升级后出了问题,需要对USB驱动进行修改,原本使用的是寄存器模式进行UART传输,但是由于FX3寄存器模式会出现长时间延时等待的问题,不得不对其传输模式进行修改。虽然赛普拉斯的EZ-USB FX3系列芯片功能强大,成本适中,但共享资源太少,API参考手册里面的干货不多,直接导致开发困难,出现问题只能去官方社区寻找答案。新模式的开发也不是一帆风顺,找来找去,只有在固件库中找到了UartLpDmaMode这个例程还比较相似。于是便在其基础上进行修改。

  在UartLpDmaMode例程中,其数据流通方向是这样的:

技术分享图片

  只是从将接收到的数据进行了循环发送,这样一来,其生产者和消费者ID便很好设置,但是你无法对DMA通道进行直接操作,换句话说,你无法发送你想要发送的数据,也无法将你接收到的数据存入自己开辟的缓冲区中进行存储使用,当然这样并不是我想要的。

  我想要操作的数据传输是能够实现想传什么传什么,接收到的数据能想什么时候用就可以什么时候用。其数据流通就如同下图:

技术分享图片

但是,我在初期对FX3的DMA消费者生产者理解不深,一度认为这是不能实现的,但经过几天的社区询问以及个人摸索,发现可以这样使用!由于期间走了很多弯路,深知百度找不到任何有关赛普拉斯有用资料的苦衷,现在把这段代码分享出来。

 

开发环境:EZ-USB FX3 Development Kit SDK1.3.4

开发板型号:CYUSB3KIT-003(CYUSB3014)

 

开发目的:实现串口DMA模式的数据发送以及接收,能够随意发送自己缓冲区中的数据,接收到的数据能够储存在个人开辟的缓冲区中

  1 /*
  2  ## Cypress USB 3.0 Platform source file (cyfxuartlpdmamode.c)
  3  ## ===========================
  4  ##
  5  ##  Copyright Cypress Semiconductor Corporation, 2010-2018,
  6  ##  All Rights Reserved
  7  ##  UNPUBLISHED, LICENSED SOFTWARE.
  8  ##
  9  ##  CONFIDENTIAL AND PROPRIETARY INFORMATION
 10  ##  WHICH IS THE PROPERTY OF CYPRESS.
 11  ##
 12  ##  Use of this file is governed
 13  ##  by the license agreement included in the file
 14  ##
 15  ##     <install>/license/license.txt
 16  ##
 17  ##  where <install> is the Cypress software
 18  ##  installation root directory path.
 19  ##
 20  ## ===========================
 21 */
 22 
 23 /* This file implements a simple UART (DMA mode) loopback application example */
 24 
 25 /*此DEMO使用DMA模式,可以发送自己缓冲区中的数据,接收到数据后,可将接收到的数据存入全局变量glRxBuffer->buffer中。
 26  *注意:
 27  *    赛普拉斯FX3的DMA缓冲区大小最小是16个字节,缓冲区大小必须是16的倍数,也就是说,发送数据至少发送16个字节,发送的数据最大不能超过缓冲区的设定值,接收也一样,否则缓冲区未满,无法触发接收和发送!
 28  *如果与其他设备通讯,可以让其他设备强制发送16个字节的数据,自己取有效位使用。如果想一个字节一个字节的发送和接收,可以使用寄存器模式。
 29  */
 30 
 31 #include <cyu3system.h>
 32 #include <cyu3os.h>
 33 #include <cyu3error.h>
 34 #include <cyu3uart.h>
 35 
 36 #define CY_FX_UARTLP_THREAD_STACK       (0x0400)  /* UART application thread stack size */
 37 #define CY_FX_UARTLP_THREAD_PRIORITY    (8)       /* UART application thread priority */
 38 #define CY_FX_UART_DMA_TX_SIZE    (0)               /* DMA transfer size */
 39 #define CY_FX_UART_DMA_BUF_SIZE (16)              /* Buffer size */
 40 
 41 CyU3PThread UartLpAppThread;                      /* UART Example application thread structure */
 42 
 43 uint8_t testBuffer[16] = {0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xff};
 44 
 45 CyU3PDmaChannel glUartRXChHandle;
 46 CyU3PDmaChannel glUartTXChHandle;
 47 CyU3PDmaBuffer_t* glTxBuffer;
 48 CyU3PDmaBuffer_t* glRxBuffer;
 49 uint8_t ClearFlag = 0;
 50 
 51 /* Application error handler */
 52 void
 53 CyFxAppErrorHandler (
 54         CyU3PReturnStatus_t apiRetStatus    /* API return status */
 55         )
 56 {
 57     /* Application failed with the error code apiRetStatus */
 58 
 59     /* Add custom debug or recovery actions here */
 60 
 61     /* Loop indefinitely */
 62     for (;;)
 63     {
 64         /* Thread sleep : 100 ms */
 65         CyU3PThreadSleep (100);
 66     }
 67 }
 68 /***********************************************************************************************
 69 *函数名 : SendData
 70 *函数功能描述 : 通过DMA模式 由串口发送数据
 71 *函数参数 : buffer-所需要发送的数据    len-发送数据的长度
 72 *函数返回值 : 无
 73 *注意:len最小为16
 74 ***********************************************************************************************/
 75 void SendData(uint8_t * buffer, unsigned int len)
 76 {
 77     CyU3PReturnStatus_t status;
 78     unsigned int i = 0;
 79     CyU3PDmaChannelGetBuffer(&glUartTXChHandle, glTxBuffer, 0);
 80     for(i = 0; i < len; i++)
 81     {
 82         glTxBuffer->buffer[i] = buffer[i];
 83     }
 84     CyU3PDmaChannelSetupSendBuffer(&glUartTXChHandle,glTxBuffer);
 85     status = CyU3PDmaChannelCommitBuffer(&glUartTXChHandle, 16, 0);
 86     if (status == CY_U3P_SUCCESS)
 87     {
 88 
 89     }
 90 }
 91 
 92 /***********************************************************************************************
 93 *函数名 : ReceivedDataCallBack
 94 *函数功能描述 : 接收缓冲区充满后的回调函数
 95 *函数参数 : chHandle-DMA通道的句柄    type-事件类型    input-输入
 96 *函数返回值 : 无
 97 *注意:形参已经被设置好,直接可以使用
 98 ***********************************************************************************************/
 99 void ReceivedDataCallBack(
100         CyU3PDmaChannel   *chHandle, /* Handle to the DMA channel. */
101         CyU3PDmaCbType_t  type,      /* Callback type.             */
102         CyU3PDmaCBInput_t *input)
103 {
104     CyU3PReturnStatus_t status;
105     if(type == CY_U3P_DMA_CB_PROD_EVENT)
106     {
107         //CyU3PDmaChannelSetWrapUp(&glUartRXChHandle);
108         status = CyU3PDmaChannelGetBuffer(&glUartRXChHandle, glRxBuffer, 0);
109         //测试用,将收到的信息在发送出去,此时测试为接收到16个字节的数据
110         SendData(glRxBuffer->buffer, 16);
111         //SendData(testBuffer, 16);
112         ClearFlag = 1;
113         if (status == CY_U3P_SUCCESS)
114         {
115             CyU3PDmaChannelDiscardBuffer(&glUartRXChHandle);
116         }
117     }
118 }
119 
120 /* This function initializes the UART module */
121 void
122 CyFxUartDMAlnInit (void)
123 {
124     CyU3PUartConfig_t uartConfig;
125     CyU3PDmaChannelConfig_t dmaConfig;
126     CyU3PReturnStatus_t apiRetStatus = CY_U3P_SUCCESS;
127 
128     //开启DCache后 一定设置为32,未开启最好也设置成32,但也可设置为16,不影响使用
129     glTxBuffer = (CyU3PDmaBuffer_t*)CyU3PDmaBufferAlloc (32);
130     glRxBuffer = (CyU3PDmaBuffer_t*)CyU3PDmaBufferAlloc (32);
131 
132     /* Initialize the UART module */
133     apiRetStatus = CyU3PUartInit ();
134     if (apiRetStatus != CY_U3P_SUCCESS)
135     {
136         /* Error handling */
137         CyFxAppErrorHandler(apiRetStatus);
138     }
139 
140     /* Configure the UART
141        Baudrate = 115200, One stop bit, No parity, Hardware flow control enabled.
142      */
143     CyU3PMemSet ((uint8_t *)&uartConfig, 0, sizeof(uartConfig));
144     uartConfig.baudRate = CY_U3P_UART_BAUDRATE_115200;
145     uartConfig.stopBit = CY_U3P_UART_ONE_STOP_BIT;
146     uartConfig.parity = CY_U3P_UART_NO_PARITY;
147     uartConfig.flowCtrl = CyFalse;             //一定不能为真
148     uartConfig.txEnable = CyTrue;
149     uartConfig.rxEnable = CyTrue;
150     uartConfig.isDma = CyTrue; /* DMA mode */
151 
152     /* Set the UART configuration */
153     apiRetStatus = CyU3PUartSetConfig (&uartConfig, NULL);
154     if (apiRetStatus != CY_U3P_SUCCESS )
155     {
156         /* Error handling */
157         CyFxAppErrorHandler(apiRetStatus);
158     }
159 
160     /* Create a DMA Manual channel between UART producer socket
161        and UART consumer socket */
162     CyU3PMemSet ((uint8_t *)&dmaConfig, 0, sizeof(dmaConfig));
163     dmaConfig.size = CY_FX_UART_DMA_BUF_SIZE;
164     dmaConfig.count = 1;
165     dmaConfig.prodSckId = CY_U3P_LPP_SOCKET_UART_PROD;   //生产者为RX
166     dmaConfig.consSckId = CY_U3P_CPU_SOCKET_CONS;        //消费者
167     dmaConfig.dmaMode = CY_U3P_DMA_MODE_BYTE;
168     dmaConfig.notification = CY_U3P_DMA_CB_PROD_EVENT;   //缓冲区充满产生的事件,此事件触发回调函数
169     dmaConfig.cb = ReceivedDataCallBack;
170     dmaConfig.prodHeader = 0;
171     dmaConfig.prodFooter = 0;
172     dmaConfig.consHeader = 0;
173     dmaConfig.prodAvailCount = 0;
174     /* Create the channel */
175     apiRetStatus = CyU3PDmaChannelCreate (&glUartRXChHandle,
176             CY_U3P_DMA_TYPE_MANUAL_IN, &dmaConfig);
177 
178     if (apiRetStatus != CY_U3P_SUCCESS)
179     {
180         /* Error handling */
181         CyFxAppErrorHandler(apiRetStatus);
182     }
183 
184     dmaConfig.size = CY_FX_UART_DMA_BUF_SIZE;
185     dmaConfig.count = 1;
186     dmaConfig.prodSckId = CY_U3P_CPU_SOCKET_PROD;               //生产者CPU
187     dmaConfig.consSckId = CY_U3P_LPP_SOCKET_UART_CONS;          //消费者为TX
188     dmaConfig.dmaMode = CY_U3P_DMA_MODE_BYTE;
189     dmaConfig.notification = 0;
190     dmaConfig.cb = NULL;
191     dmaConfig.prodHeader = 0;
192     dmaConfig.prodFooter = 0;
193     dmaConfig.consHeader = 0;
194     dmaConfig.prodAvailCount = 0;
195 
196     /* Create the channel */
197     apiRetStatus = CyU3PDmaChannelCreate (&glUartTXChHandle,
198             CY_U3P_DMA_TYPE_MANUAL_OUT, &dmaConfig);
199 
200     if (apiRetStatus != CY_U3P_SUCCESS)
201     {
202         /* Error handling */
203         CyFxAppErrorHandler(apiRetStatus);
204     }
205     /* Set UART Tx and Rx transfer Size to infinite */
206     apiRetStatus = CyU3PUartTxSetBlockXfer(0xFFFFFFFF);
207     if (apiRetStatus != CY_U3P_SUCCESS)
208     {
209         /* Error handling */
210         CyFxAppErrorHandler(apiRetStatus);
211     }
212 
213     apiRetStatus = CyU3PUartRxSetBlockXfer(0xFFFFFFFF);
214     if (apiRetStatus != CY_U3P_SUCCESS)
215     {
216         /* Error handling */
217         CyFxAppErrorHandler(apiRetStatus);
218     }
219 
220     /* Set DMA Channel transfer size */
221     apiRetStatus = CyU3PDmaChannelSetXfer (&glUartRXChHandle, 0);
222     if (apiRetStatus != CY_U3P_SUCCESS)
223     {
224             /* Error handling */
225         CyFxAppErrorHandler(apiRetStatus);
226     }
227 
228     apiRetStatus = CyU3PDmaChannelSetXfer (&glUartTXChHandle, 0);
229     if (apiRetStatus != CY_U3P_SUCCESS)
230     {
231         /* Error handling */
232         CyFxAppErrorHandler(apiRetStatus);
233     }
234 }
235 
236 /* Entry function for the UartLpAppThread */
237 void
238 UartLpAppThread_Entry (
239         uint32_t input)
240 {
241     /* Initialize the UART Example Application */
242     CyFxUartDMAlnInit();
243 
244     //uint8_t testBuffer[8] = {0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8};
245     for (;;)
246     {
247 
248         //if中的语句,是为了接收完毕后清除缓冲区,如果不清除缓冲区,如果所发数据超过缓冲区长度,第二次发送时会将上次未发送完的数据发送过来。
249         if(ClearFlag == 1)
250         {
251             //SendData(glRxBuffer->buffer, 16);
252             CyU3PDmaChannelReset(&glUartRXChHandle);
253             CyU3PThreadSleep(10);
254             CyU3PDmaChannelSetXfer(&glUartRXChHandle,0);
255             ClearFlag = 0;
256         }
257         /* No operation in the thread */
258         CyU3PThreadSleep (100);
259     }
260 }
261 
262 /* Application define function which creates the threads. */
263 void
264 CyFxApplicationDefine (
265         void)
266 {
267     void *ptr = NULL;
268     uint32_t retThrdCreate = CY_U3P_SUCCESS;
269 
270     /* Allocate the memory for the threads */
271     ptr = CyU3PMemAlloc (CY_FX_UARTLP_THREAD_STACK);
272 
273     /* Create the thread for the application */
274     retThrdCreate = CyU3PThreadCreate (&UartLpAppThread,           /* UART Example App Thread structure */
275                           "21:UART_loopback_DMA_mode",             /* Thread ID and Thread name */
276                           UartLpAppThread_Entry,                   /* UART Example App Thread Entry function */
277                           0,                                       /* No input parameter to thread */
278                           ptr,                                     /* Pointer to the allocated thread stack */
279                           CY_FX_UARTLP_THREAD_STACK,               /* UART Example App Thread stack size */
280                           CY_FX_UARTLP_THREAD_PRIORITY,            /* UART Example App Thread priority */
281                           CY_FX_UARTLP_THREAD_PRIORITY,            /* UART Example App Thread priority */
282                           CYU3P_NO_TIME_SLICE,                     /* No time slice for the application thread */
283                           CYU3P_AUTO_START                         /* Start the Thread immediately */
284                           );
285 
286     /* Check the return code */
287     if (retThrdCreate != 0)
288     {
289         /* Thread Creation failed with the error code retThrdCreate */
290 
291         /* Add custom recovery or debug actions here */
292 
293         /* Application cannot continue */
294         /* Loop indefinitely */
295         while(1);
296     }
297 }
298 
299 /*
300  * Main function
301  */
302 int
303 main (void)
304 {
305     CyU3PIoMatrixConfig_t io_cfg;
306     CyU3PReturnStatus_t status = CY_U3P_SUCCESS;
307 
308     /* Initialize the device */
309     status = CyU3PDeviceInit (0);
310     if (status != CY_U3P_SUCCESS)
311     {
312         goto handle_fatal_error;
313     }
314 
315     /* Initialize the caches. Enable both Instruction and Data Caches. */
316     status = CyU3PDeviceCacheControl (CyTrue, CyTrue, CyTrue);
317     if (status != CY_U3P_SUCCESS)
318     {
319         goto handle_fatal_error;
320     }
321 
322     /* Configure the IO matrix for the device. On the FX3 DVK board, the COM port 
323      * is connected to the IO(53:56). This means that either DQ32 mode should be
324      * selected or lppMode should be set to UART_ONLY. Here we are choosing
325      * UART_ONLY configuration. */
326     CyU3PMemSet ((uint8_t *)&io_cfg, 0, sizeof(io_cfg));
327     io_cfg.isDQ32Bit = CyFalse;
328     io_cfg.s0Mode = CY_U3P_SPORT_INACTIVE;
329     io_cfg.s1Mode = CY_U3P_SPORT_INACTIVE;
330     io_cfg.useUart   = CyTrue;
331     io_cfg.useI2C    = CyFalse;
332     io_cfg.useI2S    = CyFalse;
333     io_cfg.useSpi    = CyFalse;
334     io_cfg.lppMode   = CY_U3P_IO_MATRIX_LPP_UART_ONLY;
335     /* No GPios are enabled. */
336     io_cfg.gpioSimpleEn[0]  = 0;
337     io_cfg.gpioSimpleEn[1]  = 0;
338     io_cfg.gpioComplexEn[0] = 0;
339     io_cfg.gpioComplexEn[1] = 0;
340     status = CyU3PDeviceConfigureIOMatrix (&io_cfg);
341     if (status != CY_U3P_SUCCESS)
342     {
343         goto handle_fatal_error;
344     }
345 
346     /* This is a non returnable call for initializing the RTOS kernel */
347     CyU3PKernelEntry ();
348 
349     /* Dummy return to make the compiler happy */
350     return 0;
351 
352 handle_fatal_error:
353     /* Cannot recover from this error. */
354     while (1);
355 
356 }
357 
358 /* [ ] */

 

实验效果:能够实现发送和接收,FX3将接收到的数据再发送给主机,如图:

技术分享图片

将110行的 SendData(glRxBuffer->buffer, 16);改为111行的SendData(testBuffer, 16);能够实现,接收16位数据后,将testBuffer中的数据返回给主机,效果如图:

技术分享图片

需要注意的是:DMA_BUFFER_SIZE的大小必须为16的倍数!!最小为16!!也就是说,一次至少需要发送或者接收16个字节的数据,或者说是将缓冲区填满的数据!!

 

以上是关于Cypress EZ-USB FX3 DMA模式下的串口通讯的主要内容,如果未能解决你的问题,请参考以下文章

UART 发送 DMA。传输完成后没有 UART_IRQ_Handler 调用(它在调试模式下工作)

启用 DMA 的 UART Tx 模式

CH559L单片机DMA方式在手工选择通道模式下AD采样数据串口输出

赛普拉斯/GitLab CI/CD 集成 - 赛普拉斯不会在无头模式下启动

Cypress web自动化23-cypress run 命令行参数详解

Cypress web自动化23-cypress run 命令行参数详解