Simple USBHost library for Nucleo F446RE/F411RE/F401RE FRDM-KL46Z/KL25Z/F64F LPC4088/LPC1768

Dependencies:   FATFileSystem

Dependents:   F401RE-BTstack_example F401RE-USBHostMSD_HelloWorld

Fork of KL46Z-USBHost by Norimasa Okamoto

簡易USBホストライブラリです。
official-USBHostの下位互換で対応プログラムを僅かな修正で動かすことが出来ます。

Platforms

  • Nucleo F446RE
  • Nucleo F411RE
  • Nucleo F401RE
  • FRDM-K64F
  • FRDM-KL46Z
  • FRDM-KL25Z
  • LPC4088
  • LPC1768

Nucleo F446RE/F411RE/F401REのUSB接続方法

ST morphoUSB
U5V (CN10-8)VBUS (1 RED)
PA11 (CN10-14)DM  (2 WHITE)
PA12 (CN10-12)DP  (3 GREEN)
GND (CN10-20)GND (4 BLACK)

Examples

Import programF446RE-USBHostMouse_HelloWorld

USBHostMouse Hello World for ST-Nucleo-F446RE

Import programF401RE-USBHostMSD_HelloWorld

Simple USBHost MSD(USB flash drive) for Nucleo F401RE/FRDM-KL46Z test program

Import programF401RE-USBHostC270_example

Simple USBHost WebCam test program

Import programK64F_USBHostC270_example

Simple USBHost C270 example

Import programF401RE-BTstack_example

BTstack for Nucleo F401RE/FRDM-KL46Z example program

Import programUSBHostRSSI_example

Bluetooth device discovery example program.

Import programKL46Z-USBHostGPS_HelloWorld

Simple USBHost GPS Dongle Receiver for FRDM-KL46Z test program

USBHost/USBHALHost_LPC4088.h

Committer:
va009039
Date:
2014-07-01
Revision:
18:61554f238584

File content as of revision 18:61554f238584:

/* mbed USBHost Library
 * Copyright (c) 2006-2013 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
#pragma once
#include "mbed.h"
#include "rtos.h"
#include "USBHostTypes.h"
#include "USBEndpoint.h"

#if defined(TARGET_LPC4088)
#define HcRevision      Revision
#define HcControl       Control
#define HcCommandStatus CommandStatus
#define HcInterruptStatus InterruptStatus
#define HcInterruptEnable InterruptEnable
#define HcHCCA          HCCA
#define HcControlHeadED ControlHeadED
#define HcBulkHeadED    BulkHeadED
#define HcFmInterval    FmInterval
#define HcFmNumber      FmNumber
#define HcPeriodicStart PeriodicStart
#define HcRhStatus      RhStatus
#define HcRhPortStatus1 RhPortStatus1
#define OTGStCtrl       StCtrl
#endif
// ------------------ HcControl Register ---------------------
#define  OR_CONTROL_PLE                 0x00000004
#define  OR_CONTROL_IE                  0x00000008
#define  OR_CONTROL_CLE                 0x00000010
#define  OR_CONTROL_BLE                 0x00000020
#define  OR_CONTROL_HCFS                0x000000C0
#define  OR_CONTROL_HC_OPER             0x00000080
// ----------------- HcCommandStatus Register -----------------
#define  OR_CMD_STATUS_HCR              0x00000001
#define  OR_CMD_STATUS_CLF              0x00000002
#define  OR_CMD_STATUS_BLF              0x00000004
// --------------- HcInterruptStatus Register -----------------
#define  OR_INTR_STATUS_WDH             0x00000002
#define  OR_INTR_STATUS_UE              0x00000010
#define  OR_INTR_STATUS_FNO             0x00000020
#define  OR_INTR_STATUS_RHSC            0x00000040
// --------------- HcInterruptEnable Register -----------------
#define  OR_INTR_ENABLE_WDH             0x00000002
#define  OR_INTR_ENABLE_FNO             0x00000020
#define  OR_INTR_ENABLE_RHSC            0x00000040
#define  OR_INTR_ENABLE_MIE             0x80000000
// ---------------- HcRhDescriptorA Register ------------------
#define  OR_RH_STATUS_LPSC              0x00010000
#define  OR_RH_STATUS_DRWE              0x00008000
// -------------- HcRhPortStatus[1:NDP] Register --------------
#define  OR_RH_PORT_CCS                 0x00000001
#define  OR_RH_PORT_PRS                 0x00000010
#define  OR_RH_PORT_LSDA                0x00000200
#define  OR_RH_PORT_CSC                 0x00010000
#define  OR_RH_PORT_PRSC                0x00100000

// TRANSFER DESCRIPTOR CONTROL FIELDS
#define  TD_ROUNDING     (uint32_t)(0x00040000) /* Buffer Rounding */
#define  TD_SETUP        (uint32_t)(0x00000000) /* Direction of Setup Packet */
#define  TD_IN           (uint32_t)(0x00100000) /* Direction In */
#define  TD_OUT          (uint32_t)(0x00080000) /* Direction Out */
#define  TD_DELAY_INT(x) (uint32_t)((x) << 21)  /* Delay Interrupt */
#define  TD_DI           (uint32_t)(7<<21)      /* desable interrupt */
#define  TD_TOGGLE_0     (uint32_t)(0x02000000) /* Toggle 0 */
#define  TD_TOGGLE_1     (uint32_t)(0x03000000) /* Toggle 1 */
#define  TD_CC           (uint32_t)(0xF0000000) /* Completion Code */

