PDA

View Full Version : USB Serial Communication Continuous



pic-ker
- 10th February 2007, 18:42
Hi everyone... Im working on a device to receive serial data wirelessly (2400 baud) and then transfer it to a PC using USB. I have completed the hardware and the PIC interface however im unable to get the 18F4550 to send correct data to the PC [I get 3 characters ok...and garbage later]

Tx is a PIC 18F4550 connected to USB and RF module
I found a great USBDemo code by mister_e on this site which i modified for this...

Tx code:

Clear
DEFINE OSC 20

CMCON = 7 ' TURN ANALOG COMPARATOR MODE OFF

Include "modedefs.bas"
TRISA = %11111111
TRISB = %00000000
TRISC = %10000000
TRISD = %00000000
TRISE = %00000000

PORTA = %00000000
PORTB = %00000000
PORTC = %00000000
PORTD = %00000000
PORTE = %00000000

T2CON = %00000101
UCFG var byte EXT
ucfg = %00010100

INTCON = %10100000
T0CON = %10000000

SerialData var byte

USBBufferSizeTX con 8 ' input
USBBufferSizeRX con 8 ' output
USBBufferCount Var Byte '
USBBufferIn var byte[8] ' store incomming USB data
USBBufferOut Var Byte[8] ' store outgoing USB data

TMR0IF VAR INTCON.2 ' TMR0 overflow int flag
TMR0ON VAR T0CON.7 ' TMR0 on/off bit
TMR0IE VAR INTCON.5 ' TMR0 interrupt enable/disable bit

' Macro(s) definition
' ===================
goto SwHwInit ' skip macros
asm
Reload_TMR0 macro
; Use to stop, reload, clear overflow flag and restart TMR0
BCF _TMR0ON ; stop timer
MOVE?CW d'65000',TMR0L ; reload for timebase ~100uSec
BCF _TMR0IF ; clear overflow flag
BSF _TMR0ON ; start timer
ENDM

SendUSB macro array
; Use to Copy an specific array to USBBufferOut AND send it
; to USB bus
variable i=0
while i<8
MOVE?BB (array+i),(_USBBufferOut+i)
i+=1
endw
L?CALL _DoUSBOut
endm
endasm

SwHwInit:
pause 500 ' Settle delay
usbinit ' initialise USB
PAUSE 20 ' Delay after initializing USB
@ Reload_TMR0 ; Reload timer0
ON INTERRUPT GOTO DoUSBService


' Main program start
' ==================
Start:

IF USBBufferIn[7]=239 then
SEROUT PORTC.0,N2400,[USBBUFFERIN[7]]
GOSUB DoLow
USBBufferin[7]=0

if USBBufferIn[1]<>0 then
SEROUT PORTC.0,N2400,[USBBufferIn[1]]
GOSUB DoLow
USBBufferIn[1]=0
endif
USBService
if USBBufferIn[2]<>0 then
SEROUT PORTC.0,N2400,[USBBufferIn[2]]
GOSUB DoLow
USBBufferIn[2]=0
endif
USBService
if USBBufferIn[3]<>0 then
SEROUT PORTC.0,N2400,[USBBufferIn[3]]
GOSUB DoLow
USBBufferin[3]=0
endif
USBService
if USBBufferIn[4]<>0 then
SEROUT PORTC.0,N2400,[USBBufferIn[4]]
GOSUB DoLow
USBBufferin[4]=0
endif
USBService
if USBBufferIn[5]<>0 then
SEROUT PORTC.0,N2400,[USBBufferIn[5]]
GOSUB DoLow
USBBufferin[5]=0
endif
USBService
if USBBufferIn[6]<>0 then
SEROUT PORTC.0,N2400,[USBBufferIn[6]]
GOSUB DoLow
USBBufferin[6]=0
endif
USBService
else
if USBBUFFERin[7]<>0 then
SEROUT PORTC.0,N2400,[USBBufferin[7]]
GOSUB DoLow
USBBUFFERin[7]=0
endif
USBSERVICE
endif

gosub dousbin


goto start

DoLow:
LOW PORTC.0
USBSERVICE
PAUSE 30
USBSERVICE
return

DoUSBIn:

