PDA

View Full Version : Software on PIC will come in loop after disconnect USB connection



Ronald123
- 18th October 2007, 19:37
My application is connected via USB to a PC. Within my application I'm using a 18F2550 PIC. A status change of a I/O will be send via USB to PC.

The code which I'm using for outgoing:

USBwriteStatus:
USBService ' Must service USB regularly
USBOUT 3, USBBUFFER ,CNT_UIT, USBWRITESTATUS
RETURN

The problem is when I disconnect the USB cable it seems that the the PIC program commes in an unendless loop of "USBwriteStatus. I have mode some modifications, see below, however this will still not solve the problem.

USBwriteStatus:
USBService ' Must service USB regularly
USBOUT 3, USBBUFFER ,CNT_UIT, exitusbwritestatus
exitusbwritestatus:
RETURN

When I'm taking this SUB out of my application everything works also without USB connection to PC.

Is there somebody who knows what I'm doing wrong?
Is it possible to see the status of the USB connection (connect/disconnect) before calling the SUB USBwriteStatus.

Bruce
- 18th October 2007, 22:46
Hi Ronald,

There's a very simple solution to this. Assign a single I/O-pin as the USB bus-attach input.

Here's how;

ground --100k resistor----PIC input pin ----4.7k resistor----+V from USB connector.

When the USB cable is plugged in, the input will see +V from the USB port. When the USB
cable is removed, it will see ground.

Don't attempt to send/receive any data until you see +V on the USB bus-attach input pin.
Very simple. Very effective.

Squibcakes
- 19th October 2007, 02:43
Bruce,

Thats a great tip, (although I havent seen this problem come up before).

I'm wondering if this would be concidered a fail safe "Design Rule" and should be implemented into all USB PIC based circuits?

Cheers
Squib

Bruce
- 19th October 2007, 03:47
Hi Squib,

I can't take credit for the idea. It's an option on the Microchip USB development board, and
in the USB C firmware.

There's no reason to enable the USB module if it's not attached, so it's not a bad idea to
add in.

Ronald123
- 20th October 2007, 19:56
Hi Bruce, thank you for your almost exelent and simple sollution. Almost exelent because it will cost me 1 I/O and I don't have one I/O left. I have made a mistake because after testing this code again it was working.

USBwriteStatus:
USBService
USBOUT 3, USBBUFFER ,CNT_UIT, exitusbwritestatus
exitusbwritestatus:
RETURN

However this sollution has a disadvantage because when the outgoing USBBuffer is full it will also goto "exitusbwritestatus" without sending the information via USB, so some status information from PIC to PC will be lost.

Darrel Taylor
- 20th October 2007, 20:46
You should be able to determine if it's plugged-in or not by monitoring the usb_device_state variable.


usb_device_state VAR BYTE EXT
CONFIGURED_STATE CON EXT

IF (usb_device_state = CONFIGURED_STATE) THEN
; OK to send
ELSE
; Detached or Enumerating, don't try to send.
ENDIF

Ronald123
- 21st October 2007, 20:57
Hi Darrel, I've tried it however it is not working. I've used the following.

IF (usb_device_state = CONFIGURED_STATE) THEN
high dataled
ELSE
low dataled
ENDIF

During USB connection the dataled is on. However the status of the dataled will not change when the USB cable will be disconnected. When I connect the cable in, for short time the dataled will be turned off and within about 300msec it will be turned on. I think that the Led will be turned off during enumeration.

Do I something wrong why it is not working?

Darrel Taylor
- 22nd October 2007, 00:27
Hi Ronald,

I've done something similar before, but I didn't have a USB breadboard handy at the time I replied.

I've dug out the old mister_e usbdemo breadboard.
Blown off the dust with a half a can of "Dust-Off" ... :)

... and am taking a look.

Hoping I can figure it out.
<br>

Squibcakes
- 22nd October 2007, 01:41
Ditto, Doesn't work for me either...

Cheers
Squib

Darrel Taylor
- 22nd October 2007, 01:52
Ditto, Doesn't work for me either...

Cheers
Squib

That's right. Kick him while he's Down. :eek:

Working on it.
<br>

Darrel Taylor
- 22nd October 2007, 14:07
Yup, you 2 were right. It only picked up the Plugged, not the un-plugged state.

After a bit of re-thinking, ...
This seems to work pretty good.

The way it works is by watching the IDLEIF and SOFIF interrupt flags.
IDLEIF is triggered if the USB buss is idle for more than 3ms.
SOFIF is the Start-Of-Frame flag, which is a good indication of buss activity.

If it sees a SOFIF it sets the Plugged bit, and if it sees an IDLEIF flag it clears the Plugged bit.
Then in the Main loop you can use that flag to stop sending data if not Plugged.

This example uses Interrupts, but you can do the same thing without interrupts, just be sure to check for the flags before servicing USB.
The example turns on LED1 when Plugged, and toggles a second LED to show that the Main loop keeps executing when un-plugged.

DEFINE OSC 48
CLEAR

