NuttX U盘驱动
2017-04-14 21:22
225 查看
(嵌入式 实时操作系统 rtos nuttx 7.18 stm32 源代码分析)
NuttX U盘驱动
转载请注明出处: http://blog.csdn.net/zhumaill/article/details/70175635
(code1):nuttx/arch/arm/src/chip/stm32f10xxx_rcc.c
(code2):
(code8):
3.3.2 第2次USB主机端口中断
(code9):
3.3.3 此时轮询中的stm32_wait()中的条件if (priv->change)为真
(code10):
第3次USB主机端口中断是重复操作,无实际操作。
第4次USB主机端口中断是重复操作,无实际操作。
3.3.4 此时执行stm32_enumerate()
(code11):
nuttx usb otg的首次控制传输(发送数据):
(code12):
3.3.5 随后产生第1次USB主机通道中断:
(code13):
发送数据使用通道0,接收数据使用通道1
发送时数据放在通道0的chan->buffer,接收时数据放在通道1的chan->buffer,即应用程序定义的buffer:
usbhost_enumerate()中: //nuttx/drivers/usbhost/usbhost_enumerate.c
stm32_ctrl_recvdata()中: //nuttx/arch/arm/src/chip/stm32_otgfshost.c
收到数据后chan->buffer的指针已移位,应用程序buffer的指针没有移位
接收时stm32_transfer_start()只是使能通道,实际的数据接收是在中断中完成的
继续执行stm32_transfer_start():
3.3.6 随后产生第2次USB主机通道中断:
(code14):
能发送和接收数据,说明最低层的驱动没有问题了。
NuttX U盘驱动
转载请注明出处: http://blog.csdn.net/zhumaill/article/details/70175635
1 系统启动序列中的初始化
1.1 usb otg时钟初始化:
__start() stm32_clockconfig() rcc_reset() stm32_stdclockconfig() rcc_enableperipherals() rcc_enableahb() (code1) rcc_enableapb2() rcc_enableapb1()
(code1):nuttx/arch/arm/src/chip/stm32f10xxx_rcc.c
/* 使能已选的AHB外设 */ static inline void rcc_enableahb(void) { uint32_t regval; #if defined(CONFIG_STM32_CONNECTIVITYLINE) && defined(CONFIG_STM32_OTGFS) /* USB clock divider for USB OTG FS. This bit must be valid before * enabling the USB clock in the RCC_AHBENR register. This bit can't be * reset if the USB clock is enabled. */ regval = getreg32(STM32_RCC_CFGR); //STM32_RCC_CFGR = STM32_RCC_BASE + STM32_RCC_CFGR_OFFSET // = 0x40021000 + 0x0004 regval &= ~RCC_CFGR_OTGFSPRE; //RCC_CFGR_OTGFSPRE = (1 << 22) regval |= STM32_CFGR_OTGFSPRE; //STM32_CFGR_OTGFSPRE = 0 putreg32(regval, STM32_RCC_CFGR); #endif ...... #ifdef CONFIG_STM32_OTGFS /* USB OTG FS 时钟使能 */ regval |= RCC_AHBENR_OTGFSEN; //RCC_AHBENR_OTGFSEN = (1 << 12) #endif ...... putreg32(regval, STM32_RCC_AHBENR); //STM32_RCC_AHBENR = STM32_RCC_BASE + STM32_RCC_AHBENR_OFFSET // = 0x40021000 + 0x0014 }
1.2 usb otg vbus初始化:
在板级初始化时调用stm32_usbinitialize():(code2):
void stm32_usbinitialize(void) { /* The OTG FS has an internal soft pull-up. No GPIO configuration is required */ /* Configure the OTG FS VBUS sensing GPIO, Power On, and Overcurrent GPIOs */ #ifdef CONFIG_STM32_OTGFS stm32_configgpio(GPIO_OTGFS_VBUS); //GPIO_OTGFS_VBUS = (GPIO_ALT|GPIO_CNF_AFPP|GPIO_MODE_50MHz|GPIO_PORTA|GPIO_PIN9) stm32_configgpio(GPIO_OTGFS_PWRON); //GPIO_OTGFS_PWRON = (GPIO_OUTPUT|GPIO_CNF_OUTPP|GPIO_MODE_50MHz|\ // GPIO_OUTPUT_SET|GPIO_PORTB|GPIO_PIN8) // = 0 | 0 << 13 | 3 << 11 | 1 << 7 | 1 << 4 | 8 << 0 // stm32_configgpio(GPIO_OTGFS_OVER); #endif }
2 由用户任务调用的初始化
nsh_main() apps/examples/nsh/nsh_main.c nsh_initialize() apps/nshlib/nsh_init.c boardctl() nuttx/configs/boardctl.c board_app_initialize() nuttx/configs/shenzhou/src/stm32_appinit.c stm32_usbhost_initialize() nuttx/arch/arm/src/board/up_usb.c usbhost_msc_initialize() nuttx/drivers/usbhost/usbhost_storage.c usbhost_registerclass(&g_storage) nuttx/drivers/usbhost/usbhost_registerclass.c stm32_otgfshost_initialize(0) nuttx/arch/arm/src/chip/stm32_otgfshost.c (code3) stm32_hw_initialize(priv) nuttx/arch/arm/src/chip/stm32_otgfshost.c (code4) stm32_host_initialize(priv) nuttx/arch/arm/src/chip/stm32_otgfshost.c (code5) stm32_flush_txfifos(OTGFS_GRSTCTL_TXFNUM_HALL)nuttx/arch/arm/src/chip/stm32_otgfshost.c stm32_putreg(regval, STM32_OTGFS_GRSTCTL) nuttx/arch/arm/src/chip/stm32_otgfshost.c task_create("usbhost", CONFIG_USBHOST_DEFPRIO, CONFIG_USBHOST_STACKSIZE, (main_t)usbhost_waiter, (FAR char * const *)NULL); (code7)
2.1 usb otg gpio初始化:
(code3):FAR struct usbhost_connection_s *stm32_otgfshost_initialize(int controller) { ...... stm32_sw_initialize(priv); ...... stm32_configgpio(GPIO_OTGFS_DM); stm32_configgpio(GPIO_OTGFS_DP); stm32_configgpio(GPIO_OTGFS_ID); /* Only needed for OTG */ ...... stm32_hw_initialize(priv); (code4) ...... }
2.2 usb otg硬件初始化:
(code4):static inline int stm32_hw_initialize(FAR struct stm32_usbhost_s *priv) { uint32_t regval; unsigned long timeout; /* Set the PHYSEL bit in the GUSBCFG register to select the OTG FS serial * transceiver: "This bit is always 1 with write-only access" */ regval = stm32_getreg(STM32_OTGFS_GUSBCFG);; //STM32_OTGFS_GUSBCFG = STM32_OTGFS_BASE + STM32_OTGFS_GUSBCFG_OFFSET // = 0x50000000 + 0x000c regval |= OTGFS_GUSBCFG_PHYSEL; //OTGFS_GUSBCFG_PHYSEL = 1 << 6 stm32_putreg(STM32_OTGFS_GUSBCFG, regval); /* Reset after a PHY select and set Host mode. First, wait for AHB master * IDLE state. */ for (timeout = 0; timeout < STM32_READY_DELAY; timeout++) { up_udelay(3); regval = stm32_getreg(STM32_OTGFS_GRSTCTL); //STM32_OTGFS_GRSTCTL = STM32_OTGFS_BASE + STM32_OTGFS_GRSTCTL_OFFSET // = 0x50000000 + 0x0010 if ((regval & OTGFS_GRSTCTL_AHBIDL) != 0) //OTGFS_GRSTCTL_AHBIDL = 1 << 31 { break; } } /* Then perform the core soft reset. */ stm32_putreg(STM32_OTGFS_GRSTCTL, OTGFS_GRSTCTL_CSRST); //OTGFS_GRSTCTL_CSRST = 1 << 0 for (timeout = 0; timeout < STM32_READY_DELAY; timeout++) { regval = stm32_getreg(STM32_OTGFS_GRSTCTL); if ((regval & OTGFS_GRSTCTL_CSRST) == 0) { break; } } /* Wait for 3 PHY Clocks */ up_udelay(3); /* Deactivate the power down */ regval = (OTGFS_GCCFG_PWRDWN | OTGFS_GCCFG_VBUSASEN | OTGFS_GCCFG_VBUSBSEN); # = 1 << 16 | 1 << 18 | 1<< 19 #ifndef CONFIG_USBDEV_VBUSSENSING //已定义 regval |= OTGFS_GCCFG_NOVBUSSENS; // = 1 << 21 #endif #ifdef CONFIG_STM32_OTGFS_SOFOUTPUT //未定义 regval |= OTGFS_GCCFG_SOFOUTEN; #endif stm32_putreg(STM32_OTGFS_GCCFG, regval); //STM32_OTGFS_GCCFG = STM32_OTGFS_BASE + STM32_OTGFS_GCCFG_OFFSET = 0x50000000 + 0x0038 up_mdelay(20); /* Initialize OTG features: In order to support OTP, the HNPCAP and SRPCAP * bits would need to be set in the GUSBCFG register about here. */ /* Force Host Mode */ regval = stm32_getreg(STM32_OTGFS_GUSBCFG); //同上 regval &= ~OTGFS_GUSBCFG_FDMOD; // = 1 << 30,强制设备模式关 regval |= OTGFS_GUSBCFG_FHMOD; // = 1 << 29,强制主机模式开 stm32_putreg(STM32_OTGFS_GUSBCFG, regval); up_mdelay(50); /* Initialize host mode and return success */ stm32_host_initialize(priv); (code6) return OK; }
2.3 usb otg硬件初始化--主机模式初始化:
(code5):static void stm32_host_initialize(FAR struct stm32_usbhost_s *priv) { uint32_t regval; uint32_t offset; int i; /* Restart the PHY Clock */ stm32_putreg(STM32_OTGFS_PCGCCTL, 0); //STM32_OTGFS_PCGCCTL = STM32_OTGFS_BASE + STM32_OTGFS_PCGCCTL_OFFSET // = 0x50000000 + 0x0e00 /* Initialize Host Configuration (HCFG) register */ regval = stm32_getreg(STM32_OTGFS_HCFG); //STM32_OTGFS_HCFG = STM32_OTGFS_BASE + STM32_OTGFS_HCFG_OFFSET // = 0x50000000 + 0x0400 regval &= ~OTGFS_HCFG_FSLSPCS_MASK; //OTGFS_HCFG_FSLSPCS_MASK = 3 << OTGFS_HCFG_FSLSPCS_SHIFT // = 3 << 0 regval |= OTGFS_HCFG_FSLSPCS_FS48MHz; //OTGFS_HCFG_FSLSPCS_FS48MHz = 1 << OTGFS_HCFG_FSLSPCS_SHIFT // = 1 << 0 stm32_putreg(STM32_OTGFS_HCFG, regval); /* Reset the host port */ stm32_portreset(priv); ---> (code6): static void stm32_portreset(FAR struct stm32_usbhost_s *priv) { uint32_t regval; regval = stm32_getreg(STM32_OTGFS_HPRT); //STM32_OTGFS_HPRT = STM32_OTGFS_BASE + STM32_OTGFS_HPRT_OFFSET // = 0x50000000 + 0x0440 regval &= ~(OTGFS_HPRT_PENA|OTGFS_HPRT_PCDET|OTGFS_HPRT_PENCHNG|OTGFS_HPRT_POCCHNG); // = 1 << 2 | 1 << 1 | 1 << 3 | 1 << 5 regval |= OTGFS_HPRT_PRST; // = 1 << 8 stm32_putreg(STM32_OTGFS_HPRT, regval); up_mdelay(10); regval &= ~OTGFS_HPRT_PRST; //同上 stm32_putreg(STM32_OTGFS_HPRT, regval); up_mdelay(20); } <---- /* Clear the FS-/LS-only support bit in the HCFG register */ regval = stm32_getreg(STM32_OTGFS_HCFG); regval &= ~OTGFS_HCFG_FSLSS; // = 1 << 2 stm32_putreg(STM32_OTGFS_HCFG, regval); //stm32手册v10、v14都说是只读,而这里是写 /* Carve up FIFO memory for the Rx FIFO and the periodic and non-periodic Tx FIFOs */ /* Configure Rx FIFO size (GRXFSIZ) */ stm32_putreg(STM32_OTGFS_GRXFSIZ, CONFIG_STM32_OTGFS_RXFIFO_SIZE); //STM32_OTGFS_GRXFSIZ = STM32_OTGFS_BASE + STM32_OTGFS_GRXFSIZ_OFFSET // = 0x50000000 + 0x0024 //CONFIG_STM32_OTGFS_RXFIFO_SIZE = 128 offset = CONFIG_STM32_OTGFS_RXFIFO_SIZE; // = 128 /* Setup the host non-periodic Tx FIFO size (HNPTXFSIZ) */ regval = (offset | (CONFIG_STM32_OTGFS_NPTXFIFO_SIZE << OTGFS_HNPTXFSIZ_NPTXFD_SHIFT)); // = 128 | 96 << 16 stm32_putreg(STM32_OTGFS_HNPTXFSIZ, regval); //STM32_OTGFS_HNPTXFSIZ = STM32_OTGFS_BASE+STM32_OTGFS_HNPTXFSIZ_OFFSET // = 0x50000000 + 0x0028 offset += CONFIG_STM32_OTGFS_NPTXFIFO_SIZE; // = 128 + 96 /* Set up the host periodic Tx fifo size register (HPTXFSIZ) */ regval = (offset | (CONFIG_STM32_OTGFS_PTXFIFO_SIZE << OTGFS_HPTXFSIZ_PTXFD_SHIFT)); // = (128 + 96) | 128 << 16 stm32_putreg(STM32_OTGFS_HPTXFSIZ, regval); //STM32_OTGFS_HPTXFSIZ = STM32_OTGFS_BASE+STM32_OTGFS_HPTXFSIZ_OFFSET // = 0x50000000 + 0x0100 /* If OTG were supported, we sould need to clear HNP enable bit in the * USB_OTG control register about here. */ /* Flush all FIFOs */ stm32_flush_txfifos(OTGFS_GRSTCTL_TXFNUM_HALL); //OTGFS_GRSTCTL_TXFNUM_HALL = 16 << OTGFS_GRSTCTL_TXFNUM_SHIFT // = 16 << 6(原来是10,有误) stm32_flush_rxfifo(); /* Clear all pending HC Interrupts */ for (i = 0; i < STM32_NHOST_CHANNELS; i++) { stm32_putreg(STM32_OTGFS_HCINT(i), 0xffffffff); //STM32_OTGFS_HCINT(n) = STM32_OTGFS_BASE+STM32_OTGFS_HCINT_OFFSET(n) // = 0x50000000 + 0x508 + ((n) << 5) stm32_putreg(STM32_OTGFS_HCINTMSK(i), 0); //STM32_OTGFS_HCINTMSK(n) = STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK_OFFSET(n) // = 0x50000000 + 0x50c + ((n) << 5) } /* Driver Vbus +5V (the smoke test). Should be done elsewhere in OTG * mode. */ stm32_vbusdrive(priv, true); /* Enable host interrupts */ stm32_hostinit_enable(); }
2.4 回到stm32_usbhost_initialize(),创建usbhost_waiter任务
(code7):static int usbhost_waiter(int argc, char *argv[]) { struct usbhost_hubport_s *hport; uinfo("Running\n"); for (;;) { /* 等待一个设备,然后改变状态 */ DEBUGVERIFY(CONN_WAIT(g_usbconn, &hport)); //调用stm32_wait() (code10) uinfo("%s\n", hport->connected ? "connected" : "disconnected"); /* 刚才变成连接状态? */ if (hport->connected) { /* Yes.. enumerate the newly connected device */ (void)CONN_ENUMERATE(g_usbconn, hport); //调用stm32_enumerate() } } /* Keep the compiler from complaining */ return 0; }
3 枚举
3.1 结构体声明
USB主机驱动使用了2个结构体:usbhost_connection_s和stm32_usbhost_s。/* 结构体usbhost_connection_s在平台特定的连接监听和 * USB主机驱动的连接与枚举逻辑之间提供一个接口 */ struct usbhost_connection_s { /* 等待一个设备连接或断开 */ int (*wait)(FAR struct usbhost_connection_s *conn, FAR struct usbhost_hubport_s **hport); /* Enumerate the device connected on a hub port. As part of this * enumeration process, the driver will (1) get the device's configuration * descriptor, (2) extract the class ID info from the configuration * descriptor, (3) call usbhost_findclass() to find the class that supports * this device, (4) call the create() method on the struct usbhost_registry_s * interface to get a class instance, and finally (5) call the connect() * method of the struct usbhost_class_s interface. After that, the class is * in charge of the sequence of operations. */ int (*enumerate)(FAR struct usbhost_connection_s *conn, FAR struct usbhost_hubport_s *hport); }; /* 此结构体保持USB主机控制器的状态 */ struct stm32_usbhost_s { /* Common device fields. This must be the first thing defined in the * structure so that it is possible to simply cast from struct usbhost_s * to structstm32_usbhost_s. */ struct usbhost_driver_s drvr; /* This is the hub port description understood by class drivers */ struct usbhost_roothubport_s rhport; /* Overall driver status */ volatile uint8_t smstate; /* The state of the USB host state machine */ uint8_t chidx; /* ID of channel waiting for space in Tx FIFO */ volatile bool connected; /* Connected to device */ volatile bool change; /* Connection change */ volatile bool pscwait; /* True: Thread is waiting for a port event */ sem_t exclsem; /* Support mutually exclusive access */ sem_t pscsem; /* Semaphore to wait for a port event */ struct stm32_ctrlinfo_s ep0; /* Root hub port EP0 description */ #ifdef CONFIG_USBHOST_HUB /* Used to pass external hub port events */ volatile struct usbhost_hubport_s *hport; #endif /* The state of each host channel */ struct stm32_chan_s chan[STM32_MAX_TX_FIFOS]; }; /* In this driver implementation, support is provided for only a single a single * USB device. All status information can be simply retained in a single global * instance. */
3.2 结构体定义
/* 这是连接/枚举接口 */ static struct usbhost_connection_s g_usbconn = { .wait = stm32_wait, (code10) .enumerate = stm32_enumerate, }; static struct stm32_usbhost_s g_usbhost;
3.3 枚举过程
3.3.1 插入U盘后立即产生一个中断,中断向量号83,这是USB主机端口中断,调用函数stm32_gint_hprtisr()(code8):
stm32_gint_isr() nuttx/arch/arm/src/chip/stm32_otgfshost.c stm32_gint_hprtisr() nuttx/arch/arm/src/chip/stm32_otgfshost.c { .......... /* Check for Port Connect DETected (PCDET). The core sets this bit when a * device connection is detected. */ if ((hprt & OTGFS_HPRT_PCDET) != 0) { /* Set up to clear the PCDET status in the new HPRT contents. Then * process the new connection event. */ usbhost_vtrace1(OTGFS_VTRACE1_GINT_HPRT_PCDET, 0); newhprt |= OTGFS_HPRT_PCDET; stm32_portreset(priv); stm32_gint_connected(priv); --->stm32_gint_connected() nuttx/arch/arm/src/chip/stm32_otgfshost.c { if (!priv->connected) { ...... priv->connected = true; ...... priv->smstate = SMSTATE_ATTACHED; ...... } } <---- } ...... }
3.3.2 第2次USB主机端口中断
(code9):
stm32_gint_isr() nuttx/arch/arm/src/chip/stm32_otgfshost.c stm32_gint_hprtisr() nuttx/arch/arm/src/chip/stm32_otgfshost.c { .......... /* Check for Port Enable CHaNGed (PENCHNG) */ if ((hprt & OTGFS_HPRT_PENCHNG) != 0) { /* Set up to clear the PENCHNG status in the new HPRT contents. */ usbhost_vtrace1(OTGFS_VTRACE1_GINT_HPRT_PENCHNG, 0); newhprt |= OTGFS_HPRT_PENCHNG; /* Was the port enabled? */ if ((hprt & OTGFS_HPRT_PENA) != 0) { /* Yes.. handle the new connection event */ stm32_gint_connected(priv); /* Check the Host ConFiGuration register (HCFG) */ hcfg = stm32_getreg(STM32_OTGFS_HCFG); /* Is this a low speed or full speed connection (OTG FS does not * support high speed) */ if ((hprt & OTGFS_HPRT_PSPD_MASK) == OTGFS_HPRT_PSPD_LS) { ...... } else /* if ((hprt & OTGFS_HPRT_PSPD_MASK) == OTGFS_HPRT_PSPD_FS) */ //走这个分支 { usbhost_vtrace1(OTGFS_VTRACE1_GINT_HPRT_FSDEV, 0); stm32_putreg(STM32_OTGFS_HFIR, 48000); ...... } } } ...... }
3.3.3 此时轮询中的stm32_wait()中的条件if (priv->change)为真
(code10):
nuttx/arch/arm/src/stm32/stm32_otgfshost.c static int stm32_wait(FAR struct usbhost_connection_s *conn, FAR struct usbhost_hubport_s **hport) { FAR struct stm32_usbhost_s *priv = &g_usbhost; struct usbhost_hubport_s *connport; irqstate_t flags; /* Loop until a change in connection state is detected */ flags = enter_critical_section(); for (; ; ) { /* Is there a change in the connection state of the single root hub * port? */ if (priv->change) { connport = &priv->rhport.hport; /* Yes. Remember the new state */ connport->connected = priv->connected; priv->change = false; /* And return the root hub port */ *hport = connport; leave_critical_section(flags); uinfo("RHport Connected: %s\n", connport->connected ? "YES" : "NO"); return OK; } ...... }
第3次USB主机端口中断是重复操作,无实际操作。
第4次USB主机端口中断是重复操作,无实际操作。
3.3.4 此时执行stm32_enumerate()
stm32_enumerate() stm32_rh_enumerate() usbhost_enumerate() (code11)
(code11):
nuttx/drivers/usbhost/usbhost_enumerate.c int usbhost_enumerate(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr, FAR struct usbhost_class_s **class) { ...... /* Extract the full size of the configuration data */ cfglen = (unsigned int)usbhost_getle16(((struct usb_cfgdesc_s *)buffer)->totallen); //buffer = {len = 0x9, type = 0x2, totallen = {0x20, 0x0}, //ninterfaces = 0x1, cfgvalue = 0x1, icfg = 0x0, attr = 0x80, mxpower = 0x32} uvdbg("sizeof config data: %d\n", cfglen); /* Get all of the configuration descriptor data, index == 0 (Should not be * hard-coded!) */ ctrlreq->type = USB_REQ_DIR_IN|USB_REQ_RECIPIENT_DEVICE; ctrlreq->req = USB_REQ_GETDESCRIPTOR; usbhost_putle16(ctrlreq->value, (USB_DESC_TYPE_CONFIG << 8)); usbhost_putle16(ctrlreq->index, 0); usbhost_putle16(ctrlreq->len, cfglen); //cfglen大于16时收到的数据就出错,而这里等于32 ret = DRVR_CTRLIN(drvr, ctrlreq, buffer); //首次控制传输(发送数据),子程序中会调用(code12) if (ret != OK) { udbg("ERROR: GETDESCRIPTOR/CONFIG, DRVR_CTRLIN returned %d\n", ret); goto errout; } }
nuttx usb otg的首次控制传输(发送数据):
usbhost_enumerate() //nuttx/drivers/usbhost/usbhost_enumerate.c DRVR_CTRLIN(drvr, ctrlreq, buffer) (stm32_ctrlin()) //nuttx/arch/arm/src/chip/stm32_otgfshost.c stm32_ctrl_sendsetup(priv, req) //nuttx/arch/arm/src/chip/stm32_otgfshost.c stm32_transfer_start(priv, priv- >ep0out) //nuttx/arch/arm/src/chip/stm32_otgfshost.c (code12) stm32_gint_wrpacket(priv, chan- >buffer, chidx, wrsize) //nuttx/arch/arm/src/chip/stm32_otgfshost.c //发送缓冲区中的内容
(code12):
/* 在指定的输入或输出通道上传输数据 */ static void stm32_transfer_start(FAR struct stm32_usbhost_s *priv, int chidx, FAR uint8_t *buffer) { ...... /* Compute the expected number of packets associated to the transfer. * If the transfer length is zero (or less than the size of one maximum * size packet), then one packet is expected. */ /* If the transfer size is greater than one packet, then calculate the * number of packets that will be received/sent, including any partial * final packet. */ maxpacket = chan->maxpacket; //maxpacket= 8,在usbhost_enumerate()中定义 if (chan->buflen > maxpacket) { npackets = (chan->buflen + maxpacket - 1) / maxpacket; //定义包数目 /* Clip if the buffer length if it exceeds the maximum number of * packets that can be transferred (this should not happen). */ if (npackets > STM32_MAX_PKTCOUNT) { npackets = STM32_MAX_PKTCOUNT; chan->buflen = STM32_MAX_PKTCOUNT * maxpacket; ulldbg("CLIP: chidx: %d buflen: %d\n", chidx, chan->buflen); } } else { /* One packet will be sent/received (might be a zero length packet) */ npackets = 1; } /* If it is an IN transfer, then adjust the size of the buffer UP to * a full number of packets. Hmmm... couldn't this cause an overrun * into unallocated memory? */ #if 0 /* Think about this */ if (chan->in) { /* Force the buffer length to an even multiple of maxpacket */ chan->buflen = npackets * maxpacket; } #endif /* Save the number of packets in the transfer. We will need this in * order to set the next data toggle correctly when the transfer * completes. */ chan->npackets = (uint8_t)npackets; /* Setup the HCTSIZn register */ regval = ((uint32_t)chan->buflen << OTGFS_HCTSIZ_XFRSIZ_SHIFT) | //chan->buflen是应用程序定义 //的要接收的数据大小,也是写到寄存器中的缓冲区大小 ((uint32_t)npackets << OTGFS_HCTSIZ_PKTCNT_SHIFT) | ((uint32_t)chan->pid << OTGFS_HCTSIZ_DPID_SHIFT); stm32_putreg(STM32_OTGFS_HCTSIZ(chidx), regval); /* Setup the HCCHAR register: Frame oddness and host channel enable */ regval = stm32_getreg(STM32_OTGFS_HCCHAR(chidx)); /* Set/clear the Odd Frame bit. Check for an even frame; if so set Odd * Frame. This field is applicable for only periodic (isochronous and * interrupt) channels. */ if ((stm32_getreg(STM32_OTGFS_HFNUM) & 1) == 0) { regval |= OTGFS_HCCHAR_ODDFRM; } regval &= ~OTGFS_HCCHAR_CHDIS; regval |= OTGFS_HCCHAR_CHENA; stm32_putreg(STM32_OTGFS_HCCHAR(chidx), regval); //使能通道中断 /* If this is an out transfer, then we need to do more.. we need to copy * the outgoing data into the correct TxFIFO. */ if (!chan->in && chan->buflen > 0) { /* Handle non-periodic (CTRL and BULK) OUT transfers differently than * periodic (INTR and ISOC) OUT transfers. */ minsize = MIN(chan->buflen, chan->maxpacket); switch (chan->eptype) { case OTGFS_EPTYPE_CTRL: /* Non periodic transfer */ case OTGFS_EPTYPE_BULK: { /* Read the Non-periodic Tx FIFO status register */ regval = stm32_getreg(STM32_OTGFS_HNPTXSTS); avail = ((regval & OTGFS_HNPTXSTS_NPTXFSAV_MASK) >> OTGFS_HNPTXSTS_NPTXFSAV_SHIFT) << 2; } break; /* Periodic transfer */ case OTGFS_EPTYPE_INTR: case OTGFS_EPTYPE_ISOC: { /* Read the Non-periodic Tx FIFO status register */ regval = stm32_getreg(STM32_OTGFS_HPTXSTS); avail = ((regval & OTGFS_HPTXSTS_PTXFSAVL_MASK) >> OTGFS_HPTXSTS_PTXFSAVL_SHIFT) << 2; } break; default: DEBUGASSERT(false); return; } /* Is there space in the TxFIFO to hold the minimum size packet? */ if (minsize <= avail) { /* Yes.. Get the size of the biggest thing that we can put in the Tx FIFO now */ wrsize = chan->buflen; if (wrsize > avail) { /* Clip the write size to the number of full, max sized packets * that will fit in the Tx FIFO. */ unsigned int wrpackets = avail / chan->maxpacket; wrsize = wrpackets * chan->maxpacket; } /* 将包写到TxFIFO. */ stm32_gint_wrpacket(priv, chan->buffer, chidx, wrsize); } /* Did we put the entire buffer into the Tx FIFO? */ if (chan->buflen > avail) { /* No, there was insufficient space to hold the entire transfer ... * Enable the Tx FIFO interrupt to handle the transfer when the Tx * FIFO becomes empty. */ stm32_txfe_enable(priv, chidx); } } }
3.3.5 随后产生第1次USB主机通道中断:
(code13):
stm32_gint_isr() //nuttx/arch/arm/src/chip/stm32_otgfshost.c stm32_gint_hcisr(priv) //nuttx/arch/arm/src/chip/stm32_otgfshost.c stm32_gint_hcoutisr(priv, i) //nuttx/arch/arm/src/chip/stm32_otgfshost.c { //发送数据中断例程 ...... priv->chan[chidx].buffer += priv->chan[chidx].inflight; priv->chan[chidx].buflen -= priv->chan[chidx].inflight; priv->chan[chidx].inflight = 0; stm32_chan_halt(priv, chidx, CHREASON_XFRC) //nuttx/arch/arm/src/chip/stm32_otgfshost.c //关闭通道0 ...... }
发送数据使用通道0,接收数据使用通道1
发送时数据放在通道0的chan->buffer,接收时数据放在通道1的chan->buffer,即应用程序定义的buffer:
usbhost_enumerate()中: //nuttx/drivers/usbhost/usbhost_enumerate.c
uint8_t *buffer;
stm32_ctrl_recvdata()中: //nuttx/arch/arm/src/chip/stm32_otgfshost.c
chan->buffer = buffer;
收到数据后chan->buffer的指针已移位,应用程序buffer的指针没有移位
接收时stm32_transfer_start()只是使能通道,实际的数据接收是在中断中完成的
继续执行stm32_transfer_start():
usbhost_enumerate() //nuttx/drivers/usbhost/usbhost_enumerate.c DRVR_CTRLIN(drvr, ctrlreq, buffer) (stm32_ctrlin()) //nuttx/arch/arm/src/chip/stm32_otgfshost.c stm32_ctrl_recvdata(priv, buffer, buflen) //nuttx/arch/arm/src/chip/stm32_otgfshost.c stm32_transfer_start(priv, priv- >ep0in, buffer) //nuttx/arch/arm/src/chip/stm32_otgfshost.c (code12) ...... regval &= ~OTGFS_HCCHAR_CHDIS; regval |= OTGFS_HCCHAR_CHENA; stm32_putreg(STM32_OTGFS_HCCHAR(chidx), regval) //使能通道1
3.3.6 随后产生第2次USB主机通道中断:
(code14):
stm32_gint_isr() //nuttx/arch/arm/src/chip/stm32_otgfshost.c stm32_gint_rxflvlisr(priv) //nuttx/arch/arm/src/chip/stm32_otgfshost.c //接收缓冲区非空中断处理 { ...... switch (grxsts & OTGFS_GRXSTSH_PKTSTS_MASK) { case OTGFS_GRXSTSH_PKTSTS_INRECVD: /* IN data packet received */ { ...... dest = (FAR uint32_t *)priv->chan[chidx].buffer; fifo = STM32_OTGFS_DFIFO_HCH(0); bcnt32 = (bcnt + 3) >> 2; for (i = 0; i < bcnt32; i++) { *dest++ = stm32_getreg(fifo); //将数据从Rx FIFO复制到缓冲区 } stm32_pktdump("Received", priv->chan[chidx].buffer, bcnt); /* Toggle the IN data pid (Used by Bulk and INTR only) */ priv->chan[chidx].indata1 ^= true; /* Manage multiple packet transfers */ priv->chan[chidx].buffer += bcnt; //移动缓冲区指针 priv->chan[chidx].buflen -= bcnt; /* Check if more packets are expected */ hctsiz = stm32_getreg(STM32_OTGFS_HCTSIZ(chidx)); if ((hctsiz & OTGFS_HCTSIZ_PKTCNT_MASK) != 0) //获取所有配置描述符时,包数目为4,是 //在stm32_transfer_start()中定义的 { up_udelay(30); //如果要使用很老的U盘,添加此行 /* Re-activate the channel when more packets are expected */ hcchar |= OTGFS_HCCHAR_CHENA; hcchar &= ~OTGFS_HCCHAR_CHDIS; stm32_putreg(STM32_OTGFS_HCCHAR(chidx), hcchar); //使能通道中断。 ...... } ...... }
能发送和接收数据,说明最低层的驱动没有问题了。
4 终端挂载U盘
挂载U盘命令:nsh> mount -t vfat /dev/sda /起一个目录名相关文章推荐
- U盘安装win7sp1,在USB3.0接口上需要驱动
- U盘安装Debian,提示缺少无线网卡驱动
- U盘的驱动
- u盘驱动过程(linux-2.6.24)
- 制作U盘加载阵列驱动
- Arm9+linux fl2440 lcd驱动移植、添加MMC支持、添加U盘支持
- Linux内核usb驱动框架——U盘挂载
- 《Linux那些事儿之我是USB》我是U盘(9)总线、设备和驱动(下)
- 【转帖】USB过滤驱动,实现U盘只读控制
- 将U盘虚拟成软驱加载控制器驱动安装windows server 2003
- wince U盘驱动的增加
- Debian使用u盘安装wifi驱动的方法
- 最新XP.GHO文件下载,U盘装机GHO镜像文件,驱动最齐全的纯净版XP系统
- USB过滤驱动,实现U盘只读控制
- U盘安装Centos 更新raid驱动
- 内核linux-3.0移植到fl2440-----添加U盘,MMC和LCD驱动
- linux内核支持usb驱动,usb转串口设备,u盘
- Linux下的USB总线驱动-u盘驱动分析(程序过程分析)
- USB过滤驱动,实现U盘只读控制
- 利用U盘制作虚拟软驱加载raid驱动