can_term_driver.c 5.96 KB
Newer Older
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
1 2 3 4 5 6 7 8 9
/**
 *  @file
 *  @brief Interface for LPC11C24's on-board CCAN driver in ROM.
 *
 *
 *  @author Petr Elexa
 *  @see LICENSE
 *
 */
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
10

Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
11 12
#include "can/can_term_driver.h"
#include <string.h>
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
13 14 15 16 17 18

#if defined (  __GNUC__  )
#include "cr_section_macros.h"
__BSS(RESERVED) char CAN_driver_memory[184];  /* reserve 184 bytes for CAN driver */
#endif

19
// Time quanta (Bit-rate prescaler)
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
20
#define CCAN_BCR_QUANTA(x) ((x) & 0x3F)
21
// Synchronization jump width
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
22
#define CCAN_BCR_SJW(x) (((x) & 0x3) << 6)
23
// Time segment 1
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
24
#define CCAN_BCR_TSEG1(x) (((x) & 0x0F) << 8)
25
// Time segment 2
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
26 27
#define CCAN_BCR_TSEG2(x) (((x) & 0x07) << 12)

28 29 30 31 32 33 34 35 36 37 38 39 40 41
#define CAN_CALC_SYNC_SEG 1


// Sample point = 100 * (tseg1 + CAN_CALC_SYNC_SEG) / (tseg1 + tseg2 + CAN_CALC_SYNC_SEG)

// HW constants
#define	TSEG1_MIN 1
#define	TSEG1_MAX 13
#define TSEG2_MIN 1
#define TSEG2_MAX 8
#define SJW_MAX   4
#define BRP_MIN   1
#define BRP_MAX   32

Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
42

Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
43 44 45 46
/*****************************************************************************
 * Private functions
 ****************************************************************************/

47 48 49 50 51 52 53
/*
 * Integrated CCAN hardware timing calculation from LPC11Cxx CCAN on-chip driver example.
 * Satisfies chapter 8 "BIT TIMING REQUIREMENTS" of the "Bosch CAN Specification version 2.0"
 * at http://www.semiconductors.bosch.de/pdf/can2spec.pdf.
 *
 * Hard coded sample point 50%
 */
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
static void _timing_calculate(uint32_t baud_rate, uint32_t * can_api_timing_cfg)
{
  uint32_t pClk, div, quanta, segs, seg1, seg2, clk_per_bit, can_sjw;
  pClk = Chip_Clock_GetMainClockRate();

  clk_per_bit = pClk / baud_rate;

  for (div = 0; div <= 15; div++)
  {
    for (quanta = 1; quanta <= 32; quanta++)
    {
      for (segs = 3; segs <= 17; segs++)
      {
        if (clk_per_bit == (segs * quanta * (div + 1)))
        {
          segs -= 3;
          seg1 = segs / 2;
          seg2 = segs - seg1;
          can_sjw = seg1 > 3 ? 3 : seg1;
          can_api_timing_cfg[0] = div;
          can_api_timing_cfg[1] =
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
75
            CCAN_BCR_QUANTA(quanta - 1) | CCAN_BCR_SJW(can_sjw) | CCAN_BCR_TSEG1(seg1) | CCAN_BCR_TSEG2(seg2);
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
76 77 78 79 80 81 82
          return;
        }
      }
    }
  }
}

83 84 85 86 87 88 89 90
/*
 * Integrated CCAN hardware timing calculation from LPC11Cxx CCAN on-chip driver example.
 * Satisfies chapter 8 "BIT TIMING REQUIREMENTS" of the "Bosch CAN Specification version 2.0"
 * at http://www.semiconductors.bosch.de/pdf/can2spec.pdf.
 *
 * Uses CiA recommended sample points.
 */