void* usb_ram_malloc(size_t size, int aligment); // USBHALHost2_LPC4088.cpp
void usb_ram_free(void* p);

struct TBUF {
    uint8_t buf[0];
    TBUF(const void* data = NULL, int size = 0);
    void* operator new(size_t size, int buf_size) { return usb_ram_malloc(size+buf_size, 4); }
    void operator delete(void* p) { usb_ram_free(p); }
};

class HCED;

struct HCTD {    // HostController Transfer Descriptor
    __IO uint32_t Control;    // +0 Transfer descriptor control
    __IO uint8_t* CurrBufPtr; // +4 Physical address of current buffer pointer
    HCTD* Next;               // +8 Physical pointer to next Transfer Descriptor
    uint8_t*  BufEnd;         // +12 Physical address of end of buffer
    uint8_t* buf_top;         // +16 Buffer start address
    uint16_t buf_size;        // +20 buffer size size
    uint8_t _dummy[10];       // +22 dummy
    HCED* parent;             // +32 HCED object
                              // +36
    HCTD(HCED* ed);
    void* operator new(size_t size) { return usb_ram_malloc(size, 16); }
    void operator delete(void* p) { usb_ram_free(p); }

    void transfer(TBUF* tbuf, int len) {
        CurrBufPtr = tbuf->buf;
        buf_top = tbuf->buf;
        buf_size = len;
        BufEnd = const_cast<uint8_t*>(tbuf->buf)+len-1;
    }
    int getLengthTransferred() {
        if (CurrBufPtr) {
            return CurrBufPtr - buf_top;
        }
        return buf_size;
    }
    int status() {
        if (CurrBufPtr) {
            return CurrBufPtr - buf_top;
        }
        return buf_size;
    }
    
    uint8_t ConditionCode() {
        return Control>>28;
    }    
}; 

struct HCITD {    // HostController Isochronous Transfer Descriptor
    __IO uint32_t Control;      // +0 Transfer descriptor control
    uint8_t*  BufferPage0;      // +4 Buffer Page 0
    HCITD* Next;                // +8 Physical pointer to next Isochronous Transfer Descriptor
    uint8_t*  BufferEnd;        // +12 buffer End
    __IO uint16_t OffsetPSW[8]; // +16 Offset/PSW
    HCED* parent;               // +32 HCED object
    __IO uint8_t buf[0];        // +36 buffer
                                // +36
    HCITD(HCED* ed, uint16_t FrameNumber, int FrameCount, uint16_t PacketSize);
    uint8_t* Buffer(int fc);
    void* operator new(size_t size, int buf_size) { return usb_ram_malloc(size+buf_size, 32); }
    void operator delete(void* p) { usb_ram_free(p); }

    uint16_t StartingFrame() {
        return Control & 0xffff;
    }

    uint8_t FrameCount() {
        return ((Control>>24)&7)+1;
    }    

    uint8_t ConditionCode() {
        return Control>>28;
    }

    uint8_t ConditionCode(int fc) {
        uint16_t psw = OffsetPSW[fc];
        return psw>>12;
    }

