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) 正如上一 ...
随机推荐
- Hungary Algorithm国外板子
Codeforces 1107一题除了dp做法还有二分带权匹配O(n^3)做法,国外网友的板子时间非常优秀,但矩阵设定的事情并不是很懂-- //Codeforces 1107F const int m ...
- ssrs 里 表头 分页后显示
1. 列组,箭头,高级 2.点击行组,静态 3. 设置静态行组 属性
- 转 shell模拟数据库的读写
0.create table create table myTestTable as select rownum as id, to_char(sysdate + rown ...
- PARTITION RANGE ALL 的优化
建议如下: 检查数据库的cpu 消耗 ,Sql_id :***** 消耗过多资源,这个新上线sql, 20号才上线,是对log 进行分析,平均每次执行时间300s.,使用的是PARTITION RAN ...
- dubbo属性配置
一.覆盖策略 JVM启动-D参数优先,这样可以使用户在部署和启动时进行参数重写,比如在启动时需改变协议的端口.XML次之,如果在XML中有配置,则dubbo.properties中的相应配置项无效.P ...
- 2013上半年中国CRM市场分析报告
经过了十多年的风风雨雨,CRM度过了漫长的市场培育期,即将迎来成熟期.目前这一阶段也是CRM惨烈搏杀的一个阶段,据不完全统计,国内大大小小的CRM厂商已经超过600家,各厂商几度火拼,努力扩大自己在C ...
- uvm_driver——老司机带带我
文件:src/comps/uvm_driver.svh类: uvm_driver uvm_driver继承(C++中叫继承)自uvm_component,其中定义了两个Ports:seq_item_p ...
- apache下设置域名多站点访问及禁止apache访问80端口
apache下设置域名多站点访问 当前系统:macOS High Sierra 域名访问配置指定端口后,不同域名只能配置不同的端口 apache配置目录: sudo vim /etc/apache2/ ...
- MySQL字符集和排序介绍
客服端字符集: character_set_client utf8mb4连接字符集: character_set_connection utf8mb4数据库字符集: character_set_dat ...
- hihoCoder #1080 : 更为复杂的买卖房屋姿势 (线段树,多tag)
题意: 有编号为0~n的n+1个房屋,给出每个房屋的起始价格,随后给出m种修改,每次修改都要进行输出所有房屋的价格总和.修改有两种方式:(1)政府调控,编号L~R全置为同一价格(0)房屋自行涨跌,编号 ...