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 CCS Technical Support

CAN problem - getting started
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
newguy



Joined: 24 Jun 2004
Posts: 1909

View user's profile Send private message

CAN problem - getting started
PostPosted: Thu Jul 28, 2005 5:44 pm     Reply with quote

I just bought a couple of 18F4580's, and have installed one in my prototyping board - an ME Labs Lab-X1.

I've started with the EX_CAN.c example, and the only modifications I've made to it are as follows:

can_set_mode(CAN_OP_LOOPBACK); // added right after can_init()

port_b_pullups(TRUE); // added just before can_init() - it wouldn't run at all without this line

I've also changed the transmit to use the extended messaging (?) because it simply wouldn't receive anything otherwise. I also read somewhere on this board that the extended messaging is enabled by default in the receive routine(s)/whatever. Anyway, this is changed here:

int1 tx_ext=1;

If I compile, download and run the example as it now sits, the pic outputs (via the serial port), the tx data (all 0's as in the example), and it immediately receives all 0's. Peachy.

I decided to then change the tx data to all 0xfc.

for (i=0;i<8;i++) {
out_data[i]=0xfc;
in_data[i]=0;
}

When I recompile, download & run, the tx data shows up as 0xfc, but the received data is still all 0's. ??? I thought that perhaps in loopback mode, I may just need a wire connecting the can tx pin to the can rx pin, so I installed one. Same thing.

What am I missing? I thought that loopback should loop back whatever is written into the tx register back into the rx register. It's probably something really obvious, but for the life of me I can't see it. Question
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Jul 28, 2005 8:54 pm     Reply with quote

I have a 18F458 board. I was able to make it work in Loopback mode
by changing three lines in the EX_CAN.C file. Also, I changed the
data to 0xFC because that's what you want to use. No other changes
were required and the driver file CAN-18xxx8.C didn't need to be
changed. I don't know if this will work with your 18F4580 chip, but
since that chip has a Legacy mode which is supposed to be compatible
with the 18F458, it may work.

Here's the output displayed in my terminal window.
Code:

Running...
PUT 1: ID=24 LEN=8 PRI=3 EXT=1 RTR=0
   DATA = FC FC FC FC FC FC FC FC

GOT: BUFF=0 ID=24 LEN=8 OVF=0 FILT=0 RTR=0 EXT=1 INV=0
    DATA = FC FC FC FC FC FC FC FC   


The following code is the first part of EX_CAN.C.
The modified (or added) lines are shown below in bold.
Quote:

void main() {
struct rx_stat rxstat;
int32 rx_id;
int in_data[8];
int rx_len;

//send a request (tx_rtr=1) for 8 bytes of data (tx_len=8) from id 24 (tx_id=24)
int out_data[8];
int32 tx_id=24;
int1 tx_rtr=0; // Changed to 0
int1 tx_ext=1; // Changed to 1
int tx_len=8;
int tx_pri=3;

int i;

for (i=0;i<8;i++) {
out_data[i]=0xFC; // Newguy uses 0xFC for data
in_data[i]=0;
}

printf("\r\n\r\nCCS CAN EXAMPLE\r\n");

setup_timer_2(T2_DIV_BY_4,79,16); //setup up timer2 to interrupt every 1ms if using 20Mhz clock

can_init();
can_set_mode(CAN_OP_LOOPBACK); // Added this line

enable_interrupts(INT_TIMER2); //enable timer2 interrupt
enable_interrupts(GLOBAL); //enable all interrupts (else timer2 wont happen)

printf("\r\nRunning...");
newguy



Joined: 24 Jun 2004
Posts: 1909

View user's profile Send private message

PostPosted: Thu Jul 28, 2005 9:14 pm     Reply with quote

PCM,

You're a saint, you really are. Thank you!

Now another stupid question. Can I hook up two pics without the LT1796's? B2 --> B3 and B3 --> B2?

I just want to establish a really simple comm link between them, and I don't see a reason why the LT1796's would be necessary if the two pics were only 8" apart. I should come clean: I already hooked them up that way, and I can't get them to talk to each other. I should also mention that I commented out the loopback line.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Jul 28, 2005 11:20 pm     Reply with quote

This article says you can do it with open-collector drivers.
http://elecdesign.com/Articles/Print.cfm?ArticleID=9131
Quote:
Standard CAN drivers are available for this purpose, but other
implementations are possible. For example, a single-wire, open collector
system would work as well and could easily be employed on a single
board where a custom interface would be viable.

This thread on the Microchip forum says you can use non-inverting
open-collector drivers (such as 7407's). You would use one driver on
each CAN_TX pin and connect each output to the single-wire bus.
(Plus a ground wire, of course). Then connect each CAN_RX pin to the
bus. Also put a pull-up resistor on the bus.
http://forum.microchip.com/tm.asp?m=60377&mpage=1&key=&anchor#60377

It seems to me that if you have to use open-collector drivers, you
might as well use the CAN bus tranceivers.
newguy



Joined: 24 Jun 2004
Posts: 1909

View user's profile Send private message

PostPosted: Fri Jul 29, 2005 10:21 am     Reply with quote

Thanks PCM.

This morning I hooked up a couple of LT1796 transceivers to the pics. I have two identical setups, both running at 4 MHz. Board 1 <--> 1796 <--> 1796 <--> Board 2.

The 1796 is connected as directed in its datasheet, including the terminating resistors (120 ohm).

I changed the CAN bit rate to 125 kbits/s, as per the detailed description you gave in an earlier thread using the can bit time calculator. For a xtal of 4 MHz and 125 kbits/sec, the three baud rate control registers are:

Code:
void can_set_baud(void) {
   BRGCON1 = 0x01;
   BRGCON2 = 0x98;
   BRGCON3 = 0x01;
   /*BRGCON1.brp=CAN_BRG_PRESCALAR;
   BRGCON1.sjw=CAN_BRG_SYNCH_JUMP_WIDTH;

   BRGCON2.prseg=CAN_BRG_PROPAGATION_TIME;
   BRGCON2.seg1ph=CAN_BRG_PHASE_SEGMENT_1;
   BRGCON2.sam=CAN_BRG_SAM;
   BRGCON2.seg2phts=CAN_BRG_SEG_2_PHASE_TS;

   BRGCON3.seg2ph=CAN_BRG_PHASE_SEGMENT_2;
   BRGCON3.wakfil=CAN_BRG_WAKE_FILTER;*/
}


This was changed per your instructions.

Here is my code to try & establish CAN comms between two boards:

Code:
#include <18F4580.h> // was 18F248
#fuses HS,NOPROTECT,NOLVP,NOWDT
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

#include <can-18F4580.c>

int16 ms;

#int_timer2
void isr_timer2(void) {
   ms++; //keep a running timer that increments every milli-second
}

void main() {
   struct rx_stat rxstat;
   int32 rx_id;
   int in_data[8];
   int rx_len;

//send a request (tx_rtr=1) for 8 bytes of data (tx_len=8) from id 24 (tx_id=24)
   int out_data[8];
   int32 tx_id=36;
   int1 tx_rtr=0;
   int1 tx_ext=1;
   int tx_len=8;
   int tx_pri=3;

   int i;

   for (i=0;i<8;i++) {
      out_data[i]=0x19;
      in_data[i]=0;
   }
   port_b_pullups(TRUE);

   printf("\r\n\r\nCCS CAN EXAMPLE\r\n");

   setup_timer_2(T2_DIV_BY_4,250,1);   //setup up timer2 to interrupt every 1ms if using 20Mhz clock

   can_init();

   //can_set_mode(CAN_OP_LOOPBACK); // loopback mode

   enable_interrupts(INT_TIMER2);   //enable timer2 interrupt
   enable_interrupts(GLOBAL);       //enable all interrupts (else timer2 wont happen)

   printf("\r\nRunning...");

   while(TRUE)
   {

      if ( can_kbhit() )   //if data is waiting in buffer...
      {
         if(can_getd(rx_id, &in_data[0], rx_len, rxstat)) { //...then get data from buffer
            printf("\r\nGOT: BUFF=%U ID=%LU LEN=%U OVF=%U ", rxstat.buffer, rx_id, rx_len, rxstat.err_ovfl);
            printf("FILT=%U RTR=%U EXT=%U INV=%U", rxstat.filthit, rxstat.rtr, rxstat.ext, rxstat.inv);
            printf("\r\n    DATA = ");
            for (i=0;i<rx_len;i++) {
               printf("%X ",in_data[i]);
            }
            printf("\r\n");
         }
         else {
            printf("\r\nFAIL on GETD\r\n");
         }

      }

      //every two seconds, send new data if transmit buffer is empty
      if ( can_tbe() && (ms > 1500))
      {
         ms=0;
         i=can_putd(tx_id, out_data, tx_len,tx_pri,tx_ext,tx_rtr); //put data on transmit buffer
         if (i != 0xFF) { //success, a transmit buffer was open
            printf("\r\nPUT %U: ID=%LU LEN=%U ", i, tx_id, tx_len);
            printf("PRI=%U EXT=%U RTR=%U\r\n   DATA = ", tx_pri, tx_ext, tx_rtr);
            for (i=0;i<tx_len;i++) {
               printf("%X ",out_data[i]);
            }
            printf("\r\n");
         }
         else { //fail, no transmit buffer was open
            printf("\r\nFAIL on PUTD\r\n");
         }
      }
   }
}


This board is set to transmit 8 bytes, all 0x19, from address 36 every 1.5 seconds. The other board's software is identical, except I have it set to transmit 5 bytes, all 0xfc from address 24 every 2 seconds.

This is the output of one of the pics:

Code:
\0APUT 1: ID=36 LEN=8 PRI=3 EXT=1 RTR=0\0D                                         
\0A   DATA = 19 19 19 19 19 19 19 19 \0D                                           
\0A\0D                                                                             
\0APUT 1: ID=36 LEN=8 PRI=3 EXT=1 RTR=0\0D                                         
\0A   DATA = 19 19 19 19 19 19 19 19 \0D                                           
\0A\0D                                                                             
\0APUT 1: ID=36 LEN=8 PRI=3 EXT=1 RTR=0\0D                                         
\0A   DATA = 19 19 19 19 19 19 19 19 \0D                                           
\0A\0D                                                                             
\0APUT 1: ID=36 LEN=8 PRI=3 EXT=1 RTR=0\0D                                         
\0A   DATA = 19 19 19 19 19 19 19 19 \0D   


If I look at either of the LT1796's RX outputs, I see what appears to be an automatic retransmit from both pics. I see the same waveform (old crappy analog scope) being repeated over & over.

Crappy ascii waveform to follow.

Idle HHHHLLLHLLLHLLLHHH Idle.

The period of the waveform is just shy of 3 ms, with 3 rather long low states, with 2 short high states between the low states.

If I disconnect one of the pics, the waveform repeats approx every 16.5 ms or so. If I reconnect both pics, the waveform ends up being repeated every 8 - 12 ms or so. The waveform idles high, and is always the same (again, it may be different, but due to this scope, I can't tell).

I suspect that the CAN modules are trying to auto retransmit since the messages aren't being accepted/received by the other pic.

What's wrong?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jul 29, 2005 1:01 pm     Reply with quote

I don't have your PIC, I only have 18F458 chips. So any tests that I do
would have to use the can-18xxx8.c driver.

The can-18xxx8.c driver may work with your PICs, because they have
a Legacy mode (mode 0) which is compatible with the 18F458. Mode 0
is the default power-up mode for your PICs. So please try to use
can-18xxx8.c. Make the same changes to the can_set_baud() routine
so it will run at 125 kbs with a 4 MHz crystal.
newguy



Joined: 24 Jun 2004
Posts: 1909

View user's profile Send private message

PostPosted: Fri Jul 29, 2005 1:22 pm     Reply with quote

Same thing with the can-18xxx8.c include file. I changed the baud rate too.

One thing that happens with this new include file is that the pic stops the serial transmits after the 3rd try to send data over the CAN bus. However, if I examine the actual CAN traffic with a scope, it's still there, just as before.

I have a couple of 18LF458's on hand, so I tried this with them too. Same thing.

What should I see on the TX input of the LT1796's? I don't see anything - just looks like a DC level, about 100 mV above ground.

Edit: There was a small error in the test program I posted. It says the HS fuse is being set, but I've changed that to XT for the 4 MHz clock. Same thing again.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jul 29, 2005 1:24 pm     Reply with quote

I'll try it with a couple 18F458 boards later in the day.
newguy



Joined: 24 Jun 2004
Posts: 1909

View user's profile Send private message

GOT IT!!!!
PostPosted: Fri Jul 29, 2005 2:49 pm     Reply with quote

Exclamation Very Happy Exclamation

It bugged me that the TX lines (inputs of the 1796's) seemed to be "dead". Pointed to a hardware fault.

Out of desperation, I grabbed a couple of resistors. I had a couple of 560 ohms handy. I used them as pullups on the pic's CANTX lines, so now the CANTX lines are still directly connected to pin 1 of the LT1796, only they're also pulled up by these 560 ohm resistors.

That did it. Now it works.

Now, am I blind, or does the LT1796 data say anything about using pullups on the CANTX lines? Does the microchip documentation say anything about pullups anywhere?

Along the same lines, why didn't the port b pullups fix the problem when I enabled them?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jul 29, 2005 3:01 pm     Reply with quote

The LT1796 is a 5v chip. The data sheet says its Vih is 2.8v minimum.
Are you running your PICs at 3.0v possibly ?

From your description it sounds like the CAN_TX pins are open-drain,
but that shouldn't be the case. That's why I'm trying to come up with
a scenario that could explain what you're seeing.
newguy



Joined: 24 Jun 2004
Posts: 1909

View user's profile Send private message

PostPosted: Fri Jul 29, 2005 3:04 pm     Reply with quote

Everything is running at 5V. I can't figure it out either.

The only document I can find with a pullup on the CANTX pin is from Embedded C Programming and the Microchip PIC by Barnett, Cox & O'Cull. They have a schematic in there with a 10k pullup on CANTX and a 10k pulldown on CANRX.

I still can't figure out why enabling port b pullups didn't fix it.
newguy



Joined: 24 Jun 2004
Posts: 1909

View user's profile Send private message

PostPosted: Fri Jul 29, 2005 3:21 pm     Reply with quote

Just took out the 560 ohm pullups and replaced them with 10k pullups. Still works. Now I really can't figure out why the port b pullups didn't work. Aren't the internal pullups about 20k or so?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jul 29, 2005 3:31 pm     Reply with quote

The pull-ups are only enabled if the pin is configured as an input.
newguy



Joined: 24 Jun 2004
Posts: 1909

View user's profile Send private message

PostPosted: Fri Jul 29, 2005 3:36 pm     Reply with quote

Oh yeah. Embarassed

PCM, my sincere thanks. You really go out of your way to help everyone who asks - I really appreciate it.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jul 29, 2005 4:38 pm     Reply with quote

I found out why the pull-ups were needed. I wasn't satisfied to leave
this hanging, so I looked in the 18F4580 data sheet a little.

The 18F4580 has a register called CIOCON. The 18F458 doesn't have
that register. [Actually it does have it. See the post further in this
thread which explains what's happening]. In that register, bit 5 is the
ENDRHI bit. From the data sheet:
Quote:

ENDRHI: Enable Drive High bit (1)
1 = CANTX pin will drive VDD when recessive
0 = CANTX pin will be tri-state when recessive

So if ENDRHI is 0, the CANTX pin will be tri-stated when a logic high
is transmitted. ie., it becomes an open-drain output. That explains
why you needed the pull-up resistor.

The next question is why is this bit being set to 0 ? The data sheet
shows the power-up state is 0, which will be the tri-state mode.
That doesn't sound very compatible. It's not powering up in a mode
that's compatible with the 18F458. [Actually it is, see later in the thread].

Then in the can-18F4580.c driver, in the can_init() routine, CCS has
got this line:
Code:
CIOCON.endrhi=CAN_ENABLE_DRIVE_HIGH;

So you would think that CCS is going to fix the problem by setting it high.

But in can-18F4580.h, CCS has defined it as a 0, which is wrong, in
my opinion.
Code:
#ifndef CAN_ENABLE_DRIVE_HIGH
 #define CAN_ENABLE_DRIVE_HIGH 0
#endif

You can fix this by re-defining it to 1, and by putting that line right
above the #include statement for the driver in your main program.
Then you won't need the pull-up on the CAN_TX pin.
Code:
#define CAN_ENABLE_DRIVE_HIGH  1
#include <can-18F4580.c>



Edited to add a correction regarding the 18F458 and the CIOCON register.


Last edited by PCM programmer on Fri Jul 29, 2005 5:04 pm; edited 1 time in total
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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