⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usb in a nutshell - chapter 7 - pdiusbd11 and pic16f87x example.htm

📁 altra下载线资料。max7000系列
💻 HTM
📖 第 1 页 / 共 4 页
字号:
          the char array is fixed in the header and is not dynamic. </P><PRE>#define MAX_BUFFER_SIZE 80

bank1 unsigned char circularbuffer[MAX_BUFFER_SIZE];
unsigned char inpointer;
unsigned char outpointer;

unsigned char *pSendBuffer;
unsigned char BytesToSend;
unsigned char CtlTransferInProgress;
unsigned char DeviceAddress;
unsigned char DeviceConfigured;

#define PROGRESS_IDLE             0
#define PROGRESS_ADDRESS          3

void main (void)
{
    TRISB = 0x03;   /* Int &amp; Suspend Inputs */
    RB3 = 1;        /* Device Not Configured (LED) */
    RB2 = 0;        /* Reset PDIUSBD11 */

    InitUART();
    printf("Initialising\n\r");
    I2C_Init(); 

    RB2 = 1;        /* Bring PDIUSBD11 out of reset */

    ADCON1 = 0x80;  /* ADC Control - All 8 Channels Enabled, */
                    /* supporting upgrade to 16F877 */

    USB_Init();
    printf("PDIUSBD11 Ready for connection\n\r");
    while(1) 
	if (!RB0) D11GetIRQ(); /* If IRQ is Low, PDIUSBD11 has an Interrupt Condition */
}    
</PRE>
          <P>The main function is example dependent. It's responsible for 
          initialising the direction of the I/O Ports, initialising the I2C 
          interface, Analog to Digital Converters and PDIUSBD11. Once everything 
          is configured it keeps calling D11GetIRQ which processes PDIUSBD11 
          Interrupt Requests. </P><PRE>void USB_Init(void)
{
    unsigned char Buffer[2];

    /* Disable Hub Function in PDIUSBD11 */
    Buffer[0] = 0x00;
    D11CmdDataWrite(D11_SET_HUB_ADDRESS, Buffer, 1);

    /* Set Address to zero (default) and enable function */
    Buffer[0] = 0x80;
    D11CmdDataWrite(D11_SET_ADDRESS_ENABLE, Buffer, 1);

    /* Enable function generic endpoints */
    Buffer[0] = 0x02;
    D11CmdDataWrite(D11_SET_ENDPOINT_ENABLE, Buffer, 1);

    /* Set Mode - Enable SoftConnect */
    Buffer[0] = 0x97; /* Embedded Function, SoftConnect, Clk Run, No LazyClk, Remote Wakeup */
    Buffer[1] = 0x0B; /* CLKOut = 4MHz */
    D11CmdDataWrite(D11_SET_MODE, Buffer, 2);
}
</PRE>
          <P>The USB Init function initialises the PDIUSBD11. This 
          initialisation procedure has been omitted from the Philips PDIUSBD11 
          datasheet but is available from their <A 
          href="http://www.semiconductors.philips.com/buses/usb/products/device/pdiusbd11/faq/index.html">FAQ</A>. 
          The last command enables the soft-connect pull up resistor on D+ 
          indicating it is a <A 
          href="http://www.beyondlogic.org/usbnutshell/usb2.htm#SpeedIdentification">full 
          speed</A> device but also advertises its presence on the universal 
          serial bus. </P><PRE>void D11GetIRQ(void)
{
        unsigned short Irq;
        unsigned char Buffer[1];

        /* Read Interrupt Register to determine source of interrupt */

        D11CmdDataRead(D11_READ_INTERRUPT_REGISTER, (unsigned char *)&amp;Irq, 2);

        if (Irq) printf("Irq = 0x%X: ",Irq);
</PRE>
          <P>Main() keeps calling the D11GetIRQ in a loop. This function reads 
          the PDIUSBD11's Interrupt Register to establish if any interrupts are 
          pending. If this is the case it will act upon them, otherwise it will 
          continue to loop. Other USB devices may have a series of interrupt 
          vectors assigned to each endpoint. In this case each ISR will service 
          the appropriate interrupt removing the if statements. </P><PRE>        if (Irq &amp; D11_INT_BUS_RESET) {
            printf("Bus Reset\n\r");
            USB_Init();
        }

        if (Irq &amp; D11_INT_EP0_OUT) {
            printf("EP0_Out: ");
            Process_EP0_OUT_Interrupt();
        }

        if (Irq &amp; D11_INT_EP0_IN) {
            printf("EP0_In: \n\r");
            if (CtlTransferInProgress == PROGRESS_ADDRESS) {
                D11CmdDataWrite(D11_SET_ADDRESS_ENABLE,&amp;DeviceAddress,1);
                D11CmdDataRead(D11_READ_LAST_TRANSACTION + D11_ENDPOINT_EP0_IN, Buffer, 1);
                CtlTransferInProgress = PROGRESS_IDLE;
                }
        else {
                D11CmdDataRead(D11_READ_LAST_TRANSACTION + D11_ENDPOINT_EP0_IN, Buffer, 1);
                WriteBufferToEndPoint();
                }
        }
</PRE>
          <P>The If statements work down in order of priority. The highest 
          priority interrupt is the bus reset. This simply calls USB_Init which 
          re-initialises the USB function. The next highest priority is the 
          default pipe consisting of EP0 OUT and EP1 IN. This is where all the 
          enumeration and control requests are sent. We branch to another 
          function to handle the EP0_OUT requests. </P>
          <P>When a request is made by the host and it wants to receive data, 
          the PIC16F876 will send the PDIUSBD11 a 8 byte packet. As the USbus is 
          host controlled it cannot write the data when ever it desires, so the 
          PDIUSBD11 buffers the data and waits for an IN Token to be sent from 
          the host. When the PDIUSBD11 receives the IN Token it generates an 
          interrupt. This makes a good time to reload the next packet of data to 
          send. This is done by an additional function WriteBufferToEndpoint(); 
          </P>
          <P>The section under CtlTransferInProgress == PROGRESS_ADDRESS handles 
          the setting of the device's address. We detail this later. </P><PRE>        if (Irq &amp; D11_INT_EP1_OUT) {
            printf("EP1_OUT\n\r");
            D11CmdDataRead(D11_READ_LAST_TRANSACTION + D11_ENDPOINT_EP1_OUT, Buffer, 1);
            bytes = D11ReadEndpoint(D11_ENDPOINT_EP1_OUT, Buffer);
            for (count = 0; count &lt; bytes; count++) {
               circularbuffer[inpointer++] = Buffer[count];
               if (inpointer &gt;= MAX_BUFFER_SIZE) inpointer = 0;
              }
            loadfromcircularbuffer(); //Kick Start
        }
     
        if (Irq &amp; D11_INT_EP1_IN) {
            printf("EP1_IN\n\r");
            D11CmdDataRead(D11_READ_LAST_TRANSACTION + D11_ENDPOINT_EP1_IN, Buffer, 1);
            loadfromcircularbuffer();
        }
