+#include "can/lpc17xx_can.h"
+
+static void CAN_configPin();
+static void CAN_setBusTiming(uint32_t baudrate);
+
+//------------------------------------------
+
+static void CAN_configPin(){
+
+// CAN1 - select P0.0 as RD1. P0.1 as TD1
+
+ uint32_t pinsel0;
+ uint32_t pinmode0;
+ uint32_t pinmode_od0;
+ uint8_t pinsel0_val = 1;
+ uint8_t pinmode0_val = 0;
+ uint8_t pinmode_od0_val = 0;
+
+
+ pinsel0 = PINSEL0;
+ pinsel0 &= ~CAN1_RX_MASK;
+ pinsel0 &= ~CAN1_TX_MASK;
+ pinsel0 |= __val2mfld(CAN1_RX_MASK, pinsel0_val);
+ pinsel0 |= __val2mfld(CAN1_TX_MASK, pinsel0_val);
+ PINSEL0 = pinsel0;
+
+ pinmode0 = PINMODE0;
+ pinmode0 &= ~CAN1_RX_MASK;
+ pinmode0 &= ~CAN1_TX_MASK;
+ pinmode0 |= __val2mfld(CAN1_RX_MASK, pinmode0_val);
+ pinmode0 |= __val2mfld(CAN1_TX_MASK, pinmode0_val);
+ PINMODE0 = pinmode0;
+
+ pinmode_od0 = PINMODE_OD0;
+ if (pinmode_od0_val){
+ pinmode_od0 |= CAN1_RX_BIT;
+ pinmode_od0 |= CAN1_TX_BIT;
+ }
+ else{
+ pinmode_od0 &= ~CAN1_RX_BIT;
+ pinmode_od0 &= ~CAN1_TX_BIT;
+ }
+ PINMODE_OD0 = pinmode_od0;
+
+
+}
+
+void CAN_send(canmsg_t* msg){
+
+ uint32_t data;
+ uint32_t i;
+
+ // check status of TB1
+ while (!(CAN1SR & (1<<2))){}
+
+ CAN1TFI1 &= ~0x000F0000;
+ CAN1TFI1 |= (msg->length)<<16;
+
+ // EXT frame
+ if(msg->flags & MSG_EXT)
+ CAN1TFI1 |= (1<<31);
+ else
+ CAN1TFI1 &= ~(1<<31);
+
+ // RTR frame
+ if(msg->flags & MSG_RTR)
+ CAN1TFI1 |= (1<<30);
+ else
+ CAN1TFI1 &= ~(1<<30);
+
+ // write CAN ID
+ CAN1TID1 = msg->id;
+
+ // write first 4 data bytes
+
+ data=0;
+ for(i=0; i<4; i++)
+ data |= (msg->data[i])<<(i*8);
+
+ CAN1TDA1 = data;
+
+ // write second 4 data bytes
+
+ data=0;
+ for(i=4; i<8; i++)
+ data |= (msg->data[i])<<((i-4)*8);
+ CAN1TDB1 = data;
+
+ // write transmission request
+ CAN1CMR = 0x21;
+
+}
+
+void CAN_setBusTiming(uint32_t baudrate){
+
+ uint32_t PCLK_CAN;
+ uint32_t res;
+
+ uint8_t tq_numb; // number of time quantum
+ uint8_t TSEG1, TSEG2;
+ uint8_t BRP;
+ uint8_t SJW;
+ uint8_t SAM;
+ uint8_t div;
+
+ // 0 = the bus is sampled once
+ SAM = 0;
+
+ // the Synchronization Jump Width (this value plus one)
+ SJW = 3;
+
+ // get clock divide for CAN1
+ div = __mfld2val(PCLK_CAN1_MASK, PCLKSEL0);
+ switch(div){
+ case 0:
+ div = 4;
+ break;
+ case 1:
+ div = 1;
+ break;
+ case 2:
+ div = 2;
+ break;
+ case 3:
+ // only for CAN, for other peripherials '11' value means div=8
+ div = 6;
+ break;
+ }
+
+
+ PCLK_CAN = system_frequency / div;
+
+ res = PCLK_CAN / baudrate;
+
+
+ // calculation of tq_numb - number of time quantum (must be in <8,25>)
+ // tq_numb = TSEG1 + TSEG2 + 3
+
+ for(tq_numb=25; tq_numb>=8; tq_numb--){
+
+ if ((res%tq_numb)==0){
+
+ // Baud Rate Prescaler. The PCLK clock is divided by (this value plus one) to produce the CAN clock.
+ BRP = (res / tq_numb) - 1;
+
+ // sync. segment allways 1 tq
+ tq_numb--;
+
+ // number of tq from the sample point to the next nominal Sync. point (this value plus one)
+ TSEG2 = (tq_numb/3) - 1;
+
+ // number of tq from Sync. point to the sample point (this value plus one)
+ TSEG1 = tq_numb - (tq_numb/3) - 1;
+
+ break;
+ }
+ }
+
+ CAN1BTR = ((SAM<<23)|(TSEG2<<20)|(TSEG1<<16)|(SJW<<14)|(BRP<<0));
+
+}
+
+void CAN_init(uint32_t baudrate)
+{
+ uint32_t tmp;
+ uint32_t pclksel0;
+ uint32_t val;
+
+
+ // configure CAN1 pins
+ CAN_configPin();
+
+ // turn on power and clock for CAN1
+ PCONP |= PCCAN1;
+
+ // set clock divide for CAN1
+
+ val = 0x00; // 00 PCLK_peripheral = CCLK/4
+ pclksel0 = PCLKSEL0;
+ pclksel0 &= ~PCLK_CAN1_MASK;
+ pclksel0 &= ~PCLK_CAN2_MASK;
+ pclksel0 &= ~PCLK_ACF_MASK;
+ pclksel0 |= __val2mfld(PCLK_CAN1_MASK, val);
+ pclksel0 |= __val2mfld(PCLK_CAN2_MASK, val);
+ pclksel0 |= __val2mfld(PCLK_ACF_MASK, val);
+ PCLKSEL0 = pclksel0;
+
+ // enter reset mode
+ CAN1MOD = 1;
+
+ // disable all CAN interrupts
+ CAN1IER = 0;
+
+ // reset value of Global Status Register (global controller status and error counters)
+ CAN1GSR = 0x3C;
+
+ // request command to release Rx, Tx buffer and clear data overrun
+ CAN1CMR = (1<<1)|(1<<2)|(1<<3);
+
+ // read to clear interrupt pending in Interrupt Capture Register
+ tmp = CAN1ICR;
+
+ // set bus timing
+ CAN_setBusTiming(baudrate);
+
+ // return to normal operating
+ CAN1MOD = 0;
+
+
+}
+