HomeTOOLSEXAMPLESEXPLORE EMBEDDEDE CSERVICESECU SAMPLESRegistration
Embedded C programming Tutorial , Keil C ide , microsoftware.gr
Keil CRC and CAN BUS codes.
1. Shift led left
2.It's time for DAVE! <7/6/13>
3.Capture/Compare unit 6
4.ASC0-GPT1-MACROS
5.ASC0-FIFO-PEC
6.Analog converter
7.Memory manipulation routines
8. Recursion
9.Understanding interrupt priorities using CAPCOM2 module
10. POINTERS TO FUNCTION <4/7/13>,<4/28/13>
11.Memory models, memory types
12. The heap , part 1
13. The heap , part 2
14. The heap , part 3
15. Structure example
16. Nested structures, Array of structures.
17. Passing array of structures to function using pointers.<1/5/13>
18. Self Referential Structures
19. BITFIELDS
20. Linked list example
21. Circular linked list
22. Union example
23. Enumeration example
24. Watchdog timer example
25. Void pointer example <7/4/13>
26. The sieve of Eratosthenes
27. The stack
28. Union and bitfields as flags example. <6/23/13>
29. Look up table example. <8/11/13>
30. Seven segment display multiplexing -four digits with dot- example
31. LCD character display example - JHD162A
32. Hash table introduction example <8/27/14>
33. Array of Linked Lists example
34. Array of Linked lists-more functions included.
35. Hash table construction,searching and printing.
36. Fininte state machines- a first approach.
37. Finite state machines- two events example.
38. SPI port and an AT25128 serial eeprom hardware.
39. CRC CHECK
40. Definite Integral Calculator for Scientists, Engineers...
41 .Hamming distance of a CRC polynomial
42. Linux play starting.
43. Galois GF(2^4) Finite Field
44. Construct your own time triggered real time operating system.
45. CANBUS C CODE EXAMPLE.
45. CANBUS C CODE EXAMPLE.
CANBUS  C  CODE  EXAMPLE   <5/june/2016>

Today I am starting to present a C CANBUS code example. The code is written for xc164cm microcontroller but you can insert it in your own microcontroller easily.

Inside of the xc164cm integrated circuit there are two separated CANBUS controllers, named node A and node B. Also there are 32 message objects constructed in RAM memory space. The data space of each one of these 32 objects is 8 bytes long ,each object  can be defined as a transmit or as a receive object and can be connected to node A or to node B. You can easily configure the CAN module using Infineon Dave. 
Each object is a structure like this:

// The following data type serves as a software message object. Each access to
// a hardware message object has to be made by forward a pointer to a software
// message object (TCAN_SWObj). The data type has the following fields:
//
// uwMsgCfg:
// this byte has the same structure as the message configuration register of a
// hardware message object. It contains the "Data Lenght Code" (DLC), the 
// "Extended Identifier" (XTD), the "Message Direction" (DIR), the "Node
// Select" and the "Remote Monitoring Mode".
//
//
//         7     6     5      4    3     2         1          0
//      |-------------------------------------------------------
//      |       DLC            | DIR | XTD | NODE | RMM |
//      |-------------------------------------------------------
 
// ulID: 
// this field is four bytes long and contains either the 11-bit identifier 
// or the 29-bit identifier
//
// ulMask: 
// this field is four bytes long and contains either the 11-bit mask 
// or the 29-bit mask
//
// ubData[8]:
// 8 bytes containing the data of a frame
//
// uwCounter:
// this field is two bytes long and contains the counter value 
//

typedef struct
  {
     uword  uwMsgCfg;   // Message Configuration Register
     ulong  ulID;       // standard (11-bit)/extended (29-bit) identifier
     ulong  ulMask;     // standard (11-bit)/extended (29-bit) mask
     ubyte  ubData[8];  // 8-bit Data Bytes
     uword  uwCounter;  // Frame Counter
  }TCAN_SWObj;

To be able to 'catch' the data of each one of the 32 message objects by software we divide the data space of  each message object to four 'unsigned integer' parts . For example the  data space of message object 0 starts at address 0x200300 in RAM and it is divided to 4 unsigned integer parts as:

