PDA

View Full Version : USB to RS232 adapter



PJALM
- 24th February 2007, 20:24
Is it possible to use a PIC18F2550 as a USB to RS232 adapter with PBP by using the CDC mode?

vacpress
- 24th February 2007, 23:53
the microchip site has firmware to make a USB PIC into a serial convertor. It is fairly well documented. somewhere on the site

www.microchip.com

it is one of the first things i learned about when i began investigating PIC USB

-R

Darrel Taylor
- 25th February 2007, 00:00
Or, if you wanted to stick with PicBasic, you could try the usbcdc.bas example in the USB18 folder.
<br>

PJALM
- 25th February 2007, 00:44
I have looked at booth but they are incomplete.

I have tried to capture data from the RS232 port on the pic and output it to the USB and also from the USB to the RS232 with no sucess.

All examples are just on how to emulate the CDC.

I basically need a USB to RS232 adapter like those you can buy in any store.

I have tons of these 18F2550 chips and would rather use them to convert my exsisting projects instead of going and buying some.

PJALM
- 25th February 2007, 04:05
Ok, I got it to go from USB to the RS232 but I still cannot get the RS232 to USB to work. Here is the code I have so far.



DEFINE OSC 48

INCLUDE "modedefs.bas"

Buffer VAR BYTE[16]
Cnt VAR BYTE
B0 VAR BYTE

PIC_TX VAR PORTC.6 ' Transmit Pin
PIC_RX VAR PORTC.7 ' Receive Pin

ADCON1 = 15 ' Set all I/Os to Digital
INTCON2.7 = 1 ' Disable PortB Pullups
CMCON = 7 ' Disable Comparators

USBInit

' Main Program Loop
MainLoop:
USBService ' Must service USB regularly
cnt = 16
USBIn 3, Buffer, Cnt, MainLoop

SEROUT2 PIC_TX,84,[STR Buffer\Cnt]

Get_RS232_Data:
SERIN PIC_RX,T9600,100,Get_RS232_Data_Timeout,B0
Buffer[0] = B0
Cnt = 1
GOTO OutLoop

Get_RS232_Data_Timeout:
Buffer[0] = 0
Cnt = 0

OutLoop:
USBService ' Must service USB regularly

IF Cnt > 0 Then
USBOut 3, Buffer, Cnt, OutLoop
ENDIF

GOTO Mainloop

skimask
- 25th February 2007, 04:11
Using a MAX232 type chip in the circuit?
Depending, you might have to use N9600 instead of T9600

PJALM
- 25th February 2007, 04:13
Yes, I am using the MAX232 between the PIC18F2550 and the RS232 port.

Darrel Taylor
- 25th February 2007, 05:39
At a quick glace, there's a couple problems. Maybe more, but haven't tested it yet.

With the first USBIN, if there isn't any incoming data from USB, it just loops back to MainLoop. It never makes it to SERIN, unless it receives data from USB at the same time.

You really should use HSERIN. The RS232 data may start while the program is sending or receiving USB data, in which case you would not be able to catch it with SERIN.

Added: And the 100ms timeout on the SERIN will cause it to lose the USB connection, since it isn't servicing it anymore.
<br>

PJALM
- 25th February 2007, 06:02
Ok, I got it all working now. I took Darrel's advice and switched to using HSERIN and HSEROUT but added the use of hardware interrupts to capture the RS232 data.

Here's the new code:



DEFINE OSC 48
DEFINE HSER_RCSTA 90h
DEFINE HSER_TXSTA 20h
DEFINE HSER_BAUD 9600
DEFINE HSER_CLROERR 1

INCLUDE "modedefs.bas"

Buffer VAR BYTE[16]
Cnt VAR BYTE
B0 VAR BYTE
PIC_TX VAR PORTC.6 ' Transmit Pin
PIC_RX VAR PORTC.7 ' Receive Pin
LED1A VAR PORTB.0 ' 2 Color LED #1
LED1B VAR PORTB.1
LED2A VAR PORTB.2 ' 2 Color LED #2
LED2B VAR PORTB.3

ADCON1 = 15 ' Set all I/Os to Digital
INTCON2.7 = 1 ' Disable PortB Pullups
CMCON = 7 ' Disable Comparators

'-------------------------------------------------------------------------------
' Interrupt Settings
'-------------------------------------------------------------------------------
RCON.7 = 0 ' Disable Priority Interrupts, 1 to Enable

' Enable/Disable Interrupts
INTCON.4 = 0 ' Disable INT0 (PORTB.0)
INTCON3.3 = 0 ' Disable INT1 (PORTB.1)
INTCON3.4 = 0 ' Disable INT2 (PORTB.2)
INTCON.5 = 0 ' Disable TMR0 (Timmer 0)
INTCON.6 = 1 ' Enable Peripheral Interrupts
INTCON.7 = 1 ' Enable Global Interrupt Handler
PIE1.4 = 0 ' Disable USART Transmit Interrupt
PIE1.5 = 1 ' Enable USART Receive Interrupt
PIE2.5 = 0 ' Disable USB Interrupt

LOW LED1A ' Turn LED #1 Green
HIGH LED1B
LOW LED2A ' Turn LED #2 Off
LOW LED2B

PAUSE 500

USBInit

ON INTERRUPT GOTO Main_Interrupt_Handler
ENABLE INTERRUPT

' Main Program Loop
MainLoop:
USBService ' Must service USB regularly
Cnt = 16
USBIn 3, Buffer, Cnt, MainLoop

HIGH LED2A
PAUSE 25

HSEROUT [STR Buffer\Cnt]

LOW LED2A

GOTO Mainloop


'-------------------------------------------------------------------------------
' Interrupt Handler
'-------------------------------------------------------------------------------
DISABLE INTERRUPT ' No Interrupts past this point
Main_Interrupt_Handler:

'---------------------------------------------------------------------------
' USART Transmit Interrupt
'---------------------------------------------------------------------------
IF PIR1.4 = 1 THEN
PIR1.4 = 0
ENDIF
'---------------------------------------------------------------------------


'---------------------------------------------------------------------------
' USART Receive Interrupt
'---------------------------------------------------------------------------
IF PIR1.5 = 1 THEN
HIGH LED2B
PAUSE 25

HSERIN [B0]
Buffer[0] = B0
Cnt = 1

OutLoop:
USBService ' Must service USB regularly
USBOut 3, Buffer, Cnt, OutLoop

LOW LED2B

PIR1.5 = 0
ENDIF
'---------------------------------------------------------------------------

IntDone:
RESUME ' Return to main program
ENABLE INTERRUPT
'-------------------------------------------------------------------------------

END

Darrel Taylor
- 25th February 2007, 14:20
That was pretty quick!

I've been playing with the program here and can say that the two PAUSE 25 statements, have to GO.

Of course that messes up the LED's, but with the pauses in there, it only picks up every 7 or 8th character when sending continuous data.

Without them, it works pretty good, but it's still a bit slow.
Test data of about 1500 bytes takes nearly 3 times as long as it should. Around 1.2 sec.

I think circular buffers would help speed it up, since it has to wait till it's finished sending the HSEROUT before in can receive more data from the USB. But I guess that depends on how fast you need it to be.
<br>

PJALM
- 25th February 2007, 16:33
Thanks Darrel. I have eliminated the LEDs all together because there is really no need for them. I was testing it by just using a terminal program on 2 computers so I never noticed the speed problem till now. How do I impliment the circular buffers you mentioned?

Darrel Taylor
- 26th February 2007, 00:01
Me and my big mouth. :o

I wish I had time to work something up, but I've got too many things going on already.

You might take a look at this post by Joe S.
http://www.picbasic.co.uk/forum/showthread.php?p=28233

He's got a buffer in there for serial RX. Should give you a start.
But you really need to buffer both RX and TX.

busy busy,

Squibcakes
- 26th February 2007, 03:25
Hi Guys I've been working on the same - I can get a Half duplex data communication going but not full duplex (rs232-> usb and vice versa).

This program seems to do the trick, but even with the pauses removed I still only achieve a stable data rate at 9600 when sending large text files.

I'll try using the DT method (DT_int_18) interrupts and see if this speeds things up.

Circular buffers? The mind boggles!

Cheers

mister_e
- 26th February 2007, 03:31
i doubt it would be if you used the EUSART but may worth to try..

PicMultiCalc gaves me...

DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive
DEFINE HSER_TXSTA 24h ' Enable transmit, BRGH = 1
DEFINE HSER_CLROERR 1 ' Clear overflow automatically
DEFINE HSER_SPBRG 225 ' 9600 Baud @ 48MHz, 0.0%
SPBRGH = 4
BAUDCON.3 = 1 ' Enable 16 bit baudrate generator



mixing INT_18 and asm would certainly have some great effect.

Darrel Taylor
- 26th February 2007, 03:50
I can get a Half duplex data communication going but not full duplex

USB is a Half-Duplex protocol. There's no way to have TRUE full-duplex. 2-wires, differential levels, can only do one thing at a time.

However, with the proper buffers in place, you can make it seem like it's "FULL", in that you can send and receive at the same time from the USART. But it never truely will be Full-duplex for the USB.
<br>

Squibcakes
- 26th February 2007, 04:08
Yeah your right,

I guess what I should have said was this.

I can transmit in only one direction usb->usart, or usart->usb, not in the same program. Never mind now. I'm confused... ;(

Using Int_18 has def. sped things up!

Now I can transfer from USB->Usart successfully at 57600 baud, however Usart->Usb still only good enough at 9600 when sending text file. (Sending single key strokes is fine both directions at any speed).

I figure that the usart buffer needs to be increased as this is the bottle neck.


Cheers

Darrel Taylor
- 26th February 2007, 04:53
I think you'll find that while from USB to USART works fine. It's massively buffered by the PC. If you were to send the same text file directly to a com port at 57600, it would take 1/3 as long to transmit.

This is because the PIC waits untill the last buffer full of data is sent via HSEROUT, before allowing it to receive more from the USB. The PC does the buffering, instead of the PIC.

And on the other side of it. This program is only sending 1 byte at a time to the USB. You can send up to 64. If it were buffered at the PIC, it could save incomming 232 data while it's busy sending to USB, then send a larger packet on the next time around. I think this would greatly improve the overall speed.

Theoretically, you should be able to run quasi-full-duplex at 250kbaud, without any problems.
<br>

PJALM
- 26th February 2007, 18:23
Squibcakes: Is it possible to get a copy of the source you have working with the DT interrupts? I greatly apreciate all the help you guys are giving me.

Thanks.

Squibcakes
- 27th February 2007, 01:31
Sure thing brother,

Play around with the baud rates and see what max data speed you get. 250K would be awesome! but I think some sought of hardware hand shaking is needed to get up to those speeds. Hahaha

Anyway, first step I think is to increase the buffer size form 1 char to as DT said, about 64 Chars.



'************************************************* ***************

INCLUDE "DT_INTS-18.bas" ; Base Interrupt System
INCLUDE "ReEnterPBP-18.bas" ; Include if using PBP interrupts

' USB sample program for PIC18F4550 CDC serial port emulation

' Compilation of this program requires that specific support files be
' available in the SOURCE DIRECTORY!!

' 18F*.BAS Device header files that use the USB libraries
' CDCDESC.ASM Descriptor file for CDC serial demo
' JADESC.ASM Descriptor file for Jan Axelson demo
' MOUSDESC.ASM Descriptor file for mouse demo
' PBPCDC.INF INF file for the CDC serial driver
' USB.TXT This file
' USB18.ASM USB assembler file
' USB18.INC USB definitions file
' USB18MEM.ASM USB memory allocation file
' USBCDC.BAS CDC serial demo BASIC program file
' USBDESC.ASM Include file for descriptor file

' You WILL also need to modify the
' file USBDESC.ASM so that the only line used is -> include "CDCDESC.ASM"

' MUST use the 4 MHz xtal for this.
' this program receives data via usb virtual port then sends out via serial
' usart.


' USART module
' ------------
Define OSC 48
DEFINE HSER_RCSTA 90h
DEFINE HSER_TXSTA 20h
DEFINE HSER_BAUD 4800
DEFINE HSER_CLROERR 1

' USB module
' ----------
UCFG var byte EXT ' include UCFG register... Yeah Melabs didn't :o(
ucfg = %00010100 ' enable internal USB pull-up, Full speed USB

' ANALOG I/O CONFIG
' -----------------
ADCON1 = 15 ' Set all I/Os to Digital
CMCON = 7 ' Disable Comparator

Buffer VAR BYTE[16]
Cnt VAR BYTE
B0 VAR BYTE

ASM
INT_LIST macro ; IntSource,Label,Type,ResetFlag?
INT_Handler RX_INT,_SendUsB,PBP,yes
endm
INT_CREATE ; Creates the interrupt processor
INT_ENABLE RX_INT ; enable external (RX) interrupts
ENDASM

USBInit

' Main Program Loop

MainLoop:
USBService ' Must service USB regularly
Cnt = 16
USBIn 3, Buffer, Cnt, MainLoop

HSEROUT [STR Buffer\Cnt]
GOTO Mainloop

'---[RX_INT - interrupt handler]------------------------------------------------
' PROGRAM COMES HERE WHEN DATA ENTERS THE USART PORT
SendUsB:
HSERIN [B0]
Buffer[0] = b0
cnt = 1

OutLoop:
USBService ' Must service USB regularly
USBOut 3, Buffer, Cnt, OutLoop

@ INT_RETURN


Cheers

mpardinho
- 12th October 2007, 01:37
Data of hserin is ok

............
USBService ' Must service USB regularly

Cnt = 10
USBIn 3, Buffer, Cnt, MainLoop

' Send to pc data recived from pc
GOTO OutLoop <---------not work, not send buffer

GOTO Mainloop
.........




INCLUDE "modedefs.bas"

' Configuração
asm
__CONFIG _CONFIG1L, _PLLDIV_1_1L & _CPUDIV_OSC1_PLL2_1L & _USBDIV_2_1L
; ; ; USB clock source comes from the 96 MHz PLL divided by 2
; ; [OSC1/OSC2 Src: /1][96 MHz PLL Src: /2]
; No prescale (4 MHz oscillator input drives PLL directly)


__CONFIG _CONFIG1H, _FOSC_XTPLL_XT_1H & _FCMEN_OFF_1H & _IESO_OFF_1H
; ; ; Oscillator Switchover mode disabled
; ; Fail-Safe Clock Monitor disabled
; XT oscillator, PLL enabled, XT used by USB
__CONFIG _CONFIG2L, _PWRT_ON_2L & _BOR_ON_2L & _BORV_2_2L & _VREGEN_ON_2L
__CONFIG _CONFIG2H, _WDT_OFF_2H
__CONFIG _CONFIG3H, _MCLRE_ON_3H & _LPT1OSC_OFF_3H & _PBADEN_OFF_3H & _CCP2MX_ON_3H
__CONFIG _CONFIG4L, _STVREN_ON_4L & _LVP_OFF_4L & _XINST_OFF_4L & _DEBUG_OFF_4L
__CONFIG _CONFIG5L, _CP0_ON_5L & _CP1_ON_5L & _CP2_ON_5L & _CP3_ON_5L
__CONFIG _CONFIG5H, _CPB_ON_5H
endasm

DEFINE OSC 48

DEFINE HSER_RCSTA 90h
DEFINE HSER_TXSTA 20h
DEFINE HSER_BAUD 9600
DEFINE HSER_CLROERR 1

Buffer VAR BYTE[16]
Cnt VAR BYTE
A VAR BYTE
B VAR BYTE
C VAR BYTE


PIC_TX VAR PORTC.6 ' Transmit Pin
PIC_RX VAR PORTC.7 ' Receive Pin

ADCON1 = 15 ' Set all I/Os to Digital
INTCON2.7 = 1 ' Disable PortB Pullups
CMCON = 7 ' Disable Comparators

' Interrupt Settings
RCON.7 = 0 ' Disable Priority Interrupts, 1 to Enable

' Enable/Disable Interrupts
INTCON.4 = 0 ' Disable INT0 (PORTB.0)
INTCON3.3 = 0 ' Disable INT1 (PORTB.1)
INTCON3.4 = 0 ' Disable INT2 (PORTB.2)
INTCON.5 = 0 ' Disable TMR0 (Timmer 0)

INTCON.6 = 1 ' Enable Peripheral Interrupts
INTCON.7 = 1 ' Enable Global Interrupt Handler

PIE1.4 = 0 ' Disable USART Transmit Interrupt
PIE1.5 = 1 ' Enable USART Receive Interrupt
PIE2.5 = 0 ' Disable USB Interrupt

PAUSE 1000

USBInit

ON INTERRUPT GOTO Main_Interrupt_Handler
ENABLE INTERRUPT

' Main Program Loop
MainLoop:
USBService ' Must service USB regularly

Cnt = 10
USBIn 3, Buffer, Cnt, MainLoop

' Send to pc data recived from pc
GOTO OutLoop

GOTO Mainloop

' Interrupt Handler
'-------------------------------------------------------------------------------
DISABLE INTERRUPT ' No Interrupts past this point
Main_Interrupt_Handler:
' USART Transmit Interrupt
IF PIR1.4 = 1 THEN
PIR1.4 = 0
ENDIF

' USART Receive Interrupt
IF PIR1.5 = 1 THEN
HSERIN [A, B, C]

Buffer[0] = A
Buffer[1] = B
Buffer[2] = C
Buffer[3] = 13
Buffer[4] = 10
Cnt = 4

OutLoop:
USBService ' Must service USB regularly
USBOut 3, Buffer, Cnt, OutLoop

PIR1.5 = 0
ENDIF

'-------------------------------------------------------------------------------
IntDone:
RESUME ' Return to main program
ENABLE INTERRUPT

'-------------------------------------------------------------------------------
END