• 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个字节的数据,或者说是将缓冲区填满的数据!!

  • 相关阅读:
    鸟哥的linux私房菜学习-(八)Linux 文件与目录管理
    我的作品
    聊聊软件测试面试的一些事
    如何做一名专业的软件测试工程师
    测试Leader应该做哪些事
    软件测试工程师的岗位职责
    一个完整的性能测试流程
    做接口测试需要哪些技能
    软件质量保障体系建设
    性能测试常见瓶颈分析及调优方法
  • 原文地址:https://www.cnblogs.com/Lxk0825/p/9632830.html
Copyright © 2020-2023  润新知