首页 技术 正文
技术 2022年11月9日
0 收藏 702 点赞 2,105 浏览 9068 个字

  

  由于公司设备升级后出了问题,需要对USB驱动进行修改,原本使用的是寄存器模式进行UART传输,但是由于FX3寄存器模式会出现长时间延时等待的问题,不得不对其传输模式进行修改。虽然赛普拉斯的EZ-USB FX3系列芯片功能强大,成本适中,但共享资源太少,API参考手册里面的干货不多,直接导致开发困难,出现问题只能去官方社区寻找答案。新模式的开发也不是一帆风顺,找来找去,只有在固件库中找到了UartLpDmaMode这个例程还比较相似。于是便在其基础上进行修改。

  在UartLpDmaMode例程中,其数据流通方向是这样的:

Cypress EZ-USB FX3 DMA模式下的串口通讯

  只是从将接收到的数据进行了循环发送,这样一来,其生产者和消费者ID便很好设置,但是你无法对DMA通道进行直接操作,换句话说,你无法发送你想要发送的数据,也无法将你接收到的数据存入自己开辟的缓冲区中进行存储使用,当然这样并不是我想要的。

  我想要操作的数据传输是能够实现想传什么传什么,接收到的数据能想什么时候用就可以什么时候用。其数据流通就如同下图:

Cypress EZ-USB FX3 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将接收到的数据再发送给主机,如图:

Cypress EZ-USB FX3 DMA模式下的串口通讯

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

Cypress EZ-USB FX3 DMA模式下的串口通讯

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

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:8,958
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,482
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,328
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,111
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,743
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,777