CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Temporary second serial on shared I/O pin

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
dbotkin



Joined: 08 Sep 2003
Posts: 197
Location: Omaha NE USA

View user's profile Send private message Send e-mail Visit poster's website

Temporary second serial on shared I/O pin
PostPosted: Wed Dec 09, 2009 11:05 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Dec 09, 2009 1:58 pm     Reply with quote

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

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Wed Dec 09, 2009 2:15 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Dec 10, 2009 2:28 pm     Reply with quote

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

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Thu Dec 10, 2009 9:23 pm     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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