USB3.0设计资源 cypress芯片程序解读 联系客服

发布时间 : 星期日 文章USB3.0设计资源 cypress芯片程序解读更新完毕开始阅读976088d680eb6294dd886c7d

最重要的时刻到来了,它就是创建DMA通道,这点与以前是不同的。 dmaCfg.size = size;

dmaCfg.count = CY_FX_BULKLP_DMA_BUF_COUNT; //=8 dmaCfg.prodSckId = CY_FX_EP_PRODUCER_SOCKET; //401 dmaCfg.consSckId = CY_FX_EP_CONSUMER_SOCKET; //301 dmaCfg.dmaMode = CY_U3P_DMA_MODE_BYTE;

dmaCfg.notification = 0; ///最大的区别 没有事件通知 dmaCfg.cb = NULL; ///最大的区别 没有回调 dmaCfg.prodHeader = 0; dmaCfg.prodFooter = 0; dmaCfg.consHeader = 0; dmaCfg.prodAvailCount = 0;

于是整个程序就读完了。

再读一个例子关于用DMA_MANUAL_IN DMA_MANUAL_OUT的例子。

这个例子说明USB端点数据源和数据沉机制用bulk stream。 这个例子用了两个USB的端点。

输出端点作为生产者,作为主机数据的沉---接收者。 一个输入端点作为数据的消费者,作为主机的源。 ---发送者。 每一个端点包含CY_FX_BULK_MAX_STREAMS这么多个的bulk streams的数目。对每一个streams,一个DMA_MANUAL_IN通道被创建在生产者USB sockets和CPU之间。一个DMA_MANUAL_OUT通道被创建在CPU和消费者sockets之间。

在IN的DMA缓冲区能道中,数据从主机接收通过生者端点。CPU被通知数据收到了(回调函数)。然后CPU丢失这个缓冲,这个引向一个沉的机制。

一个常数类型的数据被连续地装进每一个输出通道的DMA缓冲区,只要当缓冲区是空。CPU然后发一个允许DMA数据传输给消费者端点,通过它向主机发送数据。这引起了一个源机制。

Bulk streams这个方法仅仅在超速情况下是有效的。对别的速度,应用程序可以用单个的DMA_MANUAL_IN and DMA_MANUAL_OUT分别用于数据的沉和数据的源。 Stream ID

Stream id 1 被映射到socket 1. stream id 2 被映射到socket 2…..

此程序与前面程序的区别在于两个函数中,一个是创建DMA通道时不同,另一个是DMA的回调函数不同。先看创建通道时的情况,如果是超速,我们就用一个 glIsStreams=1 而这个在端口设置时,就看它是否是超速,如果是,则将这个流标志置为CY_FX_MAX_STREAMS

在下面的过程中,每一个流,都对应着每一个生产者的ID。即生产者似有好几个。例如流有8个,则生产者就有8个。就要产生8个DMA通道。而这8个DMA通道,其消费者ID却是一样的。其回调函数也是一样的,哪在回调函数中怎么知道是哪一个流引起的回调呢?暂不知。 接下来,要将流与socket对应起来。

If(stream!=0) apiRetStatus =

CyU3PUshMapStream(CY_FX_EP_PRODUCER,CyU3PDmaGetSckNum(dmaCfg.prodSckId),(stream+1)); 这样,每一个生产者的ID与socket的ID号就一一对应起来的。

可以,为什么一定要从stream!=0开始。等于0时该怎么办呀?还有这个函数有三个参数,第一个是0x01,第2个就是生产者的socket ID号,第3个就是流号。

13

最后要做的工作是将要发给PC机的数据用到的缓冲区全部填满,例如填成0x55aa之类。看它是如何取得缓冲区的地址的。

For (index=0;index<8;index++) ///每一个DMA通道,用到8个缓冲区,如果共有4个通道,则将用到32个缓冲区。在创造每个通道时,都会对应一个流号。即每一个流有32个缓冲区。所以每一个通道时都要将8个缓冲区置一下。

