由于公司设备升级后出了问题,需要对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模式的数据发送以及接收,能够随意发送自己缓冲区中的数据,接收到的数据能够储存在个人开辟的缓冲区中

 /*此DEMO使用DMA模式,可以发送自己缓冲区中的数据,接收到数据后,可将接收到的数据存入全局变量glRxBuffer->buffer中。
*注意:
* 赛普拉斯FX3的DMA缓冲区大小最小是16个字节,缓冲区大小必须是16的倍数,也就是说,发送数据至少发送16个字节,发送的数据最大不能超过缓冲区的设定值,接收也一样,否则缓冲区未满,无法触发接收和发送!
*如果与其他设备通讯,可以让其他设备强制发送16个字节的数据,自己取有效位使用。如果想一个字节一个字节的发送和接收,可以使用寄存器模式。
*/ #include <cyu3system.h>
#include <cyu3os.h>
#include <cyu3error.h>
#include <cyu3uart.h> #define CY_FX_UARTLP_THREAD_STACK (0x0400) /* UART application thread stack size */
#define CY_FX_UARTLP_THREAD_PRIORITY (8) /* UART application thread priority */
#define CY_FX_UART_DMA_TX_SIZE (0) /* DMA transfer size */
#define CY_FX_UART_DMA_BUF_SIZE (16) /* Buffer size */ CyU3PThread UartLpAppThread; /* UART Example application thread structure */ uint8_t testBuffer[] = {0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xff}; CyU3PDmaChannel glUartRXChHandle;
CyU3PDmaChannel glUartTXChHandle;
CyU3PDmaBuffer_t* glTxBuffer;
CyU3PDmaBuffer_t* glRxBuffer;
uint8_t ClearFlag = ; /* Application error handler */
void
CyFxAppErrorHandler (
CyU3PReturnStatus_t apiRetStatus /* API return status */
)
{
/* Application failed with the error code apiRetStatus */ /* Add custom debug or recovery actions here */ /* Loop indefinitely */
for (;;)
{
/* Thread sleep : 100 ms */
CyU3PThreadSleep ();
}
}
/***********************************************************************************************
*函数名 : SendData
*函数功能描述 : 通过DMA模式 由串口发送数据
*函数参数 : buffer-所需要发送的数据 len-发送数据的长度
*函数返回值 : 无
*注意:len最小为16
***********************************************************************************************/
void SendData(uint8_t * buffer, unsigned int len)
{
CyU3PReturnStatus_t status;
unsigned int i = ;
CyU3PDmaChannelGetBuffer(&glUartTXChHandle, glTxBuffer, );
for(i = ; i < len; i++)
{
glTxBuffer->buffer[i] = buffer[i];
}
CyU3PDmaChannelSetupSendBuffer(&glUartTXChHandle,glTxBuffer);
status = CyU3PDmaChannelCommitBuffer(&glUartTXChHandle, , );
if (status == CY_U3P_SUCCESS)
{ }
} /***********************************************************************************************
*函数名 : ReceivedDataCallBack
*函数功能描述 : 接收缓冲区充满后的回调函数
*函数参数 : chHandle-DMA通道的句柄 type-事件类型 input-输入
*函数返回值 : 无
*注意:形参已经被设置好,直接可以使用
***********************************************************************************************/
void ReceivedDataCallBack(
CyU3PDmaChannel *chHandle, /* Handle to the DMA channel. */
CyU3PDmaCbType_t type, /* Callback type. */
CyU3PDmaCBInput_t *input)
{
CyU3PReturnStatus_t status;
if(type == CY_U3P_DMA_CB_PROD_EVENT)
{
//CyU3PDmaChannelSetWrapUp(&glUartRXChHandle);
status = CyU3PDmaChannelGetBuffer(&glUartRXChHandle, glRxBuffer, );
//测试用,将收到的信息在发送出去,此时测试为接收到16个字节的数据
SendData(glRxBuffer->buffer, );
//SendData(testBuffer, 16);
ClearFlag = ;
if (status == CY_U3P_SUCCESS)
{
CyU3PDmaChannelDiscardBuffer(&glUartRXChHandle);
}
}
} /* This function initializes the UART module */
void
CyFxUartDMAlnInit (void)
{
CyU3PUartConfig_t uartConfig;
CyU3PDmaChannelConfig_t dmaConfig;
CyU3PReturnStatus_t apiRetStatus = CY_U3P_SUCCESS; //开启DCache后 一定设置为32,未开启最好也设置成32,但也可设置为16,不影响使用
glTxBuffer = (CyU3PDmaBuffer_t*)CyU3PDmaBufferAlloc ();
glRxBuffer = (CyU3PDmaBuffer_t*)CyU3PDmaBufferAlloc (); /* Initialize the UART module */
apiRetStatus = CyU3PUartInit ();
if (apiRetStatus != CY_U3P_SUCCESS)
{
/* Error handling */
CyFxAppErrorHandler(apiRetStatus);
} /* Configure the UART
Baudrate = 115200, One stop bit, No parity, Hardware flow control enabled.
*/
CyU3PMemSet ((uint8_t *)&uartConfig, , sizeof(uartConfig));
uartConfig.baudRate = CY_U3P_UART_BAUDRATE_115200;
uartConfig.stopBit = CY_U3P_UART_ONE_STOP_BIT;
uartConfig.parity = CY_U3P_UART_NO_PARITY;
uartConfig.flowCtrl = CyFalse; //一定不能为真
uartConfig.txEnable = CyTrue;
uartConfig.rxEnable = CyTrue;
uartConfig.isDma = CyTrue; /* DMA mode */ /* Set the UART configuration */
apiRetStatus = CyU3PUartSetConfig (&uartConfig, NULL);
if (apiRetStatus != CY_U3P_SUCCESS )
{
/* Error handling */
CyFxAppErrorHandler(apiRetStatus);
} /* Create a DMA Manual channel between UART producer socket
and UART consumer socket */
CyU3PMemSet ((uint8_t *)&dmaConfig, , sizeof(dmaConfig));
dmaConfig.size = CY_FX_UART_DMA_BUF_SIZE;
dmaConfig.count = ;
dmaConfig.prodSckId = CY_U3P_LPP_SOCKET_UART_PROD; //生产者为RX
dmaConfig.consSckId = CY_U3P_CPU_SOCKET_CONS; //消费者
dmaConfig.dmaMode = CY_U3P_DMA_MODE_BYTE;
dmaConfig.notification = CY_U3P_DMA_CB_PROD_EVENT; //缓冲区充满产生的事件,此事件触发回调函数
dmaConfig.cb = ReceivedDataCallBack;
dmaConfig.prodHeader = ;
dmaConfig.prodFooter = ;
dmaConfig.consHeader = ;
dmaConfig.prodAvailCount = ;
/* Create the channel */
apiRetStatus = CyU3PDmaChannelCreate (&glUartRXChHandle,
CY_U3P_DMA_TYPE_MANUAL_IN, &dmaConfig); if (apiRetStatus != CY_U3P_SUCCESS)
{
/* Error handling */
CyFxAppErrorHandler(apiRetStatus);
} dmaConfig.size = CY_FX_UART_DMA_BUF_SIZE;
dmaConfig.count = ;
dmaConfig.prodSckId = CY_U3P_CPU_SOCKET_PROD; //生产者CPU
dmaConfig.consSckId = CY_U3P_LPP_SOCKET_UART_CONS; //消费者为TX
dmaConfig.dmaMode = CY_U3P_DMA_MODE_BYTE;
dmaConfig.notification = ;
dmaConfig.cb = NULL;
dmaConfig.prodHeader = ;
dmaConfig.prodFooter = ;
dmaConfig.consHeader = ;
dmaConfig.prodAvailCount = ; /* Create the channel */
apiRetStatus = CyU3PDmaChannelCreate (&glUartTXChHandle,
CY_U3P_DMA_TYPE_MANUAL_OUT, &dmaConfig); if (apiRetStatus != CY_U3P_SUCCESS)
{
/* Error handling */
CyFxAppErrorHandler(apiRetStatus);
}
/* Set UART Tx and Rx transfer Size to infinite */
apiRetStatus = CyU3PUartTxSetBlockXfer(0xFFFFFFFF);
if (apiRetStatus != CY_U3P_SUCCESS)
{
/* Error handling */
CyFxAppErrorHandler(apiRetStatus);
} apiRetStatus = CyU3PUartRxSetBlockXfer(0xFFFFFFFF);
if (apiRetStatus != CY_U3P_SUCCESS)
{
/* Error handling */
CyFxAppErrorHandler(apiRetStatus);
} /* Set DMA Channel transfer size */
apiRetStatus = CyU3PDmaChannelSetXfer (&glUartRXChHandle, );
if (apiRetStatus != CY_U3P_SUCCESS)
{
/* Error handling */
CyFxAppErrorHandler(apiRetStatus);
} apiRetStatus = CyU3PDmaChannelSetXfer (&glUartTXChHandle, );
if (apiRetStatus != CY_U3P_SUCCESS)
{
/* Error handling */
CyFxAppErrorHandler(apiRetStatus);
}
} /* Entry function for the UartLpAppThread */
void
UartLpAppThread_Entry (
uint32_t input)
{
/* Initialize the UART Example Application */
CyFxUartDMAlnInit(); //uint8_t testBuffer[8] = {0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8};
for (;;)
{ //if中的语句,是为了接收完毕后清除缓冲区,如果不清除缓冲区,如果所发数据超过缓冲区长度,第二次发送时会将上次未发送完的数据发送过来。
if(ClearFlag == )
{
//SendData(glRxBuffer->buffer, 16);
CyU3PDmaChannelReset(&glUartRXChHandle);
CyU3PThreadSleep();
CyU3PDmaChannelSetXfer(&glUartRXChHandle,);
ClearFlag = ;
}
/* No operation in the thread */
CyU3PThreadSleep ();
}
} /* Application define function which creates the threads. */
void
CyFxApplicationDefine (
void)
{
void *ptr = NULL;
uint32_t retThrdCreate = CY_U3P_SUCCESS; /* Allocate the memory for the threads */
ptr = CyU3PMemAlloc (CY_FX_UARTLP_THREAD_STACK); /* Create the thread for the application */
retThrdCreate = CyU3PThreadCreate (&UartLpAppThread, /* UART Example App Thread structure */
"21:UART_loopback_DMA_mode", /* Thread ID and Thread name */
UartLpAppThread_Entry, /* UART Example App Thread Entry function */
, /* No input parameter to thread */
ptr, /* Pointer to the allocated thread stack */
CY_FX_UARTLP_THREAD_STACK, /* UART Example App Thread stack size */
CY_FX_UARTLP_THREAD_PRIORITY, /* UART Example App Thread priority */
CY_FX_UARTLP_THREAD_PRIORITY, /* UART Example App Thread priority */
CYU3P_NO_TIME_SLICE, /* No time slice for the application thread */
CYU3P_AUTO_START /* Start the Thread immediately */
); /* Check the return code */
if (retThrdCreate != )
{
/* Thread Creation failed with the error code retThrdCreate */ /* Add custom recovery or debug actions here */ /* Application cannot continue */
/* Loop indefinitely */
while();
}
} /*
* Main function
*/
int
main (void)
{
CyU3PIoMatrixConfig_t io_cfg;
CyU3PReturnStatus_t status = CY_U3P_SUCCESS; /* Initialize the device */
status = CyU3PDeviceInit ();
if (status != CY_U3P_SUCCESS)
{
goto handle_fatal_error;
} /* Initialize the caches. Enable both Instruction and Data Caches. */
status = CyU3PDeviceCacheControl (CyTrue, CyTrue, CyTrue);
if (status != CY_U3P_SUCCESS)
{
goto handle_fatal_error;
} /* Configure the IO matrix for the device. On the FX3 DVK board, the COM port
* is connected to the IO(53:56). This means that either DQ32 mode should be
* selected or lppMode should be set to UART_ONLY. Here we are choosing
* UART_ONLY configuration. */
CyU3PMemSet ((uint8_t *)&io_cfg, , sizeof(io_cfg));
io_cfg.isDQ32Bit = CyFalse;
io_cfg.s0Mode = CY_U3P_SPORT_INACTIVE;
io_cfg.s1Mode = CY_U3P_SPORT_INACTIVE;
io_cfg.useUart = CyTrue;
io_cfg.useI2C = CyFalse;
io_cfg.useI2S = CyFalse;
io_cfg.useSpi = CyFalse;
io_cfg.lppMode = CY_U3P_IO_MATRIX_LPP_UART_ONLY;
/* No GPIOs are enabled. */
io_cfg.gpioSimpleEn[] = ;
io_cfg.gpioSimpleEn[] = ;
io_cfg.gpioComplexEn[] = ;
io_cfg.gpioComplexEn[] = ;
status = CyU3PDeviceConfigureIOMatrix (&io_cfg);
if (status != CY_U3P_SUCCESS)
{
goto handle_fatal_error;
} /* This is a non returnable call for initializing the RTOS kernel */
CyU3PKernelEntry (); /* Dummy return to make the compiler happy */
return ; handle_fatal_error:
/* Cannot recover from this error. */
while (); }

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

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

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