tmr0ie = 0 ' disbale TMR0 int
USBBufferCount = USBBufferSizeRX ' RX buffer size
USBService ' keep connection alive

USBIn 1, USBBufferin, USBBufferCount, Timeout ' read data, if available
Timeout: '
@ Reload_TMR0
tmr0ie = 1 ' re-enable TMR0 int
PORTB = USBBUFFERIN[0] ' output to PORTB
return


DoUSBOut:
TMR0IE = 0 ' Disable TMR0 interrupt
WaitPC: '
USBBufferCount = USBBufferSizeTX ' TX buffer size
USBService ' keep connection alive
USBOut 1, USBBufferOut, USBBufferCount, Waitpc ' if bus available, transmit data
@ Reload_TMR0
tmr0ie=1 ' Re-Enable TMR0 interrupt
return

DISABLE
DoUSBService:
usbservice ' keep connection alive
@ Reload_TMR0 ; reload timer
RESUME ' getout of here
ENABLE

' The TX is working....i can see the o/p on the oscilloscope...i have given a 30ms break after every 2400baud character
'The VB Program transmits char=239[ for sync with receiver] on USBBufferin[7] and the rest are valid data

Here's the receiver code:


Clear
DEFINE OSC 20

DEFINE HSER_RCSTA 90h ' Set receive register to receiver enabled
DEFINE HSER_TXSTA 24h
DEFINE HSER_BAUD 2400 ' Set baud rate
DEFINE HSER_SPBRG 51 ' Set SPBRG directly (normally set by HSER_BAUD)

Include "modedefs.bas"
TRISA = %11111111
TRISB = %00000000
TRISC = %10000000
TRISD = %00000000
TRISE = %00000000

PORTA = %00000000
PORTB = %00000000
PORTC = %00000000
PORTD = %00000000
PORTE = %00000000

T2CON = %00000101 ' TMR2 on, prescaler 1:4
UCFG var byte EXT ' include UCFG register
ucfg = %00010100 ' enable internal USB pull-up, Full speed USB

INTCON = %10100000 ' Enable global and TMR0 interrupts
T0CON = %10000000 ' TMR0, CLK internal, prescaler 1:2, T0ON

RCIF VAR PIR1.5 ' Receive interrupt flag (1=full , 0=empty)
TXIF VAR PIR1.4 ' Transmit interrupt flag (1=empty, 0=full)

SerialData var byte
B0 VAR BYTE
USBBufferSizeTX con 8 ' input
USBBufferSizeRX con 8 ' output
USBBufferCount Var Byte '
USBBufferIn var byte[8] ' store incomming USB data
USBBufferOut Var Byte[8] ' store outgoing USB data
DataToSend var byte[8] ' store ADCs & pushButton data to send to USB

TMR0IF VAR INTCON.2 ' TMR0 overflow int flag
TMR0ON VAR T0CON.7 ' TMR0 on/off bit
TMR0IE VAR INTCON.5 ' TMR0 interrupt enable/disable bit

CR CON 13
Char VAR BYTE


goto SwHwInit ' skip macros
asm
Reload_TMR0 macro
; Use to stop, reload, clear overflow flag and restart TMR0
BCF _TMR0ON ; stop timer
MOVE?CW d'65000',TMR0L ; reload for timebase ~100uSec
BCF _TMR0IF ; clear overflow flag
BSF _TMR0ON ; start timer
ENDM

SendUSB macro array
; Use to Copy an specific array to USBBufferOut AND send it
; to USB bus
variable i=0
while i<8
MOVE?BB (array+i),(_USBBufferOut+i)
i+=1
endw
L?CALL _DoUSBOut
endm
endasm


SwHwInit:
pause 500 ' Settle delay
usbinit ' initialise USB
PAUSE 20 ' Delay after initializing USB
@ Reload_TMR0 ; Reload timer0
ON INTERRUPT GOTO DoUSBService

DataToSend[0] = 0
datatosend[2] = 0 'PORTA.2
datatosend[3] = 0 'PORTA.3
datatosend[4] = 0 'PORTA.4
datatosend[5] = 0 'PORTA.5
datatosend[6] = 0
datatosend[7] = 0

