您的位置:首页 > 其它

NuttX U盘驱动

2017-04-14 21:22 225 查看
(嵌入式 实时操作系统 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 /起一个目录名
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息