|
|
View previous topic :: View next topic |
Author |
Message |
Linuxbuilders
Joined: 20 Mar 2010 Posts: 193 Location: Auckland NZ
|
18f45j11 and 2 UARTs |
Posted: Sat Aug 28, 2010 9:52 pm |
|
|
Hi,
I have a little problem and I wonder what am I doing wrong?
Basically I have 2 UARTs and they mostly are chaotic, they work and then not and one time I have nice comms and in another time I have rubbish on ports like this:
...command received from eth:
SSÿSÿSÿSÌÌ (it should be TEXT captured from UART2, but in next minute it will work well and then stop again)
EOL
I use Xport to talk to PIC on UART2 and RS485 on UART1.
It looks to me like I do not initiate something on ports and they go to sleep or IRQ fires up too late and collects rubbish from port.
This is my main program:
Code: |
#include <18F45J11.h>
#device adc=10
#DEVICE HIGH_INTS=TRUE
#include <ctype.h>
#include <stddef.h>
#include <string.h>
//=========DEFINE====================
#define Rx_In PIN_C7
#define Tx_Out PIN_C6
#define Tx_On PIN_B1
//===================================
//===================================
#use delay (clock=10M)
#FUSES WDT2048
#FUSES HS
#FUSES H4_SW
#FUSES STVREN
#FUSES NOPROTECT
#FUSES FCMEN
#FUSES PRIMARY
#FUSES NOWPCFG
#FUSES WPBEG
#FUSES WPDIS
#FUSES LPT1OSC
#FUSES T1DIG
#FUSES MSSPMSK7
#FUSES DSWDT2147483648
#FUSES DSWDT
#FUSES DSBOR
#FUSES RTCOSC_T1
#FUSES DSWDTOSC_INT
#FUSES NOCPUDIV
#FUSES WPFP
#pin_select U2TX = PIN_C5
#pin_select U2RX = PIN_C4
#use rs232(uart1,SAMPLE_EARLY,baud=115200,xmit=Tx_Out,rcv=Rx_In,parity=N,bits=8,stop=1,stream=bus,restart_wdt,errors,DISABLE_INTS,TIMEOUT=5)
#use rs232(uart2,SAMPLE_EARLY,baud=115200,parity=N,bits=8,stop=1,stream=eth,restart_wdt,errors,DISABLE_INTS,TIMEOUT=5)
|
and irq:
Code: |
#int_RDA2 HIGH
void comms_eth(void) {
char capture;
int next_ind = 0;
int strn_temp_eth[],a;
do {
capture = fgetc(eth);
strn_temp_eth[next_ind] = capture;
next_ind++;
} while (strn_temp_eth[next_ind] != 0x0D);
for (a=0;a<next_ind;a++) {
rx_eth[a] = strn_temp_eth[a];
}
} //void
|
Thnx for help. _________________ Help "d" others and then you shell receive some help from "d" others. |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Sat Aug 28, 2010 10:29 pm |
|
|
Code: | #int_RDA2 HIGH
void comms_eth(void) {
char capture;
int next_ind = 0;
int strn_temp_eth[],a;
do {
capture = fgetc(eth);
strn_temp_eth[next_ind] = capture;
next_ind++;
} while (strn_temp_eth[next_ind] != 0x0D);
for (a=0;a<next_ind;a++) {
rx_eth[a] = strn_temp_eth[a];
}
} //void |
You can't do this this way.
You want to get your char (or more if there's a FIFO) and add them to your string (using a static pointer) and then exit.
If you sit in the ISR like you are with the DO {} While();
the rest of your program will suffer.
-Ben _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Sat Aug 28, 2010 10:38 pm |
|
|
Oh,
and I just looked... but it appears from the datasheet that there is no high-priority for UART1 or UART2. Only standard priority.
Feel free to verify in the .LST file.
I also don't think "SAMPLE EARLY" has effect with hardware UARTs.
A getc() normally samples data in the middle of a bit time. This option causes the sample to be at the start of a bit time. May not be used with the UART
I think "DISABLE_INTs" is also not needed with hardware UARTs either.
Will cause interrupts to be disabled when the routines get or put a character. This prevents character distortion for software implemented I/O and prevents interaction between I/O in interrupt handlers and the main program when using the UART.
Lastly, RESTART_WDT probably isn't needed on UART2 because you're doing interrupts. So you don't sit and spin on getc(); waiting for a char. You only try to get them when the interrupt signals there's something worth getting.
-Ben _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D
Last edited by bkamen on Sat Aug 28, 2010 10:43 pm; edited 2 times in total |
|
|
Linuxbuilders
Joined: 20 Mar 2010 Posts: 193 Location: Auckland NZ
|
|
Posted: Sat Aug 28, 2010 10:40 pm |
|
|
thnx
by the way, what is the other way to collect data from buffer when it is ready?
how d I get this data without using do and loading it from buffer into string or var? _________________ Help "d" others and then you shell receive some help from "d" others. |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Sat Aug 28, 2010 10:48 pm |
|
|
Linuxbuilders wrote: | thnx
by the way, what is the other way to collect data from buffer when it is ready?
how d I get this data without using do and loading it from buffer into string or var? |
You only get a few (if more than one, depending on the PIC) chars at a time before an IRQ gets serviced. In your case (similar to one I had for GPS) you're looking for a CR or LF.
Do you have a max string length? is there an STX char of some sort (like the NMEA's $ char?)
If so, you can build a state machine that starts when it sees the first "$" (as an example) or maybe an STX come in...
From there, the state machine then gathers chars into the string until the string max size is hit or the ETX (or CR|LF) comes through.
Then the ISR raises a flag to tell the rest of your program there's data ready.
From there, you can have the ISR wait for the processing occur (depends on the types of packets if you will need a ring buffer or just something that operates packet by packet (or sentence like NMEA).
-Ben _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
Linuxbuilders
Joined: 20 Mar 2010 Posts: 193 Location: Auckland NZ
|
|
Posted: Sat Aug 28, 2010 11:10 pm |
|
|
thnx,
To be more specific, what would you use to replace
loop?
In my application I limit amount of chars to X by
Code: |
} while ((strn_temp_eth[next_ind] != 0x0D) || (next_ind < X));
|
This way I break loop if my string is more than X chars. From my understanding you say that do {} is not right way to get data from buffer? Do I understand it properly?
thnx _________________ Help "d" others and then you shell receive some help from "d" others. |
|
|
Linuxbuilders
Joined: 20 Mar 2010 Posts: 193 Location: Auckland NZ
|
|
Posted: Sat Aug 28, 2010 11:34 pm |
|
|
This has fixed instability:
Code: |
#use rs232(uart1,SAMPLE_EARLY,baud=115200,xmit=Tx_Out,rcv=Rx_In,parity=N,bits=8,stop=1,stream=bus,restart_wdt,errors,DISABLE_INTS,TIMEOUT=5)
#use rs232(uart2,SAMPLE_EARLY,baud=115200,parity=N,bits=8,stop=1,stream=eth,restart_wdt,errors,DISABLE_INTS,TIMEOUT=5)
#use fixed_io(A_outputs=PIN_A1,PIN_A2,PIN_A3,PIN_A5)
#use fixed_io(B_outputs=PIN_B2,PIN_B3,PIN_B4,PIN_B5,PIN_B6,PIN_B7)
#use fixed_io(C_outputs=PIN_C0,PIN_C1,PIN_C2,PIN_C3)
#use fixed_io(D_outputs=PIN_D0,PIN_D1,PIN_D2,PIN_D3,PIN_D4,PIN_D5,PIN_D6,PIN_D7)
#use fixed_io(E_outputs=PIN_E0,PIN_E1,PIN_E2)
|
It looks like if all pins are not mapped to a function then somehow multiplexer affects operation of C4/C5.
thnx _________________ Help "d" others and then you shell receive some help from "d" others. |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Sun Aug 29, 2010 1:15 am |
|
|
Linuxbuilders wrote: | thnx,
To be more specific, what would you use to replace
loop?
In my application I limit amount of chars to X by
Code: |
} while ((strn_temp_eth[next_ind] != 0x0D) || (next_ind < X));
|
This way I break loop if my string is more than X chars. From my understanding you say that do {} is not right way to get data from buffer? Do I understand it properly?
|
What I'm saying is:
You have to enter the ISR, get the chars in the RCREG (if the PIC supports more than 1) then exit the ISR.
What you have waits for the char to == 0x0D. The || next_ind < X is new and I don't know what other code is in there.
Anyway... you can't sit in the ISR while waiting for some char to == 0x0D.
Let say your PIC only supports 1 char and has no FIFO.
you'd enter the ISR, get the char, save it, exit the ISR whether the char is 0x0D or not.
Now, you also want to check to make sure you don't save a char past the end of your string -1 (to save room for the NULL if important).
-Ben _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
Linuxbuilders
Joined: 20 Mar 2010 Posts: 193 Location: Auckland NZ
|
|
Posted: Sun Aug 29, 2010 4:37 am |
|
|
Thnx, man
I didn't think about it this way. It makes a lots of sense, I will redesign IRQ routine. It makes so much sense that I can't believe that I did not think about it before.
thank you very much for this post. When I get it written I will post some code for some blokes like me lost in time and space.
thank you very much. _________________ Help "d" others and then you shell receive some help from "d" others. |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Sun Aug 29, 2010 10:33 am |
|
|
No problem,
Good luck!
-Ben _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
Linuxbuilders
Joined: 20 Mar 2010 Posts: 193 Location: Auckland NZ
|
|
Posted: Mon Aug 30, 2010 2:44 am |
|
|
Quick question:
When I receive CHAR on UART1 then CCS is turning off IRQs by default as per:
#use rs232(uart1,SAMPLE_EARLY,baud=115200,xmit=Tx_Out,rcv=Rx_In,parity=N,bits=8,stop=1,stream=bus,restart_wdt,errors,DISABLE_INTS,TIMEOUT=5)
#use rs232(uart2,SAMPLE_EARLY,baud=115200,parity=N,bits=8,stop=1,stream=eth,restart_wdt,errors,DISABLE_INTS,TIMEOUT=5)
So when I am receiving data on UART1 then my UART2 is not working? Do I understand it properly? So if it is the case, how do I make both UARTs working independently in the same time?
thnx
another question:
do I really need IRQ RDA? I think that with 40MHz pic I could easily sample data with kbhit according to this:
##################
Function: If the RS232 is under software control this function returns TRUE if the start
bit of a character is being sent on the RS232 RCV pin. If the RS232 is
hardware this function returns TRUE if a character has been received and is
waiting in the hardware buffer for getc() to read. This function may be used to
poll for data without stopping and waiting for the data to appear. Note that in
the case of software RS232 this function should
##################
and just load buffer with data as it goes and process whole strings? Right?
Like this:
void comms_from_bus(void) {
if (kbhit(bus)) {
capture_bus[next_in_bus] = fgetc(bus);
next_in_bus++;
}
} //void _________________ Help "d" others and then you shell receive some help from "d" others. |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Mon Aug 30, 2010 6:44 am |
|
|
Linuxbuilders wrote: | Quick question:
When I receive CHAR on UART1 then CCS is turning off IRQs by default as per:
#use rs232(uart1,SAMPLE_EARLY,baud=115200,xmit=Tx_Out,rcv=Rx_In,parity=N,bits=8,stop=1,stream=bus,restart_wdt,errors,DISABLE_INTS,TIMEOUT=5)
#use rs232(uart2,SAMPLE_EARLY,baud=115200,parity=N,bits=8,stop=1,stream=eth,restart_wdt,errors,DISABLE_INTS,TIMEOUT=5)
So when I am receiving data on UART1 then my UART2 is not working? Do I understand it properly? So if it is the case, how do I make both UARTs working independently in the same time?
|
I think those are for software UARTs only. You don't need them (and I think I already mentioned that), I think you should delete that in both #use rs232 statements.
I use a PIC46J11 with both UARTS running.
UART1 is a control console and UART2 is a GPS at 4800bps.
-- with no problems.
Also, "sample early" doesn't help you for hardware UARTS either. You could get rid of those too.
Quote: |
another question:
do I really need IRQ RDA? I think that with 40MHz pic I could easily sample data with kbhit according to this:
##################
Function: If the RS232 is under software control this function returns TRUE if the start
bit of a character is being sent on the RS232 RCV pin. If the RS232 is
hardware this function returns TRUE if a character has been received and is
waiting in the hardware buffer for getc() to read. This function may be used to
poll for data without stopping and waiting for the data to appear. Note that in
the case of software RS232 this function should
##################
and just load buffer with data as it goes and process whole strings? Right?
Like this:
void comms_from_bus(void) {
if (kbhit(bus)) {
capture_bus[next_in_bus] = fgetc(bus);
next_in_bus++;
}
} //void |
That all depends. Do you think your main loop always has enough processing cycles to NEVER miss a char?
-Ben _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Mon Aug 30, 2010 9:05 am |
|
|
Add to the above.
It is not missing a 'character', but missing a _bit_.
When using a 'software UART', you _must_ sample the incoming data line _more often_ than twice per bit time. At 115200bps, this means you must be waiting in a getc, or calling kbhit, at intervals no greater than every 4uSec. Even at 10MIPS, this only gives 40 instruction times between calls....
Seriously, the whole 'point' of UART hardware, is because it is hard to reliably receive/transmit serial data _ especially at high speed_, using software alone. Using the CCS software UART, comms are 'half duplex' (only one direction at a time), and 'mono stream' (only one software stream operating at any one time). It is possible to implement 'better' software UART's, to get round these limitations, but only by using timer interrupts being called at frequencies above twice the serial rate - as such 'not possible' at 115200bps.
You will not get two simultaneous serial streams at 115200bps, without using the hardware UARTs, and if you want operations to be going on without interfering with each other, using the IRQ's is the way to go.
Best Wishes |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Mon Aug 30, 2010 9:54 am |
|
|
Yup.
What he said.
-Ben _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
Linuxbuilders
Joined: 20 Mar 2010 Posts: 193 Location: Auckland NZ
|
|
Posted: Mon Aug 30, 2010 3:33 pm |
|
|
Thnx guys, I did my home work yesterday with pdfs and got an understanding of this relations between soft/hard uart.
Now my problem is as follows:
When I receive a string on one port U1 and then process it and then print some message on another port U2 I am missing incoming data on U1. I can't find anywhere information if IRQs are blocked when putc is executed. So lets say I got a string 19 chars incoming and I process it and then print out information based on it and in mean time I get another string incoming then I am missing 30% of it. I believe that during printing my IRQ RDA is not working. Any idea how to sort this out? When I was playing with software uart I did not have this problem because U2 was not based on IRD2 operation.
How do I get this bit working so I can push/pull data between both ports with very fast speed without any losses.
Thank you very much for your help. _________________ Help "d" others and then you shell receive some help from "d" others. |
|
|
|
|
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
|