Cypress EZ-USB FX3 DMA模式下的串口通讯的更多相关文章

  1. 详解linux下的串口通讯开发

    串行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使用.常用的串口是RS-232-C接口(又称EIA RS-232-C)它是在1970年由美国电子工业协会(EIA)联合贝尔系统.调制解调 ...

  2. 具体解释linux下的串口通讯开发

    串行口是计算机一种经常使用的接口,具有连接线少.通讯简单,得到广泛的使用.经常使用的串口是RS-232-C接口(又称EIA RS-232-C)它是在1970年由美国电子工业协会(EIA)联合贝尔系统. ...

  3. 【转载】详解linux下的串口通讯开发

    来源:https://www.cnblogs.com/sunyubo/archive/2010/09/26/2282116.html 串行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使 ...

  4. ubuntu下irobot串口通讯

    在window下以前就`有一个现成的串口代码.想移植到ubuntu下,发现都不一样了.要重新找个. 折腾了一上午之后,发现自己写这个串口通讯还是有一点难度. 于是,用了github上 Erick Co ...

  5. 关于嵌入式linux下的串口通讯问题---需增加回车/换行才能接收

    问题:在Linux应用层,直接从/dev/tty***使用read()函数读数据,无法读到,只有在数据末尾加上0a/0d才可以读到数据(这里是发送十六进制的数据,ASCLL码同理,增加回车才可以读到数 ...

  6. STM32基础分析——USART的DMA模式

    有关USART的DMA传输模式,其基本的概念和配置,网上有很多博客和教程都有,这里不再赘述,只是记录一下比较容易忽视而造成调试不通的问题. 1. 串口发送和接收分属两个DMA通道 一般方式操作串口时, ...

  7. CC2540 低功耗串口, POWER_SAVING 模式 下 串口 0 的使用

    低功耗 模式 下 使用 串口 ,  因为 PM2 或者 PM3 状态下  32M晶振 是不工作 的,根据手册得知没有32M晶振, 串口是不能工作的,但是可以使用 外部中断,因此,我把  串口的接收引脚 ...

  8. ASM:《X86汇编语言-从实模式到保护模式》越计卷:实模式下对DMA和Sound Blaster声卡的控制

    说实话越计卷作者用了16页(我还是删过的),来讲怎么控制声卡,其实真正归纳起来就那么几点. ★PART1:直接存储访问 1. 总线控制设备(bus master) 在硬件技术不发达的早期,处理器是最重 ...

  9. usb-host一步一步学(二)安卓在usb-host模式下列出当前连接的usb设备

    之前写了一个简单的例子usb-host一步一步学(一)安卓在usb-host模式下列出当前连接的usb设备,下面的这个例子是获取各种usb设备.usb接口以及usb连接点(endpoint) 正如上一 ...

随机推荐

  1. Codeforces Round #546 (Div. 2) A. Nastya Is Reading a Book

    链接:https://codeforces.com/contest/1136/problem/A 题意: 给n个区间,每个区间范围不超过100,n不超过100. 给一个位置k,1-(k-1)是遍历过的 ...

  2. Codeforces Round #497 (Div. 2) C. Reorder the Array

    Bryce1010模板 http://codeforces.com/contest/1008/problems #include <bits/stdc++.h> using namespa ...

  3. JAVA常用知识总结(十四)——Servlet

    Servlet属于线程安全的吗? Servlet不是线程安全的! 谈谈转发和重定向的区别 请求转发: request.getRequestDispatcher("/king_l2lu.jsp ...

  4. python_12(并发编程)

    第1章 进程 1.1 队列Queue 1.2 Queue方法 1.2.1 q.get([block [,timeout]]) 1.2.2 q.get_nowait() 1.2.3 q.put(item ...

  5. mouseover等闪烁问题

    在使用mouseover等鼠标事件时如移动上去灰色的遮罩层高度从0到100% 在操作中发现鼠标一直在图里面但遮罩会一直变化,我感觉应该是遮罩层出现后导致鼠标离开了底层图片所以会一直变化.想起之前用的 ...

  6. Linux sftp用法

    sftp用法 1. 用sftp如何登录服务器 sftp 是一个交互式文件传输程式.它类似于 ftp, 但它进行加密传输,比FTP有更高的安全性.下边就简单介绍一下如何远程连接主机,进行文件的上传和下载 ...

  7. 单线程单元(STA)线程都应使用泵式等待基元

    CLR 无法从 COM 上下文 0x20ad98 转换为 COM 上下文 0x20af08,这种状态已持续 60 秒.拥有目标上下文/单元的线程很有可能执行的是非泵式等待或者在不发送 Windows ...

  8. Asp_基础之C#基础

    1.两个练习题 1)编程实现46天,是几周几天 int days = 46: int weeks = days / 7: int day =days % 7: //Console.WriteLine( ...

  9. IE6下png背景不透明——张鑫旭博客读书笔记

    从今天开始跟着大牛张鑫旭的步伐,每天进步一点点 问题:IE6不支持png背景透明或半透明 一.可解决的方法 补充:css滤镜主要是用来实现图像的各种特殊效果.(了解) css滤镜的标识符是“filte ...

  10. 在PaaS上开发Web、移动应用(2)

    在PaaS上开发Web.移动应用(2) PaaS学习笔记目录 PaaS基础学习(1) 在PaaS上开发Web.移动应用(2) PaaS优点与限制(3) 6. 巨型代码,是指持续不断地向一个应用程序添加 ...