<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.13">
  <compounddef id="_page__developing_with_u_s_b_d" kind="page">
    <compoundname>Page_DevelopingWithUSBD</compoundname>
    <title>Developing with USB Device ROM Stack</title>
    <detaileddescription>
<para>This section introduces you to application development using USB ROM stack. The topics in this section describe high-level USB concepts and provide step-by-step instructions on implementing a USB device using USB ROM stack. For detailed information on USB concepts, see USB specifications at usb.org.</para><para><itemizedlist>
<listitem><para><ref refid="_page__developing_with_u_s_b_d_1USBD_Prerequisites" kindref="member">Prerequisites</ref></para></listitem><listitem><para><ref refid="_page__developing_with_u_s_b_d_1USBD_DefDescriptors" kindref="member">Step1: Define USB descriptors</ref></para></listitem><listitem><para><ref refid="_page__developing_with_u_s_b_d_1USBD_StackInit" kindref="member">Step2: Initializing the USBD ROM Stack</ref></para></listitem><listitem><para><ref refid="_page__developing_with_u_s_b_d_1USBD_IrqInstall" kindref="member">Step3: Connecting USB IRQ handler</ref></para></listitem><listitem><para><ref refid="_page__developing_with_u_s_b_d_1USBD_RomClassInstall" kindref="member">Step4: Initialize and attach ROM class drivers</ref></para></listitem><listitem><para><ref refid="_page__developing_with_u_s_b_d_1USBD_CustomClassInstall" kindref="member">Step5: Initialize and attach custom class drivers</ref></para></listitem><listitem><para><ref refid="_page__developing_with_u_s_b_d_1USBD_IrqnConnect" kindref="member">Step6: Enable IRQ and connect the device.</ref></para></listitem></itemizedlist>
</para><para>For advanced user who wants to change the default stack behavior by implementing custom overrides see <ref refid="_page__advanced_users" kindref="compound">Customizing USBD ROM Core Layer</ref>.</para><sect1 id="_page__developing_with_u_s_b_d_1USBD_Prerequisites">
<title>Prerequisites</title>
<para><itemizedlist>
<listitem><para>A sample project which initializes processor, clocks (oscillator, system PLL &amp; USB PLL), I/O configuration, memory subsystem and C-runtime library (includes initialization of process stack and other resources).</para></listitem><listitem><para>Obtain and include all USB ROM stack API header files in the project.</para></listitem><listitem><para>Initialize the appropriate USB clocks per chip specific clock controller.</para></listitem><listitem><para>Initialize all USB related pins (USB_VBUS, USB_ID, USB_DP, USB_DM) according to chip and board connections.  Clock and pin initialization is outside the scope of USBD ROM stack.</para></listitem></itemizedlist>
</para></sect1>
<sect1 id="_page__developing_with_u_s_b_d_1USBD_DefDescriptors">
<title>Step1: Define USB descriptors</title>
<para>A USB device provides information about itself in data structures called <emphasis>USB descriptors</emphasis> to a host during enumeration process. Hence user application should create these descriptors as per the application and provide it to the ROM stack. So that the stack takes care of responding to the standard USB requests generated by the host. See <ref refid="_page__usb_descriptors" kindref="compound">Defining USB Descriptors</ref> for more details on how to define these descriptor arrays accepted by the stack.</para></sect1>
<sect1 id="_page__developing_with_u_s_b_d_1USBD_StackInit">
<title>Step2: Initializing the USBD ROM Stack</title>
<para>To initialize the USBD ROM stack configure the initialization parameters.<itemizedlist>
<listitem><para>Define any handle to access the ROM table as shown below. <programlisting><codeline><highlight class="normal">/*<sp/>A<sp/>table<sp/>of<sp/>pointers<sp/>to<sp/>the<sp/>USBD<sp/>functions<sp/>contained<sp/>in<sp/>ROM<sp/>is<sp/>located<sp/>at<sp/>the<sp/>address<sp/>contained<sp/>at<sp/>this<sp/>location<sp/>*/</highlight></codeline>
<codeline><highlight class="normal">#define<sp/>USBD_FUNCTION_TABLE_PTR_ADDR<sp/><sp/><sp/><sp/><sp/><sp/><sp/><sp/><sp/><sp/><sp/><sp/><sp/><sp/><sp/><sp/><sp/><sp/><sp/><sp/>(0x1040011CUL)</highlight></codeline>
<codeline></codeline>
<codeline><highlight class="normal">#define<sp/>USBD_API<sp/>(*((USBD_API_T**)USBD_FUNCTION_TABLE_PTR_ADDR))</highlight></codeline>
</programlisting></para></listitem><listitem><para>Create an instance of <ref refid="struct_u_s_b_d___a_p_i___i_n_i_t___p_a_r_a_m___t" kindref="compound">USBD_API_INIT_PARAM_T</ref> as a local variable. Reset all data member of the instance to 0. <programlisting><codeline><highlight class="normal">USBD_API_INIT_PARAM_T<sp/>usb_param;</highlight></codeline>
<codeline><highlight class="normal">USB_CORE_DESCS_T<sp/>desc;</highlight></codeline>
<codeline></codeline>
<codeline><highlight class="normal">/*<sp/>reset<sp/>all<sp/>init<sp/>params<sp/>*/</highlight></codeline>
<codeline><highlight class="normal">memset((void*)&amp;usb_param,<sp/>0,<sp/>sizeof(USBD_API_INIT_PARAM_T));</highlight></codeline>
</programlisting></para></listitem><listitem><para>Define the memory area ROM stack can use for its global variables. As described in <ref refid="index_1USBD_MemModel" kindref="member">Memory Model</ref> section, the application needs to provide memory area in which the stack can allocate its global variables and also the device controller driver buffers. This memory address should be accessible by USB bus master. <programlisting><codeline><highlight class="normal">usb_param.mem_base<sp/>=<sp/>0x20000000;</highlight></codeline>
<codeline><highlight class="normal">usb_param.mem_size<sp/>=<sp/>0x2000;</highlight></codeline>
</programlisting></para></listitem><listitem><para>If the application is using dynamic memory allocator or wants to know exactly how much memory stack needs. It can call <ref refid="struct_u_s_b_d___h_w___a_p_i___t_1a0139f290b9605de953245f12b5a0ff26" kindref="member">USBD_HW_API_T::GetMemSize</ref> routine to know the size of memory buffer stack needs.<itemizedlist>
<listitem><para>Set the USB register base address location and number of endpoints used by the application to optimize driver buffer space. Setting <emphasis>max_num_ep</emphasis> to more than the maximum number of endpoints available in hardware will cause program crashes. <programlisting><codeline><highlight class="normal">usb_param.usb_reg_base<sp/>=<sp/>LPC_USB0_BASE;</highlight></codeline>
<codeline><highlight class="normal">usb_param.max_num_ep<sp/>=<sp/>6;</highlight></codeline>
</programlisting></para></listitem></itemizedlist>
</para></listitem><listitem><para>Provide event callback routines for event in which application is interested in. See <ref refid="struct_u_s_b_d___a_p_i___i_n_i_t___p_a_r_a_m___t" kindref="compound">USBD_API_INIT_PARAM_T</ref> for list of USB device events to which the application can subscribe. <programlisting><codeline><highlight class="normal">usb_param.USB_Configure_Event<sp/>=<sp/>App_Configure_Event;</highlight></codeline>
</programlisting></para></listitem><listitem><para>Define USB descriptors (see <ref refid="_page__developing_with_u_s_b_d_1USBD_DefDescriptors" kindref="member">Step1: Define USB descriptors</ref> ) and initialize the descriptor parameter. <programlisting><codeline><highlight class="normal">/*<sp/>Set<sp/>the<sp/>USB<sp/>descriptors<sp/>*/</highlight></codeline>
<codeline><highlight class="normal">desc.device_desc<sp/>=<sp/>USB_DeviceDescriptor;</highlight></codeline>
<codeline><highlight class="normal">desc.string_desc<sp/>=<sp/>USB_StringDescriptor;</highlight></codeline>
<codeline><highlight class="normal">desc.full_speed_desc<sp/>=<sp/>USB_FsConfigDescriptor;</highlight></codeline>
<codeline><highlight class="normal">desc.high_speed_desc<sp/>=<sp/>USB_HsConfigDescriptor;</highlight></codeline>
<codeline><highlight class="normal">desc.device_qualifier<sp/>=<sp/>USB_DeviceQualifier;<sp/></highlight></codeline>
</programlisting> Call <emphasis>Init()</emphasis> routine to initialize the stack. If the routine returns anything other than <ref refid="error_8h_1a905255056c349318139d94aa4523d516aa3f185f76b8de73122db389cb2db775e" kindref="member">LPC_OK</ref> then the parameters are not configured properly. See <ref refid="struct_u_s_b_d___h_w___a_p_i___t_1adf7b0f0dc37399c73b3cb03224a6715c" kindref="member">USBD_HW_API_T::Init</ref> for more details. If the initialization call is successful the handle to the instance of USBD ROM stack is return in <emphasis>phUsb</emphasis> parameter. Application should store this handle in a global scope variable to access stack functions from USBD and IRQ contexts.</para></listitem></itemizedlist>
</para><para><programlisting><codeline><highlight class="normal">/*<sp/>USB<sp/>Initialization<sp/>*/</highlight></codeline>
<codeline><highlight class="normal">ret<sp/>=<sp/>USBD_API-&gt;hw-&gt;Init(&amp;g_hUsb,<sp/>&amp;desc,<sp/>&amp;usb_param);<sp/><sp/></highlight></codeline>
<codeline><highlight class="normal">if<sp/>(ret<sp/>==<sp/>LPC_OK)<sp/>{</highlight></codeline>
<codeline></codeline>
<codeline><highlight class="normal"><sp/><sp/><sp/><sp/>.....<sp/>do<sp/>some<sp/>USB<sp/>stuff...</highlight></codeline>
<codeline><highlight class="normal">}</highlight></codeline>
</programlisting></para></sect1>
<sect1 id="_page__developing_with_u_s_b_d_1USBD_IrqInstall">
<title>Step3: Connecting USB IRQ handler</title>
<para>USBD ROM stack implements the interrupt handler for USB device controller and invokes the USBD ROM stack routines according to the event type. Hence application should connect this handler to the application vector table. This is done by calling <ref refid="struct_u_s_b_d___h_w___a_p_i___t_1a00d85b9c68f1ec92c8092dafe524fe2b" kindref="member">USBD_HW_API_T::ISR</ref> from the USB IRQ handler as shown in the code snippet below. The USBD ROM handle passed to the <emphasis>ISR()</emphasis> routine is the one obtained in previous step.</para><para><programlisting><codeline><highlight class="normal">void<sp/>USB0_IRQHandler(void)</highlight></codeline>
<codeline><highlight class="normal">{</highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/><sp/><sp/>USBD_API-&gt;hw-&gt;ISR(g_hUsb);</highlight></codeline>
<codeline><highlight class="normal">}</highlight></codeline>
</programlisting></para></sect1>
<sect1 id="_page__developing_with_u_s_b_d_1USBD_RomClassInstall">
<title>Step4: Initialize and attach ROM class drivers</title>
<para>USBD ROM stack implements several function drivers as part of its class layer. These function drivers can be attached to their corresponding interface to handle the class specific request associated with that interface. Most of the class/function drivers implemented by the USBD ROM stack take care of the class requests sent on the default control endpoint and leave most of the data handling done on bulk/isochronous endpoints to the application. Except Mass Storage class driver which implement bulk-only handler to parse SCSI commands. See individual class driver module help pages to learn more about its behavior.</para><para>In the following example Mass Storage class driver is attached to the only interface (interface 0, alt 0) present in the device configuration shown in <ref refid="_page__usb_descriptors_1USBD_ConfigDes" kindref="member">Defining USB Configuration Descriptors Array</ref> section.</para><para><itemizedlist>
<listitem><para>Configure initialization parameters of the MSC class driver <programlisting><codeline><highlight class="normal">USBD_MSC_INIT_PARAM_T<sp/>msc_param;</highlight></codeline>
<codeline></codeline>
<codeline><highlight class="normal">memset((void*)&amp;msc_param,<sp/>0,<sp/>sizeof(USBD_MSC_INIT_PARAM_T));</highlight></codeline>
</programlisting></para></listitem><listitem><para>Set the memory location where the MSC class driver can allocate buffers and global variables. All the <emphasis>init()</emphasis> routines of the ROM components are written in such a way that the <emphasis>mem_base</emphasis> and <emphasis>mem_size</emphasis> members of <emphasis>XXX_INIT_PARAM_T</emphasis> are updated with free location and size before returning. So that the next component <emphasis>XXX_INIT_PARAM_T</emphasis> can use the update values for its <emphasis>init()</emphasis> routine. Applications can cascade the component initialization this way without worrying about memory wastage/overlap issues. <programlisting><codeline><highlight class="normal">msc_param.mem_base<sp/>=<sp/>usb_param.mem_base;</highlight></codeline>
<codeline><highlight class="normal">msc_param.mem_size<sp/>=<sp/>usb_param.mem_size;</highlight></codeline>
</programlisting></para></listitem><listitem><para>Now set the MSC specific parameters. <programlisting><codeline><highlight class="normal">/*<sp/>mass<sp/>storage<sp/>params<sp/>*/</highlight></codeline>
<codeline><highlight class="normal">msc_param.InquiryStr<sp/>=<sp/>(uint8_t*)InquiryStr;<sp/></highlight></codeline>
<codeline><highlight class="normal">msc_param.BlockCount<sp/>=<sp/>MSC_MemorySize<sp/>/<sp/>MSC_BlockSize;</highlight></codeline>
<codeline><highlight class="normal">msc_param.BlockSize<sp/>=<sp/>MSC_BlockSize;</highlight></codeline>
<codeline><highlight class="normal">msc_param.MemorySize<sp/>=<sp/>MSC_MemorySize;</highlight></codeline>
</programlisting></para></listitem><listitem><para>Obtain the address location of the interface descriptor, within the device configuration descriptor array, to which the class driver has to be attached. <programlisting><codeline><highlight class="normal">pIntfDesc<sp/>=</highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/><sp/>(USB_INTERFACE_DESCRIPTOR*)((uint32_t)desc.high_speed_desc<sp/>+<sp/>USB_CONFIGUARTION_DESC_SIZE);</highlight></codeline>
<codeline><highlight class="normal">/*<sp/>check<sp/>we<sp/>are<sp/>referencing<sp/>to<sp/>the<sp/>proper<sp/>interface<sp/>descriptor<sp/>*/<sp/></highlight></codeline>
<codeline><highlight class="normal">if<sp/>((pIntfDesc<sp/>==<sp/>0)<sp/>||</highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/><sp/>(pIntfDesc-&gt;bInterfaceClass<sp/>!=<sp/>USB_DEVICE_CLASS_STORAGE)<sp/>||</highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/><sp/>(pIntfDesc-&gt;bInterfaceSubClass<sp/>!=<sp/>MSC_SUBCLASS_SCSI)<sp/>)</highlight></codeline>
<codeline><highlight class="normal">return<sp/>ERR_FAILED;</highlight></codeline>
<codeline><highlight class="normal">msc_param.intf_desc<sp/>=<sp/>(uint8_t*)pIntfDesc;</highlight></codeline>
</programlisting></para></listitem><listitem><para>Define and set the MSC class callback routines. <programlisting><codeline><highlight class="normal">/*<sp/>user<sp/>defined<sp/>functions<sp/>*/</highlight></codeline>
<codeline><highlight class="normal">msc_param.MSC_Write<sp/>=<sp/>translate_wr;<sp/></highlight></codeline>
<codeline><highlight class="normal">msc_param.MSC_Read<sp/>=<sp/>translate_rd;</highlight></codeline>
<codeline><highlight class="normal">msc_param.MSC_Verify<sp/>=<sp/>translate_verify;</highlight></codeline>
<codeline><highlight class="normal">msc_param.MSC_GetWriteBuf<sp/>=<sp/>translate_GetWrBuf;</highlight></codeline>
</programlisting></para></listitem><listitem><para>Now call the <ref refid="struct_u_s_b_d___m_s_c___a_p_i___t_1a3d421532e7d54500f285f8c2e0813e7e" kindref="member">USBD_MSC_API_T::init</ref> routine of the MSC class. <programlisting><codeline><highlight class="normal"><sp/><sp/><sp/><sp/>ret<sp/>=<sp/>USBD_API-&gt;msc-&gt;init(hUsb,<sp/>&amp;msc_param);</highlight></codeline>
<codeline></codeline>
<codeline></codeline>
<codeline><highlight class="normal">if<sp/>(ret<sp/>!=<sp/>LPC_OK)<sp/>{</highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/>vCatchError(0);<sp/>//&quot;usb_msc_mem_init<sp/>error!!!&quot;</highlight></codeline>
<codeline><highlight class="normal">}</highlight></codeline>
</programlisting></para></listitem></itemizedlist>
</para></sect1>
<sect1 id="_page__developing_with_u_s_b_d_1USBD_CustomClassInstall">
<title>Step5: Initialize and attach custom class drivers</title>
<para>To implement custom class driver or usb.org defined standard class driver which is not supported by the ROM stack, the following steps need to be followed.</para><para><itemizedlist>
<listitem><para>Install default endpoint handler to handle class specific requests by call <ref refid="struct_u_s_b_d___c_o_r_e___a_p_i___t_1a651891ae3d6612f6f566384b3d681e36" kindref="member">USBD_CORE_API_T::RegisterClassHandler</ref>. The stack calls all the registered class handlers on any EP0 event before going through default handling of the event. This gives the class handlers to implement class specific request handlers and also to override the default stack handling for a particular event targeted to the interface. Check <ref refid="group___u_s_b_d___core_1gaa578d29a85226108ef62c6d5c325b742" kindref="member">USB_EP_HANDLER_T</ref> for more details on implementing endpoint handlers.</para></listitem><listitem><para>Implement class handler.</para></listitem><listitem><para>Install endpoint handlers for other bulk/isochronous/interrupt endpoints present in the interface using <ref refid="struct_u_s_b_d___c_o_r_e___a_p_i___t_1a305d05fbc2d0c748b87edcd986bfb767" kindref="member">USBD_CORE_API_T::RegisterEpHandler</ref> routine.</para></listitem><listitem><para>Implement endpoint handlers.</para></listitem></itemizedlist>
</para></sect1>
<sect1 id="_page__developing_with_u_s_b_d_1USBD_IrqnConnect">
<title>Step6: Enable IRQ and connect the device.</title>
<para>Once the core, device controller and class drivers are initialized the stack is ready to receive the packets from host. Even if the device is physically connected to the host using an USB cable the host does not recognize the presence of device until the D+ line is pulled up using 1.5K ohm resistor (LPC device controllers operate in high-speed or full-speed mode only). To enable the connection the application software should call <ref refid="struct_u_s_b_d___h_w___a_p_i___t_1a94f866b8fdcb6c08b622badfa5703545" kindref="member">USBD_HW_API_T::Connect</ref> with <emphasis>enable</emphasis> set to 1. Before enabling the connection the application should enable the USB interrupt.</para><para><programlisting><codeline><highlight class="normal">NVIC_EnableIRQ(USB0_IRQn);<sp/>//<sp/><sp/>enable<sp/>USB0<sp/>interrupts</highlight></codeline>
<codeline><highlight class="normal">/*<sp/>now<sp/>connect<sp/>*/</highlight></codeline>
<codeline><highlight class="normal">USBD_API-&gt;hw-&gt;Connect(g_hUsb,<sp/>1);</highlight></codeline>
</programlisting></para><para><bold>Subsections :</bold> <itemizedlist>
<listitem><para><ref refid="_page__usb_descriptors" kindref="compound">Defining USB Descriptors</ref> </para></listitem>
<listitem><para><ref refid="_page__advanced_users" kindref="compound">Customizing USBD ROM Core Layer</ref> </para></listitem>
</itemizedlist>
</para></sect1>
    </detaileddescription>
  </compounddef>
</doxygen>
