Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:52

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup m
0007  *
0008  * @brief MSCAN support functions code.
0009  */
0010 
0011 /*
0012  * Copyright (c) 2008 embedded brains GmbH & Co. KG
0013  * Redistribution and use in source and binary forms, with or without
0014  * modification, are permitted provided that the following conditions
0015  * are met:
0016  * 1. Redistributions of source code must retain the above copyright
0017  *    notice, this list of conditions and the following disclaimer.
0018  * 2. Redistributions in binary form must reproduce the above copyright
0019  *    notice, this list of conditions and the following disclaimer in the
0020  *    documentation and/or other materials provided with the distribution.
0021  *
0022  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0023  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0025  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0026  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0027  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0028  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0029  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0030  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0031  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0032  * POSSIBILITY OF SUCH DAMAGE.
0033  */
0034 
0035 #include <bsp.h>
0036 #include <bsp/mscan-base.h>
0037 
0038 #define MIN_NO_OF_TQ         7
0039 #define TSEG_1               1
0040 #define TSEG_2               2
0041 #define NO_OF_TABLE_ENTRIES  4
0042 #define SJW                  3
0043 
0044 #define CAN_MAX_NO_OF_TQ         25
0045 #define CAN_MAX_NO_OF_TQ_TSEG1   15
0046 #define CAN_MAX_NO_OF_TQ_TSEG2   7
0047 #define CAN_MAX_NO_OF_TQ_SJW     2
0048 
0049 /**
0050  * Time segmant table.
0051  *
0052  * <table>
0053  *   <tr>
0054  *     <td>Number of time quantas</th>
0055  *     <td>Time Segment 1</th>
0056  *     <td>Time Segment 2</th>
0057  *     <td>Sync: Jump width</th>
0058  *   </tr>
0059  * </table>
0060  */
0061 static uint8_t can_time_segment_table
0062   [CAN_MAX_NO_OF_TQ - MIN_NO_OF_TQ + 1] [NO_OF_TABLE_ENTRIES] = {
0063   {7, 4, 2, 1},
0064   {8, 5, 2, 1},
0065   {9, 6, 2, 2},
0066   {10, 6, 3, 2},
0067   {11, 7, 3, 2},
0068   {12, 8, 3, 2},
0069   {13, 8, 4, 2},
0070   {14, 9, 4, 2},
0071   {15, 10, 4, 2},
0072   {16, 10, 5, 2},
0073   {17, 11, 5, 2},
0074   {18, 12, 5, 2},
0075   {19, 12, 6, 2},
0076   {20, 13, 6, 2},
0077   {21, 14, 6, 2},
0078   {22, 14, 7, 2},
0079   {23, 15, 7, 2},
0080   {24, 15, 8, 2},
0081   {25, 16, 8, 2}
0082 };
0083 
0084 /**
0085  * @brief Calculates the MSCAN clock prescaler value.
0086  */
0087 static uint8_t prescaler_calculation(
0088   unsigned can_bit_rate,
0089   unsigned can_clock_frq,
0090   uint8_t *tq_no
0091 )
0092 {
0093 
0094 /* local variables */
0095   uint8_t presc_val,
0096     tq_no_dev_min = 0;
0097   uint32_t bit_rate,
0098     bit_rate_dev,
0099     frq_tq,
0100     bit_rate_dev_min = 0xFFFFFFFF;
0101 
0102 /* loop through all values of time quantas */
0103   for (*tq_no = CAN_MAX_NO_OF_TQ; *tq_no >= MIN_NO_OF_TQ; (*tq_no)--) {
0104 
0105     /* calculate time quanta freq. */
0106     frq_tq = *tq_no * can_bit_rate;
0107 
0108     /* calculate the optimized prescal. val. */
0109     presc_val = (can_clock_frq + frq_tq / 2) / frq_tq;
0110 
0111     /* calculate the bitrate */
0112     bit_rate = can_clock_frq / (*tq_no * presc_val);
0113 
0114     /* calculate the bitrate deviation */
0115     if (can_bit_rate >= bit_rate) {
0116       /* calculate the bitrate deviation */
0117       bit_rate_dev = can_bit_rate - bit_rate;
0118     } else {
0119       /* calculate the bitrate deviation */
0120       bit_rate_dev = bit_rate - can_bit_rate;
0121     }
0122 
0123     /* check the deviation freq. */
0124     if (bit_rate_dev == 0) {
0125 
0126       /* return if best match (zero deviation) */
0127       return (uint8_t) (presc_val);
0128     } else {
0129 
0130       /* check for minimum of bit rate deviation */
0131       if (bit_rate_dev < bit_rate_dev_min) {
0132 
0133         /* recognize the minimum freq. deviation */
0134         bit_rate_dev_min = bit_rate_dev;
0135 
0136         /* recognize the no. of time quantas */
0137         tq_no_dev_min = *tq_no;
0138       }
0139     }
0140   }
0141 
0142   /* get the no of tq's */
0143   *tq_no = tq_no_dev_min;
0144 
0145   /* calculate time quanta freq. */
0146   frq_tq = *tq_no * can_bit_rate;
0147 
0148   /* return the optimized prescaler value */
0149   return (uint8_t) ((can_clock_frq + frq_tq / 2) / frq_tq);
0150 }
0151 
0152 /**
0153  * @brief Sets the bit rate for the MSCAN module @a m to @a can_bit_rate
0154  * in [bits/s].
0155  */
0156 bool mscan_set_bit_rate( volatile mscan *m, unsigned can_bit_rate)
0157 {
0158   mscan_context context;
0159   unsigned prescale_val = 0;
0160   uint8_t tq_no,
0161     tseg_1,
0162     tseg_2,
0163     sseg;
0164 
0165   if (can_bit_rate < MSCAN_BIT_RATE_MIN || can_bit_rate > MSCAN_BIT_RATE_MAX) {
0166     return false;
0167   }
0168 
0169   /* Enter initialization mode */
0170   mscan_initialization_mode_enter( m, &context);
0171 
0172   /* get optimized prescaler value */
0173   prescale_val = prescaler_calculation(can_bit_rate, IPB_CLOCK, &tq_no);
0174 
0175   /* Check prescaler value */
0176   if (prescale_val > 64) {
0177     /* Leave initialization mode */
0178     mscan_initialization_mode_leave( m, &context);
0179 
0180     return false;
0181   }
0182 
0183   /* get time segment length from time segment table */
0184   tseg_1 = can_time_segment_table[tq_no - MIN_NO_OF_TQ][TSEG_1];
0185   tseg_2 = can_time_segment_table[tq_no - MIN_NO_OF_TQ][TSEG_2];
0186   sseg = can_time_segment_table[tq_no - MIN_NO_OF_TQ][SJW];
0187 
0188   /* Bus Timing Register 0 MSCAN_A/_B ------------------------------ */
0189   /*    [07]:SJW1        1 : Synchronization jump width, Bit1       */
0190   /*    [06]:SJW0        0 : Synchronization jump width, Bit0       */
0191   /*                         SJW = 2 -> 3 Tq clock cycles           */
0192   /*    [05]:BRP5        0 : Baud Rate Prescaler, Bit 5             */
0193   /*    [04]:BRP4        0 : Baud Rate Prescaler, Bit 4             */
0194   /*    [03]:BRP3        0 : Baud Rate Prescaler, Bit 3             */
0195   /*    [02]:BRP2        1 : Baud Rate Prescaler, Bit 2             */
0196   /*    [01]:BRP1        0 : Baud Rate Prescaler, Bit 1             */
0197   /*    [00]:BRP0        1 : Baud Rate Prescaler, Bit 0             */
0198   m->btr0 = (BTR0_SJW(sseg - 1) | BTR0_BRP(prescale_val - 1));
0199 
0200   /* Bus Timing Register 1 MSCAN_A/_B ------------------------------ */
0201   /*    [07]:SAMP        0 : One Sample per bit                     */
0202   /*    [06]:TSEG22      0 : Time Segment 2, Bit 2                  */
0203   /*    [05]:TSEG21      1 : Time Segment 2, Bit 1                  */
0204   /*    [04]:TSEG20      0 : Time Segment 2, Bit 0                  */
0205   /*                         -> PHASE_SEG2 = 3 Tq                   */
0206   /*    [03]:TSEG13      0 : Time Segment 1, Bit 3                  */
0207   /*    [02]:TSEG12      1 : Time Segment 1, Bit 2                  */
0208   /*    [01]:TSEG11      1 : Time Segment 1, Bit 1                  */
0209   /*    [00]:TSEG10      0 : Time Segment 1, Bit 0                  */
0210   m->btr1 = (BTR1_TSEG2(tseg_2 - 1) | BTR1_TSEG1(tseg_1 - 1));
0211 
0212   /* Leave initialization mode */
0213   mscan_initialization_mode_leave( m, &context);
0214 
0215   return true;
0216 }
0217 
0218 /**
0219  * @brief Disables all interrupts for the MSCAN module @a m.
0220  */
0221 void mscan_interrupts_disable( volatile mscan *m)
0222 {
0223   m->rier = 0;
0224   m->tier = 0;
0225 }
0226 
0227 /**
0228  * @brief Enter initialization mode for the MSCAN module @a m.
0229  *
0230  * Saves the current MSCAN context in @a context.
0231  */
0232 void mscan_initialization_mode_enter( volatile mscan *m, mscan_context *context)
0233 {
0234   /* Save context */
0235   context->ctl0 = m->ctl0 & CTL0_TIME;
0236   context->rier = m->rier;
0237   context->tier = m->tier;
0238 
0239   /* Request initialization mode */
0240   m->ctl0 |= CTL0_INITRQ;
0241 
0242   /* Wait for initialization mode acknowledge */
0243   while ((m->ctl1 & CTL1_INITAK) == 0) {
0244     /* Wait */
0245   }
0246 }
0247 
0248 /**
0249  * @brief Leave initialization mode for the MSCAN module @a m.
0250  *
0251  * Saves the previous MSCAN context saved in @a context.
0252  */
0253 void mscan_initialization_mode_leave( volatile mscan *m, const mscan_context *context)
0254 {
0255   /* Clear initialization mode request */
0256   m->ctl0 &= ~CTL0_INITRQ;
0257 
0258   /* Wait for clearing of initialization mode acknowledge */
0259   while ((m->ctl1 & CTL1_INITAK) != 0) {
0260     /* Wait */
0261   }
0262 
0263   /* Leave sleep mode */
0264   mscan_sleep_mode_leave( m);
0265 
0266   /* Restore context */
0267   m->ctl0 |= context->ctl0;
0268   m->rier |= context->rier;
0269   m->tier |= context->tier;
0270 }
0271 
0272 /**
0273  * @brief Enter sleep mode for the MSCAN module @a m.
0274  */
0275 void mscan_sleep_mode_enter( volatile mscan *m)
0276 {
0277   /* Request sleep mode */
0278   m->ctl0 |= CTL0_SLPRQ;
0279 }
0280 
0281 /**
0282  * @brief Leave sleep mode for the MSCAN module @a m.
0283  */
0284 void mscan_sleep_mode_leave( volatile mscan *m)
0285 {
0286   /* Clear sleep mode request */
0287   m->ctl0 &= ~CTL0_SLPRQ;
0288 
0289   /* Wait for clearing of sleep mode acknowledge */
0290   while ((m->ctl1 & CTL1_SLPAK) != 0) {
0291     /* Wait */
0292   }
0293 }
0294 
0295 /**
0296  * @brief Enables and initializes the MSCAN module @a m.
0297  *
0298  * The module is set to listen only mode.
0299  */
0300 bool mscan_enable( volatile mscan *m, unsigned bit_rate)
0301 {
0302   bool s = true;
0303 
0304   /* Disable the module */
0305   mscan_disable( m);
0306 
0307   /* Enable module in listen only */
0308   m->ctl1 = CTL1_CANE | CTL1_LISTEN;
0309 
0310   /* Close acceptance filters */
0311   m->idac = IDAC_IDAM1 | IDAC_IDAM0;
0312 
0313   /* Clear filter */
0314   mscan_filter_clear( m);
0315 
0316   /* Set bit rate and leave initialization mode */
0317   s = mscan_set_bit_rate( m, bit_rate);
0318 
0319   /* Clear all flags */
0320   m->ctl0 = CTL0_RXFRM;
0321 
0322   /* Disable interrupts */
0323   mscan_interrupts_disable( m);
0324 
0325   return s;
0326 }
0327 
0328 /**
0329  * @brief Disables the MSCAN module @a m.
0330  *
0331  * The module is set to sleep mode and disabled afterwards.
0332  */
0333 void mscan_disable( volatile mscan *m)
0334 {
0335   mscan_context context;
0336 
0337   /* Disable interrupts */
0338   mscan_interrupts_disable( m);
0339 
0340   /* Enter initialization mode */
0341   mscan_initialization_mode_enter( m, &context);
0342 
0343   /* Disable module */
0344   m->ctl1 &= ~CTL1_CANE;
0345 }
0346 
0347 /**
0348  * @brief Sets the filter ID and mask registers of the MSCAN module @a m to
0349  * default values.
0350  */
0351 void mscan_filter_clear( volatile mscan *m)
0352 {
0353   mscan_context context;
0354 
0355   mscan_initialization_mode_enter( m, &context);
0356 
0357   /* Setup ID acceptance registers */
0358   m->idar0 = MSCAN_FILTER_ID_DEFAULT;
0359   m->idar1 = MSCAN_FILTER_ID_DEFAULT;
0360   m->idar2 = MSCAN_FILTER_ID_DEFAULT;
0361   m->idar3 = MSCAN_FILTER_ID_DEFAULT;
0362   m->idar4 = MSCAN_FILTER_ID_DEFAULT;
0363   m->idar5 = MSCAN_FILTER_ID_DEFAULT;
0364   m->idar6 = MSCAN_FILTER_ID_DEFAULT;
0365   m->idar7 = MSCAN_FILTER_ID_DEFAULT;
0366 
0367   /* Setup ID mask registers */
0368   m->idmr0 = (uint8_t) MSCAN_FILTER_MASK_DEFAULT;
0369   m->idmr1 = (uint8_t) MSCAN_FILTER_MASK_DEFAULT;
0370   m->idmr2 = (uint8_t) MSCAN_FILTER_MASK_DEFAULT;
0371   m->idmr3 = (uint8_t) MSCAN_FILTER_MASK_DEFAULT;
0372   m->idmr4 = (uint8_t) MSCAN_FILTER_MASK_DEFAULT;
0373   m->idmr5 = (uint8_t) MSCAN_FILTER_MASK_DEFAULT;
0374   m->idmr6 = (uint8_t) MSCAN_FILTER_MASK_DEFAULT;
0375   m->idmr7 = (uint8_t) MSCAN_FILTER_MASK_DEFAULT;
0376 
0377   mscan_initialization_mode_leave( m, &context);
0378 }
0379 
0380 /**
0381  * @brief Returns the number of active filters of the MSCAN module @a m.
0382  *
0383  * @see MSCAN_FILTER_NUMBER_MIN, MSCAN_FILTER_NUMBER_2, MSCAN_FILTER_NUMBER_4
0384  * and MSCAN_FILTER_NUMBER_MAX.
0385  */
0386 unsigned mscan_filter_number( volatile mscan *m)
0387 {
0388   uint8_t idam = m->idac & IDAC_IDAM;
0389 
0390   switch (idam) {
0391     case 0:
0392       return MSCAN_FILTER_NUMBER_2;
0393     case IDAC_IDAM0:
0394       return MSCAN_FILTER_NUMBER_4;
0395     case IDAC_IDAM1:
0396       return MSCAN_FILTER_NUMBER_MAX;
0397     default:
0398       return MSCAN_FILTER_NUMBER_MIN;
0399   }
0400 }
0401 
0402 /**
0403  * @brief Sets the number of active filters of the MSCAN module @a m to @a
0404  * number and returns true if @a number is valid.
0405  *
0406  * @see MSCAN_FILTER_NUMBER_MIN, MSCAN_FILTER_NUMBER_2, MSCAN_FILTER_NUMBER_4
0407  * and MSCAN_FILTER_NUMBER_MAX.
0408  */
0409 bool mscan_set_filter_number( volatile mscan *m, unsigned number)
0410 {
0411   mscan_context context;
0412   uint8_t idac = IDAC_IDAM1 | IDAC_IDAM0;
0413 
0414   switch (number) {
0415     case MSCAN_FILTER_NUMBER_MIN:
0416       break;
0417     case MSCAN_FILTER_NUMBER_2:
0418       idac = 0;
0419       break;
0420     case MSCAN_FILTER_NUMBER_4:
0421       idac = IDAC_IDAM0;
0422       break;
0423     case MSCAN_FILTER_NUMBER_MAX:
0424       idac = IDAC_IDAM1;
0425       break;
0426     default:
0427       return false;
0428   }
0429 
0430   mscan_initialization_mode_enter( m, &context);
0431 
0432   m->idac = idac;
0433 
0434   mscan_initialization_mode_leave( m, &context);
0435 
0436   /* Clear filter */
0437   mscan_filter_clear( m);
0438 
0439   return true;
0440 }
0441 
0442 /**
0443  * @brief Returns the  address of the CANIDAR register with index @a i of the
0444  * MSCAN module @a m.
0445  *
0446  * @warning The index @a i is not checked if it is in range.
0447  */
0448 volatile uint8_t *mscan_id_acceptance_register( volatile mscan *m, unsigned i)
0449 {
0450   volatile uint8_t *const idar [8] = {
0451     &m->idar0,
0452     &m->idar1,
0453     &m->idar2,
0454     &m->idar3,
0455     &m->idar4,
0456     &m->idar5,
0457     &m->idar6,
0458     &m->idar7
0459   };
0460 
0461   return idar [i];
0462 }
0463 
0464 /**
0465  * @brief Returns the  address of the CANIDMR register with index @a i of the
0466  * MSCAN module @a m.
0467  *
0468  * @warning The index @a i is not checked if it is in range.
0469  */
0470 volatile uint8_t *mscan_id_mask_register( volatile mscan *m, unsigned i)
0471 {
0472   volatile uint8_t *const idmr [8] = {
0473     &m->idmr0,
0474     &m->idmr1,
0475     &m->idmr2,
0476     &m->idmr3,
0477     &m->idmr4,
0478     &m->idmr5,
0479     &m->idmr6,
0480     &m->idmr7
0481   };
0482 
0483   return idmr [i];
0484 }
0485 
0486 /**
0487  * @brief Sets or gets the filter ID and mask in @a id and @a mask depending on
0488  * @a set of MSCAN module @a m.  The filter is selected by the value of @a
0489  * index.
0490  *
0491  * Returns true if the operation was successful.
0492  */
0493 bool mscan_filter_operation(
0494   volatile mscan *m,
0495   bool set,
0496   unsigned index,
0497   uint32_t *id,
0498   uint32_t *mask
0499 )
0500 {
0501   unsigned number = mscan_filter_number( m);
0502   unsigned offset = MSCAN_FILTER_NUMBER_MAX / number;
0503   unsigned shift = 24;
0504 
0505   volatile uint8_t *idar = NULL;
0506   volatile uint8_t *idmr = NULL;
0507 
0508   if (!set) {
0509     *id = MSCAN_FILTER_ID_DEFAULT;
0510     *mask = MSCAN_FILTER_MASK_DEFAULT;
0511   }
0512 
0513   if (index < number) {
0514     mscan_context context;
0515 
0516     mscan_initialization_mode_enter( m, &context);
0517 
0518     index *= offset;
0519     offset += index;
0520     while (index < offset) {
0521       idar = mscan_id_acceptance_register( m, index);
0522       idmr = mscan_id_mask_register( m, index);
0523 
0524       if (set) {
0525         *idar = (uint8_t) (*id >> shift);
0526         *idmr = (uint8_t) (*mask >> shift);
0527       } else {
0528         *id = (*id & ~(0xffU << shift)) | (*idar << shift);
0529         *mask = (*mask & ~(0xffU << shift)) | (*idmr << shift);
0530       }
0531 
0532       shift -= 8;
0533 
0534       ++index;
0535     }
0536 
0537     mscan_initialization_mode_leave( m, &context);
0538   } else {
0539     return false;
0540   }
0541 
0542   return true;
0543 }
0544 
0545 /**
0546  * @brief Returns the receiver and transmitter error counter values in @a rec
0547  * and @a tec of MSCAN module @a m.
0548  */
0549 void mscan_get_error_counters( volatile mscan *m, unsigned *rec, unsigned *tec)
0550 {
0551   mscan_context context;
0552 
0553   mscan_initialization_mode_enter( m, &context);
0554 
0555   *rec = m->rxerr;
0556   *tec = m->txerr;
0557 
0558   mscan_initialization_mode_leave( m, &context);
0559 }