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 调用(它在调试模式下工作)
CH559L单片机DMA方式在手工选择通道模式下AD采样数据串口输出
赛普拉斯/GitLab CI/CD 集成 - 赛普拉斯不会在无头模式下启动