PDA

View Full Version : Speed of USB EasyHID and Time problem



sjohansson
- 5th January 2007, 22:37
I'm working on a project measuring high pulse and then during the low pulse, send the value by USB to a VB app.
The problem is that when the period (High and Low pulse) is shorter than aprox 7ms I get strange data from the pic.

I decided to measure how long time a USBOut and USBSERVICE takes and here is what I got:

USBSERVICE = 4.08us
USBOut 8 Byte = 12.4us
USBOut 16 Byte = 15.7us
USBOut 32 Byte = 22.4us
USBOut 64 Byte = 35.7us

So the USB transfer should not affect my measurements of the pulse width.
I use Timer3 to measure parts of my program.
The part of code I measure in the pic code below takes 15.5us.

I use a Basic Stamp to create a squarewave to my pic CCP1 input.
The program looks like this:


Main:
IF IN15 THEN
HIGH 6
PAUSE 3
LOW 6
PAUSE 4
ENDIF
GOTO Main
END


In this case I get correct readings sent to the pc.
But if I change Pause 4 to Pause 3 the data variates a lot.
Also the Timer3 values in the pic code below variates a lot.
Wich means that that part of code takes different times to execute from time to time.

If I change the Basic Stamp program to this; the data is correct:


Main:
IF IN15 THEN
HIGH 6
PAUSE 0
LOW 6
PAUSE 7
ENDIF
GOTO Main
END


And also this works:


Main:
IF IN15 THEN
HIGH 6
PAUSE 7
LOW 6
PAUSE 0
ENDIF
GOTO Main
END


But as soon the period is under 7ms I get strange values to my vb app.

Please help me find what is wrong with my code.
I use a Pic18F4550 20Mhz, MicroCode Studio Plus and Pbp 2.46.

Thanks in advance,
Stefan



'********************************************
'Pulse width measuring
'********************************************
DEFINE OSC 48
DEFINE LOADER_USED 1
DEFINE RESET_ORG 800h ' For Microchip USB Bootloader
DEFINE INTERRUPT_ORG 808h ' For Microchip USB Bootloader

USBBufferSizeMax con 8 ' maximum buffer size
USBBufferSizeTX con 8 ' input
USBBufferSizeRX con 8 ' output
USBBuffer Var Byte[USBBufferSizeMax]
USBBufferCount Var Byte

Counts1 Var Word ' Holds Timer1 counts
Counts1Of Var Byte ' Holds the Overflow counts
Overflow var byte
RisingEdge Var Bit
Preset Var Bit
SendBytes Var Bit
SampleNo var byte
NewSample var byte
CCP1IE var PIE1.2
CCP1IF VAR PIR1.2
TMR1ON VAR T1CON.0
TRM1IF var PIR1.0
TMR1IE VAR PIE1.0
IrOnRising var BYTE
IrOnFalling var BYTE
x var byte
y var byte
Led VAR PortB.5

'Timer3 declarations
TMR3ON var T3CON.0
TMR3IF var PIR2.1
TMR3IE var PIE2.1
TMR3VALUE var WORD
TMR3OverF var byte


USBINIT
ADCON1 = 15 ' Set PORTA, PORTE and PORTB to digital.
TRISD.1 = 0 'Port D Bit 1 as Output
TRISB.5 = 0 'Port B Bit6 as Output for LED
TRISC.2 = 1 'Port C Bit2 CCP1 as Input
IrOnFalling = 4 '0100 = Capture mode: every falling edge
IrOnRising = 5 '0101 = Capture mode: every rising edge
T1CON.4 = 1 'Timer1 Prescaler Bit4
T1CON.5 = 1 'Timer1 Prescaler Bit5
Counts1 = 0
TMR1H = 0
TMR1L = 0
CCP1CON = IrOnRising '0101 = Capture mode: every rising edge
CCP1IE = 1 'CCP1IE Interrupt Disabled
SampleNo = 1
Counts1Of = 0
Overflow = 0
Low Led

'Timer3 inits
TMR3OverF = 0
TMR3IE = 1
TMR3IF = 0
T3CON.4 = 0
T3CON.5 = 0


ProgramStart:
USBSERVICE ' keep connection alive

if TRM1IF THEN 'If Timer1 Overflows
Overflow = Overflow + 1 'Incr Overflow counter
TRM1IF = 0 'Reset Flag
ENDIF

IF CCP1IF = 0 THEN ProgramStart 'Return if no Interrupt

IF CCP1CON = IrOnRising THEN
CCP1IF = 0 'Reset Flag
CCP1IE = 0 'CCP1IE Interrupt Disabled
CCP1CON = IrOnFalling 'Capture mode: every falling edge
CCP1IE = 1 'CCP1IE Interrupt Enabled
TMR1H = 0
TMR1L = 0
TMR1IE = 1 'Enable overflow flag
TMR1ON = 1 'Start Timer 1
' high Led
goto ProgramStart
ENDIF

