Back to home page

LXR

 
 

    


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

0001 /**
0002  * @file
0003  *
0004  * @ingroup RTEMSBSPsARMLPC176X
0005  *
0006  * @brief CAN controller for the mbed lpc1768 board.
0007  */
0008 
0009 /*
0010  * Copyright (c) 2014 Taller Technologies.
0011  *
0012  * @author  Diaz Marcos (marcos.diaz@tallertechnologies.com)
0013  * @author  Daniel Chicco  (daniel.chicco@tallertechnologies.com)
0014  *
0015  * The license and distribution terms for this file may be
0016  * found in the file LICENSE in this distribution or at
0017  * http://www.rtems.org/license/LICENSE.
0018  */
0019 
0020 #include <rtems/status-checks.h>
0021 #include <bsp/irq.h>
0022 #include <bsp/can.h>
0023 #include <bsp/can-defs.h>
0024 #include <bsp/mbed-pinmap.h>
0025 #include <string.h>
0026 
0027 /**
0028  * @brief The standard isr to be installed for all the can devices.
0029  *
0030  * @param arg unused.
0031  */
0032 static void can_isr( void *arg );
0033 
0034 /**
0035  * @brief Vector of isr for the can_driver .
0036  */
0037 lpc176x_can_isr_vector isr_vector;
0038 
0039 /**
0040  * @brief Represents all the can devices, and useful things for initialization.
0041  */
0042 static const can_driver_entry can_driver_table[ CAN_DEVICES_NUMBER ] =
0043 {
0044   {
0045     .device = (can_device *) CAN1_BASE_ADDR,
0046     .module = LPC176X_MODULE_CAN_0,
0047     .pconp_pin = LPC176X_SCB_PCONP_CAN_1,
0048     .pins = { DIP9, DIP10 },
0049     .pinfunction = LPC176X_PIN_FUNCTION_01
0050   },
0051   {
0052     .device = (can_device *) CAN2_BASE_ADDR,
0053     .module = LPC176X_MODULE_CAN_1,
0054     .pconp_pin = LPC176X_SCB_PCONP_CAN_2,
0055     .pins = { DIP30, DIP29 },
0056     .pinfunction = LPC176X_PIN_FUNCTION_10
0057   }
0058 };
0059 
0060 /**
0061  * @brief The CAN acceptance filter.
0062  */
0063 can_acceptance_filter *const acceptance_filter_device =
0064   (can_acceptance_filter *) CAN_ACCEPT_BASE_ADDR;
0065 
0066 /**
0067  * @brief Sets RX and TX pins for the passed can device number.
0068  *
0069  * @param cannumber CAN controller to be used.
0070  */
0071 static inline void setpins( const lpc176x_can_number cannumber )
0072 {
0073   const can_driver_entry *const can_driver = &can_driver_table[ cannumber ];
0074 
0075   lpc176x_pin_select( can_driver->pins[ CAN_TX_PIN ],
0076     can_driver->pinfunction );
0077   lpc176x_pin_select( can_driver->pins[ CAN_RX_PIN ],
0078     can_driver->pinfunction );
0079 }
0080 
0081 rtems_status_code can_close( const lpc176x_can_number minor )
0082 {
0083   rtems_status_code sc = RTEMS_INVALID_NUMBER;
0084 
0085   if ( CAN_DRIVER_IS_MINOR_VALID( minor ) ) {
0086     sc = RTEMS_SUCCESSFUL;
0087     const can_driver_entry *const can_driver = &can_driver_table[ minor ];
0088     lpc176x_module_disable( can_driver->module );
0089   }
0090 
0091   /*else wrong parameters. return RTEMS_INVALID_NUMBER*/
0092 
0093   return sc;
0094 }
0095 
0096 /**
0097  * @brief Enables CAN device.
0098  *
0099  * @param obj The device to be enabled.
0100  */
0101 static inline void can_enable( const can_driver_entry *const obj )
0102 {
0103   if ( obj->device->MOD & CAN_MOD_RM ) {
0104     obj->device->MOD &= ~( CAN_MOD_RM );
0105   }
0106 }
0107 
0108 /**
0109  * @brief Disables CAN device to set parameters, and returns the previous value
0110  * of the MOD register.
0111  *
0112  * @param obj The device to disable.
0113  * @return The previous status of MOD register.
0114  */
0115 static inline uint32_t can_disable( const can_driver_entry *const obj )
0116 {
0117   const uint32_t sm = obj->device->MOD;
0118 
0119   obj->device->MOD |= CAN_MOD_RM;
0120 
0121   return sm;
0122 }
0123 
0124 /**
0125  * @brief Resets the error count.
0126  *
0127  * @param obj which device reset.
0128  */
0129 static inline void can_reset( const can_driver_entry *const obj )
0130 {
0131   can_disable( obj );
0132   obj->device->GSR = 0;   /* Reset error counter when CANxMOD is in reset*/
0133 }
0134 
0135 /**
0136  * @brief This table has the sampling points as close to 75% as possible.
0137  * The first value is TSEG1, the second is TSEG2.
0138  */
0139 static const unsigned int timing_pts[ MAX_TSEG1_TSEG2_BITS +
0140                                       1 ][ CAN_NUMBER_OF_TSEG ] = {
0141   { 0x0, 0x0 },      /* 2,  50%*/
0142   { 0x1, 0x0 },      /* 3,  67%*/
0143   { 0x2, 0x0 },      /* 4,  75%*/
0144   { 0x3, 0x0 },      /* 5,  80%*/
0145   { 0x3, 0x1 },      /* 6,  67%*/
0146   { 0x4, 0x1 },      /* 7,  71%*/
0147   { 0x5, 0x1 },      /* 8,  75%*/
0148   { 0x6, 0x1 },      /* 9,  78%*/
0149   { 0x6, 0x2 },      /* 10, 70%*/
0150   { 0x7, 0x2 },      /* 11, 73%*/
0151   { 0x8, 0x2 },      /* 12, 75%*/
0152   { 0x9, 0x2 },      /* 13, 77%*/
0153   { 0x9, 0x3 },      /* 14, 71%*/
0154   { 0xA, 0x3 },      /* 15, 73%*/
0155   { 0xB, 0x3 },      /* 16, 75%*/
0156   { 0xC, 0x3 },      /* 17, 76%*/
0157   { 0xD, 0x3 },      /* 18, 78%*/
0158   { 0xD, 0x4 },      /* 19, 74%*/
0159   { 0xE, 0x4 },      /* 20, 75%*/
0160   { 0xF, 0x4 },      /* 21, 76%*/
0161   { 0xF, 0x5 },      /* 22, 73%*/
0162   { 0xF, 0x6 },      /* 23, 70%*/
0163   { 0xF, 0x7 },      /* 24, 67%*/
0164 };
0165 
0166 /**
0167  * @brief Checks if divisor is a divisor of value.
0168  *
0169  * @param value The number to be divided.
0170  * @param divisor The divisor to check.
0171  *
0172  * @return true if "number" is divided by "divisor"; false otherwise.
0173  */
0174 static inline bool is_divisor(
0175   const uint32_t value,
0176   const uint16_t divisor
0177 )
0178 {
0179   return ( ( value % divisor ) == 0 );
0180 }
0181 
0182 /**
0183  * @brief Gets the size of the two tseg values added according to the given
0184  * bitwidth and brp (The CAN prescaler).
0185  *
0186  * @param bitwidth The total bitwidth of a CAN bit (in pclk clocks).
0187  * @param brp The CAN clock prescaler.
0188  *
0189  * @return The value of tseg1 + tseg2  of the CAN bit. It is useful
0190  *  to serve for index for timing_pts array).
0191  */
0192 static inline uint32_t get_tseg_bit_size(
0193   const uint32_t bitwidth,
0194   const uint16_t brp
0195 )
0196 {
0197   return ( ( bitwidth / ( brp + CAN_BRP_EXTRA_BIT ) ) - CAN_TSEG_EXTRA_BITS );
0198 }
0199 
0200 /**
0201  * @brief Gets the brp and tsegbitsize in order to achieve the desired bitwidth.
0202  * @details The following must be fullfilled:
0203  *(brp + CAN_BRP_EXTRA_BIT) * (tsegbitsize + CAN_TSEG_EXTRA_BITS) == bitwidth
0204  *
0205  * @param bitwidth The bitwidth that we need to achieve.
0206  * @param brp Here it returns the calculated brp value.
0207  * @param tsegbitsize Here it returns the calculated tseg bit size value.
0208  * @return true if brp and tsegbitsize have been calculated.
0209  */
0210 static inline bool get_brp_and_bitsize(
0211   const uint32_t  bitwidth,
0212   uint16_t *const brp,
0213   uint32_t *const tsegbitsize
0214 )
0215 {
0216   bool hit = false;
0217 
0218   while ( ( !hit ) && ( *brp < bitwidth / MIN_NUMBER_OF_CAN_BITS ) ) {
0219     if ( ( is_divisor( bitwidth, *brp + CAN_BRP_EXTRA_BIT ) )
0220          && ( get_tseg_bit_size( bitwidth, *brp ) < MAX_TSEG1_TSEG2_BITS ) ) {
0221       hit = true;
0222       *tsegbitsize = get_tseg_bit_size( bitwidth, *brp );
0223     } else { /*Correct values not found, keep looking*/
0224       ( *brp )++;
0225     }
0226   }
0227 
0228   return hit;
0229 }
0230 
0231 /**
0232  * @brief Constructs the btr register with the passed arguments.
0233  *
0234  * @param tsegbitsize The size tseg bits to set.
0235  * @param psjw The sjw to set.
0236  * @param brp The prescaler value to set.
0237  * @return The constructed btr register.
0238  */
0239 static inline uint32_t get_btr(
0240   const uint32_t      tsegbitsize,
0241   const unsigned char psjw,
0242   const uint32_t      brp
0243 )
0244 {
0245   const uint32_t tseg2_value_masked =
0246     ( ( timing_pts[ tsegbitsize ][ CAN_TSEG2 ] << CAN_BTR_TSEG2_SHIFT ) &
0247       CAN_BTR_TSEG2_MASK );
0248   const uint32_t tseg1_value_masked =
0249     ( ( timing_pts[ tsegbitsize ][ CAN_TSEG1 ] <<
0250         CAN_BTR_TSEG1_SHIFT ) & CAN_BTR_TSEG1_MASK );
0251   const uint32_t psjw_value_masked =
0252     ( ( psjw << CAN_BTR_SJW_SHIFT ) & CAN_BTR_SJW_MASK );
0253   const uint32_t brp_value_masked =
0254     ( ( brp << CAN_BTR_BRP_SHIFT ) & CAN_BTR_BRP_MASK );
0255 
0256   return tseg1_value_masked | tseg2_value_masked |
0257          psjw_value_masked | brp_value_masked;
0258 }
0259 
0260 /**
0261  * @brief Calculates and returns a bit timing register (btr) for the desired
0262  * canclk frequency using the passed psjw, system clock and peripheral clock.
0263  *
0264  * @param systemclk The clock of the system (in Hz).
0265  * @param pclkdiv The peripheral clock divisor for the can device.
0266  * @param canclk The desired frequency for CAN (in Hz).
0267  * @param psjw The desired psjw.
0268  * @return The btr register value if found, WRONG_BTR_VALUE otherwise.
0269  */
0270 static inline unsigned int can_speed(
0271   const unsigned int  systemclk,
0272   const unsigned int  pclkdiv,
0273   const unsigned int  canclk,
0274   const unsigned char psjw
0275 )
0276 {
0277   uint32_t       btr = WRONG_BTR_VALUE;
0278   const uint32_t bitwidth = systemclk / ( pclkdiv * canclk );
0279 
0280   /* This is for the brp (prescaler) to start searching a reachable multiple.*/
0281   uint16_t brp = bitwidth / MAX_NUMBER_OF_CAN_BITS;
0282   uint32_t tsegbitsize;
0283 
0284   if ( get_brp_and_bitsize( bitwidth, &brp, &tsegbitsize ) ) {
0285     btr = get_btr( tsegbitsize, psjw, brp );
0286   }
0287 
0288   return btr;
0289 }
0290 
0291 /**
0292  * @brief Configures the desired CAN device with the desired frequency.
0293  *
0294  * @param obj The can device to configure.
0295  * @param f The desired frequency.
0296  *
0297  * @return RTEMS_SUCCESSFUL if could be set, RTEMS_INVALID_NUMBER otherwise.
0298  */
0299 static rtems_status_code can_frequency(
0300   const can_driver_entry *const obj,
0301   const can_freq            freq
0302 )
0303 {
0304   rtems_status_code sc = RTEMS_INVALID_NUMBER;
0305   const uint32_t    btr = can_speed( LPC176X_CCLK, LPC176X_PCLKDIV, freq, 1 );
0306 
0307   if ( btr != WRONG_BTR_VALUE ) {
0308     sc = RTEMS_SUCCESSFUL;
0309     uint32_t modmask = can_disable( obj );
0310     obj->device->BTR = btr;
0311     obj->device->MOD = modmask;
0312   } /*else couldnt found a good timing for the desired frequency,
0313       return RTEMS_INVALID_NUMBER.*/
0314 
0315   return sc;
0316 }
0317 
0318 /**
0319  * @brief Installs the interrupt handler in rtems.
0320  */
0321 static inline rtems_status_code can_initialize( void )
0322 {
0323   return rtems_interrupt_handler_install(
0324     LPC176X_IRQ_CAN,
0325     "can_interrupt",
0326     RTEMS_INTERRUPT_UNIQUE,
0327     can_isr,
0328     NULL
0329   );
0330 }
0331 
0332 rtems_status_code can_open( const lpc176x_can_number minor, can_freq freq )
0333 {
0334   const can_driver_entry *const can_driver = &can_driver_table[ minor ];
0335   rtems_status_code             sc = RTEMS_INVALID_NUMBER;
0336 
0337   if ( CAN_DRIVER_IS_MINOR_VALID( minor ) ) {
0338     /*Enable CAN and acceptance filter modules.*/
0339     sc =
0340       lpc176x_module_enable( can_driver->module, LPC176X_MODULE_PCLK_DEFAULT );
0341     RTEMS_CHECK_SC( sc, "enable can module" );
0342     sc = lpc176x_module_enable( LPC176X_MODULE_ACCF,
0343       LPC176X_MODULE_PCLK_DEFAULT );
0344     RTEMS_CHECK_SC( sc, "enable acceptance filter" );
0345     /*Set pin functions.*/
0346     setpins( minor );
0347 
0348     can_reset( can_driver );
0349     can_driver->device->IER = CAN_DEFAULT_INTERRUPT_CONFIGURATION;
0350     sc = can_frequency( can_driver, freq );
0351     RTEMS_CHECK_SC( sc, "Configure CAN frequency" );
0352     can_initialize();
0353 
0354     acceptance_filter_device->AFMR = CAN_ACCF_AFMR_ACCBP;     /*Bypass Filter.*/
0355   }
0356 
0357   return sc;
0358 }
0359 
0360 /**
0361  * @brief Calls the installed isrs, according to the active interrupts.
0362  *
0363  * @param vector The read vector of active interrupts.
0364  * @param number The CAN device to look for interruptions.
0365  */
0366 static inline void call_isrs(
0367   const uint32_t           vector,
0368   const lpc176x_can_number number
0369 )
0370 {
0371   can_irq_type i;
0372 
0373   for ( i = IRQ_RX; i < CAN_IRQ_NUMBER; ++i ) {
0374     if ( ( isr_vector[ i ] != NULL ) && ( vector & ( 1 << i ) ) )
0375       isr_vector[ i ]( number );
0376 
0377     /* else this interrupt has not been raised or it hasn't got a handler,
0378        so do nothing.*/
0379   }
0380 }
0381 
0382 /**
0383  * @brief Checks if the passed CAN device is enabled and if it is checks for
0384  * active interrupts and calls its installed isr.
0385  *
0386  * @param number The CAN device to check for interrupts rised.
0387  */
0388 static inline void search_and_call_int( const lpc176x_can_number number )
0389 {
0390   const can_driver_entry *const driver = &can_driver_table[ number ];
0391 
0392   if ( LPC176X_SCB.pconp & driver->pconp_pin ) {
0393     /*We must read the whole register at once because it resets when read.*/
0394     const uint32_t int_vector = driver->device->ICR & CAN_INTERRUPT_TYPE_MASK;
0395     call_isrs( int_vector, number );
0396   }
0397 
0398   /*else the device is shut down so we must do nothing.*/
0399 }
0400 
0401 /**
0402  * @brief The standard isr to be installed for all the CAN devices.
0403  *
0404  * @param arg unused.
0405  */
0406 static void can_isr( void *arg )
0407 {
0408   lpc176x_can_number i;
0409 
0410   for ( i = CAN_0; i < CAN_DEVICES_NUMBER; ++i ) {
0411     search_and_call_int( i );
0412   }
0413 }
0414 
0415 rtems_status_code can_read(
0416   const lpc176x_can_number minor,
0417   can_message             *message
0418 )
0419 {
0420   rtems_status_code             sc = RTEMS_IO_ERROR;
0421   const can_driver_entry *const can_driver = &can_driver_table[ minor ];
0422   can_device *const             dev = can_driver->device;
0423   registers_can_message *const  msg = &( message->registers );
0424 
0425   can_enable( can_driver );
0426 
0427   if ( dev->GSR & CAN_GSR_RBS_MASK ) {
0428     sc = RTEMS_SUCCESSFUL;
0429     *msg = dev->receive;
0430     dev->CMR = CAN_CMR_RRB_MASK;      /* release receive buffer. */
0431   } /* else Message not received.*/
0432 
0433   return sc;
0434 }
0435 
0436 /**
0437  * @brief Array of masks and control bits for the transmit buffers.
0438  * It's used for each transmit buffer in order to see if it's available and to
0439  * send data to them.
0440  */
0441 static const can_transmit_info transmit_info[ CAN_NUMBER_OF_TRANSMIT_BUFFERS ]
0442   =
0443   {
0444   {
0445     .can_status_mask = 0x00000004U,
0446     .not_cc_cmr_value = 0x21U
0447   },
0448   {
0449     .can_status_mask = 0x00000400U,
0450     .not_cc_cmr_value = 0x41U
0451   },
0452   {
0453     .can_status_mask = 0x00040000U,
0454     .not_cc_cmr_value = 0x81U
0455   }
0456   };
0457 
0458 rtems_status_code can_write(
0459   const lpc176x_can_number minor,
0460   const can_message *const message
0461 )
0462 {
0463   const can_driver_entry *const can_driver = &can_driver_table[ minor ];
0464   can_device *const             obj = can_driver->device;
0465   const uint32_t                CANStatus = obj->SR;
0466 
0467   const registers_can_message *const msg = &( message->registers );
0468   rtems_status_code                  sc = RTEMS_IO_ERROR;
0469   can_transmit_number                transmit_buffer;
0470 
0471   can_enable( can_driver );
0472 
0473   for ( transmit_buffer = CAN_TRANSMIT1;
0474         ( sc != RTEMS_SUCCESSFUL ) && ( transmit_buffer <
0475                                         CAN_NUMBER_OF_TRANSMIT_BUFFERS );
0476         ++transmit_buffer ) {
0477     if ( CANStatus & transmit_info[ transmit_buffer ].can_status_mask ) {
0478       sc = RTEMS_SUCCESSFUL;
0479       obj->transmit[ transmit_buffer ] = *msg;
0480       obj->CMR = transmit_info[ transmit_buffer ].not_cc_cmr_value;
0481     }    /*else can buffer busy, try with the next.*/
0482   }
0483 
0484   return sc;
0485 }
0486 
0487 /**
0488  * @brief Enables the interrupt type passed to the desired CAN device.
0489  *
0490  * @param number The CAN device to enable the interrupts.
0491  * @param type The type of interrupt to enable.
0492  */
0493 static inline void can_enable_interrupt(
0494   const lpc176x_can_number number,
0495   const can_irq_type       type
0496 )
0497 {
0498   const can_driver_entry *const driver = &can_driver_table[ number ];
0499   const uint32_t                ier = 1 << type;
0500 
0501   can_disable( driver );
0502   driver->device->IER |= ier;
0503   can_enable( driver );
0504 }
0505 
0506 rtems_status_code can_register_isr(
0507   const lpc176x_can_number number,
0508   const can_irq_type       type,
0509   const lpc176x_can_isr    isr
0510 )
0511 {
0512   rtems_status_code sc = RTEMS_INVALID_NUMBER;
0513 
0514   if ( ( 0 <= type ) && ( type < CAN_IRQ_NUMBER ) ) {
0515     sc = RTEMS_SUCCESSFUL;
0516     isr_vector[ type ] = isr;
0517     can_enable_interrupt( number, type );
0518   }
0519 
0520   return sc;
0521 }
0522 
0523 rtems_status_code create_can_message(
0524   can_message *const msg,
0525   const int          _id,
0526   const char *const  _data,
0527   const char         _len
0528 )
0529 {
0530   rtems_status_code sc = RTEMS_INVALID_NUMBER;
0531 
0532   if ( ( _len <= CAN_MAXIMUM_DATA_SIZE ) && ( _id <= CAN10_MAXIMUM_ID ) ) {
0533     sc = RTEMS_SUCCESSFUL;
0534     msg->low_level.dlc = _len;
0535     msg->low_level.type = CANStandard;
0536     msg->low_level.rtr = CANData;
0537     msg->low_level.id = _id;
0538     memcpy( msg->low_level.data, _data, _len );
0539   }
0540 
0541   return sc;
0542 }
0543