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

Canbus problem with PIC18F25K80

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



Joined: 24 Sep 2013
Posts: 16

View user's profile Send private message

Canbus problem with PIC18F25K80
PostPosted: Mon Oct 20, 2014 1:35 pm     Reply with quote

Hi,
I'm working on develeoping a canbus system. My node is listening the bus and send some data's every 100ms.
And i have got a run led which is blinking every 1000ms if it receives a data within 1000ms. Also this run led is blinking every 100ms if it doesn't receive any data within 1000 ms.
Code:

#include <can-18F4580.c>

#int_TIMER2            //4 ms interrupt
void TIMER2_isr(void)
{
   i4msCounter++;
   if (i4msCounter > 24)    // 25 ms * 4 = 100 ms
   {
      bCanBusTransmitDataPeriod = 1;
      i4msCounter = 0;
   }
 
      
   if (iCommTimeOutCounter != 255)   iCommTimeOutCounter++;
   if (iCommTimeOutCounter > 250)      // 250 ms * 4 = 1000 ms
      iRunLedPeriod = 25;
   else
      iRunLedPeriod = 250;

   iRunLedPeriodTimer++;   
   if (iRunLedPeriodTimer > iRunLedPeriod)
   {
      iRunLedPeriodTimer = 0;
      ioRunLed = !ioRunLed;
   }
}


#int_canrx0
void canrx0_int()
{
   iCommTimeOutCounter = 0;
   can_getd(rx_id,receive,rx_len,stat);

   if(rx_id == 0x01025018)
   {
      //some codes.
   }
}


void main()
{
   setup_timer_2(T2_DIV_BY_16,62,10);         //403 us overflow, 4,0 ms interrupt
   setup_timer_3(T3_DISABLED | T3_DIV_BY_1);
   setup_timer_4(T4_DISABLED,0,1);
   setup_comparator(NC_NC_NC_NC);

   TrisA = 0x20;
   TrisB = 0xC0;
   TrisC = 0x80;
   PortA = 0x00;
   PortB = 0x05;
   PortC = 0x30;

   can_init();
   enable_interrupts(int_canrx0);
   enable_interrupts(INT_timer2);
   enable_interrupts(GLOBAL);



   while(TRUE)
   {
      if (bCanBusTransmitDataPeriod == 1)
      {
         bCanBusTransmitDataPeriod = 0;
         can_putd(NodeX, iTrmtData, 1, 2, 1, 0);
      }
   }
}


I have got Real ICE. After Run led is blinking fastly, i halt the system, put a breakpoint in the canrx0_int(), but it doesn't come to this code.
At the same time, i'm monitoring the canbus line, it still sends the data.
It never answer to host and also my queries from canbus monitor (from PC)

Has anyone got any idea?

I'm using PIC18F25K80 and compiler version v5.017
Best regards,
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Oct 21, 2014 8:49 am     Reply with quote

One of the common reasons for non-working CAN bus projects is that one
node is setup for standard length ID's, and the other is setup for extended
ID's. They need to be the same. The CCS CAN bus drivers have
variables and parameters that can be set to select the needed ID length.
ZD



Joined: 24 Sep 2013
Posts: 16

View user's profile Send private message

PostPosted: Tue Oct 21, 2014 10:03 am     Reply with quote

Hi,
Thanks for your reply.
After power up the system, it receives the datas for example 20 seconds. (This time is not exactly 20 sec. It is changing. Sometimes it is longer than 20 sec, sometimes shorter.) After this period, it stops the receiving datas. And it never enter the canrx0_int() again. So, i think, there is no relation between id length. Because at first, it works.

Regards,
ZD



Joined: 24 Sep 2013
Posts: 16

View user's profile Send private message

PostPosted: Tue Oct 21, 2014 1:12 pm     Reply with quote