'Main Prog starts here
Start:

if RCIF then
HSERIN [DatatoSend[2]] ' take it
@ SendUSB _DataToSend
endif

gosub dousbin

goto Start


DoUSBIn:
tmr0ie = 0 ' disbale TMR0 int
USBBufferCount = USBBufferSizeRX ' RX buffer size
USBService ' keep connection alive

USBIn 1, USBBufferin, USBBufferCount, Timeout ' read data, if available
Timeout: '
@ Reload_TMR0
tmr0ie = 1 ' re-enable TMR0 int
PORTB = USBBUFFERIN[0] ' output to PORTB

' Not using USBBufferIn[1,2,3,4]

return

DoUSBOut:
TMR0IE = 0 ' Disable TMR0 interrupt
WaitPC: '
USBBufferCount = USBBufferSizeTX ' TX buffer size
USBService ' keep connection alive
USBOut 1, USBBufferOut, USBBufferCount, Waitpc ' if bus available, transmit data
@ Reload_TMR0
tmr0ie=1 ' Re-Enable TMR0 interrupt
return

DISABLE
DoUSBService:
usbservice ' keep connection alive
@ Reload_TMR0 ; reload timer
RESUME ' getout of here
ENABLE


' The VB Program receives the Serial Data using the USBBuffer[2]
I know the the connections work coz if i touch the RX pin i get a string of '255's in the VB prog...
Any suggestions why the text is garbled ? ( I have tried all combinations of T2400,N2400 etc...)
I have also tried using another PIC (628) to receive the serial data and convert it to a parallel o/p on its port and feed it to the 4550...but that doesnt work as well...
At the moment im testing it using two wires (data,gnd) between Tx and Rx and I will add the RF module later

mister_e
- 10th February 2007, 18:49
I've never tried with a DEFINE OSC 20... but i think it's the main problem.

Look how i did it in mine. (config fuse as well)

and now


DoLow:
LOW PORTC.0
USBSERVICE
PAUSE 30
USBSERVICE
return


This example don't use instant interrupt, inserting a PAUSE and using On INTERRUPT GOTO might cause some problem for the USBSERVICE.

next point...i don't know what's happen if you use both HSER_BAUD and HSER_SPBRG together... Assuming HSER_SPBRG may override the HSER_BAUD, you have a big problem as your SPBRG value is way out of range @20MHZ... but good @8MHZ.

to have 2400 baud @20MHZ, you should use...


DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive
DEFINE HSER_TXSTA 20h ' Enable transmit, BRGH = 0
DEFINE HSER_SPBRG 129 ' 2400 Baud @ 20MHz, 0.17%
DEFINE HSER_CLROERR 1 ' Clear overflow automatically


I do believe the HSER_CLROERR may help a little bit.

There's probably something else... i feel a bit lazy today ;)

pic-ker
- 10th February 2007, 18:58
I've never tried with a DEFINE OSC 20... but i think it's the main problem.

Look how i did it in mine. (config fuse as well)

I have tried it with a DEFINE OSC 48 as well....infact the USB interface works fine...i tried to switch on/off the LED pins on you demo and they work ...

The config fuses are
24 0E 3E 00 00 83 81 00 0F C0 0F E0 0F 40

in either case (48 or 20)
i have defined the PLL and OSC setting in the .inc file so the DEFINE directive has no effect


in the case of :

DoLow:
LOW PORTC.0
USBSERVICE
PAUSE 30
USBSERVICE
return

i found that this code does work...and it does generate a delay of 30ms on the Oscilloscope without affecting the Tx USB connection....The TX seems to be transmitting fine...

pic-ker
- 10th February 2007, 19:02
DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive
DEFINE HSER_TXSTA 20h ' Enable transmit, BRGH = 0
DEFINE HSER_SPBRG 129 ' 2400 Baud @ 20MHz, 0.17%
DEFINE HSER_CLROERR 1 ' Clear overflow automatically

I do believe the HSER_CLROERR may help a little bit.

Thanks, I'll try that now...

pic-ker
- 10th February 2007, 20:33
I havre tried all the above statements....

DEFINE HSER_CLROERR 1 is now inculded...

however im still getting errors...
i transmit : 239 65 66 67
I receive : 254 254 6 134 128
(5 chars for tx of 4 chars)

maybe its because i used SEROUT in conjunction with HSERIN ?

mister_e
- 11th February 2007, 13:01
And... do you get always the same results or they are always different?

pic-ker
- 12th February 2007, 11:07
Differnet results each time...


Anyway I have finally got the TX/RX to work !

Heres the section of the TX code which works:

IF USBBufferIn[7]=239 then
SEROUT PORTC.0,T2400,[USBBUFFERIN[7]]
gosub DoLow
USBBufferin[7]=0

if USBBufferIn[1]<>0 then
SEROUT PORTC.0,T2400,[USBBufferIn[1]]
gosub DoLow
USBBufferIn[1]=0
endif
USBService
if USBBufferIn[2]<>0 then
SEROUT PORTC.0,T2400,[USBBufferIn[2]]
gosub DoLow
USBBufferIn[2]=0
endif
USBService
if USBBufferIn[3]<>0 then
SEROUT PORTC.0,T2400,[USBBufferIn[3]]
gosub DoLow
USBBufferin[3]=0
endif
USBService
if USBBufferIn[4]<>0 then
SEROUT PORTC.0,T2400,[USBBufferIn[4]]
gosub DoLow
USBBufferin[4]=0
endif
USBService
if USBBufferIn[5]<>0 then
SEROUT PORTC.0,T2400,[USBBufferIn[5]]
gosub DoLow
USBBufferin[5]=0
endif
USBService
if USBBufferIn[6]<>0 then
SEROUT PORTC.0,T2400,[USBBufferIn[6]]
gosub DoLow
USBBufferin[6]=0
endif
USBService
endif

gosub dousbin


goto start

DoLow:
USBSERVICE
PAUSE 65
USBSERVICE
return

Notes:
1. You need to use the T mode if you are directly connecting PIC's.
2. Notice the Pause 65 - It now works great with a longer delay...and has no effect on the USB connection.


Heres part of the modified RX code :

DEFINE HSER_CLROERR 1 ' Clear overflow automatically
Define HSER_RCSTA 90h
Define HSER_BAUD 2400

The oscillator is set to 20Mhz in both cases using : DEFINE OSC 20
__________________________________________________ _______________

Now that the wired link is working....I checked it using a FSK TX/RX pair
and the problems are endless....
Completely random characters etc
Characters appear when i move my hand in the air !
I have tried a passive Bandpass filter around 2400hz but it doesnt sove the problem...
I have connected a Schottky TTL gate to the DataOut...for maintaining proper level transitions...
Also when I connect a LED to the DataOut of the RX it keeps flickering at a fast rate (around 10kz on the oscilloscope),even when the Tx is off...which is probably whats causing the errors..

Any ideas on how to fix this ? or is the RF module faulty ?

Dave
- 12th February 2007, 13:00
pic-ker, I bet the RF receiver module you are trying to use has no squelch control and the toggling of the receiver output is the data slicer trying to interpret noise. You will have to put some kind of sync and preamble bytes in place before you transmit the data and, if the sync and preamble bytes are not received in order and correctly you should not accept the data. This is the common problem people have when using inexpensive rx and tx modules. Even with more expensive modules the same sync/preamble techniques should be used. Also you should send a computed checksum as the last byte and this checksum should be checked at the receiver end before using the data received.

Dave Purola,
N8NTA

pic-ker
- 12th February 2007, 13:08
pic-ker, I bet the RF receiver module you are trying to use has no squelch control and the toggling of the receiver output is the data slicer trying to interpret noise. You will have to put some kind of sync and preamble bytes in place before you transmit the data and, if the sync and preamble bytes are not received in order and correctly you should not accept the data. This is the common problem people have when using inexpensive rx and tx modules. Even with more expensive modules the same sync/preamble techniques should be used. Also you should send a computed checksum as the last byte and this checksum should be checked at the receiver end before using the data received.

Dave Purola,
N8NTA

Yeah, youre right, the module was really cheap ... it doesnt have a crystal based oscillator, rather there is an inductor coil which can be adjusted by a screwdriver....

