|
|
View previous topic :: View next topic |
Author |
Message |
madcat
Joined: 30 Jul 2008 Posts: 17
|
Help! Software UART with EXT interrupt on 18F4520 |
Posted: Wed Jul 30, 2008 2:58 am |
|
|
Hi, I'm trying to implement a software UART on 18F4520 and it does work more or less without interrupts, but i have no enough time to sample it frequently so it misses some bytes. I'd like to do it with EXT interrupt.
Below is a general structure of the code I'm trying to run. All it does is take a char from pin_B1 (when there is interrupt) and send it to hardware UART so i can monitor....
I get GARBAGE !
What do i do wrong ?
yep i tried to save the char in global var and send it to rs232 outside of the #INT function - same result :(
I'm pretty stuck with this now... please help !
Code: |
#include <18F4520.h>
#device ICD=TRUE
#use delay(clock=4000000)
#fuses XT, NOWDT, NOLVP, NOBROWNOUT, NOPROTECT, PUT
#use RS232(BAUD=9600, XMIT=PIN_C6, RCV=PIN_C7, STREAM=COMM_RS232, DISABLE_INTS, ERRORS )
#use RS232(BAUD=9600, XMIT=PIN_A1, RCV=PIN_B1, STREAM=COMM_SW, DISABLE_INTS )
#byte rs232out = 0xFAD //TXREG
#INT_EXT1
void received(void) {
rs232out = fgetc(COMM_SW);
}
void main() {
disable_interrupts(global);
enable_interrupts(INT_EXT1);
ext_int_edge( H_TO_L );
enable_interrupts(global);
while (true) { }
} |
Last edited by madcat on Thu Nov 13, 2008 5:50 pm; edited 3 times in total |
|
|
Ttelmah Guest
|
|
Posted: Wed Jul 30, 2008 7:19 am |
|
|
Get rid of 'disable_ints' everywhere in the UART declarations.
This is needed when _sending_ data with a software UART, in the 'main' code, to avoid interrupts interfering with the timing. You don't want it when using the software UART inside an interrupt.
Add 'sample_early' to the software UART declaration.
The big problem, is that interrupts take _time_. It takes typically perhaps nearly fifty instruction times, from the moment when int_ext triggers, to the point where the 'getc' will actually start reading the character inside the interrupt code (about 30 instructions to actually arrive in the handler, then the getc, will check that the signal is low again, before staring to read the data). At 9600bps, with a 4Mhz clock, each bit, is only 104 instructions long, and the code will try to sample in the middle of the bit, so with the long delay arriving at the reading code, you are almost at the end of the character, and risk losing bits - this is what is probably happening. 'Sample early', reduces the delay before sampling, for exactly this type of situation.
If you switched to using the PLL, and clocked the chip at 16MHz, timing would get a lot easier.
Best Wishes |
|
|
Humberto
Joined: 08 Sep 2003 Posts: 1215 Location: Buenos Aires, La Reina del Plata
|
|
Posted: Wed Jul 30, 2008 7:30 am |
|
|
Folowing code is just to test both data reception. (not tested, let me know if it works)
Code: |
#use RS232(BAUD=9600, XMIT=PIN_C6, RCV=PIN_C7, STREAM=COMM_RS232, DISABLE_INTS, ERRORS )
#use RS232(BAUD=9600, XMIT=PIN_A1, RCV=PIN_B1, STREAM=COMM_SW, DISABLE_INTS )
int8 data_rcvd;
int8 rcvd_ext_int;
int8 rcvd_uart;
#INT_EXT
void software_receiver()
{
data_rcvd=0;
data_rcvd=fgetc(COMM_SW);
rcvd_ext_int = TRUE;
}
#INT_RDA
void serial_isr()
{
data_rcvd=0;
data_rcvd=fgetc(COMM_RS232);
rcvd_uart=TRUE;
}
void main()
{
enable_interrupts(global);
enable_interrupts(INT_RDA);
enable_interrupts(INT_EXT);
ext_int_edge( H_TO_L );
rcvd_ext_int=0;
rcvd_uart=0;
while(1)
{
......
......
if(rcvd_uart)
{fprintf(COMM_RS232,"%C", data_rcvd);
rcvd_uart=0;
}
if(rcvd_ext_int)
{fprintf(COMM_SW,"%C", data_rcvd);
rcvd_ext_int=0;
}
}
}
|
Humberto |
|
|
Guest
|
|
Posted: Thu Jul 31, 2008 10:21 am |
|
|
Ttelmah,
I do need to send data through the soft uart later in the main code so i guess i do need it ?
Also i have to control 3 software uarts, 1 hardware uart, mmc card & lcd including protocol parsing and more... soo if at 4MHz i can't cope with even one uart then all of the above may not work at 40. I have to write efficient code.
Anyway, i tried all. removed the 'disable_ints', added the 'sample_early' - no effect :(
Tried to use the HSPLL mode but CCS does not accept such fuse. The only way i found was to leave the HS and write : #use delay(clock=16M, oscillator=4M) But i'm not sure it works.
Tested it and the garbage i receive looks different now (worse) but still remain garbage. Transmitting through software UART still works fine.
I tried also to use INTRC with 32MHz - same garbage.
Interesting that when i get the same packet of data - i get the same garbage. it works like encoding but i cant figure out the function yet. |
|
|
madcat
Joined: 30 Jul 2008 Posts: 17
|
|
Posted: Thu Jul 31, 2008 10:34 am |
|
|
oops, the previous post was mine but shown like from "Guest"...
Humberto,
I've tried your code but it gives no output.
Alternatively i wrote somth similar that works but still gives the same garbage output :
Code: | #include <18F4520.h>
#device ICD=TRUE
#fuses HS, NOWDT, NOLVP, NOBROWNOUT, NOPROTECT, PUT
#use delay(clock=4000000)
#use RS232(BAUD=9600, XMIT=PIN_C6, RCV=PIN_C7, STREAM=COMM_RS232, ERRORS, DISABLE_INTS)
#use RS232(BAUD=9600, XMIT=PIN_A1, RCV=PIN_B1, STREAM=COMM_SW, SAMPLE_EARLY, DISABLE_INTS)
char ch;
int flag;
#INT_EXT1
void received(void) {
ch = fgetc(COMM_SW);
flag=1;
}
void main() {
ext_int_edge( H_TO_L );
enable_interrupts(INT_EXT1);
enable_interrupts(global);
while (true) {
if (flag) {
fputc(ch, COMM_RS232);
flag = 0;
}
}
} |
|
|
|
Ttelmah Guest
|
|
Posted: Thu Jul 31, 2008 10:58 am |
|
|
The fuse, is HS_PLL. It should work. Note the underbar. The .h include file for each processor, has all the fuses allowed listed at the top.
INTRC, can be borderline on timing, depending on supply voltage, temperature etc..
Seriously, software UART's _will never work_, if you need to receive more than one thing at a time. If the latter I/O, is at different times, no problem. If more than one channel has to receive at once, forget it, and look into adding something like an external SPI UART (phillips do some useful ones).
The timing is 'borderline' at 4Mhz, meaning you are sampling very late in the bit time. It reduces the margins available. Sample early, will fix this, and if you still have a problem, then the fault is elsewhere. Are you sure that the signal levels are correct, grounding is good, etc. etc..
I recently had really 'lovely' comms problems talking to a module. Turned out the manufacturer had got the ground pin wrong in the data sheet for the RS232 connection. Would work, intermittently.
Best Wishes |
|
|
madcat
Joined: 30 Jul 2008 Posts: 17
|
|
Posted: Thu Jul 31, 2008 11:53 am |
|
|
Code: | Error 111 "test1.c" Line 5(7,56): Unknown keyword in #FUSES "HS_PLL" |
Previously i even tried to run a text search on 18F4520.h for "PLL" and it has only #define OSC_PLL_ON 0x4000 which is related to internal RC OSC .... so i still do know how do it. Even after reading the datasheet its not quite obvious...
Basically i don't need to receive simultaneously from the SW uarts. So i was hoping for a simple software solution to minimize the hardware and not to build some proprietary limited rs232 "bus".
I tried the sampling_early as you can see in the code i posted for Humberto and it still does not work.
Both circuits (MCU and the transmitting part) have same ground and a 15cm (although not shielded) wire as a temporary connection. The MCU is 5v and the transmitting part is 3.3v but without interrupt it works fine!
Do you have some part# for a device with at least 3 uarts i can use ?
Interesting that i get a sort of permanent "encoding" i mean same packets looks same as garbage. I haven't figured out the function yet but it is definitely there. It is not a simple bit missing/shifting/xor/etc... somth more complex. It is ~same in HEX for the same packets of data! Possibly figuring out the function can give some idea on the nature of the problem (delay etc...)
The original data :
Code: |
24 47 50 47 53 41 2C 41 2C 31 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2A 31 45 0D 0A
24 47 50 56 54 47 2C 2C 54 2C 2C 4D 2C 2C 4E 2C 2C 4B 2A 34 45 0D 0A
24 47 50 47 53 41 2C 41 2C 31 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2A 31 45 0D 0A
24 47 50 56 54 47 2C 2C 54 2C 2C 4D 2C 2C 4E 2C 2C 4B 2A 34 45 0D 0A
24 47 50 47 53 41 2C 41 2C 31 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2A 31 45 0D 0A
24 47 50 56 54 47 2C 2C 54 2C 2C 4D 2C 2C 4E 2C 2C 4B 2A 34 45 0D 0A
24 47 50 47 53 41 2C 41 2C 31 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2A 31 45 0D 0A
24 47 50 56 54 47 2C 2C 54 2C 2C 4D 2C 2C 4E 2C 2C 4B 2A 34 45 0D 0A
24 47 50 47 53 41 2C 41 2C 31 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2C 2A 31 45 0D 0A
24 47 50 56 54 47 2C 2C 54 2C 2C 4D 2C 2C 4E 2C 2C 4B 2A 34 45 0D 0A
|
The "garbage encoded" data :
Code: |
B2 83 3B 9B 0B 63 41 59 C6 C6 C6 C6 C6 C6 C6 C6 C6 C6 C6 C6 C6 C6 C6 A6 16 45 C3 61
B2 83 B3 A3 3B 63 2C 35 19 D6 63 2C 1A C6 B6 53 34 D1 C3 E1
B2 83 3B 9B 0B 63 41 59 C6 C6 C6 C6 C6 C6 C6 C6 C6 C6 C6 C6 C6 C6 C6 A6 16 45 C3 61
B2 83 B3 A3 3B 63 2C 35 19 D6 63 2C 1A C6 B6 53 34 D1 C3 E1
B2 83 3B 9B 0B 63 41 59 C6 C6 C6 C6 C6 C6 C6 C6 2C 19 C6 C6 C6 C6 A6 16 45 C3 61
B2 83 B3 A3 3B 63 2C 35 19 D6 63 2C 1A C6 B6 53 34 D1 C3 E1
B2 83 3B 00 9B 0B 63 41 59 C6 C6 C6 C6 C6 C6 C6 2C 19 C6 C6 C6 C6 2C 65 45 C3 61
B2 83 B3 A3 3B 63 2C 8D C6 D6 63 2C 1A C6 B6 53 34 D1 C3 E1
B2 83 3B 9B 0B 63 41 59 C6 C6 C6 C6 C6 C6 C6 C6 C6 C6 C6 C6 C6 C6 C6 A6 16 45 C3 61
B2 83 B3 A3 3B 63 2C 35 19 D6 63 2C 1A C6 B6 53 34 D1 C3 E1
|
Look at the first 4 columns. The change from line to line is on 4rth column in the original data but in 3rd in the encoded... |
|
|
Ttelmah Guest
|
|
Posted: Thu Jul 31, 2008 3:29 pm |
|
|
As I said, look in the include file.
For that chip, the fuse is 'H4'.
As I have said before, draw out the bit patterns, and look for patterns. The transmitted patterns for the first few bytes, are (as TTL logic that should arrive at the input pin):
1....1000101001...0111000101...000010101...
Where the '...', is a gap of all 1's, depending on how fast the transmission arrives. What you have received is:
10110101001...0110000011...0110111001...
Now, the first byte, has the same 'tail' as the transmitted data, but has two ones, in the middle of a section with zeroes. The second byte, appears to have zeroes where a one should be. Notice further along, you have '2C' transmitted repeatedly, and 'C6' as the response. Draw this out:
1....10001101001...0001101001...0001101001..
1....1001100011x...001100011x...001100011x...
Now, remember that the soft UART, will start sampling at the first 'low' that it sees after it is called, so could be anywhere along the stream.
Note that the software UART, does not sample the stop bit, so won't 'look' at the tenth location when looking along the data - the locations marked 'x' in the outgoing data.
Note the alignment of the double bit pattern in the outgoing data, with the double pattern one bit _latter_ in the incoming stream.
This implies the system is actually sampling _early_. This is _impossible_, if the data is the correct polarity logic RS232 (idle high).
Describe your wiring to the PC, and to the device. What is the device?.
The SPI UART's, are normally single, or dual devices. However they are addressable, and some have the line drivers/inverters built in, which makes then as small as adding these to the PIC.
Best Wishes |
|
|
madcat
Joined: 30 Jul 2008 Posts: 17
|
|
Posted: Thu Jul 31, 2008 6:14 pm |
|
|
H4.... now i see it. Thanks. I do have the list of all fuses in the .h header but no explanation on their meaning. So i was searching somth with "PLL" in its name.
My platform:
PIC18F4520 (4MHz crystal) on PicDem 2 plus board with ICD2
PC connected to onboard RS232 exit which uses MAX3232c level converter.
The device i'm currently trying to receive data from is a GPS module:
http://www.usglobalsat.com/download/47/em408_ug.pdf
Software UART is configured on B1 pin (INT1)
The communication works fine when i connect the GPS through another level converter to the on board RS232 (instead of the PC) also it does work fine with software UART on B1 but without interrupt. So using the interrupt is what makes the change.
I've tried "INVERT" before - still garbage^(-1) As well as sample_early - no effect.
I've tried the H4 and got a different garbage for the same data:
Code: |
E6 7F EF 9F CF 7F 7F DF FE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE 3F DF FF E7
E6 7F CF CF 3F 7F EE 76 9F DF 9E 9F 9F 7F EE CF EE F6 67 FF E7
E6 7F EF 9F CF 7F 7F DF FE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE 3F DF FF E7
E6 7F CF CF 3F 7F EE 76 9F DF 9E 9F 9F 7F EE CF EE F6 67 FF E7
E6 7F EF 9F CF 7F 7F DF FE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE 3F DF FF E7
E6 7F CF CF 3F 7F EE 76 9F DF 9E 9F 9F 7F EE CF EE F6 67 FF E7
E6 7F EF 9F CF 7F 7F DF FE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE 3F DF FF E7
E6 7F CF CF 3F 7F EE 76 9F DF 9E 9F 9F 7F EE CF EE F6 67 FF E7
E6 7F EF 9F CF 7F 7F DF FE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE 3F DF FF E7
E6 7F CF CF 3F 7F EE 76 9F DF 9E 9F 9F 7F EE CF EE F6 67 FF E7
|
As you can see it is very similar. Now there is an EE sequence... Does it make sense to you ? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jul 31, 2008 6:28 pm |
|
|
Quote: | The MCU is 5v and the transmitting part is 3.3v but without interrupt it works fine! |
Which one of those is the 18F4520 PIC ?
If the PIC is the "MCU" and it's receiving data from a 3.3v logic level
device, there will be problem if use the INT1 pin for interrupts.
The INT1 pin uses TTL levels when it's in normal input mode, but it uses
Schmitt Trigger levels when it's in interrupt-input mode. For a 5v PIC,
that means a logic high level is 4.0v minimum. That's much higher
than your 3.3v device can provide. You will need a level converter chip. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Thu Jul 31, 2008 6:34 pm |
|
|
Quote: | Thanks. I do have the list of all fuses in the .h header but no explanation on their meaning. | See fuses.txt in the compiler directory. |
|
|
Ttelmah Guest
|
|
Posted: Fri Aug 01, 2008 4:07 am |
|
|
This all makes sense now.
There must just be enough voltage in the form of a little overshoot, to trigger the interrupt at some points. The result is data being sampled at completely the wrong times, and hence the problem.
Check the data sheet for the 3.3v device. Some, allow their outputs to be driven to voltages higher than the supply. On these, you can drive 5v inputs like the interrupt pin, by adding a pull-up to the 5v supply (perhaps 4.7KR), and if the device supports this, it may then work. However you need to look carefully at the specifications. Otherwise a level shifter is necessary.
Best Wishes |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1909
|
|
Posted: Fri Aug 01, 2008 11:58 am |
|
|
Level shifters: the TI TXS family (TXS0104, TXS0108) works very well. For single lines the MAX3371 works well. Be careful when selecting level shifters as some have very high internal resistances which can't pull externally pulled up lines low. The MAX3001 and the TI TXB family have high internal resistances. |
|
|
madcat
Joined: 30 Jul 2008 Posts: 17
|
|
Posted: Fri Aug 01, 2008 9:13 pm |
|
|
PCM programmer,
Yep. MCU stands for "Micro Controller Unit"
You've told a very interesting point! thanks! I've totally missed that in interrupt mode the input voltage levels are different... I don't know if there are any other problems in the code but this looks like a real problem. Also its strange how a 3.3v device could trigger a 4v input at all ? Coz do see 1 char on output for every (almost) char i send on input....
ckielstra,
Thanks for the tip! now i see it. But what a strange and unexpected place to keep it. (In the DOS age i would definitely search it there... but now i was searching in the .pdf )
Ttelmah,
I've gave a link to the only datasheet of that GPS i have in my other post. It has only limited info but looks like it can't drive a 5v input.
As a temporary measure i found a cmos Quad NAND gate (MC14011UB) that has a Vih of 2.75v with Vdd=5v so i made a repeater from 2 gates and tried to use as level converter to diagnose the problem.... no output from the gate at all :( I'm doing it in home conditions and have no scope so i don't know what is going on there. I will find my DIY scope ( i made from a logitech usb headset ) and write later if i find somth new...
newguy,
Thanks for the info. Looks good however before ordering and waiting for the parts to arrive i need to find some way to make it work to see that this is the only problem. I'll just check first if i can get in nearby but i'm not sure... |
|
|
madcat
Joined: 30 Jul 2008 Posts: 17
|
|
Posted: Thu Nov 13, 2008 5:07 pm |
|
|
Hi all again !
After some break I'm back to this project.
Now I have FTDI usb module which I use for debugging this problem. It is configured for 5v i/o which eliminates the voltage level problem.
Interesting that the problem persists !
My debug setup :
PC -> FTDI -> PIC(RB1) -> RS232 hardware UART -> PC
When I press a key on the PC (terminal #1) it is passed to FTDI (which is tested and ok) then to the RB1 port on the PIC that is configured for software interrupt. The PIC takes all chars from RB1 and sends them back to PC (terminal #2) via RS232 UART.
So basically every key I press on terminal #1 should appear on terminal#2.
What happens in reality is that on every PIC run, the first letter I press appears correctly (!!!) on terminal #2. But all consequent letters are being substituted with different ASCII (permanent mapping).
If I reset the PIC then again: first letter is ok and others are wrong.
Any ideas ??? |
|
|
|
|
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
|