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.
We have just designed a product using MSP430F5529.
I am having some trouble getting the unit to run reliably when no USB is present. I'll explain:
1) We are always powered through the USB connector; there is no other power source for the board.
2) However, it may not be plugged into a computer, we have purchased a small wall-wart that has a USB connector on it.
3) This way the customer can use our device without a computer, it will perform its functions stand-alone.
The trouble I'm having is that the unit does not start up reliably (fails 9 out of 10 times) in this mode. I have traced through the code and enabled and disabled various parts of the code. What I have found is that when USB_Connect is called it goes into never-never land; I don't even see a clock output from the device. My suspicion is that it is stuck somewhere waiting for numeration (which will never happen), has possibly entered a low power mode or something like that.
I feel like I need to have a time-out somewhere that waits for enumeration and gives up after a while.
I've been looking at this for a couple days and would appreciate any suggestions that folks may have.
Thanks.
Mike
Hi Mike,
If I understand this right - you are trying to power the device from the USB connector (from a wall-wart that has the USB connector on it) but dont want to not use the USB module as such - since its not connected to any host. Is this the case?
In this case, you could disable the VbusOnEvent or comment out the function calls (USB_enable(), USB_connect()) inside the USB_handleVbusOnEvent function in the usb_eventHandling.c file. This way the device will not try to enumerate in the first place.
Regards,
Bhargavi
Bhargavi,
Thank you very much for your response. I have seen your name in many of the MSP430F552x code examples.
I think I have not made my problem clear.
I need to be able to deal with either case: USB or no USB. I do not know which one I have until the power comes up and I start executing code. So, what I think I need to do is attempt enumeration but then drop out after a period of time and function as a stand-alone device.
Thanks.
Mike
This is interesting:
I had a scope probe on some of the signals to see what they looked like in USB and non-USB modes. Having a scope probe hanging on DP (i.e. right on the processor) lets my code execute in the non-USB mode (on the charger). I'm not sure what it means but it seems important to me.
Mike
Hi Mike,
The different USB states are described in the MSP430 USB CDC/HID Programmer's Guide. Find attached screen shot of the state diagram that reflects Device's Interaction with USB bus.
According to the state diagram, when enumeration is triggered by the device (by calling the USB_connect() function which pulls PUR up), the USB_connectionState() function is either in ST_USB_CONNECTED_NO_ENUM (USB is connected, but not enumerated - PUR not pulled high) or ST_ENUM_IN_PROGRESS (Enumeration in progress - state when PUR is pulled high but the device is not enumerated). Here is my thought - you could place a counter in USB_connectionState() function under these states and when it exceeds a certain number of times, you decide there is no host connected to the device. The counter value may not match enumeration attempts as the USB_connectionState() function is called inside a while(1) loop in main.c and would keep executing when not in any ISR/LPM.
Regards,
Bhargavi,
Thank you for your continued help.
Yes, I am quite familiar with the state diagram. I tried a scheme as you suggest. I combined those two states in main:
case ST_ENUM_IN_PROGRESS:
case ST_USB_CONNECTED_NO_ENUM:
if (enum_counter++ > 200)
{
USB_disconnect();
}
break;
It seemed that this would be the same as putting the code in USB_connectionState but I will try it there too.
Through some trial and error I found that the counter reaches a max of about 120 when connected to the computer. This translates to about 120 ms.
I will also go back to the EVM board with the straight CDC example 1 code and try the same thing.
I will again reiterate that I feel the micro goes into some kind of suspend or low-power mode while it is waitng for enumeration and it is pulled out of this mode only when it gets enumerated. So, putting in a counter is fine but the code that checks the counter never gets executed.
Mike
Bhargavi,
I went back into the USBCDC_Example1 project and made one change, I added a line in the while (1) loop to keep the LED on all the time:
while(1)
{
P1OUT |= BIT0; // Turn on LED P1.0 Mike Unger
BYTE i;
// Check the USB state and directly main loop accordingly
switch(USB_connectionState())
{
case ST_USB_DISCONNECTED:
__bis_SR_register(LPM3_bits + GIE); // Enter LPM3 w/ interrupts enabled
_NOP(); // For Debugger
break;
It acts the same way, when powered by the computer all is well, the LED comes on and stays on. When powered through the USB connector through our charger, never comes on.
Maybe someone else can try this same experiment and figure out what is happening.
Thanks.
Mike
I am still at a loss to figure out how to proceed with this. Do you have any other ideas Bhargavi? Have you worked on the USB CDC code? If not would it be possible to get in touch with the person that did? One thought I had is whether it is possible to look at the DP and DM lines after power-up and try to determine a computer is connected or not. The register USBPHYCTL has control bits for treating DP and DM as regular inputs. Do you think I can make a determination by looking at these bits if there is a computer connected or not?
Thanks.
Mike
Hi Mike,
Reg. the LED not coming ON when powered by USB connector and not host: The LED turn on statement is in the main while loop and I would think that the main while loop in main.c has to be executed regardless of if device is connected to the host or not - unless its stuck in some ISR continuously.
When you start execution of the code on the device, is the Vbus already powered by the USB power connector? Or is the power connector connected to the board after the execution begins? I ask this because in case the USB power connector is initially connected to the board, then the USB_handleVbusOnEvent(); is called before the while(1) is entered and in case USB power connector is connected to board later, the device will execute the LED turn on statement and then be in LPM3 under the ST_USB_DISCONNECTED state and plugging in the power connector causes the Vbuson interrupt.
I dont have USB wall-wart connector, so I have brought out the Vbus pin on the USB connector on-board and am providing 5V to this pin. And I dont see this problem. I am able to execute code within the main while loop when Vbus is supplied by the host or the DC power supply.
Is it possible you share your main C code, so that I can take a look at it?
Regards,
Bhargavi
Hi Mike,
Like I mentioned before, I dont have the USB wall-wart connecter, so I am doing all my tests (that involves connecting to USB wall-wart) on my end by connecting the Vbus pin of the USB connector on-board to a 5V DC power supply.
I placed a count variable that increments within the states "ST_ENUM_IN_PROGRESS" and "ST_NOENUM_SUSPENDED". The USB_connectionState() function in usb.c checks for various conditions and determines which connection state the device is in. The conditions for "ST_ENUM_IN_PROGRESS" are - USBBGVBV set in USBPWRCTL, PUREN set in USBCNF and enumeration not complete. And all these conditions along with IsDeviceSuspended checked for "ST_NOENUM_SUSPENDED". According to my tests the device gets USB suspend interrupt when the device was not connected host and the Vbus=5V was provided from DC power supply. And I believe this happens because the USB module sees no activity on D+/D- lines for 3ms and so an USB suspend interrupt occurs. So I had incremented the count variable within the ""ST_NOENUM_SUSPENDED" state in main while loop.
For proper enumeration when connected to a host, the counter variable counts upto around 20000 counts and so I placed an if condition with in "ST_ENUM_IN_PROGRESS" and "ST_NOENUM_SUSPENDED" states to trap the device in while(1) loop when count exceeds 20k x 5 = 100000counts. And I tried using this to enumerate the device (while connected to PC) many times and it passes all the time. Also, when I connected the VBUS to 5V supply (not a host), then the device gets trapped within the if condition (> 100000) in ST_NOENUM_SUSPENDED state.
Find attached the main.c file (of USBCDC_Example1) used to test this. Since your test set-up is different from what I have here, it would be good to check if you see something similar with your test set-up as well.
Regards,
Bhargavi
// (c)2009 by Texas Instruments Incorporated, All Rights Reserved. /*----------------------------------------------------------------------------+ | | | Texas Instruments | | | | MSP430 USB-Example (CDC/HID Driver) | | | +-----------------------------------------------------------------------------+ | Source: main.c, v1.19 2009/19/11 | ------------------------------------------------------------------------------+ LED Control Demo: This USB demo example is to be used with a PC application (e.g. HyperTerminal) This demo application is used to control the operation of the LED at P1.0 Typing the following pharses in the HyperTerminal Window does the following 1. "LED ON" Turns on the LED and returns "LED is ON" phrase to PC 2. "LED OFF" Turns off the LED and returns "LED is OFF" back to HyperTerminal 3. "LED TOGGLE - SLOW" Turns on the timer used to toggle LED with a large period and returns "LED is toggling slowly" phrase back to HyperTerminal 4. "LED TOGGLE - FAST" Turns on the timer used to toggle LED with a smaller period and returns "LED is toggling fast" phrase back to HyperTerminal +----------------------------------------------------------------------------+ Please refer to "USB CDC API Demo Examples Guide.pdf" for more details //----------------------------------------------------------------------------*/ #include "Common\device.h" #include "Common\types.h" // Basic Type declarations #include ".\USB_Common\descriptors.h" #include "USB_Common\usb.h" // USB-specific functions #include "main.h" #include "Common\hal_UCS.h" #include "Common\hal_pmm.h" #ifdef _CDC_ #include "USB_CDC_API\UsbCdc.h" #endif #ifdef _HID_ #include "USB_HID_API\UsbHid.h" #endif #include <intrinsics.h> #include <string.h> #include "USBCDC_constructs.h" #include "main.h" volatile BYTE bDataReceived_event = FALSE; // Indicates data has been received without an open rcv operation volatile BYTE bDataReceiveCompleted_event = FALSE; // data receive completed event volatile BYTE bDataSendCompleted_event = FALSE; // data send completed event #define MAX_STR_LENGTH 64 char wholeString[MAX_STR_LENGTH] = ""; // The entire input string from the last 'return' unsigned int SlowToggle_Period = 20000-1; unsigned int FastToggle_Period = 1000-1; unsigned long Enum_Count =0; /*----------------------------------------------------------------------------+ | Main Routine | +----------------------------------------------------------------------------*/ VOID main(VOID) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer Init_StartUp(); //initialize device //Init_TimerA1(); USB_init(); // Enable various USB event handling routines USB_setEnabledEvents(kUSB_VbusOnEvent+kUSB_VbusOffEvent+kUSB_receiveCompletedEvent +kUSB_dataReceivedEvent+kUSB_UsbSuspendEvent+kUSB_UsbResumeEvent+kUSB_UsbResetEvent); // See if we're already attached physically to USB, and if so, connect to it // Normally applications don't invoke the event handlers, but this is an exception. if (USB_connectionInfo() & kUSB_vbusPresent) USB_handleVbusOnEvent(); Enum_Count =0; while(1) { BYTE i; // Check the USB state and directly main loop accordingly switch(USB_connectionState()) { case ST_USB_DISCONNECTED: __bis_SR_register(LPM3_bits + GIE); // Enter LPM3 w/ interrupts enabled _NOP(); // For Debugger break; case ST_USB_CONNECTED_NO_ENUM: //Enum_Count++; break; case ST_ENUM_ACTIVE: Enum_Count++; __bis_SR_register(LPM0_bits + GIE); // Enter LPM0 (can't do LPM3 when active) _NOP(); // For Debugger // Exit LPM on USB receive and perform a receive operation if(bDataReceived_event) // Some data is in the buffer; begin receiving a command { char pieceOfString[MAX_STR_LENGTH] = ""; // Holds the new addition to the string char outString[MAX_STR_LENGTH] = ""; // Holds the outgoing string // Add bytes in USB buffer to theCommand receiveDataInBuffer((BYTE*)pieceOfString,MAX_STR_LENGTH,1); // Get the next piece of the string strcat(wholeString,pieceOfString); // Add it to the whole sendData_inBackground((BYTE*)pieceOfString,strlen(pieceOfString),1,0); // Echoes back the characters received (needed for Hyperterm) if(retInString(wholeString)) // Has the user pressed return yet? { if(!(strcmp(wholeString, "LED ON"))) // Compare to string #1, and respond { TA1CTL &= ~MC_1; // Turn off Timer P1OUT |= BIT0; // Turn on LED P1.0 strcpy(outString,"\r\nLED is ON\r\n\r\n"); // Prepare the outgoing string sendData_inBackground((BYTE*)outString,strlen(outString),1,0); // Send the response over USB } else if(!(strcmp(wholeString, "LED OFF"))) // Compare to string #2, and respond { TA1CTL &= ~MC_1; // Turn off Timer P1OUT &= ~BIT0; // Turn off LED P1.0 strcpy(outString,"\r\nLED is OFF\r\n\r\n"); // Prepare the outgoing string sendData_inBackground((BYTE*)outString,strlen(outString),1,0); // Send the response over USB } else if(!(strcmp(wholeString, "LED TOGGLE - SLOW"))) // Compare to string #3, and respond { TA1CTL &= ~MC_1; // Turn off Timer TA1CCR0 = SlowToggle_Period; // Set Timer Period for slow LED toggle TA1CTL |= MC_1; // Start Timer strcpy(outString,"\r\nLED is toggling slowly\r\n\r\n"); // Prepare the outgoing string sendData_inBackground((BYTE*)outString,strlen(outString),1,0); // Send the response over USB } else if(!(strcmp(wholeString, "LED TOGGLE - FAST"))) // Compare to string #4, and respond { TA1CTL &= ~MC_1; // Turn off Timer TA1CCR0 = FastToggle_Period; // Set Timer Period for fast LED toggle TA1CTL |= MC_1; strcpy(outString,"\r\nLED is toggling fast\r\n\r\n"); // Prepare the outgoing string sendData_inBackground((BYTE*)outString,strlen(outString),1,0); // Send the response over USB } else // Handle other { strcpy(outString,"\r\nNo such command!\r\n\r\n"); // Prepare the outgoing string sendData_inBackground((BYTE*)outString,strlen(outString),1,0); // Send the response over USB } for(i=0;i<MAX_STR_LENGTH;i++) // Clear the string in preparation for the next one wholeString[i] = 0x00; } bDataReceived_event = FALSE; } break; case ST_ENUM_SUSPENDED: P1OUT &= ~BIT0; // When suspended, turn off LED __bis_SR_register(LPM3_bits + GIE); // Enter LPM3 w/ interrupts _NOP(); break; case ST_ENUM_IN_PROGRESS: Enum_Count++; if(Enum_Count > 100000) while(1); break; case ST_NOENUM_SUSPENDED: P1OUT &= ~BIT0; Enum_Count++; if(Enum_Count > 100000) while(1); //__bis_SR_register(LPM3_bits + GIE); _NOP(); break; case ST_ERROR: _NOP(); break; default:; } } // while(1) } //main() /*----------------------------------------------------------------------------+ | System Initialization Routines | +----------------------------------------------------------------------------*/ VOID Init_Clock(VOID) { //Initialization of clock module if (USB_PLL_XT == 2) { P5SEL |= 0x0C; // enable XT2 pins for F5529 //for F5529 // use REFO for FLL and ACLK UCSCTL3 = (UCSCTL3 & ~(SELREF_7)) | (SELREF__REFOCLK); UCSCTL4 = (UCSCTL4 & ~(SELA_7)) | (SELA__REFOCLK); Init_FLL(USB_MCLK_FREQ/1000, USB_MCLK_FREQ/32768); // set FLL (DCOCLK) XT2_Start(); } else { P5SEL |= 0x10; // enable XT1 pins UCSCTL3 = SELREF__REFOCLK; // run FLL mit REF_O clock UCSCTL4 = (UCSCTL4 & ~(SELA_7)) | (SELA__REFOCLK); // set ACLK = REFO Init_FLL(USB_MCLK_FREQ/1000, USB_MCLK_FREQ/32768); // set FLL (DCOCLK) XT1_Start(); } // SFRIE1 |= OFIFG; // Enable OscFault ISR } //---------------------------------------------------------------------------- VOID Init_Ports(VOID) { // Initialization of ports all unused pins as outputs with low-level // set all ports to low on all pins PAOUT = 0x0000; PASEL = 0x0000; PADIR = 0xFFFF; PBOUT = 0x0000; PBSEL = 0x0000; PBDIR = 0xFFFF; PCOUT = 0x0000; PCSEL = 0x0000; PCDIR = 0xFFFF; /* PDOUT = 0x0000; PDSEL = 0x0000; PDDIR = 0xFFFF; */ PJDIR = 0xFFFF; PJOUT = 0x0000; } //---------------------------------------------------------------------------- VOID Init_StartUp(VOID) { __disable_interrupt(); // Disable global interrupts Init_Ports(); // Init ports (do first ports because clocks do change ports) SetVCore(3); // USB core requires the VCore set to 1.8 volt, independ of CPU clock frequency Init_Clock(); __enable_interrupt(); // enable global interrupts } #pragma vector = UNMI_VECTOR __interrupt VOID UNMI_ISR(VOID) { switch (__even_in_range(SYSUNIV, SYSUNIV_BUSIFG)) { case SYSUNIV_NONE: __no_operation(); break; case SYSUNIV_NMIIFG: __no_operation(); break; case SYSUNIV_OFIFG: UCSCTL7 &= ~(DCOFFG+XT1LFOFFG+XT1HFOFFG+XT2OFFG); // Clear OSC flaut Flags fault flags SFRIFG1 &= ~OFIFG; // Clear OFIFG fault flag break; case SYSUNIV_ACCVIFG: __no_operation(); break; case SYSUNIV_BUSIFG: // If bus error occured - the cleaning of flag and re-initializing of USB is required. SYSBERRIV = 0; // clear bus error flag USB_disable(); // Disable } } // TimerA Init VOID Init_TimerA1(VOID) { TA1CCTL0 = CCIE; // CCR0 interrupt enabled TA1CTL = TASSEL_1 + TACLR; // ACLK, clear TAR } // This function returns true if there's an 0x0D character in the string; and if so, // it trims the 0x0D and anything that had followed it. BYTE retInString(char* string) { BYTE retPos=0,i,len; char tempStr[MAX_STR_LENGTH] = ""; strncpy(tempStr,string,strlen(string)); // Make a copy of the string len = strlen(tempStr); while((tempStr[retPos] != 0x0A) && (tempStr[retPos] != 0x0D) && (retPos++ < len)); // Find 0x0D; if not found, retPos ends up at len if((retPos<len) && (tempStr[retPos] == 0x0D)) // If 0x0D was actually found... { for(i=0;i<MAX_STR_LENGTH;i++) // Empty the buffer string[i] = 0x00; strncpy(string,tempStr,retPos); // ...trim the input string to just before 0x0D return TRUE; // ...and tell the calling function that we did so } else if((retPos<len) && (tempStr[retPos] == 0x0A)) // If 0x0D was actually found... { for(i=0;i<MAX_STR_LENGTH;i++) // Empty the buffer string[i] = 0x00; strncpy(string,tempStr,retPos); // ...trim the input string to just before 0x0D return TRUE; // ...and tell the calling function that we did so } else if (tempStr[retPos] == 0x0D) { for(i=0;i<MAX_STR_LENGTH;i++) // Empty the buffer string[i] = 0x00; strncpy(string,tempStr,retPos); // ...trim the input string to just before 0x0D return TRUE; // ...and tell the calling function that we did so } else if (retPos<len) { for(i=0;i<MAX_STR_LENGTH;i++) // Empty the buffer string[i] = 0x00; strncpy(string,tempStr,retPos); // ...trim the input string to just before 0x0D return TRUE; // ...and tell the calling function that we did so } return FALSE; // Otherwise, it wasn't found } // Timer1 A0 interrupt service routine #pragma vector=TIMER1_A0_VECTOR __interrupt void TIMER1_A0_ISR(void) { P1OUT ^= BIT0; // Toggle LED P1.0 } /*----------------------------------------------------------------------------+ | End of source file | +----------------------------------------------------------------------------*/ /*------------------------ Nothing Below This Line --------------------------*/
Bhargavi,
Thank you very much for your help with this. Those sound like some good ideas. I will give it a try on Tuesday (Monday is a holiday in Mass).
Mike
Bhargavi,
I am working on this today but don't have much to report yet.
To answer a couple questions from you:
Yes, when code starts executing Vbus is already atatched, the Vbus powers the device completley so there is no other power source. So, yes, I'd expect it to call USB_handleVbusOnEvent before it enters the while(1) loop.
Right now I am running just the example code to make sure that none of my code has any effect. I've enclosed the main.c that I am using, I had to make a couple minor changes as we have an oscillator on the TI demo board rather than a crystal.
Thanks.
Mike
// (c)2009 by Texas Instruments Incorporated, All Rights Reserved. /*----------------------------------------------------------------------------+ | | | Texas Instruments | | | | MSP430 USB-Example (CDC/HID Driver) | | | +-----------------------------------------------------------------------------+ | Source: main.c, v1.19 2009/19/11 | ------------------------------------------------------------------------------+ LED Control Demo: This USB demo example is to be used with a PC application (e.g. HyperTerminal) This demo application is used to control the operation of the LED at P1.0 Typing the following pharses in the HyperTerminal Window does the following 1. "LED ON" Turns on the LED and returns "LED is ON" phrase to PC 2. "LED OFF" Turns off the LED and returns "LED is OFF" back to HyperTerminal 3. "LED TOGGLE - SLOW" Turns on the timer used to toggle LED with a large period and returns "LED is toggling slowly" phrase back to HyperTerminal 4. "LED TOGGLE - FAST" Turns on the timer used to toggle LED with a smaller period and returns "LED is toggling fast" phrase back to HyperTerminal +----------------------------------------------------------------------------+ Please refer to "USB CDC API Demo Examples Guide.pdf" for more details //----------------------------------------------------------------------------*/ #include "Common\device.h" #include "Common\types.h" // Basic Type declarations #include ".\USB_Common\descriptors.h" #include "USB_Common\usb.h" // USB-specific functions #include "main.h" #include "Common\hal_UCS.h" #include "Common\hal_pmm.h" #ifdef _CDC_ #include "USB_CDC_API\UsbCdc.h" #endif #ifdef _HID_ #include "USB_HID_API\UsbHid.h" #endif #include <intrinsics.h> #include <string.h> #include "USBCDC_constructs.h" #include "main.h" volatile BYTE bDataReceived_event = FALSE; // Indicates data has been received without an open rcv operation volatile BYTE bDataReceiveCompleted_event = FALSE; // data receive completed event volatile BYTE bDataSendCompleted_event = FALSE; // data send completed event #define MAX_STR_LENGTH 64 char wholeString[MAX_STR_LENGTH] = ""; // The entire input string from the last 'return' unsigned int SlowToggle_Period = 20000-1; unsigned int FastToggle_Period = 1000-1; /*----------------------------------------------------------------------------+ | Main Routine | +----------------------------------------------------------------------------*/ VOID main(VOID) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer Init_StartUp(); //initialize device Init_TimerA1(); USB_init(); // Enable various USB event handling routines USB_setEnabledEvents(kUSB_VbusOnEvent+kUSB_VbusOffEvent+kUSB_receiveCompletedEvent +kUSB_dataReceivedEvent+kUSB_UsbSuspendEvent+kUSB_UsbResumeEvent+kUSB_UsbResetEvent); // See if we're already attached physically to USB, and if so, connect to it // Normally applications don't invoke the event handlers, but this is an exception. if (USB_connectionInfo() & kUSB_vbusPresent) USB_handleVbusOnEvent(); while(1) { BYTE i; // Check the USB state and directly main loop accordingly switch(USB_connectionState()) { case ST_USB_DISCONNECTED: __bis_SR_register(LPM3_bits + GIE); // Enter LPM3 w/ interrupts enabled _NOP(); // For Debugger break; case ST_USB_CONNECTED_NO_ENUM: break; case ST_ENUM_ACTIVE: __bis_SR_register(LPM0_bits + GIE); // Enter LPM0 (can't do LPM3 when active) _NOP(); // For Debugger // Exit LPM on USB receive and perform a receive operation if(bDataReceived_event) // Some data is in the buffer; begin receiving a command { char pieceOfString[MAX_STR_LENGTH] = ""; // Holds the new addition to the string char outString[MAX_STR_LENGTH] = ""; // Holds the outgoing string // Add bytes in USB buffer to theCommand receiveDataInBuffer((BYTE*)pieceOfString,MAX_STR_LENGTH,1); // Get the next piece of the string strcat(wholeString,pieceOfString); // Add it to the whole sendData_inBackground((BYTE*)pieceOfString,strlen(pieceOfString),1,0); // Echoes back the characters received (needed for Hyperterm) if(retInString(wholeString)) // Has the user pressed return yet? { if(!(strcmp(wholeString, "LED ON"))) // Compare to string #1, and respond { TA1CTL &= ~MC_1; // Turn off Timer P1OUT |= BIT0; // Turn on LED P1.0 strcpy(outString,"\r\nLED is ON\r\n\r\n"); // Prepare the outgoing string sendData_inBackground((BYTE*)outString,strlen(outString),1,0); // Send the response over USB } else if(!(strcmp(wholeString, "LED OFF"))) // Compare to string #2, and respond { TA1CTL &= ~MC_1; // Turn off Timer P1OUT &= ~BIT0; // Turn off LED P1.0 strcpy(outString,"\r\nLED is OFF\r\n\r\n"); // Prepare the outgoing string sendData_inBackground((BYTE*)outString,strlen(outString),1,0); // Send the response over USB } else if(!(strcmp(wholeString, "LED TOGGLE - SLOW"))) // Compare to string #3, and respond { TA1CTL &= ~MC_1; // Turn off Timer TA1CCR0 = SlowToggle_Period; // Set Timer Period for slow LED toggle TA1CTL |= MC_1; // Start Timer strcpy(outString,"\r\nLED is toggling slowly\r\n\r\n"); // Prepare the outgoing string sendData_inBackground((BYTE*)outString,strlen(outString),1,0); // Send the response over USB } else if(!(strcmp(wholeString, "LED TOGGLE - FAST"))) // Compare to string #4, and respond { TA1CTL &= ~MC_1; // Turn off Timer TA1CCR0 = FastToggle_Period; // Set Timer Period for fast LED toggle TA1CTL |= MC_1; strcpy(outString,"\r\nLED is toggling fast\r\n\r\n"); // Prepare the outgoing string sendData_inBackground((BYTE*)outString,strlen(outString),1,0); // Send the response over USB } else // Handle other { strcpy(outString,"\r\nNo such command!\r\n\r\n"); // Prepare the outgoing string sendData_inBackground((BYTE*)outString,strlen(outString),1,0); // Send the response over USB } for(i=0;i<MAX_STR_LENGTH;i++) // Clear the string in preparation for the next one wholeString[i] = 0x00; } bDataReceived_event = FALSE; } break; case ST_ENUM_SUSPENDED: P1OUT &= ~BIT0; // When suspended, turn off LED __bis_SR_register(LPM3_bits + GIE); // Enter LPM3 w/ interrupts _NOP(); break; case ST_ENUM_IN_PROGRESS: break; case ST_NOENUM_SUSPENDED: P1OUT &= ~BIT0; __bis_SR_register(LPM3_bits + GIE); _NOP(); break; case ST_ERROR: _NOP(); break; default:; } } // while(1) } //main() /*----------------------------------------------------------------------------+ | System Initialization Routines | +----------------------------------------------------------------------------*/ VOID Init_Clock(VOID) { //Initialization of clock module if (USB_PLL_XT == 2) { P5SEL |= 0x0C; // enable XT2 pins for F5529 //for F5529 // use REFO for FLL and ACLK UCSCTL3 = (UCSCTL3 & ~(SELREF_7)) | (SELREF__REFOCLK); UCSCTL4 = (UCSCTL4 & ~(SELA_7)) | (SELA__REFOCLK); Init_FLL(USB_MCLK_FREQ/1000, USB_MCLK_FREQ/32768); // set FLL (DCOCLK) UCSCTL6 |= XT1OFF; // MU XT2Bypass(); // MU //XT2_Start(); // MU } else { P5SEL |= 0x10; // enable XT1 pins UCSCTL3 = SELREF__REFOCLK; // run FLL mit REF_O clock UCSCTL4 = (UCSCTL4 & ~(SELA_7)) | (SELA__REFOCLK); // set ACLK = REFO Init_FLL(USB_MCLK_FREQ/1000, USB_MCLK_FREQ/32768); // set FLL (DCOCLK) // XT1_Start(); XT1Bypass(); //MU } // SFRIE1 |= OFIFG; // Enable OscFault ISR } //---------------------------------------------------------------------------- VOID Init_Ports(VOID) { // Initialization of ports all unused pins as outputs with low-level // set all ports to low on all pins PAOUT = 0x0000; PASEL = 0x0000; PADIR = 0xFFFF; PBOUT = 0x0000; PBSEL = 0x0000; PBDIR = 0xFFFF; PCOUT = 0x0000; PCSEL = 0x0000; PCDIR = 0xFFFF; // PDOUT = 0x0000; // PDSEL = 0x0000; // PDDIR = 0xFFFF; PJDIR = 0xFFFF; PJOUT = 0x0000; } //---------------------------------------------------------------------------- VOID Init_StartUp(VOID) { __disable_interrupt(); // Disable global interrupts Init_Ports(); // Init ports (do first ports because clocks do change ports) SetVCore(3); // USB core requires the VCore set to 1.8 volt, independ of CPU clock frequency Init_Clock(); __enable_interrupt(); // enable global interrupts } #pragma vector = UNMI_VECTOR __interrupt VOID UNMI_ISR(VOID) { switch (__even_in_range(SYSUNIV, SYSUNIV_BUSIFG)) { case SYSUNIV_NONE: __no_operation(); break; case SYSUNIV_NMIIFG: __no_operation(); break; case SYSUNIV_OFIFG: UCSCTL7 &= ~(DCOFFG+XT1LFOFFG+XT1HFOFFG+XT2OFFG); // Clear OSC flaut Flags fault flags SFRIFG1 &= ~OFIFG; // Clear OFIFG fault flag break; case SYSUNIV_ACCVIFG: __no_operation(); break; case SYSUNIV_BUSIFG: // If bus error occured - the cleaning of flag and re-initializing of USB is required. SYSBERRIV = 0; // clear bus error flag USB_disable(); // Disable } } // TimerA Init VOID Init_TimerA1(VOID) { TA1CCTL0 = CCIE; // CCR0 interrupt enabled TA1CTL = TASSEL_1 + TACLR; // ACLK, clear TAR } // This function returns true if there's an 0x0D character in the string; and if so, // it trims the 0x0D and anything that had followed it. BYTE retInString(char* string) { BYTE retPos=0,i,len; char tempStr[MAX_STR_LENGTH] = ""; strncpy(tempStr,string,strlen(string)); // Make a copy of the string len = strlen(tempStr); while((tempStr[retPos] != 0x0A) && (tempStr[retPos] != 0x0D) && (retPos++ < len)); // Find 0x0D; if not found, retPos ends up at len if((retPos<len) && (tempStr[retPos] == 0x0D)) // If 0x0D was actually found... { for(i=0;i<MAX_STR_LENGTH;i++) // Empty the buffer string[i] = 0x00; strncpy(string,tempStr,retPos); // ...trim the input string to just before 0x0D return TRUE; // ...and tell the calling function that we did so } else if((retPos<len) && (tempStr[retPos] == 0x0A)) // If 0x0D was actually found... { for(i=0;i<MAX_STR_LENGTH;i++) // Empty the buffer string[i] = 0x00; strncpy(string,tempStr,retPos); // ...trim the input string to just before 0x0D return TRUE; // ...and tell the calling function that we did so } else if (tempStr[retPos] == 0x0D) { for(i=0;i<MAX_STR_LENGTH;i++) // Empty the buffer string[i] = 0x00; strncpy(string,tempStr,retPos); // ...trim the input string to just before 0x0D return TRUE; // ...and tell the calling function that we did so } else if (retPos<len) { for(i=0;i<MAX_STR_LENGTH;i++) // Empty the buffer string[i] = 0x00; strncpy(string,tempStr,retPos); // ...trim the input string to just before 0x0D return TRUE; // ...and tell the calling function that we did so } return FALSE; // Otherwise, it wasn't found } // Timer1 A0 interrupt service routine #pragma vector=TIMER1_A0_VECTOR __interrupt void TIMER1_A0_ISR(void) { P1OUT ^= BIT0; // Toggle LED P1.0 } /*----------------------------------------------------------------------------+ | End of source file | +----------------------------------------------------------------------------*/ /*------------------------ Nothing Below This Line --------------------------*/
Bhargavi,
I've been working on this for most of the day. I took your main.c file and put that into my example 1 project. What I did is added some code to deal with the no enumeration case. So, in your code where you just enter a while (1) loop when the enum counter exceeds 100000 I added a call to USB_Disconnect which I'm *pretty* sure is the right thing to do.
I've enclosed this main.c file, my changes are marked with MU.
I can run this code on either the TI development board or on our target hardware. All I need to do is change the target MSP430, we are using the 5513 and the development board has the 5529. I put in toggle LED code for either board.
What I find is that on the development board it works fine, I can connect and disconnect the USB plug and the LED always comes up flashing.
On our target hardware, not so good. It works sometimes but usually not. If I test it with the debugger, it always works. So, it would seem that we have something marginal in our hardware design which is not good news. We have duplicated the TI development board as much as possible but maybe there is something we've overlooked.
Thanks.
Mike
// (c)2009 by Texas Instruments Incorporated, All Rights Reserved. /*----------------------------------------------------------------------------+ | | | Texas Instruments | | | | MSP430 USB-Example (CDC/HID Driver) | | | +-----------------------------------------------------------------------------+ | Source: main.c, v1.19 2009/19/11 | ------------------------------------------------------------------------------+ LED Control Demo: This USB demo example is to be used with a PC application (e.g. HyperTerminal) This demo application is used to control the operation of the LED at P1.0 Typing the following pharses in the HyperTerminal Window does the following 1. "LED ON" Turns on the LED and returns "LED is ON" phrase to PC 2. "LED OFF" Turns off the LED and returns "LED is OFF" back to HyperTerminal 3. "LED TOGGLE - SLOW" Turns on the timer used to toggle LED with a large period and returns "LED is toggling slowly" phrase back to HyperTerminal 4. "LED TOGGLE - FAST" Turns on the timer used to toggle LED with a smaller period and returns "LED is toggling fast" phrase back to HyperTerminal +----------------------------------------------------------------------------+ Please refer to "USB CDC API Demo Examples Guide.pdf" for more details //----------------------------------------------------------------------------*/ #include "Common\device.h" #include "Common\types.h" // Basic Type declarations #include ".\USB_Common\descriptors.h" #include "USB_Common\usb.h" // USB-specific functions #include "main.h" #include "Common\hal_UCS.h" #include "Common\hal_pmm.h" #ifdef _CDC_ #include "USB_CDC_API\UsbCdc.h" #endif #ifdef _HID_ #include "USB_HID_API\UsbHid.h" #endif #include <intrinsics.h> #include <string.h> #include "USBCDC_constructs.h" #include "main.h" volatile BYTE bDataReceived_event = FALSE; // Indicates data has been received without an open rcv operation volatile BYTE bDataReceiveCompleted_event = FALSE; // data receive completed event volatile BYTE bDataSendCompleted_event = FALSE; // data send completed event #define MAX_STR_LENGTH 64 char wholeString[MAX_STR_LENGTH] = ""; // The entire input string from the last 'return' unsigned int SlowToggle_Period = 20000-1; unsigned int FastToggle_Period = 1000-1; unsigned long Enum_Count =0; /*----------------------------------------------------------------------------+ | Main Routine | +----------------------------------------------------------------------------*/ VOID main(VOID) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer Init_StartUp(); //initialize device //Init_TimerA1(); USB_init(); // Enable various USB event handling routines USB_setEnabledEvents(kUSB_VbusOnEvent+kUSB_VbusOffEvent+kUSB_receiveCompletedEvent +kUSB_dataReceivedEvent+kUSB_UsbSuspendEvent+kUSB_UsbResumeEvent+kUSB_UsbResetEvent); // See if we're already attached physically to USB, and if so, connect to it // Normally applications don't invoke the event handlers, but this is an exception. if (USB_connectionInfo() & kUSB_vbusPresent) USB_handleVbusOnEvent(); Enum_Count =0; while(1) { P1OUT ^= BIT0; // Toggle LED P1.0 MU P1OUT ^= BIT1; // Toggle LED P1.0 MU // LED on P1.1 on our board BYTE i; // Check the USB state and directly main loop accordingly switch(USB_connectionState()) { case ST_USB_DISCONNECTED: // __bis_SR_register(LPM3_bits + GIE); // Enter LPM3 w/ interrupts enabled MU _NOP(); // For Debugger break; case ST_USB_CONNECTED_NO_ENUM: //Enum_Count++; break; case ST_ENUM_ACTIVE: Enum_Count++; //__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 (can't do LPM3 when active) MU _NOP(); // For Debugger // Exit LPM on USB receive and perform a receive operation if(bDataReceived_event) // Some data is in the buffer; begin receiving a command { char pieceOfString[MAX_STR_LENGTH] = ""; // Holds the new addition to the string char outString[MAX_STR_LENGTH] = ""; // Holds the outgoing string // Add bytes in USB buffer to theCommand receiveDataInBuffer((BYTE*)pieceOfString,MAX_STR_LENGTH,1); // Get the next piece of the string strcat(wholeString,pieceOfString); // Add it to the whole sendData_inBackground((BYTE*)pieceOfString,strlen(pieceOfString),1,0); // Echoes back the characters received (needed for Hyperterm) if(retInString(wholeString)) // Has the user pressed return yet? { if(!(strcmp(wholeString, "LED ON"))) // Compare to string #1, and respond { TA1CTL &= ~MC_1; // Turn off Timer P1OUT |= BIT0; // Turn on LED P1.0 strcpy(outString,"\r\nLED is ON\r\n\r\n"); // Prepare the outgoing string sendData_inBackground((BYTE*)outString,strlen(outString),1,0); // Send the response over USB } else if(!(strcmp(wholeString, "LED OFF"))) // Compare to string #2, and respond { TA1CTL &= ~MC_1; // Turn off Timer P1OUT &= ~BIT0; // Turn off LED P1.0 strcpy(outString,"\r\nLED is OFF\r\n\r\n"); // Prepare the outgoing string sendData_inBackground((BYTE*)outString,strlen(outString),1,0); // Send the response over USB } else if(!(strcmp(wholeString, "LED TOGGLE - SLOW"))) // Compare to string #3, and respond { TA1CTL &= ~MC_1; // Turn off Timer TA1CCR0 = SlowToggle_Period; // Set Timer Period for slow LED toggle TA1CTL |= MC_1; // Start Timer strcpy(outString,"\r\nLED is toggling slowly\r\n\r\n"); // Prepare the outgoing string sendData_inBackground((BYTE*)outString,strlen(outString),1,0); // Send the response over USB } else if(!(strcmp(wholeString, "LED TOGGLE - FAST"))) // Compare to string #4, and respond { TA1CTL &= ~MC_1; // Turn off Timer TA1CCR0 = FastToggle_Period; // Set Timer Period for fast LED toggle TA1CTL |= MC_1; strcpy(outString,"\r\nLED is toggling fast\r\n\r\n"); // Prepare the outgoing string sendData_inBackground((BYTE*)outString,strlen(outString),1,0); // Send the response over USB } else // Handle other { strcpy(outString,"\r\nNo such command!\r\n\r\n"); // Prepare the outgoing string sendData_inBackground((BYTE*)outString,strlen(outString),1,0); // Send the response over USB } for(i=0;i<MAX_STR_LENGTH;i++) // Clear the string in preparation for the next one wholeString[i] = 0x00; } bDataReceived_event = FALSE; } break; case ST_ENUM_SUSPENDED: P1OUT &= ~BIT0; // When suspended, turn off LED // __bis_SR_register(LPM3_bits + GIE); // Enter LPM3 w/ interrupts MU _NOP(); break; case ST_ENUM_IN_PROGRESS: Enum_Count++; if(Enum_Count > 100000) USB_disconnect(); // MU //while(1); // MU break; case ST_NOENUM_SUSPENDED: P1OUT &= ~BIT0; Enum_Count++; if(Enum_Count > 100000) USB_disconnect(); // MU // while(1); // MU //__bis_SR_register(LPM3_bits + GIE); _NOP(); break; case ST_ERROR: _NOP(); break; default:; } } // while(1) } //main() /*----------------------------------------------------------------------------+ | System Initialization Routines | +----------------------------------------------------------------------------*/ VOID Init_Clock(VOID) { //Initialization of clock module if (USB_PLL_XT == 2) { P5SEL |= 0x0C; // enable XT2 pins for F5529 //for F5529 // use REFO for FLL and ACLK UCSCTL3 = (UCSCTL3 & ~(SELREF_7)) | (SELREF__REFOCLK); UCSCTL4 = (UCSCTL4 & ~(SELA_7)) | (SELA__REFOCLK); Init_FLL(USB_MCLK_FREQ/1000, USB_MCLK_FREQ/32768); // set FLL (DCOCLK) UCSCTL6 |= XT1OFF; // MU XT2Bypass(); // MU //XT2_Start(); // MU } else { P5SEL |= 0x10; // enable XT1 pins UCSCTL3 = SELREF__REFOCLK; // run FLL mit REF_O clock UCSCTL4 = (UCSCTL4 & ~(SELA_7)) | (SELA__REFOCLK); // set ACLK = REFO Init_FLL(USB_MCLK_FREQ/1000, USB_MCLK_FREQ/32768); // set FLL (DCOCLK) XT1_Start(); } // SFRIE1 |= OFIFG; // Enable OscFault ISR } //---------------------------------------------------------------------------- VOID Init_Ports(VOID) { // Initialization of ports all unused pins as outputs with low-level // set all ports to low on all pins PAOUT = 0x00FF; // MU PASEL = 0x0000; PADIR = 0xFFFF; PBOUT = 0x0000; PBSEL = 0x0000; PBDIR = 0xFFFF; PCOUT = 0x0000; PCSEL = 0x0000; PCDIR = 0xFFFF; /* PDOUT = 0x0000; PDSEL = 0x0000; PDDIR = 0xFFFF; */ PJDIR = 0xFFFF; PJOUT = 0x0000; } //---------------------------------------------------------------------------- VOID Init_StartUp(VOID) { __disable_interrupt(); // Disable global interrupts Init_Ports(); // Init ports (do first ports because clocks do change ports) SetVCore(3); // USB core requires the VCore set to 1.8 volt, independ of CPU clock frequency Init_Clock(); __enable_interrupt(); // enable global interrupts } #pragma vector = UNMI_VECTOR __interrupt VOID UNMI_ISR(VOID) { switch (__even_in_range(SYSUNIV, SYSUNIV_BUSIFG)) { case SYSUNIV_NONE: __no_operation(); break; case SYSUNIV_NMIIFG: __no_operation(); break; case SYSUNIV_OFIFG: UCSCTL7 &= ~(DCOFFG+XT1LFOFFG+XT1HFOFFG+XT2OFFG); // Clear OSC flaut Flags fault flags SFRIFG1 &= ~OFIFG; // Clear OFIFG fault flag break; case SYSUNIV_ACCVIFG: __no_operation(); break; case SYSUNIV_BUSIFG: // If bus error occured - the cleaning of flag and re-initializing of USB is required. SYSBERRIV = 0; // clear bus error flag USB_disable(); // Disable } } // TimerA Init VOID Init_TimerA1(VOID) { TA1CCTL0 = CCIE; // CCR0 interrupt enabled TA1CTL = TASSEL_1 + TACLR; // ACLK, clear TAR } // This function returns true if there's an 0x0D character in the string; and if so, // it trims the 0x0D and anything that had followed it. BYTE retInString(char* string) { BYTE retPos=0,i,len; char tempStr[MAX_STR_LENGTH] = ""; strncpy(tempStr,string,strlen(string)); // Make a copy of the string len = strlen(tempStr); while((tempStr[retPos] != 0x0A) && (tempStr[retPos] != 0x0D) && (retPos++ < len)); // Find 0x0D; if not found, retPos ends up at len if((retPos<len) && (tempStr[retPos] == 0x0D)) // If 0x0D was actually found... { for(i=0;i<MAX_STR_LENGTH;i++) // Empty the buffer string[i] = 0x00; strncpy(string,tempStr,retPos); // ...trim the input string to just before 0x0D return TRUE; // ...and tell the calling function that we did so } else if((retPos<len) && (tempStr[retPos] == 0x0A)) // If 0x0D was actually found... { for(i=0;i<MAX_STR_LENGTH;i++) // Empty the buffer string[i] = 0x00; strncpy(string,tempStr,retPos); // ...trim the input string to just before 0x0D return TRUE; // ...and tell the calling function that we did so } else if (tempStr[retPos] == 0x0D) { for(i=0;i<MAX_STR_LENGTH;i++) // Empty the buffer string[i] = 0x00; strncpy(string,tempStr,retPos); // ...trim the input string to just before 0x0D return TRUE; // ...and tell the calling function that we did so } else if (retPos<len) { for(i=0;i<MAX_STR_LENGTH;i++) // Empty the buffer string[i] = 0x00; strncpy(string,tempStr,retPos); // ...trim the input string to just before 0x0D return TRUE; // ...and tell the calling function that we did so } return FALSE; // Otherwise, it wasn't found } // Timer1 A0 interrupt service routine #pragma vector=TIMER1_A0_VECTOR __interrupt void TIMER1_A0_ISR(void) { P1OUT ^= BIT0; // Toggle LED P1.0 } /*----------------------------------------------------------------------------+ | End of source file | +----------------------------------------------------------------------------*/ /*------------------------ Nothing Below This Line --------------------------*/
I didn't work with USB before and don't plan to do so in near future, but nevertheless I followed this thread just out of curiosity.
While reading, I remembered something similar happening in my own developments, not with USB bit with I2C.
It happened with a board where placement of an external I2C RTC chip was optional. In prodcution, not only the RTC chip itself, but also the pullup resistors have been 'optimized away' with the result that the firmware hung forever when trying to detect the presence of the RTC chip.
Maybe the problem is caused by something similar. If VBUS is present, the USB functions may assume some logical levels on the other USB lines which are present if a real USB host is connected, but aren't if just 5V are attached. The USB logic is in an invalid state, confusing the software. So maybe a simple, large pullup or pulldown on the USB lines to simulate an 'unenumerated condition' (or whetever) will help.
Then why does it work with debugger and not without? Maybe line capacity or so makes it hang without debugger, while the signals have time enough to settle when the debugger is attached. Measuring changes the subject of of the measurement :)
Jens-Michael,
Thanks a lot for your response. It would seem that you had the right idea (read below). The strange thing is that the way USB works it should be the other way around, i.e. the device pulls the data lines one way or the other to signal its presence so the device should pay no mind to what the levels are. But, clearly there is something I don't understand.
Bhargavi,
I noticed yesterday that on the TI development board there is a very light pulldown on the D+ line, it's 1M. Long story short when we add that 1M on our board things start working well, I don't even think I need the timeout on the enumeration although I may leave it in anyway.
I sure would like to know why that is. We did a USB device using a Silicon Labs part a few years ago and did not need it and we have looked at many other USB designs that did not need it. Why is it needed here?
Thank you again for your help.
Mike
Hi Mike,
The 1Mohm resistor is used as a pull-down R that is required to keep the PUR pin from floating on power-up and ensure that the device does not invoke the USB BSL mode unintentionally. On power-up, the device checks if the USBBGVBV (Vbus) bit and PUR pin (reflected by the PUR_IN bit) are set and if they are, it branches to USB BSL mode (in which the device enumerates as an HID device).
The following extra components are used implement the BSL switch (one of ways used to invoke USB BSL mode) - (refer to the 80-pin target board schematic) R10=100ohm, Switch S3 and pull-down R=R11=1Mohm. When the user wants to enter the USB BSL mode, he presses the switch and connects the device to the host. By holding the switch down and connecting the device to host, Vbus is available (USBBGVBV bit is set) and PUR is connected to Vusb = 3.3V . And now the device enters BSL mode. However, with this circuitry it was initially found that the USB BSL mode was invoked even when the user did not intend to do so. So, in order to ensure proper BSL invoke, pull-down R of 1Mohm was used.
Regards,
Bhargavi
One more guess: the Silicon Labs part might have a lower input impedance than the Ti part, so the line is held low fast enough. Or the attached software is different and doesn't care for this or at elast doesn't hang.
Edit: seems like it is the software, and not the USB library embedded in the user code, but the internal USB loader code that is getting confused. This explains why attaching the debugger helps: the BSL is not started when a debugger is attached (JTAG active). Well, BSL code has to be small and it's easy to skip some probability checks :)
Hi,
I have a custom board with MSP430F5510 and I am trying to get the USB interface to work. The board has a 16MHz crystal connected to XT2. The board is connected to a WIndows host via USB cable. The power via USB is used to charge a bettery on the board.
I am using one of the example codes provided with the MSP430_USB_Developers_Package as a starting point. I used the MSP430_USB_Descriptor_Tool to generate the descriptors.c/.h and UsbIsr.c files. The setings used were MCLK = 1.048576, XT2 oscillator frequency = 16MHz.
When I run the code on the device, it is continuously stuck in the state ST_ENUM_IN_PROGRESS and the Windows host is not recognizing the device at all.
Can you please tell me if I am missing anything here??
Thanks,
Amee
HI ,
I am using msp430f5500 and i want to use USB application in that.I am using emulator to debug the code and want to send the data by usb to PC.I download the USB developers package but when i on that software the upgrade firmware button is not on how can i use that software ?
thanks and regards
Nilesh
**Attention** This is a public forum