IF CCP1CON = IrOnFalling THEN
TMR3ON = 1 'Using Timer3 for measuring
CCP1IF = 0 'Reset Flag
Counts1.HighByte = CCPR1H 'Save Values
Counts1.LowByte = CCPR1L
Counts1Of = Overflow
Overflow = 0 'Reset Overflow counter
CCP1IE = 0 'CCP1IE Interrupt Disabled
CCP1CON = IrOnRising 'Capture mode: every rising edge
CCP1IE = 1 'CCP1IE Interrupt Disabled
'TMR1ON = 0 'Stop Timer 1
TMR1H = 0
TMR1L = 0
if SampleNo = 1 then 'SampleNo used by VB app.
SampleNo = 2
else
SampleNo = 1
endif
USBBuffer(0) = Counts1.LowByte
Counts1.LowByte = 0
USBBuffer(1) = Counts1.HighByte
Counts1.HighByte = 0
USBBuffer(2) = Counts1Of
USBBuffer(3) = SampleNo
USBBuffer(4) = TMR3VALUE.highbyte
USBBuffer(5) = TMR3VALUE.lowbyte
'low Led
Gosub DoUSBOut
TMR3ON = 0 'Using Timer3 for measuring
TMR3VALUE.highbyte = TMR3H
TMR3VALUE.lowbyte = TMR3L
TMR3H = 0
TMR3L = 0
goto ProgramStart
ENDIF


GOTO ProgramStart

' ************************************************** **********
' * receive data from the USB bus *
' ************************************************** **********
DoUSBIn:
USBBufferCount = USBBufferSizeRX ' RX buffer size
x=x+1
if x > y THEN Skipping
USBService ' keep connection alive
USBIn 1, USBBuffer, USBBufferCount, DoUSBIn ' read data, if available
Skipping:
x=0
return

' ************************************************** **********
' * wait for USB interface to attach *
' ************************************************** **********
DoUSBOut:
USBBufferCount = USBBufferSizeTX ' TX buffer size
USBService ' keep connection alive
USBOut 1, USBBuffer, USBBufferCount, DoUSBOut ' if bus available, transmit data
return

End

sjohansson
- 12th January 2007, 14:26
Can someone please help me to find out why I'm not able to measure higher freq than 67Hz. Is it the speed of the USB transfer that takes too long time?

I would really apreciate if you can help me.

Thanks

Stefan.

skimask
- 12th January 2007, 14:50
Can someone please help me to find out why I'm not able to measure higher freq than 67Hz. Is it the speed of the USB transfer that takes too long time?

I would really apreciate if you can help me.

Thanks

Stefan.

Are you saying that you can only get samples from USB at 67hz or that the PIC can only count up to 67hz?

sjohansson
- 12th January 2007, 15:09
No not really. It should be 130Hz something. When the dutycycle is shorter than 7,5ms (130Hz) the pic send strange values to my vb application.
I'm sure the pic can count much higher frequences, especially as I use the CCP1 input. But my question is if there is some bugs in my pic program or if the USB is taking too long so the timer1 measure something else than only the high pulse.

Sorry for the bad English.

Regards
Stefan.

skimask
- 12th January 2007, 15:22
No not really. It should be 130Hz something. When the dutycycle is shorter than 7,5ms (130Hz) the pic send strange values to my vb application.
I'm sure the pic can count much higher frequences, especially as I use the CCP1 input. But my question is if there is some bugs in my pic program or if the USB is taking too long so the timer1 measure something else than only the high pulse.

Sorry for the bad English.

Regards
Stefan.