Hi again.
I think, i found something.
My baudrate is 62,5K. (All settings are at the default values and I'm using 10MHz crystal). That node receives a message every 100ms. So, i didn't suspect anything from overflow. (Also i look the bus traffic with CanBus monitor and it shows me the traffic on the bus around %3).
BUT, it sets COMSTAT.rx1ovfl bit. PIR5 = 0x26. So the Can Module Error Interrupt Flag is set.
I believe that, this fault prevents the receving of new datas. And i don't know, how am i overcome this issue. Please guide me!

P.S. May be the problem is coming from the baudrate mistake. I checked the old discussions. I made a calculation with MBTime. But when i set the values which are generated from MBTime, it doesn't receive any message anymore. Therefore, i leave it the default baudrate values and it works with 62,5K speed because of my crystal is 10MHz.

Best regards,
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Oct 21, 2014 1:31 pm     Reply with quote

Post the values that you calculated with MBtime. Post the 3 bytes.
ZD



Joined: 24 Sep 2013
Posts: 16

View user's profile Send private message

PostPosted: Tue Oct 21, 2014 1:56 pm     Reply with quote

I'm using the default values right now. It works 125K @20MHz crystal. But now, i'm using 10MHz crystal and my baud rate is 62,5K. I can listen the bus with Kvaser CanBus monitor with 62,5K setting. So it works. My values are:
BRGCON1 : 0x04
BRGCON2 : 0xAA
BRGCON3 : 0x05.

Before that, i wanted to set the baudrate 50K @ 10MHz. I created the values from MBTime. Now, i checked it again. I think there is a small bug at MBTime.
With 10MHz Osc, 50 Kbps, Time quanta 12, propagation delay 2Tq, Phase segment-1 6Tq, Phase Segment-2 3Tq, SJW 1Tq, it says "These settings meet all timing requirements". Then i clicked to "Generate report" and setted that three registers without checking the other details.
BUT, % Error of Target Baud Rate is -316,667% (Actual Baud rate is 208,333 kbps). I've just seen them.

I don't have any baudrate problem right now. I'm focusing on that overflow problem. I'm very glad, if you can guide me about it.

Thanks in advance.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Oct 21, 2014 2:36 pm     Reply with quote

Quote:

But now, i'm using 10MHz crystal and my baud rate is 62,5K. I can listen
the bus with Kvaser CanBus monitor with 62,5K setting. So it works.
My values are:
BRGCON1 : 0x04
BRGCON2 : 0xAA
BRGCON3 : 0x05.


If you are sure your CAN bus monitor runs at 62.5 kbps (from reading
the documentation for it), then why not use the MBtime results for
20 quanta ?

20 Quanta
Code:
Register     Binary      Hexadecimal
CNF1/BRGCON1 b'00000011' 0x03
CNF2/BRGCON2 b'10111010' 0xBA
CNF3/BRGCON3 b'00000111' 0x07


You complain that you get excessive errors. Why not use the above
settings which MBtime says give 0% errors ?


Quote:
BUT, % Error of Target Baud Rate is -316,667% (Actual Baud rate is 208,333 kbps). I've just seen them.

I don't have any baudrate problem right now. I'm focusing on that overflow problem. I'm very glad, if you can guide me about it.

You have massive % errors, but you don't have a baudrate problem ?
Really ?
ZD



Joined: 24 Sep 2013
Posts: 16

View user's profile Send private message

PostPosted: Tue Oct 21, 2014 3:53 pm     Reply with quote

It is little bit confused. May be it is caused from my English. Sorry. I try to explain it to you.

At first, i tried some values on MBTime software to learn it. May be 12 quanta remain from the old tests. But i didn't force it to use 12 quanta. Then i used the calculated values for 50K @10MHz and it didn't work. I didn't find the problem then return to the driver default values. And it start to work with 62,5K @10MHz. Now, i understand clearly why it didn't work.

My system is working with default driver values 62,5K @10MHz now. And i have got a problem with overflow error. It sets COMSTAT.rx1ovfl bit. PIR5=0x26 when it stopped the communication. So the Can Module Error Interrupt Flag is set.
I believe that, this fault prevents the receving of new datas. And i don't know, how am i overcome this issue. Please guide me!

Thanks in advance.
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Wed Oct 22, 2014 3:12 am     Reply with quote

ZD wrote:
It is little bit confused.

And it start to work with 62,5K @10MHz. Now, i understand clearly why it didn't work.

My system is working with default driver values 62,5K @10MHz now.


By default, the CCS CAN driver sets up the CAN hardware to give 125Kbits per sec from 20MHz clock. That will give 62.5Kbps from 10MHz, but with the complex way CAN timing works, the CAN timing may be less than optimal or even out of spec., but it may seem to work OK.

MBTime is very useful, but it works from a PIC clock to the CAN timing, and can't "decode" the CAN register settings to tell you what the CAN speed is, and whether its within spec. or not. So, use MBTime to work out what settings you need at your clock rate.

Tq - for timing purposes, each can bit time is divided up into a number of equal "quanta", or shorter time periods, often 8, 10, 16 or so, each of time Tq. MBtime first works out what Tqs are possible and practical with your selected PIC clock. Then, for each Tq, it works out the settings to give good CAN timing. So, for a particular PIC clock and CAN bit rate combination, say 125KHz on 20MHz, it suggests timings for 8, 10,16 and 20 Tq per bit (i.e. Tq of 1us, 0.8us, 0.5us and 0.4us).

So, getting your CAN timing right is important and needs to be done carefully.

Another issue is that by default the CAN will receive on both buffers and you need to have interrupt code (ISRs) for both #int_canrx0 and #int_canrx1. This is because when set up by the default CCS CAN code, will use receive buffer 1 as an overflow is buffer 0 is full. Both interrupts can, in fact, both be handled by the same routine. Also, its possible to reconfigure the CAN to route received messages differently but that's fairly advanced.
ZD



Joined: 24 Sep 2013
Posts: 16

View user's profile Send private message

PostPosted: Tue Oct 28, 2014 3:42 am     Reply with quote

Hi again,
Thank you very much. As you told me, overflow and #int_canrx1 interrupt occurred and i didn't handle it.
I wrote the #int_canrx1 interrupt which is completely same code with #int_canrx0. And now it works better.

Note: To be honest, still i don't understand why it overflow to the rx1. Because, it receives data only every 100 ms and i handle that received data immediately with #int_canrx1 interrupt). I'm also analyse the can datas with Kvaser CanKing and bus load is only %3. And this %3 value consist both received and transmitted datas of my node.

It works better.(Before handling #int_canrx1, it gives this fault after 3-5 minutes after power it up.) Now it works several hours and gives same fault. And i believe that, it still overflow.

Would you please tell me some ideas to overcome this fault.
Thanks in advance.
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Tue Oct 28, 2014 5:13 am     Reply with quote

What is "//some codes" in your ISR? You must finish your ISR before the next message comes in. If "//some codes" means a lot of stuff, then you will have big problems. Better to buffer your messages and then handle/interpret them in your main loop.

Also, you don't appear to have fully sorted out your baudrate problems. Yes it "works", but is it right? That may be making it unreliable.

I have CAN code that works fine with multiple CAN nodes (all PIC18s of various types) for as long as the system is powered. I don't have any of the unreliability problems you are getting. I buffer all incoming messages and handle them in a message handler called from my main loop. I have one routine, that may be declared as inline, called from the two interrupts. I ensure I handle the unlikely but possible cases of there being more than one CAN message waiting to be processed, and of there being NO message to process. I use something like this (this is simplified from my actual code and so is NOT tested). It may look long, but most of it is comments:

Code:



// 16 receive buffers. This is to allow
// for filtered messages, not ALL messages.
#define CAN_RX_BUFFERS 16

// CAN receive circular buffer counters.
// If they are equal then the buffer is empty.
// If Read  - Write mod Buffers is 1 then the buffer is full.
// The interrupt routines write in to the buffer, incrementing Write mod Buffers
// The access routines, interrupt locked to prevent buffer corruption, decrement Read mod Buffers.
// This is classic circular buffer behaviour.

signed int Can_Rx_Buffer_Count = 0;

struct Can_Buffer {
   BYTE Data[8];
   int Length;
   int32 ID;
};

struct Can_Buffer can_rx_buffer[CAN_RX_BUFFERS];

// In this implementation, to avoid 16 bit multiplies in interrupt routines,
// and to get more compact interrupt code we use real C pointers rather
// than array indicies. As a result this code has a C++ feel to it
// as it uses the -> operator extensively.
struct Can_Buffer* Can_Rx_Buffer_Write_Ptr;
struct Can_Buffer* Can_Rx_Buffer_Read_Ptr;

#define CAN_BUFFER_FULL  (Can_Rx_Buffer_Count == CAN_RX_BUFFERS)
#define CAN_BUFFER_EMPTY (Can_Rx_Buffer_Count == 0)

void Read_CAN(void)
{
   // With this arrangement of interrupt handling, with two interrupts served
   // by one handler, it is possible to service a pending interrupt before its
   // raised. When it is finally raised there is no data to receive. So it
   // possible for this routine to not receive any data under some heavy load
   // circumstances. That appears to be normal... hopefully...

   while (can_kbhit())
   {
      if(!CAN_BUFFER_FULL)   // Write to buffer if one is available.
      {
         // Copy the data and the message length into our buffer. It is
         // possible for can_getd() to fail, returning FALSE. This should never
         // happen thanks to the while above.
         can_getd(rx_id, Can_Rx_Buffer_Write_Ptr->Data, rx_len, rxstat);
         
         // For some reason the compiler didn't like an array reference in the can_getd call, so we copy
         // the length here instead.
         Can_Rx_Buffer_Write_Ptr->Length = rx_len;

         // Update the buffer write pointer, wrapping if required.
         
         // Modulo, %, below involves a divide. This is an interrupt routine and
         // the PIC implements a divide by a subroutine. This causes trouble
         // as it is not atomic nor re-entrant. Hence the compiler will
         // warn that it has to disable interrupts. If we change the number of
         // buffers to 2, 4 or 8 and use bit masking to do the mod, then this
         // issue will go away. Another way round it would be to use an if.
         
         // mod version:
         //New_Write_Pointer = (Can_Rx_Buffer_Write + 1) % CAN_RX_BUFFERS;
           
         // The if pointer version follows the same pattern.
         if (++Can_Rx_Buffer_Write_Ptr >= Can_Rx_Buffer + CAN_RX_BUFFERS)
            Can_Rx_Buffer_Write_Ptr = Can_Rx_Buffer;
         Can_Rx_Buffer_Count++;
      }
      else
      {
         // No buffer was free, we still have to read the data to somewhere
         can_getd(rx_id, buffer, rx_len, rxstat);   // ...and fill with the new data. We wont do anything with it.
   
         // No buffer was available. We should perhaps send out a debug message.
         // However sending messages from interrupt routines is generally
         // a bad idea, and on many processors/compilers is a total no-no.
      }
      // Loop round if there is any more data available.
   }
}

#int_canrx0
void canrx0_int()
{
   Read_CAN();
}

#int_canrx1
void canrx1_int()
{
   Read_CAN();
}

BOOLEAN Can_Buffer_Read(struct Can_Buffer *Buffer)
{
   // This is a flag, set by default to false.
   BOOLEAN Got_Data = FALSE;

   if (!CAN_BUFFER_EMPTY)
   {
      // Copy the data from the CAN buffer into the user's buffer.
      // We don't mind if there's an interrupt during this copy.
      *Buffer = *Can_Rx_Buffer_Read_Ptr;
     
      // Update the CAN buffer pointers.
      // The % below involves a divide. The PIC implements a divide by a
      // subroutine. This causes trouble as it is not atomic nor re-entrant.
      // Hence the compiler may warn that it has to disable interrupts
      // if we use divides in any interrupt routine. If we change the number
      // of buffers to 2 or 4 and use bit masking to do the mod, then this
      // issue will go away. Another way round the issue is to use an if.
      // Actually the problem shouldn't happen as we have interrupts turned
      // off and therefore the problem shouldn't arise. However, it may be that
      // the compiler isn't smart enough to suss that.
   
      // mod version:
      //Can_Rx_Buffer_Read %= (Can_Rx_Buffer_Read + 1) % CAN_RX_BUFFERS;
     
      // if version:
      // The pointer version follows the same pattern.
      if (++Can_Rx_Buffer_Read_Ptr >= Can_Rx_Buffer + CAN_RX_BUFFERS)
      {
         Can_Rx_Buffer_Read_Ptr = Can_Rx_Buffer;
      }
     
      // As the buffer full and empty flags, which regulate the buffer, are
      // ints and all increments, decrements and tests on ints are atomic,
      // it is OK to not interrupt lock this buffer at all.
      // This is because all the other operations: reading from the buffer
      // and updating the pointer, only ever happen here in this mainline
      // code. If the buffer count was 16 bit however, we'd have to
      // interrupt lock updating the count as it would not be atomic and
      // could be interrupted between changing one byte and the other.
      Can_Rx_Buffer_Count--;

      Got_Data = TRUE;
   }

   // Return the flag to show we have data... or not as the case may be.
   return Got_Data;
}
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