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

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

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

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

原文地址:https://www.cnblogs.com/Lxk0825/p/9632830.html