// Message Object 0 Data Register 0 Low
#define CAN_MSGDRL00           (*((uword volatile far *) 0x200300))
 
 
// Message Object 0 Data Register 0 High
#define CAN_MSGDRH00           (*((uword volatile far *) 0x200302))

// Message Object 0 Data Register 4 Low
#define CAN_MSGDRL04           (*((uword volatile far *) 0x200304))

// Message Object 0 Data Register 4 High
#define CAN_MSGDRH04           (*((uword volatile far *) 0x200306))

with  typedef unsigned int   uword;    // 2 byte unsigned; prefix: uw 

The avantage of the existence of node A and node B is that you can interconnect them inside of the integrated circuit using Dave, making a complete two nodes CANBUS network (it is called a loop-back mode) giving to you the ability to test your CANBUS software.

As a first example I'll use node A and node B connected at loop-back mode and message object 0 (mo0) configured as a recieve object connected to node A and nessage object 1 (mo1) configured as a transmit message object connected to node B . The data content of mo1 is: 0x30, 0x31, 0x32 , 0x33  ,0x34, 0x35, 0x36 ,0x37.

Using timer GPT1 to do an underflow interrupt every 800 msec we will send the data of mo1 to mo0 like this:

void GPT1_viTmr3(void) interrupt T3INT
{
  // USER CODE BEGIN (Tmr3,2)
  CAN_vTransmit(1);
  // USER CODE END


and

void CAN_vTransmit(ubyte ubObjNr)
{
  CAN_HWOBJ[ubObjNr].uwMSGCTR = 0xe7ff;  // set TXRQ, reset CPUUPD

} //  End of function CAN_vTransmit

Now mo0 has received data and produces an interrupt. So, the serial module named ASC0 reveieves the data of mo0 part by part ( remember that we divided the data space of mo0 to 4 unsigned integer parts) and send them to a terminal program ,say Hyperterminal, at your computer. The mo0 interrupt procedure is :

uword A;
 static unsigned int b=0;  

void CAN_viSRN0(void) interrupt CAN_SRN0INT
{
  uword uwStatusA;
  uword uwStatusB;

  // USER CODE BEGIN (SRN0,2)

  // USER CODE END

  while((( ((ulong)CAN_RXIPNDH << 16) + CAN_RXIPNDL) & 0x00000001) || (CAN_ASR & 0x0018) || (CAN_BSR & 0x0018))
  {

    // status change interrupt of node A
uwStatusA = CAN_ASR;
    if (uwStatusA & 0x0008)  // if TXOK
    {
      // Indicates that a message has been transmitted successfully
      // (error free and acknowledged by at least one other node).
 
      uwStatusA &= 0xfff7;
      CAN_ASR    = uwStatusA;    // reset TXOK

      // USER CODE BEGIN (SRN0_NODEA,3)

      // USER CODE END
    }

 if (uwStatusA & 0x0010)  // if RXOK
    {
      // Indicates that a message has been received successfully.

      uwStatusA &= 0xffef;
      CAN_ASR    = uwStatusA;    // reset RXOK

      // USER CODE BEGIN (SRN0_NODEA,4)

      // USER CODE END
    }

 
    // USER CODE BEGIN (SRN0_NODEA,13)

    // USER CODE END

 // status change interrupt of node B

    uwStatusB = CAN_BSR;
    if (uwStatusB & 0x0008)  // if TXOK
    {
      // Indicates that a message has been transmitted successfully
      // (error free and acknowledged by at least one other node).

      uwStatusB &= 0xfff7;
      CAN_BSR    = uwStatusB;    // reset TXOK

      // USER CODE BEGIN (SRN0_NODEB,3)

      // USER CODE END
    }

 if (uwStatusB & 0x0010)  // if RXOK
    {
      // Indicates that a message has been received successfully.

      uwStatusB &= 0xffef;
      CAN_BSR    = uwStatusB;    // reset RXOK

      // USER CODE BEGIN (SRN0_NODEB,4)

      // USER CODE END
    }

// USER CODE BEGIN (SRN0_NODEB,13)

    // USER CODE END
 
 
 
    // message object 0 interrupt

    if((CAN_HWOBJ[0].uwMSGCTR & 0x0003) == 0x0002)         // if INTPND 
    {
      if(CAN_RXIPNDL & CAN_RXIPNDL_RXIPND0)   // message object 0 receive interrupt
      {

        if((CAN_HWOBJ[0].uwMSGCTR & 0x0300) == 0x0200)     // if NEWDAT is set
        {

          if ((CAN_HWOBJ[0].uwMSGCTR & 0x0c00) == 0x0800)  // if MSGLST is set

{
            // Indicates that the CAN controller has stored a new 
            // message into this object, while NEWDAT was still set,
            // ie. the previously stored message is lost.
 
            CAN_HWOBJ[0].uwMSGCTR = 0xf7ff;  // reset MSGLST

            // USER CODE BEGIN (SRN0_OBJ0,1)

            // USER CODE END
          }
          else

{
            // The CAN controller has stored a new message
            // into this object.

            // USER CODE BEGIN (SRN0_OBJ0,2)
   b++;
 while (b==3)
 {P1L_P0=! P1L_P0; 
  b=0; }

ASC0_vSendData(CAN_MSGDRL00);
A= CAN_MSGDRL00 >>8 ;
ASC0_vSendData(A);

 ASC0_vSendData(CAN_MSGDRH00);
A= CAN_MSGDRH00 >>8 ;
ASC0_vSendData(A);

                          ASC0_vSendData(CAN_MSGDRL04 );
 A=CAN_MSGDRL04 >>8 ;
 ASC0_vSendData(A);

 
 ASC0_vSendData(CAN_MSGDRH04 );
 A=CAN_MSGDRH04 >>8 ;
 ASC0_vSendData(A);



            // USER CODE END
          }

 CAN_HWOBJ[0].uwMSGCTR = 0xfdff;    // reset NEWDAT
        }

      }  // End of RXIPND0


      CAN_HWOBJ[0].uwMSGCTR = 0xfffd;        // reset INTPND

      // USER CODE BEGIN (SRN0_OBJ0,6)

      // USER CODE END

    }

 // USER CODE BEGIN (SRN0,3)

    // USER CODE END


  }  // End of while()

  // USER CODE BEGIN (SRN0,7)

  // USER CODE END

} //  End of function CAN_viSRN0


// USER CODE BEGIN (CAN_General,10)

// USER CODE END

Identifiers of message objects are 29 bits long. Node A and Node B run at a speed of 250 kbit/sec and you can modify it using Dave. Serial module ASC0 run at 19200 baud.

The program blinks a led connected at  P1L_P0 pin when ASC0  transfers CANBUS data to your computer.

Attention! Save the ASC0.C  file before re-configure the project by DAVE!
DAVE deletes the status of some flags of ASC0, and so ASC0 IS unable to transmit. Delete the ASC0.C file generated by DAVE and paste to the project the saved ASC0.C file.

The complete CANBUS C code for the loop-back mode is    here.

a useful link is
:http://www.esacademy.com/en/library/technical-articles-and-documents/can-and-canopen/selecting-a-can-controller.html

continued . . .
 

CANBUS FIFO BUFFER AND CRC16 ERROR HANDLING <15/June/2016>

A First in first out buffer (FIFO) and a CRC error checking are presenting.

We will use message objects mo0 and mo1 connected together to make a receive FIFO .This FIFO is connected to CAN node A.

As transmiters we will use mo2, mo3 and mo4 connected to node B including the following data:

mo2 data: 0x31, 0x00,0x00,0x00,0x00,0x00,0x00,0x31
mo3 data: the CRC16-CCITT of data  of message mo2.
mo3 data: 0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x33

CRC16-CCITT(mo2)=0x6A1D

About CRC16-CCITT see article no 39.

So, our FIFO receive buffer is mo0:mo1, mo1 is the slave.

The order of transmition is : <--mo2 <--mo3 <--mo4

Let to see now what will be happening.
First transmition  of mo2, mo3 and mo4

mo2 --> mo0
mo3 --> mo1
mo4 --> mo0

So the data of FIFO will be :    m04:mo3

Second transmition of mo2 , mo3 and mo4

mo2 --> mo1
mo3 --> mo0
mo4 --> mo1

so the FIFO will  be :  mo3:mo4

Third transmition of mo2,mo3 and mo4

mo2 --> mo0
mo3 --> mo1
mo4 --> mo0

so the FIFO is  mo4:mo3
and so on.

Opening the memory window you can watch what is happening to message objects (control registers and data registers) at the addresses:

mo0 address  0x200300
mo1 address  0x200320
mo2 address  0x200340
mo3 address  0x200360
mo4 address  0x200380

important bitfields at the control registers are the :

TXRQ (2 bits long)
01 No message object data transmission is

requested by the CPU or a remote frame.

10 The transmission of the message object data,

requested by the CPU or by a remote frame, is

pending

RMTPND [15:14]

rwh Remote Pending Flag (used for transmit-objects)

01 No remote node request for a message object

data transmission.

10 Transmission of the message object data has

been requested by a remote node but the data

has not yet been transmitted. When RMTPND

is set, the CAN node controller also sets TXRQ.

RMTPND is automatically reset, when the message

object data has been successfully transmitted


Some points about CRC.
At the manual of xc164cm it is simply noted that there is a CRC calculation coming from node A and node B with no more informations.
You have not access to the way of  this CRC calculation.
Here I am using the C code of CRC16-CCITT as in article no 39 with the following functions:

 unsigned int crc16(unsigned long int message ) {
unsigned int j=0;
unsigned long int d=0x1021 ;
 
  d=d<<16; // we don't want the 16 zeros in front
  crc=message;
for (j=0;j<=15;j++)
{
test=crc>>16; // to test the #31 bit of crc. see the #define above. 
                     //A warning about value truncated here but ignore it
 
if (CRC31)
{
crc=crc<<1;
crc=crc^d ;
}
 
else crc= crc<<1;
 
}
 
crc=crc>>16;
 
return crc;
 
}
===========================

 void crc16_table (void){
unsigned int t ;
unsigned int long i;
for (i=0;i<256;i++)
{
 
t=crc16(i<<16);
 
t1[(unsigned char)i]=(unsigned char)(t>>8);
 
t2[(unsigned char)i]=(unsigned char) t;
 
}
 
}
 
====================

 
unsigned int crc16_table_calculator (unsigned char *m,  unsigned int k)  {
unsigned char a=0;
unsigned int v=0;  // v the crc
unsigned int j;
 
for(j=0; j<=k;j++) {
v=(  (unsigned int ) (t1[a]^(unsigned char) v ) ) <<8 ^( t2[a] ^ *(m+j) );
a= (unsigned char) (v>>8) ;
 
}
return v;
}


The complete project is   here.
 
Observe the "VIEWS" word file enclosed.


To be clear the above procedure of writing to the FIFO buffer I insert a
1 msec time delay before the next CANBUS message object transmition, using the following function  for T5 timer:

void delay_T5 (unsigned int t) 
{
 GPT12E_T5IC_IR =0;            // Reset IR bit
 
GPT2_vLoadTmr_GPT2_TIMER_5(t);
 
GPT2_vStartTmr_GPT2_TIMER_5(); // GPT2_vStartTmr_GPT2_TIMER_5()
 
while (GPT12E_T5IC_IR!=1 ); //wait for timer T5 to overflow
 
GPT2_vStopTmr_GPT2_TIMER_5();
  
}

I changed the data of mo2 amd mo4.  Data of   mo3 is the crc16 of mo2,
it is  0x45BF (in memory 0xBF45 that is the printable characters ΩΕ) 
Seting breakpoints at the delay calls observe the changes at memory window. Watch the enclosed "VIEWS" word file.

The project is           here.



canbus transmit and receive interrupts <25/June/2016>

Today I am presenting CANBUS transmit and receive interrupts.
I am using:
mo0 and mo1 configured as receive and assigned to node A.
mo2 and mo3 configured as transmit objects and assigned to node B , mo3 includes in its data space and the crc16 of mo2 that is 0xBF45. 

All interrupts are serviced by peripheral evevnt controller (PEC)  FOR A FAST service.  PEC is the analogous of direct memory access,

The Main transmit interrupt is that of nod B and the nested interrupts included are those of transmit  objects mo2 and mo3. This interrupt is serviced by PEC channel1. When something is transmitted by nod B a led is blinking.

The main receive interrupt is that of node A and the nested interrupts included are those of receive objects mo0 and mo1. This interrupt  is serviced by PEC channel0. When something is received by node A a led is blinking.

To see what a message object  IS READY TO DO  (transmit or rceive) the interrupt pending bitfield INTPND of the control register of a message object ( 2 BITS LONG) is checked.

The transmit interrupt  C code for nod B and mo2 and mo3 is:

void CAN_viSRN1(void) interrupt CAN_SRN1INT
{
  uword uwStatusB;
 
  // USER CODE BEGIN (SRN1,2)
 
  // USER CODE END
 
  while((( ((ulong)CAN_TXIPNDH << 16) + CAN_TXIPNDL) & 0x0000000C) || (CAN_BSR & 0x0018))
  {
 
    // status change interrupt of node B
 
    uwStatusB = CAN_BSR;
    if (uwStatusB & 0x0008)  // if TXOK
    {
      // Indicates that a message has been transmitted successfully
      // (error free and acknowledged by at least one other node).
 
      uwStatusB &= 0xfff7;
      CAN_BSR    = uwStatusB;    // reset TXOK
 
      // USER CODE BEGIN (SRN1_NODEB,3)
  P1L_P1= ~P1L_P1  ; // blink led
      // USER CODE END
    }
 
    if (uwStatusB & 0x0010)  // if RXOK
    {
      // Indicates that a message has been received successfully.
 
      uwStatusB &= 0xffef;
      CAN_BSR    = uwStatusB;    // reset RXOK
 
      // USER CODE BEGIN (SRN1_NODEB,4)
 
      // USER CODE END
    }
 
 
    // USER CODE BEGIN (SRN1_NODEB,13)
 
    // USER CODE END
 
 
 
    // message object 2 interrupt
 
    if((CAN_HWOBJ[2].uwMSGCTR & 0x0003) == 0x0002)         // if INTPND 
    {
      if(CAN_TXIPNDL & CAN_TXIPNDL_TXIPND2)   // message object 2 transmit interrupt
      {
 
        // The transmission of the last message object
        // was successful.
 
        // USER CODE BEGIN (SRN1_OBJ2,4)
 
        // USER CODE END
 
        CAN_HWOBJ[2].uwMSGCTR = 0xfdff;      // reset NEWDAT
 
      }  // End of TXIPND2
 
      CAN_HWOBJ[2].uwMSGCTR = 0xfffd;        // reset INTPND
 
      // USER CODE BEGIN (SRN1_OBJ2,6)
 
      // USER CODE END
 
    }
 
 
    // message object 3 interrupt
 
    if((CAN_HWOBJ[3].uwMSGCTR & 0x0003) == 0x0002)         // if INTPND 
    {
      if(CAN_TXIPNDL & CAN_TXIPNDL_TXIPND3)   // message object 3 transmit interrupt
      {
 
        // The transmission of the last message object
        // was successful.
 
        // USER CODE BEGIN (SRN1_OBJ3,4)
 
        // USER CODE END
 
        CAN_HWOBJ[3].uwMSGCTR = 0xfdff;      // reset NEWDAT
 
      }  // End of TXIPND3
 
      CAN_HWOBJ[3].uwMSGCTR = 0xfffd;        // reset INTPND
 
      // USER CODE BEGIN (SRN1_OBJ3,6)
 
      // USER CODE END
 
    }
 
 
    // USER CODE BEGIN (SRN1,3)
 
    // USER CODE END
 
 
  }  // End of while()
 
  // USER CODE BEGIN (SRN1,7)
 
  // USER CODE END
 
} //  End of function CAN_viSRN1
 
 
 
// USER CODE BEGIN (CAN_General,10)
 
// USER CODE END


The receive interrupt C code for node A and mo0 and mo1 is :

void CAN_viSRN0(void) interrupt CAN_SRN0INT
{
  uword uwStatusA;
 
  // USER CODE BEGIN (SRN0,2)
 
  // USER CODE END
 
  while((( ((ulong)CAN_RXIPNDH << 16) + CAN_RXIPNDL) & 0x00000003) || (CAN_ASR & 0x0018))
  {
 
    // status change interrupt of node A
 
    uwStatusA = CAN_ASR;
    if (uwStatusA & 0x0008)  // if TXOK
    {
      // Indicates that a message has been transmitted successfully
      // (error free and acknowledged by at least one other node).
 
      uwStatusA &= 0xfff7;
      CAN_ASR    = uwStatusA;    // reset TXOK
 
      // USER CODE BEGIN (SRN0_NODEA,3)
 
      // USER CODE END
    }
 
    if (uwStatusA & 0x0010)  // if RXOK
    {
      // Indicates that a message has been received successfully.
 
      uwStatusA &= 0xffef;
      CAN_ASR    = uwStatusA;    // reset RXOK
 
      // USER CODE BEGIN (SRN0_NODEA,4)
  P1L_P0= ~P1L_P0  ; // blink led
      // USER CODE END
    }
 
 
    // USER CODE BEGIN (SRN0_NODEA,13)
 
    // USER CODE END
 
 
 
    // message object 0 interrupt
 
    if((CAN_HWOBJ[0].uwMSGCTR & 0x0003) == 0x0002)         // if INTPND 
    {
      if(CAN_RXIPNDL & CAN_RXIPNDL_RXIPND0)   // message object 0 receive interrupt
      {
 
        if((CAN_HWOBJ[0].uwMSGCTR & 0x0300) == 0x0200)     // if NEWDAT is set
        {
 
          if ((CAN_HWOBJ[0].uwMSGCTR & 0x0c00) == 0x0800)  // if MSGLST is set
          {
            // Indicates that the CAN controller has stored a new 
            // message into this object, while NEWDAT was still set,
            // ie. the previously stored message is lost.
 
            CAN_HWOBJ[0].uwMSGCTR = 0xf7ff;  // reset MSGLST
 
            // USER CODE BEGIN (SRN0_OBJ0,1)
            // USER CODE END
          }
          else
          {
            // The CAN controller has stored a new message
            // into this object.
 
            // USER CODE BEGIN (SRN0_OBJ0,2)
 
            // USER CODE END
          }
 
          CAN_HWOBJ[0].uwMSGCTR = 0xfdff;    // reset NEWDAT
        }
 
      }  // End of RXIPND0
 
 
      CAN_HWOBJ[0].uwMSGCTR = 0xfffd;        // reset INTPND
 
      // USER CODE BEGIN (SRN0_OBJ0,6)
 
      // USER CODE END
 
    }
 
 
    // message object 1 interrupt
 
    if((CAN_HWOBJ[1].uwMSGCTR & 0x0003) == 0x0002)         // if INTPND 
    {
      if(CAN_RXIPNDL & CAN_RXIPNDL_RXIPND1)   // message object 1 receive interrupt
      {
 
        if((CAN_HWOBJ[1].uwMSGCTR & 0x0300) == 0x0200)     // if NEWDAT is set
        {
 
          if ((CAN_HWOBJ[1].uwMSGCTR & 0x0c00) == 0x0800)  // if MSGLST is set
          {
            // Indicates that the CAN controller has stored a new 
            // message into this object, while NEWDAT was still set,
            // ie. the previously stored message is lost.
 
            CAN_HWOBJ[1].uwMSGCTR = 0xf7ff;  // reset MSGLST
 
            // USER CODE BEGIN (SRN0_OBJ1,1)
 
            // USER CODE END
          }
          else
          {
            // The CAN controller has stored a new message
            // into this object.
 
            // USER CODE BEGIN (SRN0_OBJ1,2)
 
            // USER CODE END
          }
 
          CAN_HWOBJ[1].uwMSGCTR = 0xfdff;    // reset NEWDAT
        }
 
      }  // End of RXIPND1
 
 
      CAN_HWOBJ[1].uwMSGCTR = 0xfffd;        // reset INTPND
 
      // USER CODE BEGIN (SRN0_OBJ1,6)
 
      // USER CODE END
 
    }
 
 
    // USER CODE BEGIN (SRN0,3)
 
    // USER CODE END
 
 
  }  // End of while()
 
  // USER CODE BEGIN (SRN0,7)
 
  // USER CODE END
 
} //  End of function CAN_viSRN0
 


The complete project is      
here.

Observe the VIEWS word file enclosed.


continued...




 

Home|TOOLS|EXAMPLES|EXPLORE EMBEDDEDE C|SERVICES|ECU SAMPLES|Registration