File indexing completed on 2025-05-11 08:23:03
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
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
0029
0030
0031
0032 static void can_isr( void *arg );
0033
0034
0035
0036
0037 lpc176x_can_isr_vector isr_vector;
0038
0039
0040
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
0062
0063 can_acceptance_filter *const acceptance_filter_device =
0064 (can_acceptance_filter *) CAN_ACCEPT_BASE_ADDR;
0065
0066
0067
0068
0069
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
0092
0093 return sc;
0094 }
0095
0096
0097
0098
0099
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
0110
0111
0112
0113
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
0126
0127
0128
0129 static inline void can_reset( const can_driver_entry *const obj )
0130 {
0131 can_disable( obj );
0132 obj->device->GSR = 0;
0133 }
0134
0135
0136
0137
0138
0139 static const unsigned int timing_pts[ MAX_TSEG1_TSEG2_BITS +
0140 1 ][ CAN_NUMBER_OF_TSEG ] = {
0141 { 0x0, 0x0 },
0142 { 0x1, 0x0 },
0143 { 0x2, 0x0 },
0144 { 0x3, 0x0 },
0145 { 0x3, 0x1 },
0146 { 0x4, 0x1 },
0147 { 0x5, 0x1 },
0148 { 0x6, 0x1 },
0149 { 0x6, 0x2 },
0150 { 0x7, 0x2 },
0151 { 0x8, 0x2 },
0152 { 0x9, 0x2 },
0153 { 0x9, 0x3 },
0154 { 0xA, 0x3 },
0155 { 0xB, 0x3 },
0156 { 0xC, 0x3 },
0157 { 0xD, 0x3 },
0158 { 0xD, 0x4 },
0159 { 0xE, 0x4 },
0160 { 0xF, 0x4 },
0161 { 0xF, 0x5 },
0162 { 0xF, 0x6 },
0163 { 0xF, 0x7 },
0164 };
0165
0166
0167
0168
0169
0170
0171
0172
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
0184
0185
0186
0187
0188
0189
0190
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
0202
0203
0204
0205
0206
0207
0208
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 {
0224 ( *brp )++;
0225 }
0226 }
0227
0228 return hit;
0229 }
0230
0231
0232
0233
0234
0235
0236
0237
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
0262
0263
0264
0265
0266
0267
0268
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
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
0293
0294
0295
0296
0297
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 }
0313
0314
0315 return sc;
0316 }
0317
0318
0319
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
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
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;
0355 }
0356
0357 return sc;
0358 }
0359
0360
0361
0362
0363
0364
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
0378
0379 }
0380 }
0381
0382
0383
0384
0385
0386
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
0394 const uint32_t int_vector = driver->device->ICR & CAN_INTERRUPT_TYPE_MASK;
0395 call_isrs( int_vector, number );
0396 }
0397
0398
0399 }
0400
0401
0402
0403
0404
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;
0431 }
0432
0433 return sc;
0434 }
0435
0436
0437
0438
0439
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 }
0482 }
0483
0484 return sc;
0485 }
0486
0487
0488
0489
0490
0491
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