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個字節的數據,或者說是將緩沖區填滿的數據!!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM