This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430F5505: USB drawing too much power in LPM3

Part Number: MSP430F5505
Other Parts Discussed in Thread: CC2640

Greetings.

I am having difficulty getting LPM3 to significantly reduce my current consumption when enabling the USB subsystem (but not having anything plugged into the USB port) with my MSP430F5505.

The simplified version of my code that causes the excess current drain is:

WDT_A_hold(WDT_A_BASE); // Stop watchdog timer
PMM_setVCore(PMM_CORE_LEVEL_2);

USBHAL_initPorts();           // Config GPIOS for low-power (output low)
USBHAL_initClocks(8000000);   // Config clocks. MCLK=SMCLK=FLL=8MHz; ACLK=REFO=32kHz
USB_init( );

while( 1 )
{
    __bis_SR_register(LPM3_bits + GIE);
    _NOP();
}

If I comment out USB_init(), the MCU draws nearly 1mA less than when it is uncommented.

Inside of USB_init(), the call to USB_determineXT2Freq( ) is what causes the higher current drain, presumably because it starts up the XT2 oscillator.  I have a 12MHz crystal on the Xt2 pins.

I even tried calling USB_disconnect( ) and USB_disable( ) after calling USB_init( ), but it didn't help.

Any ideas on how to reduce the current drain in LPM3?

Thank you

Scott Wild

  • Hi Scott,

    There are several parts of the USB power system (3.3v LDO, 1.8v LDO) and the USBPLL that contribute to the overall power consumption.  The USBPLL is by far the largest, up to 7mA.  So what are you trying to do?  You are trying to initialize the USB but don't want the XT2 operating? Perhaps some more details about the application might be helpful.

  • Hi Dennis.

    This application is for a battery powered BLE wireless sensor that also has a USB port in case someone wants to communicate over a USB cable (and also to charge the battery).  The BLE processor is a CC2640.  The MSP430 is mostly a USB to serial converter that talks to the CC2640 via a UART. Refer to pasco.com for our wireless sensor product line.

    We previously used the NXP LPC11U14 as the USB processor, but we are redesigning with the MSP430 due to NXP chip shortages.

    I have the USB communication working properly, but unfortunately a 1mA drain for an idle USB processor (i.e. no USB cable plugged in) is a little excessive for our small batteries.  The NXP part only consumed a few tens of uA when it was idle.

    The MSP430 specs say that LPM3 should only draw a few uA.  I just wanted to know how to achieve that when the USB port is disconnected.  Your documentation states that calling USB_disconnect( ) and USB_disable( ) when VBus is removed should put the USB IP into a low power state after going into LPM3, but I am not seeing that.  My sample code is just the simplest case for duplicating the problem.

    Thank you

    Scott Wild

  • Hi Scott,

    Got it.  I kind of assumed it was a battery powered application.

    Ok, referring to page 16 in SLAA457, Starting a USB Design Using MSP430, how would you describe your power configuration?

    You obviously operate from battery as your primary source so I'm assuming you have an LDO for the MSP430 DVCC, correct?

    You enable the 3.3V LDO and 1.8V LDO only when the connection to a USB host is detected, correct?

    When connected to the host, do you switch power from your batteries to the MSP430's  VUSB (+3.3V)?

    The function USB_disable shows it does disable the PLL.  So if you call this function you don't see the current drop significantly?

  • Also, feel free to post your code and I can take a look.

  • Hi Dennis.

    You are correct.  I have a 3.7V LiPo driving a 3.3V LDO which always drives the AVCC/DVCC pins.  This is the case even when I plug in a USB cable (i.e. VBUS = +5V) -- I do not use the VUSB LDO output.

    In my real code, I call USB_setup( false, true ) at powerup which calls USB_init( ) but does not call USB_enable( ).  When I detect VBUS, I call USB_enable( ) and USB_connect( ) to start communicating.  When I detect VBUS removal, I call USB_disconnect( ) and USB_disable( ) to turn off the USB core.

    The current measurement isn't really useful when the USB cable is plugged in because it starts charging the battery which gives me a large negative current reading.  When the USB cable is not plugged in (VBUS = 0V), the current consumption is a little under 1mA, regardless of whether USB_disable( ) or USB_enable( ) has been called.

    Here is my actual code (a work in progress...)

    #include <string.h>
    
    #include "driverlib.h"
    
    #include "USB_config/descriptors.h"
    #include "USB_API/USB_Common/device.h"
    #include "USB_API/USB_Common/usb.h"                 // USB-specific functions
    #include "USB_API/USB_Common/defMSP430USB.h"
    #include "PascoUSBSensor.h"
    #include <msp430.h>
    
    /*
     * NOTE: Modify hal.h to select a specific evaluation board and customize for
     * your own board.
     */
    #include "hal.h"
    
    // Global flags set by events
    volatile uint8_t bCDCDataReceived_event = FALSE;  // Flag set by event handler to 
                                                   // indicate data has been 
                                                   // received into USB buffer
    
    #define VERSION_MAJOR 2
    #define VERSION_MINOR 0
    
    //#define BUFFER_SIZE 256
    //char dataBuffer[BUFFER_SIZE] = "";
    //char nl[2] = "\n";
    //uint16_t count;
    
    #define EP0_BUF_SIZE 0x400
    uint8_t usbEP0Buf[EP0_BUF_SIZE];
    
    // Endpoint descriptors
    extern __no_init tEDB __data16 tInputEndPointDescriptorBlock[];
    extern __no_init tEDB __data16 tOutputEndPointDescriptorBlock[];
    tEDB *ep2in = &tInputEndPointDescriptorBlock[1];
    tEDB *ep3out = &tOutputEndPointDescriptorBlock[2];
    uint8_t *ep2inBuf = (uint8_t *)START_OF_USB_BUFFER;
    uint8_t *ep3outBuf = (uint8_t *)(START_OF_USB_BUFFER + MAX_PACKET_SIZE);
    
    bool allowSync = false;
    bool doVendorRequest = false;
    int DoVendorRequest( );
    
    #define UART_FIFO_SIZE                  0x100
    #define MAX_UART_PACKET_SIZE            0x50
    #define PACKET_HDR_REQUEST              0x6d
    #define PACKET_HDR_ACK                  0x3e
    #define PACKET_CMD_DATA                 0x01    // Send OUT packet to BLE module or recv IN data from BLE module
    #define PACKET_CMD_SYNC                 0x02    // Send current USB frame to BLE module
    #define PACKET_CMD_PRODUCT_ID           0x03    // Module tells us what its product ID is
    
    unsigned char uartFifoBuf[UART_FIFO_SIZE];
    unsigned char uartPacketBuf[MAX_UART_PACKET_SIZE + 10];
    #define uartRecvCmd uartPacketBuf[1]
    #define uartRecvSize uartPacketBuf[2]
    uint8_t uartPacketCount = 0;
    bool uartTxdAvailable = true;   // True if we can send a new packet to the BLE module
    bool uartRxdAvailable = false;  // True if we have recvd a packet from the BLE module
    uint8_t *uartFifoTail = uartFifoBuf;
    uint8_t *uartFifoWrap = uartFifoBuf + UART_FIFO_SIZE;
    
    bool doingBleBootloadRequest = false;
    bool bleBootloadWaitForAck = false;
    bool bleBootloadGotAck = false;
    int bleBootloadResponseSize = 0;
    int bleBootloadResponseSoFar = 0;
    int bleBootloadChecksum = 0;
    volatile uint32_t tickCountMS = 0;
    uint32_t uartAckTimeout = 0;
    
    bool isConnectedToPascoApp = false;
    bool hasVBus = false;
    
    uint8_t OnVendorOutDone(void);
    void PollUsbInterrupt( );
    void PollForTransfer( );
    void PollForUartPackets( );
    void ResetBLEModule( bool bootMode );
    
    #define LED_PIN GPIO_PORT_P1, GPIO_PIN1
    #define CONN_PIN GPIO_PORT_P6, GPIO_PIN3
    #define BT_RESET_PIN GPIO_PORT_P1, GPIO_PIN7
    #define FORCE_BOOT_PIN GPIO_PORT_P1, GPIO_PIN2
    #define UART_TX_PIN GPIO_PORT_P4, GPIO_PIN4
    #define UART_RX_PIN GPIO_PORT_P4, GPIO_PIN5
    #define SetForceBootLoad( mode ) if( mode ) GPIO_setOutputHighOnPin( FORCE_BOOT_PIN ); else GPIO_setOutputLowOnPin( FORCE_BOOT_PIN )
    #define DriveResetPin( drive ) if( drive ) GPIO_setAsOutputPin( BT_RESET_PIN ); else GPIO_setAsInputPinWithPullUpResistor( BT_RESET_PIN )
    #define SetIsUsbConnected( connected ) if( connected ) GPIO_setOutputHighOnPin( CONN_PIN ); else GPIO_setOutputLowOnPin( CONN_PIN )
    #define SetLED( on ) if( on ) GPIO_setAsOutputPin( LED_PIN ); else GPIO_setAsInputPin( LED_PIN )
    
    #define CONN_PIN_OBSOLETE GPIO_PORT_P6, GPIO_PIN0
    #define SetConnObsolete( mode ) if( mode ) GPIO_setOutputHighOnPin( CONN_PIN_OBSOLETE ); else GPIO_setOutputLowOnPin( CONN_PIN_OBSOLETE )
    
    //**************************************************************************************
    //
    //**************************************************************************************
    void main (void)
    {
        WDT_A_hold(WDT_A_BASE); // Stop watchdog timer
    
        // Minimum Vcore setting required for the USB API is PMM_CORE_LEVEL_2 .
        PMM_setVCore(PMM_CORE_LEVEL_2);
    
        USBHAL_initPorts();           // Config GPIOS for low-power (output low)
        USBHAL_initClocks(8000000);   // Config clocks. MCLK=SMCLK=FLL=16MHz; ACLK=REFO=32kHz
    
        // Init USB & events, but don't connect until we detect Vbus
        USB_setup( false, true );
    
        // Set up UART for 8N1 500KBaud
        #define BRG_PRE 2
        #define BRG_MOD1 0
        #define BRG_MOD2 0
        USCI_A_UART_initParam params = {USCI_A_UART_CLOCKSOURCE_SMCLK, BRG_PRE, BRG_MOD1, BRG_MOD2, USCI_A_UART_NO_PARITY, USCI_A_UART_LSB_FIRST,
                                        USCI_A_UART_ONE_STOP_BIT, USCI_A_UART_MODE, USCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION};
        USCI_A_UART_init( USCI_A1_BASE, &params );
        USCI_A_UART_enableInterrupt( USCI_A1_BASE, USCI_A_UART_RECEIVE_INTERRUPT );
        USCI_A_UART_enable( USCI_A1_BASE );
        GPIO_setAsPeripheralModuleFunctionOutputPin( UART_TX_PIN );
        GPIO_setAsPeripheralModuleFunctionInputPin( UART_RX_PIN );
    
        // Set up initial GPIO
        GPIO_setAsOutputPin( CONN_PIN );
        GPIO_setAsOutputPin( FORCE_BOOT_PIN );
        GPIO_setDriveStrength( LED_PIN, GPIO_FULL_OUTPUT_DRIVE_STRENGTH );
        GPIO_setOutputLowOnPin( BT_RESET_PIN ); // for simulating open-drain by switching port direction.
        GPIO_setOutputLowOnPin( LED_PIN );
        SetForceBootLoad( false );
        SetLED( false );
        SetIsUsbConnected( false );
        DriveResetPin( false );
    
        GPIO_setAsOutputPin( CONN_PIN_OBSOLETE );
        SetConnObsolete( true );
    
        // Set up DMA to continuously transfer recvd data into the uart recv fifo
        DMA1SAL = (uint16_t)&UCA1RXBUF; //__data16_write_addr( (unsigned short)&DMA1SA, (unsigned long)&UCA0RXBUF );   // DMA from the UART Rx register
        DMA1DAL = (uint16_t)uartFifoBuf; // __data16_write_addr( (unsigned short)&DMA1DA, (unsigned long)uartFifoBuf );  // DMA to the UART fifo buffer
        DMA1SZ = UART_FIFO_SIZE;
        DMACTL0 |= DMA1TSEL__USCIA1RX; // DMA channel 1 triggers on UART Receive
        DMA1CTL = DMAEN | DMADT2 | DMASRCBYTE | DMADSTBYTE | DMADSTINCR_3 | DMALEVEL; // Enable byte xfers with stationary src ptr and auto-incrementing dest ptr and level triggered
    
        // Set up Timer A to count up every ms
        TA0CTL = TASSEL__SMCLK | MC__UP | ID__8 | TAIE; // SMCLK, Count up to CCR0, div 8 (2MHz count),
        TA0CCTL0 = CCIE; // Compare interrupt
        TA0CCR0 = 2000; // 1ms interrupt @ 2 MHz count
    
        // Set up USB EP2IN and ep3OUT for USB to Serial
        ep2in->bEPCNF = EPCNF_UBME; // Enable EP2 single buffer
        ep3out->bEPCNF = EPCNF_UBME; // Enable EP2 single buffer
    
        __enable_interrupt();  // Enable interrupts globally
    
        while (1)
        {
            // Check the USB state and directly main loop accordingly
            int connState = USB_getConnectionState();
            switch (connState)
            {
                // This case is executed while your device is enumerated on the USB host
                case ST_ENUM_ACTIVE:
                    PollForUartPackets( );
                    PollForTransfer( );
    
                    // Handle vendor requests in main loop context
                    if( doVendorRequest )
                    {
                        int result = DoVendorRequest( );
    
                        // Errors will stall the endpoint
                        if( result == -1 )
                            usbStallEndpoint0();
                        // If returning data on an IN endpoint, do it here
                        else if( result > 0 )
                            usbSendDataPacketOnEP0( usbEP0Buf );
                        // If processing an OUT transaction, return status IN packet when done
                        else if( !(tSetupPacket.bmRequestType & USB_REQ_TYPE_INPUT) )
                            usbSendZeroLengthPacketOnIEP0( );
                        doVendorRequest = false;
                    }
                    break;
                    
                // These cases are executed while your device is disconnected from
                // the host (meaning, not enumerated); enumerated but suspended
                // by the host, or connected to a powered hub without a USB host
                // present.
                case ST_PHYS_DISCONNECTED:
                case ST_ENUM_SUSPENDED:
                case ST_PHYS_CONNECTED_NOENUM_SUSP:
                    break;
    
                // The default is executed for the momentary state
                // ST_ENUM_IN_PROGRESS.  Usually, this state only last a few
                // seconds.  Be sure not to enter LPM3 in this state; USB
                // communication is taking place here, and therefore the mode must
                // be LPM0 or active-CPU.
                case ST_ENUM_IN_PROGRESS:
                default:;
            }
    
            // If we connected or disconnected from USB cable, let BM10 know.
            if( connState == ST_PHYS_DISCONNECTED && hasVBus )
            {
                hasVBus = false;
                SetIsUsbConnected( false );
                USB_disconnect( );
                USB_disable( );
            }
            else if( connState != ST_PHYS_DISCONNECTED && !hasVBus )
            {
                hasVBus = true;
                USB_enable( );
                USB_reset( );
                USB_connect( );
                SetIsUsbConnected( true );
            }
    
            // If VBus is removed, we can go to sleep
            if( !hasVBus )
            {
                __bis_SR_register(LPM3_bits + GIE);
                _NOP();
            }
    
        }  //while(1)
    }
    
    //**************************************************************************************
    // 1ms Timer handler
    //**************************************************************************************
    #pragma vector=TIMER0_A0_VECTOR
    __interrupt void HandleTimerAInterrupt( void )
    {
        tickCountMS++;
    
        // Blink green LED to indicate running bootloader
    //    if( (tickCountMS & 0xff) == 0 )
    //        SetLED( false );
    //    else if( (tickCountMS & 0xff) == 0x80 )
    //        SetLED( true );
    
        TA0CTL &= ~TAIFG;
    }
    
    //***************************************************************************
    // wait the requested number of ms
    //***************************************************************************
    void Delay_MS( int ms )
    {
        uint32_t timeout = tickCountMS + ms;
        while( tickCountMS < timeout )
            continue;
    }
    
    //***************************************************************************
    // Does a blocking write to the UART
    //***************************************************************************
    void UartWrite( const void *dataIn, int len )
    {
        const uint8_t *data = (const uint8_t *)dataIn;
        while( len-- )
            USCI_A_UART_transmitData( USCI_A1_BASE, *data++ );
    }
    
    //***************************************************************************
    // Called when EP0 OUT data transfer has completed
    //***************************************************************************
    uint8_t OnVendorOutDone(void)
    {
        // We can now process the request since we have al of the data
        doVendorRequest = true;
        return true;
    }
    
    //***************************************************************************
    // Handles the reception of a SETUP packet in interrupt context
    //***************************************************************************
    uint8_t HandleVendorSetupRequest( void )
    {
        // If EP0 IN (read) request
        if( tSetupPacket.bmRequestType & USB_REQ_TYPE_INPUT )
        {
            // Zero-byte reads are invalid
            if( tSetupPacket.wLength == 0 )
                usbStallEndpoint0();
            else // Return the read data in the main loop context
                doVendorRequest = true;
        }
        // If zero-data EP0 OUT (write), we are ready to process it
        else if( tSetupPacket.wLength == 0 )
            doVendorRequest = true;
        // Make sure the write isn't too big
        else if( tSetupPacket.wLength > EP0_BUF_SIZE )
            usbStallEndpoint0();
        else // Fetch the data being written
            usbReceiveDataPacketOnEP0( usbEP0Buf );
        return true;
    }
    
    //**************************************************************************************
    // UART packet parser
    //**************************************************************************************
    void PollForUartPackets( )
    {
        uint8_t *uartFifoHead = (uint8_t *)DMA1DA + UART_FIFO_SIZE - DMA1SZ;
        int count = (uartFifoHead - uartFifoTail) & (UART_FIFO_SIZE - 1);
    
        // Safety check
        if( count > 0x100 || count < 0 )
            return;
    
        // If we got a recv data byte
        while( count-- )
        {
            uint8_t data = *uartFifoTail++;
            if( uartFifoTail >= uartFifoWrap )
                uartFifoTail = uartFifoBuf;
    
            // If we are processing CC26XX ROM bootloader responses
            if( doingBleBootloadRequest )
            {
                // If waiting for an ACK to the last packet we sent
                if( bleBootloadWaitForAck )
                {
                    if( data == 0xcc || data == 0x33 )
                    {
                        bleBootloadWaitForAck = false;
                        bleBootloadGotAck = (data == 0xcc);
                    }
                }
                else // Looking for a response packet
                {
                    // The first non-zero byte of the packet is its size
                    if( bleBootloadResponseSize == 0 && data != 0 )
                        bleBootloadResponseSize = data;
    
                    // If we are expecting more data in the packet, place it in the USB EP0 buffer
                    if( bleBootloadResponseSize != 0 && bleBootloadResponseSoFar < bleBootloadResponseSize )
                    {
                        if( bleBootloadResponseSoFar >= 2 )
                            bleBootloadChecksum += data;
                        usbEP0Buf[bleBootloadResponseSoFar++] = data;
                    }
                }
            }
            else // This is a Pasco BLE/USB packet
            {
                // If we have not yet started a packet, look for the packet header signature byte
                if( uartPacketCount == 0 )
                {
                    // If we got an ACK for the last packet we sent to the BLE module
                    if( data == PACKET_HDR_ACK )
                    {
                        uartTxdAvailable = true;
                        continue;
                    }
                    // Ignore everything until we get to the beginning of a packet
                    else if( data != PACKET_HDR_REQUEST )
                        continue;
                }
    
                if( uartPacketCount < MAX_UART_PACKET_SIZE )
                {
                    uartPacketBuf[uartPacketCount++] = data;
    
                    // If we got a complete packet
                    if( uartPacketCount >= 3 && uartPacketCount >= uartRecvSize + 3 )
                    {
                        uartPacketCount = 0;
                        uartRxdAvailable = true;
                    }
                }
                else // Something is wrong, look for a new packet
                    uartPacketCount = 0;
            }
        }
    }
    
    //***************************************************************************
    // See if any packets need to be transferred between
    //***************************************************************************
    void PollForTransfer( )
    {
        // If we have not received an ACK within 100ms of our last packet
        // sent to the BLE module, assume there is a problem and ignore it
        if( !uartTxdAvailable && tickCountMS > uartAckTimeout )
            uartTxdAvailable = true;
    
        // If we are able to send a new packet to the BLE module
        if( uartTxdAvailable )
        {
            // If we have a new USB packet to send to the BLE module
            if( ep3out->bEPBCTX & EPBCNT_NAK )
            {
                // Get the received USB packet size
                uint16_t actual = ep3out->bEPBCTX & EPBCNT_BYTECNT_MASK;
                if( actual > 0 )
                {
                    if( actual > MAX_UART_PACKET_SIZE - 3 )
                        actual = MAX_UART_PACKET_SIZE - 3;
    
                    // Forward the packet to the BLE module
                    uartTxdAvailable = false;
                    uint8_t hdr[3] = { PACKET_HDR_REQUEST, PACKET_CMD_DATA, actual };
                    UartWrite( hdr, 3 );
                    UartWrite( ep3outBuf, actual );
                    ep3out->bEPBCTX = 0;
    
                    // Wait up to 100ms for ACK
                    uartAckTimeout = tickCountMS + 100;
                }
    
                // Prepare to read another USB packet from EP3OUT
                ep3out->bEPBCTX = 0;
            }
        }
    
        // If we have recvd a new packet from the BLE module
        if( uartRxdAvailable )
        {
            // If the BLE module is sending us packets, it can accept periodic sync packets
            allowSync = true;
    
            // Indicate that we've processed the packet from the BLE module
            uartRxdAvailable = false;
    
            // If we recvd a BLE packet that needs to be sent to the host via USB
            if( uartRecvCmd == PACKET_CMD_DATA )
            {
                // If the USB IN endpoint can accept new data
                if( ep2in->bEPBCTX & EPBCNT_NAK )
                {
                    // Give data to the USB host
                    memcpy( ep2inBuf, &uartPacketBuf[3], uartRecvSize );
                    ep2in->bEPBCTX = uartRecvSize;
                }
                else // Cannot send data to host, so keep trying until we can
                    uartRxdAvailable = true;
            }
            // Tell the BLE module that we've processed the packet and can now accept a new one
            if( !uartRxdAvailable )
            {
                uint8_t ack = PACKET_HDR_ACK;
                UartWrite( &ack, 1 );
            }
        }
    }
    
    //***************************************************************************
    //
    //***************************************************************************
    void ResetBLEModule( bool bootMode )
    {
        // Setting these pins high will force the BM10 into its ROM bootloader so we can upgrade firmware.
        SetForceBootLoad( bootMode );
    
        // Toggle reset to BM10 by driving the reset pin and then tri-stating it
        DriveResetPin( true );
        Delay_MS( 10 );
        DriveResetPin( false );
        Delay_MS( 500 );
    
        // Clear the force-bootloader pins
        SetForceBootLoad( false );
    }
    
    //***************************************************************************
    //
    //***************************************************************************
    static void SetUsbIsConnected( bool isConnected )
    {
        // Set the signal telling the BM10 whether we are communicating via USB
        SetIsUsbConnected( isConnected );
    
        // Give the BM10 a little time to prepare for USB communications and send a
        // no-op over to flush out any left over UART chars.
        if( isConnected )
        {
            uint8_t zero[10];
            memset( zero, 0, sizeof( zero ) );
            Delay_MS( 10 );
            UartWrite( zero, sizeof( zero ) );
            Delay_MS( 10 );
        }
    }
    
    //**************************************************************************************
    //
    //**************************************************************************************
    int DoVendorRequest( )
    {
        // Get actual product ID
        if( tSetupPacket.bRequest == PASCO_USB_SENSOR_GET_FAUX_USB_PRODUCT_ID )
        {
            *(uint16_t *)usbEP0Buf = 1029; // *DEBUG* Wireless Smart Cart
            return 2;
        }
    
        // Get USB Bridge firmware version
        else if( tSetupPacket.bRequest == PASCO_USB_SENSOR_GET_FIRMWARE_VERSION )
        {
            strcpy( (char *)usbEP0Buf, "  FUsbBridge2 " __DATE__ " " __TIME__ );
            usbEP0Buf[0] = VERSION_MAJOR;
            usbEP0Buf[1] = VERSION_MINOR;
            return strlen( (const char *)&usbEP0Buf[2] ) + 2;
        }
    
        // Read/Write memory
        else if( tSetupPacket.bRequest == PASCO_USB_SENSOR_LOAD_FIRMWARE )
        {
            unsigned long addr = tSetupPacket.wValue | ((unsigned long)tSetupPacket.wIndex << 16);
    
            // If reading memory
            if( tSetupPacket.bmRequestType & USB_REQ_TYPE_INPUT )
            {
                // Prepare a packet of data to be sent to the host
                memcpy( usbEP0Buf, (const void *)addr, tSetupPacket.wLength );
                return tSetupPacket.wLength;
            }
            else // Writing memory
            {
                // Get the data that was sent by the host
                memcpy( (void *)addr, usbEP0Buf, tSetupPacket.wLength );
                return 0;
            }
        }
    
        // Miscellaneous requests
        else if( tSetupPacket.bRequest == PASCO_USB_SENSOR_ACCESS_HARDWARE )
        {
            int subRequest = tSetupPacket.wIndex >> 8;
    
            // Allow app to tell BM10 whether it wants to communicate via USB
            if( subRequest == PASPORT_HW_SET_USB_BLE_ENABLE )
            {
                SetUsbIsConnected( tSetupPacket.wValue == 0 );
                return 0;
            }
    
            // Complete a USB IN request to unblock any readers
            else if( subRequest == PASPORT_HW_COMPLETE_USB_IN )
            {
                ep2in->bEPBCTX = 0;
                ep2in->bEPBCTY = 0;
                return 0;
            }
    
            // Go into the bootloader
            else if( subRequest == PASPORT_HW_GO_BOOT_LOADER )
            {
                allowSync = false;
    
                // Go into our own bootloader
                if( tSetupPacket.wValue == 0 )
                {
    // todo: figure this out
    //                #define RAM_BASE_ADDR 0x10000000
    //                *(uint32_t *)RAM_BASE_ADDR = FORCE_BOOT_SIG;
    //                UsbDisconnect( );
    //                NVIC_SystemReset( );
    //                result = 0;
                }
    
                // Try forcing the BLE module into CC26xx ROM bootloader mode as force boot mode
                else if( tSetupPacket.wValue == 2 )
                {
                    ResetBLEModule( true );
                    return 0;
                }
            }
    
            // Reset the BLE module to run its main firmware
            else if( subRequest == PASPORT_HW_RESET_BOARD )
            {
                ResetBLEModule( false );
                return 0;
            }
    
            // Read/write the CC26XX ROM bootlader via the UART to write firmware to the CC26XX
            else if( subRequest == PASPORT_HW_RW_TI_BOOTLOADER )
            {
                allowSync = false;
    
                // Reading response from CC26xx ROM bootloader
                if( tSetupPacket.bmRequestType & USB_REQ_TYPE_INPUT )
                {
                    if( tSetupPacket.wLength > bleBootloadResponseSize )
                        tSetupPacket.wLength = bleBootloadResponseSize;
                    return tSetupPacket.wLength;
                }
                else
                {
                    //todo: Need to find a way to stall the endpoint upon failure
                    bool success = true;
    
                    // Prep for request and response
                    bleBootloadResponseSize = 0;
                    bleBootloadResponseSoFar = 0;
                    doingBleBootloadRequest = true;
                    bleBootloadWaitForAck = true;
                    bleBootloadGotAck = false;
                    bleBootloadChecksum = 0;
    
                    // Send the request to the CC26xx ROM bootloader
                    UartWrite( usbEP0Buf, tSetupPacket.wLength );
    
                    // Wait up to 0.5 second for an ack
                    uint32_t timeout = tickCountMS + 500;
                    while( tickCountMS < timeout )
                        if( !bleBootloadWaitForAck )
                            break;
    
                    // If we didn't get an ACK, indicate an error occurred
                    if( bleBootloadWaitForAck || !bleBootloadGotAck )
                        success = false;
    
                    // If we got an ACK and we are expecting a response, wait for the response
                    else if( tSetupPacket.wValue != 0 )
                    {
                        // Wait up to 0.5 second for a response
                        uint32_t timeout = tickCountMS + 500;
                        while( tickCountMS < timeout )
                            if( bleBootloadResponseSize && bleBootloadResponseSoFar == bleBootloadResponseSize )
                                break;
    
                        bool timedOut = tickCountMS >= timeout;
                        bool checksumValid = bleBootloadResponseSize > 2 && (bleBootloadChecksum & 0xff) == usbEP0Buf[1];
    
                        // If we got a response, ack/nack it based on checksum validity
                        if( !timedOut )
                        {
                            unsigned char ack = checksumValid ? 0xcc : 0x33;
                            UartWrite( &ack, 1 );
                        }
    
                        // Indicate error if we timed out waiting for a response
                        success = (!timedOut && checksumValid);
                    }
                    else // No response requested, so we're good to go
                        success = true;
    
                    doingBleBootloadRequest = false;
    
                    return success ? 0 : -1;
                }
            }
        }
    
        return -1;
    }
    
    //**************************************************************************************
    //
    //**************************************************************************************
    uint8_t HandleEP2InInterrupt( void )
    {
        return FALSE;
    }
    
    //**************************************************************************************
    //
    //**************************************************************************************
    uint8_t HandleEP3OutInterrupt( void )
    {
        return FALSE;
    }
    
    //**************************************************************************************
    // NMI handler
    //**************************************************************************************
    #if defined(__TI_COMPILER_VERSION__) || (__IAR_SYSTEMS_ICC__)
    #pragma vector = UNMI_VECTOR
    __interrupt void UNMI_ISR (void)
    #elif defined(__GNUC__) && (__MSP430__)
    void __attribute__ ((interrupt(UNMI_VECTOR))) UNMI_ISR (void)
    #else
    #error Compiler not found!
    #endif
    {
        switch (__even_in_range(SYSUNIV, SYSUNIV_BUSIFG ))
        {
            case SYSUNIV_NONE:
                __no_operation();
                break;
            case SYSUNIV_NMIIFG:
                __no_operation();
                break;
            case SYSUNIV_OFIFG:
                UCS_clearFaultFlag(UCS_XT2OFFG);
                UCS_clearFaultFlag(UCS_DCOFFG);
                SFR_clearInterrupt(SFR_OSCILLATOR_FAULT_INTERRUPT);
                break;
            case SYSUNIV_ACCVIFG:
                __no_operation();
                break;
            case SYSUNIV_BUSIFG:
                // If the CPU accesses USB memory while the USB module is
                // suspended, a "bus error" can occur.  This generates an NMI.  If
                // USB is automatically disconnecting in your software, set a
                // breakpoint here and see if execution hits it.  See the
                // Programmer's Guide for more information.
                SYSBERRIV = 0; // clear bus error flag
                USB_disable(); // Disable
        }
    }
    
    //Released_Version_5_20_06_02
    

    Thank you

    Scott

  • Hello again

    As an additional data point, when I perform the same experiment on my MSP-TS430RGC64USB eval board, I see the same thing.  When USB is initialized but not enabled (USB_init( ), USB_disable( )), I see ~700uA current drain in LPM3.  When I don't call USB_init( ), I only see 170uA in LPM3.

    Thank you

    Scott

  • Hello again again

    One more additional data point:

    If I try turning off the USB LDOs and the XT2 oscillator after USB_init( ), the current drops a little (~500uA), but not back down to the ~170uA I see when I don't call USB_Init( ) at all.

        USB_init();                    // Init USB & events; if a host is present, connect
    
        // Disable USB LDOs
        USBKEYPID  = 0x9628;
        USBPWRCTL  = 0;
        USBKEYPID  = 0x9600;
    
        // Turn of XT2
        HWREG16(UCS_BASE + OFS_UCSCTL6) |= XT2OFF;
    

    Also, it seems like 170uA is still pretty high for LPM3 since the datasheet says it should be < 10uA.  Any ideas what I might be doing wrong?

    Thank you

    Scott

  • Hi Scott,

    If you are running code in debug mode you will see about 170-180uA contribution. If I don't call USB_init() and go straight into LPM3, I measure 5uA.  When I disable the USB module (LDO_3.3=off and LDO_1.8 = off), XT2 off and PLL off, I see about 500uA without the debugger.  I'm looking into this.

  • Hi Dennis.

    It looks like XT2 was a red herring.  The problem occurred because USB_determineXT2Freq( ) did not disable the timer when it was done detecting the XT2 frequency.  Once I added TIMER_CTL = 0; to the end of the detection loop, the current draw dropped by around 500uA.

    Thank you for the help

    Scott

**Attention** This is a public forum