Cyusb3014芯片原理之二固件代码
1.固件程序代码组成
cyfx_gcc_stratup.s 该文件存放USB3.0数据采集模块ARM-9核心处理器启动代码的汇编源文件。
cyfxgpif2config.h GPIF波形描述符,由GPIF Designer生成,可直接导入工程中,实现对GPIFII接口的控制。GPIF II Designer的工程是后缀为.cyfx,编译会生成.h文件,该.h文件本质上是保存的所有有关GPIF II的寄存器的配置,然后在固件工程中包含,与其他文件一起发挥作用。
cyfxtx.c 在该文件中提供了由Cypress封装的库函数,该类函数可以由开发者直接使用。
cyfxslfifosync.c 该文件实现了固件程序的主要功能,在该文件中实现线程的建立,对回调函数的处理,DMA通道的建立,控制传输的实现,对GPIFII的状态机加载等功能。程序入口main函数即在这个文件中。
cyfxslfifosync.h 对全局变量的定义以及对 cyfxbulklpauto.c中使用到的函数的声明。
cyfxbulklpdscr.c 在该文件中对USB设备描述符,例如配置描述符字符串描述符等进行了定义。 请查看描述符的描述章节查看详细说明。
2.固件程序代码流程(cyfxslfifosync.c)
1.固件入口 CyU3PFirmware Entry()
//这个是固件程序的入口,封装成库函数,用户不可见。
//初始化高速缓存,初始化存储器管理单元,初始化中断堆栈。
//在函数结尾,进入工具链函数。
2.工具链初始化 CyU3PToolChainInit()
//这个是工具链的初始化函数
//清理内存区域BSS段
//将程序跳转到固件的main()中
3.main()
//完成系统时钟,系统缓存,端口配置功能
3.1 对时钟配置
CyU3PSysClockConfig_t clkCfg;
//系统时钟配置 CPU、DMA、时钟源
//要求GPIF接口运行在32bit总线&100MHz时钟时应该使能让主设备大 于400MHz
CyU3PDeviceInit (&clkCfg);
//调用函数下发时钟配置
3.2 对设备缓存配置
CyU3PDeviceCacheControl (CyTrue, CyFalse, CyFalse);
//调用函数下发缓存的配置
//不使能数据缓存区(2),只使能指令缓存区(1)
3.3 对芯片接口管脚配置
CyU3PIoMatrixConfig_t io_cfg;
//使能串口,不使能I2C,SPI,I2S,S0MOde不使能,设置数据总线位宽(结合宏定义的配置)
CyU3PDeviceConfigureIOMatrix (&io_cfg);
//调用函数下发IO复用的配置
//The FX3/FX3S devices have upto 61 IO pins that can be configured to function in a variety of modes.
3.4 进入实时操作系统
CyU3PKernelEntry ();
//初始化 RTOS系统,进入实时操作系统
4.调用线程创建函数 CyFxApplicationDefine()
//This function is called by the FX3 RTOS once all of the OS and driver initialization is completed. The RTOS objects and threads required by the application can be created in this function.
//线程创建函数在实时操作系统上创建一个线程,在该线程中定义了线程入口函数,程序进入该入口函数后可对串口进行初始化以及进入应用代码执行数据传输等工作。
//线程创建函数,线程的入口函数的定义、线程堆栈尺寸大小的分配、线程优先级的定义(8)
4.1 堆栈内存分配
CyU3PMemAlloc (CY_FX_SLFIFO_THREAD_STACK);
#define CY_FX_SLFIFO_THREAD_STACK (0x0400)
//堆栈大小默认为 0x0400
4.2 线程创建
CyU3PThreadCreate(…)
“21:Slave_FIFO_sync” //线程ID 线程名
#define CY_FX_SLFIFO_THREAD_PRIORITY (8) //其中优先级为8
#define CY_FX_SLFIFO_THREAD_STACK (0x0400)//堆栈默认大小
SlFifoAppThread_Entry //线程入口函数
5.进入线程的入口函数 SlFifoAppThread_Entry()
5.1 CyFxSlFifoApplnDebugInit();//调用初始化调试模块----关于串口的初始化
CyU3PUartInit(); //调用串口的初始化函数
CyU3PUartConfig_t uartConfig; //串口参数配置 波特率、停止位、校验位; 使能串口使用管脚;开启DMA模式
CyU3PUartSetConfig (&uartConfig, NULL); //下发串口配置
CyU3PUartTxSetBlockXfer (0xFFFFFFFF); //设置串口的最大发送值为无穷大
CyU3PDebugInit (CY_U3P_LPP_SOCKET_UART_CONS, 8); //完成初始化配置 套接字和优先级
5.2 CyFxSlFifoApplnInit(); //调用初始化GPIF接口和初始化USB接口函数
5.2的第一部分 配置GPIF接口!
5.2.1CyU3PPibInit(CyTrue, &pibClock);
//使能PIB模块时钟,应在最前面
//参数1 是否初始化选择是 参数2 PIB模块时钟的具体配置
CyU3PPibClock_t pibClock; //PIB模块时钟配置结构体
pibClock.clkSrc = CY_U3P_SYS_CLK;//时钟源
pibClock.isDllEnable = CyFalse; //disable PLL
5.2.2 CyU3PGpifLoad (&CyFxGpifConfig);
//将GPIF配置参数写入GPIF寄存器
//这个结构体是从 GPIFII Designer工具生成的头文件中传值过来的
//const CyU3PGpifConfig_t CyFxGpifConfig
//This structure holds all the configuration inputs for the GPIF II
5.2.3CyU3PGpifSocketConfigure(0,CY_U3P_PIB_SOCKET_0,6,CyFalse,1) //配置线程与套接字的映射
//参数1 线程ID 参数2 套接字编号 参数3 4字节的水印值 参数4 如果是false,标志将会被置位当套接字小于水印值的时候
//参数4 Whether the partial flag should be set when the socket contains more data than the watermark
//参数5 burst大小The burst size is the minimum number of words of data that will be sourced/sinked across the GPIF interface without further updates of the GPIF DMA flags. The device connected to FX3 is expected to complete a burst that it has started regardless of any flag changes in between. Please note that this has to be set to a non-zero value (burst size is greater than one), when the GPIF is being configured with a 32-bit data bus and functioning at 100 MHz. /
5.2.4 CyU3PGpifSMStart (RESET, ALPHA_RESET);//打开GPIF状态机
//这个参数都是从tools生成的地方传递过来的 这是最开始的地方
5.2的第二部分 配置了一个IO管脚!
这中间配置了一个GPIO59管脚
/ Update the status flag. / 更新状态标志
glIsApplnActive = CyTrue;
CyU3PGpioSetValue (59, CyFalse);
5.2.6 CyU3PGpioInit(&gpioClock, NULL); //调用函数下发GPIO时钟配置
CyU3PGpioSetSimpleConfig(59, &gpioConfig);//Configure GPIO 59 as output//调用函数下发59管脚的IO配置
5.2的第三部分 配置USB接口!
5.2.7 CyU3PUsbStart(); //调用USB Start函数 启动USB设备模式驱动程序 创建控制传输的DMA通道 这是一个库函数
5.2.8CyU3PUsbRegisterSetupCallback(CyFxSlFifoApplnUSBSetupCB,CyTrue);
//参数2 选择true选择了fast enum模式(所有的枚举阶段由库函数来完成,除了class和vendor请求)
//参数1 指定了响应class和vendor请求的回调函数
CyFxSlFifoApplnUSBSetupCB //该回调函数用来响应主机请求,
//其中对于clear的回应中清空了缓存 并且复位端点和复位dma通道
5.2.9 CyU3PUsbRegisterEventCallback(CyFxSlFifoApplnUSBEventCB);
//指定了一个用来响应USB 事件的回调函数
当发生 Set_Config请求时,将会开启call back模式 即开始调用CyFxSlFifoApplnUSBEventCB函数
6.CyFxSlFifoApplnUSBEventCB //USB事件处理回调函数
//无论是哪一种模式(回送,流),只要当Set_Config事件有主机触发的时候,就会进入该函数的调用
//在这个调用中,一定会执行到,CyFxSlFifoApplnStart ();。
7.CyFxSlFifoApplnStart ();这是应用程序,完成端点的配置,DMA通道的建立
7.1根据总线速度设置来确定端点数据包长度
CyU3PUSBSpeed_t usbSpeed = CyU3PUsbGetSpeed();
switch (usbSpeed)
case CY_U3P_SUPER_SPEED:
size = 1024;
7.2配置端点号与端点类型及其他端点属性的映射
CyU3PEpConfig_t epCfg;
CyU3PSetEpConfig(CY_FX_EP_PRODUCER, &epCfg); //下发生产者端点配置
7.3创建DMA通道
CyU3PDmaChannelConfig_t dmaCfg;
//DMA缓冲区的大小,取决于速度模式,161024Bdeaf
dmaCfg.size = DMA_BUF_SIZE* size;
//DMA缓冲区的个数
dmaCfg.count = CY_FX_SLFIFO_DMA_BUF_COUNT_U_2_P;
#define CY_FX_SLFIFO_DMA_BUF_COUNT_U_2_P (2)
//DMA通道两端套接字映射
dmaCfg.prodSckId = CY_FX_PRODUCER_USB_SOCKET;
dmaCfg.consSckId = CY_FX_CONSUMER_PPORT_SOCKET;
//DMA传输模式设置
dmaCfg.dmaMode = CY_U3P_DMA_MODE_BYTE;
//下发DMA通道配置,返回一个句柄 建立了套接字经缓冲区到套接字的映射。
CyU3PDmaChannelCreate(&glChHandleSlFifoUtoP,CY_U3P_DMA_TYPE_AUTO, &dmaCfg);
7.4创建DMA通道完成之后,立即清空端点缓存
/* Flush the Endpoint memory /
CyU3PUsbFlushEp(CY_FX_EP_PRODUCER);
7.5设置DMA通道的
/ Set DMA channel transfer size. /
apiRetStatus = CyU3PDmaChannelSetXfer (&glChHandleSlFifoUtoP, CY_FX_SLFIFO_DMA_TX_SIZE);
7.6更新应用启动的状态,供外设控制器使用
/ Update the status flag. */
glIsApplnActive = CyTrue;
CyU3PGpioSetValue (59, CyFalse);
8.如果创建的是DMA MANUAL通道,可以让CPU去管理两个端口的数据发送,并且可以从回调函数中向CPU发送已经传递的数据,进行必要的处理。
3.基于SlaveFifo的程序修改
本节说明的是,创建自定义的应用时需要关注的部分。请与上一篇文章的配置部分结合的看。
1.注意系统时钟的配置
CyU3PSysClockConfig_t clkCfg; //Loc:main()
//GPIF接口运行在32bit总线&100MHz时钟时应该使能让主设备大于400MHz
//即 clkCfg.setSysClk400 = CyTrue; /* FX3 device’s master clock is set to a frequency > 400 MHz
2.设置GPIF接口数据总线位宽
CyU3PIoMatrixConfig_t io_cfg; //Loc:main()
#define CY_FX_SLFIFO_GPIF_16_32BIT_CONF_SELECT (1) //Loc:.h
//对于应用者而言,这个宏定义为1的时候,即数据总线位宽为32位,定义为 0的时候,位宽为16
//对于实际的程序,其实设置结构体属性为io_cfg.isDQ32Bit = CyTrue;&io_cfg.lppMode = CY_U3P_IO_MATRIX_LPP_DEFAULT;
3.设置线程与套接字的映射、水印值以及burst的大小
CyU3PGpifSocketConfigure (0,CY_U3P_PIB_SOCKET_0,6,CyFalse,1);//Loc:CyFxSlFifoApplnInit();
//参数1 线程ID 参数2 套接字编号 参数3 4字节的水印值 参数4 如果是false,标志将会被置位当套接字小于水印值的时候
//参数4 Whether the partial flag should be set when the socket contains more data than the watermark
//参数5 burst大小,需要研究下结论!
4.设置端点(端点号与端点属性的映射)
//类型epCfg.epType = CY_U3P_USB_EP_BULK;//Loc:CyFxSlFifoApplnStart
//使能epCfg.enable = CyTrue;
//突发长度大小,待理解 epCfg.burstLen = 1;
//流数 epCfg.streams = 0;
//同步数据包epCfg.pcktSize = size;
CyU3PSetEpConfig(CY_FX_EP_PRODUCER, &epCfg); //下发生产者端点配置 定义了端点号对应的端点类型
CyU3PSetEpConfig(CY_FX_EP_CONSUMER, &epCfg);//下发消费者端点配置
5.工作模式的选择 //Loc:.h
#define LOOPBACK_SHRT_ZLP
//#define STREAM_IN_OUT
或者
//#define LOOPBACK_SHRT_ZLP
#define STREAM_IN_OUT
6.配置DMA通道相关参数 //Loc:
6.1自动与手动
//不要定义这个宏就是自动 //#define MANUAL
6.2配置缓冲区的个数
6.3配置缓冲区的大小
6.4配置缓冲区的方向(根据consumer还是producer来确定)
6.5设置DMA最大的传输字节为无穷大
7.dscr.c中
7.1接口描述符中。修改除了0端点 之外的端点个数值
0x02, /* Number of end points 除了0端点之外的端点个数*/
7.2端点描述符中。端点号对应的端点属性
7.3版本号,目前bulk用的是3.0版本,iso用的是3.1版本
7.4同步传输模式中,要使用两个备用接口配置,还有要修改PID,不同的PID就使用不同的驱动。