CyU3PDmaChannelGetBuffer(&glChHandleBulkSrc[stream],&buf_p,CYU3P_NO_WAIT); CyU3PMemSet(buf_p.buffer,CY_FX_BULKSTREAMS_PATTERN,buf_p.size); CyU3PDmaChannelCommitBuffer(&glChHandleBulkSrc[stream],buf_p.size,0); 第一个参数指的是DMA的通道号。 再调用这个

这个函数就是先将这个数据发到消费者上去再说。共发了8个缓冲区。 如果空了怎么办?它是如何管理空和满的? 看回调函数:

回调函数根据是生产者发出的通知还是消费者发出通知来进行处理。 如果是生产者通知,一个包已经来了,则调用抛弃这个包。

CyU3PDmaChannelDiscardBuffer(chHandle); 不过我们还有别的方法去处理吗?比如收下来?查API有一个函数GetBuffer如下面的合适但是未深入去看。 如果是消费者通知,则

CyU3PDmaChannelGetBuffer(chHandle,&buf_p,CYU3P_NO_WAIT); 先得到缓冲区的数据

对于消费者,实际上是无需得到缓冲区的数据的,这个函数的意义在于返回一个指针,可以让CPU可以填充它。不过在开始时我们已经填充完毕,故就不做什么事了。但是这个函数还是必须调用的。也许这个函数还附带了一些其它功能吧。

CyU3PDmaChannelcommitBuffer(chHandle,buf_p.size,0); 这是表示发送就可以了?

下面再看一下这个FLASH编程的例子:

上位机通过某种方式,将数据下发到下位机,下位机然后编程IIC或SPI接口。以后就可以选择这些作为BOOT而不是从主机下载方式。主机下载可以作为调试应用。

先看main()函数。

将配置使能IIC SPI UART。其它没有什么不同。

再看线程函数:线程函数中未作任何事务。也没有初始化。仅仅打开一个线程。 再看线程函数中的应用:首先将UART初始化一下。然后将FlashProgInit() 然后就每隔一秒打印一些版本号。这个FlashProgInit()看它做些什么?

先初始化IIC,带有一个参数0x40. 这个参数表示页长度 40表示的是64。它是DMA的长度。 它先设IIC的时钟频率为100KHz。这是一个库函数无法看细节。 它的数据传输是通过DMA来的,故先它对IIC进行配置。

配置中设好100KHz频率,再就是总线时间无限长,再是DMA的超时无限长,再就是将其设为DMA方式。 这样调用CyU3PI2cSetConfig(&CyU3PI2cConfig,NULL) 它也是一个库函数。第二个参数为NULL表示这是一个block挂起模式,它一直等完成而不用回调函数

接下来产生一个DMA调用。这里没有缓冲区需要,只是在重载模式。所以: dmaConfig.size = pageLen; damConfig.count = 0;

dma.dmaMode = CY_U3P_DMA_MODE_BYTE; dmaConfig.prodHeader = 0;

14

dmaConfig.prodFooter = 0; dmaConfig.consHeader = 0; dmaConfig.notification = 0; dmaConfig.cb = NULL;

dmaConfig.prodSckId = CY_U3P_CPU_SOCKET_PROD; dmaConfig.consSckId = CY_U3P_LPP_SOCKET_I2C_CONS;

status = CyU3PDmaChannelCreate(&glI2cTxHandle,CY_U3PDMA_TYPE_MANUAL_OUT,&DMAcONFIG); 同时将一个全局变量glI2cPageSize = pageLen; 这个变量有用的。

接下来就是初始化SPI了。与IIC基本上是完全一样的。不过SPI的页长度设定为256。然而SPI的参量有些不同,主要是增加了时钟的POL极性,SSNPOL片选极性,高位优先,相位PHA=1,时钟频率为8M。以字节长度读写(8)。

接下来是启动USB功能。这个API函数目的是使能USP并为其设置DMA。

接下来与上面解读的一样,是设置设置过程的回调函数和事件过程的回调函数。这个设置阶段的回调函数比较复杂。事件回调函数比较简单,就是在复位或断线时将DMA通道复位。 所以重点看设置时的回调函数:

设置函数带有两个参数,setupdat0,setupdat1. 先将这个包解开:

Attr = uint8 setupdat0&0xff; //属性 Rqt = uint8 (setupdat0&0xff00)>>8 //请求 Value =uint16 setupdat0>>16; //值 Index =uint16 setupdat1&0xffff; //索引 Length = uint16 setupdat1>>16; //长度

