Library to use Arduino USB host shield on mbed

Dependents:   USBHOST_PS5

ArduinoのUSB Host Shield 2.0をmbedで使えるようにしたライブラリです。
大体のコードがArduinoからそのまま移植可能です。

Arduino UNOやMega用のホストシールド以外にもミニサイズのホストシールドでも使用可能です https://os.mbed.com/media/uploads/kotakku/dffgfddswa.png

シールドについて

3.3VのI/O用にシールドの改造が必要になりますがネット上に記事がたくさんあるのでそちらを参考にしてください

接続例

https://os.mbed.com/media/uploads/kotakku/esgsvfvhjrekldkcjxvb.png

使い方

Arduinoのコードと違うのはUSBのインスタンスの宣言部分のみです。
ピンを自分で指定できるようにしたので使いやすくなりました。

仕様

  • Arduinoのmillis関数、micros関数の移植のために内部でTimerクラスを使用しています。

main.cpp

#include "mbed.h"
#include <PS3BT.h>
#include <usbhub.h>

Serial pc(USBTX, USBRX, 115200);

//Nucleo f303k8用
USB Usb(A6, A5, A4, A3, A2); // mosi, miso, sclk, ssel, intr
BTD Btd(&Usb);
PS3BT PS3(&Btd);

int main()
{
    bool printAngle = false;

    if (Usb.Init() == -1)
    {
        pc.printf("\r\nOSC did not start");
        while (1); // Halt
    }
    pc.printf("\r\nPS3 USB Library Started");

    while (1)
    {
        Usb.Task();
        
        if (PS3.PS3Connected || PS3.PS3NavigationConnected) {
            if (PS3.getAnalogHat(LeftHatX) > 137 || PS3.getAnalogHat(LeftHatX) < 117 || PS3.getAnalogHat(LeftHatY) > 137 || PS3.getAnalogHat(LeftHatY) < 117 || PS3.getAnalogHat(RightHatX) > 137 || PS3.getAnalogHat(RightHatX) < 117 || PS3.getAnalogHat(RightHatY) > 137 || PS3.getAnalogHat(RightHatY) < 117)
            {
                pc.printf("\r\nLeftHatX: %d", PS3.getAnalogHat(LeftHatX));
                pc.printf("\tLeftHatY: %d", PS3.getAnalogHat(LeftHatY));
                if (PS3.PS3Connected)
                { // The Navigation controller only have one joystick
                    pc.printf("\tRightHatX: %d", PS3.getAnalogHat(RightHatX));
                    pc.printf("\tRightHatY: %d", PS3.getAnalogHat(RightHatY));
                }
            }
            // Analog button values can be read from almost all buttons
            if (PS3.getAnalogButton(L2) || PS3.getAnalogButton(R2))
            {
                pc.printf("\r\nL2: %d", PS3.getAnalogButton(L2));
                if (!PS3.PS3NavigationConnected)
                {
                    pc.printf("\tR2: %d", PS3.getAnalogButton(R2));
                }
            }
            if (PS3.getButtonClick(PS))
            {
                PS3.disconnect();
                pc.printf("\r\nPS");
            }
    
            if (PS3.getButtonClick(TRIANGLE))
                pc.printf("\r\nTriangle");
            if (PS3.getButtonClick(CIRCLE))
                pc.printf("\r\nCircle");
            if (PS3.getButtonClick(CROSS))
                pc.printf("\r\nCross");
            if (PS3.getButtonClick(SQUARE))
                pc.printf("\r\nSquare");
    
            if (PS3.getButtonClick(UP))
            {
                pc.printf("\r\nUp");
                PS3.setLedOff();
                PS3.setLedOn(CONTROLLER_LED4);
            }
            if (PS3.getButtonClick(RIGHT))
            {
                pc.printf("\r\nRight");
                PS3.setLedOff();
                PS3.setLedOn(CONTROLLER_LED1);
            }
            if (PS3.getButtonClick(DOWN))
            {
                pc.printf("\r\nDown");
                PS3.setLedOff();
                PS3.setLedOn(CONTROLLER_LED2);
            }
            if (PS3.getButtonClick(LEFT))
            {
                pc.printf("\r\nLeft");
                PS3.setLedOff();
                PS3.setLedOn(CONTROLLER_LED3);
            }
    
            if (PS3.getButtonClick(L1))
                pc.printf("\r\nL1");
            if (PS3.getButtonClick(L3))
                pc.printf("\r\nL3");
            if (PS3.getButtonClick(R1))
                pc.printf("\r\nR1");
            if (PS3.getButtonClick(R3))
                pc.printf("\r\nR3");
    
            if (PS3.getButtonClick(SELECT))
            {
                pc.printf("\r\nSelect - ");
                PS3.printStatusString();
            }
            if (PS3.getButtonClick(START))
            {
                pc.printf("\r\nStart");
                printAngle = !printAngle;
            }
            if (printAngle)
            {
                pc.printf("\r\nPitch: %.3lf", PS3.getAngle(Pitch));
                pc.printf("\tRoll: %.3lf", PS3.getAngle(Roll));
            }
        }
        else
        {
            pc.printf("not connect\n");
        }
    }
}

USB_Host/usbhost.cpp

Committer:
robo_ichinoseki_a
Date:
2020-05-02
Revision:
1:da31140f2a1c
Parent:
0:b1ce54272580

File content as of revision 1:da31140f2a1c:

#include "Usb.h"
#include "usbhost.h"

//#define DEBUGMODE
#ifdef DEBUGMODE
#define DEBUG(x, ...) printf("[%s:%d]" x "\n", __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
#define DEBUG(...) while (0);
#endif



/* constructor */
MAX3421E::MAX3421E(PinName mosi, PinName miso, PinName sclk, PinName ssel, PinName intr) : SPI(mosi, miso, sclk), _ss(ssel), _intr(intr)
{
    _ss = 1;
    
    //_spi.mode = SPI_MODE_MASTER;
    format(8, 0);
    frequency(26000000);
}

/* write single byte into MAX3421 register */
void MAX3421E::regWr(uint8_t reg, uint8_t data)
{
    uint8_t c[2];

    _ss = 0;

    c[0] = reg | 0x02;
    c[1] = data;
    
    SPI::write(c[0]);
    SPI::write(c[1]);
    
    //HAL_SPI_Transmit(&SPI_Handle, c, 2, HAL_MAX_DELAY);
    DEBUG("-              wirte %2x, %2x\n", c[0], c[1]);
    
    //DEBUG("w %d, %d\n", c[0], c[1]);
    
    _ss = 1;
}

/* multiple-byte write                            */

/* returns a pointer to memory position after last written */
uint8_t *MAX3421E::bytesWr(uint8_t reg, uint8_t nbytes, uint8_t *data_p)
{
    //uint8_t data = reg | 0x02;

    _ss = 0;
    
    uint8_t data = reg | 0x02;
    
    SPI::write(data);
    while (nbytes)
    {
        SPI::write(*data_p);
        nbytes--;
        data_p++; // advance data pointer
    }

    _ss = 1;
    return data_p;
}
/* GPIO write */
/*GPIO byte is split between 2 registers, so two writes are needed to write one byte */
/* GPOUT bits are in the low nibble. 0-3 in IOPINS1, 4-7 in IOPINS2 */

void MAX3421E::gpioWr(uint8_t data)
{
    regWr(rIOPINS1, data);
    data >>= 4;
    regWr(rIOPINS2, data);
    return;
}

/* single host register read    */

uint8_t MAX3421E::regRd(uint8_t reg)
{
    _ss = 0;
    
    SPI::write(reg);
    uint8_t rv = SPI::write(0);

    DEBUG("-              read %2x\n", rv);
    _ss = 1;

    return rv;
}
/* multiple-byte register read  */

/* returns a pointer to a memory position after last read   */
uint8_t *MAX3421E::bytesRd(uint8_t reg, uint8_t nbytes, uint8_t *data_p)
{
    _ss = 0;
    

    SPI::write(reg);
    memset(data_p, 0, nbytes);
    while (nbytes)
    {
        *data_p = SPI::write(0);
        data_p++;
        nbytes--;
    }
    
    _ss = 1;

    return data_p;
}

/* GPIO read. See gpioWr for explanation */

/** @brief  Reads the current GPI input values
*   @retval uint8_t Bitwise value of all 8 GPI inputs
*/
/* GPIN pins are in high nibbles of IOPINS1, IOPINS2    */

uint8_t MAX3421E::gpioRd()
{
    uint8_t gpin = 0;
    gpin = regRd(rIOPINS2);         //pins 4-7
    gpin &= 0xf0;                   //clean lower nibble
    gpin |= (regRd(rIOPINS1) >> 4); //shift low bits and OR with upper from previous operation.
    return (gpin);
}

/** @brief  Reads the current GPI output values
*   @retval uint8_t Bitwise value of all 8 GPI outputs
*/
/* GPOUT pins are in low nibbles of IOPINS1, IOPINS2    */

uint8_t MAX3421E::gpioRdOutput()
{
    uint8_t gpout = 0;
    gpout = regRd(rIOPINS1);         //pins 0-3
    gpout &= 0x0f;                   //clean upper nibble
    gpout |= (regRd(rIOPINS2) << 4); //shift high bits and OR with lower from previous operation.
    return (gpout);
}

/* reset MAX3421E. Returns number of cycles it took for PLL to stabilize after reset
  or zero if PLL haven't stabilized in 65535 cycles */

uint16_t MAX3421E::reset()
{
    uint16_t i = 0;
    regWr(rUSBCTL, bmCHIPRES);
    regWr(rUSBCTL, 0x00);
    while (++i)
    {
        if ((regRd(rUSBIRQ) & bmOSCOKIRQ))
        {
            break;
        }
    }
    return (i);
}

/* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */

int8_t MAX3421E::Init()
{
    XMEM_ACQUIRE_SPI();
    // Moved here.
    // you really should not init hardware in the constructor when it involves locks.
    // Also avoids the vbus flicker issue confusing some devices.
    /* pin and peripheral setup */

    _ss = 1;

    XMEM_RELEASE_SPI();
    /* MAX3421E - full-duplex SPI, level interrupt */
    // GPX pin on. Moved here, otherwise we flicker the vbus.
    regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL));

    if (reset() == 0)
    { //OSCOKIRQ hasn't asserted in time
        return (-1);
    }

    regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host

    regWr(rHIEN, bmCONDETIE | bmFRAMEIE); //connection detection

    /* check if device is connected */
    regWr(rHCTL, bmSAMPLEBUS); // sample USB bus
    while (!(regRd(rHCTL) & bmSAMPLEBUS))
        ; //wait for sample operation to finish

    busprobe(); //check if anything is connected

    regWr(rHIRQ, bmCONDETIRQ); //clear connection detect interrupt
    regWr(rCPUCTL, 0x01);      //enable interrupt pin

    return (0);
}

/* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */

int8_t MAX3421E::Init(int mseconds)
{
    XMEM_ACQUIRE_SPI();
    // Moved here.
    // you really should not init hardware in the constructor when it involves locks.
    // Also avoids the vbus flicker issue confusing some devices.
    /* pin and peripheral setup */

    _ss = 1;

    XMEM_RELEASE_SPI();
    /* MAX3421E - full-duplex SPI, level interrupt, vbus off */
    regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL | GPX_VBDET));

    if (reset() == 0)
    { //OSCOKIRQ hasn't asserted in time
        return (-1);
    }

    // Delay a minimum of 1 second to ensure any capacitors are drained.
    // 1 second is required to make sure we do not smoke a Microdrive!
    if (mseconds < 1000)
        mseconds = 1000;
    delay(mseconds);

    regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host

    regWr(rHIEN, bmCONDETIE | bmFRAMEIE); //connection detection

    /* check if device is connected */
    regWr(rHCTL, bmSAMPLEBUS); // sample USB bus
    while (!(regRd(rHCTL) & bmSAMPLEBUS))
        ; //wait for sample operation to finish

    busprobe(); //check if anything is connected

    regWr(rHIRQ, bmCONDETIRQ); //clear connection detect interrupt
    regWr(rCPUCTL, 0x01);      //enable interrupt pin

    // GPX pin on. This is done here so that busprobe will fail if we have a switch connected.
    regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL));

    return (0);
}

/* probe bus to determine device presence and speed and switch host to this speed */

void MAX3421E::busprobe()
{
    uint8_t bus_sample;
    DEBUG("busprobe()\n");
    bus_sample = regRd(rHRSL);             //Get J,K status
    bus_sample &= (bmJSTATUS | bmKSTATUS); //zero the rest of the byte
    switch (bus_sample)
    { //start full-speed or low-speed host
    case (bmJSTATUS):
        if ((regRd(rMODE) & bmLOWSPEED) == 0)
        {
            regWr(rMODE, MODE_FS_HOST); //start full-speed host
            vbusState = FSHOST;
        }
        else
        {
            regWr(rMODE, MODE_LS_HOST); //start low-speed host
            vbusState = LSHOST;
        }
        break;
    case (bmKSTATUS):
        if ((regRd(rMODE) & bmLOWSPEED) == 0)
        {
            regWr(rMODE, MODE_LS_HOST); //start low-speed host
            vbusState = LSHOST;
        }
        else
        {
            regWr(rMODE, MODE_FS_HOST); //start full-speed host
            vbusState = FSHOST;
        }
        break;
    case (bmSE1): //illegal state
        vbusState = SE1;
        break;
    case (bmSE0): //disconnected state
        regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST | bmSEPIRQ);
        vbusState = SE0;
        break;
    } //end switch( bus_sample )
}

/* MAX3421 state change task and interrupt handler */

uint8_t MAX3421E::Task(void)
{
    uint8_t rcode = 0;
    uint8_t pinvalue;
    //USB_HOST_SERIAL.print("Vbus state: ");
    //USB_HOST_SERIAL.println( vbusState, HEX );

    pinvalue = _intr.read();

    //pinvalue = digitalRead( MAX_INT );
    if (pinvalue == 0)
    {
        rcode = IntHandler();
    }
    //    pinvalue = digitalRead( MAX_GPX );
    //    if( pinvalue == LOW ) {
    //        GpxHandler();
    //    }
    //    usbSM();                                //USB state machine
    return (rcode);
}

uint8_t MAX3421E::IntHandler()
{
    uint8_t HIRQ;
    uint8_t HIRQ_sendback = 0x00;

    DEBUG("IntHandler\n");
    HIRQ = regRd(rHIRQ); //determine interrupt source
    //if( HIRQ & bmFRAMEIRQ ) {               //->1ms SOF interrupt handler
    //    HIRQ_sendback |= bmFRAMEIRQ;
    //}//end FRAMEIRQ handling
    if (HIRQ & bmCONDETIRQ)
    {
        busprobe();
        HIRQ_sendback |= bmCONDETIRQ;
    }
    // End HIRQ interrupts handling, clear serviced IRQs
    regWr(rHIRQ, HIRQ_sendback);
    return (HIRQ_sendback);
}