static void _timing_calculate_sp(uint32_t baud_rate, uint32_t * can_api_timing_cfg)
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
91
{
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
  uint32_t pClk, div, quanta, segs, seg1, seg2, clk_per_bit, can_sjw;
  pClk = Chip_Clock_GetMainClockRate();

  uint8_t spt_nominal;

  if (baud_rate > 800000)
  {
	spt_nominal = 75;
  }
  else if (baud_rate > 500000)
  {
	spt_nominal = 80;
  }
  else
  {
	spt_nominal = 87;
  }

  clk_per_bit = pClk / baud_rate;

  for (div = 0; div <= 15; div++)
  {
    for (quanta = 1; quanta <= 32; quanta++)
    {
      for (segs = 3; segs <= 17; segs++)
      {
        if (clk_per_bit == (segs * quanta * (div + 1)))
        {
          segs -= 3;

          // Sample point
          seg2 = segs - (spt_nominal * segs) / 100;
          seg2 = seg2 > TSEG2_MIN ? (seg2 < TSEG2_MAX ? seg2 : TSEG2_MAX) : TSEG2_MIN; // Clamp the value
          seg1 = segs - seg2;

          can_sjw = seg1 > 3 ? 3 : seg1;

          can_api_timing_cfg[0] = div;
          can_api_timing_cfg[1] =
            CCAN_BCR_QUANTA(quanta - 1) | CCAN_BCR_SJW(can_sjw) | CCAN_BCR_TSEG1(seg1) | CCAN_BCR_TSEG2(seg2);
          return;
        }
      }
    }
  }
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
137 138
}

Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
139
static inline void _125_kbaud_75sp(uint32_t * can_api_timing_cfg)
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
140
{
141
  /* 125kb 75%, CAN_CLK tolerance 5% */
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
142
  /* Propagation time for UTP copper cable (0.64c) with maximum distance of 100 meter is 0.55us */
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
143
  /* CANCLKDIV: CAN_CLK=48MHz */
144
  /* CANBT register: TSEG1=11, TSEG2=4, SJW=4, BRP=4 (actual value written is -1) */
145 146
  can_api_timing_cfg[0] = 5;
  can_api_timing_cfg[1] = CCAN_BCR_QUANTA(3) | CCAN_BCR_SJW(3) | CCAN_BCR_TSEG1(10) | CCAN_BCR_TSEG2(3);
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
147 148
}

Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
149 150 151 152
/*****************************************************************************
 * Public functions
 ****************************************************************************/

153
void CAN_init(CCAN_CALLBACKS_T * ptr_callbacks, uint32_t baud_rate)
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
154 155 156 157 158 159 160 161
{
  // Power up CAN
  Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_CAN);

  // Deassert reset
  Chip_SYSCTL_DeassertPeriphReset(RESET_CAN0);

  /* Initialize CAN Controller structure*/
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
162
  uint32_t ClkInitTable[2];
163
  _timing_calculate(baud_rate, &ClkInitTable[0]);
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
164

Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
165 166
  /* Initialize the CAN controller */
  LPC_CCAN_API->init_can(&ClkInitTable[0], TRUE);
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
167

Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
168
  /* Configure the CAN callback functions */
169
  LPC_CCAN_API->config_calb(ptr_callbacks);
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
170

Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
171 172 173
  /* Enable the CAN Interrupt */
  NVIC_EnableIRQ(CAN_IRQn);
}
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
174

175
void CAN_recv_filter(uint8_t msgobj_num, uint32_t id, uint32_t mask, bool extended)
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
176
{
177
  CCAN_MSG_OBJ_T msg_obj = {0, };
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
178

179 180 181 182 183 184
  if (extended == true)
  {
    id |= CAN_MSGOBJ_EXT;
    mask |= CAN_MSGOBJ_EXT;
  }

185 186 187 188 189 190
  msg_obj.msgobj = msgobj_num;
  msg_obj.mode_id = id;
  msg_obj.mask = mask;
  LPC_CCAN_API->config_rxmsgobj(&msg_obj);
}

191
void CAN_recv_filter_all_ext(uint8_t msgobj_num)
192 193 194 195
{
  CCAN_MSG_OBJ_T msg_obj = {0, };

  msg_obj.msgobj = msgobj_num;
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
196
  msg_obj.mode_id = CAN_MSGOBJ_EXT;
197
  msg_obj.mask = CAN_MSGOBJ_EXT;
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
198
  LPC_CCAN_API->config_rxmsgobj(&msg_obj);
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
199
}
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
200

201
void CAN_send_once(uint8_t msgobj_num, uint32_t id, uint8_t * data, uint8_t size)
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
202 203 204 205 206
{
  if (size > CAN_DLC_MAX) size = CAN_DLC_MAX;

  CCAN_MSG_OBJ_T msg_obj;

207
  msg_obj.msgobj  = msgobj_num;
208
  msg_obj.mode_id = id;
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
209 210
  msg_obj.mask    = 0x0;
  msg_obj.dlc     = size;
211 212

  memcpy(msg_obj.data, data, size);
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
213 214 215 216 217 218 219

  LPC_CCAN_API->can_transmit(&msg_obj);
}

void CAN_send_test(void)
{
  CCAN_MSG_OBJ_T msg_obj;
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
220
  /* Send a simple one time CAN message */
221 222
  msg_obj.msgobj  = CCAN_MSG_OBJ_LAST;
  msg_obj.mode_id = CAN_MSGOBJ_EXT | 0x123456;
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
223 224
  msg_obj.mask    = 0x0;
  msg_obj.dlc     = 4;
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
225 226 227 228
  msg_obj.data[0] = 0;
  msg_obj.data[1] = 1;
  msg_obj.data[2] = 2;
  msg_obj.data[3] = 3;
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
229
  LPC_CCAN_API->can_transmit(&msg_obj);
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
230 231
}

Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
232
void CAN_IRQHandler(void)
Bc. Petr Elexa's avatar
Bc. Petr Elexa committed
233 234 235 236
{
  LPC_CCAN_API->isr();
}