INCLUDE "DT_INTS-18.bas" ' Base Interrupt System

ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler USB_INT, _DoUSBService, ASM, yes
endm
INT_CREATE ; Creates the interrupt processor
endasm

UIE VAR BYTE EXT
UEIE VAR BYTE EXT
UIR VAR BYTE EXT
IDLEIF VAR UIR.4
SOFIF VAR UIR.6
Plugged VAR BIT

LED1 VAR PORTB.0 : LOW LED1
LED2 VAR PORTC.1 : LOW LED2


USBBufferCount Var Byte
DataToSend var byte[8]
USBBufferCount = 8

pause 500 ' initialise USB...
usbinit
usbservice
UIE = $7F
UEIE = $9F
@ INT_ENABLE USB_INT

;----[Main program starts here]-----------------------------------------------
Main:
LED1 = Plugged ; LED1 indicates OK to Send
IF Plugged then ; if bus available, transmit data
USBOut 1, DataToSend, USBBufferCount, Main
ENDIF
toggle LED2 ; blink LED2 to show Main Loop is still running
pause 100
goto Main

;----[USB Interrupt Handler]--------------------------------------------------
DoUSBService:
IF IDLEIF THEN Plugged = 0
IF SOFIF THEN Plugged = 1
usbservice
@ INT_RETURN


HTH,

Squibcakes
- 24th October 2007, 02:47
Hi DT,

Great! I tried this one and it works. Good one.

However, I've tried to incorp. it into an existing program and it doesn't work.

Your code seems to indicate that the USBSERVICE routine is continually called by the USB_int handler. How often does this interrupt? Only when it is plugged / unplugged or all the time?

The problem is that I'm servicing the USBSERVICE through a 1msec Timer1 interrupt handler and trying to read the flags in that interrupt but they don't set.



'---[TMR1 - interrupt handler]---------------------------------------------------
USB_SERVICE: ' COMES HERE 1msec TO SERVICE THE USB PORT

T1CON.0 = 0 ' TURN OFF TIMER
TMR1L = COUNTER1.byte0 ' RELOAD TIMER LOW
TMR1H = COUNTER1.byte1 ' RELOAD TIMER HIGH
IF IDLEIF THEN Plugged = 0
IF SOFIF THEN Plugged = 1
USBService ' KEEP USB ALIVE
T1CON.0 = 1 ' TURN ON TIMER


@ INT_RETURN


The way I see it is that SOFIF should always be set since I'm servicing USB every 1 msec untill I disconnect the USB cable.

I would do away with the Timer1 Interrupt altogether and use USB_INT but how often does the USB_int get called?


Cheers
Squib

Darrel Taylor
- 24th October 2007, 04:22
Using the USB_INT source is much more efficient than using a 1ms timer.

During Enumeration it may only be a few microseconds between interrupts, and there are a lot of them. Consequently, it connects to the PC much faster.

But during normal operation, it drops to about every 10-20 milliseconds, although that depends on the polling time set up in the descriptor.

When the cable is un-plugged, you don't get any USB interrupts at all (after the IDLE int).

Plus using the USB_INT frees up a Timer. :)

ADDED:
But that doesn't explain why the Plugged example above doesn't work with the Timer Interrupts. It should work.

Are there any other USBSERVICE statements in the program?
There should only be 1.

<br>

Squibcakes
- 24th October 2007, 05:50
DT,

What you say makes sense and I like the fact that it frees up a Timer.

I found in my original program that I missed (during a cut and paste) the section where you loaded UIE and UEIE with values... which would explain why it wasn't running with my timer ints.... :)

The whole point of this exercise is to "error trap" the pic for any unforseen conditions, eg I've seen the PIC hang sometimes when shutting down pc coms programs that don't close the port nicely. Hopefully this will stamp that one out. LOL

Now, since you have all the answers, do you have tonight's Lotto Numbers by any chance?

Cheers
Squib

Darrel Taylor
- 25th October 2007, 11:30
... do you have tonight's Lotto Numbers by any chance? ...

Oh sure ... Here's the numbers for California's Super Lotto Plus, for all future draws.
Just come back here before each game for the new numbers.

<font size="+1"><b><script type="text/javascript">var picks = new Array(5);var TempNum, LoopCount; for (LoopCount=1;LoopCount<6;LoopCount+=1){picks[LoopCount] = 0;}for (LoopCount=1;LoopCount<6;LoopCount+=1){TempNum = Math.round(Math.random()*47)+1;for (var DupCheck=1;DupCheck<LoopCount;DupCheck+=1){if (TempNum == picks[DupCheck]){TempNum = Math.round(Math.random()*47)+1;DupCheck = 1}}picks[LoopCount] = TempNum;document.write(picks[LoopCount]+"-")}document.write("<font color=red>"+Math.round(Math.random()*27+1)+"</font>")</script></b></font>

Of course it would have been better, had you asked for "tonight's Winning Lotto Numbers"! :D
<br>

Art
- 30th October 2007, 20:25
Lol,
NVM. if the game is played long enough, they'll win at some stage.