USB3.0设计资源 - cypress芯片程序解读 2

2026/1/22 3:45:12

在开发板上,由于53:56脚被连接到UART,这意味着我们要么选择DQ32模式,要么选择LppMode. 不然UART就没办法用了。Lpp模式好象是GPIO+UART模式,见datasheet 33页。 几个参数 用UART,不用IIC 不用IIS,不用SPI。没有GPIO使用到(简单复杂都没有)。 然后就是设置配置了。

最后进入到内核。不返回。结束主程序。

内核于是调用某一个函数,也就是CyFxApplicationDefine(void)。程序就从此开始了。 问:

1程序是如何下载到USB中去的。要怎么做。例如将这个编译好的代码放到什么目录里还是怎么办,还是启动时,安装driver时,自动下载,这个下载的东西是个什么文件格式?该放在哪里?不明白 2.难道GPIF口上没接任何东西, 如何将PC机发下来的数据发回到PC机上去? 生产者:USB的OUT接口1,向GPIF发送一批数据

消费者:GPIF向IN接口81,由它消费掉一批数据。然后通过IN发回PC机。

再看一个简单一点的GPIO的例子

1先是一个错误处理的函数,我们不需要它,故这是一个死循环。

2 CyFxDebugInit 这个函数,将串口作为调试口用 115200bps

3 void CyFxGpioIntrCb (

uint8_t gpioId /* Indicates the pin that triggered the interrupt */ )

这个函数是一个中断回调函数。必须在某个地方注册一下。

它有下列过程:apiRetStatus =CyU3PGpioGetValue(gpioID,&gpioValue); //这个函数得到某个端口中断的值 这个gpioValue是一个BOOL值。而ID则是某一个端口的端口号。这个函数只能返回一个引脚。 等会看这个ID是什么指定的。

CyU3PEventSet(&glFxGpioAppEvent,

CY_FX_GPIOAPP_GPIO_HIGH_EVENT,CYU3P_EVENT_OR);

如果为高,则设置一个事件。是一个高事件发生。注意到事件是一个全局变量,而这个事件中有许多参数,其中比较重要的是一个回调函数。应该在某个地方将这个事件与一个回调函数联系起来。一会要补充这里

5. Void CyFxGpioInit (void)

apiRetStatus = CyU3PGpioInit(&gpioClock,CyFxGpioIntrCB); 这个函数是设定gpio的时钟,以及中断的回调函数。这与4中部分形成对照。 然后将gpio45定义为输入且允许中断

gpioConfig.intrMode = CY_U3P_GPIO_INTR_BOTH_EDGE;

apiRetStatus = CyU3PGpioSetSimpleConfig(45, &gpioConfig);

GPIO的21脚本来作为GPIF的控制信号的。不能用CyU3PDeviceConfigureIOMatrix来将它作为GPIF IOs. 这个过载API调用必须进行必须小心当改变这个引脚的功能时。如果IO脚作为GPIF的一部分连到外部设备上。则它不能再作为GPIF IO使用。在这里CTL4是不使用的,所以用它用IO脚是安全的。

apiRetStatus = CyU3PDeviceGpioOverride(21,CyTrue); 接下来apiRetStatus = CyU3PGpioSetSimpleConfig(21,&gpioConfig);

6 接下来有两个线程,一个是输出线程,一个是输入线程,先看输出线程:

5

apiRetStatus = CyFxDebugInit(); ////初始化调试模式。这个在2中定义的。 CyFxGpioInit();这个也在前面5定义过。后面是一个闪灯程序。 apiRetStatus = CyU3PGpioSetValue(21,true); 将输出置为高。 延时2秒,将输出变为低。 延进2秒。

7 下面再来看输入线程:是一个循环,等事件发生。

txApiRetStatus = CyU3PEventGet (&glFxGpioAppEvent,

(CY_FX_GPIOAPP_GPIO_HIGH_EVENT | CY_FX_GPIOAPP_GPIO_LOW_EVENT), CYU3P_EVENT_OR_CLEAR, &eventFlag, CYU3P_WAIT_FOREVER);

这里表示永远等下去。等到后要清除事件,另返回事件的标志,这个标志我们没有用。如果等到高的标志,就打印一个引脚为高,如果为低,就打印一个引脚为低的标志。估计这个等事件标志将被block.

这样整个过程清楚了,IO脚触发引起一个中断。这个中断回调函数中将触发一个事件。在这个线程中将等事件发生,如果发生了,就打印出引脚的状态。

事件在什么地方初始化呢?还是不需要初始化?

8 果然,事件是要初始化的。在应用程序中初始化了,下面就看这个应用程序 先创建一个输出线程。 再创建一个输入线程

然后 retThrdCreate = CyU3EventCreate(&glFxGpioAppEvent); 9 最后看一下main()