if( sttr&CY_U3P_USB_TYPE_MASK!=CY_U3P_USB_VENDOR_RAT)

return FALSE; ///如果不是VENDOR请求,则返回假—意连云港着由驱动缺省处理 ////所以证明这是一个vendor设置请求 {

到底有多少页,如果不能整除,则页数要加1。因为只能一页一页的读。

打印一个信息,我们将开始访问地址为??的设备,字节地址为,字节数为,总共??页 尽管用不到DMA的缓冲,但是我们还是用到了这个结构:

CyU3PDmaBuffer_t 并将它内部的*buffer指向我们用到的4096字节的缓冲区。

Buffer_p.buffer = buffer;

case CY_FX_RQT_ID_CHECK: ///如果是看软件版本号,则直接写回去。 CyU3PUsbSendEP0Data(8,(uint8*)glFirmareID); break;

case CY_FX_RQT_I2C_EEPROM_WRITE:

i2cAddr = 0xA0|(value&0x0007)<<1; ///芯片地址放在value中

status = CyU3UsbGetEP0Data(length,glEp0Buffer,NULL); ///从EP0得到很长的数据 case CY_FX_RQT_I2C_EEPROM_READ: i2cAddr = 0xA0 |(value&0x07)<<1;

CyU3PMemSet(glEp0Buffer,0,sizeof(glEp0Buffer));//将接收缓冲全部清零

Status = CyFxFlashProgI2cTransfer(index,i2cAddr,length,glEp0Buffer,CyTrue); 索引,地址,长度缓冲区 这是一个小复杂的程序,其中最未一个参数指的是读还是写如果读则为真。 Switch(rqt)

15

{

While(pageCount!=0)

If(isRead) ////如果是读操作 preamble.length = 4;

preamble.buffer[0] = devAddr; preamble.buffer[1] = byteAddress>>8; preamble.buffer[2] = byteAddress&0xff; preamble.buffer[3] = devAddr|0x01; preamble.ctrlMask = 0x0004; buf_p.size =glI2cPageSize; buf_p.count = glI2cPageSize;

status = CyU3PI2cSendCommand(&preamble,glI2cPageSize,isRead); status = CyU3PDmaChannelSetupRecvBuffer(&glI2cRxHandle,&buf_p);

status = CyU3PDmaChannelWaitForCompletion(&glI2cRxHandle,CY_FX_FLASH_PROG_TIMEOUT); else{ ///这是写的情形,就不写了 。。。。。。。。 } }

byteAddress +=glI2cPageSize; buf_p.buffer +=glI2cPageSize; gageCount --; Sleep(10);

粗略地看,这个例子是在SETUP阶段与下位机进行一些对话,从而得到I2C和SPI的读写,擦除动作。 现在我们要做的是接收上位机的指定,进行设置。然后上位机就通过一个端口读图象数据,而下位机则从GPIF-II端口往某一端口通过DMA读数据。作一片FPGA,使之以某种方式往GPIF中写数据。通过设一个DMA通道,往IN端口发送数据。

这与同步GPIF 的例子有点象,但是发下来的数据,下位机CPU要读取的。读总是通过DMA进行的。只是对于CPU的读,采用的方式可能就不是自动而是manual_in。

再看一个SPI读写的例子,它是主程序命令从SPI中读写一些数据。 SPI传输子程序看一下: 页地址,字节计数,缓冲区,读写标志 因为只能一页一页的读或写,故读写总是从页地址开始的

CyFxSpiTransfer(uint16_t,pageAddress,uint16_t bytecount,uint8_t *buffer,Cyboot_t isRead) {

CyU3PDmaBuffer_t buf_p; Uint8_t location[4]; Uint32_t byteAddress=0;

Uint16_t pageCount=byteCount/glSpiPageSize; CyU3PReturnStatus_t status=CY_U3P_SUCESS;

If(byteCount ==0

Return CY_U3P_SUCESS;

If(byteCount%glSpiPageSize!=0)

pageCount++; ///如果除不尽,则按多一页来读写 buf_p.buffer = buffer;

16