</PRE>
          <P>EP1 OUT and EP1 IN are implemented to read and write bulk data to 
          or from a circular buffer. This setup allows the code to be used in 
          conjunction with the BulkUSB example in the Windows DDK's. The 
          circular buffer is defined earlier in the code as being 80 bytes long 
          taking up all of bank1 of the PIC16F876's RAM. </P><PRE>        if (Irq &amp; D11_INT_EP2_OUT) {
            printf("EP2_OUT\n\r");
            D11CmdDataRead(D11_READ_LAST_TRANSACTION + D11_ENDPOINT_EP2_OUT, Buffer, 1);
            Buffer[0] = 0x01; /* Stall Endpoint */
            D11CmdDataWrite(D11_SET_ENDPOINT_STATUS + D11_ENDPOINT_EP2_OUT, Buffer, 1); 
        }

        if (Irq &amp; D11_INT_EP2_IN) {
            printf("EP2_IN\n\r");
            D11CmdDataRead(D11_READ_LAST_TRANSACTION + D11_ENDPOINT_EP2_IN, Buffer, 1);
            Buffer[0] = 0x01; /* Stall Endpoint */
            D11CmdDataWrite(D11_SET_ENDPOINT_STATUS + D11_ENDPOINT_EP2_IN, Buffer, 1); 
        }

        if (Irq &amp; D11_INT_EP3_OUT) {
            printf("EP3_OUT\n\r");
            D11CmdDataRead(D11_READ_LAST_TRANSACTION + D11_ENDPOINT_EP3_OUT, Buffer, 1);
            Buffer[0] = 0x01; /* Stall Endpoint */
            D11CmdDataWrite(D11_SET_ENDPOINT_STATUS + D11_ENDPOINT_EP3_OUT, Buffer, 1); 
        }

        if (Irq &amp; D11_INT_EP3_IN) {
            printf("EP3_IN\n\r");
            D11CmdDataRead(D11_READ_LAST_TRANSACTION + D11_ENDPOINT_EP3_IN, Buffer, 1);
            Buffer[0] = 0x01; /* Stall Endpoint */
            D11CmdDataWrite(D11_SET_ENDPOINT_STATUS + D11_ENDPOINT_EP3_IN, Buffer, 1); 
        }
 
}
</PRE>
          <P>Endpoints two and three are not used at the moment, so we stall 
          them if any data is received. The PDIUSBD11 has a Set Endpoint Enable 
          Command which can be used to enable or disable function generic 
          endpoints (any endpoints other than the default control pipe). We 
          could use this command to diable the generic endpoints, if we were 
          planning on not using these later. However at the moment this code 
          provides a foundation to build upon. </P><PRE>void Process_EP0_OUT_Interrupt(void)
{
    unsigned long a;
    unsigned char Buffer[2];
    USB_SETUP_REQUEST SetupPacket;

    /* Check if packet received is Setup or Data - Also clears IRQ */
    D11CmdDataRead(D11_READ_LAST_TRANSACTION + D11_ENDPOINT_EP0_OUT, &amp;SetupPacket, 1);

    if (SetupPacket.bmRequestType &amp; D11_LAST_TRAN_SETUP) {
</PRE>
          <P>The first thing we must do is determine is the packet we have 
          received on EP0 Out is a data packet or a <A 
          href="http://www.beyondlogic.org/usbnutshell/usb6.htm#SetupPacket">Setup 
          Packet</A>. A Setup Packet contains a request such as Get Descriptor 
          where as a data packet contains data for a previous request. We are 
          lucky that most requests do not send data packets from the host to the 
          device. A request that does is SET_DESCRIPTOR but is rarely 
          implemented. </P><PRE>        /* This is a setup Packet - Read Packet */
        D11ReadEndpoint(D11_ENDPOINT_EP0_OUT, &amp;SetupPacket);

        /* Acknowlegde Setup Packet to EP0_OUT &amp; Clear Buffer*/
        D11CmdDataWrite(D11_ACK_SETUP, NULL, 0);
        D11CmdDataWrite(D11_CLEAR_BUFFER, NULL, 0);

        /* Acknowlegde Setup Packet to EP0_IN */
        D11CmdDataWrite(D11_ENDPOINT_EP0_IN, NULL, 0);
        D11CmdDataWrite(D11_ACK_SETUP, NULL, 0);

        /* Parse bmRequestType */
        switch (SetupPacket.bmRequestType &amp; 0x7F) {
</PRE>
          <P>As we have seen in our description of <A 
          href="http://www.beyondlogic.org/usbnutshell/usb4.htm#Control">Control 
          Transfers</A>, a setup packet cannot be NAKed or STALLed. When the 
          PDIUSBD11 receives a Setup Packet it flushes the EP0 IN buffer and 
          disables the Validate Buffer and Clear Buffer commands. This ensures 
          the setup packet is acknowledged by the microcontroller by sending an 
          Acknowledge Setup command to both EP0 IN and EP0 OUT before a Validate 
          or Clear Buffer command is effective. The recept of a setup packet 
          will also un-stall a STALLed control endpoint. </P>
          <P>Once the packet has been read into memory and the setup packet 
          acknowledged, we being the parse the request starting with the request 
          type. At the moment we are not interesting in the direction, so we AND 
          off this bit. The three requests all devices must process is the 
          Standard Device Request, Standard Interface Request and Standard 
          Endpoint Requests. We provide our functionality (Read Analog Inputs) 
          by the Vendor Request, so we add a case statement for Standard Vendor 
          Requests. If your device supports a USB Class Specification, then you 
          may also need to add cases for Class Device Request, Class Interface 
          Request and/or Class Endpoint Request. </P><PRE>            case STANDARD_DEVICE_REQUEST:
                printf("Standard Device Request ");
                switch (SetupPacket.bRequest) {
                    case GET_STATUS:
                        /* Get Status Request to Device should return */
                        /* Remote Wakeup and Self Powered Status */
                        Buffer[0] = 0x01;
                        Buffer[1] = 0x00;
                        D11WriteEndpoint(D11_ENDPOINT_EP0_IN, Buffer, 2);
                        break;

                    case CLEAR_FEATURE:
                    case SET_FEATURE:
                        /* We don't support DEVICE_REMOTE_WAKEUP or TEST_MODE */
                        ErrorStallControlEndPoint();
                        break;
</PRE>
          <P>The Get Status request is used to report the status of the device 
          in terms of if the device is bus or self powered and if it supports 
          remote wakeup. In our device we report it as self powered and as not 
          supporting remote wakeup. </P>
          <P>Of the Device Feature requests, this device doesn't support 
          DEVICE_REMOTE_WAKEUP nor TEST_MODE and return a USB Request Error as a 
          result. </P><PRE>                    case SET_ADDRESS:
                        printf("Set Address\n\r");
                        DeviceAddress = SetupPacket.wValue | 0x80;
                        D11WriteEndpoint(D11_ENDPOINT_EP0_IN, NULL, 0);
                        CtlTransferInProgress = PROGRESS_ADDRESS;
                        break;
</PRE>
          <P>The Set Address command is the only command that continues to be 
          processed after the status stage. All other commands must finish 
          processing before the status stage. The device address is read and 
          OR'ed with 0x80 and stored in a variable DeviceAddress. The OR'ing 
          with 0x80 is specific to the PDIUSBD11 with the most significant bit 
          indicating if the device is enabled or not. A zero length packet is 
          returned as status to the host indicating the command is complete. 
          However the host must send an IN Token, retrieve the zero length 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -