|
|
View previous topic :: View next topic |
Author |
Message |
dbotkin
Joined: 08 Sep 2003 Posts: 197 Location: Omaha NE USA
|
Temporary second serial on shared I/O pin |
Posted: Wed Dec 09, 2009 11:05 am |
|
|
This may seem a little unusual, but here goes.
Chip: PIC18F4620
Compiler: PCWH 4.099
I have the hardware UART talking to another chip, that's the standard I/O used for serial communication. Right now everything is working fine, no questions about that.
I'm adding a new feature that will require sending serial data via a pin normally used for a different purpose. It's just a general purpose I/O pin (D7, to be specific) that I use only as an output. I want to be able to send data to that pin, but everything else goes to the hardware UART as usual. So here's what I have:
Code: |
#use rs232(baud=9600,parity=N,xmit=TXD,rcv=RXD,bits=8,ERRORS)
#use rs232(baud=9600,parity=N,xmit=KEYLINE,bits=8,stream=K3)
printf("testing 1 2 3"); // Should print to hardware UART
fputs("Hello word",K3); // Should print to D7
|
So my questions are...
1.) Are there any problems not specifying a receive pin in #use rs232? The compiler doesn't complain.
2.) Will there be any problems using D7 for an output pin, when not sending serial data to it? I use output_high and output_low in various parts of the program. It's only under certain conditions that serial data will be sent.
3.) Will all of my existing putc(), printf(), getc(), gets() and similar calls use the hardware UART by default, since I don't specify a stream with any of them? In other words... the manual says putc(), getc(), etc. use stdio. Does this default to the hardware UART as I think it should? Or do I need to rewrite all of me serial I/O to use a stream name?
I'll be trying this out later on, just wanted to ask here in case anyone has been down this road before. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Dec 09, 2009 1:58 pm |
|
|
If you use one stream, they all have to be streams. Your posted code
will all use the bit-banged port on pin D7. That's because it's the last
#use rs232 statement of the two statements, and they don't both use
streams. (The solution is to make everything be a stream if you have
two or more #use rs232 statements, and edit your main code to use
stream-capable functions).
How do I know this ? (Besides already knowing it).
First, I install vs. 4.099 and make a test program. I do several alternating
lines, which attempt to use both RS-232 ports. (pin D7 and the hardware
pins). If it's working, then when I look at the .LST file, I should see
alternating calls to bit-banging code and to the hardware UART registers.
Code: |
#include <18F4620.h>
#fuses XT,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(clock=4000000)
#define TXD PIN_C6
#define RXD PIN_C7
#define KEYLINE PIN_D7
#use rs232(baud=9600,parity=N,xmit=TXD,rcv=RXD,bits=8,ERRORS)
#use rs232(baud=9600,parity=N,xmit=KEYLINE,bits=8,stream=K3)
//======================================
void main(void)
{
printf("testing 1 2 3"); // Should print to hardware UART
fputs("Hello word",K3); // Should print to D7
printf("testing 1 2 3"); // Should print to hardware UART
fputs("Hello word",K3); // Should print to D7
while(1);
}
|
Now I look at the .LST file. I don't see any accesses to the hardware
UART registers, such as the TXREG. All calls are to bit-banging code
or to fetch chars from the constant strings.
Code: |
.................... printf("testing 1 2 3"); // Should print to hardware UART
000A6: CLRF @@06
000A8: MOVF @@06,W
000AA: RCALL 0004 // Get a string char
000AC: INCF @@06,F
000AE: MOVWF @00
000B0: MOVWF ??65535
000B2: RCALL 003E // *** Call bit-bang code for D7
000B4: MOVLW 0D
000B6: SUBWF @@06,W
000B8: BNZ 00A8
.................... fputs("Hello word",K3); // Should print to D7
000BA: CLRF @@06
000BC: MOVF @@06,W
000BE: RCALL 0022 // Get a string char (Hello string)
000C0: IORLW 00
000C2: BZ 00CC
000C4: INCF @@06,F
000C6: MOVWF ??65535
000C8: RCALL 003E // *** Call bit-bang code for D7
000CA: BRA 00BC
000CC: MOVLW 0D
000CE: MOVWF ??65535
000D0: RCALL 003E // *** Call bit-bang code for D7
000D2: MOVLW 0A
000D4: MOVWF ??65535
000D6: RCALL 003E // *** Call bit-bang code for D7
.................... printf("testing 1 2 3"); // Should print to hardware UART
000D8: CLRF @@06
000DA: MOVF @@06,W
000DC: RCALL 0004 // Get a string char
000DE: INCF @@06,F
000E0: MOVWF @00
000E2: MOVWF ??65535
000E4: RCALL 003E // *** Call bit-bang code for D7
000E6: MOVLW 0D
000E8: SUBWF @@06,W
000EA: BNZ 00DA
.................... fputs("Hello word",K3); // Should print to D7
000EC: CLRF @@06
000EE: MOVF @@06,W
000F0: RCALL 0022 // Get a string char (Hello string)
000F2: IORLW 00
000F4: BZ 00FE
000F6: INCF @@06,F
000F8: MOVWF ??65535
000FA: RCALL 003E // *** Call bit-bang code for D7
000FC: BRA 00EE
000FE: MOVLW 0D
00100: MOVWF ??65535
00102: RCALL 003E // *** Call bit-bang code for D7
00104: MOVLW 0A
00106: MOVWF ??65535
00108: RCALL 003E // *** Call bit-bang code for D7
....................
.................... while(1);
0010A: BRA 010A
.................... } |
Here's the bit-bang code for pin D7. You can recognize it by looking
for the code that sets up a bit counter near the start. You've got 8 bits
to send. Therefore, bit-bang code will likely set up a loop and it will need
a loop counter. There will always be a DJNZ-type of instruction that
jumps back near the top of the main loop. This line will decrement the
bit counter. There may be a software delay loop that is called, depending
on the baud rate. Sometimes, NOPs may be used instead of that.
This code carefully avoids doing Calls, I assume, to keep the stack usage
down. It jumps around with Branch instructions instead of using calls.
Code: |
.................... #use rs232(baud=9600,parity=N,xmit=TXD,rcv=RXD,bits=8,ERRORS)
.................... #use rs232(baud=9600,parity=N,xmit=KEYLINE,bits=8,stream=K3)
0003E: BCF TRISD.7
00040: BCF LATD.7
00042: MOVLW 08 // 8 bits
00044: MOVWF @01 // Bit counter
00046: BRA 0048
00048: NOP
0004A: BSF 01.7
0004C: BRA 006A
0004E: BCF 01.7
00050: RRCF ??65535,F
00052: BTFSC STATUS.C
00054: BSF LATD.7
00056: BTFSS STATUS.C
00058: BCF LATD.7
0005A: BSF 01.6
0005C: BRA 006A
0005E: BCF 01.6
00060: DECFSZ @01,F // Decrement the bit counter
00062: BRA 0050
00064: BRA 0066
00066: NOP
00068: BSF LATD.7
0006A: MOVLW 1C // Software time delay
0006C: MOVWF FSR0L
0006E: DECFSZ FSR0L,F
00070: BRA 006E
00072: BRA 0074
00074: BTFSC 01.7
00076: BRA 004E
00078: BTFSC 01.6
0007A: BRA 005E
0007C: RETLW 00
....................
|
To see the code at 0004 and 0022, which gets the strings, you need to
edit the .H file for the PIC, and comment out the #nolist line at the top.
Then re-compile and you can see the "string fetching" code, and identify
it.
It's taken me much longer to type up this explanation than to do all of
this. I hope I've explained how you can use the .LST file to see what
the compiler is doing. You don't have to be able to write assembly,
you just have to be able to read it somewhat, to do this type of analysis. |
|
|
dbotkin
Joined: 08 Sep 2003 Posts: 197 Location: Omaha NE USA
|
|
Posted: Wed Dec 09, 2009 2:15 pm |
|
|
Thanks for the WAY over the top explanation. :) I was afraid that would be the case. I'll probably just need to go through and change everything to streams, because the new feature will be killer enough to justify the work... I think.
I actually do use the .LST file quite often to see how things are being done; for whatever reason, it just didn't occur to me to do so in this case. I'll blame the cold medicine... it's tough writing code when your head feels like you've just been smacked with a big sand bag. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Dec 10, 2009 2:28 pm |
|
|
I know. I figured that you probably knew this stuff. But previously,
someone else had asked me how I knew the answer to a question.
So I used your post to do a tutorial on using the .LST file. |
|
|
dbotkin
Joined: 08 Sep 2003 Posts: 197 Location: Omaha NE USA
|
|
Posted: Thu Dec 10, 2009 9:23 pm |
|
|
Thanks.
Well, I went through the code today. It wasn't as painful as I thought it would be. I am using a HEAVILY modified version of the CCS supplied USB master files from their USB master demo kit; there's a usb_putc() function that pretty much just uses fputc() to send output to the right serial port. All I needed to do was replace a bunch of putc() statements with usb_putc() and then tack on the stuff for the "other" serial stream. Easy peasy. Tomorrow maybe I'll get ambitious and test it. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|