    uint16_t Length(int fc) {
        uint16_t psw = OffsetPSW[fc];
        return psw & 0x7ff;
    }
};

#define HCTD_QUEUE_SIZE 3

struct HCED {    // HostController EndPoint Descriptor
    __IO uint32_t Control; // +0 Endpoint descriptor control
    HCTD* TailTd;          // +4 Physical address of tail in Transfer descriptor list
    __IO HCTD* HeadTd;     // +8 Physcial address of head in Transfer descriptor list
    HCED* Next;            // +12 Physical address of next Endpoint descriptor
                           // +16
    uint8_t m_ConditionCode;
    Queue<HCTD, HCTD_QUEUE_SIZE> _done_queue; // TD done queue
    struct {
        uint8_t queue_count;
        uint8_t queue_limit;
        uint16_t FrameNumber;
        uint8_t FrameCount; // 1-8
        HCITD* Current_itd;
        uint8_t Current_FrameCount;
    } iso;
    inline osEvent done_queue_get(uint32_t millisec) { return _done_queue.get(millisec); }
    inline void irqWdhHandler(HCTD* td) {_done_queue.put(td);} // WDH
    HCTD* get_queue_HCTD(uint32_t millisec=osWaitForever);
    HCITD* get_queue_HCITD();
    HCITD* new_HCITD();
    HCED(USBEndpoint* ep);
    void* operator new(size_t size) { return usb_ram_malloc(size, 16); }
    void operator delete(void* p) { usb_ram_free(p); }

    uint8_t FunctionAddress() {
        return Control & 0x7f;
    }

    uint8_t EndpointNumber() {
        return (Control>>7) & 0x7f;
    }

    int Speed() {
        return (Control>>13)&1;
    }

    void setFunctionAddress(int addr) {
        Control &= ~0x7f;
        Control |= addr;
    }

    void setMaxPacketSize(uint16_t size) {
        Control &= ~0x07ff0000;
        Control |= size<<16;
    }

    uint16_t getMaxPacketSize() {
        return (Control>>16)&0x7ff;
    }

    void setToggle(uint8_t toggle);
    uint8_t getToggle();

    int Skip() {
        return (Control>>14) & 1;
    }

    void setSkip() {
        Control |= (1<<14);
    }

    void setFormat() {
        Control |= (1<<15);
    }

    bool enqueue(HCTD* td);
    void init_queue(HCTD* td);
};

struct HCCA {    // Host Controller Communication Area
    HCED* InterruptTable[32]; // +0 Interrupt Table
    __IO uint16_t FrameNumber;// +128 Frame Number
    __IO uint16_t Pad1;       // +130
    __IO HCTD* DoneHead;      // +132 Done Head
    uint8_t Reserved[116];    // +136 Reserved for future use
    uint8_t Unknown[4];       // +252 Unused
                              // +256
    void* operator new(size_t size) { return usb_ram_malloc(size, 256); }
    void operator delete(void* p) { usb_ram_free(p); }
    void enqueue(HCED* ed);
};

class USBHALHost {
protected:
    USBHALHost();
    void init();
    virtual bool addDevice(USBDeviceConnected* parent, int port, bool lowSpeed) = 0;
    int token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength = 0);
    int token_iso_in(USBEndpoint* ep, uint8_t* data, int size);
    int multi_token_in(USBEndpoint* ep, uint8_t* data = NULL, int size = 0);
    int multi_token_out(USBEndpoint* ep, const uint8_t* data = NULL, int size = 0);
    void multi_token_inNB(USBEndpoint* ep, uint8_t* data, int size);
    USB_TYPE multi_token_inNB_result(USBEndpoint* ep);
    void setToggle(USBEndpoint* ep, uint8_t toggle);

    // report
    uint32_t m_report_irq; 
    uint32_t m_report_RHSC;
    uint32_t m_report_FNO; 
    uint32_t m_report_WDH;  
    uint32_t m_report_sp;

private:
    void init_hw_ohci(HCCA* pHcca);
    void ResetRootHub();
    void token_init(USBEndpoint* ep);
    static void _usbisr(void);
    void UsbIrqhandler();
    HCCA* m_pHcca;
    bool wait_attach();
    bool root_lowSpeed;
    static USBHALHost * instHost;
};