I think it would be better if I get another module :-) instead of doing all that syncing/CRCing etc

Dave
- 12th February 2007, 13:18
pic-ker, Even if you buy a more expensive rf module pair you will still have the same problem. I speak of a squelch circuit that mutes the data line from the receiver when there is no received carrier. However you will still have to send some kind of sync byte for the program to lock onto for the data stream. Also if you don't send some kind of checksum with the data packet you will have no idea of the data bytes in the packet are valid.

Dave Purola,
N8NTA

pic-ker
- 12th February 2007, 14:36
I am sending a sync packet of '239' in a frame of 6 characters, But I find that there is no need for error checking as I am using this mainly for text messaging..

dave, do you have any kind of squelch circuit in mind ? and how do I detect when the carrier is present ?

Dave
- 12th February 2007, 16:36
pic-ker, There is no easy way to add a squelch circuit unless the receiver you are using has an RSSI output available. This stands for "Reletive Signal Strength Indicator" and it is an output usually derived from the IF portion of the receiver. If this analog signal was to be compared to a reference voltage that signal strength would be the level that the signal has to be to (open or unsquelch or unmute) the the data stream.

Dave Purola,
N8NTA

mister_e
- 12th February 2007, 16:46
Few post before you said you didn't use the RF for now.. is this still true?

If you receive always different things, it sounds like a baudrate problem to me... dpending your config fuses settings, hardware it may ruine your whole life..

try a simple serial comm before adding the USB.

skimask
- 13th February 2007, 00:53
I am sending a sync packet of '239' in a frame of 6 characters, But I find that there is no need for error checking as I am using this mainly for text messaging..

dave, do you have any kind of squelch circuit in mind ? and how do I detect when the carrier is present ?

There's a big, long thread (Serin Serout Problem is what I think it's called) that's got loads of good info on how to use some of those cheap RF modules, explanations on the preambles, sync's, etc.etc., why you need them, how many to put out there, etc. Lots of answers for you in there...

pic-ker
- 13th February 2007, 10:44
Few post before you said you didn't use the RF for now.. is this still true?

If you receive always different things, it sounds like a baudrate problem to me... dpending your config fuses settings, hardware it may ruine your whole life..

try a simple serial comm before adding the USB.

Its true, I tested the TX/RX using a wire initially and there were absolutely no problems with the baudrate or noise etc

Now that I have attached the RF modules I get errors..its probably because this module uses ASK

Ideally the module should not require CRC bits, what I mean is if you send a '1' you should get a '1'

Im trying another data link from here:
www.cappels.org/dproj/LCRFLINK/LCRFLINK.htm

i'll try it and let you guys know...

skimask
- 13th February 2007, 13:53
Its true, I tested the TX/RX using a wire initially and there were absolutely no problems with the baudrate or noise etc
Now that I have attached the RF modules I get errors..its probably because this module uses ASK
Ideally the module should not require CRC bits, what I mean is if you send a '1' you should get a '1'
Im trying another data link from here:
www.cappels.org/dproj/LCRFLINK/LCRFLINK.htm
i'll try it and let you guys know...

Most of those RF modules use ASK. And generally, they don't need CRC bits (that's all up to you), but what they do need is manchester encoding (aka bi-phase encoding) to keep the internal data slicer from losing it's mind.
Search for and check that thread I mentioned earlier and you'll see. Basically, you end up cutting your data rate in half by changing all the 1's to '10' and 0's to '01'. Sounds silly but it works great.

pic-ker
- 14th February 2007, 13:27
Most of those RF modules use ASK. And generally, they don't need CRC bits (that's all up to you), but what they do need is manchester encoding (aka bi-phase encoding) to keep the internal data slicer from losing it's mind.
Search for and check that thread I mentioned earlier and you'll see. Basically, you end up cutting your data rate in half by changing all the 1's to '10' and 0's to '01'. Sounds silly but it works great.

I got my RF module to work...I was using the +VCC from the USB port to power the receiver and that was causing some continuous ripple

I used a battery supply,connected the grounds,used a 0.01uF decoupling cap and now it works..

Thank you guys for your suggestions...
I will post the complete project once the VB.net Code is complete..