So, simulate some numbers. Plug in fake values into your registers (turn off the timers so they don't count up themselves), and see what the VB program displays. If it's good, you've probably got your CCP registers set up incorrectly. Also, make sure you're not trying to start counting in the middle of a pulse or something when the USB service RETURNs, wait for a solid high or low, then start counting.

sjohansson
- 12th January 2007, 15:52
So, simulate some numbers. Plug in fake values into your registers (turn off the timers so they don't count up themselves), and see what the VB program displays.
Good idea, I will try that.


Also, make sure you're not trying to start counting in the middle of a pulse or something when the USB service RETURNs, wait for a solid high or low, then start counting.
How can I do that? I thought that's what CCP1IF does. Just triggering if ccp pin rising or falling. Right?

Also another question; Is it best to turn On and Off the timer for each cycle or should it be On all the time and just reset the timer registers?

skimask
- 12th January 2007, 18:27
Good idea, I will try that.


How can I do that? I thought that's what CCP1IF does. Just triggering if ccp pin rising or falling. Right?

Also another question; Is it best to turn On and Off the timer for each cycle or should it be On all the time and just reset the timer registers?

Just a thought, and I know it's not the best thought...

Since the hardware is giving you a bit of a problem, have you thought about using PBP's built-in Count and/or Pulsin commands? At 48mhz, you should have plenty of resolution to work with.

Also, you might want to put an LCD of some sort on your PIC, so you can read the values before they get send over the USB to the PC. You might be sending bad numbers in the first place.

For the problem-How about a variable that's declared as a byte variable that you might actually want as a word variable? (overflowing where you don't want it to, something like that)

Darrel Taylor
- 16th January 2007, 09:04
Hi Stefan,

I've been looking at your program, and frankly I've got more questions than answers. But, I have found a few interesting things.

First off, I can verify that the program completely "Wigs Out" when the pulses are faster than 125pps. This also seems to be the Limit for the number of HID reports per second. I've been working on a couple other USB programs and have seen the same number.

An easy way to verify what's happening is to modify the DoUSBout like this...
' ************************************************** **********
' * wait for USB interface to attach *
' ************************************************** **********
DoUSBOut:
USBBufferCount = USBBufferSizeTX ' TX buffer size
USBService ' keep connection alive
USBOut 1, USBBuffer, USBBufferCount, OutBusy ' if bus available, transmit data
return

OutBusy:
toggle PORTB.0 ' toggle led to show when USB is busy
GOTO DoUSBOut
Change the PORTB.0 to an LED on your board.

Then you'll see that the "BAD" numbers received by the VB program, happen at the same time the LED starts blinking, due to a busy USB condition. (anything above 125hz)

At this point I still don't understand what's going wrong, but I have found a possible way around it. By changing the DoUSBOut to this...
' ************************************************** **********
' * don't wait for USB interface to attach, abort if busy *
' ************************************************** **********
DoUSBOut:
USBBufferCount = USBBufferSizeTX ' TX buffer size
USBService ' keep connection alive
USBOut 1, USBBuffer, USBBufferCount, OutBusy ' if bus available, transmit data
RETURN

OutBusy:
toggle PORTB.0 ' toggle led to show when USB is busy
RETURN

This will discard the current reading if the USB is busy, and go back and measure another pulse, (rinse and repeat).

I've run it up to 500hz and it never "messes up".

Of course, this won't be able to report every pulse to the VB program, Hopefully you don't need them all.

HTH,

sjohansson
- 16th January 2007, 21:02
Hi Darrel.

Thanks for verifying the problem. Now I know that it is not just my program messing with me..

But it's still confusing because when I use my Basic Stamp to simulate a signal, it works fine with 7ms High and 0ms low pulse. (BS code #3 in my first post.) This means that USBOut has enough time to execute even if the low pulse is only a few us. Can it be the vb app that is the bottleneck here?
Pic send it quick but next time it try to send the pc is still busy with the last one. What do you think about that?
If the pic is the bottleneck then I wonder how it can catch the next pulse without any problem? In that case it should be stuck in the DoUSBOut routine.

I will make a test to measure 16 pulses, save all values in buffer(0) to buffer(31) and then send all 32byte to the pc. Sending 32 bytes takes 22.4us according to my tests so that should be just fine from the pic point of view. It will be interesting to se how the pc handle it.

Unfortunatley I need to measure all pulses. I use the values in the vb app to calculate acceleration, rpm and total revs.

My next task is to simultaneously check the USBIn for new data.
This without halting the program. I have made some test with the code example from bruce at post:
http://www.picbasic.co.uk/forum/showpost.php?p=15305&postcount=3
This seems to work but I have not test it at higher speed yet.
Do you have any other good solutions to do this? Maybe using USB interrupt USBIF or something else?

I'll let you know about my further test.

Thanks again.

Stefan.

Darrel Taylor
- 17th January 2007, 01:18
> Can it be the vb app that is the bottleneck here?

I was using a Delphi App, also created by EasyHID, and saw the same thing. So I doubt it's anything to do on the PC side.

> If the pic is the bottleneck then I wonder how it can catch the next pulse without any problem? In that case it should be stuck in the DoUSBOut routine.

As long as the frequency is less than 125hz, it never get's a BUSY response. But, once it goes above that, it does get "stuck in the DoUSBOut routine".
This becomes evident if you try the first example in Post#8.

> I will make a test to measure 16 pulses, save all values in buffer(0) to buffer(31) and then send all 32byte to the pc.

I guess it depends on the highest frequency you'll need to measure, but you may not need to go that high. For say 10,000 RPM, you'll only need about 166 samples per second (Unless there are multiple pulses per rev). So if you capture 2 samples per report, you'll only need 83 reports per second, which should be well within the limits, and give a faster "Update Rate".

> Do you have any other good solutions to do this? Maybe using USB interrupt USBIF or something else?

Well, there's this ...
Instant Interrupts - Revisited, post 148
http://www.picbasic.co.uk/forum/showthread.php?p=30682#post30682

Which works with this ...
USBDemo, something to learn USB a little bit
http://www.picbasic.co.uk/forum/showthread.php?t=5418
<br>

sjohansson
- 18th January 2007, 22:21
Thanks Darrel.

Fels like I'm on the right track again.
I made some tests with USBIn today and it seems to work.
I call DoUSBIn directly after the DoUSBOut so it has time enough to transmit before the next high pulse trig the ccp input.
And if the drum is not rotating DoUSBIn is called by interval using Timer3.

Regards

Stefan.