NuttX U盘驱动

(嵌入式 实时操作系统 rtos nuttx 7.18 stm32 源代码分析)
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 /起一个目录名

你可能感兴趣的:(NuttX)