一个USB3.0的固件运行的过程大致如下面的图所示
首先是Firmware Entry
FX3的切入点是CyU3PFirmwareEntry()这个函数,这个函数定义在了FX3的API 库里面的,而且对用户是不可见的!这个函数规定了程序的入口,
这个入口函数做了以下的几个工作:
1:禁用Cache,说是为了Bootload。具体不知道cypress是怎么弄的了!
2:初始化MMU和CACHE
3:初始化FIQ(快速中断)、IRQ(普通中断)、SYS(系统模式)、SVC(管理模式)的栈。
4:执行完毕是去调用CyU3PToolChainInit()函数。
其次就是Tool Chain 初始化
CyU3PToolChainInit: # clear the BSS area __main: mov R0, #0 ldr R1, =_bss_start ldr R2, =_bss_end 1:cmp R1, R2 strlo R0, [R1], #4 blo 1b b main
代码如上可以看出来代码里面就做了两个工作
1:清理BSS段
2:将程序跳转到main()
接下来就是Device Initialization设备初始化
下面进行的就是main函数里面的操作了
分三步
1:首先是调用CyU3PDeviceInit (NULL);这个函数,
这个函数做了三个操作:
a:配置主时钟,传递的参数是NULL说明CLOCK是默认的形式配置好的!
b:VIC外设部件的中断管理模块初始化
c: 配置GCTL和 PLLs
2;配置cache使用CyU3PDeviceCacheControl (CyTrue, CyFalse, CyFalse);
这个FX3设备有8K的数据cache,还有8K指令cache。上面的代码说明数据cache没有打开,指令cache打开了!一般在有大数据处理的时候才会打开数据cache,如果是简单的处理打开了cache可能会降低整个系统的效率!
3.一些外部设备的管脚使能
io_cfg.useUart = CyTrue; io_cfg.useI2C = CyFalse; io_cfg.useI2S = CyFalse; io_cfg.useSpi = CyFalse; #if (CY_FX_SLFIFO_GPIF_16_32BIT_CONF_SELECT == 0) io_cfg.isDQ32Bit = CyFalse; io_cfg.lppMode = CY_U3P_IO_MATRIX_LPP_UART_ONLY; #else io_cfg.isDQ32Bit = CyTrue; io_cfg.lppMode = CY_U3P_IO_MATRIX_LPP_DEFAULT; #endif io_cfg.gpioSimpleEn[0] = 0; io_cfg.gpioSimpleEn[1] = 0; io_cfg.gpioComplexEn[0] = 0; io_cfg.gpioComplexEn[1] = 0; status = CyU3PDeviceConfigureIOMatrix (&io_cfg); if (status != CY_U3P_SUCCESS) { goto handle_fatal_error; }
4:俗称召唤OS,听着挺吓人呵呵,通过调用CyU3PKernelEntry()
主要做的事情是初始化OS
下一步是OS Timer
然后是应用程序的定义
ptr = CyU3PMemAlloc (CY_FX_SLFIFO_THREAD_STACK); retThrdCreate = CyU3PThreadCreate (&slFifoAppThread, "21:Slave_FIFO_sync", SlFifoAppThread_Entry, 0, ptr, CY_FX_SLFIFO_THREAD_STACK, CY_FX_SLFIFO_THREAD_PRIORITY, CY_FX_SLFIFO_THREAD_PRIORITY, CYU3P_NO_TIME_SLICE, CYU3P_AUTO_START );
然后定义 线程,
void BulkSrcSinkAppThread_Entry (uint32_t input) { CyU3PReturnStatus_t stat; uint32_t eventMask = CYFX_USB_CTRL_TASK | CYFX_USB_HOSTWAKE_TASK; uint32_t eventStat; CyFxUartLpApplnInit(); CyFxBulkSrcSinkApplnInit(); int a = 1; for (;;) { ; } }
USB的模块初始化
这里主要是CyFxBulkSrcSinkApplnInit(); 的执行上一个 CyFxUartLpApplnInit();函数式执行串口的程序是用来帮忙调试的毕竟固件不能在线调试只能通过串口来做简单的辅助测试了;下面重点来说
CyFxBulkSrcSinkApplnInit();他的执行过程
这里面是主要是分两大步:
第一是:GPIF-II Initialization
pibClock.clkDiv = 2; pibClock.clkSrc = CY_U3P_SYS_CLK; pibClock.isHalfDiv = CyFalse; pibClock.isDllEnable = CyFalse; apiRetStatus = CyU3PPibInit(CyTrue,&pibClock);
以上是模块的时钟的初始化, 接下来是将GPIF设置成Slavefifo的模式。
apiRetStatus = CyU3PGpifLoad (&Sync_Slave_Fifo_2Bit_CyFxGpifConfig);
然后打开状态机
apiRetStatus = CyU3PGpifSMStart (SYNC_SLAVE_FIFO_2BIT_RESET, SYNC_SLAVE_FIFO_2BIT_ALPHA_RESET);
下面就是USB部分的启动和配置了,首先是启动USB的环境
调用 apiRetStatus = CyU3PUsbStart();
然后为了能够响应一系列的操作,我们需要注册各种回调函数,这里包括
CyU3PUsbRegisterSetupCallback(CyFxSlFifoApplnUSBSetupCB, CyTrue);
CyU3PUsbRegisterEventCallback(CyFxSlFifoApplnUSBEventCB);
设置USB的各个描述字!
使用
apiRetStatus = CyU3PUsbSetDesc(CY_U3P_USB_SET_HS_DEVICE_DESCR, NULL, (uint8_t *)CyFxUSB20DeviceDscr);注册描述字!
链接USB的引脚
apiRetStatus = CyU3PConnectState(CyTrue, CyTrue);
在事件的Callback函数里面有会调用EDP的配置DMA的配置
EDP的配置
CyU3PMemSet ((uint8_t *)&epCfg, 0, sizeof (epCfg)); epCfg.enable = CyTrue; epCfg.epType = CY_U3P_USB_EP_BULK; epCfg.burstLen = 1; epCfg.streams = 0; epCfg.pcktSize = size; apiRetStatus = CyU3PSetEpConfig(CY_FX_EP_PRODUCER, &epCfg);
DMA的配置
dmaCfg.size = size; dmaCfg.count = CY_FX_SLFIFO_DMA_BUF_COUNT; dmaCfg.prodSckId = CY_FX_PRODUCER_USB_SOCKET; dmaCfg.consSckId = CY_FX_CONSUMER_PPORT_SOCKET; dmaCfg.dmaMode = CY_U3P_DMA_MODE_BYTE;
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
apiRetStatus = CyU3PDmaChannelSetXfer (&glChHandleSlFifoUtoP, CY_FX_SLFIFO_DMA_TX_SIZE);
再来就是设计DMA的事件响应函数,
void CyFxSlFifoUtoPDmaCallback ( CyU3PDmaChannel *chHandle, CyU3PDmaCbType_t type, CyU3PDmaCBInput_t *input ) { CyU3PReturnStatus_t status = CY_U3P_SUCCESS; if (type == CY_U3P_DMA_CB_PROD_EVENT) { status = CyU3PDmaChannelCommitBuffer (chHandle, input- >buffer_p.count, 0); if (status != CY_U3P_SUCCESS) { CyU3PDebugPrint (4, "CyU3PDmaChannelCommitBuffer failed, Error code = %d\n", status); } glDMARxCount++; } }