source: rtems/c/src/lib/libbsp/powerpc/gen5200/mscan/mscan-base.c @ 0e27119

4.11
Last change on this file since 0e27119 was 0e27119, checked in by Joel Sherrill <joel.sherrill@…>, on Oct 11, 2012 at 8:52:18 PM

Use proper 3 line form of license text

  • Property mode set to 100644
File size: 13.1 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup m
5 *
6 * @brief MSCAN support functions code.
7 */
8
9/*
10 * Copyright (c) 2008
11 * Embedded Brains GmbH
12 * Obere Lagerstr. 30
13 * D-82178 Puchheim
14 * Germany
15 * rtems@embedded-brains.de
16 *
17 * The license and distribution terms for this file may be
18 * found in the file LICENSE in this distribution or at
19 * http://www.rtems.com/license/LICENSE.
20 */
21
22#include <bsp.h>
23#include <bsp/mscan-base.h>
24
25#define MIN_NO_OF_TQ         7
26#define TSEG_1               1
27#define TSEG_2               2
28#define NO_OF_TABLE_ENTRIES  4
29#define SJW                  3
30
31#define CAN_MAX_NO_OF_TQ         25
32#define CAN_MAX_NO_OF_TQ_TSEG1   15
33#define CAN_MAX_NO_OF_TQ_TSEG2   7
34#define CAN_MAX_NO_OF_TQ_SJW     2
35
36/**
37 * Time segmant table.
38 *
39 * <table>
40 *   <tr>
41 *     <td>Number of time quantas</th>
42 *     <td>Time Segment 1</th>
43 *     <td>Time Segment 2</th>
44 *     <td>Sync: Jump width</th>
45 *   </tr>
46 * </table>
47 */
48static uint8_t can_time_segment_table
49  [CAN_MAX_NO_OF_TQ - MIN_NO_OF_TQ + 1] [NO_OF_TABLE_ENTRIES] = {
50  {7, 4, 2, 1},
51  {8, 5, 2, 1},
52  {9, 6, 2, 2},
53  {10, 6, 3, 2},
54  {11, 7, 3, 2},
55  {12, 8, 3, 2},
56  {13, 8, 4, 2},
57  {14, 9, 4, 2},
58  {15, 10, 4, 2},
59  {16, 10, 5, 2},
60  {17, 11, 5, 2},
61  {18, 12, 5, 2},
62  {19, 12, 6, 2},
63  {20, 13, 6, 2},
64  {21, 14, 6, 2},
65  {22, 14, 7, 2},
66  {23, 15, 7, 2},
67  {24, 15, 8, 2},
68  {25, 16, 8, 2}
69};
70
71/**
72 * @brief Calculates the MSCAN clock prescaler value.
73 */
74static uint8_t prescaler_calculation(
75  unsigned can_bit_rate,
76  unsigned can_clock_frq,
77  uint8_t *tq_no
78)
79{
80
81/* local variables */
82  uint8_t presc_val,
83    tq_no_dev_min = 0;
84  uint32_t bit_rate,
85    bit_rate_dev,
86    frq_tq,
87    bit_rate_dev_min = 0xFFFFFFFF;
88
89/* loop through all values of time quantas */
90  for (*tq_no = CAN_MAX_NO_OF_TQ; *tq_no >= MIN_NO_OF_TQ; (*tq_no)--) {
91
92    /* calculate time quanta freq. */
93    frq_tq = *tq_no * can_bit_rate;
94
95    /* calculate the optimized prescal. val. */
96    presc_val = (can_clock_frq + frq_tq / 2) / frq_tq;
97
98    /* calculate the bitrate */
99    bit_rate = can_clock_frq / (*tq_no * presc_val);
100
101    /* calculate the bitrate deviation */
102    if (can_bit_rate >= bit_rate) {
103      /* calculate the bitrate deviation */
104      bit_rate_dev = can_bit_rate - bit_rate;
105    } else {
106      /* calculate the bitrate deviation */
107      bit_rate_dev = bit_rate - can_bit_rate;
108    }
109
110    /* check the deviation freq. */
111    if (bit_rate_dev == 0) {
112
113      /* return if best match (zero deviation) */
114      return (uint8_t) (presc_val);
115    } else {
116
117      /* check for minimum of bit rate deviation */
118      if (bit_rate_dev < bit_rate_dev_min) {
119
120        /* recognize the minimum freq. deviation */
121        bit_rate_dev_min = bit_rate_dev;
122
123        /* recognize the no. of time quantas */
124        tq_no_dev_min = *tq_no;
125      }
126    }
127  }
128
129  /* get the no of tq's */
130  *tq_no = tq_no_dev_min;
131
132  /* calculate time quanta freq. */
133  frq_tq = *tq_no * can_bit_rate;
134
135  /* return the optimized prescaler value */
136  return (uint8_t) ((can_clock_frq + frq_tq / 2) / frq_tq);
137}
138
139/**
140 * @brief Sets the bit rate for the MSCAN module @a m to @a can_bit_rate
141 * in [bits/s].
142 */
143bool mscan_set_bit_rate( volatile mscan *m, unsigned can_bit_rate)
144{
145  mscan_context context;
146  unsigned prescale_val = 0;
147  uint8_t tq_no,
148    tseg_1,
149    tseg_2,
150    sseg;
151
152  if (can_bit_rate < MSCAN_BIT_RATE_MIN || can_bit_rate > MSCAN_BIT_RATE_MAX) {
153    return false;
154  }
155
156  /* Enter initialization mode */
157  mscan_initialization_mode_enter( m, &context);
158
159  /* get optimized prescaler value */
160  prescale_val = prescaler_calculation(can_bit_rate, IPB_CLOCK, &tq_no);
161
162  /* Check prescaler value */
163  if (prescale_val > 64) {
164    /* Leave initialization mode */
165    mscan_initialization_mode_leave( m, &context);
166
167    return false;
168  }
169
170  /* get time segment length from time segment table */
171  tseg_1 = can_time_segment_table[tq_no - MIN_NO_OF_TQ][TSEG_1];
172  tseg_2 = can_time_segment_table[tq_no - MIN_NO_OF_TQ][TSEG_2];
173  sseg = can_time_segment_table[tq_no - MIN_NO_OF_TQ][SJW];
174
175  /* Bus Timing Register 0 MSCAN_A/_B ------------------------------ */
176  /*    [07]:SJW1        1 : Synchronization jump width, Bit1       */
177  /*    [06]:SJW0        0 : Synchronization jump width, Bit0       */
178  /*                         SJW = 2 -> 3 Tq clock cycles           */
179  /*    [05]:BRP5        0 : Baud Rate Prescaler, Bit 5             */
180  /*    [04]:BRP4        0 : Baud Rate Prescaler, Bit 4             */
181  /*    [03]:BRP3        0 : Baud Rate Prescaler, Bit 3             */
182  /*    [02]:BRP2        1 : Baud Rate Prescaler, Bit 2             */
183  /*    [01]:BRP1        0 : Baud Rate Prescaler, Bit 1             */
184  /*    [00]:BRP0        1 : Baud Rate Prescaler, Bit 0             */
185  m->btr0 = (BTR0_SJW(sseg - 1) | BTR0_BRP(prescale_val - 1));
186
187  /* Bus Timing Register 1 MSCAN_A/_B ------------------------------ */
188  /*    [07]:SAMP        0 : One Sample per bit                     */
189  /*    [06]:TSEG22      0 : Time Segment 2, Bit 2                  */
190  /*    [05]:TSEG21      1 : Time Segment 2, Bit 1                  */
191  /*    [04]:TSEG20      0 : Time Segment 2, Bit 0                  */
192  /*                         -> PHASE_SEG2 = 3 Tq                   */
193  /*    [03]:TSEG13      0 : Time Segment 1, Bit 3                  */
194  /*    [02]:TSEG12      1 : Time Segment 1, Bit 2                  */
195  /*    [01]:TSEG11      1 : Time Segment 1, Bit 1                  */
196  /*    [00]:TSEG10      0 : Time Segment 1, Bit 0                  */
197  m->btr1 = (BTR1_TSEG2(tseg_2 - 1) | BTR1_TSEG1(tseg_1 - 1));
198
199  /* Leave initialization mode */
200  mscan_initialization_mode_leave( m, &context);
201
202  return true;
203}
204
205/**
206 * @brief Disables all interrupts for the MSCAN module @a m.
207 */
208void mscan_interrupts_disable( volatile mscan *m)
209{
210  m->rier = 0;
211  m->tier = 0;
212}
213
214/**
215 * @brief Enter initialization mode for the MSCAN module @a m.
216 *
217 * Saves the current MSCAN context in @a context.
218 */
219void mscan_initialization_mode_enter( volatile mscan *m, mscan_context *context)
220{
221  /* Save context */
222  context->ctl0 = m->ctl0 & CTL0_TIME;
223  context->rier = m->rier;
224  context->tier = m->tier;
225
226  /* Request initialization mode */
227  m->ctl0 |= CTL0_INITRQ;
228
229  /* Wait for initialization mode acknowledge */
230  while ((m->ctl1 & CTL1_INITAK) == 0) {
231    /* Wait */
232  }
233}
234
235/**
236 * @brief Leave initialization mode for the MSCAN module @a m.
237 *
238 * Saves the previous MSCAN context saved in @a context.
239 */
240void mscan_initialization_mode_leave( volatile mscan *m, const mscan_context *context)
241{
242  /* Clear initialization mode request */
243  m->ctl0 &= ~CTL0_INITRQ;
244
245  /* Wait for clearing of initialization mode acknowledge */
246  while ((m->ctl1 & CTL1_INITAK) != 0) {
247    /* Wait */
248  }
249
250  /* Leave sleep mode */
251  mscan_sleep_mode_leave( m);
252
253  /* Restore context */
254  m->ctl0 |= context->ctl0;
255  m->rier |= context->rier;
256  m->tier |= context->tier;
257}
258
259/**
260 * @brief Enter sleep mode for the MSCAN module @a m.
261 */
262void mscan_sleep_mode_enter( volatile mscan *m)
263{
264  /* Request sleep mode */
265  m->ctl0 |= CTL0_SLPRQ;
266}
267
268/**
269 * @brief Leave sleep mode for the MSCAN module @a m.
270 */
271void mscan_sleep_mode_leave( volatile mscan *m)
272{
273  /* Clear sleep mode request */
274  m->ctl0 &= ~CTL0_SLPRQ;
275
276  /* Wait for clearing of sleep mode acknowledge */
277  while ((m->ctl1 & CTL1_SLPAK) != 0) {
278    /* Wait */
279  }
280}
281
282/**
283 * @brief Enables and initializes the MSCAN module @a m.
284 *
285 * The module is set to listen only mode.
286 */
287bool mscan_enable( volatile mscan *m, unsigned bit_rate)
288{
289  bool s = true;
290
291  /* Disable the module */
292  mscan_disable( m);
293
294  /* Enable module in listen only */
295  m->ctl1 = CTL1_CANE | CTL1_LISTEN;
296
297  /* Close acceptance filters */
298  m->idac = IDAC_IDAM1 | IDAC_IDAM0;
299
300  /* Clear filter */
301  mscan_filter_clear( m);
302
303  /* Set bit rate and leave initialization mode */
304  s = mscan_set_bit_rate( m, bit_rate);
305
306  /* Clear all flags */
307  m->ctl0 = CTL0_RXFRM;
308
309  /* Disable interrupts */
310  mscan_interrupts_disable( m);
311
312  return s;
313}
314
315/**
316 * @brief Disables the MSCAN module @a m.
317 *
318 * The module is set to sleep mode and disabled afterwards.
319 */
320void mscan_disable( volatile mscan *m)
321{
322  mscan_context context;
323
324  /* Disable interrupts */
325  mscan_interrupts_disable( m);
326
327  /* Enter initialization mode */
328  mscan_initialization_mode_enter( m, &context);
329
330  /* Disable module */
331  m->ctl1 &= ~CTL1_CANE;
332}
333
334/**
335 * @brief Sets the filter ID and mask registers of the MSCAN module @a m to
336 * default values.
337 */
338void mscan_filter_clear( volatile mscan *m)
339{
340  mscan_context context;
341
342  mscan_initialization_mode_enter( m, &context);
343
344  /* Setup ID acceptance registers */
345  m->idar0 = MSCAN_FILTER_ID_DEFAULT;
346  m->idar1 = MSCAN_FILTER_ID_DEFAULT;
347  m->idar2 = MSCAN_FILTER_ID_DEFAULT;
348  m->idar3 = MSCAN_FILTER_ID_DEFAULT;
349  m->idar4 = MSCAN_FILTER_ID_DEFAULT;
350  m->idar5 = MSCAN_FILTER_ID_DEFAULT;
351  m->idar6 = MSCAN_FILTER_ID_DEFAULT;
352  m->idar7 = MSCAN_FILTER_ID_DEFAULT;
353
354  /* Setup ID mask registers */
355  m->idmr0 = (uint8_t) MSCAN_FILTER_MASK_DEFAULT;
356  m->idmr1 = (uint8_t) MSCAN_FILTER_MASK_DEFAULT;
357  m->idmr2 = (uint8_t) MSCAN_FILTER_MASK_DEFAULT;
358  m->idmr3 = (uint8_t) MSCAN_FILTER_MASK_DEFAULT;
359  m->idmr4 = (uint8_t) MSCAN_FILTER_MASK_DEFAULT;
360  m->idmr5 = (uint8_t) MSCAN_FILTER_MASK_DEFAULT;
361  m->idmr6 = (uint8_t) MSCAN_FILTER_MASK_DEFAULT;
362  m->idmr7 = (uint8_t) MSCAN_FILTER_MASK_DEFAULT;
363
364  mscan_initialization_mode_leave( m, &context);
365}
366
367/**
368 * @brief Returns the number of active filters of the MSCAN module @a m.
369 *
370 * @see MSCAN_FILTER_NUMBER_MIN, MSCAN_FILTER_NUMBER_2, MSCAN_FILTER_NUMBER_4
371 * and MSCAN_FILTER_NUMBER_MAX.
372 */
373unsigned mscan_filter_number( volatile mscan *m)
374{
375  uint8_t idam = m->idac & IDAC_IDAM;
376
377  switch (idam) {
378    case 0:
379      return MSCAN_FILTER_NUMBER_2;
380    case IDAC_IDAM0:
381      return MSCAN_FILTER_NUMBER_4;
382    case IDAC_IDAM1:
383      return MSCAN_FILTER_NUMBER_MAX;
384    default:
385      return MSCAN_FILTER_NUMBER_MIN;
386  }
387}
388
389/**
390 * @brief Sets the number of active filters of the MSCAN module @a m to @a
391 * number and returns true if @a number is valid.
392 *
393 * @see MSCAN_FILTER_NUMBER_MIN, MSCAN_FILTER_NUMBER_2, MSCAN_FILTER_NUMBER_4
394 * and MSCAN_FILTER_NUMBER_MAX.
395 */
396bool mscan_set_filter_number( volatile mscan *m, unsigned number)
397{
398  mscan_context context;
399  uint8_t idac = IDAC_IDAM1 | IDAC_IDAM0;
400
401  switch (number) {
402    case MSCAN_FILTER_NUMBER_MIN:
403      break;
404    case MSCAN_FILTER_NUMBER_2:
405      idac = 0;
406      break;
407    case MSCAN_FILTER_NUMBER_4:
408      idac = IDAC_IDAM0;
409      break;
410    case MSCAN_FILTER_NUMBER_MAX:
411      idac = IDAC_IDAM1;
412      break;
413    default:
414      return false;
415  }
416
417  mscan_initialization_mode_enter( m, &context);
418
419  m->idac = idac;
420
421  mscan_initialization_mode_leave( m, &context);
422
423  /* Clear filter */
424  mscan_filter_clear( m);
425
426  return true;
427}
428
429/**
430 * @brief Returns the  address of the CANIDAR register with index @a i of the
431 * MSCAN module @a m.
432 *
433 * @warning The index @a i is not checked if it is in range.
434 */
435volatile uint8_t *mscan_id_acceptance_register( volatile mscan *m, unsigned i)
436{
437  volatile uint8_t *const idar [8] = {
438    &m->idar0,
439    &m->idar1,
440    &m->idar2,
441    &m->idar3,
442    &m->idar4,
443    &m->idar5,
444    &m->idar6,
445    &m->idar7
446  };
447
448  return idar [i];
449}
450
451/**
452 * @brief Returns the  address of the CANIDMR register with index @a i of the
453 * MSCAN module @a m.
454 *
455 * @warning The index @a i is not checked if it is in range.
456 */
457volatile uint8_t *mscan_id_mask_register( volatile mscan *m, unsigned i)
458{
459  volatile uint8_t *const idmr [8] = {
460    &m->idmr0,
461    &m->idmr1,
462    &m->idmr2,
463    &m->idmr3,
464    &m->idmr4,
465    &m->idmr5,
466    &m->idmr6,
467    &m->idmr7
468  };
469
470  return idmr [i];
471}
472
473/**
474 * @brief Sets or gets the filter ID and mask in @a id and @a mask depending on
475 * @a set of MSCAN module @a m.  The filter is selected by the value of @a
476 * index.
477 *
478 * Returns true if the operation was successful.
479 */
480bool mscan_filter_operation(
481  volatile mscan *m,
482  bool set,
483  unsigned index,
484  uint32_t *id,
485  uint32_t *mask
486)
487{
488  unsigned number = mscan_filter_number( m);
489  unsigned offset = MSCAN_FILTER_NUMBER_MAX / number;
490  unsigned shift = 24;
491
492  volatile uint8_t *idar = NULL;
493  volatile uint8_t *idmr = NULL;
494
495  if (!set) {
496    *id = MSCAN_FILTER_ID_DEFAULT;
497    *mask = MSCAN_FILTER_MASK_DEFAULT;
498  }
499
500  if (index < number) {
501    mscan_context context;
502
503    mscan_initialization_mode_enter( m, &context);
504
505    index *= offset;
506    offset += index;
507    while (index < offset) {
508      idar = mscan_id_acceptance_register( m, index);
509      idmr = mscan_id_mask_register( m, index);
510
511      if (set) {
512        *idar = (uint8_t) (*id >> shift);
513        *idmr = (uint8_t) (*mask >> shift);
514      } else {
515        *id = (*id & ~(0xffU << shift)) | (*idar << shift);
516        *mask = (*mask & ~(0xffU << shift)) | (*idmr << shift);
517      }
518
519      shift -= 8;
520
521      ++index;
522    }
523
524    mscan_initialization_mode_leave( m, &context);
525  } else {
526    return false;
527  }
528
529  return true;
530}
531
532/**
533 * @brief Returns the receiver and transmitter error counter values in @a rec
534 * and @a tec of MSCAN module @a m.
535 */
536void mscan_get_error_counters( volatile mscan *m, unsigned *rec, unsigned *tec)
537{
538  mscan_context context;
539
540  mscan_initialization_mode_enter( m, &context);
541
542  *rec = m->rxerr;
543  *tec = m->txerr;
544
545  mscan_initialization_mode_leave( m, &context);
546}
Note: See TracBrowser for help on using the repository browser.