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

Help! Software UART with EXT interrupt on 18F4520

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



Joined: 30 Jul 2008
Posts: 17

View user's profile Send private message

Help! Software UART with EXT interrupt on 18F4520
PostPosted: Wed Jul 30, 2008 2:58 am     Reply with quote

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







PostPosted: Wed Jul 30, 2008 7:19 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Jul 30, 2008 7:30 am     Reply with quote

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








PostPosted: Thu Jul 31, 2008 10:21 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Jul 31, 2008 10:34 am     Reply with quote

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







PostPosted: Thu Jul 31, 2008 10:58 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Jul 31, 2008 11:53 am     Reply with quote

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







PostPosted: Thu Jul 31, 2008 3:29 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Jul 31, 2008 6:14 pm     Reply with quote

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) Smile 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

View user's profile Send private message

PostPosted: Thu Jul 31, 2008 6:28 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Jul 31, 2008 6:34 pm     Reply with quote

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







PostPosted: Fri Aug 01, 2008 4:07 am     Reply with quote

This all makes sense now. Smile
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: 1903

View user's profile Send private message

PostPosted: Fri Aug 01, 2008 11:58 am     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Aug 01, 2008 9:13 pm     Reply with quote

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 Smile )

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

View user's profile Send private message

PostPosted: Thu Nov 13, 2008 5:07 pm     Reply with quote

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 ! Confused

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 ???
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