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

4.104.115
Last change on this file since efdfd48 was efdfd48, checked in by Ralf Corsepius <ralf.corsepius@…>, on 11/29/09 at 15:27:07

Whitespace removal.

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