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模式的数据发送以及接收,能够随意发送自己缓冲区中的数据,接收到的数据能够储存在个人开辟的缓冲区中
/*此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模式下的串口通讯的更多相关文章
- 详解linux下的串口通讯开发
		
串行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使用.常用的串口是RS-232-C接口(又称EIA RS-232-C)它是在1970年由美国电子工业协会(EIA)联合贝尔系统.调制解调 ...
 - 具体解释linux下的串口通讯开发
		
串行口是计算机一种经常使用的接口,具有连接线少.通讯简单,得到广泛的使用.经常使用的串口是RS-232-C接口(又称EIA RS-232-C)它是在1970年由美国电子工业协会(EIA)联合贝尔系统. ...
 - 【转载】详解linux下的串口通讯开发
		
来源:https://www.cnblogs.com/sunyubo/archive/2010/09/26/2282116.html 串行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使 ...
 - ubuntu下irobot串口通讯
		
在window下以前就`有一个现成的串口代码.想移植到ubuntu下,发现都不一样了.要重新找个. 折腾了一上午之后,发现自己写这个串口通讯还是有一点难度. 于是,用了github上 Erick Co ...
 - 关于嵌入式linux下的串口通讯问题---需增加回车/换行才能接收
		
问题:在Linux应用层,直接从/dev/tty***使用read()函数读数据,无法读到,只有在数据末尾加上0a/0d才可以读到数据(这里是发送十六进制的数据,ASCLL码同理,增加回车才可以读到数 ...
 - STM32基础分析——USART的DMA模式
		
有关USART的DMA传输模式,其基本的概念和配置,网上有很多博客和教程都有,这里不再赘述,只是记录一下比较容易忽视而造成调试不通的问题. 1. 串口发送和接收分属两个DMA通道 一般方式操作串口时, ...
 - CC2540   低功耗串口, POWER_SAVING  模式 下  串口 0  的使用
		
低功耗 模式 下 使用 串口 , 因为 PM2 或者 PM3 状态下 32M晶振 是不工作 的,根据手册得知没有32M晶振, 串口是不能工作的,但是可以使用 外部中断,因此,我把 串口的接收引脚 ...
 - ASM:《X86汇编语言-从实模式到保护模式》越计卷:实模式下对DMA和Sound Blaster声卡的控制
		
说实话越计卷作者用了16页(我还是删过的),来讲怎么控制声卡,其实真正归纳起来就那么几点. ★PART1:直接存储访问 1. 总线控制设备(bus master) 在硬件技术不发达的早期,处理器是最重 ...
 - usb-host一步一步学(二)安卓在usb-host模式下列出当前连接的usb设备
		
之前写了一个简单的例子usb-host一步一步学(一)安卓在usb-host模式下列出当前连接的usb设备,下面的这个例子是获取各种usb设备.usb接口以及usb连接点(endpoint) 正如上一 ...
 
随机推荐
- js onclick=‘save()’ 和 onclick='return save()'
			
onclick="function()" 表示只会执行 function , 但是不会传回 function 中之回传值onclick = "return functio ...
 - ubuntu管理apt包的常用命令
			
安装 apt-get install nginx #安装 apt-get install nginx --reinstall #重新安装 删除 apt-get remove nginx #卸载 apt ...
 - hdu 3686 Traffic Real Time Query System  点双两通分量 + LCA。这题有重边!!!
			
http://acm.hdu.edu.cn/showproblem.php?pid=3686 我要把这题记录下来. 一直wa. 自己生成数据都是AC的.现在还是wa.留坑. 我感觉我现在倒下去床上就能 ...
 - jsp第一章 动态网页开发基础
			
动态网站可以实现交互功能,如用户注册.信息发布.产品展示.订单管理等等: 动态网页并不是独立存在于服务器的网页文件,而是浏览器发出请求时才反馈网页: 动态网页中包含有服务器端脚本,所以页面文件名常以a ...
 - Java之构造方法及this、super关键字
			
有关构造方法的理解: 需要对对象的数据进行初始化,则创建一个构造方法,此方法名字和类名一样,但是没有返回值(类型和具体的值都没,但是可以写return;).构造方法是用来创建对象的,所以是不能被对象调 ...
 - kafka客户端发布record(消息)
			
kafka客户端发布record(消息)到kafka集群. 新的生产者是线程安全的,在线程之间共享单个生产者实例,通常单例比多个实例要快. 一个简单的例子,使用producer发送一个有序的key/v ...
 - 解决 Cocos2d-x 3.2 error C1041: 无法打开程序数据库vc120.pdb
			
单个项目解决方案 解决方案是为项目添加 /FS (Force Synchronous PDB Writes) 编译选项,具体位置在: 一劳永逸的解决方案 直接修改cocos的项目模板templates ...
 - [转+补]Android打包so后魅族5中安装运行崩溃问题的解决方法
			
上周在做噪音检测so集成中,遇到不同的so库打包到 APK 时,安装在某些机器上,出现 java.lang.UnsatisfiedLinkError 加载失败. 为此,深究了一下原理,和给出了解决方案 ...
 - 解析没有key的Json
			
没有key的Json,例如:["http://www.cnblogs.com/Cherry-B/p/4625133.html","http://www.cnblogs.c ...
 - iOS 字符串处理笔记
			
iOS字符串处理笔记,包括如何使用正则表达式解析,NSScanner扫描,设置和使用CoreParse解析器来解析处理自定义符号等内容 搜索 在一个字符串中搜索子字符串 最灵活的方法 - (NSRan ...