Main()中主要是将GPIO引脚初始化一下。

io_cfg.gpioSimpleEn[0] = 0;

io_cfg.gpioSimpleEn[1] = 0x00002000; /* GPIO 45 */ io_cfg.gpioComplexEn[0] = 0; io_cfg.gpioComplexEn[1] = 0;

45引脚为什么对应的是0x2000. 这是因为它是32位的,45引脚=32+13 这个D13位正好是0X2000

从main开始看起:

再看一下几个定义:输出线程,输入线程及事件在文件一开始就定义了。

CyU3PThread gpioOutputThread; /* GPIO thread structure */ CyU3PThread gpioInputThread; /* GPIO thread structure */ CyU3PEvent glFxGpioAppEvent; /* GPIO input event group. */

它主要是调用了一个串口设置函数,然后就进入到cache控制设置,再后来就是设置一个IO脚,45脚使之使能。并且选用配置模式(即LPP模式)。允许了UART,不允许IIC,IIS,SPI,另外isDQ32bit也不允许。这个表示它不支持GPIF的32位模式。

然后我们再看应用程序启动,这是由系统自动调用的。我们可能修改它的内容,但是它是必须的。 这个函数中,它创建了两个线程。一个是输入线程,一个是输出线程。

另外,容易遗忘的一件事是它创建了一个事件。事件的创建只要这样就可以了: retThrdCreate = Cy3U3PEventCreate(&glFxGpioAppEvent);

再往上,就是输入线程了。这个线程看输入引脚的变化,而这个变化由中断回调函数引起,中断回调函数中,它会产生一个事件,而我们的线程就监视这个事件。如果有事件高发生,就串口打印一个引脚高,如

6

果低,就打印一个引脚低。看它是如何实现的: txApiRetStatus = CyU3PEventGet(&glFxGpioAppEvent,

(CY_FX_GPIOAPPP_GPIO_HIGH_EVENT|CY_FX_GPIOAPP_GPIO_LOW_EVENT), CYU3P_EVENT_OR_CLEAR,&eventFlag,CYU3P_WAIT_FOREVER);

这是个等事件的函数,这个函数无法找到它的定义,它是一个API函数。我们找API,发现它的参数含义。 这里有一个CYU3P_EVENT_OR_CLEAR表示只要上面有一个位被设置就返回且清除标志。----OR。 而真正的事件就放在标志中返回了。

既然有读事件,就必有设置事件,事件的设置应该在中断回调中实现。而中断回调的注册,应该在初始化时实现。下面应该可以很快看到这点。---事实上,在下面的输出线程中就实现了注册

输出线程实现,输出线程比较有意思的是其DebugInit()居然是在它中间实现的。这有点不合常理。 而接下来,它又调用了初始化GpioInit()这个函数。在这个函数中,先初始化GPIO,这个GPIO居然还要将时钟也设置一下,有点不合常理。在这个初始化中,它还指明了GPIO中断回调函数的注册。尽管这个中断函数应该是在输入线程中注册似更合理一些。接下来,45脚要用之为输入,所以要将配置设一下:

gpioConfig.outValue = CyTrue; //输出为高 因为是输入,要将它设为高 gpioConfig.inputEn = CyTrue; //输入使能

gpioConfig.driveLowEn = CyFalse; //不要驱动低也不要驱动高 gpioConfig.driveHighEn = CyFalse;

gpioConfig.intrMode = CY_U3P_GPIO_INTR_BOTH_EDGE; //允许中断 apiRetStatus = CyU3PGpioSetSimpleConfig(45, &gpioConfig);

如此这般配置了45脚。

接下来,要配置21脚,因为21脚比较特殊本来是用于GPIF的CTRL4的。现在要使用它就要重载一下: 这样的IO脚是不可以象在主程序中哪样,将它直接设为输出的,而是要先重载。 同样,看输出脚是如何定义的

gpioConfig.outValue = CyFalse; ///低电平 gpioConfig.driveLowEn = CyTrue; //允许低输出 gpioConfig.driveHighEn = CyTrue; ///允许高输出

gpioConfig.inputEn = CyFalse; //方向设为输出,(假的输入就是输出) gpioConfig.intrMode = CY_U3P_GPIO_NO_INTR; //不用中断

再看一下回调函数,如何实现它的:

当引脚有跳变时,这个函数被调用。首先,它得到引脚的值。这个回调函数是带参数的。当它发生时,会带过来一个参数。表明是哪一个引脚触发了这个事件。这在库函数中可能已经处理了,提供给用户程序就不用麻烦再去看原因了。我想可能有一个机制,即有一个中断状态寄存器,表示是哪一个引脚变化了。 在这里调用了一个函数:CyU3PGpioGetValue(gpioId,&gpioValue); 注意到这个值是一个BOOL型的。 然后根据情况来设置事件:

CyU3PEventSet(&glFxGpioAppEvent,CY_FX_GPIOAPP_GPIO_HIGH_EVENT,CYU3P_EVENT_OR); 我们看,其中有要设置的事件指针,有什么事件,以什么方式设置,它是以OR的方式设置的。这个OR表示的是将这个第2个参数与当前的事件标志进行或。显然,如果相或的话,则事件标志将被置1,而如果与则完全不同,它没效果。

(在得到事件中,有一个AND表示全部标志都符合才生成事件,所以也是用OR的,不然,不可能全部符合的,永远不会发生事件了,因为不可能既变高又变低的)

至此整个程序解读完了。在这个例子中,似乎没用到USB有关的部分。

7

有了这个基础后,再看一下原来syncFifo的文档。方法同样从后向前看。 先看main()

1 main基本上没有什么变化,除了不用配置45脚之外。 2再看应用程序启动部分,只创建了一个线程。

3再看在这个线程中做什么事,事实上,它就是每秒钟打一些串口信息,接收了多少包,发送了多少包。不过在开始时,它增加了2个初始化设置,第一个初始化设置设置了串口,第2个初始化,是一个非常关键的初始化,它设置了GPIF口和USB接口。

pibClock.clkDiv = 2; ///除2 pibClock.clkSrc = CY_U3P_SYS_CLK; //用系统时钟 pibClock.isHalfDiv = CyFalse; ///半倍数除不用 /* Disable DLL for sync GPIF */

pibClock.isDllEnable = CyFalse; ///DLL不用,为什么不知道? apiRetStatus = CyU3PPibInit(CyTrue, &pibClock); ///PP初始化

//下面这个函数将GPIF的配置初始化一下,这个配置字是预先定制好的,我们不管它内容 apiRetStatus = CyU3PGpifLoad(&Sync_Slave_Fifo_2Bit_CyFxGpifConfig);

再下面就是启动状态机,至此,GPIF设置完成。

后面要启动USB配置了。这个函数的目的是为USB配置一个DMA通道,也就是启动driver.

USB的SETUP过程我们不干预,故注册这个SETUP回调函数尽管在程序中也注册了,但是却直接返回一个FALSE,故其实质是交给主程序去处理去。什么事也不做。

USB的事件处理我们就要干预了。所以我们先注册它,然后,在这个注册的回调函数中,进行干预。看这个回调函数,发现在配置事件中进行了处理,另一个是在断开连接及复位时进行了处理。 配置事件中做了如下处理:

先取得USB的速度,由于USB已经启动到配置这一步,故其与PC沟通后速度信息已经知道了,所以它是可以得到的。得到速度的目的是为了想得到DMA的尺寸,即1024字节。也就是buffer的尺寸。 我们在这里,要得到生产者和消费者的端点配置。

但是这个配置如何与PC打交道,我们是不知道的。是在这个库函数中就进行或者是另有一个机制不清楚。 然后要为U TO P 产生一个DMA通道。 U作为生产者,P作为消费者。 dmaCfg.size = size; ///大小

dmaCfg.count = CY_FX_SLFIFO_DMA_BUF_COUNT; ///2个DMA缓冲就可以了 dmaCfg.prodSckId = CY_FX_PRODUCER_USB_SOCKET; ///生产者的ID号 dmaCfg.consSckId = CY_FX_CONSUMER_PPORT_SOCKET; ///消费者的ID号 dmaCfg.dmaMode = CY_U3P_DMA_MODE_BYTE; ///按字节计算的 /* Enabling the callback for produce event. */

dmaCfg.notification = CY_U3P_DMA_CB_PROD_EVENT; // 产生通知 dmaCfg.cb = CyFxSlFifoUtoPDmaCallback; //回调函数的定义 dmaCfg.prodHeader = 0; //头没用 dmaCfg.prodFooter = 0; //尾没用 dmaCfg.consHeader = 0; //

dmaCfg.prodAvailCount = 0; //等到多少个缓冲区空才。。 apiRetStatus = CyU3PDmaChannelCreate (&glChHandleSlFifoUtoP, CY_U3P_DMA_TYPE_MANUAL, &dmaCfg);

然后再产生另一个DMA通道。这个通道与上一个基本相同。除了ID号和回调函数不一样之外。

8


USB3.0设计资源 - cypress芯片程序解读 2.doc 将本文的Word文档下载到电脑
搜索更多关于: USB3.0设计资源 - cypress芯片程序解读 2 的文档
相关推荐
相关阅读
× 游客快捷下载通道(下载后可以自由复制和排版)

下载本文档需要支付 10

支付方式:

开通VIP包月会员 特价:29元/月

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信:xuecool-com QQ:370150219